《后端技术面试 38 讲》学习笔记 Day 06
19 | 组件设计原则:组件的边界在哪里?
软件设计的核心目标就是高内聚、低耦合。
组件内聚原则主要讨论哪些类应该聚合在同一个组件中,以便组件既能提供相对完整的功能,又不至于太过庞大。
复用发布等同原则、共同封闭原则、共同复用原则
组件耦合原则讨论的是组件应该包含哪些功能和类,而组件耦合原则讨论组件之间的耦合关系应该如何设计。
无循环依赖原则、稳定依赖原则、稳定抽象原则
稳定依赖原则通俗地说就是,组件不应该依赖一个比自己还不稳定的组件。
公司的技术沉淀与实力,公司的业务情况,部门与团队的人情世故,甚至公司的过往历史,都可能会对组件的设计产生影响。而能够深刻了解这些情况的,通常都是公司的一些“老人”。所以,年龄大的程序员并不一定要和年轻程序员拼技术甚至拼体力,应该发挥自己的所长,去做一些对自己、对公司更有价值的事。
心得体会
- 组件的内聚讲的是 一个组件本身,哪些类应该放进来,哪些类应该独立出去;
- 组件的耦合将的是多个组件之间的关系,其依赖应该是一个稳定的方向;
- 技术的沉淀是会有很多历史原因的,对这些设计、实现的过往,往往是“老人”才会有深刻认识。我们在一家公司里算不算“老人”,不仅是工龄的上升,而是对公司的技术体系发展、业务演变有深刻的认知。
工作体验
- 文中举例了Jdbc的稳定抽象、评论区举了Slf4j的稳定抽象。其实Spring的Resource接口也是,bean的定义就有多种来源,可以是xml,可以是注解。
- 公司的公共服务中心对外提供服务的工具包中,类似User、Position、Org等也都是接口,是遵循稳定抽象原则的。
- 稳定依赖原则也有体验过,当时我想引进一个github上的工程进来作为依赖,TL就看了一下那个工程,是个人维护的工程,认为其稳定性欠佳,让我重新选型,也是这样的一个道理。
20 | 领域驱动设计:35岁的程序员应该写什么样的代码?
原文摘抄
如果你对自己要开发的业务领域没有清晰的定义和边界,没有设计系统的领域模型,而仅仅跟着所谓的需求不断开发功能,一旦需求来自多个方面,就可能发生需求冲突,或者随着时间的推移,前后功能也会发生冲突,这时你越是试图弥补这些冲突,就越是陷入更大的冲突之中。
软件只有需求分析,并没有真正的设计,系统没有一个统一的领域模型维持其内在的逻辑一致性。
领域模型
由于事务脚本模式中,Service、Dao 这些对象只有方法,没有数值成员变量,而方法调用时传递的数值对象没有方法(或者只有一些 getter、setter 方法),因此事务脚本又被称作贫血模型。
在领域模型模式下,业务逻辑围绕领域模型设计。
而领域模型的对象则包含了对象的数据和计算逻辑,比如合同对象,既包含合同数据,也包含合同相关的计算。
领域模型是合并了行为和数据的领域的对象模型
使用领域模型增加新的产品类型的时候,就不需要修改现有的代码,只需要扩展新的产品类和收入策略类就可以了。
在需求变更过程中,如果一个需求和领域模型有冲突,和模型的定义以及模型间的交互逻辑不一致,那么很有可能这个需求本身就是伪需求。
领域驱动设计就是从领域出发,分析领域内模型及其关系,进而设计软件系统的方法。
通常的做法是把整个领域拆分成多个子域。强相关的多个子域组成一个限界上下文。
实体设计是 DDD 的核心所在,首先通过业务分析,识别出实体对象,然后通过相关的业务逻辑设计实体的属性和方法。这里最重要的,是要把握住实体的特征是什么,实体应该承担什么职责,不应该承担什么职责,分析的时候要放在业务场景和限界上下文中,而不是想当然地认为这样的实体就应该承担这样的角色。
并不是领域内的对象都应该被设计为实体,DDD 推荐尽可能将对象设计为值对象。
六边形架构是 DDD 中比较知名的一种架构方式,领域模型通过应用程序封装成一个相对比较独立的模块,而不同的外部系统则通过不同的适配器和领域模型交互,比如可以通过 HTTP 接口访问领域模型,也可以通过 Web Service 或者消息队列访问领域模型,只需要为这些不同的访问接口提供不同的适配器就可以了。
通过领域实体及其交互完成业务逻辑处理才是 DDD 的核心目标。
35 岁的程序员真正有优势的是他在一个业务领域的多年积淀,对业务领域有更深刻的理解和认知。
心得体会
- DDD强调的是业务架构,抽象为领域模型,这个是需要大量业务经验积累的。能够掌握整个领域的才是一个系统的核心思想。
- 把握不住业务,不能理解真正的需求,实践往往容易出偏差、返工,这也是软件工程的软实力,却不可忽视。
工作体验
- 什么人最能够掌握整个系统,就是那些对系统方方面面都可以说的头头是道的人,已经有的功能,没有的功能,他都能十分健谈。这样的人在公司里的体现,有一点就是经常被人请教。
- DDD实施是有难度的,对业务人员是有要求的,需要有业务专家在团队内参与领域模型的完善;对程序员也是有要求的,一方面要理解需求,一方面要懂得编程,一个初级的程序员可能很容易把工程往贫血模式带偏,当这样的程序员数量多的时候,项目就会退化,并且应用层、领域层大量的类也会加重工作量。DDD是真的很难在项目外包,合作开发的项目展开。
答疑丨对于设计模式而言,场景到底有多重要?
原文摘抄
是否要使用各种设计原则和设计模式去设计一个非常灵活的程序,主要是看你的需求场景。如果你的场景就是需要灵活,就是要各种复用,应对各种变更,那么一开始就应该这样设计。
对于软件开发而言,复杂的永远是业务逻辑,而不是设计模式。设计模式是可重复的,可重复的东西即使看起来复杂,熟悉了就会觉得很简单。
《UML 精粹》《敏捷软件开发: 原则、模式与实践》《架构整洁之道》《企业应用架构模式》
心得体会
- 技能还是要付诸于实践,在复杂的业务逻辑(需求场景),才是设计原则和设计模式大放异彩的地方。
- 要有高的眼光,不然事先怎么才能知道应用复杂的架构和设计模式呢?
工作体验
- 新增、修改一整个框架的接入,会导致原有的代码大改。例如部门内的BI平台,原先强绑定于部门内的公共服务中心来做登陆、权限获取等等。而当平台崭露头角,高层希望它能够服务于整个中心,再服务于整个公司,甚至于让子公司、一线业务人员也使用起来。系统定位的变化,就要求接入更多的登陆认证相关的系统。是应该事先考虑到的吗?我想,如果作为架构师、作为业务架构师,建设这个平台之初,是否应该考虑一下?
所幸,公共服务中心的接口设计较为合理,我们平台的代码健壮性也较高,能够在短期内抽象出一整个模块,与多个平台适配。