Skip to content

Commit 6e2cc23

Browse files
committed
improve readability in zh
1 parent 0e8fd45 commit 6e2cc23

25 files changed

+106
-106
lines changed
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
# 学会Debug
1+
# 学会 Debug
22

33
调试(Debug)是作为一个程序员的基石。调试这个词第一个含义即是移除错误,但真正有意义的含义是,通过检查来观察程序的运行。一个不能调试的程序员等同于瞎子。
44

5-
那些认为设计、分析、复杂的理论或其他东西是更基本的东西的理想主义者们不是现实的程序员。现实的程序员不会活在理想的世界里。即使你是完美的,你周围也会有,并且也需要与主要的软件公司或组织,比如GNU,或者与你的同事,写的代码打交道。这里面大部分的代码以及它们的文档是不完美的。如果没有获得代码的执行过程可见性的能力,最轻微的颠簸都会把你永远地抛出去。通常这种可见性只能从实验获得,也就是,调试。
5+
那些认为设计、分析、复杂的理论或其他东西是更基本的东西的理想主义者们不是现实的程序员。现实的程序员不会活在理想的世界里。即使你是完美的,你也需要与在你周围的主要软件公司或组织 (比如 GNU ) 的代码,和你同事写的代码打交道。这里面大部分的代码以及它们的文档是不完美的。如果没有获得代码的执行过程可见性的能力,最轻微的颠簸都会把你永远地抛出去。通常这种可见性只能从实验获得,也就是,调试。
66

7-
调试是一件与程序运行相关的事情,而非与程序本身相关。你从主要的软件公司购买一些产品,你通常不会看到(产品背后的)程序本身。但代码不遵循文档这样的情况(让你整台机器崩掉是一个常见又特殊的例子)或者文档没有说明的情况仍然会出现不可避免的,这意味着你做的一些假设并不对,或者一些你没有预料到的情况发生了。有时候,神奇的修改源代码的技巧可能会生效。当它无效时,你必须调试了。
7+
调试是一件与程序运行相关的事情,而非与程序本身相关。你从主要的软件公司购买一些产品,你通常不会看到(产品背后的)程序本身。但代码不遵循文档的情况(让你整台机器崩掉是一个常见又特殊的例子)或者文档没有说明的情况仍然会出现。更常见的是,你的程序出现了一个错误,当你检查你写的代码的时候,却不知道这个错误是怎么发生的。不可避免的,这意味着你做的一些假设并不对,或者一些你没有预料到的情况发生了。有时候,神奇的修改源代码的技巧可能会生效。当它无效时,你必须调试了。
88

9-
为了获得一个程序执行的可见性,你必须能够执行代码并且从这个过程中观察到什么。有时候这是可见的,比如一些正在呈现在屏幕上的东西,或者两个事件之间的延迟。在许多其他的案例中,它与一些不一定可见的东西相关,比如代码中一些变量的状态,当前真正在执行的代码行,或者是否一些断言持有了一个复杂的数据结构。这些隐藏的细节必须被显露出来。
9+
为了获得一个程序执行的可见性,你必须能够执行代码并且从这个过程中观察到什么。有时候这是可见的,比如一些正在呈现在屏幕上的东西,或者两个事件之间的延迟。在许多其他的案例中,它与一些不一定可见的东西相关,比如代码中一些变量的状态,哪一行代码正在被执行,或者是否一些断言持有了一个复杂的数据结构。这些隐藏的细节必须被显露出来。
1010

1111

12-
通常的(一些)观察一个正在执行的程序的内部的方法可以如下分类
12+
观察一个正在执行程序的内部的方法通常可按如下分类
1313

1414
- 使用一个调试工具;
1515
- Printlining[(戳这里看释义)](../../4-Glossary.md) - 对程序做一个临时的修改,通常是加一些行去打印一些信息;
1616
- 日志 - 用日志的形式为在程序的运行中创建一个永久的视窗。
1717

