编程范式巡礼(最终季)--超级范式

本周是编程范式系列的最后一次分享,让我们拉长视角,看向远方,进入"元编程"的领域,在《冒号课堂》中起了个很酷的名字:"超级范式"。

从通用语言到领域语言

先给大家做一个小练习:

以下哪些属于编程语言:

A.Java B.Html C.Spring Bean Definition D.Comment

答案是ABC,从中,我们可以感受到编程语言的一些特性:

  • 必需:有语法结构、可运行
  • 可选:可编译、可调试、可扩展

    类似人类语言,作为与计算机的唯一沟通渠道,编程语言的发展也是多种多样的。

多样性体现在哪里呢?可以是解决的问题不同,可以是运行的环境不同,也可以是用户群不同等。

我们可以用一个词来概括这种不同,就是"领域(Domain)"。而仅服务于某一领域的语言,称为"领域语言(DSL)"。

领域语言示例

上面提到的html、Spring Bean Definition以及SQL都是领域语言,这里列几个更有趣的。

Gradle是一个灵活的通用构建工具,让java项目在构建上有了跨越性发展。可以看到采用领域语言后,自有度有明显的提高,开发人员也更容易进行扩展。

println 'This is executed during the configuration phase.'
task configured {
println 'This is also executed during the configuration phase.'
}
task testBoth {
doFirst {
println 'This is executed first during the execution phase.'
}
println 'This is executed during the configuration phase as well.'
}

Cucumber是一个能够理解用普通语言描述的自动化测试工具,在普通测试工具可运行可跟踪的基础上,案例可读性的大大提升了。

功能: 用户登录
为了能够浏览网站只对在线会员可见的那些内容
作为一名访客
我希望能够登录 场景: 用户登录功能
假如 没有<somebody@somedomain.com>这个用户
当 我以<somebody@somedomain.com/password>这个身份登录
那么 我应该看到<用户名或密码错误>的提示信息
而且 我应该尚未登录

在领域语言的帮助下,编程语言在"人性化"的方向上迈进了一步。

从领域语言到元编程

前面介绍了领域语言的概念,我们通常会将其列到"工具"的范畴。如何成为一个范式,就要引入"超级范式"元编程了。

元编程是编写、操纵程序的程序。在传统编程中,运算是动态的,但程序本身是静态的;在元编程中,二者都是动态的。

下面举个处理客户交易单的例子,采用通用语言Scala实现如下。

val t1 = FixedIncomeTradeImpl {
tradeingAccount = NOMURA,
instrument = IBM,
currency = USD,
market = NYSE,
quantity = 100,
unitPrice = 42
}

如果我们站在编程外行的角度看,这段代码是存在不少问题的。

  1. 等号的作用与常识不符,一般理解为比较,这里是赋值
  2. 有非常多令人费解的符号,比如{}
  3. 没有表达出输入间的关联,比如USD应该是用来描述unitPrice的。

下面使用领域语言进行优化,更加符合自然语言的表达。

val equityTrade =
100 discount_bonds IBM
for_client NOMURA on NYSE at 42.ccy(USD)

具体实现上,采用了Scala的"隐式转换"特性,这是一种元编程的方法。

object TradeImplicits {
class InstrumentHelper(qty: Quantity) {
def discount_bonds(db: DiscountBond) = (db, qty)
def equities(eq: Equity) = (eq, qty)
}
}

目前来看,元编程还是比较依赖于语言层面的支持,以Ruby、Groovy为代表的动态语言支持最佳,Scala提供了部分支持。但是从总体看,更为主流的Java语言尚未提供支持。比较可行方法是采用Scala、Groovy等jvm语言,嵌入Java代码中进行实现。

小结

元编程从实现复杂看并不亚于通用语言,篇幅有限无法深入,对细节感兴趣建议大家阅读《领域专用语言实战》。

最后,想用Martin Fowler的一段访谈来小结下。原文地址

