敏捷与结构性模块化(二)

阅读数:1620 2013 年 12 月 2 日 06:20

上一篇文章中,介绍了结构性模块化与敏捷之间的关系,在这个系列的第二篇文章中,我们将会研讨OSGi™,在实现Java™的结构性模块化方面,OSGi 扮演了核心的角色;OSGi 与流行的敏捷方法论之间存在着自然的联系。

1 但我们已经实现了模块化!

绝大多数开发人员都同意程序应该模块化。尽管在面向对象的程序设计出现的早期,逻辑性模块化的要求就被迅速满足了(见 http://en.wikipedia.org/wiki/Design_Patterns ), 但是软件行业花费了很长的时间才理解结构性模块化的重要性。特别是,结构性模块化可以提高程序的可维护性和灵活性,控制和减少环境带来的复杂性。

只是 JAR 文件的组合

在《Java Application Architecture》(本书已经由机械工业出版社引进出版,中文书名为《 Java 应用架构设计:模块化模式与 OSGi 》——译者注)一书中,Kirk Knoernschild 探索研究了结构性的模块化,并建立了一套关于结构化设计的最佳设计模式。Knoernschild 认为,在模块化风潮中并不需要开发模块化的框架;对于 Java,JAR 文件结构就足够了。

敏捷与结构性模块化(二)

事实上,在“敏捷”开发团队中根据代码库的增长将应用分解为较小的 JAR 文件的做法并不罕见。随着 JAR 文件大小的增加,他们会被分解为更小的 JAR 文件的集合。从代码角度,特别是如果遵循 Knoernschild 的结构化设计模式,我们会认为,从某个结构层看,程序是模块化的。

但这是否敏捷?

从创建应用的团队,以及负责随后维护人员的角度来看,应用是更敏捷的。团队了解依赖关系,以及变化的影响。然而,这种知识并没有关联到组件上。一旦团队成员离开了公司,程序和业务就有可能立刻受到影响。同样,对第三方(即使是同一个组织的不同团队)来说,该应用可能依然是单独的巨大代码库。

如果程序中只有一层结构性的模块,它必然不是自描述的。由于缺乏描述模块之间内在关系的元数据,由此产生的业务系统本质上是脆弱的。

那么 MAVEN 呢?

Maven 文档(项目对象模型,Project Object Model——POM)也能表达组件之间的依赖关系。这些依赖关系由组件的名称定义。

鉴于此,基于 Maven 的模块化程序可以被任何第三方很容易地整合起来。然而,在上一篇文章我们已经提到,由名称定义依赖关系是有缺陷的。由于组件之间的依赖关系并不能明确表明需求(Requirement)和功能(Capability),第三方不能推断出依赖关系的存在原因和可替代的部分。

程序可以被整合,但却不能变更。这种方式是否使得程序比之前的“JAR 文件组合”更为“敏捷”还值得商榷。

对 OSGi 的需求

就如 Knoernschild 在《Java 应用架构设计》中阐述的那样,一旦实现了结构性模块化,我们很容易就能将它迁移到 OSGi 之中,也就是 Java 领域中的模块化标准。

OSGi 不仅帮助我们保证结构性的模块化,它同时提供了必须的元数据来保证我们建立的模块化结构也是敏捷的结构。

OSGi 通过需求和功能表达依赖关系。因此,第三方可以立刻知道哪些组件可能是可替换的。因为 OSGi 同样使用语义化的版本控制,所以第三方可以立即推测出,某个组件的变更是否有破坏系统的潜在危险。

OSGi 同样也具有展现结构化层次的能力。

在模块化的一端,我们使用面向服务的架构(Service Oriented Architecture,SOA);在另一端,我们使用 Java 包和类。然而,正如 Knoernschild 表述的那样,在这两端之间缺少了必要的层次。

敏捷与结构性模块化(二)

图 1: 结构化层次:缺失了中间的部分(Kirk Knoernschild – 2012)

中间缺少层次的问题,在 OSGi 中得到了直接的解决

敏捷与结构性模块化(二)

图 2: 结构化层次: OSGi 服务和 Bundle

正如 Knoernschild 所描述的,OSGi 所提供的模块化层次解决了一些比较关键的问题:

  • 代码的重用:通过使用 OSGi Bundle,能够促进代码的重用。
  • 进程内和进程间的重用:OSGi 服务是轻量级服务,允许相互间动态寻找或绑定对方。OSGi 服务可能发布在相同的 JVM 中,也可以通过实现了 OSGi 远程服务规范的工具发布在网络内的分布式 JVM 中。粗粒度的业务程序可能是由数个更小粒度的 OSGi 服务组成的。
  • 部署单元:OSGi Bundle 提供对自然单元进行部署、更新和补丁的基础功能。
  • 组合单元:OSGi Bundle 和服务在组合的等级结构中都是基本要素。

因此,OSGi Bundle 和服务作为 OSGi 联盟开放规范的主要部分,为 Java 提供了之前缺失的、结构性模块化中的重要层次。原则上,OSGi 技术使基于 Java 的业务系统实现“敏捷——从上至下贯穿各层”成为可能。

我们现在可以看到,OSGi 的结构(Bundle 和服务)与流行的敏捷方法论很匹配,并且能够促进它们得以实现。

拥抱敏捷

敏捷运动主要关注于实现敏捷的产品开发和交付相关的流程(Process),当前已经存在一些精益与敏捷(Lean&Agile)的方法,其中的每一种都是两种广为人知的方案的变种、混合或延伸。这两种方案就是 Scrum 和 Kanban( http://en.wikipedia.org/wiki/lean_software_development )。

为了每种方案更加有效,都需要在某种程度上具有结构性的模块化。

Scrum

客户一直在改变他们的想法。Scrum 承认“需求改动(requirement churn’)”的存在,并且采用基于经验的( empirical ,http://en.wikipedia.org/wiki/empirical)方式完成软件的交付。Scrum 承认问题不能完全被理解或被预先定义。Scrum 着重于最大限度地提高团队能力,以更快完成交付并解决更多新的需求。

Scrum 是迭代式渐进的增长过程,以“Sprint”作为基本的开发单元。每个 Sprint 都是在“固定时间(time-boxed”(http://en.wikipedia.org/wiki/Timeboxing)内的工作,即它有一个明确的期限。对于每个 Sprint,它的期限是事先固定的,一般在一周到一个月之间。Sprint 开始之前会有一个明确任务和目标的计划会议,Sprint 之后会有一个回顾会议,这个会议上要评估进度并总结本 Sprint 的经验教训。

每个 Sprint 的期间,团队将完成产品的一部分。纳入 Sprint 的特性来源于产品的 backlog,这是一个按顺序排列的需求(http://en.wikipedia.org/wiki/Requirement)列表。

Scrum 鼓励创建自组织的团队,这通常需要团队所有成员的协同工作和口头交流实现。

Kanban

“Kanban”起源于日语,意思是“布告板”或“看板”。它的根源可以追溯到 20 世纪 40 年代后期的日本丰田汽车制造公司(见 http://en.wikipedia.org/wiki/Kanban )。Kanban 鼓励团队对工作、工作流程、进程、风险等建立共同的理解,以此团队将取得在某个问题上的共识,然后在此基础上提出能够达成一致的改进方案。

从结构性模块化的角度来看,Kanban 的重点在于在制件(Work-In-Progress, WIP)、有限的发布和反馈,可能这是该方法中最为有意思的:

  1. 在制件(WIP)一定是处在一个多级工作流的某个步骤。当目前的 WIP 所规定的流程完全走完后,在下一阶段有处理能力的情况下,工作将被“拉”到下一阶段。
  2. 工作在每个工作流程的进度都是受监视的、可评估、可报告的。通过积极地管理流程(flow),我们可以对那些持续发生的、增量式的以及渐进的升级变更对系统所产生的积极或消极影响进行评估。

由此可见,Kanban 鼓励持续的、增量式的以及渐进的系统变更。随着结构性模块化的程度得到提高,流动率也同时增加,而每个更小的模块将消耗更少的时间处于“在制品”状态。.

敏捷成熟度模型

随着结构性模块化程度的提高,Scrum 和 Kanban 的目标将更容易实现。能力成熟度模型(Capability Maturity Model ,参见 http://en.wikipedia.org/wiki/Capability_Maturity_Model),主要被公司或项目用于估测它们在软件开发过程获得的改进。同样的,模块化成熟度模型(Modularity Maturity Model)更倾向于描述组织或项目在模块化方面上的进展,这个概念是由 Graham Charters 博士在 OSGi Community Event 2011 上 (参加 http://slidesha.re/ZzyZ3H) 提出的。现在我们扩展一下这个理念,分析模块化成熟度模型对企业在敏捷方面的影响。

模块化成熟度模型的阶段总共分为以下六个阶段:

特定的(Ad Hoc——没有任何正式的模块化内容。依赖关系不明。Java 程序没有或很少有什么结构可言。在这种环境下,敏捷管理流程将无法实现商业目标。

模块(Module——不再直接使用类(或者包含类的 JAR),而是使用有清晰的版本规范的模块,依赖关系可由模块的标识确定(包括版本名)。Maven、Ivy 和 RPM 就是这类模块化解决方案的例子,在这里依赖通过版本化的标识符进行管理。企业一般都有存储这些模块的库。然而这些库的价值并没有完全体现出来,因为这些模块没有描述它们的功能和需求。

许多企业内部的研发团队都在这一级别的成熟度。象 Scrum 这样的敏捷流程是可能的,而且也对企业提供了一些价值。然而,流程在有效性和扩展性方面的最终收益将会因为结构性模块化而受到限制。例如模块间的需求和功能通常通过口头进行交流。这些没有良好定义的结构化依赖同时会影响到持续集成 (Continuous Integration, CI)方面的能力。

模块化(Modularity——模块的标识并不同于真正的模块化。我们已经知道模块的依赖关系可以通过契约关系(即功能和需求)而不是组件名来进行表述。在这一点上,基于功能和需求表述依赖关系的解决方案,成为动态软件组建机制的基础。这个层次的结构性模块化依赖同时会使用语义化的版本。

通过采用如 OSGi 之类的模块化框架,Scrum 过程中扩展性的问题也得到了解决。由于强制封装,并使用功能和要求来定义依赖关系,OSGi 使得众多小团队可以进行独立且高效的开发,而且这些开发可以并行。Scrum 管理工作的效率也能获得相应的提高。每个 Sprint 能够关注于一个或多个事先定义好结构实体,也就是 OSGi Bundle 的开发或重构工作。同时,语义化版本命名规则,使得不同的团队之间能高效地交流。因为 OSGi Bundle 提供了有效的模块化和隔离机制,并行的研发团队可以在同一应用中的不同结构范围内安心地工作。

服务(Service——对于用户而言,基于服务的协作方式隐藏了服务的构建细节。客户端与提供者的实现之间能够实现解耦。由此可知,服务提倡松散耦合。具有动态寻找和绑定功能的 OSGi 服务直接支持了松耦合、动态结构、应用的整合或装配等功能。更为重要的是,服务是实现运行时敏捷的基础,包括快速增强业务功能或自动适应环境的改变。

结构性的模块化达到了这一层次,企业可以简单而自然地运用 Kanban 原理,并达到可以持续集成的目标。

委托(Devolution——文件的所有权移交给模块化的资源库,资源库鼓励协作和统一管理。资产会根据它们所声明的功能自动选择。这样做的好处包括:

  • 对已有的模块更加了解
  • 减少重复工作并提高质量
  • 协作和授权
  • 质量和操作控制

因为软件具有一套完整的需求和功能说明,开发人员能通过语义化的版本与第三方交流模块的变更(破坏性的或非破坏性的)。委托机制允许开发团队按其需求快速找到第三方伙伴的软件。委托机制保证了灵活的软件创建方式,使分布的团队能够以更为有效的方式进行交流。软件可以是由同一组织的其他团队创建,也可以使用外部第三方的软件。委托机制阶段提高了代码重用度和效率,降低了外包、众包、内包在创建软件制件方面的风险。

动态化(Dynamism——这个等级建立在模块化、服务和委托的基础之上,并且是敏捷的顶点。

  • 可以根据模块化组件快速地装配出业务程序。
  • 因为保证了高度的结构性模块化(通过 OSGi Bundle 的边界进行隔离),组件可能被众多小的开发团队——本地、近岸和离岸(on-shore,near-shore,off-shore)——高效率地创建并维护。
  • 因为每个程序都是自描述的,即便最复杂的业务系统也可以很容易地被理解、维护和改进。
  • 因为使用了语义化的版本,变更的影响可以在所有参与人员之间得到有效的交流,这包括管理和变更控制流程等。
  • 软件的补丁可以热部署到产品中,而不需要重启业务系统。
  • 可以快速地扩展和启用程序功能,同样不需要重启业务系统。
  • 最后,因为动态装配进程知道运行时环境的功能,程序的结构和功能会根据环境自动调节,实现了在共有云或传统数据中心环境中的透明部署和优化。

敏捷与结构性模块化(二)

图 3 模块化成熟度模型

组织的模块化演变(Modularisation Migration)策略,将由贯穿这些模块化等级的路径所决定。大多数组织已经从最初“特定的”阶段发展到“模块”阶段。同时,有些重视高度敏捷的组织希望跨入终点,即动态化。每个组织可能通过数种路径,配合必要的发展策略,从“模块”达到“动态化”。

  • 为了尽快地实现收益,组织可能会通过将现有代码重构为 OSGi Bundle,从而直接发展到“模块化”阶段。随后自然就能获得“委托”和“服务”的好处。对于未开发的应用显然也要采取这种策略。
  • 对于遗留的程序,可选择先达到“服务”阶段。首先,把粗粒度的软件组件用 OSGi 服务来表达,随后,在每个服务的层面上推动代码级的模块化(即 OSGi Bundle)。对于那些拥有许多遗留程序的大型企业,这是一条更加容易的路径。
  • 最后,通过对现有的软件采用 OSGi 元数据,企业可以开始初步到达“委托”阶段。需求与功能的采用,加上语义化版本的使用,都能为第三方明确地描述现存的结构以及变更的影响范围。尽管结构性模块化并没有得到提高,但是“委托”阶段使得企业以后更便于到达“模块化”和“服务”的层级。

拥有不同的选择以及根据具体的场景实践这些选择,正是我们所期望达到的更加敏捷的环境。

原文英文地址: Agility and Structural Modularity – part II

作者简介

Richard Nicholson是 Paremus 的 CEO 和创始人,这是一个 2001 年成立的软件公司,总部位于英国。

在意识到高度可维护以及高度敏捷的系统在本质上必须是高度模块化的之后,Paremus 在 2004 年开始研究下一代的软件系统。这种持续的努力体现在了 Paremus Service Fabric 产品之中,这是一个高度可适应的、基于 OSGi 的自装配运行时,可用于企业级和云环境。作为 OSGi 联盟的主席(2010-2012),Richard 开始推进 OSGi Cloud 并鼓励 OSGi 联盟参与到敏捷软件社区中。

Richard 在很多的研究领域都保持了浓厚的兴趣,这支撑了 Service Fabric 的研发,他的研究领域包括复杂的适应性系统(Complex Adaptive System)以及敏捷(Agility)、模块化组装(Modular Assembly)、结构化多样性(Structural Diversity)和适应性(Adaption)之间的关系。

成立 Paremus 之前,Richard 在花旗集团 /Salomon Smith Barney,领导着欧洲系统工程(European System Engineering)相关的工作。Richard 获得了曼切斯特大学的物理学荣誉学位,并在格林尼治皇家天文台( Royal Greenwich Observatory)获得天体学物理博士。

Richard 的博客: http://adaptevolve.paremus.com

Paremus 的博客: http://blogs.paremus.com


感谢张卫滨对本文的审校。

给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

收藏

评论

微博

用户头像
发表评论

注册/登录 InfoQ 发表评论