18-
当调试工具稳定可用时,它们是非常美妙的,但[Printlining](../../4-Glossary.md)和写日志是更加重要的。调试工具通常落后于编程语言的发展,所以在任何时间点它们都可能是无效的。另外,调试工具可能轻微改变程序实际执行的方式。最后,调试有许多种,比如检查一个断言和一个巨大的数据结构,这需要写代码并改变程序的运行。当调试工具可用时,知道怎样使用调试工具是好的,但学会使用其他两种方式是至关重要的
18+
当调试工具稳定可用时,它们是非常美妙的,但 [Printlining](../../4-Glossary.md) 和写日志甚至是更加重要的。调试工具通常落后于编程语言的发展,所以在某些时候它们可能会是无效的。另外,调试工具可能轻微改变程序实际执行的方式。最后,调试有许多种,比如检查一个断言和一个巨大的数据结构,这需要写代码并改变程序的运行。当调试工具可用时,知道怎样使用调试工具是好的,但学会使用其他两种方式也是至关重要的
1919

20-
当需要修改代码时,一些初学者会害怕调试。这是可以理解的,这有点像探索型外科手术。但你需要学会打破代码,让它跳起来,你需要学会在它上面做实验,并且需要知道你临时对它做的任何事情都不会使它变得更糟。如果你感受到了这份恐惧,找一位导师 - (否则)在许多人面对这种恐惧的脆弱的开始时刻,我们会因此失去很多优秀的程序员
20+
当调试需要修改代码的时候,一些初学者会感到害怕。这是可以理解的,这有点像探索型外科手术。但你需要学会打破代码,让它跳起来,你需要学会在它上面做实验,并且需要知道你临时对它做的任何事情都不会使它变得更糟。如果你感受到了这份恐惧,找一位导师 - 就是因为许多人在一开始面对这种恐惧的的时候表现的太脆弱,我们因此失去了很多本可以变成优秀程序员的人
2121

22-
Next [如何通过分离问题空间来Debug](02-How to Debug by Splitting the Problem Space.md)
22+
Next [如何通过分离问题 Debug](02-How to Debug by Splitting the Problem Space.md)

zh/1-Beginner/Personal-Skills/02-How to Debug by Splitting the Problem Space.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
# 如何通过分割问题空间来Debug
1+
# 如何通过分割问题 Debug
22

33
调试是有趣的,因为它一开始是个迷。你认为它应该这样做,但实际上它却那样做。很多时候并不仅是这么简单---我给出的任何例子都会被设计来与一些偶尔在现实中会发生的情况相比较。调试需要创造力与智谋。如果说调试有简单之道,那就是在这个谜题上使用分治法。
44

5-
假如,你创建了一个程序,它会在一个序列里做十件事情。当你运行它的时候,它崩溃了。因为你写的代码并不想让它崩溃,所以现在你有一个谜题了。当你查看输出时,你可以看到序列里前七件事情运行成功了。最后三件事情在输出里却看不到,所以你的谜题变小了:“它是在执行第8、9、10件事的时候崩溃的”。
5+
假如,你创建了一个程序,它会依次执行十件事情。当你运行它的时候,它却崩溃了。但你本来的目的并不是想让它崩溃,所以现在一个谜题扔给你了。当你查看输出时,你可以看到序列里前七件事情运行成功了。最后三件事情在输出里却看不到,所以你的谜题变小了:“它是在执行第8、9、10件事的时候崩溃的”。
66

7-
你可以设计一个实验来观察它是在哪件事情上崩溃的吗?当然,你可以用一个调试器或者我们可以在第8第9件事后面加一些[printlining](../../4-Glossary.md)的语句(或者你正在使用的任何语言里的等价的事情),当我们重新运行它的时候,我们的谜题会变得更小,比如“它是在做第九件事的时候崩溃的”。我发现,把谜题是怎样的一直清楚地记在心里能让我们保持注意力。当几个人在一个问题的压力下一起工作时,很容易忘记最重要的谜题是什么。
7+
你是否可以设计一个实验来观察它是在哪件事情上崩溃呢?当然,你可以用一个调试器或者我们可以在第8第9件事后面加一些[printlining](../../4-Glossary.md)的语句(或者你正在使用的任何语言里的等价的事情),当我们重新运行它的时候,我们的谜题会变得更小,比如“它是在做第九件事的时候崩溃的”。我发现,把谜题是怎样的一直清楚地记在心里能让我们保持注意力。当几个人在一个问题的压力下一起工作时,很容易忘记最重要的谜题是什么。
88

