1 整洁性
- 语义简单明确,优先考虑易于读者理解的写法
- 简洁!=代码短
- 复杂的问号表达式反而不如 if else 方便理解
- 个人疑问:问号表达式可以一定程度上提供条件数据传送,而非条件转移
- 复杂的问号表达式反而不如 if else 方便理解
- 提前返错
- 提前返回错误判断可以减少主体逻辑的缩进数量,使主体代码逻辑更醒目
- 利用析构函数做清理工作
- 利用C++析构函数做清理工作,在复杂冗长代码中不会漏掉. 比如执行回调,关闭文件,释放内存
- 用朴素直观的算法
- 在非关键路径上,优先使用朴素直观,维护性好的代码.
- 用轮询代替条件变量
- 非关键路径上这么做,代码间接,不容易出bug
- 轮询: 一直等待信号
- 在关键对象增加magic字段
- 增加magic字段和断言检查,可以及时发现内存错误
2 测试
边界
状态/分支测试
重复/幂等性测试
兼容性测试
防御性测试
- 关注系统在最差情况下的表现,明确能力边界
避免写出不稳定case
例
- 测试不聚焦,无脑复制粘贴,等价类测试爆炸
- 异步等待,基于时间假设,sleep 并发,未能在预期的窗口期交互
- 有顺序依赖的测试,共享某个状态
- 资源溢出,数据库链接满、内存 OOM 析构随机 core
- 析构未严格保序或者未构造
- 多线程共享资源的错误用法导致概率 crash
- 有未处理完的任务就退出
3 提交
- 一次提交不要超过400行代码,最好只解决一个问题
- 自我检查
- 速度<500行/小时
- 一次review时间不超过1小时
- 接口>测试>实现
4 高效工作方法
抽象和分而治之
- 抽象:明确模块之间的依赖关系,确定API接口
- 分而治之:对子系统设计进行合理的注释,帮助理解
- 代码提交尽量做到原子[不可分割的特性.修复.优化],测试代码一同提交
不要重复
- 寻找重复逻辑和代码,并进行封装
- 寻找流程重复,使用脚本或者工具自动化
- 沉淀踩坑经验
快速迭代
- 不要过度设计
- 尽快让代码运行和快速验证,不断迭代来完善
- 为了快速验证,本地测试成本低
- 实现一个可运行的脚手架,再持续添加内容
忌“太心急”,慢即是快
- 需求澄清:类似 TCP 三次握手,用自己理解的方式再给对方讲一遍,确认双方理解一致,对焦,避免重复返工
- 自我提问:为什么做这件事?业务价值是什么?关键技术是什么?已有的系统和它对比有什么不同?兄弟团队是否做过类似的工作?是否有经验可供参考?业务/技术的适用场景是什么?预计耗时和进度风险?
- 新人往往脚踏实地,忘记了仰望星空,只顾着埋头苦干,不思考背后的业务价值,这一锄头,那一铁锹,遍地都是坑,就是不开花,费时费力,成就感低。
忌低效沟通,用数据说话
- 精确地描述问题,上下文和范围,提供有效信息
- 文档是提高沟通效率的最佳方式之一,Google 有文档文化,推荐阅读《Design Docs at Google》[5]
- Bad Case:「测试 CX6 网卡时,IOPS 大幅下降」
- Good Case:「在 100g 网络标卡 CX6 验证性能时,8 jobs 32 depth iosize 4K 场景下,极限 IOPS 从 120 万下降至 110 万,与 FIC 卡相比性能存在 8% 差异」
忌“蠢问题”,学会提问
- 鼓励新人多提问,但提问的问题一定要有质量
- 关于如何提出一个好问题推荐阅读《提问的智慧》[6]
- Bad Case:「我在编译耗时很长,我怀疑是资源不够,这种情况怎么办?」
- Good Case:「我的开发机编译耗时 2 小时,不符合预期,OS 是 centOS 7U、128GB 内存、64Core,编译并发度是 20 核,未限制内存,编译过程使用 Top 查看确实 20 核并发,Cpu 和 Mem没有达到瓶颈,iostat 看磁盘使用率每秒 60%」
5 延伸阅读
编写可读代码的艺术
software Engineer at Google
人月神话
数据密集型应用系统设计