CRUD工程师晋级之路

CRUD工程师晋级之路

每当到了工作总结的时间,就总有朋友苦着脸跟我说,“工作一年到头,除了写了些BUG,就整天做一些CRUD,完全没长进……”呵呵,这里说的写BUG只是开开玩笑,然而这“整天CRUD,没见长进”恐怕是好多人的真实感受。

啥是“CRUD”?我们在管理、操作大量数据的时候,一种典型的模式就是使用(关系型)数据库。而针对数据库的添加(Create)、查询(Retrieve)、更新(Update)和删除(Delete),就是在其之上的基本操作。不少不明真相的工程师的工作就是以此为核心的,因此“CRUD工程师”甚至作为一种调侃性质的标签,为广大工程师所熟知。

显而易见,现在具有一定规模的计算机系统中,不使用数据库情况的少之又少。数据库简直就是现代软件开发中的一剂灵丹妙药:

1. 能够可靠、快速地存储、检索千万、乃至上亿级别的数据量
2. 强大的事务管理机制,满足了大部分场景中对数据一致性的需求
3. 主从同步、数据分片等集群化的机制,除了提高系统可靠性以外,很好的解决了分布式系统中,数据集中化管理的需求

数据库那么强大,难怪众多工程师爱它到不能自拔,心甘情愿地成为广大“CRUD工程师”中的一员。那么,今天就让咱们聊一聊这数量庞大的“CRUD工程师”群体的晋级之路。

图1 关系数据库

1. 关系模式直接作为业务模式

关系型数据库(Relational Database)的核心实体就是数据表,核心操作就是在定义好的数据表上的CRUD操作。这套东西实在是太好用了,也太深入人心了,以至于你能在好多地方都能看到这种将关系模式直接用作业务模式的系统:

A. 某业务系统,竟然将其一核心业务实体的状态字段更新操作直接暴露为一个写接口,不做有效性检查,全无状态转移图之说;
B. 某单据系统,其作废单据操作竟然是果断干脆的数据库 DELETE 操作,没有历史记录,不留任何痕迹,接手该系统的同学在认识到这一点后表示生无可恋;
C. 某大部门的团队间仍然奉行系统间的数据库对接模式,以至于这些系统很快就严重耦合,就像一群摔成一团的相扑选手,互相扭打在一块儿,躺地上动弹按不得;
D. 某团队声称实现了一套“元业务系统”,产品经理可以撸起袖子可视化手搭业务系统。实际是实现了一套黑科技,除了将 RDBMS 的 DML(即CRUD)直接暴露出来,甚至直接暴露出了 DDL(数据库定义)……

(有点后怕的,我要在这里补充一句:以上 case 都是本人杜撰,切勿对号入座!(逃…))

这些系统的问题,是声称已经套上了业务的外衣,实则最多就是件“皇帝的新衣”。这种处于裸奔状态的系统,几乎无法保证业务逻辑的正确性、完整性。

之所以有这种情况的出现,是因为有太多的 CRUD 工程师对“业务逻辑”的理解出了问题。可能是出于能力有限,也可能是因为并不在意,这些工程师的内心独白其实是这个样子的:“业务逻辑不就是建个表、填填表嘛,最多再加上点副作用的操作”。

呵呵,如果真这么想,这焦油坑你趟得不冤。大多数“业务方向工程师”严重缺乏“业务建模”的意识,将关系模式直接用作业务模式,由此引出的傻事不胜枚举。

让我们拿国际象棋再举个例子:

图2 国际象棋 Initial

作为一枚CRUD工程师,在完成了左边的数据表设计和右边的数据展现以后,往往就认为已经万事大吉了。但仔细想想,这样的产品在交付后,对使用它的客户——现实情况中既可能是最终用户,也可能是上下游系统——提出了相当多的潜在要求。对!CRUD工程师从来不会提示你这些潜在需求,谁会对自己并不知道的事情作说明呢?

简而言之,这样的一个国际象棋程序,自身对国际象棋规则完全是一窍不通的。就是拿出个表格给你,随你填成啥样。在这件事情上,完全指望使用者不犯错,这是何等的心大!

