前言
  • 架构服务于业务,提升并行开发效率,是为了解决业务开发过程中的问题,要完成的目标,以及达到目标所制订的行为,完成相应的结果,不是为了做架构而架构
  • 每个架构师也一定都有一套自己的方法论,但不管采用什么方法,全局观、高度的代码审美能力,和灵活使用各种设计模式都贯穿其中的,架构的意义是要实现高内聚低耦合。架构跟设计模式息息相关,那么都有哪些设计模式呢?
  • 架构设计的六大原则,以及衍生的原则都有哪些?
背景
  • 以客户愿景为前提,提取分解出顶层概念,再而分解成子系统或模块,然后每个子系统再拆分业务功能,
  • 过程:顶层设计 -> 子系统设计 -> 模块设计 -> 类文件设计 -> 方法设计,把一个庞大的系统最后分解成一个个组件
  • 分解,聚焦问题,降低问题的复杂度;隔离问题,便于管理;
  • 居高临下宏观上统筹规划,排任务优先级,防止出现瓶颈,做到风险前移,理清系统边界,挖掘潜在需求。
  • 提取通用功能、降低开发工作量。重复是软件的大忌。
架构设计的方法论

每个架构师都有自己的一套方法论:

  • 第一步:搞清楚要解决哪些问题,并找到解决这些问题的充要条件

    • 你必须得清楚你要做什么,业务方希望要什么。而不是为了架构而架构,也不是为了体验新技术而改架构方案。以前是MVC,最近流行MVVM,如果过去的MVC是个好架构,没什么特别大的缺陷,就不要推倒然后搞成MVVM。
    • 关于充要条件我也要说明一下,有的时候系统提供的函数是需要额外参数的,比如read函数。还有翻页的时候,当前页码也是充要条件。但对于业务方来说,这些充要条件还能够再缩减。比如read,需要给出file descriptor,需要给出buf,需要给出size。但是对于业务方来说,充要条件就只要file descriptor就够了。再比如翻页,其实业务方并不需要记录当前页号,你给他暴露一个loadNextPage这样的方法就够了。
    • 搞清楚对于业务方而言的真正充要条件很重要!这决定了你的架构是否足够易用。另外,传的参数越少,耦合度相对而言就越小,你替换模块或者升级模块所花的的代价就越小。
  • 第二步:问题分类,分模块

  • 第三步:搞清楚各问题之间的依赖关系,建立好模块交流规范并设计模块

    • 关键在于建立一套统一的交流规范。这一步很能够体现架构师在软件方面的价值观,虽然存在一定程度上的好坏优劣(比如胖Model和瘦Model),但既然都是架构师了,基本上是不会设计出明显很差的方案的。所以这里是架构师价值观输出的一个窗口,从这一点我们是能够看出架构师的素质的。
    • 另外要注意的是,一定是建立一套统一的交流规范,不是两套,不是多套。你要坚持你的价值观,不要摇摆不定。要是搞出各种五花八门的规范出来,一方面有不切实际的炫技嫌疑,另一方面也会带来后续维护的灾难。
  • 第四步:推演预测一下未来可能的走向,必要时添加新的模块,记录更多的基础数据以备未来之需考虑架构未来的走向,以及考虑做完这一轮架构之后,接下来要做的事情。一个好的架构虽然是功在当代利在千秋的工程,但绝对不是一个一劳永逸的工程。软件是有生命的,你做出来的架构决定了这个软件它这一生是坎坷还是幸福。

  • 第五步:先解决依赖关系中最基础的问题,实现基础模块,然后再用基础模块堆叠出整个架构

    • 这一步也是验证你之前的设计是否合理的一步,随着这一步的推进,你很有可能会遇到需要对架构进行调整的情况。这个阶段一定要吹毛求疵高度负责地去开发,不要得过且过,发现架构有问题就及时调整。否则以后调整的成本就非常之大了。
  • 第六步:量化,打点,跑单元测试,跑性能测试,根据数据去优化对应的地方
    你得用这些数据去向上反馈,体现自己的能力和价值(向你的boss邀功),你也得用这些数据去不断调整你的架构。

总而言之就是要遵循这些原则:自顶向下设计(1,2,3,4步),自底向上实现(5),先测量,后优化(6)。

架构设计原则

架构设计原则要学会灵活应变,千万不要生搬硬套,否则只会把简单问题复杂化,六大原则的英文首字母拼在一起就是 SOLID(稳定的),所以也称之为 SOLID 原则

