title: 好代码
categories: [software-engineering]
什么才是好的代码?
每个写程序的人都会有这样的思考.
而其中很多人, 可能都会对 "优雅" 有执念.
Dan Abramov 今年分享了一篇文章, Goodbye, Clean Code.
里面提到了几点:
- 重构并不总是好的.
- 在重构或重写代码时一定要与团队充分沟通.
- 在需求不稳定时, 重构会造成额外的负担. (尤为赞同)
- 不要对代码层面的抽象化与复用太过执着.
- 每位写程序的人可能都会经历这个阶段, 别怕.
这里一方面提到了团队的重要性, 加强沟通, 提升信任, 另一方面主要说的就是,
什么是干净的代码? 我们再延伸一下, 什么是好代码?
在我初学编程的时候, 我在思考如何写出优良的代码.
在我初学软件工程的时候, 我总会听到大家的提醒: 不要提前优化.
好像有一些矛盾, 工程在阻止我写出好代码吗? 让我们把 "团队" 也加入其中, 一起想想.
关于如何定义好代码, 如何让团队写出好代码, 是有许多点需要去平衡的:
- 功能完整性
- 团队能力
- 风格一致性
- 开发速度
- 代码执行效率
- 代码细节
- 代码复用
- 程序架构
这些点并不能单独拿来说, 其中一些点是相互制约的, 另一些点是相互促进的.
- 功能完整性是一切的前提.
- 但功能也分基础功能与扩展功能, 基础功能必做, 扩展功能则需要考虑开发成本可延后.
- 团队能力影响剩下的许多点. 如果团队能力弱, 则可以适当放宽风格一致性, 并且不要
使用过于复杂的程序架构.
- 风格一致性看上去没什么必要, 但对代码的观感与可读性, 是有很大提升的. 可能会
间接影响开发速度. 一般我们都会使用自动化的 format 工具去做.
- 开发速度与代码执行效率可以说在一定程度上是互斥的, 比如 Ruby 开发速度快, C
代码执行效率高. 一般来说都倾向于开发速度, 但没有绝对的, 如果花 10 分的时间可以
提升 30 分的执行效率, 这时间还是值得的.
- 代码执行效率可以很高, 但是有一个接受度阈值的, 一旦过了这个阈值, 大家都能接受,
那么再向上的提升就不那么必要的. 但随着程序负载增大等原因, 这个阈值可能会变.
- 关于代码细节, 可以说的方面很多. 一般, 只要不出错, 都可以接受, 但如果一个地方
使用生成可迭代对象的方法去做遍历, 那一定是可以继续优化的.
- 代码复用. 一般来说, 能复用的地方就复用. 但如何确定能复用? 我们不该在写第一个
例子的时候就开始对这个例子进行抽象以方便下一次复用, 而是要在下一次真正到来的
时候再开始抽象并复用. 甚至有时候当第二次, 第三次出现的时候我们都还不做复用,
比如 Dan Abramov 提到的, 需求还在变化中, 提前抽象会导致将来的功能变动难以实现,
从而导致更大的工作量.
- 程序架构. 架构似乎是最不重要的, 但也却是一开始就要确定的. 当然, 随着业务发展,
什么都可能会变, 架构也会随着变化. 架构是综合了上面所有的点, 总结出来的. 架构
要能保证功能的完全性, 符合团队能力, 可以实现自动化的风格一致性, 不会拖慢
开发速度, 在基础环节上能达到代码执行效率阈值, 同时尽可能约束代码细节, 避免
低级错误, 提供代码复用优化的可能.
关于如何平衡功能的实现与代码的优雅, 我的观点一直是:
- 代码的好是没有止境的, 只能无限接近于满分.
- 代码需要适应环境的变化, 尤其是高级语言.
- 基于以上两点, 好代码是慢慢进化的, 不断进化的, 不能一蹴而就.
- 先以最快速度完成基础功能, 然后不断优化.
- 开始时, 不使用框架或类库, 如果要用, 则使用基础的, 可插拔的.
- 随着项目的推进, 功能逐渐复杂, 产品目标逐渐清晰, 这时再考虑利用框架重构或重写.
在 Go Proverbs 中有这样一句话与 Dan Abramov 的文章异曲同工:
A little copying is better than a little dependency.
现在, 就让我们停下来, 更多的思考, 然后进入对好代码执着的下一个阶段吧.