一、技术方案意义
我们为什么需要写技术方案?总结下来无非是几点,从不同人的视角来看:
-
产品:验证技术方案是否能够 match 上产品方案
-
测试:验证技术方案对测试方案是否有足够 & 准确的输入
-
同事 & leader:参与技术方案评审,验证技术方案的合理性
-
新人(不单单指新同学也指新接触这一块的同学):拿到技术方案可以很快对某一块的事情熟悉起来
二、好的技术方案形式
我们都知道技术方案是指导具体开发工作的,可以分别从开发的事前、事中、事后来讨论这个问题。
事前:
-
明确的目标:整个技术方案要达成什么目的
-
低沟通成本:产品测试能从技术方案上获取足够的输入,不需要反复找你确认
-
技术选型思考:为什么要这么做?和业内方案相比有什么好处和坏处,如何权衡的
事中:
-
少调整:尽可能少的技术方案需要调整, 否则无法完成开发任务
事后:
-
少补丁:尽可能少的 bug 或者遗漏
-
可扩展 & 可复用:相对简单的改动就能支持新增需求,类似场景可复用不需要重复开发
一篇好的技术方案可以贯穿整个研发的生命周期,并且能起到很好的指导意义,就如同写小说之前作者必须出一个大纲的逻辑是一致的。
三、好的技术方案怎么写
3.1 清晰的目标
一份技术文档需要有一个清晰的目标(业务需求建议自己总结而不是 Copy from PRD,技术自发的那肯定得自己总结),那目标怎么来的呢?是从需求里转化过来的。那么,如何将对应的需求转化为一个清晰的目标?我认为最重要的是要尽量定义一个可衡量的标准。需求的种类一般来说就两种,分别是:
1. 产品类需求——业务方 or 产品方发起提给技术,包括但不限于以下几种:
-
页面交互:能提升多少的运营操作效率,多少 PV、UV 这种可量化的数字?
-
业务 SOP 调整:带来的业务价值是什么?是能降多少本还是提升多少时效?
-
数据订正:订正能解决什么问题?防止多少钱未结算?又或者是防止多少客诉?
2. 技术类需求——技术自发提出,包括但不限于以下几种:
-
性能优化:优化多少?20%、30% 还是 50%?
-
数据隔离:隔离的范围是什么,涉及多少张表,多少数据?可以减少当前的什么问题?减少多少?
-
各种小工具:没有小工具之前是什么样?有之后是什么样?可以带来什么好处?
-
研发效能提升:提升多少?有没有可以量化的指标?而不是为了做而做。
在众多的需求当中还有一些是我们要去辨别的伪需求——不是用户真正想要的需求,如用户想要将一个飞机改造成火箭,但是产品可能提过来的仅仅是把飞机的两个翅膀砍掉,那么砍掉翅膀就能变成火箭了吗?明显不能,所以这种需求一定要注意鉴别。
3.2 大纲图
“不谋全局者不足谋一域”,在技术方案中我想也是如此。在一个技术方案中,一个大纲图是不可或缺的 ,有的人叫它技术架构图,有的人叫它数据流转图,这都不重要,重要的是我们能从这张图中看到整体的脉络,那么这张图需要以下几个要点:
-
图不用很细(比如加工比较复杂我们可以简单写**加工),但是要能看到全貌,具体的每个模块如果需要展开的,那么在对应的详细设计中体现即可,在这里我们关注的是整体;
-
接口如有归属不同的应用要标明;
-
数据存储介质不同要标明;
-
数据流转的箭头要清晰明确;
-
数据加工计算的输入和输出要体现,同时要体现加工的运行环境(比如到底是 odps 计算还是内存计算,内存计算的话是在那个应用)。
3.3 模型设计
讲到数据模型设计,E-R 图是必不可少的,E-R 图应该包含以下信息:
1. 每个领域对象,如果要持久化,都有表来存储。我们设计完 ER 图的时候,应该根据这条原则做一番检查,避免漏掉一些表。在大型项目中,漏掉表是很常见的事情,应尽量避免。
2. 领域对象之间的关系,如果要持久化,都要在表结构中体现。这种体现,可能是 code 字段,可能是外键,可能是中间表。我们设计完 ER 图的时候,也应该根据这条原则做一番检查,避免漏掉一些关系。在大型项目中,漏掉关系更是司空见惯,应尽量避免。
3. 清晰定义的表名。设计 ER 图的时候,就要设计出清晰定义的表名。清晰定义的表名,可以帮助大家理解 ER 图,可以帮助大家映射回领域对象及其关系。在后续的设计和实施中,将沿用这个表名。
4. 清晰定义的字段名、字段类型、字段长度和枚举值。很多同学容易忽略这点,他们往往清晰定义了表名,却没有重视表的字段。认真去做的时候,会发现,这里面有很多工作。例如,字段名是否合适,用什么类型好,字段长度多少合适,是否有枚举值等等,都需要一一斟酌。如果这点做好了,在实施的时候,可以避免很多麻烦,甚至避免返工。
3.4 对外依赖提前确认
技术方案 1:需要依赖缓存、分布式调度中间件、消费外部的消息,但是没有把对应的中间件使用方式、数据格式贴出来。
技术方案 2:需要依赖缓存、分布式调度中间件、消费外部的消息,将缓存接入的方法 & 对应的缓存 key-value 设计写清楚,将分布式调度中间件接入所需要准备的依赖项梳理好,将外销消息对应的 topic 和数据格式列清楚。
两个方案对比好坏其实很明显。如果一开始我们在技术方案里面将外部依赖确定好,那么我们在开发的时候就一马平川,反之如果外部依赖都不确定的情况下就进入到开发,那么返工的概率将大大增加,从而降低我们的工作效率。
那么,对外的依赖有哪些以及我们应该要确认什么信息呢?下面列举了一些常见的依赖情况:
-
外部 hsf 依赖:需要确认对应 hsf 接口的类、方法、version,以及二方包(也可使用泛化调用);
-
外部消息依赖:需要确认消息的 topic、数据格式;
-
分布式调度、缓存等中间件:当前应用是否接入过该中间件,未接入需要去到官网确认接入文档,接入的话需要确认是否可以复用接入逻辑。
3.5 内部前后模块依赖 & 层次结构
模块依赖层次从高到低分为:
-
领域依赖(如交易依赖商品)
-
应用依赖(如 cntcp 应用依赖 cngfc 应用)
-
接口依赖(如滚存看板查询接口依赖于锁接口 & 渠道集接口)
我们举接口依赖的例子来看:一共三个接口分别是滚存看板查询接口、锁接口、渠道集接口。滚存看板查询接口依赖于锁接口和渠道集接口。
技术方案 1 目录层次:滚存看板查询接口、锁接口、渠道集接口;
技术方案 2 目录层次:锁接口、渠道集接口、滚存看板查询接口。
很明显,技术方案 2 是更加合理的,A 依赖于 B 那么 B 应该先做。
我们在写技术方案的时候,要考虑什么应该在前什么应该在后,而不是想一步写一步。要有一个清晰、有序的结构,不然别人看起来就会是杂乱无章的。
3.6 模块内容
3.6.1 具体的接口定义
接口定义有几点要求:
-
完整的类和方法名
-
入参字段如果系统中已有,那便沿用;如果没有,那么英文的描述需要准确(可同产品业务商榷)
-
出参字段要求同入参
3.6.2 详细的时序图
时序图能够更直观地看到层次、数据流转等信息。除了时序图觉得的还有一些要点:
-
数据加工的详细图(如有)——同样推荐用图的形式可以更直观
-
消息设计(如有),明确消息生产方、消费方、tps、数据结构
-
自测用例(推荐),比较重要的功能点构造一些自测用例
3.6.3 技术选型分析
要求:实现一个定时任务,定期将过期的数据删除。
技术方案 1:使用 spring 自带的定时器进行数据清除。
技术方案 2:使用分布式调度中间件(如 schedulerx)进行定时过期数据清除。
乍一看好像都能实现,但仔细对比两个实现方式之后我认为大部分人还是会选择技术方案 2,为什么?下面列出一些在选择技术方案时考虑的点。
目标是否可达成 | 实现难度 | 可维护性 | 可扩展性 | |
技术方案1-spring定时器 | 是 | 易 | 易 | 低 |
技术方案2-分布式调度中间件 | 是 | 易 | 中 | 高 |
3.6.4 安全生产
安全生产包括几个部分,包括且不限于下面几个部分:监控、对账、灰度方案、数据隔离、兼容性评估、发布流程
监控:
-
监控目标:写清楚监控的是什么内容
-
监控点:如通过打印日志监控,那么日志打印在哪个类的哪个方法
-
监控触发:是通过 sunfire 采集触发还是其它,如果是 sunfire 采集最好能把监控项地址贴出来
-
监控订阅人:监控告警需要的订阅人
-
监控触发后的解决方法:如果发生异常该如何解决?如手工触发结算
对账:
-
对账目标:写清楚对账是为什么
-
对账方式:写清楚是怎么对账的(如通过 odps 天级定时任务,履行单上的关务资源 code 和日志表中关务 cp 回传报文的关务资源 code 对比要一致,不一致的形成某个数据集,通过锦衣卫-资损风险平台配置)
-
对账告警订阅人
-
对账异常之后的解决办法
灰度方案,包括但不限于:
-
多方前置准备
-
灰度切流开关设计
-
灰度切流节奏
-
异常应对
向前兼容性,包括但不限于:
-
接口的向前兼容:尤其是对外的接口
-
数据结构的向前兼容:如不能随意改变字段的存储类型和格式
环境隔离:
-
如有租户隔离 & 预发线上隔离的情况需要考虑数据
发布流程,包括但不限于:
-
发布计划
-
检查项列表
-
发布流量监控
参考资料:
1.微信公众号(阿里开发者)-《如何写出一篇好的技术方案?》