如何写好一篇好的技术方案

641.png

1 背景

近期在写某个项目的技术方案时,来来回回修改许多版,同时也将之前自己写的&别人写的技术方案都翻出来看了几遍,其实也很苦恼,于是也产生了一个想法:为什么我们需要写技术方案?
总结下来无非是几点,从不同人的视角来看:

  1. 产品-验证技术方案是否能够match上产品方案

  2. 测试-验证技术方案是否足够&准确的输入写测试方案

  3. 同事&leader-参与技术方案评审,验证技术方案的合理性

  4. 新人(不单单指新同学也指新接触这一块的同学)-拿到技术方案可以很快对某一块的事情熟悉起来

    2 什么样的技术方案是一个好的技术方案

我们都知道技术方案是指导我们开发的,那么我们就分别从开发的事前、事中、事后来讨论这个问题

1.事前

a.明确的目标——整个技术方案要达成什么目的

b.低沟通成本——产品测试能从技术方案上获取足够的输入,不需要反复找你确认

c.技术选型思考——为什么要这么做?和业内方案相比有什么好处和坏处,如何权衡的

2.事中

a.少调整-尽可能少的技术方案需要调整, 否则无法完成开发任务

3.事后

a.少补丁-尽可能少的bug或者遗漏

b.可扩展&可复用-相对简单的改动就能支持新增的需求、类似的场景可复用不需要重复开发


一篇好的技术方案是可以贯穿整个研发的生命周期,并且起到很好的指导意义的,就如果写网络小说之前作者必须出一个大纲的逻辑是一致的。

3 如何写好一篇好的技术方案

那么如何写出一篇好的技术方案呢?下面列举出笔者认为技术方案应该做到的一些点

3.1 清晰的目标

一份技术文档我认为是需要有一个清晰的目标的(业务需求建议自己总结而不是copy from prd,技术自发的那肯定得自己总结),那目标怎么来的呢?是从需求里转为过来的,那么如何将对应的需求转化为一个清晰的目标呢?我认为最重要的是要尽量定义一个可衡量的标准。需求的种类一般来说就2种,分别是

1.产品类需求——业务方or产品方发起提给技术,包括且不限于以下几种

a.页面交互——能提升多少的运营操作效率,多少PVUV这种可量化的数字

b.业务sop调整——带来的业务价值是什么?是能降多少本还是提升多少时效?

c.数据订正——订正能解决什么问题?防止多少钱未结算?又或者是防止多少客诉?

2.技术类需求——技术自发提出,包括且不限于以下几种

a.性能优化——优化多少?20%、30%还是50%?

b.数据隔离——隔离的范围是什么,涉及多少张表,多少数据?可以减少当前的什么问题?减少多少

c.各种小工具——没有小工具之前是什么样?有之后是什么样?可以带来什么好处?

d.研发效能提升——提升多少?有没有可以量化的指标?而不是为了做而做


在众多的需求当中还有一些是我们要去辨别的伪需求——不是真正的用户想要的,如用户想要将一个飞机改造成火箭,但是产品可能提过来的仅仅是把飞机的两个翅膀砍掉,那么砍掉翅膀就能变成火箭了嘛?明显不能,所以这种需求一定要注意鉴别。

3.2 大纲图

有句话叫“不谋全局者,不足谋一域”,在技术方案中我想也是如此。在一个技术方案中,一个大纲图是不可或缺的 ,有的人叫它技术架构图,有的人叫它数据流转图,这都不重要,重要的是我们能从这张图中看到整体的脉络,那么这张图需要有哪几个要点呢?

  1. 图不用很细(比如加工比较复杂我们可以简单写**加工),但是要能看到全貌,具体的每个模块如果需要展开的,那么在对应的详细设计中体现即可,在这里我们关注的是整体

  2. 接口如有归属不同的应用要标明

  3. 数据存储介质不同要标明

  4. 数据流转的箭头要清晰明确

  5. 数据加工计算的输入和输出要体现,同时要体现加工的运行环境(比如到底是odps计算还是内存计算,内存计算的话是在那个应用)

