读书·架构整洁之道(原则篇)

2024-06-24 01:08

本文主要是介绍读书·架构整洁之道(原则篇),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

十四年不修行,只读书,一年通幽。二十日不解碑,只静坐,一日看尽前陵碑 ----- 猫腻《择天记》

  • 一.设计与架构究竟是什么?
  • 二.SOLID设计原则
    • SRP:单一责任原则(Single Responsibility Principle)
    • OCP:开闭原则(Open Closed Principle)
    • LSP:里氏替换原则(Liskov Substitution Principle)
    • ISP:接口隔离原则(Interface Segregation Principle)
    • DIP:依赖倒置原则(Dependence Inversion Principle)
  • 三.组件构建原则
    • 组件聚合
      • REP:复用/发布等同原则
      • CCP:共同闭包原则
      • CRP:共同复用原则
    • 组件耦合
      • ADP:无依赖环原则
      • SDP:稳定依赖原则
      • SAP:稳定抽象原则

欢迎关注微信公众号“江湖喵的修炼秘籍”

近日在读Bob大叔的《架构整洁之道》,全书大体上可以分为两部分,前半部分讲设计原则,后半部分讲软件架构,这篇文章是对前半部分的一些观点的整理和思考。

一.设计与架构究竟是什么?

什么是设计?什么是架构?两者的区别是什么?

两者没有任何区别。

架构”这个词存在于“高层”级的讨论之中,这种讨论中往往会把“底层”的实现细节排除在外。

设计”往往用来指代具体的系统底层组织结构和实现细节。

但是底层细节设计和高层架构信息是不可分割的,它们组合在一起,共同定义了整个软件系统,缺一不可。所谓底层和高层本身就是一系列决策组成的连续体,并没有清晰的分界线。

软件架构和设计的终极目标是什么?

软件架构的终极目标,是用最小的人力成本来满足构建和维护该系统的需求。

评估一个软件架构的优劣,可以用成本来衡量。如果满足一个用户需求的成本很低,而且在软件的整个生命周期中都可以保持低成本,那就是一个优良的设计,反之亦然。

麻乱系统的问题出在哪?

如果随着软件的迭代,作出变更所需要的成本不断增高,那就是一个典型的麻乱系统。

原因是工程师们持续低估了良好的设计、整洁的代码的重要性,无法平衡好系统架构和系统行为的关系。

如何平衡软件系统的行为价值和架构价值?

行为价值:软件的核心价值(最直观的价值维度),包括需求的实现,以及可用性保障(功能性bug 、性能、稳定性)

架构价值:保持软件的灵活性,便于理解、易于修改、方便维护、轻松部署。

按照艾森豪威尔矩阵划分的话,系统架构是重要但不特别紧急的,系统行为是紧急但不特别重要的。系统架构问题要优先于系统行为问题,如何平衡两者关系,应该是软件研发人员的职责。

思考:工程师所处的团队和所负责的项目可能是用户驱动、产品驱动或是技术驱动,不同的角色对系统的关注点不同,用户和产品自身也缺乏对软件架构的认识和评估重要性的能力,这个应该是软件开发人员的职责。软件开发人员有责任与其他部门进行抗争,避免不必要的妥协,将软件架构摆在第一位(事实上是很难的一件事)

二.SOLID设计原则

设计原则的意义?

通常来说,要想构建一个好的软件系统,应该从写整洁的代码开始做起。毕竟,如果建筑所使用的砖头质量不佳,那么架构所能起到的作用也会有限。反之亦然,如果建筑的架构设计不佳,那么其所用的砖头质量再好也没用。这就是SOLID设计原则索要解决的问题。

SOLID原则的主要作用是告诉我们如何将数据和函数组织成类,如何将类链接起来成为程序。

SOLID包括如下原则:

SRP:单一责任原则(Single Responsibility Principle)

任何一个软件模块都应该只对某一类行为者负责。

这里的一个软件模块可以理解成一个源代码文件,比如java的一个类。

行为者可以理解为一个或多个有共同需求的人。

反面案例:

重复的假象:为了避免重复编码,开发者强行将不同行为者所依赖的代码强行凑在一起,SRP强调这类代码一定要分开。

代码合并:多人为了不同的目的修改了同一份源代码,很容易造成问题的产生。避免这种问题的方法就是将服务不同行为者的代码进行切分。类切分后可以使用facade模式(外观模式)提供统一的入口。

思考
1.接口一定要做到单一职责,类要尽量做到单一职责。

