本文最后的更新日期为2008-4-26
软体开发技术不断改进,其背后推动的力量主要是为了应付软体固有之复杂与善变的特性,而解决这些问题的其中一项重要关键,就在于抽象化(abstraction)。观察整个软体开发技术演进的历史,可以发现它其实就是不断提高抽象层次的过程。举例来说,电脑只看得懂机器码,因此组合语言便可视为第一次抽象化的成果--它让程式设计师更容易撰写程式码。后来出现的高阶语言,如C 语言、Pascal 等,则又再提升了程式语言的抽象层次,直到我们现在使用的VB、C#、Java 等,不难看出每一代程式语言的功能与抽象层次都不断提升。然而,软体系统的规模与复杂度也同样与日俱增,那种访谈需求之后立刻埋头写程式的做法已经无法应付复杂的软体系统,因此我们需要分解复杂系统的方法,将事物理出一番头绪,并利用人类更容易理解的文字或符号来表达我们的设计。经过多年的努力与整合,软体开发社群终于对如何表达设计有了共识:UML。
刚开始,UML只是用来表达问题领域概念的工具,让我们可以将软体设计的想法以一套多数人都能理解的符号呈现出来,方便与他人沟通、讨论。能够做到这样,UML就已经是贡献良多了。毕竟,软体工程社群也是花了十几年才逐渐达成此共识(如果从1990年代的OMT、OOSE、和Booch'93算起)。然而模型最终还是得透过程式语言实作出来,从抽象概念到具体实作,这当中有太多繁复的细节需要开发人员填补,于是,我们不断在OO专案中讨论究竟模型要画到多细(文件要堆多高)才够、table schema究竟什么时候才可以开始设计、要不要用OR mapping…诸如此类的,其过程不只麻烦,开发成本也高。试想,要是模型画好了,就能够直接产生可执行的程式码,不就一举消弭了分析设计和实作之间的鸿沟吗?对此问题,以UML为基础所衍生的解决方案主要是executable UML和OMG(Object Management Group;物件管理组织)提倡的模型驱动架构(Model-Driven Architecture;MDA)。
回想数年前,当时去参加一场OOAD 课程,休息时间私下请教讲师,他们的团队是否真的有用那套modeling 工具的code-gen 功能(从画好的UML 模型自动产生程式码),答曰没有。那么,现在的UML 塑模工具是否已经进步到足以让我们在实际的专案开发中使用code-gen,甚至逆向工程(从程式码产生模型)呢?支援MDA 的工具,其模拟、验证模型、以及产生程式码的功能是否真的实用,且值得我们投资(购买工具、学习如何使用工具、以及描绘模型)?
关于这点,个人是抱持怀疑的态度。UML原本就是用来表达较高层次的抽象模型,这模型是给人看的(而不是机器),其基本表示法在语意上并未精确到能直接和实作对应。然而,就算用上stereotypes、tagged values、和OCL(Object Constraint Language),如此是否就够精确、完整,还是令人存疑;若要做到精确、完整的表达,是否又会弄出一套非常复杂的表示法(例如MDA的另一项关键技术:Meta-Object Facility;简称MOF),也是需要考虑的因素。想用UML画出可直接执行的模型,或者将模型直接转成可执行的程式码,距离实用的程度似乎还有一些距离。Booch在2004年MDA Journal中说的一段话或许是最好的注脚:
「唯有当塑模的概念能够直接对应到领域概念,而非电脑技术的概念,MDA方能展现其完整价值。」
(The full value of MDA is only achieved when the modeling concepts map directly to domain concepts rather than computer technology concepts.)
如此说来,难道软体开发的过程就无法再系统化、自动化一些吗?既然以UML呈现的抽象分析设计模型不够精确,那么是否有什么方法可以让我们用精确的方式描述问题领域,并直接与实作接轨?相较于UML和MDA,微软给我们的答案是DSL与软体工厂(Software Factories)。
DSL是Domain-Specific Language的缩写,中文译为「特定领域语言」(或译「领域特定语言」),也就是开发人员为了解决特定领域的问题所定义的专用语言。Karl Frank认为,「domain-specific languages」可以泛指任何特定领域的语言,例如UML、XML,甚至连C#、Java都算是特定领域的语言,因为它们都是针对特定目的(软体开发),用于特定场合的语言,这是比较广义的看法。不过,就软体开发这块领域而言,UML、C#、Java可运用于各类型的软体开发,所以我们通常将它们视为通用目的语言。另一方面,由于微软近年大力提倡DSL及其支援工具,因此当我们提到DSL时(至少在讨论.NET平台上的软体开发时),通常是指微软提出的概念和支援工具,而讲到「特定领域语言」(domain-specific languages)时,则可能泛指任何特定领域的语言。
Martin Fowler指出,DSL并不是新观念,早期Unix的"little languages"使用lex和yacc产生程式码,以及在LISP中定义的语言,都是运用DSL技术的例子。微软方面最早则是由Charles Simonyi开始研发支援DSL程式设计的工具,他称之为「Intentional Programming」。为了明白区分,Fowler将所有使用DSL的程式设计方式统称为「语言导向程式设计」(Language-Oriented Programming),而将支援语言导向程式设计的开发工具统称为「语言工作台」(Language Workbench)[ 1]。
呼~真多术语。其实大概知道有这些名词就好,简单地说,就像程式语言需要编译器和IDE 工具,DSL 也一样需要编译或解译的工具才有实质的意义。
有在写程式的人其实多少都有用到DSL,例如曾经红极一时的Delphi,它的.DFM 档案就是一种特定领域语言。我们只要利用Delphi IDE 提供的视觉化拖拉设计方式,将控制项放在Windows Form 上面,并设定其属性,IDE 就会帮我们在.DFM 档案中产生对应的描述,其内容与格式类似这样:
object Form1: TForm1
Left = 192
Top = 107
Width = 509
Height = 462
Caption = 'Form1'
object DBGrid1: TDBGrid
Left = 60
Top = 80
Width = 341
Height = 293
end
object Database1: TDatabase
AliasName = 'DBDEMOS'
Connected = True
DatabaseName = 'testdb'
LoginPrompt = False
end
end
当然,我们也可以为自己量身订作一套特定领域语言。举例来说,假设我们要设计一款射击游戏,此游戏的每一关都有一只魔王(boss),而我们希望用一个外部档案来定义魔王的运动路径,例如:
Stage: 1
BossClass: Dragon
InitialPosition: 400, 300
MovingPath1: (3,2,10) (-4,2,30) (5,-1,30) ......
MovingPath2: (7,-2, 5) (12,0,10) ......
第1 列到第3 列分别描述了第几关、魔王的类别名称、初始位置,第4 列则为魔王的第一种移动路径,第5 列是另一种移动路径,其中每一对括弧中的三个数字分别代表x 偏移量、y 偏移量、以及在该位置持续多少个时间单位。
为了处理魔王的运动路径,我们自行定义了一种语言来描述这些资料,这就是我们的domain-specific language。
上述资料也可用改XML 格式来描述,例如:
<Stage>
<Number>1</Number>
<BossClass>Dragon</BossClass>
<InitialPosition>400,300</InitialPosition>
<MovingPath1>(3,2,10) (-4,2,30) (5,-1 ,30) ......</MovingPath1>
<MovingPath2> (7,-2,5) (12,0,10) ......</MovingPath2>
</Stage>
其实我们可以发现很多软体技术都是采用XML来描述特定领域,例如JSP和ASP.NET应用程式的组态档、Windows Presentation Foundation使用的XAML等都算是特定领域语言的应用。
以上所提的例子都是纯文字的DSL,但是它也可以是图形符号。文字型的DSL 好处在于容易给电脑处理,例如字串的搜寻、代换,以及文字内容的差异比对、合并等等。图形式DSL 的优点则是一目了然,很容易掌握整个模型的概观以及各元素之间的关系。微软的DSL 是偏向以图形符号的方式呈现。
DSL既然是处理特定问题领域的语言,除了程式开发人员之外,领域专家(domain expert)也必须会用。此时外部DSL就明显占优势:你可以为特定领域定义一套比较简单的,甚至连end-user都能够自行修改的语法。DSL拥护者认为(希望),将来一定会演进到由end-user自行修改领域逻辑的地步,届时程式开发人员大部分时间都会用在开发DSL支援工具上面,而不是与不断变动的需求奋战。这种境界似乎太过美好,好到不够真实。然而就算这一天真的到来,也不代表开发人员的工作内容将有一百八十度大转变,或程式设计师会突然丢掉饭碗--软体开发的工作总是需要优秀、严谨、细心的程式设计师。不过,有了DSL,那些容易变动的软体需求或许能够大部分交给end-user自行掌控,让他们也能调整软体的行为;能够由DSL控制的部份愈多,软体的维护成本就愈低,开发人员也够将心力投注在其他更有价值的工作上面。这或许是一个理想境界,但是退一步想,即使只有开发人员会使用DSL,对提升软体开发的生产力应该也有不少帮助。(怎么个有帮助法?这部份等下次再写一篇文章讨论吧。)
在决定是否使用DSL时,还有一些问题必须考虑。首先,问题领域是否复杂到值得花费人力、时间来定义一套DSL?如果只是一般的小问题,其实就用不着大费周章定义一套DSL,至于哪种问题算大,哪种问题算小,这恐怕还得看每个case的情况,以及靠经验来判断。
Good judgment comes from experience. Experience comes from bad judgment.
Jim Horning
其次,如果DSL 由领域专家负责撰写,领域专家与程式设计师之间的沟通可能会是比较棘手的问题。而且,在结构化设计与物件导向设计世代交替时,系统分析师已经历过一段学习UML 的痛苦期,现在又要他们学习另一套(甚至多套)DSL,这恐怕会造成不少反弹。
开发人员的逆袭
UML最近几年在软体工程领域可说是引领风潮,然而,随着时代进步,更新更好的开发技术会不断出现,UML的地位也势必面临挑战。这应是好事,至少可以提醒我们:到底UML对软体开发带来哪些好处?我们是否过度使用、推崇、甚至迷信UML,以至于碰到任何问题都只想着该用哪种UML图来表达?正如Abraham Maslow说的:「当你手中只有铁槌,你会倾向将所有碰到的问题看成钉子。」
个人的看法还是以实用观点出发,在分析设计时,碰到觉得适合用UML 图形表达的,当然还是用UML,但不用太在意如何第一次就把图画得尽善尽美,以及设想如何好好的保存这些图,以免大部分的注意力局限在画图这件事情上,原本分析设计的目的反而被模糊掉。
如果您有使用UML,我想您应该会同意UML 仍有它擅长的地方(表达较高层次的抽象概念),而且它仍然有持续扩充的机会。毕竟,UML 已经是广为接受的表示法,在既有的基础上改进,总是比另创一套新的语言更省力,这也是某些UML 拥护者的看法。
从塑模的角度来看,UML是从比较高抽象层次的角度出发,尝试以通用的表示法来呈现系统分析设计的结果,然后逐渐细化,衔接到软体的实作。DSL则是强调与实作更紧密的整合,虽然它也是一种塑模语言,但我觉得它是比较从程式开发人员的角度出发,一种由下往上衔接的尝试。这样的尝试能否成功?从现有的文章、讨论、和书籍来看,微软大约是从2003年开始研发推广DSL和软体工厂的概念,到现在已过了四个年头,从Visual Studio对DSL的支援,我们可以看出微软正逐渐落实软体工厂的理念。此方法若能广为软体开发社群接受,想必又是一次典范转移。至于结果如何,还是让时间来回答吧。小结 DSL的目标很明确,就是要协助软体开发人员提高生产力。然而,要吸引更多软体开发人员的目光,需要的是强大的辅助工具和令人眼睛为之一亮的杀手级应用。在这方面,微软正不断地加强DSL Tools,而且微软一向强调eat your own dog food(吃自己做的狗食),再加上愈来愈多专家(如Martin Fowler)的投入,其后续发展颇值得我们关注。此外,如Steve Cook所言,DSL只是协助软体开发的其中一项工具,我们还必须有灵活的(agile)开发流程(process)、软体框架(framework)、以及模式(patterns)的搭配,方能大幅提高生产力,而其最终的理想目标,是让软体开发也能像制造业的生产流程一样,建立具有多条产品线的软体工厂[2]。关于软体工厂的概念,可以参考Jack Greenfield的文章[3];他和Keith Short、Steve Cook、以及Stuart Kent等人合着的《Software Factories》有更完整详细的介绍,中研院的吴信辉先生也曾发表过一系列「细说软体工厂」的文章,可以用Google找到一些。
Martin Fowler, " Language Workbenches: The Killer-App for Domain Specific Languages? "
URL: http://martinfowler.com/articles/languageWorkbench.html
Steve Cook, " Domain-Specific Modeling and Model Driven Architecture, " MDA Journal, January 2004.
Jack Greenfield, " Software Factories: Assembling Applications with Patterns, Models, Frameworks, and Tools. "
URL: http://msdn2.microsoft.com/en-us/library/ms954811.aspx
作者: Huanlin Tsai 于 4/21/2008