下面的图可供参考
4d513d6abe5a254a0cded80189236b1.jpg 

3.3 模型设计

讲到数据模型设计 那么E-R图是比不可少的 那么E-R图里应该是包含以下的信息的

  1. 每个领域对象,如果要持久化,都有表来存储。我们设计完ER图的时候,应该根据这条原则做一番检查,避免漏掉一些表。在大型项目中,漏掉表是很常见的事情,应尽量避免。

  2. 领域对象之间的关系,如果要持久化,都要在表结构中体现。这种体现,可能是code字段,可能是外键,可能是中间表。我们设计完ER图的时候,也应该根据这条原则做一番检查,避免漏掉一些关系。在大型项目中,漏掉关系更是司空见惯,应尽量避免。

  3. 清晰定义的表名。设计ER图的时候,就要设计出清晰定义的表名。清晰定义的表名,可以帮助大家理解ER图,可以帮助大家映射回领域对象及其关系。在后续的设计和实施中,将沿用这个表名。

  4. 清晰定义的字段名、字段类型、字段长度和枚举值。很多同学容易忽略这点,他们往往清晰定义了表名,却没有重视表的字段。认真去做的时候,会发现,这里面有很多工作。例如,字段名是否合适,用什么类型好,字段长度多少合适,是否有枚举值等等,都需要一一斟酌。如果这点做好了,在实施的时候,可以避免很多麻烦,甚至避免返工。

3.4 对外依赖提前确认

技术方案1:需要依赖缓存、分布式调度中间件,消费外部的消息,但是没有把对应的中间件使用方式,数据格式给贴出来

技术方案2:需要依赖缓存、分布式调度中间件,消费外部的消息,将缓存接入的方法&对应的缓存key-value设计写清楚、将分布式调度中间件接入所需要准备的依赖项梳理好、将外销消息对应的topic和数据格式列清楚

两个方案对比好坏其实很明显。如果一开始我们在技术方案里面将外部依赖确定好,那么我们在开发的时候就一马平川,反之如果外部依赖都不确定的情况下就进入到开发,那么返工的概率将大大增加从而降低我们的工作效率

那么对外的依赖有哪些以及我们要确认的都是些什么呢?下面列举了一些我们常见的一些依赖

  • a.外部hsf依赖——需要确认对应hsf接口的类、方法、version,以及二方包(也可使用泛化调用)

  • b.外部消息依赖——需要确认消息的topic、数据格式

  • c.分布式调度、缓存等中间件——当前应用是否接入过改中间件,未接入需要去到官网确认接入文档,接入的话需要确认是否可以复用接入逻辑



3.5 内部前后模块依赖&层次结构

首先模块依赖层次从高到底分为

  • a.领域依赖(如交易依赖商品)

  • b.应用依赖(如cntcp应用依赖cngfc应用)

  • c.接口依赖(如滚存看板查询接口依赖于锁接口&渠道集接口)

我们举接口依赖的例子来看:一共三个接口分别是滚存看板查询接口、锁接口、渠道集接口 滚存看板查询接口依赖于锁接口和渠道集接口
技术方案1-目录层次: 滚存看板查询接口、锁接口、渠道集接口
技术方案2-目录层次: 锁接口、渠道集接口、滚存看板查询接口
很明显,技术方案2是更加合理的,A依赖于B那么B应该先做
我们在写技术方案的时候要考虑什么应该在前什么应该在后而不是想一步写一步,要有一个清晰、有序的结构,而不是别人看起来是杂乱无章的。

3.6 一个模块里面应该有啥

下面列出一个技术方案的模块里面应该要写哪些东西,供参考

3.6.1 具体的接口定义

要求:实现一个飞机运力合同查询接口,入参为运力大区
技术方案1:
入参:

1
2
3
4
{
"area": "南美"
}


出参:

1
2
3
{
"date": "***"
}


技术方案2:
方法名:CapacityService.queryPlan

入参:

1
2
3
{
"cnArea": "南美"
}

出参:

1
2
3
{
"date": "***"
}

