《架构整洁之道》:Chap11. DIP: THE DEPENDENCY INVERSION PRINCIPLE DIP:依赖反转原则

The Dependency Inversion Principle (DIP) tells us that the most flexible systems are those in which source code dependencies refer only to abstractions, not to concretions. 依赖反转原则(DIP)主要想告诉我们的是,如果想要设计一个灵活的系统,在源代码层次的依赖关系中就应该多引用抽象类型,而用具体实现。 In a statically typed language, like Java, this means that the use, import, and include statements should refer only to source modules containing interfaces, abstract classes, or some other kind of abstract declaration. Nothing concrete should be depended on. 也就是说,在 Java 这类静态类型的编程语言中,在使用 use、import、include 这些语句时应该只引用那些包含接口、抽象类或者其他抽象类型声明的源文件,不应该引用任何具体实现。 ...

March 14, 2024

《架构整洁之道》:Chap10. ISP: THE INTERFACE SEGREGATION PRINCIPLE ISP:接口隔离原则

The Interface Segregation Principle (ISP) derives its name from the diagram shown in Figure 10.1. “接口隔离原则(ISP)”这个名字来自图 10.1 所示的这种软件结构。 The Interface Segregation Principle In the situation illustrated in Figure 10.1, there are several users who use the operations of the OPS class. Let’s assume that User1 uses only op1, User2 uses only op2, and User3 uses only op3. 在图 10.1 所描绘的应用中,有多个用户需要操作 OPS 类。现在,我们假设这里的 User1 只需要使用 op1,User2 只需要使用 op2,User3 只需要使用 op3。 Now imagine that OPS is a class written in a language like Java. Clearly, in that case, the source code of User1 will inadvertently depend on op2 and op3, even though it doesn’t call them. This dependence means that a change to the source code of op2 in OPS will force User1 to be recompiled and redeployed, even though nothing that it cared about has actually changed. ...

March 13, 2024

《架构整洁之道》:Chap9. LSP: THE LISKOV SUBSTITUTION PRINCIPLE LSP:里氏替换原则

In 1988, Barbara Liskov wrote the following as a way of defining subtypes. 1988 年,Barbara Liskov 在描述如何定义子类型时写下了这样一段话: What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.1 ...

March 12, 2024

《架构整洁之道》:Chap8. OCP: THE OPEN-CLOSED PRINCIPLE OCP:开闭原则

The Open-Closed Principle (OCP) was coined in 1988 by Bertrand Meyer.1 It says: 开闭原则(OCP)是 Bertrand Meyer 在 1988 年提出的,该设计原则认为: A software artifact should be open for extension but closed for modification. 设计良好的计算机软件应该易于扩展,同时抗拒修改。 In other words, the behavior of a software artifact ought to be extendible, without having to modify that artifact. 换句话说,一个设计良好的计算机系统应该在不需要修改的前提下就可以轻易被扩展。 This, of course, is the most fundamental reason that we study software architecture. Clearly, if simple extensions to the requirements force massive changes to the software, then the architects of that software system have engaged in a spectacular failure. ...

March 11, 2024

《架构整洁之道》:Chap7. SRP: THE SINGLE RESPONSIBILITY PRINCIPLE SRP:单一职责原则

Of all the SOLID principles, the Single Responsibility Principle (SRP) might be the least well understood. That’s likely because it has a particularly inappropriate name. It is too easy for programmers to hear the name and then assume that it means that every module should do just one thing. SRP 是 SOLID 五大设计原则中最容易被误解的一个。也许是名字的原因,很多程序员根据 SRP 这个名字想当然地认为这个原则就是指:每个模块都应该只做一件事。 Make no mistake, there is a principle like that. A function should do one, and only one, thing. We use that principle when we are refactoring large functions into smaller functions; we use it at the lowest levels. But it is not one of the SOLID principles—it is not the SRP. ...

March 10, 2024

《架构整洁之道》:Part3. DESIGN PRINCIPLES 设计原则

Good software systems begin with clean code. On the one hand, if the bricks aren’t well made, the architecture of the building doesn’t matter much. On the other hand, you can make a substantial mess with well-made bricks. This is where the SOLID principles come in. 通常来说,要想构建一个好的软件系统,应该从写整洁的代码开始做起。毕竟,如果建筑所使用的砖头质量不佳,那么架构所能起到的作用也会很有限。反之亦然,如果建筑的架构设计不佳,那么其所用的砖头质量再好也没有用。这就是 SOLID 设计原则所要解决的问题。 The SOLID principles tell us how to arrange our functions and data structures into classes, and how those classes should be interconnected. The use of the word “class” does not imply that these principles are applicable only to object-oriented software. A class is simply a coupled grouping of functions and data. Every software system has such groupings, whether they are called classes or not. The SOLID principles apply to those groupings. ...