InfoQ:面对某个领域的多种变化,我们应该怎样利用领域特定语言,比方说在开发某个产品线的时候?

MF:和其它许多事情一样,我不认为领域特定语言的代码和其它代码有多大的区别。领域特定语言能够表达人们更深层次的思想是因为,和普通的命令-查询式API相比,领域特定语言以一种更加自然的方式表述领域内的不同变化。

领域语言的价值在于更加"人性",更易于使用。其出发点是一种"减法思维",通过限定外部使用范围而获得了更好的内在价值。

InfoQ:领域特定语言看起来很擅长解决某个系统内的子域问题,比如说系统配置管理。项目组该如何在创造一种能够覆盖多个领域的复杂庞大的领域特定语言和多个小领域特定语言之间做出取舍?

MF:我们其实非常鼓励使用许多小的领域特定语言。比方说你不会试图去扩展正则表达式来设计HTML页面,也不会用CSS来进行文本匹配。对我们来说,让领域特定语言与众不同的正是其有限表达这一特性。

在使用上,领域语言之间可以互相组合,和而不同,目标是发挥1+1>2的效果。

InfoQ:一些组织和项目不接受领域特定语言的主要原因是什么?是因为复杂性,还是因为缺乏对问题域和解决方案域的了解?

RJP:除了新的工具和开发流程这些问题,使用领域特定语言还需要用新的思维方式思考问题。关于哪些是构成好的领域特定语言设计的因素,还有待于我们去逐步发掘。当然也少不了“我们很久以前就听说过”的关于业务可读/可写程序的观点以及它所引发的怀疑。

我最早接触领域语言概念,是在学习Ruby语言的过程中,当时的感受完全是颠覆式。由于涉及到思维方式的转换,也是限制领域语言发展的一个重要因素。目前,领域语言并未成为业界的主流解决方案,但其思考之深刻、思路之精妙让人非常惊艳,码农们如果希望开拓视野、提升自我,强烈建议学习。

小课堂week19 编程范式巡礼最终季 超级范式的更多相关文章

  1. 小课堂week16 编程范式巡礼第一季 三大基石

    编程范式巡礼第一季 三大基石 最近迷上了一些哲史类书籍,回望过去.放眼未来,往往沉浸在其思维之美中无法自拔.计算机编程是一门非常年轻的学科,沉淀不足也是年轻的一个侧面,在编程领域,有足够思想深度的作品 ...

  2. 小课堂week17 编程范式巡礼第二季 并发那些事

    编程范式巡礼第二季 并发那些事 继续上周的编程范式话题,今天想聊一下并发范式. 并发也算一种范式? 真正的并发式编程,绝不只是调用线程API或使用synchronized.lock之类的关键字那么简单 ...

  3. 小课堂week18 编程范式巡礼第三季 谈谈依赖反转

    编程范式巡礼第三季--谈谈依赖反转 今天会进入深一点的主题,谈一个软件开发的"道":依赖反转.根据我的观察,这也是架构师与程序员的分水岭之一. 什么是依赖反转 引出问题 让我们从U ...

  4. [小北De编程手记] : Lesson 06 玩转 xUnit.Net 之 定义自己的FactAttribute

    xUnit.Net本身提供了标记测试方法的标签Fact和Theory.在前面的文章<Lesson 02 玩转 xUnit.Net 之 基本UnitTest & 数据驱动>中,也对它 ...

  5. [小北De编程手记] : Lesson 05 玩转 xUnit.Net 之 从Assert谈UT框架实践

    这一篇,本文会介绍一下基本的断言概念,但重点会放在企业级单元测试的相关功能上面.下面来跟大家分享一下xUnit.Net的断言,主要涉及到以下内容: 关于断言的概念 xUnit.Net常用的断言 关于单 ...

  6. [小北De编程手记] : Lesson 04 玩转 xUnit.Net 之 Fixture(下)

    上一篇文章<[小北De编程手记] : Lesson 03 玩转 xUnit.Net 之 Fixture(上)>向大家介绍了xUnit.Net 共享数据的方式.Test Case的构造函数 ...

  7. [小北De编程手记] : Lesson 08 - Selenium For C# 之 PageFactory & 团队构建

    本文想跟大家分享的是Selenium对PageObject模式的支持和自动化测试团队的构建.<Selenium For C#>系列的文章写到这里已经接近尾声了,如果之前的文章你是一篇篇的读 ...

  8. Spark小课堂Week3 FirstSparkApp(Dataframe开发)

    Spark小课堂Week3 FirstSparkApp(代码优化) RDD代码简化 对于昨天练习的代码,我们可以从几个方面来简化: 使用fluent风格写法,可以减少对于中间变量的定义. 使用lamb ...

  9. Spark小课堂Week3 FirstSparkApp(RDD开发)

    Spark小课堂Week3 FirstSparkApp 问题:Java有哪些数据结构 大致有如下几种,其中List与Map是最重要的: List Map Set Array Heap Stack Qu ...

