如何探索大型开源软件库( 四 )


B.Kernighan&D.Pike(《程序设计实践》)
正如Arandr所提到的 , 与有经验的维护人员交谈以及向新贡献者解释你的理解是一种有积极意义的习惯 。 这两种方法都需要对代码库进行积极的思考 , 通常比“试错”策略要快 。
安排一个会议 , 和你的MLH导师/代码维护人员一起看下你的计划 。 为会议准备一份最详细的计划 。 在理想情况下 , 计划是一系列变更的分解 , 这里的分解是指做这项变更主要需要哪些步骤?这里有一条很好的经验法则:你使用的每个动词都应该有自己的步骤 。
下面是一个不错的步骤分解示例:
新建一个类myApiService.js将myComponent.js文件中函数getApiResponse的代码提取到自己的类中 。 这个类的公共方法将是……编写一个新的测试测试 , 覆盖未向xyz函数传递参数的用例 。会议期间 , 导师/维护者会帮助你澄清并改进计划 。 他们可能会要求你改进计划的某些方面 , 或者直接进入验收阶段 。
调试、记录日志及性能分析
调试是一门需要进一步研究的艺术.……最有效的调试技术似乎是那些设计时就内置到程序中的技术——如今 , 许多最好的程序员会将近一半的程序用于为另一半程序的调试提供便利;这部分程序最终会被丢弃 , 但最终生产力的提高令人惊讶 。
另一个好的调试实践是记录所犯的每一个错误 。 尽管这可能会很尴尬 , 但对任何研究调试问题的人来说 , 这些信息都非常宝贵 , 而且它还可以帮助你学习如何减少将来的错误数量 。
D.Knuth(《计算机程序设计》第一卷)
调试器是每个程序员工具库里最强大的工具之一 。 理想情况下 , 为了了解某些函数调用 , 你应该选择一个请求流 , 发起一个请求 , 并在调试器的引导下完成整个请求流 。 当你在调试器的引导下查看不同的文件时 , 你正在利用你的视觉记忆 。 你会记住代码是如何组织的以及文件是什么样子的 。 对于许多调试器 , 如gdb和pdb , 命令集几乎是一样的 。 下面这些基本命令 , 你应该熟悉:
l——显示当前行及以下的代码行p——在当前上下文中计算表达式并打印其值s——逐步执行代码n——下一行代码(例如:如果你不想执行argsort , 想跳到下一行 , 则可以使用n)q——退出调试器b——设置断点(依赖提供的参数)在某些情况下 , 使用数据断点是有好处的 。 数据断点让你可以在存储在特定内存位置的值发生变化时中断执行 。 例如 , 监控变量X变为NULL , 找出谁过早地释放了内存导致了悬空指针 , 观察全局数据访问流 , 这些都是它的一些用例 。 Shog9在StackOverflow上提供了更全面的用例 。
在这一点上 , 一个常见的问题是——难道打印语句不够吗?视情况而定!GlenK.Peterson的回答很好地描述了这一观点:
我发现 , 对于纯粹的软件问题 , 思考问题并测试系统 , 了解关于这个问题的更多信息比逐行执行代码要有用得多 。 使用print语句 , 我就可以看到命令行或日志文件中发生的所有事情并在想象中重现 , 而且比使用调试器来回切换更容易 。
通常 , 解决最难的Bug要抛开计算机来理解问题 。 有时用一张纸或白板 , 有时答案会在我做其他事情的时候自己显现出来 。 最棘手的Bug可以通过仔细查看代码来解决 , 就像在玩Where'sWaldo 。 其余的 , 使用打印语句或日志语句似乎就很简单 。
不同的人有不同的风格 , 不同的风格适合不同的任务 。 Print语句并不一定是比调试器次一级的方法 。 这取决于你所做的事情 , 它们也可能更好用 , 特别是在没有原生调试器的语言中(Go有吗?)
在有些情况下 , 程序失败的部分非常大;程序采用非线性流控方法;程序是多线程;实时运行;或者执行像写文件这样的破坏性操作——更好的选择是使用日志记录和断言 , 可以看下StackOverflow上slugfilter所作的解释 。
要了解关于调试的详细内容 , 可以阅读麻省理工学院讲师RobertMiller和MaxGoldman为课程6.005:软件构造配套的阅读材料 。
从Python文档中可以看出 , Profilers提供了程序的确定性性能分析(deterministicprofiling) 。 其中 , 概要文件是一组统计信息 , 描述程序各个部分执行的频率和时间 。 它们将帮助你了解程序的哪些部分占用了大部分时间和/或资源 , 以便你可以集中精力优化这些部分 。 麻省理工学院的阅读材料MissingSemester是一份详细介绍性能分析器的精彩指南 。
结论:
对于调试 , 人们的态度往往是开始时厌恶 , 执行时不情愿 , 结束时炫耀 。