转载-通过学习原理提高编程能力 Get better at programming by learning how things work

38 阅读12分钟

转载 通过学习事物的运作方式来提高编程能力 --- Get better at programming by learning how things work

当我们谈论如何在编程方面变得更好时,我们经常谈论测试、编写可重用的代码、设计模式和可读性。

所有这些事情都很重要。但在这篇博客文章中,我想谈谈另一种提高编程能力的方法:学习你正在使用的系统是如何工作的!这是我提高编程能力的主要方式。

“事物如何运作”的例子

为了解释我所说的“事物如何运作”,以下是一些不同类型的编程和你可以学习它们如何运作的示例。

 前端JS

  • 事件循环的工作原理
  • HTTP方法,如GET和POST
  • DOM是什么以及你可以用它做什么
  • 同源策略和跨域资源共享(CORS)

 CSS:层叠样式表

  • 行内元素与块级元素的渲染方式有所不同
  • 默认流程是什么
  •  flexbox如何工作
  • CSS如何决定将哪个选择器应用于哪个元素(层叠样式表中的“层叠”部分)

 系统编程

  • 堆和栈之间的区别
  • 虚拟内存的工作原理
  • 二进制中如何表示数字
  • 符号表是什么
  • 外部库的代码如何加载(例如动态/静态链接)
  • 原子指令和互斥锁的区别

你可以使用某物而不了解其工作原理(这也是可以的!)

我们与许多不同的系统合作,期望每个人都对所有系统的所有内容都有全面的了解是不合理的。例如,许多人编写发送电子邮件的程序,而其中大多数人可能并不完全了解电子邮件的工作原理。电子邮件非常复杂!这就是为什么我们需要抽象化的原因。

但是,如果你正在认真地处理一些东西(比如CSS、HTTP、goroutines或电子邮件),而且你并不真正理解它们的工作原理,有时候你会遇到问题。

你的错误会告诉你何时需要改进你的心智模型

当我在编程时,如果我对某个东西的工作原理缺乏关键概念,它不会总是以明显的方式显示出来。会发生的是:

  • 由于错误的心理模型,我的程序会出现错误
  • 我将努力快速修复这些错误,并且我将无法找到正确的问题来诊断它们
  • 我感到非常沮丧

我认为能够意识到这一点实际上是一项重要的技能:我慢慢学会了辨认出那种“等等,我真的很困惑,我觉得对这个系统的运作有些不理解,是什么原因呢?”的感觉

成为一名高级开发人员并不是完全了解一切,而是能够迅速意识到自己不知道某些东西并学习它。说到成为一名高级开发人员...

即使是资深开发人员也需要了解他们的系统如何工作

到目前为止,我从未停止学习事物的运作方式,因为我们所涉及的系统类型如此之多!

例如,我了解很多关于C程序和Web编程的基本原理(就像这篇文章开头的例子),但是当涉及到图形编程/OpenGL/GPU时,我对基本概念知之甚少。有时候,我会发现自己对一个我以为了解的系统缺少了很多信息,比如去年我发现自己对CSS的工作原理了解得很少。

当你使用一个系统已经有10年经验时,突然意识到自己真的不懂它是令人不爽的("呃,我不是应该早就知道这个了吗?我已经用了这么久!"),但这是正常的!关于计算机有很多知识,而且我们不断地创造新的知识,所以没有人能够掌握每一个细节。

我如何从“我困惑了”到“好的,我明白了!”

当我意识到自己困惑时,我喜欢这样处理:

  1. 我对一个话题感到困惑(“嘿,当我在我的Javascript程序中写 await 时,实际上发生了什么?”)
  2. 将我的困惑分解为具体的事实性问题,比如“当有一个 await 并且它在等待时,它如何决定下一步运行我的代码的哪个部分?这些信息存储在哪里?”
  3. 通过编写程序、在互联网上阅读或询问他人,找出这些问题的答案
  4. 通过编写一个程序来测试我的理解(“嘿,这就是我遇到异步错误的原因!我可以这样修复它!”)

最后的“测试我的理解”步骤非常重要。理解计算机工作原理的整个目的就是实际编写代码让它们完成任务!

我发现,如果我能够利用我新获得的理解来做一些具体的事情,比如实现一个新功能、修复一个错误,甚至只是编写一个演示该事物如何工作的测试程序,那么它会感觉到比仅仅阅读有更多的实际意义。然后,我更有可能在以后的实践中能够使用它。

只是学习一些事实就能帮助很多

学习事物的工作原理并不需要是一件很大的事情。例如,我以前并不真正了解浮点数是如何工作的,我感到紧张,担心会发生我不理解的奇怪事情。

然后在2013年的某一天,我参加了Stefan Karpinski的一次讲座,他解释了浮点数的工作原理(大致包含了这个漫画中的信息,但还有更多奇怪的细节)。现在,我对使用浮点数感到完全自信!我知道它们的基本限制是什么,以及什么时候不应该使用它们(用于表示大于2^53的整数)。我知道我不知道的东西 - 我知道编写数值稳定的线性代数算法很困难,我不知道如何做到这一点。

将新的事实与你已经知道的信息联系起来

学习一个新事实时,很容易能够背诵一句话,比如“好的,一个字节有8个位”。这是正确的,但又怎样呢?更难(也更有用!)的是能够将这些信息与你已经了解的编程知识联系起来。