2.代码块独立,每个方法只提供单一的功能,复用性高。

3.函数功能简化以后,单个函数的代码量也会减少,可读性高,可以方便的使用函数名表明函数功能,由于方法功能明确,也会降低变更带来的风险。

4.很难有固化的标准去度量划分标准,如果根据SRP原则过分的细分,会导致类数量剧增。

5.如何区分真的重复还是假的重复?前提是开发者是否可以正确的判断出方法的的行为者是不是相同的。

OCP:开闭原则(Open Closed Principle)

设计良好的计算机软件应该易于扩展,同时抗拒修改

OCP原则的目的是让系统易于扩展,同时限制每次修改的范围。软件应该可以在不修改原有代码的基础上轻易的被扩展。

思考
1.SRP原则已经要求每个函数提供单一的功能,每个函数都可以作为一个基础组件。OCP原则要求我们将这些组件间的依赖关系按照层次结构进行组织,使高阶组件不会因低阶组件的修改而受到影响。

2.我们应该将会频繁变更的逻辑和基本稳定的逻辑分离开。

LSP:里氏替换原则(Liskov Substitution Principle)

子类对象能够替换程序中父类对象出现的任何地方,并且保证原来程序的逻辑行为不变及正确性不被破坏。

LSP原则是一种指导继承关系以及接口和其实现方式的设计原则。

思考
1.理解LSP原则的关键,是理解design by contract(契约式设计),子类在设计的时候,要遵守父类的行为约定(包括函数声明要实现的功能;对输入、输出、异常的约定;以及注释中所包含的其他特殊说明)。父类定义了函数的行为约定,那子类可以改变函数的内部实现逻辑,但不能改变函数原有的行为约定。接口和实现类之间的关系也应该符合这个原则。

2.LSP原则强调的是父类应该可以被子类随意替换,引用类不应该依赖它所使用的类,如果程序需要通过逻辑判断才能决定使用父类还是子类,则其违反了LSP原则。比如正方形/长方形问题,数学上我们可以认为正方形是一种特殊的长方形,但软件设计中,正方形不是长方形的子类。

ISP:接口隔离原则(Interface Segregation Principle)

在设计中应避免不必要的依赖

任何层次的软件设计如果依赖了它不需要的东西,都会带来意料之外的麻烦

思考
1.如果认为“接口”指的是一个接口类对应的一系列接口组成的集合,那么如果使用者只用到这些接口中的一部分,那么我们就应该把这些接口抽离出来,单独提供给调用者。

2.如果认为“接口”指定是单个接口或者单个函数,如果调用者只用到这个接口功能的一部分,那么这个接口也不符合SRP(单一责任原则),接口粒度不够细,需要进行拆分,ISP原则也为是否符合SRP原则提供了一种评判标准。

DIP:依赖倒置原则(Dependence Inversion Principle)

细节应当依赖于抽象,抽象不应当依赖于细节

1.抽象的接口层远比具体实现稳定

2.应在代码中多使用抽象接口,尽量避免使用多变的具体实现(比如使用抽象工厂模式)

3.不要在具体实现上创建衍生类

4.不要覆盖包含具体实现的函数

5.应该避免在代码中写入任何与具体实现相关的名字,或者其他容易变动的事物的名字

思考
1.依赖反转的核心是面向接口编程,代码依赖时,应该依赖接口,而不是具体实现。其实也不一定都能一步到位的做到,可能前期并不存在抽象和继承的可能性,如果全部都抽象出来,工作量也很繁重,可以在前期评估,如果有扩展的可能性,可以直接一步到位,如果未来几乎不存在扩展的可能性,可以在后期扩展的尝试重构。

2.我们重点关注的应该是经常会变动的实现模块

三.组件构建原则

组件聚合

REP:复用/发布等同原则

软件复用的最小粒度应该等同于其发布的最小粒度

Maven等模块管理工具的出现推动出现了大量可复用的组件和组件库,基于此,REP原则要求组件库必须由某种流程来驱动,并提供明确的版本号、发布日期、变更内容、发布文档等信息,以便依赖方对是否需要升级组件库提供决策依据,从而真正的实现软件复用。

思考:REP原则的重点是告诉软件开发者应该怎么做,而不是如何去做。REP原则要求组件中的类和模块必须是紧密相关的,一个组件不能由一组没有关联的类和模块组成,但是并没有定义如何将类和模块组合成组件。

