好架构的特点 by Martin
A good architecture allows major decisions to be DEFERRED!
A good architecture maximizes the number of decisions NOT made
设计架构时最容易犯得错误就是先关注细节,例如用什么数据库,用什么框架,但是这些都不是最重要的,架构最需要关注的是
- 系统存在的原因,背景,目的
- 系统在做什么,解决什么问题
- use cases
- 什么业务模型能更好的满足 use cases
关于架构的一些原则和知识
- 架构的三个维度:业务,技术,组织
- (第一性) 架构的设计目标是以最小的人力来构建和维护系统: 最大化程序员的生产力, 同时最小化系统的运营成本
- 工程师一般都会过于自信,而且不会偷懒工作。真正偷懒的地方是持续低估那些优秀的良好设计代码和架构的重要性
- 无论是长期还是短期,胡乱设计的代码和架构的工作速度其实比用正确的方式更慢; 唯一可以使工作变快的方法是使用正确的方式做事
- 为设计良好的架构而斗争. 如果系统越来越难以维护,最终无法修改, 或者靠大量人力修复无止尽的 bug,这说明架构师没有与需求方做足够的抗争,没有完成自己应尽的职责。
- 最小表达力原则(Least expressiveness principle)值得遵守: 只有当使用最简洁的方式(常量,查表)不能表达想法时,再去使用图灵完备的编程语言.
- 用尽可能简单的形式解决问题, 达成目标, 符合架构的第一性原则.
- 架构是关于Trade-off的工作, 一切架构皆是选择, 没有银弹.
- 复杂性不能被消除, 只能被转移.
如何做好软件架构
- 架构师应该关注的方面: 技术 + 业务 + 组织; 技术往往是最容易解决的部分; 技术和组织都服务于业务; 注意康威定律
- 一个优秀的架构师应该致力于最大化可选项的数量,细节的决策要越晚做越好; 需要考虑到的角度,开发,部署,运行,维护,保持可选项
- 构建和维护系统过程中, 最消耗人力的是系统中的耦合. 降低耦合, 降低复杂度应该成为第一优先考虑的原则.
- 如果有两段看起来重复的代码, 如果他们有不同的变更频率或者缘由, 那么这两段代码并非真正重复
- 代码复用的决策要基于业务逻辑做出, 而不是单纯地从代码文本判断
- 当DRY原则与解耦冲突是, 解耦优先; 实际上, 代码复用并没有那么重要
- 不要将未来的需求抽象化, 想象中的需求往往不会落地. 但这并不意味着要忽略可预见的预防性建模.
- 架构的任务是找到高层策略和底层细节之间的架构边界, 同时保证这些边界遵守依赖关系原则.
- 使用多范式编程: 面向过程, 面向对象, 泛型, 函数式编程, DSL. 架构师不应将视野局限于特定的模型, 而总是选择最适合的范式. 范式的选择应遵循最小表达力原则.
关于复杂性
- 复杂性不能被消除, 只能被转移. 参考控制论的”必要多样性”概念: 只有复杂性才能处理复杂性. 实际上, 多想想现实世界的各种”不可能三角”.
- 将复杂度控制在明确定义的地方, 而不是尝试隐藏它.
- 复杂性的来源
- 不要尝试消除复杂度, 设法学习专业的知识, 以加强你对复杂度的了解
关于高效能团队
- 团队有四种基本拓扑: 流动式团队, 赋能团队, 复杂子系统团队, 平台团队
- 团队的三种核心交互模式: 协作, 服务, 促进
- 团队协作关系
关于整洁架构
- 结构化编程限制goto, 限制程序控制权的直接转移,实现函数级别隔离
- 面向对象编程限制数据访问和函数访问, 限制程序控制权的间接转义,实现对象级别隔离
- 函数式编程限制和规范程序中的赋值,实现可变与不可变部分的隔离
关于SOLID原则
- 里氏替换原则:如果父类可以实例化, 则子类在覆写父类函数时, 行为需要与被覆写函数保持一致:前置条件不能被加强、后置条件(输出)不能被削弱、异常情况保持一致(不能抛出父类不会抛出的异常)
参考资料
高效能团队模式
软件复杂性的来源与应对
代码防腐实用技术
复杂度是不灭的
复杂度是不灭的-1
找到你的服务边界
监控报警的哲学
设计数据密集型应用
顿悟和自我突破时刻
最小表达力原则
整洁架构摘要
异地多活方案
复用是邪恶的
依赖和耦合
模块化编程
耦合
细说几种内聚的类型
图解7种耦合关系
控制论-必要多样性
变化驱动-正交设计