作者 | Adam Zerner

译者 | 张健欣

策划 | 万佳

有一句广为流传的话:代码是写给人看的,而不是为了给机器执行。然而,编写人类易于阅读的代码,这说起来容易做起来难。这件事需要花费几年时间去学习,花费几十年才能掌握。我也许可以提供一个捷径:像一名教育者一样思考代码质量。“捷径”这个词表达的能力很强大。这并不是一个捷径。但我认为,这种观点很重要。Alan Kay 说过,观点抵得上 80 点智商。

1

了解你的受众

Rails

在工作中,我们使用 Rails、Node 和 Vue。主应用程序是用 Rails 写的,前端的一部分是用 Vue 写的,然后我们还用 Node 编写了一些 lambda 函数。在理想世界中,Rails 人员写 Rails,Node 人员写 Node,Vue 人员写 Vue,但实际情况并非如此。实际上,我们会遇到这样的情况:Node 和 Vue 人员不得不阅读或编写 Rails 代码。

委婉地说,Rails 是一个古怪的框架,会发生很多奇怪的事情,约定大于配置。例如,如果你看到如下代码:

# app/controllers/api/foo/bar/baz_controller.rb
def showend

Rails 会自动在app/views/api/foo/bar/baz内部寻找show.html.erbshow.jbuilder来作为响应。但如果你不是一个 Rails 开发者... 你不会知道这些!你所看到的只是一个空方法,它似乎什么也没做!更重要的是,你没办法搞明白。答案不是隐藏在一些父类或 mixin 中,而是藏在这种部落知识的书中。

https://guides.rubyonrails.org/?fileGuid=rU8e3yc0h4Mztn6T

我不确定这个 controller actions 的示例是不是一个好例子。实际上,这是你很快就能学会的,或者你团队中的某人可以马上发现并帮助你的。但是在其他一些情况下,你可以用 Rails 做一些古怪的事情,而只有那些正好掌握这些部落知识的人能够理解。

当你在一个拥有经验丰富的 Rails 专家的团队工作中时,这不是个问题。事实上,这些古怪的东西能够帮助 Rails 专家变得更高效。但是,如果你工作在一个对 Rails 都是新手的团队中时,这些菜鸟绝对会陷入绝望和沮丧中。

这就是需要像一名教育者一样思考的地方。假设你是一名教授。如果你站在一小群博士面前,举办一个高度专业化、集中化的研讨会,你可以使用花哨的术语等而不用担心这些术语超出观众的认知。但是... 如果你发现自己站在一座演讲厅中面对一群本科生,那么,使用这些术语就不是一个明智的选择。

对于 Rails 也是这样。问题不在于某样东西是“最佳实践”还是“Rails 编程方式”,而是在于它对你的受众是否有意义。

Angular

我过去犯过这个错误。

https://adamzerner.bearblog.dev/using-obscure-features-of-a-programming-language/?fileGuid=rU8e3yc0h4Mztn6T

在以前的一家公司,我们使用 Rails、Angular 和 Python。我是那个“使用 Angular 的家伙”。团队的其他人大部分都是 Rails 人员。

我对于自己对 directives 的使用感到少许得意。但我的上司叫我停止使用这些东西,坚持使用正常的 controllers。他甚至提到,他的理由是因为这是大部分软件开发人员如果进入一个代码库期待看到的编程方式。

当时,我认为很明显,他错了。我看到的 Anguar 专家撰写的所有视频和书籍,都告诉我这些是最佳实践。他们都是专家,而且他们看起来比我的上司更了解 Angular,所以我认为我应该相信这些专家而不是我的上司。至少我是这么想的。

ELI5

在《函数式编程为什么重要》一书中,Eric Normand 谈到了一个有关游戏树的程序。他说,在大学里,他用一堆for循环写过一个类似的程序。然后,他谈到了一篇论文作者采取的方法:

他的解决方案,当然更简洁,是... 非常简洁。非常简洁。我也不知道我能不能读懂它。

这说明了一些问题,因为 Eric Normand 是一名函数式编程方面的专家。如果你的代码过于简洁,以至于即使是领域专家也很费劲才能理解它,那么这可能不是你应该追求的目标。在同一期播客中,Normand 反思函数式编程语言 / 代码是否过于简洁。

这让我想起 EliezerYudkowsky 在《Explainers Shoot High. Aim Low!》中写的有些东西:

  • 几年前,一位著名的科学家曾告诉我,他是如何以比平时低得多的技术水平为自己的领域撰写一篇解释性文章的。他认为这对该领域以外的学者,甚至报道者,都会有用。这篇论文最终成为他所在领域最受欢迎的论文之一,被引用次数超过了他所写的其他任何文章。*

  • 并不是他的同行科学家都很愚蠢,而是我们往往大大低估了正确理解事物所需的努力。*

