1
1. 熵增的概念
1.1 什么是熵增
熵的概念最早起源于物理学,用于度量一个热力学系统的无序程度。热力学第二定律,又称“熵增定律”,表明了在自然过程中,一个孤立的系统总是从最初的集中、有序的排列状态,趋向于分散、混乱和无序;当熵达到最大时,系统就会处于一种静寂状态。
通俗的讲:系统的熵增过程,就是由原始到死亡的过程。(熵增定律同时也是一个哲学问题)。“熵”是“活跃”的反义词,代表负能量。
1.2 如何反熵增
反熵增,即熵减。是通过系统之外的第三者对其“做功”,实现对孤立系统的“熵转移”,使得原系统的熵总量减少;熵减可以使系统从混乱恢复有序。
2
2.软件系统的熵增
在软件开发、维护过程中。软件的生命力总是从最初的理想状态,逐步趋向于复杂、混乱和无序状态发展,直到软件不可维护而被迫下线或重构。这种损坏软件质量的因素的逐步增长,叫做软件的熵增现象。
2.1 软件熵增的表现
- 代码混乱、新人不易上手
- 代码高度冗余,复用性低,开发效率低
- 扩展和修改困难,牵一发动全身
- 业务数据错乱
- 程序性能低下
- 系统难以移置
- BUG率居高不下
- 其它……
2.2 软件熵增的导因
系统本身缺乏设计和规范的定义
- 开发人员太“个性”,不遵守设计和开发规范
- 开发人员不了解架构,随意更改和扩展
- Leader或架构师对代码的管控缺位
- 特殊或不合理的需求导致的架构妥协
- 赶进度时采用更快捷的“临时解决方案”
- 开发人员缺乏“重构精神”
- 开发团队重业务实现,不重设计。
- 其它……
3
3.软件系统反熵增
从前述的分析,我们现在基本可以明确,软件熵增的根本导因是:架构被忽视,或架构失控所导致。那么,如何进行软件系统反熵增? 答案是对软件架构做“功”。做“功”可以采取的措施如下:
3.1 认识软件架构
当在考虑软件架构时,首先需要明白任何软件系统都应该根据具体的应用和业务场景,而确立一种“架构风格”或“架构模式”。常见的系统架构模式有:
- 分层模式(Layer)
- 管道-过滤器模式(Channel Filter) = 流式(Stream)
- 主从模式(Master Slaves)
- 点对点模式 (P2P)
- 事件驱动模式 (EDA)
- MVC模式(MVC)
- ……
需要说明的是,在确立架构模式时,并非单选项,而是多选项。你可以根据需要将各种架构模式进行嵌套实施。而本次分享,主要是以最为常见,且应用最为广泛的“分层模式”为例来探讨。
3.1.1核心组成
3.1.2 分层
关于分层:
- 按问题域划分的逻辑或实体层次
- 每一层都有清晰的边界
- 越上层越简单,越底层越复杂
- 上层面向用户,底层面向机器
- 分层间自顶向下依赖
- 上层依赖底层是调用,底层依赖上层是通知
- 每一层可单独测试、复用和交付
常见的分层级别有两种:应用服务级 、系统架构级。其中,应用服务级指的是单个进程内部的代码分层。而系统架构级则是整体架构分层,比前者的视野更高。
3.1.3 模块
关于模块:
- 按业务或职能域划分的逻辑或实体模块
- 模块归属于特定的分层,是分层的组成单元
- 每一个模块都有清晰的边界
- 模块的边界取决于领域模型
- 模块是对领域模型的具体实现
-
上层模块依赖下层模块,同层模块间最小依赖
3.1.4 组件
关于组件:
- 组件,概念等同于library
- 组件与模块的特性相似
- 组件的粒度小于模块
- 组件可被包含于模块内部,也可以独立。
- 模块内部组件是私有组件,独立组件是公共组件。
- 组件的交付形态可以是: 类、JAR包、OSGI Bundle、Maven Module、Plugin等。
3.1.5 领域模型
关于领域模型:
- 领域模型,也称概念模型,是软件系统的核心业务模型。
- 领域模型描述的是系统的各个业务实体,以及实体间的关系。
- 领域模型是进行系统架构和模块设计的基础和依据。
- 架构设计的第一步,就是对领域进行建模。
- 领域模型的演进,是随着产品需求变化一起迭代。
- 领域模型设计得越稳定,系统风险越低。
- 我们所熟悉的E-R图,就是领域模型的一种表现形式。
3.1.6 外部对象
外部对象,是指当前软件系统以外的,被当前系统所依赖和引用的外部系统或服务。例如工作流(BPM)、统一权限服务、敏感词检测服务(OCR)等等。通过引用外部服务来完成当前软件系统所需要的特定的功能或者业务。
3.1.7 中间件
关于中间件:
- 中间件是构建业务系统的必需品
- 中间件组成系统的基础架构
- 中间件与业务无关,仅提供公共的技术服务
- 中间件是系统技术选型的结果
- 原则上,系统任意层均可直接依赖中间件
- 其它……
中间件和外部对象,都属于当前软件系统之外的对象。但他们区别在于:中间件是基础,是必须品,他与软件的技术架构有关。而外部对象则与业务有关,但不一定是必须品。
3.2 做好架构设计
在软件设计阶段,需要对软件架构做好概要设计。一般地,需要做以下工作:
- 领域分析与建模
- 确立架构风格/模式(以及中长期规划)
- 模块设计(确立模块边界)
- 系统技术选型(开发框架+中间件)
- 系统部署架构规划
- 定义与编制开发规范
- 开发者培训(架构师对开发者进行培训)
同时,至少输出以下成果:
- 概要设计说明书
- 系统开发规范/手册
3.3 面向架构编程
面向架构编程(OAP),是指开发人员在软件开发过程中,时刻考虑着所写的每一段、每一行代码在软件架构中的位置,以及对架构的影响。这要求开发人员必须具有基本的架构知识和架构思维。通过面向架构编程方法,可以确保代码遵从架构规范,总是保持有序。
面向架构编程(OAP)有以下几点核心要求:
- 系统架构必须清晰明确
- 开发者必须懂架构、了解架构
- 任何代码都要从架构(全局)着眼,考虑合适的位置,而不是随意扩展。
-
人人坚守架构规范的底线
在面向架构编程实践过程中,笔者分享以下几点建议:
- 维护好领域模型(坚持以领域模型为中心)
- 编码时找准代码的位置
- 懂得制造概念(做抽象)
- 处理好依赖关系
- 将复杂问题先分解后串联
- 消化特殊需求,避免特殊处理
- 代码即文档(编写易于理解的API)
- 培养和运用产品思维
3.3.1 维护好领域模型
- 把握好各领域对象之间的依赖关系(依赖方向、类型)。在业务代码进行扩展时,坚守这种依赖原则。坚持以领域模型为主线,可以指导业务代码找到合理的位置。
- 数据库不承载核心业务模型,而仅仅只做数据持久化工具。
- 核心业务模型的实现上浮到业务层,由业务代码实现。
- 领域设计可参考DDD
3.3.2 找准代码位置
开发人员时常有一种感觉:当新开发一个功能,或创建一个类,或扩展一个方法时,代码应该放到哪里最合适? 笔者给出的建议是,按以下导向思路来确立代码的位置:分层->模块->组件。即,根据当前代码的功能和性质,结合我们的架构规范和相关原则。确定代码应该属于哪一个分层,哪一个模块,哪一个组件。
3.3.3 懂得制造概念
当一段功能或业务在原有框架中无法找到合适的位置时,那就创造一个新概念去承载它,实际上就是扩展概念(领域)模型。
在创造(抽象)一个新概念时,需要考虑好新的抽象元素如何与原有的概念模型(领域模型)进行合理的关联和对接。
3.3.4 处理好依赖关系
每一个独立的架构单元,例如分层、模块、组件都应有清晰的边界。当各单元之间必须产生交互时,就意味着依赖关系的建立。各单元间的依赖越简单则越整洁,越复杂则越混乱。处理好依赖关系有利于分层、模块或组件的移植和复用。
举例:在下图所示的依赖关系处理中,依赖方式2优于依赖方式1。
3.3.5 复杂问题的分解与串联
将一个复杂的问题或需求分解成若干个小的问题或功能来实现,然后再将各个小功能串联起来解决大的问题。
问题分解原则:
- 每个子问题之间尽量职责单一,边界清晰
- 问题分解的好处:
- 更有助于理解问题的本质,思路更清晰
- 复杂问题被简单化,减少了出错
- 每个子问题都可能成为复用单元
- 更利于测试和后期维护
-
其它……
3.3.6 消化特殊需求,避免特殊处理
常常遇到一些特殊、个性化需求,与现有的业务和架构相悖。直接实现总显得格格不入。面对这种情况,最好的思路是将这种个性的、特殊需求化解为“通用需求”,避免“特殊化”的存在。可采用的方法主要是考虑对业务流程或概念模型的扩展或调整。
3.3.7 代码即文档(编写易于理解的API)
好的代码往往简洁、模式清晰、易于阅读,而无须过多的注释。开发人员应把自己设计的API当作“产品”,把API的调用者当作自已的客户,做好API的使用体验。
3.3.8 培养和运用产品思维
产品思维可以指导开发者对代码设计进行较好的决策。在此提出几点建议:
- 开发人员应该培养对产品的思考力,在处理业务需求、设计和编码时,可以结合对产品价值、产品理念、产品愿景等相关层面的考虑。
- 在产品和业务层面,能分析和理解需求的本质;能与产品经理对等探讨,能给产品提出“靠谱”的建议。
- 当遇到不合理需求对架构造成不可避免的破坏时,应能提出合理的产品级解决方案来化解需求与技术的矛盾。
3.4 做好架构把控
架构质量的两个把控点:设计评审、代码走查。
其中,设计评审的主要内容有:
- 新功能的架构位置(哪一端?哪一层?哪个模块?哪个组件?)
- 新功能的代码结构(包括但不限于:类图、API定义)
- 新功能、代码与既有架构、代码的连接点,以及外部对象依赖
- 更新的领域模型(可选)
而对于代码走查。是针对审评过的设计,走查代码是否按设计进行实现。
如果代码实现与设计有差异,应解释差异的原因,并重新评估架构影响。
回过头来,所谓架构把控,是指把控好架构分层、模块、组件的边界,以及依赖有关系。
3.4 合理的团队结构
常见的团队结构有两种:梯形结构、扁平结构。
在梯形结构中,普通成员不能直接受理新需求,原因是普通成员往往缺乏架构意识和常识,很容易对架构造成破坏。而因由骨干成员接受新需求,并对需求进行技术方案的设计后,指导普通成员完成编码实现。
扁平结构相对于梯形结构,研发更为敏捷,适合敏捷开发模式。扁平结构中的每一个成员都是骨干,都具有局部或架构设计能力。
团队中各级别成员的分工和能力要求建议如下:
3.4 架构的迭代与传承
4
4 总结
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!