现在软件产品都面临着快速高质量的要求,而我们也在一直追求着这个目标。项目管理软件规模较大,定制能力要求强,规模化开发也是一个很重要的目标。
影响生产力的现有主要因素
- 业务领域设计研究不够深入。
当业务复杂而又缺乏良好的设计时,那它就会变得难以重构和组合。越来越多的领域规则被嵌入到查询代码中,大部分数据访问基础结构的技术复杂性,很快使得客户代码陷入混乱。由于开发人员不能够确切的知道整个系统的功能,重复问题就产生了。我们可以对那些类和方法进行分解使之便于重用,但这样一来各个小部分分别有什么作用又变得难以跟踪。一个缺乏清晰设计的软件,单是看到其中的混乱结构就会让开发人员头脑发晕,更不用说对设计进行修改(那只会使设计更加混乱),有时甚至会由于意料之外的依赖关系而导致设计完全无法工作。这种脆弱性导致我们无法构造出行为更加丰富的系统(除非系统的规模相当小),也阻碍了重构和迭代精化的进行。 - 基础架构通用设计问题。
比如权限、流程、报表基础设施的支持,效率、应用模式的支持。 - 技术本身带来的问题。
比如配置文件的管理,工具支持不够,新技术带来的学习曲线,底层技术的质量。
其他主要因素
产品的快速和质量是由需求、开发、测试共同完成的,影响进度和质量的不能只考虑技术本身,可能我们开发的方法就未成型,可以改善的地方可以更多。所以我认为对现状的改善不能只关注软件技术,而需要对软件工程领域多投入一些关注。
那么如何才能快速开发高质量的产品?如何才能提高我们的生产力?下面描述一下我的一些观点。
领域开发
-
领域驱动开发
很多原因都会造成软件开发的复杂性,然而其核心则是由于问题领域本身的复杂性。控制复杂问题的关键是建立一个好的领域模型,它越过问题域的表象介绍其底层的 结构,给软件开发人员提供所需的方法。领域驱动设计的一个核心的原则是使用一种基于模型的语言。因为模型是软件满足领域的共同点,它很适合作为这种通用语 言的构造基础。
-
特定领域开发
我们现在使用通用语言开发时,是利用编译器将代码编译成可执行的程序,不需要去直接修改二进制而是修改代码然后重新编译。特定领域开发也类似与一般开发,当发现软件有问题时,我们不是直接修改代码,而是修改领域模型,然后利用工具将模型转成代码再进行编译或者直接将模型转为配置。使用特定领域开发将大幅提升我们的生产力。
特定领域开发强调更安全、更高层次的自动化。它在软件业中已经应用比较广泛,也存在多种相关的方法,例如产生式编程、软件工厂、特定领域建模(DSM)、面向问题语言(LOP)、模型驱动架构(MDA)、意图编程等。以上各个方法之间存在一些类似之处,在我工作中借鉴了部分产生式编程、软件工厂和DSM的思想,这几个也是我一直觉得比较好,希望在产品中更加深入应用的一些方法,下文我将介绍软件工厂相关的一些方法。
软件工厂
软件工厂由四个基础构建块组成,分别是产品线工程,架构框架,模型驱动开发和构建指南。
-
产品线工程
- 软件产品线是指具有一组可管理的共同特性的软件密集性系统的集合,这些系统满足特定的市场需求或任务需求,并且按预定义的方式从一个公共的核心资产开发得 到。构建一个产品主要工作是组装或生成,而不是重新开发,主要活动是集成而不是编程。每条软件产品线都有一个预先定义的指南和计划,用来定义确切地产品构 建方法。
- 在软件产品线方法中,重用是有计划的、能够实现的和强制的。资产库包括从一开始就花费大量成本进行开发的各类产品-即需求、领域模型、软件构架、性能模型、测试用例和组件。所有资产都是为重用而设计,并且为了能重用与多个系统进行了优化。
- 产品线中每个产品都是核心资产的一个简单定制,核心资产必须认真设计并不断重构。
- 产品线核心关注范围、通用性、可变性和扩展点
软件产品线活动概述
一个产品线是基于商业策略,满足给定市场的一组系统。产品线开发区别两种活动:为重用而开发(for reuse)和使用重用来开发(with reuse)。传统重用方法主要是基于代码的重用,而软件产品线的重用包括在产品开发生命周期各阶段的资产。如上图所示,软件产品线工程由领域工程和应用工程组成。
领域工程
- 纵向领域(vertical domain):根据系统类别而组织的领域。如预算软件、材料管理、合同管理、企业报表系统等。
- 横向领域(horizontal domain):根据软件部件的类别而组织的领域。比如数据关系计算引擎、报表引擎、工作流系统等。
- 领域之间有3中类型的关系:
- 包含:比如成本管理软件包含了材料管理系统
- 使用:比如公司大部分软件都使用了报表引擎
- 类似:领域之间侧重点不同,但有很多的相似性,通过深入研究一个领域,可以取得对另一个领域的更好理解。比如报表引擎中对于表达式解析和索引部分可能与数据关系计算引擎类似。
应用工程
应用工程是基于领域工程的结果构建系统的过程。对一个新的具体应用做需求分析的时候是利用已有的领域模型,通过领域分析提供的各种通用功能、支持的变量配置、 提供的扩展等来描述客户需要。如果新的需求在领域模型中不存在,则可以定制,或者反馈到领域工程来扩充领域的支持范围。
软件产品线工程框架
上图是软件产品线工程框架图。框架分为两个阶段:领域工程和应用工程。领域工程产出平台的公共核心资产,应用工程产出产品。在整个开发生命周期中,存在9个 子流程,八个流程互相匹配成四组类似流程,需求、设计、实现和测试在领域工程和应用工程都存在,每一匹配组的流程都紧密相连。领域工程的子流程目的在于满 足通用需求,而在应用工程是为了生产可供使用的产品。应用工程的子流程需要提供反馈给领域工程,这种循环反馈才能确保平台一直都能有效的生产出最终产品。
基于BAPO的系统族评估框架(FEF)
BAPO模型覆盖了软件工程的主要关注点。这四个关注点(商业、架构、流程和组织)成为了FEF的四个评估维度。每个维度有五个级别,并且有三到四个方面。
领域工程开发活动大纲
产生式编程方法中对领域工程开发的各个活动进行介绍。
1.领域分析
- a) 领域定义
- i. 目标和风险承担者分析。此活动的工作量依赖于项目的大小和上下文。
- ii. 领域范围界定和上下文分析
- 应用领域和现有系统的分析
- 领域特征的确定
- 与其他领域关系的确定
- b) 领域建模
- i. 关键概念的确定
- ii. 关键概念的特征建模(共同点、可变性、特征依赖和特征交互)
2.领域设计
- a) 整个实现架构的确认和规范
- b) 领域特定语言的确认和规范
- c) 配置知识的规范
3.领域实现(DSL、产生器和实现组件的实现)
4.领域测试
-
模型驱动开发
MDD建立在更高级别的抽象基础上,不同于传统使用类、方法、属性抽象软件,而是使用业务领域概念(比如工作流模型、实体关系模型、报表模型、界面描述模型等)来描述模型。代码生产和领域特定语言是模型驱动开发的一些重要概念。
DSM的三个核心元素
有经验的开发员人都希望能达到一下目标:
- 不重复自己:不反复做同类设计,拷贝粘贴代码,大量重复劳动
- 三次重复后就该考虑自动化
- 定制方案比通用方案更好
DSM是领域特定建模,可以很好的解决以上三个问题。定义模型语言,代码生成和框架代码是DSM的三个主要元素。在工作中在UI方面采用元数据驱动的方法,很好的解决了以往UI带来的重复工作以及很好的提高了这方面的软件质量。通过定义UI的元数据模型,项目运行框架通过生成的元数据信息来自动生成界面并绑定数据和操作事件。
代码和模型
代码和模型一般存在以下几种模式,DSM属于最后一种。
DSM开发角色
在以前的基于组件开发技术中,有人开发组件,有人使用组件。在产品线开发中,一部分人开发所有项目通用的平台,一部分人使用这些资产进行开发。DSM开发组织机构与这些方法类似,也区分两种不同的角色:开发DSM解决方案的角色和使用DSM进行开发的角色。
在DSM中我们可以定义出以下几种角色:
- 领域专家:有DSM应用的问题领域的丰富知识。他们知道术语、概念和领域规则。当开发业务系统时,专家懂得业务知识。如果是技术领域,则架构师和开发经理就是领域专家。
- DSM用户:使用模型语言进行开发。这个角色的人员最多。模型在高级别层次上进行抽象,很大程度上支持测试、产品管理、QA、实施、销售和客户等多种人员进行沟通。测试人员可以使用模型建立测试用例,部署人员可以生产安装程序,管理人员可以获取度量信息等
- 基于特定模型语言的语言开发人员:设计元模型,并提供使用指导和模型示例。语言开发人员与领域专家和关键DSM用户关系密切。
- 生成器开发人员:从模型转换成代码。通常生成器开发人员也是定义领域框架的人员。
- 领域框架开发人员:通常是有应用架构的经验开发人员。他们提供在目标环境下的参考实现,并且已经开发过组件框架、类库等。
- 工具开发人员:实现模型语言和代码生成器的工具支持。
- 架构框架不同于一般产品的开发框架。架构框架的需求来源是产品线所有产品的共性,架构需要实现所有共性,灵活实现变化点,并支持独立产品的扩展点。
- 架构不是瀑布式的,不是一层不变,而应该随着开发迭代周期不断的重构演化。
-
架构框架
-
构建指南
对产品线产品实现的最佳实践,指导开发人员什么时候该做什么以及怎么做,可以降低学习曲线,并减少错误。
模型驱动开发应用目标
通过几个转变来改变长期的工作方式:
- 面向通用语言 –> 模型驱动开发。使用特定模型,提高产品生产力和质量。
- 基于数据库开发 –> 领域驱动开发。减少业务领域设计研究不够深入带来的问题
- 开发人员驱动 –> 业务人员驱动
现在主要工作围绕大量开发人员,通过模型驱动开发,业务分析人员可以建立模型,需求分析、编码、测试人员将基于统一模型进行工作。软件开发人员逐步像分析设计人员发展,底层设计编码由少量具有经验的开发人员承担。