我认为在编写代码时记住这一点是一件好事。

降低水平?

“了解你的受众”并不一定意味着你需要将所有东西都降低水平。

想想大学教授教本科生。在学期开始的时候,可能需要慢慢来,在解释事物时要非常慎重。但是,随着特定术语和概念开始为全班所熟悉,自由地使用这些术语可能就更好。

同样,当有一些术语和概念很难被人们理解时,慢慢介绍这些概念而不是完全避免使用这些概念可能更有意义,这样学生们就可以学习这些概念并在将来使用它们。

我认为问题的关键是,像往常一样,这涉及到权衡问题,你需要意识到这些问题并在你的决策中加以考虑。

2

可视化

教育者使用什么工具来教学?幻灯片、教科书、讲座视频、演示、测验、办公时间、家庭作业、图表、模拟,等等。当我们编写代码时,这些工具对我们开发者还有使用意义吗?

其中一些是不适用的。例如,一个完整的教学视频。其它则是有点儿傻。例如,测验。但是,我认为至少有些工具是可以使用的。

录像

让我们重新考虑一下讲座视频。对于你写的每个 10 行函数代码,进行一个深入的讲解是不现实的。但是对于更大的代码块呢?对于一个 lambda 函数或者一个重要的模块进行深入的讲解,我认为是有意义的。

事实上,我认为类似的事情已经发生了。当处理代码库中一些自己不太熟悉的部分时,我最喜欢的一个小技巧是使用git blame来增进自己对代码的理解。我会看到大部分代码是谁写的,在 Slack 上交流,然后他们会花费大约 20 分钟时间给我进行大致的讲解。我觉得这非常有用。那么,为什么不像这样记录一份讲解,并在文件头部以代码注释的形式链接到这份讲解呢?

我认为最大的原因是可维护性。随着代码库的演变,视频将变得陈旧过时。当代码注释这样的东西变得过时了,很容易编辑它们,但是对于一个视频,你不能真正地编辑从 17:34 到 21:40 的片段。至少不太容易。

我对这个观点有一些反对意见。是的,它最终会变得陈旧,但那又怎样?如果代码更改很小,视频就仍不会过时,其收益大于成本。如果代码变化很大,那么你可以再花 20 分钟录制一份讲解。即使出于任何原因,团队没有同步,最终导致在代码变化很大时没有更新视频,我也不认为这会造成任何重大伤害。如果有人点击它并开始观看,他们会很快意识到这个视频过时了并停止观看。

另一个我反对的观点是录制视频很费时。那简直是胡说八道。我们已经花费了大量时间来尽量产出高质量的代码:前期工作、重构、代码评审,等等。花 20 分钟时间,以一种随意的意识流的方式对着镜头进行讲解,与你花的其它时间相比是微不足道的。我认为这种观点真正要表达的是,录制视频给人的感觉像是要做一件大事。

图表

好吧,让我们看看其它工具,图表怎么样?

我觉得图表很棒!幸运的是,它们已经被一些人采用了。特别是在架构层次,来说明不同的模块是如何连接到另外一个模块的。

然而,我感觉图表仍然没有得到充分利用。

下面是一个例子,说明如何将它用于架构级别较低的事务。对于“水容量最多的容器”问题,以下视觉参考会非常有用:

在我看来,前端代码领域是图表尤其未被充分利用的一个领域。我认为在代码旁边伴随图表很酷,这样你就可以放一张图片展示一个 React 组件是什么样子的。是的,你可能已经通过打开一个网页,并且使用检查工具(或者仅仅通过常识)来确定哪些代码对应哪些 UI,但这样做会有点儿小别扭。也许减少这些小别扭是一个不错的主意。

特别是我想到的以下几点。你的文本编辑器中应该有这个插件。当你的文本编辑器看到一段代码注释后面跟着一个以.jpg结尾的 URL

// https://example.com/code-images/modal.jpg

它左边会有一个小的折叠 / 展开箭头,当你点击展示时,它会内联展示图片!我想这样会方便很多。

我的朋友 Brendan Long 有一个好主意:使用某种插件根据这些组件的一些模拟数据自动生成这些图表或图片。

总之,这条思路不仅仅是我个人的强烈感觉,更是一种猜想,但确实很有趣!

3

Clean code

让我们抛开视频之类的边缘话题,回到一个我们更熟悉的世界。在这个世界里,我们尝试以一种更容易被他人理解的方式编写代码。

