4-001 找到够用的设计
关于架构设计,笔者补充一个原则:【笔者补充:奥卡姆剃刀原则】:切勿浪费较多东西,去做用较少东西,同样可以做好的事情 —— 百度百科。这个原理称为 “ 如无必要,勿增实体 ”,即 “ 简单有效原理 ”。
架构设计的目标不是理性的寻找最佳设计,而是找到一个够用的设计。可通过以下方法来寻找够用的设计:
1)将解决方案看成实验:把每个可能的解决方案看成是待验证的实验,验证的速度和效率越高,找到合适的组合结构的时间就越短,利益相关方就能越快收益。【笔者补充:敏捷思想的体现】:这里作者提出的快速出方案,快速验证,符合敏捷宣言:“ 工作的软件重于详尽的文档 ”。
2)设法降低风险:架构是软件系统的技术,架构师必须时刻考虑哪些地方可能出错,并据此开展设计,根据风险决定接下来设计什么。
3)努力简化问题:简单问题通常有简单的解法,因此将复杂问题分解为若干加单问题,会更容易解决。架构设计中,简化问题的方法有很多,比如:减少利益相关方的数量可以减少冲突的观点;增加或较少约束条件、关注问题的子集,也可降低复杂度;识别常规问题,利用现成的解决方案解决。
4)快速迭代学习:学习越快,探索得越多,对解决方案就越有信心。如果有可能失败,越早知道越好。设计周期太长,则需要思考下目标是否过于宏伟抽象,我们更喜欢能产生具体成果的频繁迭代设计。【笔者补充】:这里作者也提倡小步快跑,是典型的敏捷思想。
5)同时考虑问题和解决方案:问题的边界是由可能的解法勾勒的。为了理解问题,必须探索各种解决方案,而为了探索解决方案,又必须加深对问题的理解。软件架构设计需要同时考虑问题及其解决方案。如:架构设计初期试着写一些代码,就是该策略的具体运用。
尽早制定一份架构设计策略,确定哪些架构马上设计,哪些架构以后再考虑。既可以让团队明白架构将如何生长,也能培养各方对团队的信心。
4-002 决定前期做多少架构设计
前期如果不设计架构,开发出来的系统很可能不符合要求,同时,设计架构也能降低未来返工的风险;如果花大量时间设计架构,则会耽误开发,延误交付。因此,每个软件系统都有一个设计的最佳平衡点 —— 在开发之前用最适当的时间设计架构。
在《Architecting: How Much and When?》一书中,作者Barry Boehm给出了软件开发的项目总工期公式如下:
项目总工期 = 架构设计 + 开发 + 返工(弥补缺陷、重写代码、改正错误)
最佳平衡点主要由:软件规模、需求变更、系统复杂度三个要素决定。由架构设计时间和返工时间构成的关系图中,最佳平衡点位置如下:
由上图:当架构设计时间少于20%(总工期的20%)的时,项目总工期随着架构设计时间的增加逐步减少,但边际收益在递减;随着架构设计时间的进一步增加,虽然返工量仍然减少,但总工期反而变长。
Boehm还研究了随着软件系统规模的变化,最佳平衡点的变动情况,如下图所示:
上图的数据,可以用来评估自己的架构设计时间是否在合理的范围内。分析上图,包含如下要点:
1)软件系统越大,前期做架构设计的收益越大:千万行代码的大型软件系统,将37%的时间花在架构设计上是一个明智的选择。
2)软件系统越小,前期做架构设计的收益越小:一万行代码的小型软件系统,架构设计时间不应超过5%。
3)前期架构设计做得不够,要对后期返工做好心理准备:小型软件系统前期不做过多架构设计可以缩短总工期,但是返工还是不可避免。如果前期架构设计做的不够,系统越大,后期返工的概率越高。
4)前期架构设计的投入越多,后期返工就越少:前期架构规划和设计有助于减少错误。如果重视项目的质量和可控性,而不在乎效率,可以多花点时间做前期架构规划(哪怕是小型系统)。
用软件系统规模来评估前期的架构设计的工作量很方便,也有团队用系统复杂度来决定前期架构设计的工作量。而对于可以用常规解决方案处理的系统,即使规模很大也可以不用做太多的前期架构规划。
4-003 用风险做向导
软件开发总是有风险的。风险是很好的指示器,提醒我们什么东西会构成障碍。凭直觉写下对系统的担忧和顾虑,对他们排序,列出优先级。把风险最高,最麻烦的排在前面,然后选择合适的思维模式降低风险。
4-003-01 确定条件和后果
描述风险需要两个部分:条件 和 后果。条件是当前的实际情况,后果是由条件引发的、将来可能出现的不良状况。如:条件:供应商欠款未付,当前开发依赖的SDK拿不到,而公司付款需要至少3周 ——> 后果:软件开发时间顺延3周,总工期延长3周。
4-003-02 借助风险选择思维模式
软件架构设计是一项降低风险的活动。列举几项项目中的风险,以及团队降低风险的对策:
风险项 | 思维模式 | 风险对策 |
模型训练服务最初是为其它目的开发的; 新请求可能会导致其过载 | 理解模式、评估模式 | 与开发模型训练服务的团队进行沟通,了解其可伸缩性;做实验测算吞吐量 |
数据处理将消耗大量的时间和资源;可能无法顺利完成处理任务 | 探索模式 | 头脑风暴,探讨提高可靠性的方法,研究任务调度模式,寻找可缩短处理时间的替代设计方案 |
需要大量数据训练统计模型;数据的存储成本太高,模型可能无法满足 | 展示模式 | 建立成本估算模型,向利益相关方展示各种设计方案的利弊;通过调整待办列表的优先级减小风险的时间窗口 |
储存的数据可能包含敏感的客户信息;对数据进行隔离的要求超出了我们的能力范围 | 评估模式 | 根据需求对可用的计算平台进行打分 |
风险帮助我们决定设计内容,思维模式帮助我们制定降低风险的策略。通过条件、影响、概率和事件窗口等因素来确定必须降低的风险的可以解决部分,需要选择合适的思维模式,选择方法如下:
如果 | 可以尝试 |
要解决的问题还不确定,对于利益相关方和其他系统参与者,还需要更深入的了解 | 理解模式 |
解决方案还不确定,需要充分了解可选的方案 | 探索模式 |
利益相关方不完全了解准备实施的方案 | 展示模式 |
在设计决策上举棋不定 | 评估模式 |
4-003-03 风险降低后转为被动设计
架构师应该努力将技术风险降低到架构不再是系统中最大风险源的地步。一旦将架构风险降低到 “ 恰如其分 ”的状态,我们就可以考虑将时间花在其它地方。此时,就可以从主动设计转为被动设计,如下图所示:
其中:主动设计是指主动设法降低架构风险;被动设计是指监控系统运行表现,只在必要时采取纠正措施。
即使进入被动设计阶段,仍有很多工作需要做,如:进一步修改和完善文档;根据新情况进行架构微调;通过结对编程和代码评审来培训团队成员;防止架构变异等。
由于新风险的出现、系统的实现偏离了计划,或者发现先前的假设是错误等原因,架构可能随时重新成为重大风险源。此时,需要切换回主动设计模式。
4-004 制定设计计划
设计计划指出团队在架构设计上分配时间的总体策略。设计计划不一定是正式的时间表,但要体现设计思路,可以将计划记录在简单的文档里,内容包含以下几个方面:
1)结束设计的条件:没有标准答案,很大程度上取决于团队、利益相关方、项目背景的实际情况。基于实际情况,来确定:是开始写代码前做尽量少的前期设计,还是尽可能完整地做好架构规划?各个部分的设计独立开展,还是某些部分需要一起开始?等等。
2)必要的设计成果:在设计开始前,让大家明确如何记录架构设计。画在白板上拍照,还是用传统的文档记录?团队是否有现成的设计文档模板?设计成果(用例图、类图、UML模型图、设计文档等)应该存储在哪里?
3)时间节点:给出关键设计工作的时间节点,如:需求审查、设计审查、设计评估等的时间节点。此外,还要给出利益相关方会面的时间节点,如:开发即将开始;初期要完成的工作范围等。
4)重大风险:使用风险驱动的设计方法,应将重大风险也放到设计计划里。在软件系统的整个生命周期中(尤其前期的架构设计阶段),应该不断回顾风险列表。
5)概念架构设计:可以先从可行的解决方案里选择一个,思考解决方案可以更好地帮助我们定义问题。概念架构不需要很复杂,可以画一张草图,只要能表达初步的设计想法就行。
不同软件系统的架构设计时间从数小时、数天,到数月不等。无论耗时多久,牢记设计思维的四条原则(HART原则),专心寻找够用的设计,则能在需要的时间里找到一个可行的解决方案。