架构是什么?

尘码刚刚踏入编程的大门的时候,就总听到前辈们在谈论一个名词: 架构

他对于这个词充满了好奇,这好像是一个神奇的存在,能够塑造整个软件的形态,决定其成败。

前辈发现了尘码的疑惑,讲解道:

你可以把架构看作是一座大厦的结构。
我们在这个结构中放置各个功能模块,确保它们相互协调,整个系统能够稳定运行。

尘码点点头,似乎懂了,又似乎没懂。

前辈见状笑了笑,说:且听我徐徐道来。

一、架构起源

1.1 任务清单时代

很久很久之前,编程界还没出现 架构 的说法。

在那个古老的年代,所谓编程就是挨个给计算机下达一系列的指令。

就像小时候我妈喊我出去买菜,给我一个任务清单:

  1. 先去楼下小卖部打瓶酱油。
  2. 然后到菜市场买一个土豆。
  3. 如果看到西瓜,就买两个。
  4. 最后,别忘了在回家的路上买包面包。

当时的编程方式就好比小时候的任务清单,这对于一些简单的任务来说可能足够了,就像买菜的任务清单一样。

PS: 用专业属于来说,这叫做 面向过程

1.2 任务清单模式的问题

但是随着时间的推移,人们发现编程世界面临着越来越复杂的挑战。

比如一个贪吃蛇游戏,你能否用任务清单的方式去说明这个游戏的编写逻辑呢?

是有点复杂,但我们勉强也能想到办法:

  1. 初始化游戏:

    1. 创建蛇的初始位置和长度。
    2. 在游戏区域生成初始食物。
  2. 处理用户输入:

    1. 监听用户按键,包括上、下、左、右箭头键。
    2. 根据按键调整蛇的移动方向。
  3. 更新蛇的位置:

    1. 根据当前移动方向,更新蛇头的位置。
    2. 更新蛇身体的位置。
  4. 检测碰撞:

    1. 检测蛇头是否与食物位置重合,如果是,增加蛇的长度,并在新位置生成食物。
    2. 检测蛇头是否与蛇身体碰撞,如果是,游戏结束。
    3. 检测蛇头是否与墙壁碰撞,如果是,游戏结束。
  5. 更新游戏状态:

    1. 记录游戏分数。
    2. 更新游戏速度(随着时间的推移可以加快)。
  6. 绘制游戏界面:

    1. 在屏幕上绘制蛇的位置和形状。
    2. 绘制食物的位置。
    3. 显示当前分数和游戏状态
  7. 游戏结束处理:

    1. 显示游戏结束画面。
    2. 提供重新开始游戏的选项。

也确实可以实现。
而如果我们想让这个贪吃蛇游戏更好玩,添加更多的想法。
比如给食物加点特殊效果——某些食物吃了会加速。

此时我们不得不回到刚才这么一大坨任务清单式的逻辑中寻找这个新功能的位置。
光是想想都头大,这样太麻烦了,而且以后每加一个新功能,我们都得重新痛苦一番。

我们需要想想办法——怎么样才能让我们更方便的添加新功能呢?

1.3 架构设计的萌芽

很自然的,我们发现,可以把我们的逻辑归纳总结起来,分而治之!
我们可以把整个贪吃蛇游戏例子中的任务清单逻辑归纳总结起来!

整个游戏逻辑可以分为3类:

  • 游戏世界类:

    • 负责游戏的整体逻辑和流程控制。
    • 包含 Snake 对象和 Food 对象。
    • 处理用户输入、更新游戏状态、绘制游戏界面等。
  • 贪吃蛇类:

    • 表示贪吃蛇对象。
    • 包含蛇的位置、长度、移动方向等属性。
    • 提供移动、吃食物、检测碰撞等方法。
  • 食物类:

    • 表示食物对象。
    • 包含食物的位置、效果等属性。
    • 提供生成新的位置等方法。

当需要给食物添加新功能(例如加速效果)时,我们只需修改 食物类 的相关逻辑,而不必涉及整个游戏的逻辑。新功能的添加不会对游戏的整体逻辑产生影响。

这很棒,很完美。

PS:这就叫 面向对象 设计,这个过程也叫 架构设计

二、架构概念

2.1 开发上的概念