9-
调试技术中分治的关键和算法设计里的分治是一样的。你只要从中间开始划分,就不用划分太多次,并且能快速地调试。但问题的中点在哪里?这就是真正创造力和经验需要参与的地方
9+
调试技术中分治的关键和算法设计里的分治是一样的。你只要从中间开始划分,就不用划分太多次,并且能快速地调试。但问题的中点在哪里?这就是真正需要创造力和经验的地方了
1010

11-
对于一个真正的初学者来说,可能发生错误的地方好像在代码的每一行里都有。一开始,你看不到一些其他的你稍后将会学到的维度,比如执行过的代码段,数据结构,内存管理,与外部代码的交互,一些有风险的代码,一些简单的代码。对于一个有经验的程序员,这些其他的维度为整个可能出错的事情展示了一个不完美但是有用的思维模型。拥有这样的思维模型能让一个人更高效地找到谜题的中点。
11+
对于一个真正的初学者来说,可能发生错误的地方好像在代码的每一行里都有。一开始,你看不到一些你稍后开发的时候才会看到的其它纬度,比如执行过的代码段,数据结构,内存管理,与外部代码的交互,一些有风险的代码,一些简单的代码。对于一个有经验的程序员,这些其他的维度为整个可能出错的事情展示了一个不完美但是有用的思维模型。拥有这样的思维模型能让一个人更高效地找到谜题的中点。
1212

1313
一旦你最终划分出了所有可能出错的地方,你必须试着判断错误躲在哪个地方。比如:这样一个谜题,哪一行未知的代码让我的程序崩溃了?你可以这样问自己,出错的代码是在我刚才执行的程序中间的那行代码的前面还是后面?通常你不会那么幸运就能知道错误在哪行代码甚至是哪个代码块。通常谜题更像这个样子的:“图中的一个指针指向了错误的结点还是我的算法里变量自增的代码没有生效?”,在这种情况下你需要写一个小程序去确认图中的指针是否都是对的,来决定分治后的哪个部分可以被排除。
1414

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# 如何移除一个错误
22

3-
我曾有意把检查程序执行和修复错误分割开来,但是当然,调试也意味着移除bug。理想状况下,当你完美的发现了错误以及它的修复方法时,你会对代码有完美的理解,并且有一种顿悟(啊哈!)的感觉。但由于你的程序会经常使用不具有可视性的、没有一致性注释的系统,所以完美是不可能的。在其他情况下,可能代码是如此的复杂以至于你的理解可能并不完美。
3+
我曾有意把检查程序执行和修复错误分割开来,但是当然,调试也意味着移除 bug。理想状况下,当你完美的发现了错误以及它的修复方法时,你会对代码有完美的理解,并且有一种顿悟(啊哈!)的感觉。但由于你的程序会经常使用不具有可视性的、没有一致性注释的系统,所以完美是不可能的。在其他情况下,可能代码是如此的复杂以至于你的理解可能并不完美。
44

5-
在修复bug时,你可能想要做最小的改变来修复它。你可能看到一些其他需要改进的东西,但不会同时去改进他们。试图使用科学的方法去改进一个东西,并且一次只改变一个东西。修复bug最好的方式是能够重现bug,然后把你的修复替换进去,重新运行你的程序,观察bug不再出现。当然,有时候不止一行代码需要修改,但你在逻辑上仍然需要使用一个独立原子(译者注:以前人们认为原子不可再分,所以用用原子来代表不可再分的东西)的改变来修复这个bug
5+
在修复 bug 时,你可能想要做最小的改变来修复它。你可能看到一些其他需要改进的东西,但不会同时去改进他们。试图使用科学的方法去改进一个东西,并且一次只改变一个东西。修复 bug 最好的方式是能够重现 bug,然后把你的修复替换进去,重新运行你的程序,观察 bug 是否不再出现。当然,有时候不止一行代码需要修改,但你在逻辑上仍然需要使用一个独立原子(译者注:以前人们认为原子不可再分,所以用用原子来代表不可再分的东西)的改变来修复这个 bug
66

