架构整洁之道

作者罗伯特 C. 马丁分类计算机-计算机综合
推荐值87.6 %来源微信读书
笔记数量21评论数量

推荐序二 久远的教诲,古老的智慧

  • ,我看到的系统设计图里,根本没有“层次”的概念,各个模块没有一致的层次划分,与子系统交互的不是子系统,而是一盘散沙式的接口,甚至接口之间随意互调、关系乱成一团麻的情况也时常出现,带来的就是维护和调试的噩梦。吹散历史的迷雾,不正是古老的goto陷阱的再现吗?

序言

  • 软件的架构并没有固定的展现形式,你所看到的每一个视图的背后都是架构师所做的层层抉择。一个视图包含了哪些部分,排除了哪些部分;用特殊形状和颜色强调了哪些部分,又有哪些部分被泛泛地一笔带过,甚至直接忽略,这些都是这个视图本身的特性。
  • 女士,这就是爱情的穷凶极恶之处,人的意愿是无穷的,而实际行动却处处受限。人的欲望是无止境的,行为却不得不遵从现实的限制。——威廉·莎士比亚[3]
  • 一个系统的常规变更不应该是成本高昂的,也不应该需要难以决策的大型设计调整,更不应该需要单独立项来推进。这些常规变更应该可以融入每日或者每周的日常系统维护中去完成。
  • 现实中是会被挑战跑得好好的为什么要改造?
    一个系统的常规变更不应该是成本高昂的,也不应该需要难以决策的大型设计调整,更不应该需要单独立项来推进。这些常规变更应该可以融入每日或者每周的日常系统维护中去完成。

前言

  • Java其实和C区别并不大,和FORTRAN也没那么大区别

第1部分 概述

第1章 设计与架构究竟是什么

  • 底层设计细节和高层架构信息是不可分割的。它们组合在一起,共同定义了整个软件系统,缺一不可。所谓的底层和高层本身就是一系列决策组成的连续体,并没有清晰的分界线。
  • 软件架构的终极目标是,用最小的人力成本来满足构建和维护该系统的需求。
  • 一个软件架构的优劣,可以用它满足用户需求所需要的成本来衡量。如果该成本很低,并且在系统的整个生命周期内一直都能维持这样的低成本,那么这个系统的设计就是优良的。如果该系统的每次发布都会提升下一次变更的成本,那么这个设计就是不好的。就这么简单
  • 要想跑得快,先要跑得稳。

第2章 两个价值维度

  • 软件系统的第一个价值维度:系统行为,是紧急的,但是并不总是特别重要。软件系统的第二个价值维度:系统架构,是重要的,但是并不总是特别紧急。
  • 业务部门与研发人员经常犯的共同错误就是将第三优先级的事情提到第一优先级去做。换句话说,他们没有把真正紧急并且重要的功能和紧急但是不重要的功能分开

第2部分 从基础构件开始:编程范式

第5章 面向对象编程

  • 面向对象编程到底是什么?业界在这个问题上存在着很多不同的说法和意见。然而对一个软件架构师来说,其含义应该是非常明确的:面向对象编程就是以多态为手段来对源代码中的依赖关系进行控制的能力,这种能力让软件架构师可以构建出某种插件式架构,让高层策略性组件与底层实现性组件相分离,底层组件可以被编译成插件,实现独立于高层组件的开发和部署。

第3部分 设计原则

第8章 OCP:开闭原则

  • 设计良好的计算机软件应该易于扩展,同时抗拒修改。换句话说,一个设计良好的计算机系统应该在不需要修改的前提下就可以轻易被扩展。
  • 让我们再来复述一下这里的设计原则:如果A组件不想被B组件上发生的修改所影响,那么就应该让B组件依赖于A组件。

第9章 LSP:里氏替换原则

  • 这里需要的是一种可替换性:如果对于每个类型是S的对象o1都存在一个类型为T的对象o2,能使操作T类型的程序P在用o2替换o1时行为保持不变,我们就可以将S称为T的子类型。
  • 这里提到的接口可以有多种形式——可以是Java风格的接口,具有多个实现类;也可以像Ruby一样,几个类共用一样的方法签名,甚至可以是几个服务响应同一个REST接口。
  • go的interface实现是否也参考了Ruby的签名?
    这里提到的接口可以有多种形式——可以是Java风格的接口,具有多个实现类;也可以像Ruby一样,几个类共用一样的方法签名,甚至可以是几个服务响应同一个REST接口。
  • 对于特殊逻辑的兼容,尽量使用configuration as code来实现,避免直接hardcode。其一是因为配置实现更加灵活,便于变更,其二也是从LSP原则考虑,尽量保证架构的简洁统一。
    软件架构师应该创建一个调度请求创建组件,并让该组件使用一个配置数据库来保存URI组装格式,这样的方式可以保护系统不受外界因素变化的影响。例如其配置信息可以如下:

第11章 DIP:依赖反转原则

  • 依赖反转原则(DIP)主要想告诉我们的是,如果想要设计一个灵活的系统,在源代码层次的依赖关系中就应该多引用抽象类型,而非具体实现。
  • 显而易见,把这条设计原则当成金科玉律来加以严格执行是不现实的,因为软件系统在实际构造中不可避免地需要依赖到一些具体实现。例如,Java中的String类就是这样一个具体实现,我们将其强迫转化为抽象类是不现实的,而在源代码层次上也无法避免对java.lang.String的依赖,并且也不应该尝试去避免
  • 我们主要应该关注的是软件系统内部那些会经常变动的(volatile)具体实现模块,这些模块是不停开发的,也就会经常出现变更。
  • 应在代码中多使用抽象接口,尽量避免使用那些多变的具体实现类
  • 在大部分面向对象编程语言中,人们都会选择用抽象工厂模式来解决这个源代码依赖的问题。
See all book notesSee all book notes