从三明治到六边形
本文首先发表于ThoughtWorks洞见。 软件项目的套路 如果你平时的工作是做各种项目(而不是产品),而且你工作的时间足够长,那么自然见识过很多不同类型的项目。在切换过多次上下文之后,作为程序员的你,自然而然的会感到一定程度的重复:稍加抽象,你会发现所有的业务系统都几乎做着同样的事情: 从某种渠道与用户交互,从而接受输入(Native App,Mobile Site,Web Site,桌面应用等等) 将用户输入的数据按照一定规则进行转换,然后保存起来(通常是关系型数据库) 将业务数据以某种形式展现(列表,卡片,地图上的Marker,时间线等) 稍加简化,你会发现大部分业务系统其实就是对某种形式的资源进行管理。所谓管理,也无非是增删查改(CRUD)操作。比如知乎是对“问题”这种资源的管理,LinkedIn是对“Profile”的管理,Jenkins对构建任务的管理等等,粗略的看起来都是这一个套路(当然,每个系统管理的资源类型可能不止一种,比如知乎还有时间线,Live,动态等等资源的管理)。 这些情况甚至会给开发者一种错觉:世界上所有的信息管理系统都是一样的,不同的仅仅是技术栈和操作的业务对象而已。如果写好一个模板,几乎都可以将开发过程自动化起来。事实上,有一些工具已经支持通过配置文件(比如yaml或者json/XML)的描述来生成对应的代码的功能。 如果真是这样的话,软件开发就简单多了,只需要知道客户业务的资源,然后写写配置文件,最后执行了一个命令来生成应用程序就好了。不过如果你和我一样生活在现实世界的话,还是趁早放弃这种完全自动化的想法吧。 复杂的业务 现实世界的软件开发是复杂的,复杂性并不体现在具体的技术栈上。如Java,Spring,Docker,MySQL等等具体的技术是可以学习很快就熟练掌握的。软件真正复杂的部分,往往是业务本身,比如航空公司的超售策略,在超售之后Remove乘客的策略等;比如亚马逊的打折策略,物流策略等。 用软件模型如何优雅而合理的反应复杂的业务(以便在未来业务发生变化时可以更快速,更低错误的作出响应)本身也是复杂的。要将复杂的业务规则转换成软件模型是软件活动中非常重要的一环,也是信息传递往往会失真的一环。业务人员说的A可能被软件开发者理解成Z,反过来也一样。 举个例子,我给租来的房子买了1年的联通宽带。可是不多过了6个月后,房东想要卖房子把我赶了出来,在搬家之后,我需要通知联通公司帮我做移机服务。 如果纯粹从开发者的角度出发,写出来的代码可能看起来是这样的: public class Customer { private String address; public void setAddress(String address) { this.address = address; } public String getAddress() { return this.address; } } 中规中矩,一个简单的值对象。作为对比,通过与领域专家的交流之后,写出来的代码会是这样: public class Customer { private String address; public void movingHome(String address) { this.address = address; } } 通过引入业务场景中的概念movingHome,代码就变得有了业务含义,除了可读性变强之外,这样的代码也便于和领域专家进行交流和讨论。Eric在领域驱动设计(Domain Drvien Design)中将统一语言视为实施DDD的先决条件。 层次架构(三明治) All problems in computer science can be solved by another level of indirection, except of course for the problem of too many indirections....