March 9, 2024

The Importance of SOLID Design Principles

Author: Stephen Watts SOLID is a popular set of design principles that are used in object-oriented software development. SOLID is an acronym that stands for five key design principles: single responsibility principle, open-closed principle, Liskov substitution principle, interface segregation principle, and dependency inversion principle. All five are commonly used by software engineers and provide some important benefits for developers. The SOLID principles were developed by Robert C. Martin in a 2000 essay, “Design Principles and Design Patterns,” although the acronym was coined later by Michael Feathers. In his essay, Martin acknowledged that successful software will change and develop. As it changes, it becomes increasingly complex. Without good design principles, Martin warns that software becomes rigid, fragile, immobile, and viscous. The SOLID principles were developed to combat these problematic design patterns. ...

April 19, 2023

里氏替换原则Liskov substitation principle

为什么叫里氏替换原则? 里氏替换原则在SOLID这五个设计原则中是比较特殊的存在:如果违反了里氏替换原则,不只是降低软件设计的优雅性,很可能会导致Bug。 里氏替换原则译自Liskov substitution principle。Liskov是一位计算机科学家,也就是Barbara Liskov,麻省理工学院教授,也是美国第一个计算机科学女博士,师从图灵奖得主John McCarthy教授,人工智能概念的提出者。 Robert Martin在《敏捷软件开发:原则、模式与实践》一书中对原论文的解读:子类型(subtype)必须能够替换掉他们的基类型(base type)。这个是更简明的一种表述。 违背 LSP 原则的一个简单示例 一个非常明显地违背 LSP原则的示例就是使用 RTTI(Run Time Type Identification)来根据对象类型选择函数执行。 void DrawShape(const Shape& s) { if (typeid(s) == typeid(Square)) DrawSquare(static_cast<Square&>(s)); else if (typeid(s) == typeid(Circle)) DrawCircle(static_cast<Circle&>(s)); } 正方形和长方形,违背原则的微妙之处 很多情况下对 LSP 原则的违背方式都十分微妙。设想在一个应用程序中使用了 Rectangle 类,描述如下: public class Rectangle { private double _width; private double _height; public void SetWidth(double w) { _width = w; } public void SetHeight(double w) { _height = w; } public double GetWidth() { return _width; } public double GetHeight() { return _height; } } 违反里氏替换原则的危害 当我们违反了这一原则会带来有一些危害:反直觉。期望所有子类行为是一致的,但如果不一致可能需要文档记录,或者在代码跑失败后涨此知识;不可读。如果子类行为不一致,可能需要不同的逻辑分支来适配不同的行为,徒增代码复杂度;不可用。可能出错的地方终将会出错。 ...

April 19, 2023

整理和总结我自己的软件架构知识体系

最近开始整理自己实际项目中用到的和可能用到的软件架构体系,我打算每种架构都好好写文章,并且根据自己的实际情况定制出相应的架构,我还希望把他编写成一个codesmith模板,可以实现自动化代码。前面7种是具体落地的软件架构,最后1种是架构设计思想。 1、极简数据库访问架构,这种架构非常适合编写一些小软件,里面只有一个SQLHelper文件,并且模仿三层架构,拥有DAL类和BLL类,最后加上一个程序入口Program。 2、简单三层架构,这种架构非常适合开发小型项目,web层就是MVC或者API,并且拥有BLL层和DAL层。 3、N层架构,这是一种适合大型项目的开发架构,但是更多是基于数据库构建的系统,没有基于DDD或者其他好的软件设计模式。 4、基于AutoFac、依赖注入和模板模式的多层架构。 5、基于ABP框架的架构,完全按照DDD设计模式开发,可能有些臃肿,但是非常适合大型软件和系统。 6、基于整洁架构的框架,完全按照DDD并且结合各种软件技术。 7、垂直切片架构,这是一种和传统分成架构完全不一样的架构,适合已经熟悉DDD和各种架构模式的成熟团队使用,并且适合开发微服务架构下的子系统。 8、基于清晰架构的微服务软件架构设计思想,这不是具体的实现,而只是一种架构大局观,用于指导大型的软件架构设计。

April 3, 2023

