为什么你的轮子很难用(四)组件的设计工程 1

197 阅读11分钟

画外音:

一直都在收拾了别人的烂摊子,总结一下怎么做一个"人见人夸"的功能设计。

这个系列主要写给产品看,最佳实践不敢说,失败案例我有大把可以分享和吐槽的。

研发请随意,有不妥的地方欢迎指正。

前情提要:

# 为什么你的轮子很难用(一):别造,造的话先盘组织和业务

# 为什么你的轮子很难用(二): 从战略到抽象1

# 为什么你的轮子很难用(二):从战略到抽象2

# 为什么你的轮子很难用(二):从战略到抽象3

# 为什么你的轮子很难用(三):需要梳理方法和方案选型标准

当你不得不造一个轮子的时候,你需要先储备一些基础常识。内容很多,我们分期讲:

————————————————————————————————

二、组件设计的设计工程

微信截图_20220606205402.png

当我们粗略定下来方案之后,就要开始规划功能了。

规划功能可不是上来就时序和类图做技术设计。

而是 拿出之前整理好的 干系人关注点 和 干系人阻力点。

详见: # 为什么你的轮子很难用(三):需要梳理方法和方案选型标准

开始思考:在功能中需要怎么融入日常管理 和 放大这个功能对各个环节的价值。

第一步:管理设计

为什么第一步强调管理思考呢?

因为 出了风险或者对线上有负面影响 就要被回滚啊。

如果公司有 事故责任认定的EP部门,还要扣工资,绩效和年终。

所以 麻烦大家先站在 老板的 角度想一想。

不然造一个轮子出来,把自己坑了那就实在得不偿失了。

就算你只是想 面向晋升和简历编程,最好也得掂量掂量。

作为老板,对于这个轮子考虑的是什么?

  • 业务价值:有什么有用,在什么数据指标上能看到提升
  • 成本控制: 联动全局上下游需要付出多少人力物力
  • 落地风险:这个轮子会导致多少下游出问题,掉指标
  • 精细管理:从这里能储备什么数据,对什么环节做控制

以上都是一个轮子需要考虑的东西。

所以在工作中,业务方/老板 问你要数据,

总是出现:这块没有埋,那块没日志,数据结构没设计这个字段.... 核心问题是什么:

是 早期在设计轮子的的时候,只顾着解决明面上提过来的需求交付功能。

而没有,基于多角色的需要,进行 功能流程,接口逻辑,数据结构的设计。

无论你后期时候需要 自动化或者智能化。都是建立在 早期的数据化搭建的。

别相信产品说只是试试,产品这个岗位就是为了改需求而生的。

真试错成功了,后面需求疯狂迭代起来,老板连重构的时间都不给你。

比如说:

能加上索引/唯一键/操作日志事件的都单独加上。有数值id就有加密id,提前哈希分表的就提前分表。

有添加就有删除,有查看就有导出,有单个就有批量,有存库就有hive,增删改查基本都别偷懒。

第二步:价值设计

价值设计,大白话讲: 这个轮子很好用,对业务/用户有帮助。

那 核心价值和核心场景是什么,外延价值和拓展场景是什么,要提前思考清楚。

考验的是你 能不能准确蒙中甲方未来的需求变化。

我们可以举几个例子:

1)比方说,要搞 一个优惠券发放。这时 产品跟你说 一个用户限制只能领取1次同个id的优惠券

真的傻到 按UID做幂等吗?这就扯淡了吧,那以后改多次怎么办,连累 上下游跟你一起换接口?

2)再比放说,记录一下作者的合同签约,先只做 添加签约和查询。

真的傻到 按UID做唯一键吗?一个作者一辈子只能签1次,这可能吗?那续约怎么办?

3)再或者说,上传一些卡号卡密的CDK。需要分多少种类型,能不能多次上传,上传要不要做去重?

真的傻到 按文件md5做哈希校验闭着眼存redis的list?稍微一改字符就能绕开,有必要做吗?

这跟脱裤子放屁有什么区别?

——

以上例子,都是我见过的真实案例。

太多人只考虑眼前,或者考虑自己当前搞起来快不快。

对外号称敏捷迭代,实际上给长期增加了大量的改造成本。

而这些本来稍微花几分钟枚举一下,就可以规避掉。

你自己造的屎山,大部分情况下都是连累你自己去维护的。

第三步:用例设计

这里考验的是每个人的知识储备,也就是你见过的情况多不多。

建议每个人都整理一下常见的用例,这对你后期CV一把梭乃至组件化都是有帮助的。

这里我们以一些业务后台admin最常见功能举例:

分类注意要点
一共需要多少字段
 选择什么字段做唯一键
 每个字段能否做校验
 配置选项之间是否有级联或互斥
 有单条新增怎么做多条批量
 多条数据间有重复是覆盖,去重还是打回
能软删就不硬删除,先下架后删除
 删除的前置校验条件是什么,时间/状态/被引用?
 删除之后需要联动多少下游做变更处理
什么类型创建后,是否不能修改
 为了可以改,数据计算的策略是是么
 什么数据被修改可以回溯填补
 什么数据被修改可以回滚还原
怎么存,存多久,怎么同步,怎么过期,要不要加缓存
 怎么查,加什么字段做索引和查询
 有单条件,要不要加多条件
 有单个查,要不要加批量查
返回内容怎么分页,怎么排序
选择能用树结构做分类就提前做
 超过5个选项的内容就得加搜索
 除了单个,是否涉及多个选择,全局选择
 下拉选择没有,能不能直接在当前新增
状态能拆出多少状态:发布状态,时间状态...
 不同状态下,对于增删改查需要做什么校验处理
