1. 通用图灵机
代码可以看做储存在磁盘上的,一种特殊类型的数据,
计算机读取到这些代码之后,就会模拟代码所描述的行为,
再针对不同的输入完成不同的动作。
这一过程的理论模型,称为通用图灵机。
和图灵机不同的是,
图灵机,是一台固定的计算机器,根据输入计算结果,
而通用图灵机,则可用来模拟不同的图灵机,因此它有两个输入。
一个是被模拟的图灵机计算过程之编码,另一个则是被模拟图灵机的原始输入,
最终,通用图灵机会得到被模拟图灵机的计算结果。
因此,代码可以被当做数据来看待。
反之亦然。
解释器模式就是这种思想的一个应用,
实际工程中,我们会对配置信息或DSL进行解析,
还原出它们所描述的计算行为。
2. 描述层次
对于大部分编程语言的代码而言,有一个比较好的性质,
那就是,我们有一定的活动空间,对代码进行重新组织,
却不会改变它们(被关心)的外部行为。
这正是代码重构的可行性基础。
在代码的组织方式上,不同人会有不同的办法,
但区分出不同的描述层次,应当会是一项良好的编程实践,
提升描述层次的过程,在计算机科学中,通常被称为抽象。
管理计算机系统复杂性的关键是通过一些定义明确的接口把计算机系统分成不同的抽象层次。
抽象层次允许忽略或简化系统设计的底层实现细节,从而简化高层组件的设计。
—— 《虚拟机-系统与进程的通用平台》
实际操作中,接口也是用编程语言来书写的,
因此,程序员首先面对的是语言,其次是理解语言背后被描述的下一层事实。
配置也是一种语言形式,只不过它很少提供抽象机制。
这样的话,我们就很难对配置信息进行指代,不利于控制复杂度。
3. 不可判定性
The Rule of Least Power指出了与编程语言相关的一项原则,
Powerful languages inhibit information reuse.
对于图灵完备的计算模型,
其结果是不可判定的,
得到结果的唯一的办法,是将它运行一遍。
一种计算模型越强大,就越难预测它的行为。
如果我们有幸发明了一种足够强大的领域特定语言,
那么在判定它的运行时特征时,就会遇到麻烦,
如果没有完整的测试用例来保障,部分错误就不得不在用户使用时才显现出来。
因此,在决定设计DSL之前,不妨先考虑一下,
我们可以对它进行哪些静态检查以避免用户犯错。
4. 新语言问题
随着用户需要的语言特性被不断添加,
语言障碍会变得越来越明显,称为新语言问题,
极大的增加了用户的学习成本。
灵活是要有代价的。
就像一个平衡游标,一端是只有单一用途的软件,而且工作得很好,但很难或根本无法改变它的行为。
然而另一端则是编程语言,你可以用它编写游戏,应用服务器或股票管理系统,这就是灵活性。
显然,大多数软件都在两点之间,而不是这两端点中的任何一个。
—— 《持续交付》
况且,用户可能并不需要灵活性,而是不想受到不该有的限制,
用户也不想写配置文件,更不想用DSL进行编程,他们想要的是功能,
因此我们还是将键盘从用户那里拿回来吧。
也许只有当我们自己写配置文件的时候才会发现,
它们与一些难以维护的晦涩代码,并没什么太大区别。
5. 傻瓜式框架
让系统可配的另一个动机是,让无法胜任设计工作的人员,也有能力进行开发。
然而,《领域驱动设计》一书中这样强调,
如果这些人在设计方面不够聪明,就不应该让他们来开发软件。
如果他们足够聪明,那么用『傻瓜式』的框架来应付他们只会为他们造成障碍,使他们得不到所需的工具。
消除重复劳动的软件开发宗旨,会终结在傻瓜式框架的边界上。
因为未经良好构思的框架,并没有仔细考虑如何解决用户的重复操作问题,
所以,本可避免的重复劳动,就这样转移到了框架用户的日常工作之中,制造了重复劳动。
这样做到底划不划算,值得深思。
结语
让系统可配置,或者采用领域特定语言,是一种很好的实践,
但是一旦构思不当,所带来的问题就会比它要解决的问题还要多。
其主要原因在于,未经深思熟虑的配置以及DSL,会限制用户的表达能力,
这也是另外一个从模式的使用者角度评判设计优劣的例子。
参考
The Rule of Least Power
重构:改善既有代码的设计
设计模式
持续交付
领域驱动设计
可计算性与计算复杂度导引
形式语言与自动机理论
虚拟机-系统与进程的通用平台