“ 过去几个月,我总是在问自己类似的问题:为什么我们总在苛求完美的代码?因为内部项目需要,重新捡起编码任务之后,我发觉我们组内(也可能是大多数软件开发世界中的大多数人)花费了大量时间在规整编码规范、模式和测试代码,但这真的有必要么?”
作为软件开发机构,我们需要持续地进行预算、时间和特性的平衡。这种平衡的结果是,许多特性需要修改,或者干脆不做了,可能原因是耗时过长或者成本太高。
从另一个方面来说,工程师通常感到项目特别赶,出来的代码通常都不完美。我相信对于任何软件研发机构来说,这个现状都是很明显的。
上个月,我跟我们的一位客户(CEO)谈话,他们的 CTO 和主程要求我们帮助他们重构一部分代码。在不作出重大修改的前提下添加新功能几乎不可能,而且没有人对整体代码实现很了解。
尽管目前运行一切良好,这部分项目初始代码从技术角度来看就是一团乱。这位客户(CEO)问我为什么需要重构,从他的角度来看,代码目前没有任何问题,只是需要发布新功能可以再快一点。
我想这种情况下,双方都很有道理。开发者们希望用最新的技术写出完美的代码,写完善的文档,每个人都可以了解到具体实现,从而可以方便测试和后续的维护升级。而另一方面,其它人却只是希望快速经济地完成功能,从而他们可以推出新功能或者推销给更多客户。
那我们该怎么平衡这两种诉求呢?
忘掉未来,为现在而编码
大多数产品公司经历了几个阶段。每个阶段都需要对“完美”的意思有不同的看法。我们可以长时间地讨论哪些阶段是存在的,但为了本文,我将仅仅(just)区分为:概念验证代码、 MVP 代码和长期维护代码。并分别举例说明。
在为产品制定新的想法时,花费任何时间编写可扩展的、全面测试的并符合最新编码标准的代码是没有意义的。目标是提供一个概念原型,例如连接几个 API 或尝试一个新的接口想法。当实现目标之后,任何人都不太可能再次深入这个代码。
大多数人在构建最小可行的产品时,都高估了对优质代码的需求。每个创业公司的最重要的事情是发布在一个漂亮的、功能完善的产品。该产品的后台工作原理并不重要。直到你的 MVP 真正得到关注,你可以着手处理劣质代码,甚至手工做些事情来证明你拥有一个适合的产品/市场。
只有在你确定使用它,并且客户开始流入时,你应该开始关心代码,如果没到这一步,你其实仅仅(just)写了一次性的代码而已。
一旦这些辛苦积攒的客户开始流入,你有可能产生一些收入或吸引外部的融资。 现在是开始思考整洁、长期维护的代码的正确时机。这是在介绍中的示例上我们的客户所处的场景。
鉴于你受众有可能增长,你需要开始考虑性能、稳定性和可用性。 你的工程团队也将扩大规模。这将迫使你实施编码标准、文档标准和一系列其他流程和实践。你开始需要完美的代码了。
可以看到,在每个阶段示例中我们的代码目标都有所不同,对于“完美”的定义,自然也有所不同。
并不存在完美的代码
我们都知道,开发软件涉及到多个不同的阶段。所以其实很难断定,到底有什么所谓完美的代码,完全适用于所有的开发阶段。
客户的需求,五花八门。可写代码时用的库其实却更甚。有些库是我们自己写的,也有一些是第三方的。有时候看一个项目的代码,还确实可能会发现它混杂了不同人的代码;比如说,自己的团队先写点代码给项目开个头,之后交给客户的团队写一会。最后呢,却又由我们自己来收尾。
由此可见,每个项目的代码风格,以及用到的技术、实现方法等都可以很不一样。你的项目,或许在发布时堪称完美。但是,经过上面所说的这种把项目丢来丢去的过程之后,我猜最后肯定经常会有人嫌其他团队写的代码有问题,那这种项目显然就不完美了啊。
现实就是如此,想达成某件事,不可能会有什么完美的方法。至于编程,虽然我这么说可能会感觉有点奇怪,但它压根就不是一门严谨的学科。你想编程实现某个需求,往往会有很多方法。到最后你或许会发现,这些方法,其实都行得通。
处理不完美的代码
不完美并不等于劣质。去网上搜一下 Pareto principle 和 Sufficient Design 就知道为啥了。
让一个人去写项目,如果这人发现项目里用了一堆过时了的代码,或者是用了 MVP 架构,又或者是项目写了很久很久,那这人肯定很想把整个项目给重写了,这样才感觉整个项目尽在掌握,如鱼得水,而不是看着就头疼。
不过呢,重写大项目一直都不是啥好事,整天流于形式写框架,却白白浪费了写业务逻辑的时间,这很没必要的。有些事情可以不用管它,别太纠结。但是呢,如果你重写的代码符合我下面说的这些标准,那你重写也不是啥坏事的说:(节录自这篇文章)
1、重写的代码真能实现需求么?
2、代码真的正确无误,而且效率还不错么?
3、在遇到并处理错误时可以做到不崩溃,或者安全地结束执行么?
4、试起来容易不?
5、如果要改动代码,能尽量又简单又安全不?
这最后一条标准大概是最难做到的,毕竟要做到模块分离和抽象化,还要写测试代码来确保符合预期效果;而且代码若还有改动,只要修改相应的一部分测试代码就行,这样才可以更加轻松地调试和改动代码。
从零开始写项目时,一定要花点心思。无论是写新项目,还是重写旧项目,都要规范地写代码。比如说,代码风格要清爽、要有可读性、要遵从一定的代码规范。但是但是,一定要小心,不要过早优化你写的代码。
写的时候只管想下一个要实现的需求是什么,而不是边写边纠结怎么缓存资源、怎么弄个复杂的数据结构来储存数据之类的事情,还有别动不动就担心执行效率。你代码越简单,其他那些要接手你代码的人就越感谢你。
刚开始写项目时,这些很重要;以后给客户写项目时也一样重要,毕竟说不定哪天客户就要你把项目交给他们来继续写呢。
把这些带入实践中
每个星期我都会和有好想法的人交谈,但他们希望用很小的预算来实现他们的想法。当他们问我实现他们的想法需要花费多少时,我的回答是在 10k 至几十亿之间,所以基本上是把这个问题抛回给对方,问他们希望花费多少。
根据他们的回答,我会试图清楚地向他们解释他们可以期待什么:概念证明、MVP(Minimum Viable Product – 最简化可实行产品)或拥有长期可用代码的产品。
作为程序员,我们应该尝试不那么完美主义,并且牢记保持这一目标。提供价值比我们的代码整洁更重要。只有当你为了长期目标,去追求完美才有意义。
作为首席执行官(CEO),你应该问自己,预算是否适合你的产品所在阶段,并且要牢记预算所提供的限制和机会。有时需要重构。
我相信,只要我们在内部或为客户开始一个新项目时,我们都需要询问代码的完美程度。所以我们可以根据短期和长期的期望来交付产品。
写在最后
人们取笑我对 just 这个词的使用。因为我经常会说这句话 “just do it like this” (照这样做就可以了)。然后人们会向我解释说,这没有那么简单,因为我没有考虑到诸多的边缘情况。
也许我是有意这样做,只想着 happy path(愉快路径),而忽略了任何可能出错的东西。在本文的上下文中,我决定强调 just 这个词,因为它与文章中讨论的问题高度相关。
有时你只需要为愉快路径进行编码。