构建自己的软件大厦 #
在我工作将近10年的那段时间,我开始总结自己先前所参加过的所有软件项目。虽然我一直工作于一家对代码质量很是讲究的软件公司,然而遗憾的是在我所参加过的项目中,没有一个是我满意的。我开始思索这里面的原因,总结下来至少有以下几点:
- 软件项目通常都是团队项目,其中每个开发者的思路可能是不同的,导致后进者无法领会到前人的思路,在沟通不畅的情况下,软件架构可能很快腐化;
- 多数软件项目受限于交付进度,很多时候为了按时上线不得不做出很多技术上的妥协,烂代码由此产生,日积月累,由量变到质变,以至于后来变成了一座无人敢改的“屎山”;
- 项目中的成员经验不同,编程能力良莠不齐,项目管理者不可能让新人们学够了才开始贡献代码,于是不同水平的代码揉杂在一起;
- 软件的需求千变万化,后进需求有可能导致软件架构的整体重构,但是这种整体重构往往是管理者们无法认可的,于是只在表面上修修补补,最终代码变成了“四不像”。
在一个逐利的商业化世界里,以上原因似乎都无可厚非,但是就个人而言,这样的软件完全不是我想要的。我希望绕开那些现实的桎梏,像作家写书一样,开发出一套能让自己心仪的软件作品,构建出属于自己的软件大厦。于是,3年之后,我开发出了码如云(https://www.mryqr.com/),一个基于二维码的一物一码管理平台。
由于没有了前文提到的众多使软件变烂的因素的影响,我可以完全根据自己的计划决定什么时候做什么事情,特别是需要对既有代码进行修改的时候。算法实现不满意了,改;模型设计不满意了,改;有新需求需要添加,改。比如,在项目原本都快上线的最后2个月,我发现代码中的分组(Group)模型的设计过于简单——当时只允许创建单层分组,无法满足实际的业务场景。于是,我暂停了项目上线的筹备,花时间将分组模型从单层改为多层。由于分组概念贯穿于整个码如云的业务模型中,因此此次重构的影响范围非常大,但是由于项目代码一直保持着比较好的可扩展性,整个改造过程仅花了不到2周时间就完成了,并且全部是业余时间完成(事实上整个码如云的开发过程都是在业余时间完成的)。又比如,前端CSS编写方式一开始使用的是Vue.js的“Scoped CSS”方式,在项目都开始了将近1年左右的时候,我觉得这种方式不爽了,于是停下了所有的工作,又花时间将“Scoped CSS”改为了“CSS Module”的方式。
码如云全程采用了领域驱动设计,整洁架构和事件驱动架构的架构思想完成开发。
领域驱动设计(Domain Driven Design,DDD)的概念最早诞生于2004年左右,诞生之后并未大量普及,近年来随着微服务的兴起而重新进入人们的视野,发展到现在(2023年)依然炙手可热。在如今这场对DDD的追捧中,有肯定,有批评,有务实,有浮夸,一些针锋相对的争论甚至骂战依旧在各个微信群中不断上演。我在2013年便翻译了《实现领域驱动设计》一书,那时微服务的概念还没出来,DDD也基本上被束之高阁于少数软件架构师的范围内。当时,我在国外的某个论坛上看到这本书,然后找到了网上的免费试读章节,读完真是有种相见恨晚的感觉。下来我立即将该书推荐给了之前搞过DDD的同事张逸(后来《解构领域驱动设计》的作者),他居然花了大几百元从国外邮购了本书的英文原版,后来也是在他引荐下我得以与出版社合作翻译该书。
如今,行业里有种声音将DDD称为“玄学”,即把DDD当做是一门虚无缥缈不知所云的学问。事实上,DDD本身不是“玄学”,而是被不少人解读成了“玄学”,在他们心中,DDD作为一种高高在上的”哲学思想”而存在着,你要是将其与具体的编程语言或者技术框架稍微沾点边呢,他们都说你太低级,不配谈论DDD。作为典型的务实派,我是反对这种做法的。在我看来软件是很具体很实在的东西,与之相关的理论或者工具也应该具有同样的属性,DDD也不例外,搞DDD的终点应该是可以工作的软件代码,而不是天花乱坠的概念浮夸。我自认是能够清楚地认识DDD价值的人,在码如云的开发过程中,我成功地将DDD落地,我也希望向软件同行们证明:DDD能落地,DDD不玄乎,DDD很具体,DDD与编程强相关。为此,我也撰写了一系列DDD落地文章供同行们参考。
整洁架构(Clean Architecture)是我近年来一直推崇并实践的软件思想。在我看来,整洁架构与DDD在很多方面都有共通之处,比如都强调对系统中不同组件之间的解耦,以及各组件之间边界的清晰性,在DDD中这被称为”技术复杂度和业务复杂度的分离“。在码如云代码中,虽然我并没有按照《架构整洁之道》书中所写那样追求完全的整洁架构目标,但是在结合了项目实际的情况后,我尽可能地实现了整洁架构,比如在核心的领域模型中,我做到了仅仅依赖于Spring框架的4个注解,除此之外不再对任何框架有任何依赖。此外,事件驱动架构(Event Driven Architecture,EDA)也是我特别关注的软件架构,其特别适合于系统组件之间的解耦以及关注点的分离。通常来说,软件系统有浅系统和深系统之分。浅系统表示对业务用例的处理流程比较短;而深系统则表示对一个业务操作的处理可能导致一连串的后续动作,从而使得业务链条变长。对于深系统而言,如果将业务闭环中的所有操作都放在同一个业务用例中处理,那么系统中将出现大量的紧耦合,此时便可使用事件驱动架构将各个业务操作解耦开来。
无论是DDD,整洁架构,还是事件驱动架构,它们都只是工具而已,其目的都只有一个:做好软件。
曾经有人说,Github上多数的项目都死于前100次提交。我比较幸运,能从头到尾将这件事做成,前后1万多次提交,总共20多万行代码。我也还清楚地记得,在将码如云第一次搬上线的那个星期六的下午,没有咖啡,没有小酒,我只是长长的舒了一口气,暗暗为自己几年前许下的诺言做了个了结,然后像往常一样带女儿出去散步了。