设计的目的
一般在程序编程,方案设计,以至系统架构的时候,往往会考虑以下几个方面的折衷,然后应用某类”设计模式”或者”架构思想”:
- 初次开发效率(设计直观性,时间成本)
- 可维护性,可读性(scope不变的情况下,是否改动频繁)
- 可扩展性(后续scope会否增大,甚至是否可能要支持进一步拆分以及并行多人员开发)
- 可扩容性(流量压力是否可能增大)
- 鲁棒性(抗regression,抗edge case)
- 可用性
- 实时性
- 一致性
- 对快速发布的要求
以上是直接的目标,有一些细节层面的表现:
- 代码或者架构是否足够清晰,是否有过度冗余(冗余其实不一定有问题)
- 耦合是否松散
- 内聚性如何,是否自恰,完备
- 是否易于改动或者扩展
有一句 一般性正确 的话叫做”高内聚,低耦合,易扩展,拥抱变化“,并不是这样的设计就一定对,只不过可能适用于大多数场景。
然后要特别注意避免“过度设计或者过度优化”。
而对于大多数互联网应用而言,目标往往是为了能实现敏捷开发、部署、迭代。
不同的设计思想
再后面因为对目标优先级的不同,可延伸出不同的”模式”或者”思想”,比如:
- 面向过程 vs 面向对象 vs 面向组件 vs 函数式
- 巨型单体 vs 面向服务 vs 微服务 vs 分布式高并发设计
- 各种设计模式
- 继承 vs 组合
- 开放 vs 封闭 (对扩展开放,对修改封闭)
- 约定 vs 配置
总体而言,没有绝对的”好”与”坏”,主要还是要看应用场景和目标优先级,来选择适合的方案。
以下几个具体的”模式”或者”思想”。
面向对象
这其实也像是一 世界观,如何在程序的世界里“认知和抽象现实世界“。
主要是应用封装,继承,多态。
有以下几个优势:
- 内聚性较好,对象掌控自己的核心功能模块(“封装”)
- 耦合规则清晰,对象的边界清晰(“封装”,世界观是由不同的对象建立起来的)
- 以上可以提供不错的扩展性,和鲁棒性
- 规避冗余,方便重用(“继承”,“多态”)
微服务
一般来说,应用微服务是为了 处理复杂场景 的,采用的原因往往是 1)业务非常复杂,且规模很大 2)开发的人员和团队非常多。
能大幅提高并行开发能力,但对基础架构要求较高,可用性也是个挑战
它的优势:
- 边界清晰,单个服务很容易开发、理解和维护(但设计不好的情况下,整体上可能是比较能理解甚至混乱的)
- 方便控制regression,往往一个功能的改动只会影响一个具体的服务。
- 部署速度较快,每个服务可以单独发布,且体量较小。
- 每个服务可以独立扩展。计算密集型,IO密集型的服务可以有效分离,更方便科学扩展。
一些挑战: - 如前面所言,整体的复杂必不一定下降,甚至上升。
- 分布式系统对基础架构(PaaS)的要求较大,不然会大幅增加基础架构的维护成本。
- 如果依赖性比较复杂,可用性不易控制。
关于扩展:
- 水平扩展(复制实例,应用负载均衡)
- 业务拆分(不同的业务,不同的计算、吞吐属性)
- 数据分区(不同地域)
参考: