08 - 架构设计三原则

优秀程序员和架构师之间还有一个明显的鸿沟需要跨越,这个鸿沟就是“不确定性”;
对于编程来说,本质上是不能存在不确定的,而对于架构设计来说,本质上是不确定的,同样的一个系统,A 公司和 B 公司做出来的架构可能差异很大,但最后都能正常运转。

选择

相比编程来说,架构设计并没有像编程语言那样的语法来进行约束,更多的时候是面对多种可能性时进行选择

  • 是要选择业界最先进的技术,还是选择团队目前最熟悉的技术?如果选了最先进的技术后出了问题怎么办?如果选了目前最熟悉的技术,后续技术演进怎么办?
  • 是要选择 Google 的 Angular 的方案来做,还是选择 Facebook 的 React 来做?Angular 看起来更强大,但 React 看起来更灵活?
  • 是要选 MySQL 还是 MongoDB?团队对 MySQL 很熟悉,但是 MongoDB 更加适合业务场景?
  • 淘宝的电商网站架构很完善,我们新做一个电商网站,是否简单地照搬淘宝就可以了?

架构设计领域并没有一套通用的规范来指导架构师进行架构设计,更多是依赖架构师的经验和直觉

  • 架构设计时遵循这几个原则,有助于你做出最好的选择
    1. 合适原则
    2. 简单原则
    3. 演化原则

合适原则

  • 合适原则宣言:“合适优于业界领先”

再好的梦想,也需要脚踏实地实现!这里的“脚踏实地”主要体现在下面几个方面

  1. 将军难打无兵之仗

大公司的分工比较细,一个小系统可能就是一个小组负责,阿里的中间件团队有几十个人,而大部分公司,某个业务团队可能就十几个人。十几个人的团队,想做几十个人的团队的事情,而且还要做得更好,不能说绝对不可能,但难度是可想而知的

  • 没那么多人,却想干那么多活,是失败的第一个主要原因。
  1. 罗马不是一天建成的

业界领先的很多方案,都是经过几年时间的发展才逐步完善和初具规模的,经历过的挑战和踩坑,都是架构设计非常关键的促进因素,单纯靠拍脑袋或者头脑风暴,是不可能和真正实战相比的

  • 没有那么多积累,却想一步登天,是失败的第二个主要原因。
  1. 冰山下面才是关键

大多的时候,业界领先的方案其实都是“逼”出来的,“业务”发展到一定阶段,量变导致了质变,出现了新的问题,已有的方式已经不能应对这些问题,需要用一种新的方案来解决,通过创新和尝试,才有了业界领先的方案

  • 没有那么卓越的业务场景,却幻想灵光一闪成为天才,是失败的第三个主要原因。
  • 真正优秀的架构都是在企业当前人力、条件、业务等各种约束下设计出来的,能够合理地将资源整合在一起并发挥出最大功效,并且能够快速落地

简单原则

  • 简单原则宣言:“简单优于复杂”
  • 软件领域的复杂性体现在两个方面:
  1. 结构的复杂性
  • 结构复杂的系统几乎毫无例外具备两个特点:
    1. 组成复杂系统的组件数量更多;
    2. 同时这些组件之间的关系也更加复杂。
  • 以图形的方式来说明复杂性:
两个组件组成的系统

三个组件组成的系统

四个组件组成的系统

五个组件组成的系统
  • 组件越多,就越有可能其中某个组件出现故障,从而导致系统故障
    • 假设组件的故障率是 10%
    • 有 3 个组件的系统可用性是(1-10%)×(1-10%)×(1-10%)= 72.9%
    • 有 5 个组件的系统可用性是(1-10%)×(1-10%)×(1-10%)×(1-10%)×(1-10%)=59%
  • 某个组件改动,会影响关联的所有组件,这些被影响的组件同样会继续递归影响更多的组件
    • 以上面图中 5 个组件组成的系统为例,组件 A 修改或者异常时,会影响组件 B/C/E,D 又会影响 E
    • 这个问题会影响整个系统的开发效率,因为一旦变更涉及外部系统,需要协调各方统一进行方案评估、资源协调、上线配合
  • 定位一个复杂系统中的问题总是比简单系统更加困难
    • 首先是组件多,每个组件都有嫌疑,因此要逐一排查
    • 其次组件间的关系复杂,有可能表现故障的组件并不是真正问题的根源
  1. 逻辑的复杂性