7-
有时候,可能实际上有几个bug,但表现出来好像是一个。这取决于你怎么定义bug,你需要一个一个地修复它们。有时候,程序应该做什么或者原始作者想要做什么是不清晰的。在这种情况下,你必须多加练习,增加经验,评判并为代码赋予你自己的认知。决定它应该做什么,并注释/或用其他方式阐述清楚,然后修改代码以遵循你赋予的含义。这是一个进阶或高级的技能,有时甚至比一开始用原始的方式创建这些代码还难,但真实的世界经常是混乱的。你必须修复一个你不能重写的系统。
7+
有时候,可能实际上有几个 bug,但表现出来好像是一个。这取决于你怎么定义 bug,你需要一个一个地修复它们。有时候,程序应该做什么或者原始作者想要做什么是不清晰的。在这种情况下,你必须多加练习,增加经验,评判并为代码赋予你自己的认知。决定它应该做什么,并注释或用其他方式阐述清楚,然后修改代码以遵循你赋予的含义。这是一个进阶或高级的技能,有时甚至比一开始用原始的方式创建这些代码还难,但真实的世界经常是混乱的。你必须修复一个你不能重写的系统。
88

99
Next [如何使用日志调试](04-How to Debug Using a Log.md)
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# 如何使用日志调试
22

3-
*Logging*(日志)是一种编写系统的方式,可以产生一系列信息记录,被称为log*Printlining*只是输出简单的,通常是临时的日志。初学者一定要理解并且使用日志,因为他们对编程的理解是局限的。因为系统的复杂性,系统架构必须理解与使用日志。理想地,程序运行时,日志产生的信息的数量需要是可配置的。通常,日志提供了下面三个基本的优点:
3+
*Logging*(日志)是一种编写系统的方式,可以产生一系列信息记录,被称为 log*Printlining* 只是输出简单的,通常是临时的日志。初学者一定要理解并且使用日志,因为他们对编程的理解是局限的。因为系统的复杂性,系统架构必须理解与使用日志。在理想的状态下,程序运行时产生的日志信息数量需要是可配置的。通常,日志提供了下面三个基本的优点:
44

5-
- 日志可以提供一些难以重现的bug的有效信息,比如在产品环境中发生的、不能在测试环境重现的bug
5+
- 日志可以提供一些难以重现的 bug 的有效信息,比如在产品环境中发生的、不能在测试环境重现的 bug
66
- 日志可以提供统计和与性能相关的数据,比如语句间流逝过的时间。
77
- 可配置的情况下,日志允许我们获取普通的信息,使得我们可以在不修改或重新部署代码的情况下调试以处理具体的问题。
88

9-
需要输出的日志数量总是一个简约与信息的权衡。太多的信息会使得日志变得昂贵,并且造成[*滚动目盲*](../../4-Glossary.md),使得发现你想要的信息变得很困难。但信息太少的话,日志可能不包含你需要的信息。出于这个原因,让日志的输出可配置是非常有用的。通常,日志中的每个记录会标记它在源代码里的位置,执行它的线程(如果可用的话),时间精度,并且,通常有,一些额外的有效信息,比如一些变量的值,剩余内存大小,数据对象的数量,等等。这些日志语句撒遍源码,但只出现在主要的功能点和一些可能出现危机的代码里。每个语句可以被赋予一个等级,并且将会在系统设置输出这个等级时输出这个记录。你应该设计好日志语句来标记你预期的问题。预估测量程序表现的必要性。
9+
需要输出的日志数量总是一个简约与信息量的权衡。太多的信息会使得日志变得昂贵,并且造成[*滚动目盲*](../../4-Glossary.md),使得发现你想要的信息变得很困难。但信息太少的话,日志可能不包含你需要的信息。出于这个原因,让日志的输出可配置是非常有用的。通常,日志中的每个记录会标记它在源代码里的位置,执行它的线程(如果可用的话),时间精度,并且通常还有一些额外的有效信息,比如一些变量的值,剩余内存大小,数据对象的数量,等等。这些日志语句撒遍源码,但只出现在主要的功能点和一些可能出现危机的代码里。每个语句可以被赋予一个等级,并且只有在系统被配置成输出相应等级的记录的时候才输出这个等级的记录。你应该设计好日志语句来标记你预期的问题。预估测量程序表现的必要性。
1010

11-
如果你有一个永久的日志,printling现在可以用日志的形式来完成,并且一些调试语句可能会永久地加入日志系统。
11+
如果你有一个永久的日志,printling 现在可以用日志的形式来完成,并且一些调试语句可能会永久地加入日志系统。
1212

1313
Next [如何理解性能问题](05-How to Understand Performance Problems.md)

0 commit comments

Comments
 (0)