就像我在文章开头所说的,如果你将自己当作一个教导团队其他人如何使用这段代码的人,很多公认的关于 clean code 的想法都会自然而然地产生。描述性变量名、模块化、恰当的缩进,等等。我还从 clean-code-javascript“借”了一些示例过来。

差的代码

// What the heck is 86400000 for?setTimeout(blastOff, 86400000);

好的代码

// Declare them as capitalized named constants.const MILLISECONDS_IN_A_DAY = 60 * 60 * 24 * 1000; //86400000;
setTimeout(blastOff, MILLISECONDS_IN_A_DAY);

差的代码

const address = "One Infinite Loop, Cupertino 95014";const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;saveCityZipCode(  address.match(cityZipCodeRegex)[1],  address.match(cityZipCodeRegex)[2]);

好的代码

const address = "One Infinite Loop, Cupertino 95014";const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;const [_, city, zipCode] = address.match(cityZipCodeRegex) || [];saveCityZipCode(city, zipCode);

差的代码

function emailClients(clients) {  clients.forEach(client => {    const clientRecord = database.lookup(client);    if (clientRecord.isActive()) {      email(client);    }  });}

好的代码

function emailActiveClients(clients) {  clients.filter(isActiveClient).forEach(email);}function isActiveClient(client) {  const clientRecord = database.lookup(client);  return clientRecord.isActive();}

差的代码

