1、程序员的3个层次
1.1、普通程序员
a、编写代码:正确处理业务流程和数据计算;b、让代码跑起来
1.2、工程师
代码:易读、易扩展、易维护、可重用;效率:开发高效、快速
特点:有洁癖、有工匠精神、有修养
1.3、架构师
权衡、决策
简化、灵活
应对复杂度
2、软件开发需要解决的问题
1、微观:代码
2、宏观:架构
3、分离控制与逻辑
控制:对程序流转, 与业务逻辑无关, 如:多线程、异步 、服务发现、消息中间件等, 另外还有业务逻辑中的判断(if else) , 是否可以去掉if else , 变为根据一定规则进行路由到不同逻辑, 这样也便于扩展, 职责分离,同时也便于测试
逻辑:实实在在的业务逻辑,解决用户问题的逻辑
控制、逻辑构成了整体的软件复杂度,有效分离得到最大简化
3、架构对软件开发的影响
好的软件架构:
人力成本:可以大大节省软件项目构建与维护的人力成本。
变更成本:让每次变更都短小简单,易于实施
风险:并且避免缺陷
扩展性:最大程度地满足功能性和灵活性要求
4、设计与架构的关系
二者之间没有区别,这是作者的观点。个人思考,一般的软件设计与架构设计差别还是很大的,面临的问题,思考的方式都是不一样的。
底层设计细节和高层架构信息是不可分割的。
6、复杂软件开发的思想
要想跑得快,先要跑得稳
7、软件系统的价值
软件系统可以通过行为和架构两个维度来实现实际价值
7.1、行为价值
包括需求的实现,以及可用性保障(性能、稳定性)
是最直观的价值
7.2、架构价值
软件系统必须灵活,必须容易被修改
7.3、架构价值是否是必须要有的?
看情况!
如果业务是明确的、稳定的,架构的价值就可以忽略不计;但业务通常是不明确的、飞速发展的,这时架构就无比重要
7.4、哪个价值维度更重要
第一个价值维度:系统行为,是紧急的,但是并不总是特别重要
第二个价值维度,系统架构,是重要的,但是并不总是特别紧急
开发人员的职责: 平衡系统架构的重要性和功能的紧急程度,为好的软件架构而持续斗争
如果忽视软件架构的价值,系统将会原来越难以维护,终有一天,系统将会变得再也无法修改,导致:重构!
7.5、只关注行为价值带来的问题
当我们只关注行为价值,不关注架构价值时,会发生什么事情?这是书中记录的一个真实案例,随着版本迭代,工程师团队的规模持续增长,但总代码行数却趋于稳定,相对应的,每行代码的变更成本升高、工程师的生产效率降低。从老板的视角,就是公司的成本增长迅猛,如果营收跟不上就要开始赔钱。
7.6、如何处理好行为价值和架构价值的关系
重要紧急矩阵中,做事的顺序是这样的:1.重要且紧急 > 2.重要不紧急 > 3.不重要但紧急 > 4.不重要且不紧急。实现行为价值的需求通常是PD提出的,都比较紧急,但并不总是特别重要;架构价值的工作内容,通常是开发同学提出的,都很重要但基本不是很紧急,短期内不做也死不了。所以行为价值的事情落在1和3(重要且紧急、不重要但紧急),而架构价值落在2(重要不紧急)。我们开发同学,在低头敲代码之前,一定要把杂糅在一起的1和3分开,把我们架构工作插进去。
5、软件架构的目标
终极目标:用最小的(人力,资源)成本来满足构建和维护该系统的需求
最大化程序员的生产力,同时最小化系统的总运营成本。最大限度地降低构建和维护一个系统所需的人力资源
支撑软件系统的全生命周期,设计良好的架构让系统便于理解、易于修改、方便维护,并能轻松部署。
开发阶段:组件不要使用大量复杂的脚手架;不同团队负责不同的组件,避免不必要的协作。
部署阶段:部署工作不要依赖成堆的脚本和配置文件;组件越多部署工作越繁重,而部署工作本身是没有价值的,做的越少越好,所以要减少组件数量。
运行阶段:架构设计要考虑到不同的吞吐量、不同的响应时长要求;架构应起到揭示系统运行的作用:用例、功能、行为设置应该都是对开发者可见的一级实体,以类、函数或模块的形式占据明显位置,命名能清晰地描述对应的功能。
维护阶段:减少探秘成本和风险。探秘成本是对现有软件系统的挖掘工作,确定新功能或修复问题的最佳位置和方式。风险是做改动时,可能衍生出新的问题。
8、软件架构是什么
规划如何将系统切分成组件,并安排好组件之间的排列关系,以及组件之间互相通信的方式
9、划分边界
架构师追求的目标是最大限度地降低构建和维护一个系统所需的人力资源。
最消耗人力资源的是什么?
系统中存在的耦合:
1、过早做出的、不成熟的决策所导致的耦合
2、是那些与系统的业务需求无关的决策,包括要采用的框架、数据库、Web服务器、工具库、依赖注入等。
解决方案:通过划清边界(个人理解边界,即是职责的问题),可以推迟和延后一些细节性的决策,最终会为我们节省大量的时间、避免大量的问题。
10、插件式架构
1、软件开发技术发展的历史:就是一个如何想法设法方便地增加插件,从而构建一个可扩展、可维护的系统架构的故事。
2、系统的核心业务逻辑必须和其他组件隔离,保持独立,其他组件要么可以去掉的,要么有多种实现的。
个人思考:
1、插件的本质是, 将大的职责组件分开独立的小的职责组件(插件), 另外一点必须有维护组件(串联起来小的组件, 可以工作), 有新的需求, 可以增加(扩展)小的组件;有新的外围框架或是中间件,可以方便切换!
2、核心业务逻辑, 与依赖外部服务或是组件分开,再包装一层,可以方便替换
3、对依赖反转原则(DIP)和稳定抽象原则(SAP)的具体应用
11、业务逻辑
业务逻辑是一个系统存在的意义,属于核心功能,是系统用来赚钱或省钱的那部分代码,是整个系统中的皇冠明珠。
业务逻辑应该保持纯净,不要掺杂用户界面或者所用数据库相关东西。
理想情况下,代表业务逻辑的代码应该是整个系统的核心,其它底层概念的实现应该以插件形式接入系统中。
业务逻辑应该是系统中最独立、复用性最高的代码。
12、整洁架构
常见系统架构,六边形架构(端口与适配器架构)、DCI架构、BCE架构。
共同设计目标:按照不同关注点对软件进行切割。
核心点:分层 + 依赖规则
分析:
1、分层:关注点分离思想
分层:这些架构都会将软件切割成不同的层,至少有一个层是只包含软件的业务逻辑的,用户接口、系统接口属于其他层。
2、依赖规则
代码依赖只能使由外向内,内层结构的代码不能包含有任何外层结构的信息
1、越靠近圆心即越是稳定的,即代表高层策略,越外围表示是低层组件,
2、依赖方式:从图中也可以看出,低层组件依赖高层组件(策略)
3、业务实体层:包含业务实体,即应用的业务对象,封装最通用最高层的业务逻辑(单独某个业务实体的逻辑),它不应该受外界影响
4、用户用例层:实现用户某个用例场景的业务逻辑封装,是对业务实体的组装、封装
5、接口适配层:目的是进行数据的交换,包含有网关、控制器、展示器, 如:实体层和用户实例层使用的数据转化成为持久层能使用的数据,比如数据库
6、框架与驱动层:包含数据库、用户界面、web框架等
每一种架构一定能在写系统的业务逻辑的时候有以下特征:
1、与框架分离:系统架构不依赖于某个功能丰富的框架中的某个函数,框架被当作工具使用,不需要让让系统来适应框架。
2、可测试性:系统的业务逻辑可以脱离UI、数据库、Web服务及其他外部元素来测试。
3、与UI分离:UI必须能非常容易独立地修改。而不能在改变UI的同时需要改变系统其他部分。比如当把系统的UI从Web UI改成控制台UI,你并不需要改变任何业务逻辑的代码。
4、与数据库分离:能很方便地在Oracle,SQL Server,Mongo DB,BigTable,CouchDB或者其他数据库中进行切换和改变。业务逻辑决不能依赖这些数据库。
个人思考:目前公司一直使用某种数据库,这个在一定时间内改变的可能性比较小!
5、与外部结构分离:系统的业务逻辑并不需要知道任何外部的结构。
13、SOLID设计原则
SRP(单一职责原则):
每个软件模块都有且只有一个需要改变的理由。
适用范围:方法、类、接口、包、模块、应用(应用的职责)、系统(业务系统的边界)
OCP(开闭原则):
易于扩展、 修改关闭
LSP(里氏替换原则):
如果想用可替换组件来构建软件系统,那么这些组件必须遵守同一个约定,以便让这些组件可以相互替换。
软件架构层面,一旦违背了可替换性,该系统架构就不得不为此增添大量复杂的应对机制。
ISP(接口隔离原则)
主要告诫软件设计师应该在设计中避免不必要的依赖。
任何层次的软件设计如果依赖了它并不需要的东西,就会带来意料之外的麻烦
DIP(依赖反转原则):
依赖关系应该应该多引用抽象类型,而非具体实现
其他原则
关注点分离
14、应该把哪些类应该被组合成一个组件?
主要是解决组件聚合的问题
原则:复用/发布等同原则、共同闭包原则、共同复用原则。
15、如何管理组件之间的依赖关系?
主要是解决组件耦合的问题
帮助我们确定组件之间的相互依赖关系,要考虑三个原则:无依赖环原则、稳定依赖原则、稳定抽象原则。
15.1、无依赖环原则 (Acyclic Dependencies Principle,ADP)
组件依赖关系图中不应该出现环
影响:环形依赖关系使得一个组件修改之后的影响范围将变得非常大,环中任何一个组件发生变更,会对环上每一个组件产生影响,进而导致对环上组件依赖的其他组件产生影响,导致系统难以升级和维护。
如何打破依赖循环?
1)使用依赖反转原则
2)创建一个新组件
15.2、稳定依赖原则(The Stable Dependencies Principle,SDP)
依赖关系必须指向更稳定的方向
如何衡量一个组件的稳定性?
不稳定性指标:I = (对别的组件依赖个数)/ (对别的组件依赖个数 + 别的组件对自己依赖个数)
15.3、稳定抽象原则(The Stable Abstractions Principle,SAP)
一个组件的抽象化程度应该与其稳定性保持一致。
组件的抽象化程度 A = 组件中抽象类和接口的数量/组件中具体类的数量。
稳定的组件应该是抽象的,应该由接口和抽象类组成。
一个不稳定的组件应该包含具体的实现代码。
依赖关系应该指向更加抽象的方向。
参考相关书箱
代码整洁之道
代码整洁之道:程序员的职业素养
架构整洁之道