当前位置:网站首页>如何写出好代码 - 防御式编程指南
如何写出好代码 - 防御式编程指南
2022-07-01 15:32:00 【InfoQ】
引言

什么是防御式编程?
Class Main {
private Connection con = = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
public List<Student> doQuery(String name) {
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id, grade, name, gender FROM students WHERE name=" + name);
List<Student> studentList = new ArrayList<>();
while(rs.next()) {
long id = rs.getLong(1);
long grade = rs.getLong(2);
String name = rs.getString(3);
String gender = convertGender(rs.getInt(4));
Student student = new Student(id, grade, name, gender);
studentList.add(student);
}
return studentList;
}
private String convertGender(int gender) {
switch(gender) {
case 0 : return "male";
case 1 : return "female";
}
return null;
}
}
边界防御:检查所有的外部输入
异常处理:在正确性和健壮性之间做好取舍
- 正确性是指:程序永不返回不准确的结果,即使这样做会不返回结果或是直接退出程序。
- 健壮性是指:系统在不正常的输入或不正常的外部环境下仍能正常运行,哪怕输出结果是错误的或者不完整的。
应检尽检:没有完全可靠的外部环境
显示约束:简单直接的代码风格
减少依赖:write once, run anywhere
傻瓜式注释
契约式编程
- 前置条件:期望所有调用它的客户模块都保证一定的进入条件,比如非NULL、非0等要求;
- 后置条件:保证退出时给出特定的属性,比如程序退出时会释放数据库连接;
- 不变式:在进入时假定,并在退出时保持一些特定的属性。
避免过度设计
- 预防不可能会发生的错误,如上面的case所示,对于数据库返回的结果,采用rs.next()即可判断是否有值,而不需要对rs进行非null判断;
- 过多的防御式代码,会导致整体程序显得臃肿、难以维护,代码里充斥着大量的判断和非业务代码;程序的性能也会受此影响;
- 当代码中有非常多的异常捕捉和处理时,可能会导致异常被吞掉,没有正常地报出来。
总结
- 提高工程质量——减少bug和问题;
- 提高源码可读性—— 源码应该变得可读且可理解,并且能经受code review;
- 让软件能通过预期的行为来处理不可预期的用户操作。
附录:防御式编程checkList
- 子程序是否保护自己免遭有害输入数据的破坏?
- 你用断言来说明编程假定吗?其中包括了前条件和后条件吗?
- 断言是否只是用来说明从不应该发生的情况?
- 你是否在架构或高层设计中规定了一组特定的错误处理技术?
- 你是否在架构或高层设计中规定了是让错误处理更倾向于健壮性还是正确性?
- 你是否建立了隔栏来遏制错误可能造成的破坏?是否减少了其他需要关注错误处理的代码的数量?
- 代码中用到辅助调试的代码了吗?
- 如果需要启用或禁用添加的辅助助手的话,是否无需大动干戈?
- 在防御式编程时映入的代码量是否适宜–既不过多,也不过少?
- 在开发阶段是否采用了进攻式编程来使错误难以被忽视?
- 你在项目中定义了一套标准化的异常处理方案吗?
- 是否考虑过异常之外的其他替代方案?
- 如果可能的话,是否在局部处理了错误而不是把它当成一个异常抛到外部?
- 代码中是否避免了在构造函数和析构函数中抛出异常?
- 所有的异常是否都与抛出它们的子程序处于同一抽象层次上?6).每个异常是否都包含了关于异常发生的所有背景信息?
- 代码中是否没有使用空的catch语句?(或者如果使用空的catch语句确实很合适,那么明确说明了吗?)
- 检查有害输入数据的代码是否也检查了故意的缓冲区溢出、SQL注入、HTML注入、证书溢出一级其他恶意输入数据?
- 是否检查了所有的错误返回码
- 是否捕获了所有的异常?
- 出错消息中是否避免出现有助于攻击者攻入系统所需的信息?
- 最终产品代码中对错误的处理方式要比“垃圾进,垃圾出”复杂的多。
- 防御式编程技术可以让错误更容易发现、更容易修改,并减少错误对产品代码的破坏。
- 断言可以帮助人尽早发现错误,尤其是在大型系统和高可靠性的系统中,以及快速变化的代码中。
- 关于如何处理错误输入的决策是一项关键的错误处理决策,也是一项关键的高层设计决策。
- 异常提供了一种与代码正常流程角度不同的错误处理手段。如果留心使用异常,它可以成为程序员们知识工具箱中的一项有益补充,同时也应该在异常和其他错误处理手段之间进行权衡比较。
- 针对产品代码的限制并不适用于开发中的软件。你可以利用这一优势在开发中添加有助于更快地排查错误的代码。
作者简介
开源福利
- GitHub 地址: https://github.com/CloudWise-OpenSource/FlyFish
- Gitee 地址:https://gitee.com/CloudWise/fly-fish
- 万元现金活动: http://bbs.aiops.cloudwise.com/t/Activity

边栏推荐
- Description | Huawei cloud store "commodity recommendation list"
- 使用 csv 导入的方式在 SAP S/4HANA 里创建 employee 数据
- Summary of week 22-06-26
- What is the relationship between network speed, broadband, bandwidth and traffic?
- Sort out the four commonly used sorting functions in SQL
- 做空蔚来的灰熊,以“碰瓷”中概股为生?
- Beilianzhuguan joined the dragon lizard community to jointly promote carbon neutralization
- Intelligent operation and maintenance practice: banking business process and single transaction tracking
- Introduction to MySQL audit plug-in
- MySQL service is starting. MySQL service cannot be started. Solution
猜你喜欢
Zhang Chi Consulting: lead lithium battery into six sigma consulting to reduce battery capacity attenuation
leetcode:329. 矩阵中的最长递增路径
Photoshop plug-in HDR (II) - script development PS plug-in
OpenSSL client programming: SSL session failure caused by an insignificant function
Short Wei Lai grizzly, to "touch China" in the concept of stocks for a living?
Introduction to MySQL audit plug-in
leetcode:329. Longest increasing path in matrix
Photoshop插件-HDR(二)-脚本开发-PS插件
It's settled! 2022 Hainan secondary cost engineer examination time is determined! The registration channel has been opened!
How to realize clock signal frequency division?
随机推荐
《QT+PCL第九章》点云重建系列2
go-zero实战demo(一)
[300 + selected interview questions from big companies continued to share] big data operation and maintenance sharp knife interview question column (III)
Research on manually triggering automatic decision of SAP CRM organization model with ABAP code
The solution to turn the newly created XML file into a common file in idea
【锁】Redis锁 处理并发 原子性
[leetcode] 16. The sum of the nearest three numbers
SQL常用的四个排序函数梳理
opencv学习笔记五--文件扫描+OCR文字识别
Go zero actual combat demo (I)
opencv学习笔记四--银行卡号识别
【ROS进阶篇】第五讲 ROS中的TF坐标变换
摩根大通期货开户安全吗?摩根大通期货公司开户方法是什么?
[target tracking] |stark
榨汁机UL982测试项目有哪些
Don't ask me again why MySQL hasn't left the index? For these reasons, I'll tell you all
[Cloudera][ImpalaJDBCDriver](500164)Error initialized or created transport for authentication
Stm32f411 SPI2 output error, pb15 has no pulse debugging record [finally, pb15 and pb14 were found to be short circuited]
微信网页订阅消息实现
GaussDB(for MySQL) :Partial Result Cache,通过缓存中间结果对算子进行加速