Elements of Design
条评论Preface
今天拿着《从 bal 谈谈软件系统设计》去找锋哥“检视”,他都没看几句,就开始跟我扯了。哈哈。
趁着我还记得记录一下。
设计的受众
大哥上来就说,这个东西的受众是谁,你打算写什么东西在里面:你是想跟别人介绍 bal 有什么呢?还是说描述 bal 设计成这个样子的原因呢?还是想分享从头设计一个系统的思路,给别人启发,然后拿 bal 来做例子呢?
如果是给跟我水平差不多的人、或者新员工讲,那么我只需要描述好系统里面有什么元素,这些元素之间的关系是什么,以至于为什么是这样,并不需要描述很严密的推演和思考过程。因为这个东西已经成型了,我们只需要去阐述已有东西存在的合理性就行。
如果是真是我要设计一个软件,掏出一个方案让我等级更高的人评审,那么描述的内容侧重点就不一样了,此时的文档更需要去描述设计的思考过程。
设计方案的元素
软件的设计方案大抵由这么三个部分组成:
- 假设
- 推导
- 结论
假设
假设是约束、也是约定。
约束 constraint
的意思是外部条件对软件的限制,说明了**“软件只能或者不能怎么做”**。
考虑一下从零开始研发一个产品的场景,进行软件设计时我们首先要考虑诸如业务形态、产品形态、部署形态/环境这种最大方向的问题,从而给软件进行“定性”。
举例:如果软件会被部署在多个 CPU 上,不同 CPU 上的软件是需要协同工作的,那么它就必须是分布式的。
约定 contract
表达的是这些条件是稳定的,是可以被当我软件设计的地平线,承认“软件可以做什么”。就好比 C++ 的标准,白纸黑字说明白的条款,我是可以信赖的。
举例:要做一个模块管理的功能,我们需要选择一个具体的数值类型来表示模块的 id,那这个时候如果认为部署的实例中,模块的数量不会太多,比如说不会超过 255 个,那么一个
uint8_t
足以描述这个信息。假如某天因为部署人员误操作部署了 256 个模块,那么软件是没有义务去保证模块管理功能再能正常工作的。
约束和约定其实是一个意思,但是我觉得稍微区分一下角度可以更好的去理解软件作为一个整体,它跟外部的环境其实是一个“权利和义务”的微妙关系。
那么,我说:软件要在满足约束限制的情况下,充分利用约定的带来的自由。
🤯咦 你这是什么 C++ 心法吗?
推导
有了假设之后,我们就可以进行推导了。
推导就是从假设出发,进行相关的演绎描述,类似于做数学题的答题过程:已知 X 定理(假设),所以 Y1,所以 Y2。
举个例子:
假设:软件系统是分布式的,软件可能被部署在多个进程或者说多个 CPU 上。
推导 1:模块之间必然不能仅通过指针来进行相互访问
甚至说都不应该先考虑指针推导 2:模块之间必定是通过通信来交互的
推导 3:还需要一个概念,来描述“能不能通过指针相互访问”的约束(至于要不要显式地定义为“进程”,这里就不再展开了,但是既然这么说,那肯定是不建议的:D)
推导 4:…
其实推导是整个设计过程中最有意思的一个部分,你可以基于假设,一步步地构建你心中的系统。在你不停地“自圆其说”的过程中感受到自己创造力的迸发。
推导过程其实也分 DFS 和 BFS。
假设系统被拆出一个领域 A,你既可以先把 A 里面的 a1, a2, a3… 都想清楚,当然也可以把领域 B, C, D… 都定义出来,再逐个击破。
大哥说:这个嘛,主要就看心情和本事了。如果你对某个领域比较熟悉,觉得肯定不是问题,那就可以先跳过嘛。但要是你心情好,思路连贯,那先把这个领域设计完,也可以~
结论
推导的过程就是为了得出结论。
结论也很简单,就是选择了什么方案、每个领域/子系统的职责边界、以及它们之间如何协作。
如果我们在做系统设计方案的话,这个主要是明确整体的架构,提供开发的大方向。
当然最关键的地方还是 API 和模块本身的定位吧,其实总觉得 API 就是边界就是契约,定好了边界,从系统的纬度来看,其实设计基本就完成了,因为从系统这个高度去看,必然是不关心实现的。
如果是小到模块/类的这种设计结论,实际开发流程中可能会提一下具体的接口和大致的算法逻辑?
因为已经太具象化了,所以也就顺便提一嘴,但是方案评审的关键产出绝对不是那几个 API 和成员变量的容器类型选型!
设计方案的评审
在向别人描述一个完整的设计方案的时候,大致内容应该有:
- (背景)为了解决 A1,A2… 问题;
- (假设)我认为 B1,B2…;
- (推导)所以会有 C1,C2…;
- (结论)所以我认为/选择 D1,D2…;
因此,一个设计方案被评审的时候,这四项内容都是可以被挑战的点。
通常来说背景可能会稍微宽泛一点,属于是上桌的人的共识,比如说实现一个 A1 功能、达成 A2 目标,这个是客观的,相对明确的。
需求都没搞懂搞啥设计啊喂
从假设开始,个人的因素就会开始起显著作用,评审时经常获得的同行评价就是假设“不全面”“不合理”等。
受限于设计人员的开发经历、对业务的理解,很多假设在别人眼里就是站不住脚的,这可太正常了。当然也有可能是因为大家对同一个事情的理解和预期不一致,也会产生必要的一些讨论和争执。
比如上面关于模块数量的例子,获取不同部署实体之间需要交换各自的模块信息,那么虽然单个部署实体中模块总数不会超过 255,但是整个系统来看,部署实体需要维护的模块总数是会超过 255 的。设计人员没有考虑到这个场景/约束,因此上面选型的
uint8_t
可能就不符合要求了。
这可太有趣了,我又能从别人那学到什么新奇的想法。
轮到推导了,大家对假设达成共识以后,现在就更像是题干和限制已经描述清楚,对题的演绎过程进行批判。
推导的过程常常伴随着对于既定现象的观察和定量分析,作为一个事实依据的补充来引出下一个观点。
推导的关键是要确保每一步推导都有充分的论据支持,结论之间具有清晰的逻辑关联。这个阶段强调的是推理的合理性、渐进性,大家认同的是 1 + 1 = 2
,那你的下一句不能是“地球绕着太阳转”。
推导过程中也会出现分歧,比如考虑到技术可行性、实现和维护成本、后续演进方向等,大伙对于同一件要完成的事情,也会有不同的思考。
我真的见过不少人说话前言不搭后语,两个事情之间有没有因果关系,硬是通过关联词“虽然但是”“因为所以”强词夺理进行描述。
比如说:因为这里执行慢,所以要用多线程。
这种如此直白又不经过脑子的推导,还是不要有的好。
🤔
不要“理所当然”。
不要过度追求完美。
不要主观臆断。
不要经验主义。
如果推导过程顺利,那么最后的结论大家应该也是基本一致的。
现在可以开工啦~
结论
写得真烂真乱啊
设计是一门艺术,而方案的讨论其实就是每个人交换思考过程的一个脑袋按摩罢了。
这东西有标准答案吗?没有。
那怎么校验一个设计是否成功呢?等到第一个无法招架的需求来了之后,自然就证明当初的这个设计有点力不从心了。
本文标题:Elements of Design
文章作者:Henry Wu
发布时间:2024-11-30
最后更新:2025-08-20
原始链接:https://henrywu.netlify.app/2024/11/30/elements-of-design/
版权声明:转载请注明出处。CC BY-NC-SA 4.0