例如,让我们来看看这个“一个字节中的8位”的事情。在你的程序中,你可能有字符串,比如“你好”。你已经可以开始问很多关于这个的问题了,比如:

  • 表示字符串“Hello”所使用的内存字节数是多少?(是6个字节-5个字符加上末尾的空字节)
  • “H”这个字母对应的是哪些位呢?(“Hello”的编码将使用ASCII,所以你可以在ASCII表中查找!)
  • 如果你有一个正在运行的程序,它正在打印出字符串“Hello”,你能否查看它的内存并找出这些字节在内存中的位置?你如何做到这一点?

重要的是在这里提出问题并探索你感兴趣的联系 - 也许你对字符串在内存中的表示方式不太感兴趣,但你真的想知道一个心形表情符在Unicode中占用多少字节!或者你想了解浮点数是如何工作的!

我发现当我将新的事实与我已经熟悉的事物(如表情符号、浮点数或字符串)联系起来时,信息会更加牢固。

接下来,我想谈谈获取信息的两种方式:向人提问是与否问题,以及向计算机提问。

如何获取信息:提问是或否问题

当我与比我更了解这个概念的人交谈时,我发现开始时提出一些非常简单的问题会有帮助,其中答案只有“是”或“否”。我之前写过关于如何提出好问题的文章,其中提到了是/否问题,但我非常喜欢它,所以让我们再谈谈它!

我这样做是因为它迫使我准确表达我当前的心理模型,并且因为我认为是/否问题对被问者来说通常更容易回答。

例如,以下是一些不同类型的问题:

  • 请检查您当前的理解是否正确

    • “像素着色器和片段着色器是同一样东西吗?”
  • 你听过的概念之间如何相关

    • “Shadertoy使用OpenGL吗?”
    • 图形卡是否了解三角形?
  • 关于某事的主要目的是什么的高层次问题

    • “mysql orchestrator是否代理数据库查询?”
    • OpenGL比Vulkan对图形卡的控制更多还是更少?

是/否问题让你掌控局面

当我问一些非常开放性的问题,比如“X是如何工作的?”,我发现通常会出现以下两种错误方式:

  1. 这个人开始告诉我一堆我已经知道的事情
  2. 这个人开始告诉我一些我不知道的事情,但这些并不是我真正感兴趣理解的内容

这两件事都令人沮丧,但当然这些都不是他们的错!他们不可能知道我想要关于X的具体信息,因为我没有告诉他们。但是,每次不得不打断别人说“哦,不好意思,那不是我想知道的!”总是让人感到不好。

我喜欢是/否问题,因为虽然它们更难构思,但我更有可能得到我想要的确切答案,也不太可能浪费被问者的时间,让他们解释一堆我不感兴趣的事情。

问是或不是的问题并不总是容易的

当我向某人提问以尝试了解新事物时,有时会发生这种情况:

我:所以,只是为了确认我的理解,它是这样工作的,对吗?

他们:实际上,不,这是完全不同的事情

我(内心惊慌的瞬间)

好的,让我思考一分钟关于我下一个问题

得知我的心理模型完全错误并不会让人感到好,尽管这是非常有帮助的信息。提出这种非常具体的问题(尽管更有效!)会让你处于比提出更广泛的问题更脆弱的位置,因为有时你必须透露你完全错误的具体事情!

当发生这种情况时,我喜欢说我要花一分钟将这个新事实融入我的思维模式,并思考下一个问题。

好的,这就是我对于是/否问题的爱的插曲的结束 :)

如何获取信息:向计算机询问

有时候当我试图回答自己的问题时,没有人可以问,我会去谷歌或搜索文档,但找不到任何答案。

但是计算机的美妙之处在于,你通常可以通过向计算机提问来获得关于计算机的答案!

以下是我曾经提出的一些问题和我进行的计算机实验的几个例子(来自以前的博客文章):

  • 原子操作比互斥锁快还是慢?(博客文章:尝试使用互斥锁和原子操作)
  • 如果我将一个用户添加到一个组中,那么作为该用户运行的现有进程会有新的组吗?(博客文章:Linux上的组是如何工作的?)
  • 在Linux上,如果你有一个监听在0.0.0.0的服务器,但你没有任何网络接口,你能连接到那个服务器吗?(博客文章:什么是网络接口?)
  • SQLite数据库中的数据实际上是如何在磁盘上组织的?(博客文章:SQLite是如何工作的?第一部分:页面!)

询问计算机是一种技能

学习如何将“我对X感到困惑”转化为具体问题,并将该问题转化为可以在计算机上运行的实验来明确回答它,确实需要时间。

但这是一个非常强大的工具!如果你不仅限于只能通过谷歌搜索、文档中的内容或周围人所知的东西,那么你可以做更多的事情。

请注意你仍然不理解的内容

就像我之前说的,重点不是要理解每一件事情。但特别是当你变得更加资深时,意识到自己不知道的东西是很重要的!例如,以下是我不知道的五件事情(在一个非常长的列表中):

  • 数据库事务/隔离级别的工作原理
  • 顶点着色器如何工作(在图形中)
  • 字体渲染的工作原理
  • BGP / peering的工作原理
  • Python中多重继承的工作原理

我现在真的不需要知道那些东西是如何工作的!但是有一天我很确定我会需要知道数据库事务是如何工作的,我知道当那一天来临时我可以学会它 :)

有人读了这篇帖子问我:“你如何找出自己不知道的东西?”我没有一个好的答案,所以我很想听听你的想法!

感谢Haider Al-Mosawi、Ivan Savov、Jake Donham、John Hergenroeder、Kamal Marhubi、Matthew Parker、Matthieu Cneude、Ori Bernstein、Peter Lyons、Sebastian Gutierrez、Shae Matijs Erisson、Vaibhav Sagar和Zell Liew阅读本草案。