在上文贪吃蛇整个的设计过程,咱们做了三件事:

  1. 明确 业务目标 :实现贪吃蛇游戏
  2. 拆分 多个模块 :游戏模块、贪吃蛇模块、食物模块
  3. 把他们 组合 起来以实现目标。

对于开发来讲,架构便特指根据业务目标所实现的模块模块间的关系的设计。

2.2 团队上的概念

而随着项目的增长,往往会需要更多的同学一起进行协作开发。而人多了问题就多了,比如:

  1. 能力问题:
    一个团队的成员的能力往往都是良莠不齐的。
  2. 沟通问题:
    不同的小伙伴负责不同的任务,但往往对互相的任务互不关心。
    团队信息传递也并不总会那么顺畅,导致每个人对整个项目的了解都不够深入。
    这同样需要在架构上做相应的思考和设计。
  3. 冲突问题:
    多人并行开发的情况下,总会出现代码冲突的情况。
    解决冲突往往也还需要额外的功夫,有时候甚至需要重新设计代码结构,增加了开发的难度。
  4. 等等等等,后面章节中再讨论。

架构 同样也得根据上诉问题,去考虑模块的拆分和设计。

2.3 运维上的概念

在项目成果落地后,长期的运行维护期间也需要考虑不少问题,比如:

  1. 需求变更:
    在项目运行的过程中,需求可能会发生变化。架构应该具有足够的灵活性,以便在不影响整体稳定性的前提下进行相对容易的调整和扩展。良好的架构应该能够支持对功能的快速迭代,使项目能够适应不断变化的业务需求。
  2. 运行质量:
    用久了、用的人多了,总会出现质量问题。
    包括但不限于性能下降、内存泄漏、逻辑冲突等等。
    架构设计应该考虑到这些可能的问题,并提供相应的解决方案。
    例如通过监控、通过抽查、或者一些自动化测试的机制。
  3. 技术债务:
    无论架构设计得多好,技术债都是不可避免的。
    可能来自某个开发不注意,可能来自某天项目赶着上线。
    架构设计应该注重可维护性,以减少技术债务的累积。
  4. 等等等等,后面章节中再讨论。

也就是说,架构 除了满足当前业务目标外,还得尽量去考虑未来需求的变化,去考虑配套设施工作机制的设计,以去确保整个软件工程的高效稳定的运行,创造价值。

2.4 整体概念

所以通常来讲,我们谈的 架构 其实不仅仅只是指代 代码 上的设计,而是整个软件工程的设计。

在软件架构中,需要从整个软件工程的生命周期出发,思考项目的全局设计。这包括从业务目标需求分析产品设计代码设计整体测试发布上线运营维护,甚至下线死亡的每个阶段。在这个过程中,需要在满足业务需求的同时,根据实际的资源情况,通过合理的技术选型和设计原则来确保系统的稳定性、可扩展性和可维护性。

三、架构作用

总的来讲,架构设计其实就是为了让复杂的问题简单化,把一个抽象的系统给具体化。

在前文提到的贪吃蛇的架构设计中,我们在代码层面简化了问题,获得了一些好处:

  1. 比如代码更容易理解了:
    从对整个系统的理解,转变成了只需要理解三个对象。
  2. 比如新功能更容易迭代了:
    我们只用变更局部模块,而不必涉及整个系统。
  3. 比如更好测试了:
    对于每个对象单元,我们也能更好的去规划预期,设计测试用例进行测试。

而对于团队和运维上的问题同理。
也是依次发现问题分析问题,然后把大问题拆解成小问题,把抽象的问题拆解成具体的问题。
具体的策略我会在后续章节发起更详细的探讨。

稍做延展:

架构设计也不仅仅只是针对软件开发。
有系统的地方就有架构,比如咱们人体的消化系统,比如整个生态系统,无不涉及一定的架构设计。
后续章节咱们再来探讨其中哲学。

四、小结

前辈说到这里顿了一顿,才发现尘码似乎已经神游物外睡着了。
尘码似乎也是感觉到什么,突然醒来,挠挠头讪笑抱歉。

前辈微笑到:“没关系,架构设计也确实并非一蹴而就的过程,而是一个不断演化、优化的过程。一两句话本就说不清楚,若有兴趣,咱们后面再慢慢讲。”


我是尘码,欢迎一起讨论架构设计上的理解。
有兴趣也欢迎关注我的公众号:尘码的划水工坊。


尘码在摸鱼
1 声望0 粉丝