向 Linus Torvalds 学习让编出的代码具有 “good taste”
在最近关于 Linus Torvalds 的一个采访中，这位 Linux 的创始人，在采访过程中大约 14:20 的时候，提及了关于代码的 “good taste”。good taste？采访者请他展示更多的细节，于是，Linus Torvalds 展示了一张提前准备好的插图。
编程 代码
116.31.81.182
学习了
来自广东广州的 Firefox 53.0|Ubuntu 用户
2017-05-11T09:18:14.000
183.208.31.247
原先的 10 行代码现在减少为 4 行。<br />
明明是5行好吧。这智商。
来自江苏南京的 Firefox 52.0|Windows 10 用户
2017-05-11T10:26:49.000
183.208.31.247
对不起，确实是4行。
来自江苏南京的 Firefox 52.0|Windows 10 用户
2017-05-11T10:27:58.000
153.99.93.231
网格的列子有点搞笑了吧……<br />
好像也是在这里看到的一篇文章，大意就是写代码之前要先把问题想清楚，而不是一边写一边“用代码进行思考”
来自江苏的 Chrome 58.0|Windows 7 用户
2017-05-11T11:32:31.000
113.106.15.4
作为一个linux发行版用户我必须发言，因为看到留言中windows用户较多。
来自广东中山的 Firefox 53.0|GNU/Linux 用户
2017-05-11T17:11:34.000
112.117.181.123
我记得以前有相似的文章，代码例子是一样的，但是图片不一样。
来自云南昆明的 Firefox 53.0|GNU/Linux 用户
2017-05-11T18:25:40.000
118.198.228.151
现在CPU都很强大，对于一般开发而言，没必要花很多时间进行代码优化，至少公司不会给你这个时间。现在看中的是产品效率
来自北京的 Android Browser|Android 6.0 用户
2017-05-11T20:39:22.000
222.210.108.99
虽然我不是码农，但我不敢苟同你的看法，硬件技术的发展不是为了低劣的代码～同理优质高效的的代码应该是一个码农应用的追求～
来自四川成都的 Chrome 58.0|GNU/Linux 用户
2017-05-12T09:40:29.000
116.1.20.190
为啥不需要free这个节点？
来自广西桂林的 Chrome Mobile 40.0|Android 6.0 用户
2017-05-12T14:36:40.000
175.0.195.16
有点个人价值追求好伐，人活着不是为了公司kpi
来自湖南长沙的 QQ Browser 9.6|Windows 7 用户
2017-05-12T14:52:49.000
61.188.187.59
看来我写代码中对某些代码看不顺眼是正确的了？见过太多的“bad taste”的代码，以至于我怀疑自己这样过度考虑是否有必要了。
来自四川南充的 Chromium 58.0|Ubuntu 用户
2017-05-12T20:54:40.000
61.52.140.106
上面代码中如果entry是不存在的会怎么样？
来自河南郑州的 Chrome Mobile 58.0|Android 6.0 用户
2017-05-13T11:52:54.000
223.104.3.158
代码的可阅读性比性能更重要。只有写代码的人才会考虑性能。在中国，有哪些公司看中代码性能？真看中性能，何必使用C++，C#，java，还有很多解析语言？在中国，搞代码的，你的工资和你写的代码性能几乎无关
来自北京的 Android Browser|Android 6.0 用户
2017-05-13T12:34:11.000
221.220.214.18
Linus给出的样例代码好像都没法退出while循环。
来自北京的 Opera 44.0|Windows 10 用户
2017-05-13T21:17:40.000
123.123.252.104
+1
来自北京的 Chrome 57.0|GNU/Linux 用户
2017-05-15T08:48:48.000
1.80.3.54
只是个例子，只是为了说明good test&nbsp;&nbsp;，linus不free是他不会吗 , 我很好奇你看文章的重点是什么，是为了找显而易见的错误码？？？
来自陕西西安的 Chrome 58.0|Windows 7 用户
2017-05-17T17:55:32.000
58.243.250.186
不需要free的原因有很多，可能是将内存管理交给调用者。也可能采用了内存池的方法，无需free。
来自安徽合肥的 Chrome 47.0|Windows 10 用户
2017-06-13T18:00:56.000
96.9.70.200
完成工作和自身价值归并为一才有更好的未来,仅仅完成工作,那么35岁危机很快就来了.
来自美国的 Chrome 100.0|Windows 10 用户
2022-05-04T11:54:12.000
在最近关于 Linus Torvalds 的一个采访中，这位 Linux 的创始人，在采访过程中大约 14:20 的时候，提及了关于代码的 “good taste”。good taste？采访者请他展示更多的细节，于是，Linus Torvalds 展示了一张提前准备好的插图。
![](/data/attachment/album/201705/13/092618z2vyzoqzriqzavcf.jpg)


