我们何时可以认为软件产品被真正地完成了呢?通常情况下,当我们不再为其提供后续支持,或者该产品已经 被其它产品替代的时候,它的生命就终结了,几乎所有软件产品都会经历从开始到结束的演化过程。但存在了很长 时间的大型企业级系统却会随着时间的推移,向不可维护、变僵硬的趋势发展。这导致了软件开发的停滞,使得响 应客户需求的时间变长。
本文说明了如何使用MDSD方法来决这些问题。文章首先介绍了我们要解决的问题——向后兼容性问题和升级问 题,说明了为什么这些问题很难解决,然后描述了在当前的软件体系结构中容易隐藏非功能性关注面的地方。
文章中举了三个例子,用来说明MDSD技术如何帮助我们在不损失灵活性的前提下,解决软件生命周期问题。这 些例子都是来自于电子保健行业中的真实敏捷项目,作者还说明了其中的最佳实践可以怎样应用于其他情况下。
项目中得到的经验教训被总结为拇指规则(在面对复杂环境时候采用的一种简化或经验性的处理方式,因为理 性的处理能力是有限的),在文章的最后,引用了一些有用的框架与工具,它们是目前解决方案的基础。
介绍
在软件工程领域,经过几年的实践,模型驱动的软件开发(MDSD)已经证明了它并非是昙花一现。如今,MDSD 的很多承诺[1]已经变成现实,大量成功的例子也持续涌现出来。
本文说明了可以如何使用模型驱动方法来解决当前软件系统中的一些问题。牢记MDSD最佳实践[2],我们将关注 软件生命周期本身这个非功能性需求。
软件生命周期
几乎所有的现代软件系统都面临着生命周期问题。当产品发布或是部署时,你不得不解决向后兼容以及迁移策 略等问题。我们通常会低估产品兼容性问题,或是在开发中完全忽略这个问题。当我们不得不花费很多资源来解决 产品兼容性问题时,才会后悔莫及。严肃地看待这个问题会影响到软件产品的演进,正如我们将在下面这个例子中 所看到的。
案例:java.lang.Cloneable
Java中的java.lang.Cloneable接口说明了向后兼容性是如何限制软件演化的。该接口在JDK 1.0时被引入,仅 作为一个标记,并不提供任何接口方法,想要支持克隆的类型都需要实现这个接口。
此外,它还需要提供 java.lang.Object.clone()方法合适的实现。其实clone()方法如果定义在 java.lang.Cloneable接口中似乎更有说服力,并且更自然。但事实上该接口从未改变过,因为那将会破坏向后兼 容性。引入克隆接口方法会导致对所有已实现该接口的类的编译错误。关于这个bug的完整历史,请参看[3],对于 java.lang.Cloneable更详细的讨论,请参看[4]。
在分析我们系统中已经存在的生存周期问题细节以前,非常有必要建立一个公共术语表。
向后兼容性
如果出现以下情况,那么可以认为该系统是向后兼容的:
它能处理以前系统的接口
它能处理以前系统的数据
该系统的使用者不必关心系统版本改变
系统的修改可能引发向后不兼容的问题。通过引入兼容性层可以解决这个问题,该层负责提供以前系统接口的 视图。在这样的环境中,权衡并设计进-出良好的接口更加重要。
关于二进制与源代码的兼容性在本文中不做讨论,[5]中描述了它们和Java语言之间的差异。
更新
更新描述的是对已有软件的改进。通过一次更新,应用的特性集是不会被扩展的。更新的主要目的在于提供额 外的健壮性(例如修复安全隐患)。更新不会涉及到接口与数据描述的改变,它不会引发向后兼容性问题。OSGi版 本控制体系[6]定义了版本分类模式major.minor.micro。一次更新只增加第三位,即micro位的版本号。