《编程匠艺》之开发工具与技巧

第二部分: 代码的神秘生命(代码开发的技术与技巧)

1. 欲善其事,先利其器(使用工具)

  1. 尽可能全面的了解你的常用工具, 为此投入的时间是值得的.
  2. 使用工具发挥作用:
    • 了解它能做什么
    • 学习如何驾驭它
    • 了解它适合什么任务
    • 检查它是否可用
    • 找到了解更多信息的途径
  3. 工具链的组成
    1. 源代码编辑工具

      • 代码编辑器
      • 代码处理工具(diff比较工具, sed流查找修改工具, awk样式匹配工具, grep正则匹配工具, find/locate文件查找工具)
      • 代码浏览工具
      • 版本控制工具
      • 源代码生成工具
      • 源代码美化工具
    2. 代码构建工具
      • 编译器(优化到什么程度?编译器遵循的标准是什么?如何生成正确指令集的代码)
      • 链接器(是否可以生成库对象, 静态库,动态库;是否能生成可调试文件)
      • 构建环境(make, automake, cmake等)
      • 测试工具链(如自动化单元测试框架, 模拟内存不足, 负载过高等)
    3. 调试和调查工具
      • 调试器(gdb, ddd)
      • 分析器(性能分析等)
      • 代码校验器(静态检查如lint, 动态工具如内存分配/边界检查器)
      • 度量工具(统计函数,注/代 比, 圈复杂度, 重复度等)
      • 反汇编工具
      • 缺陷跟踪系统
    4. 语言支持工具
      • 编程语言本身(语言特性,如go协程)
      • 运行时和解释程序(如java虚拟机)
      • 组件和库()
    5. 其他工具
      • 文档工具
      • 项目管理
  4. 工具总结
    • 你的工具箱中有哪些工具?哪些是频繁使用的?
    • 是否已经发挥了工具的最大作用?是否尝试优化使用?
    • 是否已经是能找到的最好工具?

2. 测试代码的魔术(保证代码质量)

  1. 测试分为不同的层次,作为开发人员,主要关注的是在代码实现过程中的测试.
  2. 关于测试的疑问:
    • 为什么需要测试?这个应该不需要再复述了,为了保证交付的软件是满足要求的.
    • 谁来测试?自己应该为自己写的代码进行充分的测试,而不是寄希望与测试人员.
    • 测试内容都有哪些?这是个很好的问题,需要测试代码中的函数,类,流程等,根据测试的内容不同,可以分为单元测试和功能测试与集成测试.
    • 何时开始测试?越早开始成本越低.
  3. 影响测试难度的因素:
    • 分支与条件多少
    • 代码规模
    • 依赖关系
    • 外部输入
    • 多线程
    • 代码演变
  4. 测试类型
    • 单元测试(测试类或者函数)
    • 组件测试(验证一个或者多个单元组成的完整组件行为)
    • 集成测试(测试下一个系统中的多个组件,确保正确相连)
    • 回归测试
    • 负载测试(确保性能达到)
    • 压力测试(确保超负荷时,不会乱成一团,用于获取软件的实际容量)
    • 疲劳测试(使代码在较高负荷下连续工作一段时间,以确定是否有内存泄露和内存碎片化造成的性能降低)
    • 可用性测试(用户使用测试)
  5. 挑选单元测试用例
    • 既然不能测试所有的情况,那么怎么挑选用例呢?可以挑选下面的主要点:

      1. 良好的输入
      2. 不好的输入(如极大值,极小值, 过长或者过短字符串, 空字符串)
      3. 边界值(边界值本身,边界值上方, 边界值下方)
      4. 随机数(自动化随机产生)
      5. 零值
  6. 编写可测试的代码
    • 使各部分代码自包含,尽量减少不必要的关联
    • 不要依赖于全局变量
    • 限制代码的复杂度,拆分代码.
    • 保持代码的可观测性.
  7. 测试自动化
    • 将自动化运行的单元测试成为你构建的一部分
    • 测试的代码应尽量逻辑简单,避免测试代码出现问题
  8. 故障描述
    • 在测试出现问题时,需要详细的描述问题,描述的内容包括:

      • 出现问题时的环境(软件版本,硬件版本)
      • 可以使问题复现的最简单的步骤
      • 关于问题出现的可重复性和频率
      • 有可能相关联的其他事物
  9. 在测试时出现的问题就应该进行跟踪,并对其进行自动化测试的覆盖.
  10. 开发测试管理
    • 缺陷跟踪系统(报告故障, 分配责任, 确定优先级, 标记状态)
    • bug审查(重点在于讨论缺陷以及如何处理, 不要讨论修改细节)
  11. 单元测试需要到什么程度?如果一段代码简单的看一下已经不能证明是否正确的时候,就该引入测试用例了.
  12. 测试驱动开发的模式, 编写代码之前的测试只能是黑盒测试.

