1. 业务系统越来越复杂,开发怎么分工?
1.1 背景
公司的业务系统已经迭代了10年,子系统大大小小加起来大约有80到100个。开发团队有30多人,每人负责几个子系统,所有相关事项都由个人全权负责,需处理产品业务沟通、开发、测试、线上运维、数据统计分析等各方面的工作。当人员离职或调动时,子系统通常会交接给新人,导致文档丢失和设计意图不明确的情况屡见不鲜。随着业务的发展,公司对系统的专业性要求越来越高,专门设立了产品经理岗位;然而,开发人员的分工似乎没有太大变化。
直到最近,公司开始重视数据决策,甚至请来了专业的第三方数据建模分析团队。在为数据分析团队提供数据时,我发现了一些明显的问题:
- 要获取某个子领域的完整数据,需要逐一联系开发人员,询问数据的业务含义和标准,才能获取完整信息。如果要获取更多领域的完整数据,需要联系的开发会更多。
- 数据来自多个子系统,零散分布在各自的MySQL数据库,收集、清洗、组合这些数据需要大量工作。
- 开发系统页面功能、数据统计分析、测试、运维都是一人全包,难以在功能开发和数据分析等特定领域形成专业化的工具积累。
总体来看,团队分工较为原始,烟囱式分配工作任务,专业深度难以提升。
1.2 开发怎么分工?
在降本增效的大背景下,公司无法在开发、测试、系统功能和数据统计等多个维度实现细化分工,因为这会增加支出。更可行的做法是在现有开发团队内进行一次细化分工。如果只能做一次一分为二的分工,我的分工思路:
- 面向实际问题:当前主要问题是数据获取难度大。考虑到后台开发人员的能力特点,可以将系统功能(CRUD、业务流程、页面交互接口)与数据统计分开,这两者的技术栈也有明显差异。因此,适合在这个维度上进行分工。
- 常见分工方式:按开发、测试、运维分工。但这种分工并不能解决主要矛盾:开发人员有能力自行测试和运维自己的功能,随着公司CI/CD和K8s部署平台的完善,这方面的矛盾并不突出。
分析结论:将开发人员划分为“系统功能开发”和“数据统计开发”两类,各自的职能和变化点如下:
系统功能开发:
- 负责子系统的CRUD、业务流程、页面接口开发。
- 向流程引擎、消息中间件、分布式组件方向深入发展。
- 不再负责数据统计分析,有更多时间专注于中间件开发,抽取业务系统的共性部分。
- 以两三人小组形式负责更大范围的领域系统,合并可能重复的子系统。
数据统计开发:
- 负责数据资产管理、报表开发、数据建模分析。
- 向大数据、数据建模、数据挖掘、机器学习方向深入发展。
- 不再处理一线业务流程的问题,减少被干扰的次数。
- 负责比功能开发更大范围的领域,将上下游各领域数据汇总分析。
通过这样的分工,团队可以更有效地解决当前问题,同时提升整体专业性和效率。
2. 分工后,两类开发的边界在哪里?
2.1 数据划分
有分工,就应该有边界,明确的责任边界是顺利合作的基础。从数据的角度来看,我们需要识别整个系统中的数据,并明确每个岗位的责任。可以按照常见的业务系统数据库垂直划分和数据仓库分层划分的方法进行,如图所示。
2.2 数据维护职责划分
数据维护职责划分:
-
业务系统数据库,由系统功能开发人员负责。
-
数据仓库的DWS和ADS层,由数据统计开发人员负责。
-
ODS层和DWD层的职责划分存在一些争议:
-
ODS层的数据是业务系统的原始数据快照,每个周期生成一次,表结构与业务系统基本一致。由于ODS层的表结构和字段含义由系统功能开发人员设计和维护,因此由他们负责是合理的。考虑到ODS层与业务系统的耦合关系,即当业务系统的表结构发生变化时,ODS的表结构也需要相应调整,这种耦合关系由系统功能开发人员维护再合适不过了。
有了明确的责任划分后,数据统计开发人员再也不用为了统计报表,辛苦地跑去各个业务系统数据库快照数据了。而系统功能开发人员也不用再担心自己维护的数据库被随意导出,或者一旦修改表结构就引发其他报表统计问题。两边都省心,皆大欢喜!
-
DWD层负责对ODS层的数据进行清理和整合,形成标准的数据基础表。虽然ODS层的责任划分还算明朗,但DWD层的归属在业界和团队内部却有较大争议。数据统计开发人员对ODS层并不熟悉,ODS层不是他们设计的,表结构也主要面向OLTP。而系统功能开发人员对于如何设计DWD层的数据表结构也没有十足把握,需要了解清楚DWD层之上的统计分析需求才好设计,而他们并不熟悉DWD层之上的情况。
究竟谁的说法更合理呢?数据统计开发人员确实对ODS层不熟悉,不仅是表结构,明确字段的业务含义、适配表结构变更等都是难点,这符合客观事实。而系统功能开发人员确实对DWD层之上的统计分析不了解,那么他们真的需要了解这些才能设计好DWD层的表结构吗?答案未必。从分层架构来看,上层依赖底层,底层不需要感知到上层的存在。因此,系统功能开发人员的说法实际上站不住脚,DWD层的责任理应由他们承担。
-
最终责任划分结果如下图:
两类开发的依赖边界是DWD层,数据统计开发人员禁止读写ODS层和业务系统的数据,DWD层有效隔离了业务系统表结构变更对上层的影响。为了使系统功能开发人员可以设计出良好的DWD层,我们制定了一套《标准宽表的设计原则》。
3. 标准宽表的设计原则
在介绍设计原则之前,我们先通过一个具体案例来感受一下如何设计DWD层的表结构。我们把这种符合规范的DWD层表称为“标准宽表”。
3.1 案例:公交车运营信息的宽表设计
假设你现在是一名分析员,你的长期目标是优化每辆公交车的路线和发车频率,使公交车既能更好地服务市民,又能为公司带来可观的收益。为了达成这一目标,我们需要哪些信息用于分析呢?我们希望获取的信息既要充分,不能遗漏关键信息;也不需要过多无关信息,以免增加数据获取和分析的工作量;此外,这些信息必须在当前技术水平下是可获得的。如果我们用表格来记录信息,每张表只能记录同一类内容,至少需要以下几张表?可以进行以下场景的分析:
- 哪条公交线路最拥挤?哪条线路相对空闲?
- 哪个站点人满为患?发车频率是否合理?增加班次能否解决问题?行车路线是否需要优化?
- 乘客等待公交车的平均时长是多少?哪条线路和哪个站点的等待人数和时间最长?
- 哪条公交线路收益最好?什么时间段收益最好?整体收益如何?公交车型是否需要优化?
读者可以先花5分钟思考一下,然后再继续往下读。
最终梳理出来,我们需要2张宽表:
宽表1:公交车运行记录表
这张表格的每一行记录了一次公交出行的信息。通过它,我们可以分析线路和班次的运营情况。
字段分类 | 字段 | 示例数据及说明 |
---|---|---|
基础信息 | 公交车车牌 公交车司机 线路 始发站点 结束站点 |
粤B6688GD 王师傅 101路 火车站 动物园总站 |
运行信息 | 班次 总里程 出发时间 结束时间 总载客数 |
08:10 60km 2024-01-02 08:10:00 2024-01-02 09:52:32 300人次 |
收入信息 | 车费收入 广告收入 补贴收入 油费成本 车辆成本 司机成本 |
823元 100元 50元 30元 200元 100元 |
宽表2:公交站点上下客记录表
这张表格的每一行记录了一次公交车到站的信息。公交车可以在车门处安装记录器,记录每个站点上下车的人数,但由于技术限制,没有办法记录到每个人的上车站点和下车站点。
字段分类 | 字段 | 示例数据及说明 |
---|---|---|
基础信息 | 公交车车牌 公交车司机 线路 始发站点 结束站点 班次 |
粤B6688GD 王师傅 101路 火车站 动物园总站 08:10 |
到站信息 | 站点名称 站点经度 站点纬度 到站时间 离站时间 已行驶时长 已行驶里程 |
何香凝美术馆站 113.98 22.53 2024-01-02 09:03:32 2024-01-02 09:03:58 53:33 32.38km |
载客信息 | 到站总人数 离站总人数 上车人数 下车人数 本站刷卡总金额 |
36 45 12 3 24元(此列数据可能缺失) |
读者朋友,你的设计需要几张表呢?是否每张表都是同一类内容,是不是只表达一种事件、或一种关系、或一种实物呢?
你是否疑惑,这两张表真的能解答上述场景中的问题吗?这正是分析师的专业所在,他们需要在有限的数据中分析、推理,挖掘出有价值的信息。这里不做展开,有兴趣的读者可以继续思考,怎样利用上面数据,估算出每个站点用户等待某条线路的平均时长?
3.2 标准宽表的设计原则
结合上述案例,我们直接给出标准宽表的设计原则,只有2个:
-
单一原则,一张表只能描述同一层次的一种事物。
它可以是一种事件,例如每次告警记录一行,每次刷卡记录一行;它可以是一种关系,例如每个好友关系记录一行,每个师生关系记录一行;它可以是一种实物,例如公司每台笔记本记录一行,每个员工记录一行。不满足单一原则的例子:一个表中既有每个订单的信息,又有订单下每个商品的信息,用一个type字段区分,订单和订单下的商品,它们不是同一个层次;再比如,一个表中即记录了班级的信息,又记录了学生的信息,班级和学生,不是同一种事物。
单一原则的最大价值:降低表的理解门槛。数据分析开发人员会感谢系统功能开发人员提供如此清晰的数据。
-
不丢失信息原则,不管采用哪种数据结构记录,都要确保信息没有丢失,丢失信息是不可逆的。
以公交站点记录为例,原始信息包括每个站点的到站前总人数、离站时总人数、上车人数和下车人数。如果我们只记录到站前总人数和离站时总人数,就会导致信息丢失,因为我们无法从中推算出每个站点的上车和下车人数。而如果我们只记录每个站点的上车人数和下车人数,就不会发生信息丢失,因为到站前总人数和离站时总人数可以被计算出来。当然,这种记录方式有个小缺点,就是无法对数据进行对账。
你可能会想,信息丢失这么明显的事,怎么可能发生呢?其实,这通常源于人的“傲慢”:我现在不需要这个信息,所以我不在意,也不记录。
回到之前的问题,设计DWD层的表时,真的需要了解DWD上层的具体需求吗?答案是不需要!只要确保信息不丢失就行。读者可能会疑惑:在不了解需求的情况下,真的能设计好表吗?其实,这里并不是完全不了解,而是不需要了解具体的需求。可以这样理解:如果开发要写一个基础工具类,他们只需把功能设计得尽可能完备,以满足大多数需求,而不需要事先知道具体的使用场景;如果运营商要搭建5G网络,他们只需确保网速、网络延迟和网络覆盖都做到位,而不必事先了解5G网络将催生哪些应用。同样地,在设计DWD层的表时,我们对表的大致用途是有了解的。我们要尽可能保留所有有价值的信息,不丢失数据。至于具体如何使用这些数据,是上层需要深入挖掘的事情。某个字段现在可能用处不大,但将来可能非常重要。我们无法预见未来的具体需求,也不应该因此有意删减信息。这正是“不丢失信息原则”的初衷。
3.3 Kimball维度模型概述
业界常见的数据仓库建模模型有Kimball模型、Inmon模型等,其中Kimball模型的设计理念和标准宽表的设计原则非常贴合。以下摘要了一些感悟深刻的点:
- 维度建模就是时刻考虑如何能够提供简单性,以业务为驱动,以用户理解性和查询性能为目标。
- 在同一事实表中,必须具有相同的粒度,同一事实表中不要混用多种不同的粒度,不同的粒度数据建立不同的事实表。
4. 管理标准宽表的产品原型图
为了方便数据统计开发人员查找所需数据、监控保障宽表数据质量,我们设计了一款管理标准宽表的工具。
以上是产品原型图,以供参考。