function addToDate(date, month) {  // ...}const date = new Date();// It's hard to tell from the function name what is addedaddToDate(date, 1);

好的代码

function addMonthToDate(month, date) {  // ...}const date = new Date();addMonthToDate(1, date);

代码注释

我比较倾向于传统的日志类注释的写法

/** * 2016-12-20: Removed monads, didn't understand them (RM) * 2016-10-01: Improved using special monads (JP) * 2016-02-03: Removed type-checking (LI) * 2015-03-14: Added combine with type-checking (JR) */function combine(a, b) {  return a + b;}

位置标记

// Scope Model Instantiation$scope.model = {  menu: "foo",  nav: "bar"};// Action setupconst actions = function() {  // ...};

明显的注释

function hashIt(data) {  // The hash  let hash = 0;// Length of string  const length = data.length;// Loop through every character in data  for (let i = 0; i < length; i++) {    // Get character code.    const char = data.charCodeAt(i);    // Make the hash    hash = (hash << 5) - hash + char;    // Convert to 32-bit integer    hash &= hash;  }}

应该避免这样使用位置注释和明显的注释。然而,我对于“好代码通常是它自身的文档”这一点有所保留。我通常默认假定:

  • 我注意到人们在工作中使用解释性注释,而我不会在那些场景中这样做,但我发现这些注释确实很有用;

  • 这种“像教育者一样思考”的框架让我觉得它们很有价值。

我不想争论这些注释是没有被充分利用的。那很难。相反,我只是想建议你据此重新评估自己的立场。下次编写函数时,问问你自己,是否会有其他人会很难理解你所写的代码。问问你自己,是否可以添加一些不会显得多余和臃肿的注释。问问你自己,一名教育者会怎么做。

4

后记:像个可用性设计师一样思考?

这篇文章是关于你在写代码时像一名教育者一样思考。我认为这个想法很好,但这是唯一的好想法吗?填空:“像个 ____ 一样思考代码质量”。还有哪些有意义的想法?

我想到的最重要的是“可用性设计师”。为什么?因为我一直认为,用户测试是人们应该在代码库中做的事情!

想想看,我在文档最后一段所说的:

问问你自己,是否会有其他人会很难理解你所写的代码

可用性设计师一直在做这类事情!这是他们的工作!但不仅如此,他们还做其它哪些事情?

用户测试! 他们不会凭空猜想人们会理解如何使用他们的产品。他们会进行测试。把它放到真正的用户面前,看看有哪些别扭的点。为什么我们不能对代码也这样做呢?

原文链接:

https://adamzerner.bearblog.dev/think-like-an-educator-about-code-quality/?fileGuid=rU8e3yc0h4Mztn6T

逆锋起笔是一个专注于程序员圈子的技术平台,你可以收获最新技术动态最新内测资格BAT等大厂大佬的经验增长自身学习资料职业路线赚钱思维,微信搜索逆锋起笔关注!

如何把 if-else 重构成高质量代码?

编写高性能 Java 代码的最佳实践!

常见代码重构技巧(非常实用)

怎样写出可读性高的代码?

编写高质量代码 改善Python程序的91个建议

点个在看少个 bug ????

像一名教育者一样思考代码质量相关推荐

  1. 一周技术思考(第21期)-人们说脏话的频率是衡量代码质量的唯一标准

    大家好,这里记录,我每周读到的技术书籍.专栏.文章以及遇到的工作上的技术经历的思考,不见得都对,但开始思考总是好的. Bob大叔在<代码整洁之道>这本书中,曾说过,"人们说脏话的 ...

  2. python的有效变量名_python里用变量命名改善代码质量

    编程时,总会遇到各种各样的变量,取一个好的变量名能够有效提高代码的可读性,而且python是一种,动态类型的语言,良好的变量名,能够在编写代码或者再次阅读代码时提高效率. 1. 变量名不要太宽泛,要有 ...

  3. Python 工匠:善用变量来改善代码质量

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由鹅厂优文发表于云+社区专栏 作者:朱雷 | 腾讯IEG高级工程师 『Python 工匠』是什么? 我一直觉得编程某种意义上是一门『手艺 ...

  4. 提高面试代码质量的三要素

    作者总结自己多年面试他人以及被他人面试的经验,发现应聘者可以从代码的规范性.完整性和鲁棒性三个方面提高代码的质量. 程序员在职业生涯中难免要接受编程面试.有些程序员由于平时没有养成良好的编程习惯,在面 ...

  5. 代码质量度量标准_Google研发度量改进实践

    Google改进过程: 本文案例源自:<Measuring Engineering Productivity> 作者:Ciera Jaspen,Google 前言 随着敏捷开发.DevOp ...

  6. 一堂如何提高代码质量的培训课

    今天这堂培训课讲什么呢?我既不讲Spring,也不讲Hibernate,更不讲Ext,我不讲任何一个具体的技术.我们抛开任何具体的技术,来谈谈如何提高代码质量.如何提高代码质量,相信不仅是在座所有人苦 ...

  7. 范钢:一堂如何提高代码质量的培训课

    今天这堂培训课讲什么呢?我既不讲Spring,也不讲Hibernate,更不讲Ext,我不讲任何一个具体的技术.我们抛开任何具体的技术,来谈谈如何提高代码质量.如何提高代码质量,相信不仅是在座所有人苦 ...

  8. 14个提高代码质量的好问题

    阅读本文大概需要 2.6 分钟. 并不是代码写的越多,代码的质量就越高.思考才是. 解决一个问题,打开电脑就手撕代码,最终的结果往往是各种代码问题,经过一系列迭代后,代码积重难返,最终的结果就是推到重 ...

  9. 代码质量随想录(四):排版,不只是为了漂亮

    代码质量随想录(四):排版,不只是为了漂亮 作者: 爱飞翔  发布时间: 2012-06-15 21:18  阅读: 1433 次  原文链接   全屏阅读 [收藏]   写了前三篇(一.二.三)之后 ...

  10. 代码质量随想录(四)排版,不只是为了漂亮

    写了前三篇之后,发现比我预想的效果要好.关注代码质量的朋友还蛮多的,而且很多意见和建议也很有益,指出了我文章中的一些问题. 我这种家庭妇男型的自由职业者来说,在平常写代码的时候可以多停下来,思考一些代 ...

最新文章

  1. 你还在 select * 吗?
  2. DispatcherServlet代码分析及运行过程
  3. 【转】C#调用ADOX创建Access数据文件后关闭连接
  4. __declspec(naked)和__asm编写实践总结
  5. 为了涨薪,我给面试公司看我拿到的offer
  6. WORD如何关闭标题段落分页功能?
  7. 二重循环~~for循环
  8. Tomcat运行流程
  9. matlab fir带通滤波,基于Matlab的FIR带通滤波器设计与实现
  10. 从金蝶k3到金税盘_金蝶k3怎样结转主营业务成本
  11. MD4 算法代码实现
  12. Excel中将汉字(名字)转换为拼音
  13. win10安装VS2008失败解决方案
  14. 推荐系统-协同过滤在Spark中的实现
  15. 【Day3.3】美攻铁道市场零距离接触行驶中的火车
  16. command-codes
  17. 陈式太极拳小架一路拳谱(陈鑫拳架)
  18. 铜仁一中2021高考成绩查询,贵州铜仁第一中学2021年招生录取分数线
  19. 小甲鱼零基础入门python教程视频_小学生作文
  20. 翻译一篇SpiderMonkey GC的文章

热门文章

  1. 图片过渡性放大的小发现
  2. 高考并不能改变什么,接下来两次选择更加重要
  3. Android Studio问题解决之引入github开源库
  4. 供应商如何与FASTENAL建立EDI连接?
  5. 关于研发公司文化不搞小团队自己人说起
  6. P8架构师都要懂的微服务架构深度解析:微服务构建,领域驱动设计
  7. LINUX du查看目录和文件大小
  8. 37_接口多态的综合案例
  9. Vue.js 2.0 学习笔记(五)路由
  10. 转:Linux openssl 生成证书的详解