3. 寻找缺陷, 并解决它(如何解决问题)

  1. bug的种类(如果你能准确知道它, 就能控制它)

    • 从远处看(三类)
    1. 编译失败
    2. 运行时崩溃
    3. 非预期的输出行为
    • 从近处看(更细致的分类)
    1. 句法错误(避免的方式是打开所有编译告警,并使代码通过lint检查)
    2. 构建错误(彻底清除中间构建, 从头构建)
    3. 语义错误(变量未初始化, 比较浮点数, 数值溢出, 隐士类型转换; 使用lint检查)
    • 从更近处看(语义缺陷)
    1. 段错误(主要是错误的指针使用)
    2. 内存溢出(表现可能是运行很远处出现莫名的错误)
    3. 内存泄露()
    4. 内存耗尽
    5. 数学错误(浮点异常, 溢出, 除数为0等)
    6. 程序暂停(无限循环, 死锁, 竞争)
  2. 除错的艺术
    • 地下之路
    • 地上之路
  3. 调试工具
    • 调试器(如gdb)
    • 内存访问校验器(确认是否有内存泄露和溢出)
    • 系统调用追踪(如strace)
    • 内核转储core文件
    • 日志
    • 静态分析器
  4. 调试箴言
    • 避免使用调试器"闲逛", 要注意调试黄金法则:多动脑子.

4. 代码构建

  1. 主要的构建机制有三种:

    • 解释型语言
    • 编译型语言
    • 字节型语言
  2. 同一项目中,所有的成员都应该使用相同的构建系统,否则,构建的就不是同一个软件,可能存在参数等差异.
  3. 构建应该注意的事项:
    • 构建完成后,需要为发行打包
    • 每个版本都需要存档存储,或者在git上打一个版本tag.
    • 每个版本都需要一个发行说明
    • 当构建版本时,必须选择正确的编译器开关集.