在[最近关于 Linus Torvalds 的一个采访中](https://www.ted.com/talks/linus_torvalds_the_mind_behind_linux)，这位 Linux 的创始人，在采访过程中大约 14:20 的时候，提及了关于代码的 “good taste”。good taste？采访者请他展示更多的细节，于是，Linus Torvalds 展示了一张提前准备好的插图。






他展示的是一个代码片段。但这段代码并没有 “good taste”。这是一个具有 “poor taste” 的代码片段，把它作为例子，以提供一些初步的比较。


![Poor Taste Code Example](/data/attachment/album/201705/11/072252rlm1gii96i06pm1g.png)


这是一个用 C 写的函数，作用是删除链表中的一个对象，它包含有 10 行代码。


他把注意力集中在底部的 `if` 语句。正是这个 `if` 语句受到他的批判。


我暂停了这段视频，开始研究幻灯片。我发现我最近有写过和这很像的代码。Linus 不就是在说我的代码品味很差吗？我放下自傲，继续观看视频。


随后， Linus 向观众解释，正如我们所知道的，当从链表中删除一个对象时，需要考虑两种可能的情况。当所需删除的对象位于链表的表头时，删除过程和位于链表中间的情况不同。这就是这个 `if` 语句具有 “poor taste” 的原因。


但既然他承认考虑这两种不同的情况是必要的，那为什么像上面那样写如此糟糕呢？


接下来，他又向观众展示了第二张幻灯片。这个幻灯片展示的是实现同样功能的一个函数，但这段代码具有 “goog taste”　。


![Good Taste Code Example](/data/attachment/album/201705/11/072253qknxg6vjkhxhh1cw.png)


原先的 10 行代码现在减少为 4 行。


但代码的行数并不重要，关键是 `if` 语句，它不见了，因为不再需要了。代码已经被重构，所以，不用管对象在列表中的位置，都可以运用同样的操作把它删除。


Linus 解释了一下新的代码，它消除了边缘情况，就是这样。然后采访转入了下一个话题。


我琢磨了一会这段代码。 Linus 是对的，的确，第二个函数更好。如果这是一个确定代码具有 “good taste” 还是 “bad taste” 的测试，那么很遗憾，我失败了。我从未想到过有可能能够去除条件语句。我写过不止一次这样的 `if` 语句，因为我经常使用链表。


这个例子的意义，不仅仅是教给了我们一个从链表中删除对象的更好方法，而是启发了我们去思考自己写的代码。你通过程序实现的一个简单算法，可能还有改进的空间，只是你从来没有考虑过。


以这种方式，我回去审查最近正在做的项目的代码。也许是一个巧合，刚好也是用 C 写的。


我尽最大的能力去审查代码，“good taste” 的一个基本要求是关于边缘情况的消除方法，通常我们会使用条件语句来消除边缘情况。你的测试使用的条件语句越少，你的代码就会有更好的 “taste” 。


下面，我将分享一个通过审查代码进行了改进的一个特殊例子。


这是一个关于初始化网格边缘的算法。


下面所写的是一个用来初始化网格边缘的算法，网格 grid 以一个二维数组表示：grid[行][列] 。


再次说明，这段代码的目的只是用来初始化位于 grid 边缘的点的值，所以，只需要给最上方一行、最下方一行、最左边一列以及最右边一列赋值即可。


为了完成这件事，我通过循环遍历 grid 中的每一个点，然后使用条件语句来测试该点是否位于边缘。代码看起来就是下面这样：



```
for (r = 0; r < GRID_SIZE; ++r) {
    for (c = 0; c < GRID_SIZE; ++c) {
        // Top Edge
        if (r == 0)
            grid[r][c] = 0;
        // Left Edge
        if (c == 0)
            grid[r][c] = 0;
        // Right Edge
        if (c == GRID_SIZE - 1)
            grid[r][c] = 0;
        // Bottom Edge
        if (r == GRID_SIZE - 1)
            grid[r][c] = 0;
    }
}

```

虽然这样做是对的，但回过头来看，这个结构存在一些问题。


1. 复杂性 — 在双层循环里面使用 4 个条件语句似乎过于复杂。
2. 高效性 — 假设 `GRID_SIZE` 的值为 64，那么这个循环需要执行 4096 次，但需要进行赋值的只有位于边缘的 256 个点。


用 Linus 的眼光来看，将会认为这段代码没有 “good taste” 。


所以，我对上面的问题进行了一下思考。经过一番思考，我把复杂度减少为包含四个条件语句的单层 `for` 循环。虽然只是稍微改进了一下复杂性，但在性能上也有了极大的提高，因为它只是沿着边缘的点进行了 256 次循环。



```
for (i = 0; i < GRID_SIZE * 4; ++i) {
    // Top Edge
    if (i < GRID_SIZE)
        grid[0][i] = 0;
    // Right Edge
    else if (i < GRID_SIZE * 2)
        grid[i - GRID_SIZE][GRID_SIZE - 1] = 0;
    // Left Edge
    else if (i < GRID_SIZE * 3)
        grid[i - (GRID_SIZE * 2)][0] = 0;
    // Bottom Edge
    else
        grid[GRID_SIZE - 1][i - (GRID_SIZE * 3)] = 0;
}

```

的确是一个很大的提高。但是它看起来很丑，并不是易于阅读理解的代码。基于这一点，我并不满意。


我继续思考，是否可以进一步改进呢？事实上，答案是 YES！最后，我想出了一个非常简单且优雅的算法，老实说，我不敢相信我会花了那么长时间才发现这个算法。


下面是这段代码的最后版本。它只有一层 `for` 循环并且没有条件语句。另外。循环只执行了 64 次迭代，极大的改善了复杂性和高效性。



```
for (i = 0; i < GRID_SIZE; ++i) {
    // Top Edge
    grid[0][i] = 0;

    // Bottom Edge
    grid[GRID_SIZE - 1][i] = 0;
    // Left Edge
    grid[i][0] = 0;
    // Right Edge
    grid[i][GRID_SIZE - 1] = 0;
}

```

这段代码通过每次循环迭代来初始化四条边缘上的点。它并不复杂，而且非常高效，易于阅读。和原始的版本，甚至是第二个版本相比，都有天壤之别。


至此，我已经非常满意了。


那么，我是一个有 “good taste” 的开发者么？


我觉得我是，但是这并不是因为我上面提供的这个例子，也不是因为我在这篇文章中没有提到的其它代码……而是因为具有 “good taste” 的编码工作远非一段代码所能代表。Linus 自己也说他所提供的这段代码不足以表达他的观点。


我明白 Linus 的意思，也明白那些具有 “good taste” 的程序员虽各有不同，但是他们都是会将他们之前开发的代码花费时间重构的人。他们明确界定了所开发的组件的边界，以及是如何与其它组件之间的交互。他们试着确保每一样工作都完美、优雅。


其结果就是类似于 Linus 的 “good taste” 的例子，或者像我的例子一样，不过是千千万万个 “good taste”。


你会让你的下个项目也具有这种 “good taste” 吗？




---


via: <https://medium.com/@bartobri/applying-the-linus-tarvolds-good-taste-coding-requirement-99749f37684a>


作者：[Brian Barto](https://medium.com/@bartobri?source=post_header_lockup) 译者：[ucasFL](https://github.com/ucasFL) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 组织编译，[Linux中国](https://linux.cn/) 荣誉推出