时间有单个起止,就有永久有效
 有单个起止,是否需要多次循环
 有多次循环,就有无规律的多个起止
 日期和时间,是否需要拆分,进行特殊控制。
同步对方删除,没通知我,怎么做diff
 对方null,我怎么防御性编程,部份修改部分不改
隔离应用设计怎么跟业务分离
 业务与业务之间怎么多租户隔离互不影响
 怎么实现针对某个业务的特殊逻辑
接口接口复用性怎么设计,通用字段和拓展字段是什么
 使用有先后顺序的接口,能否合并提供功能
 怎么反爬,频控怎么做,限流怎么做

只有当你对绝大多数情况(用例)能快速枚举,了如指掌的情况下,才能抽象出一个合理的组件。

画外音:

很多人呢,面向部分场景,抽象了一个具备多态的模块,可配置输入得到对应输出。

就开始搞对外服务,说组件化了,然后业务方上来一瞧,怎么这也没有,那也没有,WTF 怎么用啊?
胆子大点的 连 租户服务隔离 都没做,上来就说自己是中台,让所有人中心依赖他。

有一个接入方QPS上去了,把系统打挂,就会连累所有接入方一起死。
比如最近520,腾讯的livelink中台因为斗鱼的调用QPS太高,连累上 B站/虎牙/快手等多家一起扑街。

其实很多事情的,是有硬性标准和行业规范的,只是大家都不愿意投入成本重视起来,最终囚徒博弈互相坑爹。

——————

当你了解了所有的要点,那就可以开始写用例了。

写用例,是一个人的基本功。

很多产品为什么PRD的功能逻辑,写不全,很大程度上就是没经历过 用例 的训练。

用例该怎么梳理呢?

一般通用格式是:

模块命名前置条件操作步骤预期结果
--------

这里我们以一个最简单的 列表状态管理 作为示意:

- 模块名称:列表页-列表-状态管理
用例1- 前置条件:进入页面,加载列表
- 操作步骤:无
- 预期结果:查询列表数据,展示每条数据的状态
    1)上下架:以开关组件展示,绿色==上架,灰色=下架 
    2)状态标签:
        若 当前数据为 上架状态
            当 today < start time,状态标签==未开始   
            当 start time <= today < end time ,状态标签==进行中 
            当 today >= end time,状态标签==已结束
        若 当前数据为 下架状态
            状态标签=已下架
 用例2- 前置条件:该条数据为上架状态           
 - 操作步骤:点击开关
 - 预期结果:
    校验当前用户是否具备操作权限,
    若具备,
      操作弹窗提示:"是否执行上架操作?"
      点击确认按钮,开关切换为灰色,状态标签变更为已下架,页面toast提示"下架成功"
      点击取消按钮,关闭弹窗。
    若不具备,页面toast提示"您缺少操作权限"
    
 用例3- 前置条件:该条数据为下架状态   
 - 操作步骤:点击开关
 - 预期结果:
    校验当前用户是否具备操作权限,
    若 具备,
        操作弹窗提示:"是否执行下架操作?"
        点击确认按钮,开关切换为灰色,状态标签变更为已下架,页面toast提示"下架成功"
        点击取消按钮,关闭弹窗。
    若 不具备,
       页面toast提示"您缺少操作权限"

看起来是不是和prd差不多?

其实 好的prd 可以直接当做测试用例。

那么现在,基于这个用例,我们就可以改写成prd,把这个模块大致写一遍。

     - 模块名称:列表页-列表-状态管理
     - 前端逻辑:
       控件1:开关按钮
        展示逻辑:绿色==上架,灰色=下架 
        操作交互:
         1)下架操作:
         校验当前用户是否具备操作权限,
            若具备,
              操作弹窗提示:"是否执行上架操作?"
              点击确认按钮,开关切换为灰色,状态标签变更为已下架,页面toast提示"下架成功"
              点击取消按钮,关闭弹窗。
            若不具备,页面toast提示"您缺少操作权限"
         2)上架操作:
         校验当前用户是否具备操作权限,
            若 具备,
                操作弹窗提示:"是否执行下架操作?"
                点击确认按钮,开关切换为灰色,状态标签变更为已下架,页面toast提示"下架成功"
                点击取消按钮,关闭弹窗。
            若 不具备,
               页面toast提示"您缺少操作权限"
       控件2:标签文案
       展示逻辑:
           若 当前数据为 上架状态
              当 today < start time,状态标签==未开始   
              当 start time <= today < end time ,状态标签==进行中 
              当 today >= end time,状态标签==已结束
           若 当前数据为 下架状态
              状态标签=已下架
       操作交互:无
       控件3:页面toast
       展示逻辑:
        根据接口msg返回内容,展示 {报错码}:{报错文案}
        在当前页面居中展示5秒后自动消失
       操作交互:支持手动点击关闭

     - 后端逻辑:
       接口1:列表数据接口
           入参:无
           出参: {msg,1:{name,上下架状态,start_time,end_time}....}
           依赖:略
           实现:略
       接口2:上下架操作接口
           入参:id,操作值,uid,timestamp // 1-上架,2-下架
           出参:{msg}

再基于这个模块,抽象出组件。

这个时候你就要考虑了:

  • 前后端分离,业务逻辑放哪里:是做成纯前端组件,还是 前+后组件。这是不一样的选型。
  • 后续遇到类似的拓展场景有什么,如何兼容:这决定了你的数据接口和组件设计。
  • 基于现有功能,应该抽象什么出来字段实现配置化:这决定了你的组件被人用得爽不爽。

所谓 从需求到模块,是一个 复杂到简单的归纳过程。 但是 从模块到组件,是一个 从简单到复杂的演绎,再从复杂到简单的归纳。

从需求到模块的拆解,先到这里。 我们下一篇,讲一讲,如何从 模块 到 组件。