关于软件的架构:微服务架构、清晰架构、整洁架构、洋葱架构、六边形架构、垂直切片架构、基于DDD分层架构、三层架构

这段时间一直在重构公司的项目代码,所以非常关注软件架构的设计,回顾我的架构接触史:第一次接触C#和.NET的时候就知道了三层架构和多层架构,当时被DAL和BLL等分层震惊了,原来软件设计还有那么多门道;毕业之后工作一直在使用多层架构,接着是MVC架构的出现,这种快速开发web站点的架构横扫整个行业;后来进入大厂工作,接触到了DDD;最近几年微服务架构又风声水起。 整体下来我最开始用了三层架构、然后是多层架构,接着是MVC架构配合多层架构,最后到了微服务架构,现在深刻理解那句话:没有最好的架构,只有最合适的架构。 网上看到有个人总结传统的架构演变之路: 三层架构:这是最简单、同时也是最成熟的软件应用程序架构,它将应用程序组织到三个逻辑和物理计算层中,包括表示层或用户界面、用于处理数据的应用(业务逻辑)程序层和用于存储和管理应用程序关联数据的数据层。大型项目中很少用,但是我还是会在一些小工具和小应用里运用。 多层架构:这种架构是三层架构的升级版,就是增加更多层对系统进行隔离,提高可扩展性和复用性,当然也增加了系统的复杂度。这是我刚毕业那家年用得最多的架构。 基于DDD的分层架构:采用领域驱动设计的思想设计的多层架构,以领域模型为核心、使用依赖注入和控制反转等技术来实现软件,对系统进行解耦,获得最大限度地可维护性和可扩展性。这是我现在在项目中用得最多的架构。 领域模型准确反映了业务语言,而传统数据对象除了简单setter/getter方法外,没有任何业务方法,即失血模型,那么DDD领域模型就是充血模型(业务方法定义在实体对象中)。首次清晰描述了领域驱动的分层实现并统一了业务语言。单一职责、低耦合、高内聚、业务内核沉淀。 六边形架构:让用户、程序、自动化测试和批处理脚本可以平等地驱动应用,让应用的开发和测试可以独立于其最终运行的设备和数据库。 左侧: 代表 UI 的适配器被称为主适配器,它们发起了对应用的一些操作,端口(应用层API)和它的具体实现(controller实现)都在应用内部。右侧: 表示和后端工具链接的适配器,被称为从适配器,它们只会对主适配器的操作作出响应,端口在应用内部(业务接口),具体实现(impl)在应用之外。 **洋葱架构:**在端口和适配器架构的基础上贯彻了将领域放在应用中心,将传达机制(UI)和系统使用的基础设施(ORM、搜索引擎、第三方 API…)放在外围的思路。洋葱架构在业务逻辑中加入了一些在“领域驱动设计”中被识别出来的层次。 围绕独立的对象模型构建应用。内层定义接口,外层实现接口。依赖的方向指向圆心。所有的应用代码可以独立于基础设施编译和运行。职责分离更彻底,高内聚低耦合。更好的可测试性和可维护性。 **整洁架构:**这套架构是站在巨人的肩膀上,把MVC、EBI、端口适配器、洋葱架构、DDD融会贯通,形成了一套落地实践方案。 清晰架构:融合 DDD、洋葱架构、整洁架构、CQRS等一系列架构的信息,这种架构很复杂,你可以根据实际情况来选择。 微服务架构:微服务架构的诞生是因为docker的兴起,因为可以更好地管理各种部署,所以可以将一个大型系统拆分部署到docker之中,每个小服务都能实现集群部署。我个人认为并非一开始就要上微服务架构,架构是不断演化的过程,哪怕是一开始就定位很大系统,可以先划分出基本的服务就行(比如登录系统、支付中心、内容服务、接口开放平台和后台系统),更细的划分可以随着业务的发展不断演化——当然前提是要一直保证代码的整洁和简洁、遵循基本的面向对象代码原则。 垂直切片架构:我是最近才接触到了这种架构,我们的项目最近用到了MediatR和AutoMapper,这两个开源项目的作者Bogard JIMMY BOGARD在自己的项目中实现了这种架构,通过反思洋葱架构和整洁架构等各种分层和抽象得出来的一种架构,作者不建议做太多的分层,因为各种以来会导致大量的问题,作者认为在微服务架构里面特别实用,当然代码也会准从DDD的设计原则。作者认为在所谓传统正常的“N层”或六边形或任何架构中,通过垂直切片移除这些层障碍,并沿着变化轴聚合在一起:

March 24, 2023