5. 优化代码(追求速度和效率)

  1. 软件优化的含义:

    • 程序的执行速度加快
    • 减小可执行文件的大小
    • 提高代码的质量
    • 提高计算结果的准确性
    • 将启动时间减到最小
    • 增加数据的吞吐量
    • 减少存储开销
  2. 造成代码臃肿,运行慢,体积大的原因?
    • 不必要的复杂性
    • 间接(额外的中间层)
    • 重复(重复的调用复杂的计算过程)
    • 糟糕的设计(加大了沟通的模块的距离)
    • I/O等待
  3. 为什么不进行优化?
    • balabala...备选方案
  4. 为什么要进行优化?
    • balabala...特殊领域如游戏, dsp, 实时系统, 金融计算等领域.
  5. 怎么进行优化?
    • 确定程度运行的慢, 并证明确实需要优化(但是要注意,也许并不是慢在代码级,而是设计上有问题)
    • 找出运行最慢的代码,以这段代码为目标(使用合适的分析工具)
    • 先测试这段的性能
    • 对这段代码优化
    • 测试优化后的代码是否功能正常
    • 测试速度提升多少,并决定下一步
  6. 怎么分析哪段代码最慢?
    • 使用合适的分析工具
    • 手动添加计时
    • 计算每个函数的调用频率(有工具, 也可以利用编译器的hook)
    • 通过单个函数变慢来测试它对整个程序执行时间的影响
    • 在进行分析时,要谨慎的选择分析数据,可以选择基本的数据集, 高负荷的数据集和普通的数据集.
  7. 优化的技术
    • 优化有两种大的方向:修改设计和修改代码
    • 基于运行速度的优化包括:
      • 加快较慢代码的速度
      • 尽量少做较慢的事情
      • 将较慢的事情推迟到不得不进行的时候
    • 代码设计层的修改包括:
      • 添加缓存层, 加快较慢的数据的访问
      • 使用资源池
      • 为速度牺牲一点精度
      • 变串行为并行,使用多线程模型
      • 使用更合适的算法和数据结构
    • 代码层的修改包括:
      • 编译器的优化级别提高
      • 循环展开
      • 代码内嵌(inline)
      • 移到编译时(如通过设置uint, 省掉<0 的检查)
      • 强度折减(使用等价的操作替代其他指令, 如使用移位代替除法)
      • 子表达式(对于多个地方会用到的同一个操作,抽出来)
      • 无用代码删除
      • (下面的方式更推荐)
      • 如果发现一个函数慢, 那么不要频繁调用, 缓存结果
      • 跨语言封装, 比如把java重新在c中实现
      • 重新整理代码(推迟工作, 对函数做检查及时跳出, 循环条件中不做计算)
      • 空间换时间, 提前缓存需要大量计算的结果
      • 利用短路判断,把可能导致退出的条件放在前面
  8. 对程序性能产生深刻影响的决策有:
    • 功能数量 VS 代码规模
    • 程序速度 vs 内存消耗
    • 存储和缓存 vs 按需计算
    • 近似的计算 vs 精确的计算
    • 内嵌 vs 函数调用; 单一的 vs 模块化的
    • 通过引用或者地址传递 vs 传递副本
    • 通过硬件实现 vs 通过软件
    • 写死的直接访问 vs 间接访问
    • 预先确定的固定的值 vs 可变可配置的值
    • 编译时工作 vs 运行时工作
    • 本地函数调用 vs 远程函数调用
    • 巧妙的算法 vs 清晰的算法
  9. 较慢的程序的瓶颈可能在哪?
    • 内存颠簸(不停的换出)
    • 等待磁盘/网口等访问(等待I/O慢)
    • 等待较慢的数据库事务
    • 存在锁等待
  10. 对使用的语言和操作系统, 要大致了解其相关成本, 如函数调用, inline函数, 可以通过查看对应的指令, 来了解大致时间级别.

6. 安全的代码(防止被黑)

  1. 做安全防护的第一步是:了解你拥有哪些重要的资源, 是否拥有一些敏感的信息或者特定的能力.
  2. 不安全的软件源头:
    • 不安全的设计和体系
    • 缓冲区溢出
    • 嵌入的查询字符串
    • 竞争状况(常出现在复杂的多现场模型里)
    • 整数溢出
  3. 编码中的保护方法
    • 限制设计中的输入数量,安排所有的通信通过系统某部分进行
    • 在尽可能低的权限上运行程序
    • 避免开发并不真正需要的功能
    • 不要依赖于不可靠的库
    • 避免存储敏感数据
    • 要对输入进行检查(包括命令行参数, 环境变量, web表单, 文件大小等);要检查输入的大小, 格式, 有效性以及数据的真正内容.

原文地址:https://www.cnblogs.com/yhp-smarthome/p/11074575.html

时间: 2024-11-10 12:09:05

《编程匠艺》之开发工具与技巧的相关文章

《编程匠艺》读书笔记

<编程匠艺>读书笔记之一 <编程匠艺>读书笔记之二 <编程匠艺>读书笔记之三 <编程匠艺>读书笔记之四 <编程匠艺>读书笔记之五 <编程匠艺>读书笔记之六 <编程匠艺>读书笔记之七 <编程匠艺>读书笔记之八 <编程匠艺>读书笔记之九 <编程匠艺>读书笔记之十 <编程匠艺>读书笔记之十一 <编程匠艺>读书笔记之十二 <编程匠艺>读书笔记之十三 <编

VS2010开发工具使用技巧&lt;之简单讲解&gt;

俗语云:工欲善其事必先利其器! 1.代码放大 效果:放大前----------------------------------------------------------------->放大后 2.高亮选中 3.添加行号 效果如下: 4.折行显示代码 下图代码过长,出现滚动条 效果如下: 5.工具->选项中显示不全       效果:处理前----------------------------------------------------->处理后 6.更改高亮显示的颜色 效果如

学习Python编程必会的开发工具,这些你都会用吗?