CCP:共同闭包原则

我们应该将那些会同时修改,并且为相同目的而修改的类放到同一个组件中,而将不会同时修改,并且不会为了相同的目的而修改的那些类放到不同的组件中

CCP原则是组件层面对于SRP原则和OCP原则的进一步阐述。

首先SRP原则认为一个类只提供一种单一的职责,CCP原则认为一个组件因为不同的目的而同时修改。

OCP原则认为一个类应该对扩展开放,对修改关闭,CCP原则中闭包的概念就是OCP原则中对修改关闭的范围。

思考

将SRP原则和OCP原则的理念进行融合,并提升到组件层面,首先我们应该将具备相同职责,即开发过程中会为了同一个目的进行修改的代码聚合在一起,放在同一个组件中,相反,如果需要为了不同的目的而修改,则需要拆分开来。同时,我们需要将比较稳定,不会发生修改的部分聚合在一起,将需要一同变更的聚合在一起,从而合理的控制闭包的范围。

OCP原则的重点是告诉软件开发者应该将哪些类聚合在一起,这些要求的目的是为了在需要对组件进行修改时,可以尽可能的缩小影响范围。

CRP:共同复用原则

不要强迫一个组件的用户强制依赖它们不需要的东西

CRP原则是ISP原则在组件层面的阐述,两者的重点都是不要依赖不需要的东西。

思考
1.CRP原则的重点是告诉开发者需要将哪些类分开

2.可以通过现实中的例子进一步加强理解。

第一个例子是一个项目将服务发布成组件时,在pom依赖中不应该依赖没有用的依赖,这种操作的后果是,组件的依赖方也必须继承这些无用的依赖,并且在解决版本冲突上需要花费一些精力

第二个是类似比较有争议的lombok组件,如果在组件中使用lombok,则组件的依赖方也必须依赖lombok组件,侵入性太强

REP原则和CCP原则是黏性原则,CRP原则是排他性原则,三者之间的关系和侧重点是需要软件设计师去根据实际情况进行取舍的。

组件耦合

ADP:无依赖环原则

组件依赖关系中不应该出现环

系统中不同组件之间的依赖应该是单向进行的,不应该出现循环依赖

如果出现的循环依赖 可以尝试使用依赖反转原则(DIP)或者创建创建一个包含涉及到依赖类的新组建 纠正依赖关系

组件依赖关系必须要随着项目的逻辑设计一起扩展和演进,在最初就设计完美的依赖关系是不现实的

SDP:稳定依赖原则

依赖关系必须要指向更稳定的方向

1.程序不会是一尘不变的,修改是必然的。

2.稳定与不稳定:被依赖的组件时稳定的,依赖其他组件的组件是不稳定的,依赖的组件越多越不稳定,因为当所依赖的组件被修改时,该组件被修改的概率也会增大。

不稳定性=入向依赖/(入向依赖+出现依赖),SDP原则的目标是每个组件的不稳定性都应该大于其所依赖的组件,即依赖关系的稳定性方向是单向的,并且被依赖的组件要更稳定。

3.SDP原则的重点是稳定性的方向,对于稳定性本身来说并无要求,并不是所有的组件都应该是稳定的。当所有组件的稳定性都为1时,系统将无法变更

SAP:稳定抽象原则

一个组件的抽象化程度应该与其稳定性程度保持一致

1.一个组件如果是稳定的,它就应该是抽象的,这样符合OCP原则,既稳定又方便扩展

2.一个组件如果是不稳定的,它就应该有具体的实现,方便进行修改

3.SAP原则将抽象与稳定性之间建立了关联,根据SDP原则可以引申出:依赖的关系必须要指向更抽象的方向

4.抽象度=抽象类+接口数量/组件中类的总数量 范围在0和1之间,抽象度过高和过低都不是好事,我们软件设计的目标应该保持抽象度中间值附近

这篇关于读书·架构整洁之道(原则篇)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1088766

相关文章

mybatis的整体架构

mybatis的整体架构分为三层: 1.基础支持层 该层包括:数据源模块、事务管理模块、缓存模块、Binding模块、反射模块、类型转换模块、日志模块、资源加载模块、解析器模块 2.核心处理层 该层包括:配置解析、参数映射、SQL解析、SQL执行、结果集映射、插件 3.接口层 该层包括:SqlSession 基础支持层 该层保护mybatis的基础模块,它们为核心处理层提供了良好的支撑。

百度/小米/滴滴/京东,中台架构比较

