Alex Hudson 在他的博客上表达了“软件架构正在走下坡路”的看法,以 CQRS、事件溯源和本地存储为例,说明软件架构存在的问题以及应该如何正视及解决这些问题。以下内容翻译自作者博客,已获得翻译授权,查看原文 Software architecture is failing 。
我怀疑软件架构在过去是否真的有过巅峰式的成功。Web 三层架构成为很多人进入软件开发领域的起点,“12 Factor App”原则鼓励开发人员采用能够简化开发和扩展的最佳实践。然而,在过去几年,我发现那些提倡架构的开发者们花了很大成本把高度复杂的系统强行塞到初创的项目当中。在我看来,这样只会让事情变得更糟。
首先,我想在这篇文章里谈论一些特定的模式和技术。我并不反对这些模式和技术,我不觉得它们有什么问题,我只是觉得,它们当中有一些在应用方面存在一定的局限。我相信银弹是不存在的,而且我认为所谓好的架构也仅限在它所要解决问题的领域,在进行架构设计时需要更多地考虑适应性。
过去一年,我与多个技术团队及业务人员有过多次沟通,我总是听到他们提到类似的问题。比如,“我们的交付速度不够快”、“我们的系统太复杂,难以维护”、“我们去年交付的系统已经过时了,但要替换它很困难”。
我看到很多技术团队在做出决策时并不知道如何将组织面临的业务问题与技术战略结合在一起。他们缺乏技术策略,通常会武断地做出决定,比如“我们要百分之百地使用微服务”,但他们却无法说清楚这一决定与实际业务之间有什么直接的联系。
错误行为一览
CQRS。最近我关注 CQRS 比较多,因为它几乎无处不在。有一天,我在 Twitter 上看到一篇关于“如何使用 CQRS 来开发 MVP”的文章。对于大部分不了解 CQRS 的人来说,他们会认为 CQRS 是一种 RPC 模式,可以用在复杂多变的数据存储上,而且大部分入门教程都会说 CQRS“适合用在大型复杂的系统上”。
很多文章说 CQRS 是解决微服务事务问题的良药(但实际上并不是),但其实真正的原因是推崇 CQRS 的大部分开发者不喜欢 ORM。
还有一种情况更加糟糕——代码量大肆增加、系统的发布举步维艰,但却不能从中得到明显的好处。
我看到有些系统正在使用 CQRS,但实际上 CRUD 完全可以满足他们的要求。于是我问他们为什么,他们说是因为“责任”或“领域问题”,但从来没有人说其实他们是基于业务方面的原因而做出这样的选择。
事件溯源。事件溯源与 CQRS 是有关联的,因为它们经常被结合在一起使用。事件溯源的核心原理是说,你有一系列不可变的事件日志,使用这些日志可以创建出具有最终一致性的应用视图,而不是在 RDBS 里保存状态。
这是一种典型的“不考虑业务需求”的技术选型。我见过两个不同的初创公司,他们以“不可变日志”的形式保存客户数据。如果你问他们“你打算怎样做到 GDPR 的要求并将数据移除掉”,他们通常会说,“我们还没想过这个问题”。我告诉他们,如果他们不处理好这些数据就会违规,他们就面露难色。
本地存储。有一个开发团队认为前端都应该做成单页应用,能够处理离线内容,这听起来似乎很有道理。但问题是,他们处理的很多数据是敏感数据,如果这么做,那些敏感的内容就会散播到各种各样的浏览器缓存里。
通常很少看到人们重用已有的技术,反而是出于各种原因追求“热门”的东西。看到那么多开发人员正在开发底层的东西,着实让人吃惊。
我们做错了什么?
我把这一切归咎到技术领导者头上,包括我在内。那些没有在大公司(比如 Facebook、Google、Amazon)工作的技术人员,他们并没有深入意识到在小型企业里应该怎样开发软件系统。他们没有深入讨论怎样做才算成功、怎样做才是正确的以及如何总结出有用的模式。
很多技术文章大讲特讲如何构建具有伸缩性、高性能的大规模系统。了解 Netflix 是如何面临挑战并解决问题绝对是件有趣的事情,了解 Google 在做出各种技术决策时是如何考虑问题对我们来说也大有裨益。但他们的大部分问题在其他公司并不会出现,所以他们的解决方案也未必适合其他公司。
在当今世界,我们很容易理解为什么有些团队痴迷于这些公司所说的解决方案。他们想快速发展,交付更健壮的服务,不想落后。
我记得有一次跟一个工程师聊起他们的一个核心服务。他说,“它已经彻底落伍了,没有人维护它。只要不遇到极端情况,它都能正常运行。要把它替换掉真的是太困难了,它表现得还算不错,业务部门不想花时间去替换掉能够正常运行的系统”。这就是问题所在,他们把“成功”的定义(它表现得不错,性能也不错,我们没必要把它替换掉)与“可用”的定义混为一谈。
一项好的技术要能够推动业务的发展,特别是对于技术公司来说。技术的核心部分是价值的来源,所以一定不能掉以轻心。很多软件和服务就像是脚手架,我们可以利用它们来完成我们的工作。
我们应该做些什么?
我们经常无法决定是该开发软件还是该购买软件。开发软件应该是最后的选择,“我们之所以要自己开发,是因为我们找不到我们需要的软件”。我想从更多的技术领导者那里看到他们是如何不通过开发软件来解决问题的。
我想我们对未来担忧得有点过头了。虽然我们嘴上说“你根本不需要它”,但心里可不这么认为。我们关注技术债务,但同时又抱怨敏捷“不管用”。我希望看到更多的项目能够把架构决策延后到流程的后面阶段。
我希望看到更多快速的交付。小型软件看起来未必有趣,但只要能体现业务价值,那它就是英雄,而创建软件的开发者也是真正的明星。如果我们能及早出发,就能尽早到达目的地。我们需要重用已有的成果,要知道“混搭”并不是什么下三滥的手段。
我也特别希望能够看到更多的开发者能够在有约束的环境下工作。我经常听到有人说,“我们使用了某某产品或某某框架,它有一些无法解决的问题,所以我们自己推出了替代品”。或许这样做是对的,但这并非唯一的解决办法,要知道,条条大路通罗马。
你所碰到的问题为你的发展奠定了基础,开发人员需要经历一些愚蠢的事情才能成长。我希望看到人们能够看到事物的潜力,我们总是低估了现有系统的能力,同时又高估了自建软件的能力。我想,是时候让我们接地气地关注中型企业的软件架构了。
其他人的评论
问题并非出在这些模式上,与架构本身也没有很大关系。架构指的是高层次的管理、一系列非功能性需求以及教导和帮助他人的能力。CQRS 和事件溯源并不是架构。
从另一方面来看,开发者和架构师的盲目崇拜才是问题所在。追求新技术的心态没有止境,技术人员往简历上贴金的做法横行于世。不过,正如 Albero Brandolini 所说的——如果开发人员没有了业务方面的挑战,他们就会通过解决技术挑战来获得愉悦感。
开发者在一个领域专注了太长时间,开始从别处获得“需求”,几乎无暇顾及业务问题。最后,他们只能与技术为伴——新的框架、新的工具或者新的模式。
问题不在于架构,而在于业务与开发者之间如何看待对方。我希望能够在各种开发者大会上呼吁这一观点,但他们似乎更热衷于推销各种“时髦”技术。
说到事件溯源和 CQRS,我认为关于“你不是 Google”(请看之前的一篇热门文章“一语点醒技术人:你不是 Google”)的争论有点偷换概念。即使你不是 Google,也完全可以使用这些模式。如果你对领域知识知之甚少,反而能够从使用事件模式中获得好处,因为通过观察过去发生的事件有助于你了解领域知识的来龙去脉。而在所谓的“CRUD 足矣”的系统里,你只能看到当前的状态,最终很可能会违反单一职责原则(SRP),并在数据库层面出现大量的重复性事务,这是一条不归路(应该说已经变成了大泥球)。当人们说“让我们走回老路吧”,我就会感到很吃惊,就好像他们不知道他们过去构建的系统已经变成大泥球一样。如果认为这是因为开发者发生了变化,那就大错特错了。人是一样的人,初衷都是好的,但对业务和系统的发展方向知之甚少,仅此而已。那么凭什么认为现在就会比过去更好呢?
Niklas Lochschmidt
我已经使用 CQRS 和事件溯源好几年时间了。我非常赞同作者的一些观点,软件不在于多,而在于精,自己开发框架也不应该成为首选的方案。
不过我并不赞成“CQRS 是一种 RPC 模式,可以用在复杂多变的数据存储”这一说法。Martin Fowler 在他的一篇文章中写道:“CQRS 的核心理念是说,你可以使用不同于读取信息的模型来更新信息”。不过他也随之给出了警告:“要知道,CQRS 会增加大部分系统的复杂性”。RPC 可以与 CQRS 一起用,但不是必需的。系统也可以一边读取文件,一边对 GraphQL 查询做出响应。它的本质是为命令(command)和查询(query)构建不同的模型。如果你不需要不同的模型,那么 CQRS 确实会带来不必要的复杂性,但请不要混淆了一些概念(有些人认为 CQRS 是一个框架,但其实它是一种架构模式)。
我们使用事件溯源的目的不太一样。我们需要核心系统全部的审计日志,并从日志事件流中分析出一些特定的度量指标。事实上,我们经常使用事件溯源,并基于此成功进行过几次系统重构,而纯存粹的状态驱动的系统里难以做到这点。捕捉到用户的意图和知道用户行为的结果是两码事。也就是说,事件溯源对你的核心领域来说才是有意义的。另外,如果在一开始没有考虑到 GDPR(通用数据保护条例),后续就会有麻烦。在你有了数据库备份或 WAL(预写式日志)归档之后,被要求清除敏感数据也是个问题,不是吗?
Alex
我试着以一种简单明了的方式为非技术人员解释 CQRS:在我看来,该模式里的命令部分更为重要,所以它才会与 RPC 相提并论。它与 REST 很不一样,REST 操作资源,而不是触发命令。我知道其他的模式也存在问题,而作者以 CQRS 为例,可能是因为很多人最近都在尝试使用 CQRS(可惜都以失败告终)。
我想另找时间分享我的一些有关 CQRS 和事件溯源的经验,我觉得它们应该拿出来单独讲,而且很难讲得好。这就好比讨论函数编程语言和过程编程语言:LISP 风格的语言有很多好处,舒适的编程环境会带来极高的效率。但并不是每个人都会这么觉得——我想知道为什么,毕竟这不是技术本身的问题。
我很赞同作者关于事件溯源的见解。我过去曾将它用在医疗记录上:放射医疗报告就是事件溯源的一个很直观的例子,虽然最开始它还处在理论阶段。对基于时间的处理来说,它很显然就是一个很好的方案。不过,我想很多开发者对最终一致性问题仍然心存疑惑。
关于 GDPR 的问题也值得另开话题。数据备份和 WAL 归档确实是个问题,但它并非一般性的问题,而且非常复杂。在系统里保留 PII(个人识别信息)数据也是我比较关心的一个问题,尽管在软件的角度加入了使用期限,但问题仍然存在。
感谢雨多田光对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ , @丁晓昀),微信(微信号: InfoQChina )关注我们。
评论