前言
随着开源框架、工具和社区的快速发展,编码越来越方便、快捷,但充满“坏味道”的代码依然随处可见。本文想回归到码农的本源,大致梳理一下本人对“好的代码”的粗略见解。由于能力和时间有限,加上读者诸君中大牛云集,这里只是点到即止,权当抛砖引玉。
一、逻辑正确
– 反例:
- 需求实现遗漏或理解错误
- 空指针异常
- index越界
- 边界错误(>与>=用混,<与<=用混)
- 句柄或内存等资源未释放
- =与==用混
- i++与++i用错
- 深浅克隆用错
- 未初始化
- 调用函数时未判断返回值,就直接使用调用结果(C/C++程序容易中招)。
以上反例看起来司空见惯,但许多bug(尤其是大bug)与此有关。
– 保证手段:
-
Code Review:
1)自我Review
2)组内交叉Review
3)组外Review
4)工具检测一般认为组外Review/专家评审比自我Review效果要好,但我依然认为,许多bug(尤其是简单bug)是可以通过自我Review发现的,而交付测试时bug众多的一个重要原因是没有做好自我Review。让我们养成习惯,每当写完某块代码后,静下心来,看看每个变量、操作符、函数调用等等,是不是表达了我们的真实意图。如果用心做了并持之以恒,再看看bug量是否变少了。
-
Unit Test:
网上资料很多,不赘述。
二、安全
– 反例:
- 存在SQL注入漏洞
ResultSet rs = statement.executeQuery("select * from userinfo where user='" + user + "' and password='"+ password + "'");
- 存在XSS注入漏洞
Web程序对于用户输入的内容未加过滤处理,这样黑客可以通过HTML或JS注入篡改网页,进行攻击。 - 密码等敏感信息明文传输或保存
- API无防刷措施
可增加如下等防护手段:
1)鉴权
2)验证码
3)时效
4)限流等 - SQL查询大数据量未限制条数
- 存在缓冲区溢出漏洞(C/C++语言程序容易中招)
– 保证手段:
- 制定安全编码规范,养成安全编码习惯。
- 使用安全检测工具。
- 进行渗透测试。
三、易懂
- 要有Code As Documentation意识
可参照福勒大师的文章:
https://martinfowler.com/bliki/CodeAsDocumentation.html - 使用顾名思义的包名、类名、参数名、变量/常量名
- 有必要的注释
1)公共类的说明
2)公共方法的用途及参数说明
3)带算法或复杂逻辑的代码块前有说明 - 避免巨大类、巨大方法
- 排版合理
1)行宽
2)缩进
3)括号等
四、性能好
为了有好的性能,主要有如下方面的优化方法。
- 算法优化
即降低计算复杂度,往往会带来性能上质的飞跃,是非常有效的性能优化方法之一。 - 实现方式优化
1)单线程 => 多线程
2)同步 => 异步
3)Java BIO => NIO/AIO
4)缓存 - 其他细节优化
1)循环体内减少逻辑判断、try catch
2)synchronized修饰符用在最小作用域
3)合理使用懒加载/延迟初始化(需谨慎)
4)使用恰当的数据类型
如:在满足需求的前提下,用Java 基本类型int 替代 对象类型Integer,float 替代 double
5)指令级优化
五、可复用
- 共通方法:
把多处使用的相同/相似代码,抽取成共通方法。 - 共通类:
把一组相关的共通方法,组成共通类。 - 库:
把一组共通类,打包成共通库。 - 公共组件/服务:
把一组相近的公用功能包装成公共组件/服务。 - 抽象与建模:
把共同的属性和方法定义在父类里。 - 活用设计模式:
注意要避免反模式
六、易扩展
- 基于接口实现:
定义合适的接口,活用继承、重载、重写等。 - 基于接口实现:
1)Plugin模式(如:Eclipse的Plugin)
2)控制反转(IoC) - 基于消息实现:
1)消息队列
2)消息生产者
3)消息消费者 - 注意防止过度设计
七、易排查
为了排查问题,许多时候通过IDE进行debug即可,但在有些场合,尤其是对于服务端程序来说,一个古老但有效的方法是在合适的地方添加日志。
关于如何添加日志,大致说明如下。
- 代码层面:
1)在关键调用前后加日志,记录输入、输出参数。
2)日志分级(如:debug、info、warning、error等)
3)必要时在日志中加入Trace Number,以便跟踪时序/源头。 - 设计层面:
为重要的用户操作加日志,以便可以追溯操作履历。
注:过多的日志输出会带来性能损失,要避免日志泛滥。
八、兼容
不同类别的应用,在兼容方面可能有不同的注意事项。
- 手机App:
1)兼容不同系统版本
2)兼容不同屏幕分辨率
3)兼容不同第3方App环境
4)兼容有虚拟按键情况 - 手机App服务端:
兼容老版本App - WWW、WAP端:
1)兼容不同屏幕分辨率、字号设置等
2)兼容不同品牌/版本的浏览器、缩放比例等
3)根据不同UA,自动切换到合适的UI布局
九、容错
- 要有容错意识:
- 可能的容错方法(采用与否,视实际场景需要而定):
1)设置合适的默认值
2)先检查合法性再使用(反例:把字符串直接转换成数字或日期)
3)大小写不敏感
4)全角半角不敏感
5)特殊字符处理(比如:必要时可采用转义符)
6)忽略左右空格(trim)
十、编码思想与态度
- 编码思想:
1)编程语言数十种,编码思想皆(大多)通用。
2)好的程序猿,不管用什么编程语言,大都能写出好的代码。 - 态度:
1)对代码的态度
不管是自己生产的代码,还是自己接管的代码,都要像对娃一样,对TA负责。
2)对bug的态度
对自己负责的代码产生的bug(至少简单bug),有愧疚感。