图3 国际象棋 Bad case & Good case

于是,这个国际象棋程序完全有可能出现 Bad case 的这种诡异情况:黑色骑士(knight)走出一个华丽的斜线,和其中一个白色兵(pawn)共处一室(什么鬼?!)“国际象棋填表系统”并不会阻止你这样做,因为它并没有正确与错误之分。

这时候,CRUD工程师被客户、老板抓出来收拾残局了。经过一番调研,原来客户是想把黑色骑士走到6d,并吃掉(capture)另一个白色兵。“产品已经够简单的了,客户怎么都这么蠢?”CRUD工程师嘀咕道,“哎,这工作坑真是多啊”。

在焦油坑中的你,有没有想过这自救之路在哪里?

2. 设计和实现领域模型

在做招聘面试时,一般我会避免和面试者谈到 MVC 这个他们准备过多次的话题。了无新意倒是其次,更麻烦的是业界的不少传统实践,把CRUD工程师们的思路越带越偏。

模型(Model)、视图(View)、控制器(Controller)三分天下的架构划分,似乎有一种每一块的比重基本都在33%上下的暗示。加上各种强大的 MVC、ORM 框架的加持,CRUD工程师们以为可以躺着干活了:在数据库里建几张表,写个页面渲染模板,再写个页面请求响应处理函数(是的,经常就是在一个函数内搞定),好了齐活,收工下班。

然而,只要你做的不是那种创业公司一上线就黄,没几个人用过的系统;经历过哪怕只是两三次的产品迭代,面临越来越丰富和深入的用户需求。你会发现,原来的控制器部分一直在不停膨胀,模型的问题也常常想打自己的脸。

更巨大的变化,是现在早已不再是 PC Web 的时代了,原生 App、移动 Web 等等多种客户端技术在近几年爆发(IOS、Android、JavaScript、…),青出于蓝而胜于蓝。原先 MVC 中的视图(Web 页面)渲染工作,面临被新技术的完全替代。CRUD工程师手中的系统们,面临向 SOA(Service Oriented Architecture)转型。(SOA又是个庞大的话题,今天暂且不表)

夜深人静,四下无人,CRUD工程师再次陷入深深的困惑:一边是臃肿不堪的模型和控制器层,另一边是逐渐收缩和服务化的视图层,难道建表、写表、读表就要成为我的唯一主题了吗?

如果不是CRUD,业务系统后端工程师的价值在哪里?

理解并抽象出业务逻辑,建立满足需求的业务模型,以此设计实现出可靠的系统,并有效地控制复杂性。这才是大部分业务系统后端工程师的工作重点,也是解决他们工作中遇到的问题和难点的关键。

我最早听说领域驱动设计(DDD:Domain Driven Design)也是在多年前年少无知的时候。那时候心想,“领域(Domain)是个什么鬼?大神们总整新名词,估计又是种屠龙之技……”于是就把 DDD 的书籍、材料束之高阁。经历了几年的后端研发工作,见过一些复杂的系统和变态的需求后,再回头来看看 DDD,才发现当初是“too young too simple, sometimes naive”:

DDD 就是用来设计和实现业务逻辑的一剂良药。如果非要将它称作“屠龙之技”,那后端工程师面临的复杂业务逻辑真就像龙一样庞大而凶神恶煞!


图4 Software: Front End vs Back End

3. 改变和挑战

关于后端业务系统的“术”先说到这里,接下来我们聊聊“道”。

凯文·凯利(Kevin Kelly)在他的畅销作品《失控》中,用蜂群的例子向读者们阐述了“涌现”(emergence)的概念,即一个复杂系统中由次级组成单元间简单的互动所造成的复杂现象。

在我的工作中,也遇到过类似虽算不上玄乎,但也相当有趣的现象:随着系统特性、功能的逐渐添加,某天我们发现了一组特别的 case,是由三个功能相互影响,产生的特殊情况。这三个功能由早到晚,分别有超过5年、1年和不到2个月的“年龄”。那个例子并没有任何 bug 产生,仔细分析起来结果也并不令人意外,只是之前谁都没有意识到逻辑的推进,数据的变化,能有这么灵活、这么快。

