架构和软件设计想法

为什么选择DSL(下)

2019-04-13  本文已影响32人  ulysses830

软件和组织架构的一致性

先做一个小结,软件面临的核心问题是功能扩展时的成本(人力、时间、故障等综合考虑)。解决的基本思路,其一、引入各种软件设计方法来管理复杂性,过程大体上都可以视为基于抽象的拆分和组合; 其二、分解职责到不同的人,定义明确的边界和运作方式,以获得分工的效率。

正如康威定理指出的,软件架构决定组织架构。软件的复杂性管理方式和人员职责拆分及组织架构应该是同构的。换言之,要么组织混乱、多头管理、大部分人力都是同时进行多个任务,同时代码乱成一团。要么组织结构清晰,任务优先级明确,大部分人专注于-两件事,同时代码质量也还说得过去。不太可能出现一好一坏。其中,软件架构是决定性因素,这是任何研发组织和官僚组织最核心的区别。(这里没有贬低官僚组织的意思,研发组织和官僚组织的目标不同,所以解决方案也不会相同)

基于模型、分层的软件架构

(下述讨论,不包括模块化\组件化、组件间接口管理等问题。这些问题的直接体现业务本质,它们也是架构设计的部分,也有一些拆分的原则,比如业务内聚,相似的过程、依赖相同的数据,边界清晰等等,但不是本文讨论的核心。)

什么情况可以不考虑软件设计?系统足够简单并且看起来不会变得复杂;已经有了针对这个领域的好用的框架和语言。也就是说,要么这个问题太简单不值得解决,要么这个问题已经有了通解,否则就需要考虑设计问题。

如果一个复杂系统又使用相对低级(缺乏抽象机制,如C)的语言——通常是某些大型嵌入式系统, 异常注重性能硬件资源又没法扩展——那么设计问题就会便得生死攸关。架构是顶层设计,它是业务(领域)复杂性的高度抽象,提供系统拆分和组合的基本方法,并提供机制以使得其他设计问题可以延迟决策(最后一点是读<clcanarchitecture>--书想到的,蛮有意思)。

架构设计,第一步做架构级建模。

定义系统包含哪些聚合根(哪些核心的实体?)、聚合根之间的关系,以及哪些东西应该作为核心概念显式的体现在聚合根上。要避免聚合根关系复杂化,网状化,否则系统从起点就已经难以维护了。核心概念实际上是提供给后续设计做拆分的尺规。依据单一 职责原则做具体考量时,不同的角色(架构,业务分析,开发),不同的人之间理解往往相去万里乃至鸡同鸭讲。而核心概念就是要提供基本的共识,它们往往是系统的痛点所在,是降解系统复杂度的枢纽。比如如果一个系统有非常丰富的状态,且复杂的依据状态择路的代码导致系统难以维护,那么“状态”就应该抽取出来,作为核心概念显式的聚合在聚合根上。状态可以作为单一职责的一个标准。比如一个抽象行为有多个实现,每个实现只应该给为状态的一个值服务。

下来应该做分层设计。

典型的Evans给出一个四层模型, 基础设施层,领域层,应用层,用户界面层。基础设施必须有,没有就会重复造轮子,一个造得比一个崎岖;有了基础设施则需要部署某些控制点,避免团队自行开发已有的工具。领域层包含业务的核心知识。应用层是关于领域知识的组合,定义软件功能,提供具体的服务。但要分析关于领域知识的组合是否也是核心的领域知识?如果是的话,领域层可以考虑分成多个子层,毕竟处理组合和般性的业务知识会采用不同的策略。

系统已经从聚合根、核心概念(纵向)和分层(横向)两个方向拆分完毕了,图纸已经画好。如何保证按图索骥就成了问题的关键。靠提升人员能力、价值观宣贯、编码规范、培训、走查、结对编程...这些都不够。既不明确,也不稳定。

架构落地由DSL切入

还是从软件/架构设计落地 和 人员职责定义两个方向考虑。

支持软件设计落地。

DSL的语法元素中,应该包括架构建模中的聚合根和核心概念,并定义它们之间可能的组织和交互形式。这样系统既能显式的拆分到我们期望的基本粒度,又能有一致的组合方式,一致很重要。

有时DSL并不会完整的实现系统,而只是定义框架中的元素和组织形式,具体的实现形式并不关心,DSL会生成一组接口来约束需要用宿主语言具体实现的部分,接口的职责和形式已经是明确的了。这意味着分层结构将中有一层与这部分职责对应。好吧,我说的就是涉及复杂组合的那部分。

可以看出,DSL是一个非常具体的切入点,当采取这套方法后,我们已经抽象出来的概念和拆分的粒度会被形式化。而不会受个人(或组织)的偏好影响,乃至最终腐化到渣都不剩。而采用DSL后,架构的意图,如我佛所言,所得正觉(架构知识),如沙中炼金,一旦炼出,永不复归于沙。

人员职责划分

至少架构师、业务分析师(BA)、开发基于DSL可以各司其职了。

架构师的职责在系统建模、分层之外,增加DSL设计和维护的职责,他交出的成果不再只有文档和PPT,而是具有更强约束性和规定性的DSL语法。

BA用DSL来描述业务,他可以输出DSL文件,这样对开发的约束是明确的,成果可以固化,而且BA的意图更难被扭曲。

开发依据DSL生成的接口填空。

会增加一个新的角色,转换器(编译器)开发者,无论内部或外部DSL,这个职责都是需要的,原则上架构师可以承担这个责任毕竟他最清楚语法的意图,但很可能一个人做不完。

DSL的其他好处包括

在DSL可以描述的范围内大幅提高开发效率;

统一风格(减少编程实现模式层面选择困难);

处理性能的非业务优化(代码实现方式和内存排布导致的优化可以由转换器完成);

可以在转换器内嵌很多检查项,保证代码本身的一致性,而不必要做运行时检查。

可以想象,在转换器身上能做的文章非常多,规模越大,这个好处就越明显。

上一篇下一篇

猜你喜欢

热点阅读