一、怎样将软件架构思想应用到代码中?

  1. 上篇说到,好的软件架构,是要花费最小的人力,实现软件的构建和维护
  2. 那对应到代码中是什么样呢?

个人理解,就是需求变动的时候,需要改动的代码最少。

  1. 但是需求就是在不断的变,要改动的代码怎么能少呢?

需求的变化不是我们工程师能决定的。但是修改的代码量却是可以减少的。

使用合理的方法应对变化,是核心。

  1. 对于个人而言,如何就能算花费的能量最少了?

看《意志力》一书讲了,人在不断做决策的过程中,会消耗大量能量。

这也是我们工程师消耗能量最多的地方。工程师就是要不断分析当前条件,给出当前情况下我认为最正确的方法。不断决策。

因此,我们需要想办法设计,让我们在维护的过程中尽可能的少做决策。

二、关于软件设计的个人看法

  1. 计算机编程的本质是降低复杂度,没有万能药。

是我看《unix编程艺术》一书中看到的。

我认同,我认为工程师就是要不断分析当前条件,给出当前情况下我认为最正确的方法。

如果通过套用一下什么公式,就设计出完美的软件,那真是太无聊了。

软件架构 收敛 软件架构之道_实际案例

  1. 架构的设计者需要是一线程序员。

因为一线的程序员,才能时刻体会到不良的设计带来的问题。

  1. 软件的设计需要从实际案例出发。

因为没有万能药,很难空想什么高大上的模式来解决问题。要从实际情况出发。

  1. 软件设计是要分离变化和不变的部分

下面的案例将说明这个问题。

饮血剑是否被购买,饮血剑的参数,饮血剑的被动效果。都是可能被调整的。但是只要把这些可能变化的部分分离出去,代码就更可靠。

三、实际案例

  1. 介绍一下背景。
    英雄联盟中,买了饮血剑之后,打别人是可以将造成的伤害,转换成自己的HP增加的。
    如果让你来实现一下饮血剑的吸血功能,如何实现?
  2. 考虑两种方案。
  • 第一种:

A 购买饮血剑之后,每次攻击,就判断自己是否有饮血剑。

消息传递给B(告诉B我有饮血剑)(B被攻击)。

B收到伤害之后,判断A给自己的消息,是否有饮血剑,if (withEatFloodSword == 1) ,然后根据自身受到的伤害给A回血。

  • 第二种:

A购买饮血剑之后,设置一下攻击到别人的时候的回调函数。比如,onAttackOther 回调。

消息发送给B,(B被攻击)

B受到伤害之后,尝试调用onAttackOther回调,如果回调非空,就调用。否则就不调用。

  1. 然后评估一下两种方案。
  • 采用第一种方案,饮血剑的作用范围。

从购买到被攻击,都需要A有饮血剑这个信息的参与

  • 采用第二种方案,饮血剑的作用范围。

只有购买成功的时候作用一下。

卖掉饮血剑的时候,可能把这个回调置空就可以。

  1. 如果有bug.发现吸血吸不上来。
  • 首先,使用第二种方案出现bug的可能性就低,因为只要购买的时候给函数指针赋值了,饮血剑回调功能是对的,基本就是OK的。
  • 其次,第二种方案有bug,基本也就是集中在饮血剑 这个类或者说 模块中。不会影响其它。
  • 但是第一种方案实现,你需要跟踪整个流程去排查。而且,别的什么修改也可能在流程中干扰饮血剑的工作。工作量就非常大。
  • 第一种方案,你需要做大量的决策来解决问题。第二种方案要少的多。
  1. 扩展。
  • 事实上,就算是别的什么功能的装备也可以使用这个机制。比如,你买破败+饮血+九头蛇,那就把对应的回调加到链表中一个个执行就可以。
  • 如果使用第一种方案,那你要整个流程都加一遍。工作量就非常大。
  • 第一种方案,你需要大量的决策去调试新功能。第二种就不是。基本一个饮血剑好使,其它的就也好使了。
  1. 总结

1.购买的装备是什么,装备的属性,装备的被动,是可能被调整,可能变化的。但是使用这种方法,可以在需求变化的时候,我们少改一些代码。

2.使用第二种方法,饮血剑和整个攻击流程的节点,没有耦合。

3.实际的设计中,就是面对这些形形色色的问题,不断地思考方法,让要修改的部分,尽可能的少

4.我们不能消灭变化,但是可以把变化的部分尽可能放到一小部分代码中。让不变的代码,永远不要变。每次只修改变化的小部分代码,我们的工作量,就会降低。

5.如果真的和上一条所说的这样,架构就是好的架构。

6.这就是 《unix编程艺术》中说的,分离原则,策略与机制分离,接口和引擎分离。机制往往是不变的。策略是随时变化的。我们要做的就是每次维护只改变策略来满足需求。

7.尽可能设计让维护的工程师做更少决策的代码。

四、参考文献

  1. 《unix编程艺术》
  2. 《架构整洁之道》
  3. 《意志力》