虽说接下来我会告诉大家如何一份写高质量代码,但照此执行其实离我心目中的高质量的代码还有一点的距离,我心目中理想的高质量代码的终极目标是——大家统一的“视如己出”的代码风格,包括了一致的命名选取、IDE、依赖环境等等,以及容易出错的长链路数据的管控,全覆盖测试,甚至由更早的模块保证功能正常的输入约定。
代码规范
至少了解1~2份通用的代码规范
架构要求
函数
- 函数体尽可能小
- 函数入参尽可能少
- 类中被调用的函数尽可能有序出现在调用者附近
类
符合面向对象设计原则
7个原则可以通过一个谐音辅助记忆——“开单依理,少和解”,作为你某次急冲冲地上班,导致小事故被人讹的一个告诫(上班开车注意安全,迟到就迟到一会吧)
模块
代码和功能上好类
设计文档
包括概要、详细设计
- 功能描述
- 列举
- 实现方式
- 关键实现
- 方案选择
- 不容易理解的地方
- 解释说明
- 关键实现
- 实现流程
- 数据流的角度
- 复杂 -> 流程图
- 简单 -> 表格
- IPO图
- 时序图
- 数据流的角度
- 数据结构
- 关键数据结构
- 代码表示
- 领域化语言(像proto的定义、动态库导出的模块定义文件)
- 关键数据结构
- 注意事项
- 未完成项
- 待改善处
- 与其他方合作的约定
- 哪里做数据有效性的判断
- 命名同步
写代码最重要的原则——Don’t Repeat Yourself
不要重复你自己,不过外部调用时就地打印日志会更符合逻辑也方便后续跟踪业务
- 越底层(潜在地被多次调用)的代码不应该打印日志
- 日志的打印代码应该出现在你梳理逻辑最早可以看到的地方,就像拆箱放在最上面的使用说明
- 为了多处调用相同函数前后跟踪采用相同的打印,先花片刻思考是否可以提炼到统一接口,打印一份日志,失败了就“小小重复一下”
代码结构
- include
- src
- tests
- 什么时候需要测试
- 没信心的函数
- 重构的正确性保证
- 测试用例一直保留
- 什么时候需要测试
- examples
- 链路短的功能验证
- 提供给使用者的参考
- tools
- 评测
- 转换
- build
- lib
- test
- bin
多使用空格组织代码
横向空格
- 缩进
- 长代码换行,两个tab以上
纵向空格
- 逻辑块
- 函数间
审慎使用宏定义分隔代码块
此时的宏定义就像轮胎上的补丁、电路板上的飞线一样,事后尽可能重新设计代码来“换新”。跨越多行代码的宏定义加上注释,参考如下:
#if defined (ADAS_J3)
// code block A
#else // !ADAS_J3
// code block B
#endif // ADAS_J3
Magic number
代码中除明确的数值数比较,可以直接使用常量数值外,其他应该使用constexpr变量替代
命名约定
- 类的成员变量
结尾加下划线后缀,如string table_name_;
- 成员变量初始化,参考哪些变量会自动初始化
异常处理
- 避免除“0”,防止数据越界
- 内聚的函数,优先通过代码约定限制越界,而不是频繁或冗余的if过滤
- try catch抓取异常
- 异常打印log或报告异常,或两者兼之
- 检查是不是所有异常都处理,编译器往往会告诉你
别忽略编译器警告
审慎地处理所有编译器警告
运行
调试工具
- gdb
- top
多掌握一些调试工具,效率会极大提高
避免写内存泄露的代码
- 了解什么是内存泄露
- memset的使用避免直接对类操作,尤其避免对std::vector、std::string等操作
- 容器的使用vector list map,避免无限制地增加
测试
单元测试
- 分支覆盖、边界条件
- 功能测试
- 功能完成
集成测试
灵魂拷问
为什么要写高质量的代码,你的理由是什么?评论区见
书籍推荐
《代码整洁之道》
《重构——改善既有代码的设计》