前些年,我与几位同事为某 FinTech 公司的核心系统做现代化改造,客户要求我们开发出一个更现代化的系统接管全部功能,最终目标是使老旧系统完全退役。
没错,说不定你已经在其他地方听过这种故事了。最后的结果嘛,我们成功了一半:我们开发出了更加稳定的新系统,但未能完全使老系统退役。
尽管我们叫它“老旧系统”(Legacy),但它的岁数还没有我大。客户想要换掉它的主要原因是它的技术栈过于陈旧,无论是市场上还是公司内部,都难以找到能维护它的人,更不用说响应业务变化了。
在这个系统的壮年,一群才华横溢的工程师将他们的聪明才智转化成了各种业务逻辑和流程,层层堆叠在其中,分散存储在数千张数据表中,最终形成了这个核心系统。
我们称其为“龟仙人”:老练,强大,但行动迟缓。
前辈们并没有为“龟仙人”留下什么文档,因此我们只能从运行的系统中学习到底要做些什么。
回顾这段奇妙的经历,我想跟大家分享下我所看到的“好”与“不好”。他山之石可以攻玉,希望这些经历可以帮助到后来者。
这不是我们启动项目做的第一件事,却是早期至关重要的一环。Kent Beck在《极限编程》一书中提到,“软件开发本质上是一种设计”。在这个项目中,我更加深刻地体会到了这一点。
我们要做的,就是把正确的知识正确地固化到软件中,然后让它正确地运行。项目伊始,我们就组织了熟悉业务的工程师、产品经理和研发经理参加事件风暴会议,大家各抒己见拼出了新系统早期的知识,从而形成了能够带来实际价值的业务流。
图片来自: https://mrpicky.dev/design-level-event-storming-with-examples/
开始时我们确实对同义多名和同名多义感到头痛,而且对在公司内对某个概念赋予一个统一的称谓充满向往。我们幻想着一个没有歧义的世界是多么美好。
得益于对DDD了解的深入,我们对这种一刀切式的简单化有了抵抗力。鉴于各个领域的独特性,同义多名和同名多义不仅是合理的,而且是必要的。
在实践中,做好翻译或防腐层即可,以避免其他领域的知识侵入当前领域。
以术语 Policy 为例,在承保上下文它代表着保单,在风险上下文它又是规则的意思,如果要强行统一,又要以谁为准呢?
康威定律在这家公司依然表现亮眼,无论是核心系统还是其他产品外围系统,无一例外都遵循着这句话:设计系统的架构受制于产生这些设计的组织的沟通结构。
因此,在经过事件风暴理解了业务流程以后,为了让团队能专注于一类问题空间,客户决定将组织架构重组为以领域划分的模式,每个领域由一到两个小团队负责。
跨领域的团队之间互相约定交互方式,同时鼓励通过午餐会、咖啡时间等社交(Social)活动使不同领域团队之间有机会交流,但又不会太过打扰。
图片来自:https://www.infoq.cn/article/every-architect-should-study-conway-law
这是我最喜欢的决策之一,虽然来自错失恐惧症(FOMO),但经过团队成员和首席工程师反复论证,最后证明它确实是适合当前领域的。
事件驱动(以及溯源)意味着历史不可变,因此系统在某一刻的状态完全可以通过将它的各种变化事件叠加计算得出,这在复现问题上有着无可比拟的优势。
事件驱动的另一优势是能够解耦不同服务/模块,上下游服务不再需要互相确认已经收到变化,也不必立刻执行操作,这为削平请求高峰创造了机会。暴论一下,每个程序员都应该能熟练使用事件驱动/事件溯源的系统。如果你觉得不是,看看 git 系统,它就是事件溯源的。
与上面说的“一刀切”式的简单化不同,这是经过设计和考量的简单化,它为我们带来了测试的简单性和可审计性。当然,计算机行业缺少不存在银弹,事件驱动架构存在着消耗计算资源、Schema版本升级困难等弱点,叠加诸如事件延迟、幂等性、可重试等其他挑战,需要小心验证是否适合你的场景。
图片来自:https://aws.amazon.com/cn/what-is/eda/
在服务开发到某个阶段,不再需要加入新功能时,也许大家觉得它已经“足够好”了。
这时候作为一个leader,你是否会选择找几个年轻的(便宜)程序员来维护它,把其他人投入到新服务的开发中?这个选择不一定是错的,但要非常谨慎,以免这个“足够好”的服务中的知识就此散失。
在老旧项目改造中,这种“维护模式”导致的知识断层现象非常常见。
例如,某个服务的开发者全部从公司离职,接手的团队没有人能说清楚这个服务在干什么业务,更不用讲怎么往前演进了。
维护模式说的是如何留住某个服务的知识,本条则是如何留住团队/领域的知识。
大多数人不可能永远留在一家公司,但如何在人员发生变化的时候保证团队有足够的知识来交付、运维当前的系统呢?
尽管我们也用到了架构决策记录(ADR),但它存放在管理文件的Confluence里,距离实际影响的代码还是有距离,不好直接找到。
不过,随着检索增强生成技术(RAG)的发展,也许“AI + 文档”会是个好选择。
此外,将业务通过测试用例保存在代码中是我们的惯用做法。
然而,如果某个重要服务已经积累了数百个测试用例,如何管理这些测试让它们发挥知识载体的作用也是一大挑战。
我目前还没有太好的解决方案,希望大家可以一起探讨。
图片来自:https://www.ml6.eu/blogpost/leveraging-llms-on-your-domain-specific-knowledge-base
每个程序员都有着改变世界的梦想,但在这之前,我们得知道敲下的这行代码部署出去会对整个系统造成什么影响。
改造过程中出现了多次鲁莽的修改,每次都能让人手忙脚乱好一阵。
不理解影响范围,不清楚上下文的时候,也正是去理解和澄清业务与技术的时候。
在修改遗留系统前,最好将认知程度提升到繁杂(Complicated)甚至是清晰(Clear)的程度。
图片来自Wiki: https://en.wikipedia.org/wiki/Cynefin_framework#/media/File:Cynefin_framework_2022.jpg
最后想说的是,在一个复杂系统中,想要一劳永逸解决问题是不现实的,对团队施以过大的交付压力同样会挤压跨功能需求的生存空间,导致看起来没问题的软件在上线后表现得不符合预期。
对于稍有经验的程序员以及其他更资深的成员,工作中有着太多可以决策的事情。
它们可能是关于如何执行一次实验以及记录实验结果,可能是决定采用某种通信协议,也可能是选择使用单体或者微服务架构。
当运营当前系统、组织数字化转型、发展交付团队、跨部门协作等工作同时出现在面前时,如何保证重要的工作能够等到重视,如何在维护系统的同时发展更多的有价值业务能力,如何发掘公司中已有的知识,如何打造学习型团队留住领域知识等,这些都是令人头疼但又不得不面对的问题。
前事不忘后事之师,带着这些问题,我又一次在知识的海洋中寻找答案,《创新驱动设计:单体与微服务混合架构策略与实践》正是一本可以解答我的困惑的书。
本书认为,对于那些想要带来改变的IT行业从业者而言,都应该做好心理和技术准备,逐步改造自己、团队和环境,用实验验证假设的合理性,一步步靠近最终目标。
本书的前两个部分介绍了推进改变所需的工具和概念,第三部分则探讨了作者推荐的有灵活性的架构,第四部分即提供了从单体到微服务架构的一些指导,又提醒读者不要沉迷于微服务的光环,应当根据所在环境选择合理的架构模式。
本书适合程序员、架构师、项目经理以及其他资深领导者,让你可以有效组织团队与协作,能够基于需求和目标做出平衡的架构决策,从而聚焦于价值和创新,交付更具可演进性的系统,并避免代价高昂的错误。
↑限时五折优惠↑
尊敬的博文视点用户您好: 欢迎您访问本站,您在本站点访问过程中遇到任何问题,均可以在本页留言,我们会根据您的意见和建议,对网站进行不断的优化和改进,给您带来更好的访问体验! 同时,您被采纳的意见和建议,管理员也会赠送您相应的积分...
时隔一周,让大家时刻挂念的《Unity3D实战核心技术详解》终于开放预售啦! 这本书不仅满足了很多年轻人的学习欲望,并且与实际开发相结合,能够解决工作中真实遇到的问题。预售期间优惠多多,实在不容错过! Unity 3D实战核心技术详解 ...
如题 ...
读者评论