小米中台建设实践 01 小米的三大中台建设:业务+数据+技术 业务中台--从业务说起 在中台建设中,需要规范化的服务接口、一致整合化的数据、容器化的技术组件以及弹性的基础设施。并结合业务情况,判定是否真的需要中台。 小米参考了业界优秀的案例包括移动中台、数据中台、业务中台、技术中台等,再结合其业务发展历程及业务现状,整理了中台架构的核心方法论,一是企业如何共享服务,二是如何为业务提供便利。

读书摘录《控糖革命》

又到了每周推荐时间,这周末给大家推荐一本书《控糖革命》。身体是革命的本钱,只有保持健康的身体,才能保证持久的生产力,希望我的读者都可以身体健康,青春永驻。 推荐前,首先申明在《控糖革命》一书中,作者提出了一些颇具争议的观点,这些观点并没有经过系统的科学论证,但这并不妨碍我们从中获取一些有益的控糖建议。作者通过分享作者的个人经验和研究,为我们提供了一种全新的饮食理念,帮助我们更好地控制血糖峰值

系统架构设计师: 信息安全技术

简简单单 Online zuozuo: 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo :本心、输入输出、结果 简简单单 Online zuozuo : 文章目录 系统架构设计师: 信息安全技术前言信息安全的基本要素:信息安全的范围:安全措施的目标:访问控制技术要素:访问控制包括:等保

利用命令模式构建高效的手游后端架构

在现代手游开发中,后端架构的设计对于支持高并发、快速迭代和复杂游戏逻辑至关重要。命令模式作为一种行为设计模式,可以有效地解耦请求的发起者与接收者,提升系统的可维护性和扩展性。本文将深入探讨如何利用命令模式构建一个强大且灵活的手游后端架构。 1. 命令模式的概念与优势 命令模式通过将请求封装为对象,使得请求的发起者和接收者之间的耦合度降低。这种模式的主要优势包括: 解耦请求发起者与处理者

JVM内存调优原则及几种JVM内存调优方法

JVM内存调优原则及几种JVM内存调优方法 1、堆大小设置。 2、回收器选择。   1、在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存,这个数值不能准确的反应堆内存的真实占用情况,因为GC过后这个值是不会变化的,因此内存调优的时候要更多地使用JDK提供的内存查看工具,比如JConsole和Java VisualVM。   2、对JVM内存的系统级的调优主要的目的是减少

创业者该如何设计公司的股权架构

本文来自七八点联合IT橘子和车库咖啡的一系列关于设计公司股权结构的讲座。 主讲人何德文: 在公司发展的不同阶段,创业者都会面临公司股权架构设计问题: 1.合伙人合伙创业第一天,就会面临股权架构设计问题(合伙人股权设计); 2.公司早期要引入天使资金,会面临股权架构设计问题(天使融资); 3.公司有三五十号人,要激励中层管理与重要技术人员和公司长期走下去,会面临股权架构设计问题(员工股权激

【系统架构设计师】黑板架构详解

黑板架构(Blackboard Architecture)是一种软件架构模式,它模仿了多个专家系统协作解决问题的场景。在这种架构中,“黑板”作为一个中央知识库,存储了问题的当前状态以及所有的解决方案和部分解决方案。黑板架构特别适合于解决那些没有确定算法、需要多个知识源(或称为“专家”)共同作用才能解决的复杂问题。 一、黑板架构的组成 黑板架构主要由以下几个部分组成: 黑板(Blackboa

Python中的属性装饰器:解锁更优雅的编程之道

引言 在Python的世界里,装饰器是一个强大的工具,它允许我们以一种非侵入性的方式修改函数或方法的行为。而当我们谈论“属性装饰器”时,则是在探讨如何使用装饰器来增强类中属性的功能。这不仅让我们的代码更加简洁、易读,同时也提供了强大的功能扩展能力。本文将带你深入了解属性装饰器的核心概念,并通过一系列实例展示其在不同场景下的应用,从基础到进阶,再到实际项目的实战经验分享,帮助你解锁Python编程

Java后端微服务架构下的API限流策略:Guava RateLimiter

Java后端微服务架构下的API限流策略:Guava RateLimiter 大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿! 在微服务架构中,API限流是保护服务不受过度使用和拒绝服务攻击的重要手段。Guava RateLimiter是Google开源的Java库中的一个组件,提供了简单易用的限流功能。 API限流概述 API限流通过控制请求的速率来防止