SOLID 原则

  • 1,单一责任原则(Single Responsibility Principle - SRP):对于一个类,仅有一个引起它变化的原因,不同的类具备不同的职责,分工协作各司其职。
  • 2,开放封闭原则(Open Closed Principle - OCP):对扩展开放,对修改封闭,要考虑到后续的扩展性,而不是原有的基础上来回修改。
  • 3,里氏替换原则(Liskov Substitution Principle - LSP):父类可以被子类无缝替换,且不影响原有的任何功能。
  • 4,迪米特法则(最少知识原则 Least Knowledge Principle - LKP):尽量减少类的依赖关系,减少对象之间的交互,从而减少类之间的耦合,低耦合高内聚
  • 5,接口隔离原则(Interface Segregation Principle - ISP):不对外暴露没有意义的接口。
  • 6,依赖倒置原则(Dependence Inversion Principle - DIP):高层具体实现模块不应该依赖底层模块,应该依赖于抽象层,抽象层不应该依赖于具体实现,应该依赖于底层。

粒度原则

  • REP(复用、发布等同原则):软件复用的最小粒度应等同于其发布的最小粒度。直白地说,就是要复用一段代码就把它抽成组件,该原则指导我们组件拆分的粒度。
  • CCP(共同闭包原则):为了相同目的而同时修改的类,应该放在同一个组件中。CCP 原则是 SRP 单一责任原则在组件层面的描述。该原则指导我们组件拆分的粒度。对大部分应用程序而言,可维护性的重要性远远大于可复用性,由同一个原因引起的代码修改,最好在同一个组件中,如果分散在多个组件中,那么开发、提交、部署的成本都会上升。
  • CRP(共同复用原则):不要强迫一个组件依赖它不需要的东西。CRP 原则是 ISP原则在组件层面的描述。该原则指导我们组件拆分的粒度。

REP、CCP、CRP 三个原则之间存在彼此竞争的关系,REP 和 CCP 是黏合性原则,它们会让组件变得更大,而 CRP 原则是排除性原则,它会让组件变小。遵守REP、CCP 而忽略 CRP,就会依赖了太多没有用到的组件和类,而这些组件或类的变动会导致你自己的组件进行太多不必要的发布;遵守 REP、CRP 而忽略 CCP,因为组件拆分的太细了,一个需求变更可能要改 n 个组件,带来的成本也是巨大的。

其它设计原则

  • 不要重复你自己(Don’t repeat yourself - DRY)
    不要让重复的代码到处都是,要让它们足够的重用,所以要尽可能地封装。

  • 保持它简单与傻瓜(Keep it simple and stupid - KISS)
    不要让系统变得复杂,界面简洁,功能实用,操作方便,要让它足够的简单,足够的傻瓜。

  • 高内聚与低耦合(High Cohesion and Low Coupling - HCLC)
    模块内部需要做到内聚度高,模块之间需要做到耦合度低。

  • 惯例优于配置(Convention over Configuration - COC)
    尽量让惯例来减少配置,这样才能提高开发效率,尽量做到“零配置”。很多开发框架都是这样做的。

  • 命令查询分离(Command Query Separation - CQS)
    在定义接口时,要做到哪些是命令,哪些是查询,要将它们分离,而不要揉到一起。

  • 关注点分离(Separation of Concerns - SOC)
    将一个复杂的问题分离为多个简单的问题,然后逐个解决这些简单的问题,那么这个复杂的问题就解决了。难就难在如何进行分离。

  • 契约式设计(Design by Contract - DBC)
    模块或系统之间的交互,都是基于契约(接口或抽象)的,而不要依赖于具体实现。该原则建议我们要面向契约编程。

  • 你不需要它(You aren’t gonna need it - YAGNI)
    不要一开始就把系统设计得非常复杂,不要陷入“过度设计”的深渊。应该让系统足够的简单,而却又不失扩展性,这是其中的难点。

设计模式

请添加图片描述
我们知道的设计模式有很多,但是有没有仔细思考过这些设计模式呢,这些设计模式总体分三种:创建型,结构型,以及行为型
认清这些设计模式,可以更好的帮助架构师构造我们的项目工程。

架构目标
  1. 代码整齐,分类明确,没有common,没有core(关联)
  2. 不用文档,或很少文档,就能让业务方上手
  3. 思路和方法要统一,尽量不要多元
  4. 没有横向依赖,万不得已不出现跨层访问
  5. 对业务方该限制的地方有限制,该灵活的地方要给业务方创造灵活实现的条件
  6. 易测试,易拓展
  7. 保持一定量的超前性
  8. 接口少,接口参数少
  9. 高性能