杨云,ThoughtWorks总监级咨询师。二十余年软件开发行业经验,在互联网、企业应用软件、咨询行业都有多年的深耕。指导过多个DDD实施项目的落地。近年来致力于研究如何能使DDD建模在大规模开发团队的情况下确实的落地到代码层面。 杨云还是函数式编程的宣导者,翻译过《深入理解Scala》和《高性能Scala》,还写过一系列介绍Haskell语言的文章。并提出了将函数式编程思想和DDD建模相结合的类型流建模方法论。
众所周知,客户需求的自然形态是面向过程(或者叫结构化编程)的。 你在任何项目上,跟业务专家聊需求,你得到的都是先做什么、后做什么;流程、子流程。
至于面向对象,是一种设计方法,并不是所谓最接近现实世界的设计思想,反而是设计师硬凹过来的。只不过现在的程序员上学就学的面向对象,受面向对象训练良久,已经忘了面向过程了。不信你可以把你的类图拿给不懂技术的业务需求方,解释给他们听,问问业务专家脑子里的现实世界是不是这样的。
但面向过程毕竟被淘汰了,而且淘汰是有理由的:
当一个团队多人共同开发一个应用的时候,由于过程之间存在依赖,而每个过程都可以操作任何资源,并且过程和资源的关系不是显式的,这就使不同开发者之间产生互相干扰,而且是隐式的。因此,随着业务和系统复杂度的提高,和开发团队规模的增加,面向过程只能被淘汰。
面向对象强调行为和数据的封装。某种角度来说,相当于说我的资源只有我能碰,你不许碰,你的资源只有你能动,我也不碰。我们之间只能通过公开的接口(或消息)来交互。从类比的角度看,一个微服务有点像面向对象的宏观体现。其内部数据(聚合)只允许本服务自己操作,别的服务只能通过这个服务的API来访问。这样在一定程度上降低了开发者的互相干扰。
但是,一个微服务比较大且复杂的时候,微服务内的开发团队往往也不止一人,这些内部的开发者之间仍然存在着干扰。和原本的面向过程没有本质区别。
另一个问题就是面向对象本身缺乏统一认识,太多争议。贫血模型和充血模型之争,继承和组合之争,静态方法的问题等等,还有很多case by case的争论。一个设计经常被一些人说不OO,同时被另一些人说不实用。Java的面向对象和和AKKA或者说Actor模型所体现的面向对象又不一样。包括和传说的面向对象鼻祖smalltalk(我没有经验)又有区别。
最近这一两年,我们越来越多指导客户团队做DDD落地的咨询项目,当面对客户大规模的厂商团队(而且常常是来自多个厂商)的时候,大量的junior的厂商开发人员是不理解面向对象的,而不同厂商的高级开发人员互相之间以及和我们之间都是没有统一认识的,这一点对大规模应用的维护带来了非常大的麻烦。
而很多人寄予厚望的函数式编程,虽然有很明显的优点,而且内部争议不太多,但是始终无法大规模使用。经过多年的努力推广,我已经深深认识到:如果开发人员必须要理解了Monad、MonadTransformer之类的概念才能用上函数式编程,那么函数式编程注定只能在小圈子里流行。
因此,在去年(2019年11月)我提出了一种新的设计方法论,叫做类型流(TypeFlow)。这种方法论可以算是一种世俗化的函数式编程和改进型的过程式设计。它的思想可以用下面这张图表达。
类型流有以下特点:
类型流设计建模的构造块如下:
以一个TODO应用为例,创建代办事项设计图如下:
这个例子较为简单,但已经可以体现出类型流方法论的主要规则:
这些规则带来以下特点:
这些特点带来以下优势:
类型流最核心的思想是显式的副作用剥离,通过这一点得到函数式编程的好处,而不引入函数式编程的难点。再放一张图解释一下副作用剥离的常见模式:
把上图的一个大函数剥离后,得到了纯函数修改业务数据状态,这个函数不需要知道入参是从哪个数据库表里查来的,也不需要知道它自己的输出要被写到哪里去。这个函数变得极其容易单元测试。图上还有两个未连接的输出,工具应该很容易检测出来。
这个图和流程的区别在于:除了样子有点像,他们完全就不是一种东西。流程图里的每一步都是一个过程,这个过程可以做任何事情,操作任何资源,从流程图上是完全看不出它操作了什么资源的。因此流程图完全继承了过程式编程的所有缺点。
◐ 类型流的团队组织
这么长的文章看到这里,大家想必也应该能看出来,类型流是针对大团队、细分工组织设计的方法论。高级程序员团队画类型流图建模,利用工具生成代码骨架,初级程序员填空。高级程序员团队仍然是一个敏捷团队,而初级程序员只有基本的编程要求。甚至单元测试能力也不要求。刚才我虽然说纯函数很容易单元测试,但其实也很容易开发一个配套的测试工具,可以读取文本的输入参数列表和期望返回值列表,可以让专职的测试人员或者BA去填。所以是对高级程序员提供了要求,对初级程序员极大降低了要求的方法论。
◐ 类型流的适用场景
从2019年11月宣布以来,由于种种原因,工具方面进展缓慢,但方法论本身在好几个客户那里,作为DDD落地方法的详细设计一级的方法得到了应用,取得不错的效果,也越来越完善。在此介绍给大家参考,欢迎意见和建议。
附:本文得到了杨云(大魔头)的授权,很怀念曾经和大魔头并肩在深圳开展咨询工作的岁月。今天是2020年的最后一天,用大魔头推出的类型流方法作为「逸言」的收尾,希望大家看到DDD兼容并包的一面。顺祝各位读者新年快乐!