在O’Reilly软件架构大会的开幕致辞中,Raffi Krikorian为那些承担了重写某个系统重任的技术领导与架构师分析了相关的策略与战术。凭借着他在担任Twitter工程团队的副主裁期间所学到的经验,Krikorian对于重新设计架构这一流程的管理提出了12点计划,包括定义“完成”、检测现有系统,以及维持代码的质量。
Krikorian目前是Uber高级技术中心的工程领导,之前也在Twitter工程团队担任副主裁,他在致辞中首先表示,重写、或对某个系统的架构进行重组背后的原因与流程往往会因为一系列问题的出现而备受折磨:人们往往会低估复杂性、人们永远不会做到完全理解客户、系统的需求不断地在改变、而且整个流程所需的时间通常远远超出人们的预期。
Krikorian认为,重写架构的原因通常是由于现有的应用程序无法再满足客户的需求、无法实现规模的扩大、或是无法实现类似产品所具有的特性。在演讲中列举了一系列的系统重写案例学习、着重指出了一些常见的陷阱,并为承担一次成功的系统重写架构任务提供了一些策略。一个核心主题贯穿了整个演讲,那就是尽量避免完整的重写,但如果已经选择了走这条路,那么应当事先对以下12点内容进行思考,并在系统重写架构过程中不断调整。
- 坚定方向(为了业务的提高)
- 定义“完成”
- 渐进式前进
- 找到起跑线
- 不要忽略数据
- 更好地管理技术债务
- 远离那些虚荣的东西(例如使用“热门”的技术栈)
- 做好准备面对压力
- 了解业务
- 做好面对政治因素的准备
- 对于代码质量有所掌握
- 让团队做好准备
Krikorian随后依次对这些要点进行了探讨,他首先表示,在应用程序的重写过程中,业务产品经理会表现得非常焦虑,但技术领导必须对这一点加以控制。业务与技术方面的干系人必须在共同的努力下对什么是“完成”进行定义,这样才能够实现一次成功的架构重写。可以在定义需求时使用一些现有的需求规格分析技术,但不应将现有的代码作为整个新系统的规格说明。
Krikorian同时也表示,要保持新系统与现有系统的功能100%的等价是非常困难的。当现有的系统在生产环境上运行的过程中,有可能会加入新的功能,以应对某些问题或边界情况,而这些修改也许没有被很好地记录在文档中。
你真的清楚这套系统在做些什么吗?
“让新的系统能够实现现有系统的能力”这一点比你想象中要困难。
大多数程序员甚至都不知道应当问些什么问题,而如果他们并非系统最初的设计者,那他们就更加摸不着头脑了。
实现特性是一件困难的事,因此更应当采用渐进的方式进行重写。最合适的方式是采取一种敏捷式的、集成的、并且基于持续交付的流程。在每次迭代结束之后,都应当能够做到随时准备发布新的系统,并且应该定期地为业务干系人展示经过重写的功能。Krikorian同时也对在重写中混入新特性的做法进行了警告:
混入新的特性是相当诱人的行为,尤其是新特性的开发在旧系统中停止的前提下。
但这种做法可能会要了你的命。
在常规的开发中,你也会尽量避免这一点,那么为什么现在又一次犯错呢?
与应用程序的代码相比,某个软件系统底层的数据的变化往往显得十分缓慢。但Krikorian警告说,在重写过程中使用虚构的、或是人为的数据会造成安全性方面的错觉。必须尽快使用真实数据进行测试,有时可以使用类似于摸黑启动(dark launching)或模拟流量(traffic shadowing)之类的技术。必须有计划地决定如何在现在系统与新的应用程序中保持数据的一致性。对现有系统必须进行全面检测(包括性能与数据处理两方面),然后根据这部分检测结果在系统重写中进行决策。
在任何一次系统重写的过程中,对技术债务的管理都是一个核心部分,如果对这部分视而不渐,会不断增加软件的熵。造成技术债务的原因通常是来自于业务的压力、缺乏流程、缺乏一种定义良好的架构、以及缺乏工程上的导师制度。
Krikorian表示,组织应该培养一种保证设计质量的文化。应当鼓励重构、同时也应当鼓励持续设计以及其它有关代码质量的实践。在开发时间中应当专门抽出一部分以解决技术债务。如果没有合适的照料,那么真实世界中的代码会变得越来越复杂难懂。由于开发者通常会将更多的时间放在阅读而不是编写代码上,因此应当通过代码审查的方式保证代码结构的“可读性”。
Krikorian同时也建议,在重写过程中应当尽量避免“虚荣的东西”,例如选择某种“热门”的新语言或技术栈。虽然这种选择很有诱惑,能够在短期内提高开发团队的动力,或将其用做一种招聘工具,但技术领导应当做出对团队的长期利益有益的选择。
在重写的过程中,很有可能会招致客户的强烈不满。外部的客户无法获得新的特性,而内部的客户也因为重写而不得不停下工作。
在整个工程中可能会出现政治性的斗争,并且由于最后期限几乎总是被推迟,因此受挫的情绪可能会在在整个组织中蔓延开。
Krikorian警告说,在开始重写之前“没有人会考虑到这些问题”。这些斗争对重写可能会产生破坏性,而技术领导必须对可能出现的决心动摇的情况进行管理。
在重写过程中,将一个开发团队划分为两个团队的做法并不罕见,由其中一个团队负责维护旧的系统,另一个团队负责重写架构的工作。虽然这能够成为一种有效的做法,但技术领导需要做好准备,以应对可能出现在这两个团队之间的压力。修复bug与救火是很有压力的工作,而某一个团队必须要承担这一任务,而另一个团队则可以置之不理。Krikorian建议,技术领导必须在负责维护现有系统的团队中维持或建立一种支持的角色。在团队之间应当定期进行项目进度方面的沟通,并且保证重写过程中的所有工作保持透明度。
在重写开始之前,技术领导要指出所有的业务干系人,这一点十分重要。同时也要指出在重写任务背后的非技术动力并加以管理,例如增加特性交付的速度,或减少硬件方面的成本。Krikorian表示,整个重写的流程以及相应的流程报告并须由数据驱动,其中可以包含成本节约、特性交付速度、可靠性、性能以及稳定性方面的指标。必须避免将此当作一件趣事的想法,而是必须展示这些实验的成果。
Krikorian在演讲的最后结尾时表示,承担了系统重写任务的技术领导或架构师经常会处于一个危险的位置上。在重写中使用了大量的工程资源,而同时又不能在业务上交付任何新特性。在保持系统运行时进行重写的工作必须尽量保持在很小的范围内,并且必须使用例如持续集成和持续交付这样的技术定期地进行整合。同时对重写的系统中的代码质量并须加以密切关注。
按照康威定律,理想的架构与团队的结构也必须一致,正如Krikorian所说:
架构影响了团队的结构,后者又反过来影响了前者……
在slideshare上可以找到Raffi Krikorian的这场“在运行过程中进行架构重写”演讲的幻灯片。O’Reilly软件架构大会于2015年三月在波士顿举办,在会议的网站上可以找到更多的细节,其中包含了这些演讲录像的链接。
查看英文原文:Raffi Krikorian Provides Guidance for “Re-architecting on the Fly”