随机推荐

  1. thinkphp5.0Traits引入

    ThinkPHP 5.0开始采用trait功能(PHP5.4+)来作为一种扩展机制,可以方便的实现一个类库的多继承问题. Traits 是一种为类似 PHP 的单继承语言而准备的代码复用机制.Trai ...

  2. JQuery插件ajaxFileUpload 异步上传文件(PHP版)

    太久没写博客了,真的是太忙了.善于总结,进步才会更快啊.不多说,直接进入主题. 前几天想在手机端做个异步上传图片的功能,平时用的比较多的JQuery图片上传插件是Uploadify这个插件,效果很不错 ...

  3. 【BZOJ 1566】 1566: [NOI2009]管道取珠 (DP)

    1566: [NOI2009]管道取珠 Time Limit: 20 Sec  Memory Limit: 650 MBSubmit: 1659  Solved: 971 Description In ...

  4. [CF126D]Fibonacci Sums/[BJOI2012]最多的方案

    [CF126D]Fibonacci Sums/[BJOI2012]最多的方案 题目大意: 将\(n(n\le10^9)\)表示成若干个不同斐波那契数之和的形式,求方案数. 思路: 如果不考虑\(0\) ...

  5. 利用SharpZipLib对字符串进行压缩和解压缩

    添加对ICSharpCode.SharpZipLib的引用. using ICSharpCode.SharpZipLib.BZip2; /// <summary> /// 压缩 /// & ...

  6. [转]Android 中fill_parent与wrap_content的区别

        在Android中,对于组件的属性“layout_width”和“layout_height”, 其值总是设置为“wrap_content”或“fill_parent”. 那么,这两个值有什么 ...

  7. CROC 2016 - Elimination Round (Rated Unofficial Edition) E. Intellectual Inquiry 贪心 构造 dp

    E. Intellectual Inquiry 题目连接: http://www.codeforces.com/contest/655/problem/E Description After gett ...

  8. Cocoapods报错Unable to satisfy the following requirements

    很多时候我们都会去gitHub上down别人的源码去研究,如果别人的项目用pod集成了,当我们下载好后不外乎cd到项目根目录pod install一下,集成项目所需的库类.今天在我pod instal ...

  9. 用C++/CLI搭建C++和C#之间的桥梁(四)—— 网络资源

    关于C++/CLI的基础,我前面已经写过了几篇文章介绍过一些了,不过这些基本上都是管中窥豹,如果要详细了解C++/CLI,MSDN无疑是最好的教程. 使用 C++ 互操作(隐式 PInvoke) Vi ...

  10. Visual Studio 2010 使用 Git Extensions 连接 google code

    下载最新版本 Git Extensions http://code.google.com/p/gitextensions/downloads/list Git Extensions 2.46 Wind ...