写了多年代码,但是在架构方面没专门系统的去学习过。去年部门对支撑客服业务的系统重新建设了一遍,在架构上做了一些域的划分,感觉还是比较有效果的。最近自己手上负责的一个系统需要支持多租户,在做升级改造,但感觉比较吃力,缺少点套路。所以想找些这方面的书籍学些提升下,于是找到了Bob大叔的《架构整洁之道》,也是我读的第一本架构方面的书。下面针对我自己感触比较大、有收获的地方做下罗列。
本书给我最大的感受是对组件依赖关系的理解,这里有两个原则,一是稳定依赖原则,依赖关系必须要指向更稳定的方向。二是稳定抽象原则,稳定的组件应该是抽象的,这样它的稳定性就不会影响到扩展性,另一方面,该原则也要求一个不稳定的组件应该包含具体的实现代码,这样它的不稳定就可以通过具体的代码被轻易修改。另外底层组件要依赖高层组件,我们的业务逻辑应该属于高层组件,而数据库、web、应用程序框架都属于细节,属于底层组件,应该以插件的形式接入,构成一个整洁的嵌入式架构。
SOLID原则。讲几个。SRP(单一职责原则),每一个软件模块都应该只对一个用户或者利益相关者负责。LSP(里氏替换原则),书中对此概念描述的不是很好。感觉这样描述更容易理解:“子类所在的地方用父类替换时行为保持不变”。该原则指导我们如何正确的使用继承关系。想起自己以前写的继承类就违反了该原则,在子类里滥用了重写。子类原则上不应该重写父类中已经实现的方法。ISP(接口隔离原则),想想之前写的系统里面一个接口类里面包含了多少方法,囧。
代码复用的理解,我之前在项目中出现重复代码都会抽到一起集中管理,对于复用确实没错,但是这不一定对的,重复代码因为处在不同的业务中,随着业务变更、需求迭代,原本相同的代码会出现差异。如果抽到一起可能会出现各种if else逻辑,最后变的难以维护。所以不要看到重复代码就想着要合并以做到复用,在操作之前分析下是否会出现分化的可能。
代码依赖与控制流,代码依赖跟控制流并不一定是一致的。我们的控制流一般是这样的:展现层->应用层->领域层->基础设施层(持久化等),但是我们的代码依赖应该是展现层->应用层->领域层<-基础设施层。基础设施层应该依赖于领域层。这就是依赖反转控制。如何做到这一点也很简单,通过在领域层设置接口,基础设置层来实现这些接口就行。
架构包括的设计内容,软件架构不仅要设计开发、部署,还涉及运维、测试,而且同样非常重要。
Main组件,Bob大叔认为系统启动的入口main也应该设计成组件,main组件是系统中最细化的部分——也就是底层的策略。Main组件的任务是创建所有的工厂类、策略类以及其他的全局设施,并最终将系统的控制权转交给最高抽象层的代码来处理。而且Main组件也可以视为应用程序的插件,比如可以设计专门针对生产环境的main组件、测试环境的main组件。
架构测试,测试也是一种系统组件,也要遵循依赖关系原则,而且可以独立部署。Bob大叔讲到了可测试性设计原则:要不依赖于多变的东西。回想我们的自己的系统,我们是一个工作流系统,要完成一个业务流程的集成测试需要多个角色按步骤来的完成页面操作,记得当时我们的测试同学花了很大的精力开发了UI自动化测试工具,测试系统可以自动登录测试账号做页面UI的点击操作。但是页面UI经常做修改,测试维护成本非常大,所以过不了多久就用不了了。这也就是书中提到的脆弱的测试问题。现在想来,我们应该基于测试专用API来构建我们的测试用例。
事件溯源,书中的描述增加了我对此概念的理解,书中是这样描述的,在这种体系下,我们只存储事务记录,不存储具体状态,当需要具体状态时,我们只要从头开始计算所有的事务即可。而我们实际并没有这么做,是因为我们没有足够大的存储量和处理能力来满足需求。所以我们在用CQRS架构设计系统的时候,往往不会完全照搬,会舍弃时间事件溯源。但我们一直在使用的git就是以这种形式在工作的!
指标量化,书中给我们提供了稳定性指标、组件抽象化程度指标的测量方法,居然可以量化分析,有么有很6。
架构细节保证,这一部分是由Simon Brown撰写的。中心思想是,如果不考虑具体实现细节,再好的设计也无法长久。确实在我们架构系统的初期,设计往往是比较合理的,但随着时间推移,特别是新同学的加入,因为对系统架构思想不理解,系统变得越来越乱。作者其中提到可以利用编译器来维护架构设计原则。比如java可以通过控制类的访问修饰符(protected),限制被外部直接访问(依赖)。在java语言中还有osgi、java9模块化等方式可用。