你已经在某个项目的一部分中拖延了很久。推迟了一周以后,今天是你计划打开遗留代码库并查看已完成的内容的时候。你一想到这代码库就害怕。因为你知道离岸软件开发团队已经接触了多年这些代码,而且这些代码已经有五年的历史了。你还知道让你接手这些代码就是让你去改进它们的。由于预算问题,管理层决定“重用”代码,而不是放弃整个项目。现在,你身处国外,你希望在另一边等待你的是“好代码”,但是又非常清楚这些代码有95%的概率是“烂代码”。
你用一大杯咖啡开始一天的生活,让(修复这些代码的)这个过程不那么痛苦。因为在几分钟内,你就会接触到一个非常糟糕的代码示例。
乱得像意大利面一样的代码 — by Jun Wu
这些代码不仅乱得像你家三岁小孩刚画的画,还有点像他喜欢的食物一样。
确定了这些代码到底有多烂以后,你可以向管理层再次重申这些代码的修复时长是重写代码所需时长的两倍。
1. 无法访问的代码
如果不改变逻辑,那么这段代码将永远无法访问。
示例:
代码语言:javascript复制function {} {return x;z=a b;}
修复措施:删掉它们
2. 包括冗余类的无用代码
这一类的代码完全就是多余的,或者根本就没有任何作用。
示例:
代码语言:javascript复制function() {a b;}orfunction() {c=a b;c=a;c=b c;}
修复措施:要么重写代码,要么删掉。
3. 过于庞大的类
如果这个类花了20分钟才找到其中的逻辑,那你还留着它干什么?(赶紧删了吧!)这都有多少行代码了,长得像一章小说一样。
修复措施:请赶紧重构!
4. 循环引用导致产生上帝对象
这类代码似乎很快就会回到相同的目标。这将会导致 上帝对象 (https://en.wikipedia.org/wiki/God_object)的产生,一个“了解过多或负责过多”的对象。这也是反模式的一个例子。
图片来自 Wikipedia
修复措施:重构代码,或者设计并将它们分成独立的分组。
5. 投机性的代码
有人写这些代码仅仅是为了防止某些将来可能出现(但从来没有发生过的)的情况发生。
修复措施:删了吧,别留了。
6. 硬编码
这类代码是最容易发现和预防的。因为在每次修改值的时候,都必须修改代码。这类硬编码也被认为是一种反模式。一般情况下,在项目释放资源以添加一个允许用户输入值的动态解决方案之前,会暂时执行这个操作。
修复措施:创建一个该动态的接口允许修改值。
7. 神奇的数字
就是一个直接使用的数字,你也不知道为什么是它。
示例:
代码语言:javascript复制function(){for(int i=0; i<10; i ){
}
}
在上面的示例中,10 就是那个神奇的数字。
修复措施:用 数值10 来初始化的变量 替换掉这个固定值 10.
8. 冗长的如果(条件)
以下是一个非常长的 if 语句的逻辑,不同的行仅用于简单地容纳这些逻辑。
代码语言:javascript复制if(get_data(data)=success || (reuse(data)&&cut_data(data)==success)||(reuse_again(data) && cut_data(data)==success))
解决办法:用特定的编程语言样式对这类冗长的 if(条件)语句进行格式化。
9. 顺序耦合
也就是说,必须要按照特定顺序才能调用的方法。举个例子,假设你有一个“begin”的方法,你必须要在“start”方法之前调用它,然后才能调用“drive”方法。
修复措施:请使用设计模式里面的“模板方法模式”。
10. 过度使用继承方法
面向对象编程中过多的继承将会导致代码紧密耦合且不灵活。然而,你可以把注意力放在组成上。
neethack.com(http://neethack.com/2017/04/Why-inheritance-is-bad/)上有一个很好的例子和解决方法,可移步查看。
11. 不使用核心编程语言的功能
这一点不是非常明显。但是,为了这个项目而选择某种编程语言是有原因的。Python中的一个很好的例子就是使用循环来处理简单的任务,而不是使用列表理解。
12. 过度复杂的注释
如果你的注释在一段非常大的代码块中,或者过于复杂,这有可能是一个警告信号,说明了这段代码也需要重构。
修复措施:通过提取方法或变量来重构。
13. 消息链
消息链就像老师跟幼儿A说话,幼儿A和幼儿B说话一样。老师就是客户端,幼儿是消息链中的对象。而这里的问题是,这条消息链上任何关系的更改都需要对客户端进行更改。
修复措施:通过隐藏委托进行重构。
14. 数据块
这里指的是代码的不同部分包含了相同的变量组。其中一个典型的例子是,当你在代码中多次连接到服务的参数时,就会发现这个数据块。
修复措施:通过创建一个新的参数对象或者提取类来重构。
15. Poltergeists
这些类在系统中扮演的角色有限,本质上只是使得软件变得更加混乱。它们有可能是临时关联、无状态类、临时对象和类,以及冗余指向。
修复措施:通过将原本在poltergeist中的动作移动到它们调用的相关类中来重构。
结语
我已经详细介绍了15种不同的方法来发现这些“烂代码”,现在是时候通过定义“什么是好代码”来结束本文了。
图片来自:@safesolvent unsplash.com
- 良好的代码应当具有良好的组织、良好的测试、简单且直观。
- 良好的代码应该是非常优雅的,因此可以非常轻松地向学龄儿童解释其中的逻辑。
- 任何人都能写出一手好代码,你的程序员不必成为火箭科学家也能写出好代码。
- 最重要的是,良好的代码将长久保留、生生不息。
如果你还没有读过《 Clean Code: A Handbook of Agile Software Craftsmanship (整理代码:敏捷软件的工艺手册)》这本书,建议你去读一读:https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882。 良好的代码只需要几个简单的修复。你还在等什么?
吴恩达新书《Machine Learning Yearning》完整中文版