技术方案2是更好的,为什么?测试、前端 、后续要接手该接口的人都能够一下子找到你的接口并清楚的知道他的输入输出是什么,并且1和2的入参一个area一个cnArea,那么到底那个更对呢?这里由于系统中在用的都是cnArea,固沿用cnArea是对的(一致性减小沟通成本)。

这里总结对接口定义有几点要求:

  1. 完整的类和方法名
  2. 入参字段如果系统中已有那便沿用,如果没有那么英文的描述需要准确(可同产品业务商榷)
  3. 出参字段要求同入参



3.6.2 详细的时序图

  • 要求:实现一个学生信息查询接口

  • 技术方案1:写出查询结果中执行的相关步骤。

    • step1. 入参校验
    • step2. 查询A表
    • step3. 对A标返回结果做校验
    • step4. 查询B表
      ······
  • 技术方案2:在1的基础上使用时序图表达出来

推荐使用技术方案2,好处是尽管内容相同但是时序图能够更直观的看到层次、数据流转等信息


除了以上比较基础的2点我觉得的还有一些要点
数据加工的详细图(如有)——同样推荐用图的形式可以更直观
消息设计(如有),明确消息生产方、消费方,tps、数据结构
自测用例(推荐),比较重要的功能点构造一些自测用例
······

3.7 技术选型分析

  • 要求:实现一个定时任务,定期将过期的数据删除
  • 技术方案1:使用spring自带的定时器进行数据清除
  • 技术方案2:使用分布式调度中间件(如schedulerx)进行定时过期数据清楚

咋一看好像都能实现,那么我们仔细对比两个实现方式之后我认为大部分人还是会选择技术方案2,为什么?下面列出一些在选择技术方案时考虑的点

目标是否可达成 实现难度 可维护性 可扩展性
技术方案1-spring定时器
技术方案2-分布式调度中间件



3.8 安全生产

安全生产包括几个部分,包括且不限于下面几个部分

  • a. 监控
  • b. 对账
  • c. 灰度方案
  • d. 数据隔离
  • e. 兼容性评估
  • f. 发布流程

我们举一个例子。

需求:在消费者收货成功时触发对商家的结算
技术方案1:,写了一堆如何如何触发结算,如何如何更好的支持后续的可扩展性
技术方案2:
,写的方案可扩展性没有技术方案1高,但是做好了未触发结算的监控、触发结算之后的对账并设计好了对应的报表防止出现资损


其实这也是我们在技术方案中可能会忽略的,埋头于代码结构如何如何的好,但是有些东西其实是要比单纯的代码更重要的,就比如风险控制,完备的监控、不可缺少的对账是保障公司资金安全更是保障我们自己绩效的工具【狗头】(此处应有表情)

那么对于监控、对账的具体要求是什么呢?笔者认为

监控:

  • a.监控目标——写清楚监控的是什么内容
  • b.监控点——如通过打印日志监控,那么日志打印在哪个类的哪个方法
  • c.监控触发——是通过sunfire采集触发还是其它,如果是sunfire采集最好能把监控项地址贴出来
  • d.监控订阅人——监控告警需要的订阅人
  • e.监控触发后的解决方法——如果发生异常改如何解决?如手工触发结算


对账:

  • a.对账目标——写清楚对账是为什么
  • b.对账方式——写清楚是怎么对账的(如通过odps天级定时任务,履行单上的关务资源code和日志表中关务cp回传报文的关务资源code相对比要一致,不一致的形成某个数据集,通过锦衣卫-资损风险平台配置)
  • c.对账告警订阅人
  • d.对账异常之后的解决办法


还有其它几个部分

  1. 灰度方案,包括且不限于
  • a.多方前置准备
  • b.灰度切流开关设计
  • c.灰度切流节奏
  • d.异常应对
  1. 向前兼容性,包括且不限于
  • a.接口的向前兼容-尤其是对外的接口
  • b.数据结构的向前兼容-如不能随意改变字段的存储类型和格式
  1. 环境隔离-如有租户隔离&预发线上隔离的情况需要考虑数据

  2. 发布流程,包括且不限于

  • a.发布计划
  • b.检查项列表
  • c.发布流量监控

带土.jpeg