2000行代码
早在写《架构腐化之谜》的时候,我就意识到,造成架构腐化的根本原因是系统复杂度变大的必然趋势以及人类遗忘的天性。延缓项目腐化最好的方法,是根本不给腐化的机会。生活中,自然通风、阳光透亮、家具摆放合理的、不留死角的房间出现虫子的可能性很低;代码也一样,一份简单、符合直觉的代码,放在复杂度完全可控的代码库中,能够极大的降低学习的门槛以及避免腐化的可能。
包括自己在内,很多人当然以为这只是美好的想法。绝大多数开发者仅仅能尝到项目早期的甜头,在后期则进入了愈发沉重的深渊。对于文中所说的似乎只是一个遥不可及的想法。为了证明这个是否真的可行,从去年10月开始,我在自己的产品中进行了一个尝试:在保持功能正常增长的前提下,项目总体功能代码不超过2000行。
现在是什么情况呢?从去年10月到现在,git统计数据如下
414 files changed, 42824 insertions(+), 698 deletions(-)
430次总共提交
Code LOC: 1568 Test LOC: 799 Code to Test Ratio: 1:0.5
功能代码总共不超过1600行代码(当然未包含大量的CoffeeScript以及HTML/Sass代码),完成了大部分的核心业务逻辑。未来可见的功能也应该能够在400多行的空间里完成。系统中也存在不少能够提取为独立Gem的地方,可以继续进行隔离简化。
应该说得益于Ruby简洁的语法,以及在rubygems社区提供的各种高质量的gem,让以前不可想象的麻烦变得几行代码就能搞定。
我们得到了什么好处?今天新加入了一名程序员,花了点时间介绍产品背景之后,在不到2个小时的时间里,就完成了一个典型的功能。并且还顺带修正了一些代码上的Bug。
Rails固然是特例。但推广到其他的语言,只要遵循以下原则,应该是毫无问题的:
- Don’t Repeat Yourself - 绝对不要重新发明轮子。github上fork数量多的项目基本上已经相当成熟了。即便有问题,fork, fix, pull request的响应时间比以往任何一种方式都要迅速,还能回馈社区。
- 遵循约定,遵循约定。在某个时候总忍不住自己写了类似于get ‘cities/edit’在routes.rb中,但随着类似的代码越加越多,最终索性就变成了resources :cities. Rails是经过许多工程实践的框架,其中的最佳实践很多时候是经过验证的。对于其他技术框架也应该一样。有时候发现了异常情况,不要为这种异常情况特殊处理,约定化也许是更好的方案。
- 隔离,隔离。凡是与核心业务无关的功能代码,在找不到开源替代的时候,想办法将其通用化。比如我们用到了解析openflights的机场数据。这部分与核心业务毫无关系,将其隔离为Gem,再引用,能够减少无关代码干扰,形成知识分界,对于专注了解系统有莫大好处。
- 警惕未经使用的功能、代码、注释、甚至数据库字段。保持代码库总在最精简的状态下。
这个产品已经上线。在可见的未来,2000行的界限还是够用的。等到超过的那一天,我再写写看看。也许那一天可能永远都不会到来。