1.6 何时需要DSL
每个应用程序的业务规则都应该明确、可读、直白。DSL是对业务规则建模的最佳手段。开发一种DSL,把原来写成time() – 1209600
的时间表示形式变为2.weeks.ago
并不难,但它对用户可能产生巨大的影响。
你应不应该在下一个项目中使用基于DSL的开发?作决定之前,你应该先掂量一下各种优缺点。DSL跟任何一种技术一样,有其暗藏的危险。身为开发者,你比任何人都更有资格判断眼前的问题是否需要用DSL来建模。为此,你需要了解DSL通常会有的一些优点和缺点。
1.6.1 优点
基于DSL的开发在领域复杂度较高时可以提供更高的回报。前面提过,几乎你经手的每个项目都会用上一些小的DSL引擎。当你开始规划一个复杂的建模项目时,应该在有意识地权衡过各种选择之后再做最后决定。下面提供的一些论点将有助于你决定是否采用基于DSL的开发方式。
1. DSL更具表现力
DSL趋向于提供一种覆盖面小、范围集中的API接口,处理的各种抽象概念都具有领域内的精确语义。用户热爱DSL。
2. DSL更精炼
因为精炼,DSL易于观看、观察、设想、展示。Dan Roam(参见1.9节文献[2])称之为视觉化思考的四个步骤 。DSL的精炼性缩短了程序与问题之间的语义距离。
3. DSL设计于更高的抽象层次
DSL不需要应对低层次的语言构造、数据结构优化及其他实现手法。相反,DSL在一个更有利的层次体现领域知识,比起一般基于通用编程语言的实现层次,更便于领域知识的保存、验证和重用。这个特点使得DSL符合许多不懂编程的领域专家的需求。
4. DSL的回报更高
从开发生命周期的长远来看,基于DSL的开发趋向于产生较高的回报。
5. 基于DSL的开发容易扩大规模
如果项目团队对于特定编程语言的掌握程度不一,可以让熟练的程序员先集中精力实现DSL,然后给其他成员使用。因为DSL的抽象层次较高,所以更易于学习掌握,可以充当一种扩充开发团队的载体。
任何一种技术范式都有其优点,基于DSL的开发范式也不例外。我们会在第3章继续讨论基于DSL的开发。下面是DSL通常存在的一些潜在危险,它们在开发项目中的出现会令你大为头疼。
1.6.2 缺点
DSL的所有缺点都可以关联到软件开发生命周期中招致额外成本的实现开销。
1. 语言设计很难
实现DSL是一种语言设计工作,而语言设计是复杂的任务,且无法凭人多取胜。顾及从零开始设计一种语言的词法和文法的复杂程度,大多数人选择将DSL寄身于别的高级语言之中。即便如此,设计工作仍然相当难,绝不是生手程序员可以胜任的。后面几章会谈到各种语言特性以及用它们实现内嵌式DSL的情况。
2. DSL需要前期投入
在项目中引入基于DSL的开发也会引入前期成本。只有当模型的复杂度适中,这样的代价才值得接受。在开发周期的后期阶段,当成本被摊平之后,这样做的好处会最终显现出来。
3. 使用DSL可导致性能隐忧
DSL有时候会给程序带来性能隐忧。毕竟,它又增加了一个间接层。作为项目经理,你要考虑部署规模、重用范围等因素,才能决定是否采用基于DSL的开发。
4. DSL有时缺乏足够的工具支持
任何开发方法都需要充分的工具支持才能在程序员团体中普及。工具支持包括很多方面,比如有无IDE集成、单元测试支持、语言工作台(language workbench)、性能分析支持等。如果你的DSL生成多种目标语言用于执行,那么各种语言之间的互操作性也是一个潜在问题。
5. “学不完的DSL”现象
任何一种外部DSL都要求开发者另外学习。内部DSL只要求开发者学习它在现有宿主语言之上营造的接口。开发者经常对又要学习一种新语言感觉厌烦,不仅因为没完没了,还因为新语言的用途很有限。
6. DSL可导致语言间的摩擦
通常开发一个应用程序要用到不止一种DSL。当结合使用多种语言时,人们往往担心最终的领域模型不能保持一致。DSL的组合使用并不简单,因为一般各个DSL都是彼此独立地发展起来的。如果不小心应对,语言的多样性可以导致各自为政的混乱状态。
从图1-3可以看出,DSL是建立在实现模型基础上的语言学抽象。你把领域模型抽象得越好,就越容易在上面设计出自然的语言。我们来看看模型应该具备什么特质,才能为创造一种富于表现力的DSL奠定坚实的基础。