使用DSL表达软件设计意图 - guitarvydas


我们目前还没有一种用于DI(Design Intent设计意图的简称,意图包括架构,业务规则)的语言。
当DI被嵌入到了代码中的会出现病症:如果你需要重构,那么很可能代码还没有被切分为DI和实现两个部分。

过多的细节走向了DI的对立面。 
大多数语言都以他们有多少功能而自豪,而不是他们有多么少的功能。 

当你创建DI时,你不想关心某样东西是如何实现的(例如,数组与列表)。
这种实现低层次的效率与性能是工程师所关心的,而不是架构师。

DSL是将DI与实现分开的一种方式。


不要做基础语言已经做过的事情
让底层基础语言处理繁重的工作。

只有在省力的情况下才使用 DSL

  • 设计:使用DSL而不是使用详细的HLL可以 "更好地 "表达一个设计吗?
  • 架构的重用:DI(设计意图,又称架构)的重用比代码的重用更重要。代码很便宜,思考很困难。
  • 保持 "业务规则 "与代码分离:使用一种语言进行DI,另一种语言进行实现。
  • 编码:使用DSL可以减少编码时间吗?
  • 自动化:让DSL来写代码; 编写可以编写程序的程序。

维护

  • 使用DSL能减少维护工作吗?
  • 维护工程师可以更快理解DI(设计意图)吗?
  • DSL能为你执行D.R.Y.(Don't Repeat Yourself)吗?
  • 维护工程师能否通过调整DSL更快地进行错误修复?
  • 维护工程师能否通过调整DSL来更快地完成功能升级?


尽量少写代码

  • 创建小型DSL
  • 使用DSL减少编码
  • 依靠基础语言来完成重任
  • 使用比文本更多的东西:
    管理层使用图表(例如在白板上)。
    程序员也应该使用图表。
    在同一个文档中混合使用图表和文本是可以的。
  • 图表可以很容易地转译

图可以很容易转译
考虑字形,而不是像素。 使用回溯分析器(如Ohm、PROLOG等)。

Gedanken的例子:

  • 你怎么知道4条线是否构成一个盒子[1]?
  • 你怎么知道一个盒子是否比另一个盒子小? 
  • 如何知道较小的盒子是否与较大的盒子的边缘相交? 
  • 你怎么知道一段文字是否完全在一个盒子里?
  • 你怎么知道一个箭头(一条荣耀的线)是否连接了两个盒子?
  • 如果这条线是由许多小段组成的呢?
  • 你如何画一个网络?
  • 如何画一个状态机?[。
  • 当你用椭圆代替方框时,有什么变化?
  • 当你用弯曲的线代替直线段时,会有什么变化?


当所有其他方法都失败时:自动化
以某种方式自动生成代码。 使用一个漂亮的格式,使代码可以被人类阅读。
你可以一直使用生成的代码,就像它是手工写的一样(由别人写的)。


为什么管理层痛恨DSL

  • 对DSL的(错误)认知
    管理层认为DSL写作是一个浪费时间的漏洞。 这种印象是基于一种错误的观念,即编写DSL和编写编译器是一样的。
    管理层看到了创建一个DSL的前期成本。 管理层知道如何衡量开发时间(和成本),但不知道如何衡量维护(理解)成本。
    管理层不可能雇佣那些已经理解特定DSL的可互换的单位,即程序员。
    理解一个DSL需要思考,理解一个产品设计也需要思考。 
  • 雇用
    目前,我们还不知道如何在简历的基础上雇用思想家。 
  • 工程师的职业
    工程师行业在几十年前就遇到了这个问题,即雇用思想家。 
    答案是把这个行业分成几个部分。 
    如果你在大学里学习了4年的课程,并获得了工程学位,那么你就被认为是一名工程师。
    在贸易学院学习两年的人被认为是贸易人员。 
    其他人则被认为是工人和砌砖工人。
    为了使这一计划发挥作用,各阶层之间必须使用一种沟通方法--蓝图。

绕行

  • 工程中不使用绕行
    工程师在设计上盖章(盖章或签字),并在法律上对他们的设计负责。
    砌砖工人可能会发现设计中的 "缺陷 "或 "改进",但他们从不对蓝图进行实质性的修改。 这些改动必须得到签字工程师的批准。
    绕行的做法在劳动和工程中从未使用过。
  • 绕行是一种症状
    当人们认为生成技术不是在所有情况下都有效时,就会使用绕行技术。
    绕行通常会造成意外的复杂性。
    如果你认为你需要绕行,那么: 

  1. 证明这个符号在某些情况下不起作用
  2. 修正这个符号,不要把绕行当作创可贴。


蓝图
目前的编程语言不能像蓝图那样使用。
目前的编程语言暴露了太多的细节,无法有效地用作通信机制,如蓝图。
在我看来,答案就在于隔离。

图纸
蓝图是暴露出很少细节的图纸。
蓝图是由简单的元素组成的。
目前的编程语言暴露了太多的细节,无法像蓝图在工程和建筑中的使用方式那样使用。

可扩展性
进一步解释:
软件设计中的主要问题是可扩展性。
我们希望像乐高积木一样把各个部分 "插 "起来。
更好的可扩展性意味着更少的依赖性。
早期的硬件设计人员在这方面是 "正确的"。 他们把令人难以置信的复杂设备(由各种铁锈组成的半导体)建成芯片/IC(集成电路)。
芯片是黑盒子。 它们有一组输入/输出引脚。 芯片的内部是不可捉摸的--被包裹在不透明的环氧树脂中。
除了通过芯片的引脚,没有任何东西从芯片中漏出或进入芯片。

芯片的属性是用容易测量的术语来描述的:

  • 一个引脚上的电压
  • 一个引脚所需的电流
  • 给定一组输入,输出的图/图表
  • 时序。

然后,硬件设计者 "发现",芯片之间的点对点布线导致了不可扩展的设计。
他们建立了一个(小的)层次结构--芯片安装在插在背板上的电路板上。

最早的背板基本上是点对点的线束。 例如,我拥有的早期Wang文字处理器,其背板有大约400个引脚,允许一块板上的芯片直接向另一块板上的芯片发送信号。
然后,出现了S100总线。 它只有100个引脚。 它有很好的定义和记录。 某些连接是不允许的,即使它们可以作为点对点的连接更有效地完成。
总线的概念导致了苹果电脑的出现,并最终导致了IBM台式电脑的出现。 (总线的定义不止一个,但市场将其淘汰了)。

软件可以像芯片一样构建吗? 我认为是的。

我们需要分层次地构建软件。
分而治之。
层次结构中的各层之间不能有任何泄漏。 ("任何东西 "包括像变量、类型、控制流、任何种类的依赖关系等等)。

严谨与权衡
工程学是关于做出权衡的。
工程师们并不努力去证明一个设计是有效的--他们只是在设计中建立安全系数。 
目前对可证明的软件设计的追求不会导致工程的发展。 
我们需要的是对可能的权衡的描述,例如,它的运行速度有多快?需要多大的内存?需要多大的处理能力?什么是故障安全装置,"大红按钮"?如果它崩溃了,可以做什么?它是否有一个 "已知的开始状态"? 设计每个功能需要多少钱? 测试每个功能需要多少钱?有什么利害关系? 它需要进行多彻底的测试? 最坏情况下的吞吐量是多少? 平均吞吐量是多少?MTBF是多少?它是单源的还是多源的,有什么影响?

复杂性
我认为软件是一个层次分明的黑盒子。 每个盒子的架构师选择最佳方式来描述黑盒子的设计意图。 工程师找出如何在 "I "上打点,在 "T "上打叉。 生产工程师找出如何测量并使黑匣子 "更有效",而编码员则为实现黑匣子打下基础。

黑匣子架构
我认为软件是一个黑盒子的层次结构[3]。 每个盒子的架构师选择最好的方式来描述一个黑盒子的设计意图。 工程师想出如何在I上打点,在T上划线。 生产工程师找出如何使黑匣子 "更有效",而编码员则为黑匣子的实施打下基础。

许多银弹
一个好的架构师会有一个装满 "银弹 "的工具带。 也许一个问题最好用关系术语来描述,也许一个问题最好用状态机来描述(还可以用图来描述),也许一个问题可以用同步方式来分解,等等,等等。

PSLs
领域特定语言 (DSL) 与问题特定语言 (SPL):
我将使用术语PSL而不是DSL来强调每个问题+解决方案的特定问题。 
PSL的意思是特定问题的语言。 旧的术语,DSL,意味着特定领域的语言。
在我看来,"领域 "这个词太宽泛了,我们必须把重点放在问题上,我们必须用专业化而不是泛化来解决具体问题。