Python软件基金会阐明了开发人员如何在Python的三个主要使用领域使用Python:数据科学.web开发和DevOps. 就流行程度而言,Python可能是世界上发展最快的编程语言[1],但是开发人员在使用它做什么,使用什么工具呢? Python软件基金会阐明了开发人员如何在Python的三个主要应用领域使用Python:数据科学.web开发和DevOps. 去年秋天,基金会和IDE软件公司JetBrains为2018年度Python开发者调查报告[2]对150个国家的2万多名专业和业余开

《编程匠艺》之代码的表面

第一部分: 处理代码的细节(代码的表面) 处理代码的细节,主要分为如下的几个方向,check: 善于防守, 考虑代码的健壮性. 好的样式.精心布局. 为文件和函数以及各部分起个好名字. 良好的注释. 错误处理,处理好可能会出现的错误.保证不崩溃. 逻辑清晰,可理解. 1. 防御性 防御性的诱因: 恶意用户 客户端错误的使用 运行环境不完整 外部运行库问题 如果可以使用函数局部变量,就不要使用全局变量.如果能使用循环体内的变量,就不使用函数级变量. 防御要义: 使用合适的风格和规范. 逻辑清晰,

《编程匠艺》之软件的架构与改良

第三部分: 代码的形成过程(软件的架构) 1. 崇尚设计(如何做良好的软件设计) 软件设计的层次 系统体系结构(整体系统和子系统,以及子系统之间的连接方式) 模块于组件 类和数据类型 函数 设计良好的特征 简洁和优雅 模块化(高内聚,低耦合) 良好的接口(为了创建良好的接口,可以遵循下面的步骤:) 确定客户端, 了解它的需求 确定供应端, 了解它的能力 推断所需的接口类型(函数, 类, 网络协议?) 确定操作的性质(究竟需要提供什么样的功能?) 可扩展性(需要仔细评估现在的功能, 以后可能有的功

sublime前端开发工具常用技巧

ctrl+N//新建文件夹ctrl+shift+p//打开命令行!,ctrl+E//快速生成html模板ctrl+E//自动补齐ctrl+P(#@)//goto 任何地方,其中#查找元素,@查找样式ctrl+enter//对齐回车ctrl+[     ctrl+]//前者伸展,后者缩进ctrl+shift+v//自动适应格式的粘贴产生多行游标的方法:1,选定目标,ctrl+d(选定下一个) ctrl+k(跳过某一项)2,选定目标,alt+F33,选定目标,ctrl +a ctrl+shift+L

【开发工具】vim编辑器实用技巧总结

总结一些我们在平时使用vim编辑器的一些实用功能,后续会一直更新. 1.  visual插件 visual插件其实相当于一个书签作用,比如我们在一篇很长的源代码文件中,我们可以标记一行,然后后来我们再想回到这一行时,只需要一个快捷键就能迅速定位到这一行,非常方便,不用不停地往上或往下翻. 1.1  常用命令 1.  mm标记一个标签: 2.  F2回到被标记的那一行: 3.  连续按两次mm就可以取消标签: 4.  shift+F2可以在几个标签来回切换: 2.  emmet.vim插件 emm

搬来的谷歌开发工具技巧

http://segmentfault.com/a/1190000003882567 小小的放大镜图标告诉你有哪些 CSS 类/选择器 位于哪个 CSS 文件,决定了某个特殊元素的样式和 CSS 的属性.例如,在任意 DOM 元素上右击选择 “审查元素”,切换到 “Computed” 子菜单,可以查找你感兴趣的 CSS 属性并且点击放大镜可以直接定位到的 CSS 类/选择器在 .css 文件中的位置. (当你开发新的大型 web app 项目的时候非常有用): 想看看当前的 web app 发送

操作系统开发的工具与技巧

操作系统开发的工具与技巧_IT/计算机_专业资料.如何开发操作系统操作...(cDest,szData); // 使用 cDest ... } NASM 汇编器微软的宏汇编器MASM http://www.zhihu.com/people/wplzzmrnhttp://www.zhihu.com/people/xdcwchttp://www.zhihu.com/people/pqdwdlhttp://www.zhihu.com/people/dqdbkgulthttp://www.zhihu.c