仓库源文

.. Kenneth Lee 版权所有 2017-2020

:Authors: Kenneth Lee :Version: 1.0

概要设计不是代码


很多人不做概要设计,代码写成什么样就写成什么样。有些人在要求下写概要设计,但基 本上把代码选择性地拷贝上来。

但我review这些的代码的时候,就算写了概要设计(这个文档),我也总是忍不住想吐嘈 :为什么不做概要设计?

什么时候我会想吐嘈呢?我举一些例子:

  1. 概念空间混乱,device这个名字,有时指驱动,有时指模块,有时指设备的实例,除了 跟踪执行流程,你完全把握不了这个代码是如何组织的

  2. 函数安排得乱七八糟,该属于这个模块的函数或者函数实现,写到了另一个模块或者函 数中

  3. 数据结构混乱,指针满天飞,最后你只能认为所有的数据都是全局的。就算他们的索引 在某个模块内,但在这些无所不在的指针的帮忙下,你总是可以从任何地方访问任何数 据。

  4. 状态机混乱,状态机本身不是自恰的,而是附属于流程的。经常是在这个流程中缺个标 记,就加个状态,然后对应写个if,在另一个流程中又需要一个状态了,又写一个if。 好了,最后你想复盘这个状态机的时候,你发现状态空间奇大无比,你根本不知道系统 最后会陷在什么状态上。生生把一个可控的代码变成一个卷积神经网络。

  5. 逻辑关系混乱,比如分配一个资源,本来应该在全局资源池中分配的,结果写的时候看 到本对象里有一个“本CPU的资源列表”,顺手就从这个列表分配了。这种代码,跑也是 能跑的。但不对就是不对。

  6. 锁关系混乱,交叉死锁。链表的锁,链表成员的锁,类的锁,类实例的锁乱用,看见谁 用谁。或者关键流程上锁,把大部分CPU堵死。或者对非原子变量偷鸡,不上锁。所有 这些行为,都是把系统放入一个不可知状态,这种程序一旦成型,根本无法维护。

很多人不明白国内的代码为什么都活不长久,你抽离那些政治,民主,民族,人情的争辩 ,想想你自己怎么写程序的。这样的程序也能活得长久,那真是没有天理了。

由此知之,我认为概要设计应该做的事情是:

  1. 概念定义,以及概念之间的关系

  2. 概念和数据结构的对应关系

  3. 概念和模块的对应关系

  4. 关键状态机

  5. 关键流程(注意,不是代码,这是为了把模块关系串起来,不是为了描述代码关系)

  6. 线程部署,锁的关系。

  7. 关键Latency路径

  8. 关键动态对象(资源)的生命周期

  9. 接口函数组的集体Review,A模块对外提供了一组函数,有十几个,多了吗?少了吗? 关系可以整合吗?这要成组进行推演。

  10. 外部接口,比如配置方法,API设计等

不一定全部要写,取决于哪些代码本身无法表达。

所以,概要设计,很大程度上是UML图,ER图,STP图,但它们不是代码的翻译。代码不是 概要设计,别拷贝代码上来。

ps:有人会提出,代码本身可以代替概要设计。我对此的观点是:如果你的代码能清晰表 述上面提出的概念(包括在代码未来发展的方向上),代码确实可以代替概要设计。但除 了逻辑非常简单的模块或者Plugin,我没有看过3千行以上的代码可以这样做的。

但我个人支持这样的代码存在,对于这样的代码,我认为可以隔离在某个特定的枝叶节点 上,比如某个网页上用于展示的js代码,那种代码破坏性低,生存期短,但能解决特定问 题,也有它的作用。