如何写好&评审一份技术方案
一、前言
作为一个技术开发者,特别是高级、资深开发、架构师等,往往会遇到根据需求撰写技术方案,这里的需求包括业务需求和技术需求。如何评判技术方案的好坏,如何写好技术方案,尤其对于研发人员来讲是非常重要的。
我见过太多由于前期规划不到位(甚至是没有技术方案设计,开个技术讨论会口头沟通一下,就直接评工期开干的),这其中不乏很重要,工期很长的项目。而最后呢,到联调阶段各组串不起来,研发和产品同学之间都没沟通清楚,对需求理解不一致。导致最终很被动,到处挖坑补洞,而且花费了更多的时间和精力,项目bug满天飞,甚至导致项目延期,后续扩展性不强等等问题。
所以我认为,技术方案是必不可少的一个环节,往往很多坑在这个阶段就可以避免的。如果一开始没有技术方案或者技术方案存在缺陷,对于后面系统影响是非常大的,可能会导致故障、bug或者影响系统的可扩展性、可维护性等问题。
今天我们就重点来聊聊如何写好技术方案以及如何评审技术方案这个话题。
二、写好技术方案的意义
1、提高沟通效率
对于整个团队,通过技术方案文档和评审对齐能够提高沟通效率:
产品经理:产品经理可以审查技术方案是否与产品设计有偏差,是否满足当前产品需求和后续产品设计规划;
技术leader:开发leader可以把控方案是否满足技术要求,包括技术规范,性能要求,实现复杂度,可扩展性等;
测试:测试同学可以掌握需求技术实现原理,改动点,影响点,再做针对性测试用例设计;
新人:后续接手项目的新同学可以通过技术方案文档熟悉系统。
2、提高开发效率和质量
对于开发同学,通过写技术方案,把需求和实现提前梳理一遍,减少等到编码阶段才发现前期考虑不全导致返工的情况;并且写好技术方案再编码,使得编码时思维更加清晰,提高编码效率和质量。
三、怎样才是好的技术方案
1.思路清晰
在讲技术需求时,常见的问题是一上来直接给出解决方案,导致受众不能理解为什么要这样设计。其实相比解决方案,更重要的是怎么思考的,思考的过程非常重要。思路就是思考的线索,思路清晰的方案,层次分明,让受众快速理解清楚。
整个技术方案思考的线索可以用5W2H分析法串起来:Why、Who、When、Where、What、How 和 How much(如下图所示),从七个方面去分析思考:
整个技术方案需要先基于需求背景,定义清楚要解决的问题,明确目标,搞清楚 Why。定义清楚问题之后,再从When,What,Where,How等不同的角度,对问题进行分析和解决,先讲整体架构,再细化流程,先主线,再分支,先正常链路,再异常链路。
2.满足需求
技术方案满足的需求包括功能需求和非功能需求。功能需求不仅是当前产品提出的功能需求,还要对未来需求的扩展有一定的规划,预留好扩展点,这就要求开发在规划设计前,对现状和需求进行充分的收集和分析。
除了功能需求,更考验开发同学技术实力的是非功能需求,包括异常处理,降级方案,灰度方案,运维方案,高可用设计等。设计时要结合具体业务场景,当前项目阶段,做合理的权衡,避免陷入极端:或面面俱到,过度设计;或方案过粗,考虑不周。
技术方案满足当下需求是一方面,另外需要考虑系统架构设计的可扩展性,为将来的业务发展奠定一定的基础。
3.可实施
可以这样评估一个技术方案是否可实施:技术方案完成之后,其他人能否照着技术方案按时按质完成开发并上线?有的技术方案看似高大上,高瞻远瞩,开发实施起来却困难重重,常见原因如下:
不够细:涉及改动的字段,报文,异常情况,边界情况,历史数据兼容等处理没说明清楚
做不完:方案做的调整过大,虽然能解决问题,但是实施起来时间不够
在写技术方案时,方案需要足够完善详细,把开发涉及的关键点考虑完善,这些点没有先界定清楚的话,开发的时候容易才发现跟系统当前现状有冲突,或者开发出来偏离方案设计。
方案的设计也要考虑时间,开发成本,是否符合系统现状、团队可调配的资源,有些方案从技术的角度是最佳,但是从实施的角度并非最佳,例如会额外引入上下游系统相应的改动,带来一定的沟通协作成本。所以方案设计在考虑产品和技术等限制的同时,也需要考虑当前现状,要求的上线时间等其他因素,选择最合适的技术方案。可以在方案中写不同的实现的评估对比,进行取舍权衡,或者方案拆成不同的开发实施阶段。
四、如何去写好技术方案
1.需求对齐
为什么产品文档介绍过需求,技术方案里面还要写需求说明?主要原因如下:
介绍需求:通过在技术方案里面简明扼要介绍产品需求,有利于其他看技术方案的人快速理解需求,后面具体技术实现的出发点。
对齐需求:需求说明部分体现了开发同学对产品需求的理解,在技术评审阶段进一步与产品同学检查对齐一遍,减少理解出现偏差。
RD 角度对 PM 同学提出的需求的理解,不是复述,而是总结和抽象;对需求进行拆解,映射到功能层面;作为流程、接口定义的依据;
描述角度:新增了哪些功能,已有的功能做了哪些变更
除了原始需求外,可能会涉及历史遗留的逻辑问题,或优化类的需求(响应耗时、实时返回调整为异步处理等),不属于 PM 同学所提的需求范围,但对需求的实现存在影响,需要纳入考虑。
2.技术方案设计
2.1.技术选型
如果涉及到引入新的框架或中间件,需要做一下选型说明,例如引入消息中间件、存储引入NOSQL,具体使用何种消息中间件、NOSQL,需要从性能、可靠性等角度去分析技术选型,以及目前使用的框架、中间件存在哪些缺陷,需要和团队同学进行明确。
2.2.存储设计
包括存储结构(包括MySQL、ES、Redis、OSS等)设计,包括表和字段的概念定义,各个表之间的关联,业务系统如何使用这些库表。
新建/已有表增加字段,或新的业务导致新的查询场景,原表结构/索引设计无法满足要求,可能会导致慢查询
注意事项:
表名、字段命名规范
业务场景,常用查询条件,决定索引的设计 (索引字段、单列/联合索引、索引类型:BTREE,HASH)
数据规模,决定是否需要进行拆分(分表、分库设计)
确认历史数据是否存在异常(重要)!!!
2.3.接口设计
涉及与FE、外部服务交互,必须确保相关人员都已经明确了需要关注的接口和参数、返回值,接口文档格式:路径,入参(字段名称、类型、是否必填、备注说明),返回值(字段名称、类型、是否必填、备注说明);
入参和返回值,必须提供 demo 数据;
返回值约定错误码、异常信息、是否需要前端接收并展示异常消息内容
2.4.架构流程图
包括系统统架构图(简单的功能迭代不必包含,技术项目涉及架构变更时必须体现)、流程图、外部服务依赖、子模块(子系统)简要描述。
画图时,注意不要想在一张图里面做到面面俱到,画之前要想清楚这张图要表达什么内容,传递什么信息,再针对性来画,不同的类型的图不要合在一起。例如想说明系统的部署结构用部署图,说明业务的主要流程用流程图;如果图里面,既有系统部署涉及的基础组件,又有业务处理流程,图表现出来的信息就比较混乱。
2.5.依赖分析
系统服务之间的依赖主要分为外部依赖和内部依赖,针对系统间的依赖需要考虑相关协同方上线时间,避免上线时间依赖导致项目延期。
外部依赖需要结合系统间流程图说明整笔业务请求涉及哪些系统组成部分,业务的发起来源,系统间交互调用了具体哪个接口,请求处理基本步骤和数据落地存储逻辑。
对外依赖分析需要考虑以下几点:
外部 dubbo服务依赖:需要确认对应dubbo接口的类、方法、version,以及二方包(也可使用泛化调用);
外部消息依赖:需要确认消息的 topic、数据格式;
分布式调度、缓存等中间件:当前应用是否接入过该中间件,未接入需要去到官网确认接入文档,接入的话需要确认是否可以复用接入逻辑。
内部依赖需要结合业务处理流程图说明请求如何加工计算数据,处理的具体步骤,最终处理完成之后结果如何保存,或者传输到什么地方。
内部依赖需要考虑领域依赖、应用依赖、接口依赖。
2.6.可扩展性设计
可扩展性设计关注的是后续系统的迭代升级,需求变更,系统怎么维护的问题。这块的关键点主要是代码复杂度问题,不好维护的系统,会因为系统引入一个新需求,整个系统需要做大量改动。因此系统需要考虑通过提前做一些可拓展设计方便后续维护,体现在以下方面:
扩展点分析:结合产品需求分析后续扩展带来的变化点,为了支持这些变化系统需要预留哪些扩展点。
系统建模:针对变化点,对系统对象进行建模,主要关注:模块(职责明确的模块或者组件)、关系(组件间明确的关联关系)、边界(约束和指导原则)。
设计模式:使用设计模式时,要注意设计模式的底层逻辑是“找到变化,封装变化”,将变化封装在可控范围内,具体介绍设计模式涉及的类图,以及拓展新需求时,系统需要做的变动。
配置项:包括配置项的具体定义,预留一些开关定义。
2.7.可靠性设计
可靠性设计包括以下要点:
灰度方案
如果是新系统初步上线用于替代老系统,新系统还需要经过进一步线上验证,这时需要考虑灰度方案,包括灰度的周期计划,灰度的范围/维度,灰度配置策略。
容量评估
容量评估需要根据请求量,评估要预留给程序多少相应的运行资源。包括内存,磁盘,CPU,存储服务等。评估的点包括:接口平均QPS、峰值QPS、接口请求和返回报文大小,消息队列的平均消息数、峰值消息数、报文大小。这一部分如果是改动的业务,可以参考以前的监控,如果是新业务或者新活动可以跟运营、产品确定业务量。若预估峰值会很高,需要进行压测。
弹性处理
消息重复消费、接口重复调用对应的服务是否保证幂等?是否考虑了服务降级?哪些业务支持降级?支持自动降级还是手工降级?是否考虑了服务的超时熔断、异常熔断、限流熔断?触发熔断后对客户的影响?服务是否做了隔离,单一服务故障是否影响全局,隔离是否可以进一步做到租户隔离?这些问题统统需要我们想清楚对应的解决方案,才会进一步保证架构设计的合理性。
兼容性
上下游依赖是否梳理过,影响范围多大?怎么进行新老系统替换?新老系统能否来回切换?数据存储是否兼容老的数据处理?如果对你的上下游系统有影响,是否通知到上下游业务方?上下游依赖方进行升级的方案成本如何最小化?这些问题需要有完美的解决方案,稍有不慎会导致故障。
另外细粒度的兼容需要考虑如下两点:
接口的向前兼容:尤其是对外的接口
数据结构的向前兼容:如不能随意改变字段的存储类型和格式
监控报警
当方案不确定性比较大,容易出错,一旦出错造成的影响较大,需要加监控告警,说明的信息包括:模块,监控指标,监控阈值,报警方式等。
9.上线部署计划
不想需求上线后各种问题,疲于应对,那就有必要在技术方案阶段考虑上线部署的问题,在技术方案设计中先提前准备好,等到上线阶段对着技术方案写的注意事项,步骤进行一步步检查和执行,减少上线事项遗漏或者处理出错的情况。
上线部署部分涉及的点包括环境准备,系统准备,发布顺序,线上验证;
(1) 环境准备
系统依赖环境的准备包括MySQL、Redis、MQ、ES和Nginx等服务搭建和初始化,机器资源等。
(2) 系统准备
系统准备常见主要如下:
依赖的服务配置,数据更新,例如数据库表创建,SQL初始化脚本,Nginx配置更新,MQ的topic创建,网络端口打通,监控配置,IP白名单申请,定时任务创建。
引用服务项目配置更新,代码检查,分支merge。
(3) 发布顺序
发布部署的服务之前有业务依赖关系,被依赖的服务需要先发布部署,如果这种依赖关系,在技术方案中应当标明。
(4) 线上验证
线上验证的部分需要结合测试用例,需要说明服务部署之后,怎么验证服务是否正常,需要做哪些检查验证项。
在开发和测试阶段,当配置项,脚本,配置出现更新调整,需要更新保存在技术方案文档里面,上线时照着文档操作,不容易遗漏。
五、如何评审技术方案
互联网时代,大家提倡敏捷迭代,总嫌传统方式太重,流程复杂,影响效率,什么都希望短平快,在扁平化的组织中,经常是需求火速分发到一线研发,然后就靠个人折腾去了,其实技术方案评审这同样是一个非常重要的环节。技术方案评审的价值在于集众人的力量大家一起来分析看看方案里是否有坑,方案上线后是否会遇到不可逾越的重大技术问题,提前尽可能把一些事情先考虑到提出质疑其实对项目的健康发展有很大的好处。
基于技术方案评审,我们的目标核心是要满足以下几点:
满足需求,确保设计方案合理,各方面都考虑到了,避免缺陷和遗漏,不求方案多牛,至少不犯错。
保证架构设计合理和基本一致,符合整体原则。
维持对系统架构的全局认知,避免黑盒效应。
成本最小化,包括投入时间成本和财力成本,比如项目可能需要引入Redis,Mysql,ES, MongoDB 等基础资源,那公司是否能提供这些资源(服务器是要钱的),是否有开源的替代方案,是否要自行维护。
通过评审发掘创新亮点,推广最佳实践。
技术方案设计既要保证架构设计的合理性和可扩展性,又要避免过度设计。架构设计不仅仅是考虑功能实现,还有很多非功能需求,以及持续运维所需要的工作,需要工程实践经验,进行平衡和取舍。
reference:
https://mp.weixin.qq.com/s/JK1sIs5vLS8VfFg1PwCTbA