意识到结构的复杂性后,那我们是不是可以,用最简单的结构,就是整个系统只有一个组件,即系统本身,所有的功能和逻辑都在这一个组件中实现

显然这样做是行不通的,原因在于除了结构的复杂性,还有逻辑的复杂性,即如果某个组件的逻辑太复杂,一样会带来各种问题

  • 逻辑复杂几乎会导致软件工程的每个环节都有问题,假设现在淘宝将这些功能全部在单一的组件中实现,可以想象一下这个恐怖的场景
    1. 系统会很庞大,可能是上百万、上千万的代码规模,“clone”一次代码要 30 分钟
    2. 几十、上百人维护这一套代码,某个“菜鸟”不小心改了一行代码,导致整站崩溃
    3. 需求像雪片般飞来,为了应对,开几十个代码分支,然后各种分支合并、各种分支覆盖
    4. 产品、研发、测试、项目管理不停地开会讨论版本计划,协调资源,解决冲突
    5. 版本太多,每天都要上线几十个版本,系统每隔 1 个小时重启一次
    6. 线上运行出现故障,几十个人扑上去定位和处理,一间小黑屋都装不下所有人,整个办公区闹翻天
    7. 谁都无法忍受这样的场景...
  • 复杂的电路就意味更强大的功能,而复杂的架构却有很多问题
    • 原因在于电路一旦设计好后进入生产,就不会再变,复杂性只是在设计时带来影响
    • 而一个软件系统在投入使用后,后续还有源源不断的需求要实现,因此要不断地修改系统,复杂性在整个系统生命周期中都有很大影响
  • 复杂算法导致的问题主要是难以理解,进而导致难以实现、难以修改,并且出了问题难以快速解决
    • ZooKeeper 功能虽然相对简单,但因使用ZAB协议,系统实现却比较复杂
    • etcd 采用的是 Raft 算法,相比 ZAB 协议,Raft 算法更加容易理解,更加容易实现
  • 无论是结构的复杂性,还是逻辑的复杂性,都会存在各种问题,所以架构设计时如果简单的方案和复杂的方案都可以满足需求,最好选择简单的方案

演化原则

  • 演化原则宣言:“演化优于一步到位”。

从和目的、主题、材料和结构的联系上来说,软件架构可以和建筑物的架构相比拟。
—— 维基百科

  • 对于建筑来说,永恒是主题;而对于软件来说,变化才是主题
  • 架构设计的一个误区:试图一步到位设计一个软件架构,期望不管业务如何变化,架构都稳如磐石
  • 考虑到软件架构需要根据业务发展不断变化这个本质特点,软件架构设计其实更加类似于大自然“设计”一个生物,通过演化让生物适应环境,逐步变得更加强大:
    • 首先,生物要适应当时的环境
    • 其次,生物需要不断地繁殖,将有利的基因传递下去,将不利的基因剔除或者修复
    • 第三,当环境变化时,生物要能够快速改变以适应环境变化;如果生物无法调整就被自然淘汰;新的生物会保留一部分原来被淘汰生物的基因
  • 软件架构设计同样是类似的过程:
    • 首先,设计出来的架构要满足当时的业务需要
    • 其次,架构要不断地在实际应用过程中迭代,保留优秀的设计,修复有缺陷的设计,改正错误的设计,去掉无用的设计,使得架构逐渐完善
    • 第三,当业务发生变化时,架构要扩展、重构,甚至重写;代码也许会重写,但有价值的经验、教训、逻辑、设计等(类似生物体内的基因)却可以在新架构中延续
  • 实际架构设计时,应认真分析当前业务的特点,明确业务面临的主要问题,设计合理的架构,快速落地以满足业务需要,然后在运行过程中不断完善架构,不断随着业务演化架构

小结

本文介绍了面对“不确定性”时架构设计的三原则,分别是合适优于业界领先、简单优于复杂、演化优于一步到位

你可能感兴趣的:(08 - 架构设计三原则)