所以后来,我有一种感觉,构建成熟的后端业务系统,就像是在用一条条的规则创造一个小世界。然而,CRUD工程师不相信,也没有手段去创造。根本上,他们认为自己没创造任何东西,只是数据库表的搬运工。

有一类很让我心烦的情况,就是在解释技术、算法、计算机程序是什么的时候,总是有人不胜其烦的蹦出“不就是0和1嘛”的粗糙的还原主义观点。自底向上,他们否认一切架构起来的模型抽象和客观存在。“匹萨饼不也就是馕加肉嘛”,这也是他们常持有的观点。

比如说操作系统中的文件系统,实际就是对磁盘等物理存储介质的一层抽象。最终文件系统被很好地定义和实现了,好到对上层用户屏蔽掉了诸如磁盘扇区、磁道、磁头这样的物理细节,此外也达到了足够的独立和抽象,甚至底层换成内存、FTP、NFS 也是 OK 的。再比如说 TCP 协议。所有人对 TCP 的认识,应该都是在通信的双方之间,建立了可靠的、全双工的通信管道。但是CRUD工程师们,可能说什么也不会相信,TCP连接是在IP层上“抽象”、“虚拟”出来的。

对于操作系统来说,文件系统即是其要实现的一套重要业务;对于TCP/IP构建的互联网来说,TCP即是其要实现的一套重要业务。拜先贤们所赐,这些“重要业务”都被完美实现了。否则,若是按照CRUD工程师的尿性,看个视频恐怕还要时不时控制下磁盘磁头,设定扇区和磁道;发个邮件还要担心网络丢包(丢包重传)或者拥堵(流量控制)呢!

回到现实当中,我们还面临一个更大的挑战,即如何定义业务模型?如果我们连自己要做的是什么都不清楚的话,那我们应该如何开始?

DDD 之父 Eric Evans 说,工程师应该和“领域专家”充分合作,共同梳理、挖掘出核心领域模型。Eric Evans 又说,“领域专家”不是某个特定的职位,他可能是深入了解业务和系统的任何角色。这下情况就尴尬了。“领域专家”是那种“人人都可以是的”产品经理吗?这下我和CRUD工程师一块儿,陷入了深深的思索。

“如果给我 1 个小时解答一道决定我生死的问题,我会花 55 分钟来弄清楚这道题到底是在问什么。一旦清楚了它到底在问什么,剩下的 5 分钟足够回答这个问题。”——爱因斯坦
“如果有人不相信数学是简单的,那是因为他们没有意识到人生有多复杂。”——冯·诺依曼

大概,我前面说的“设计和实现业务”,应该改成“发现和创造业务”更为恰当吧。

4. 一些结论

关于产品经理:
正因为以上的原因,我会对真正靠谱的产品经理敬佩有加。他们真正担起了“领域专家”的角色,或者至少在这条路上不断前进。

关于工程师:
a) 对于任何一个眼光长远的工程师,我是认可其尝试去做好“领域专家”这件事的(一般被称作“业务能力强”)
b) 对于一心向往只做“纯技术方向”的工程师,还请你早日展现出“5分钟内完美解决数学问题”的能力,并且尽快找到那个替你解决前 55 分钟的工作的人
c) 对于三十岁退休不再写代码的架构师、工作三五年走向人生巅峰的CTO,以及问出“程序员就是吃青春饭”的家伙,我想分享的一点小小经验是:我发现很多程序员连读书时候学习的 OOD(面向对象设计)、OOP(面向对象编程)都没拿到 60 分;更让人汗颜的是,若能早日打开你的技术视野,你会发现,这评分根本就不是百分制的,是上不封顶的!别再玷污“工匠精神”这个词了

关于CRUD工程师的晋级之路:
是的,抱歉我在一开始向你隐瞒了真相:CRUD工程师一路低头走到黑的晋级之路恐怕是一条死路。但别着急,当你转过身来,仔细观察下之前一次次擦身而过的荆棘丛林深处,隐约出现的光亮,那才是你的下一个目的地。
发布于 2017-02-26

文章被以下专栏收录