代码审核 How to Effectively and Politely Critique Code
Programming is often a team effort for introverts. When working as a developer, you will run into decisions other developers have made that you consider mistakes.
编程通常是一项团队工作。 作为一名开发人员,您将遇到其他开发人员已经做出的决定,您认为错误。
It could be a data structure designed with three tightly bound tables. It could be a massive REST API managing all the company's requests with obsolete technology you need to extend or replace. It could include delicate, untested code that when modified, is likely to cause both personal and technical explosion.
它可以是由三个紧密绑定的表设计的数据结构。 它可能是一个庞大的 restapi,用于管理公司的所有需要扩展或替换的过时技术请求。 它可能包括一些微妙的、未经测试的代码,这些代码一旦被修改,很可能会导致个人和技术方面的爆炸。
I have built systems that contained all of these flaws, or worked with the (sometimes catastrophic) results. Working with and learning from other programmers is simply easier when you can critique their code effectively without offending them.
我已经建立了包含所有这些缺陷的系统,或者处理(有时是灾难性的) 结果。 与其他程序员一起工作并向他们学习,只有当你能够在不冒犯他们的情况下有效地批评他们的代码时,才会变得简单。
Typical Code Review Process 典型的代码审查过程
The first step in almost any writing is to 1) write something, 2) have a group of your peers read through it, and 3) adjust to their commentary.
几乎任何写作的第一步都是: 1) 写点东西,2) 让你的一群同伴通读它,3) 调整他们的评论。
The importance of peer review is mirrored in the fine arts, where feedback on the semantics of your decisions is a significant part of any class. When learning to program, however, you generally receive a series of close-ended problems sized for individual consumption, and peer review of your code is rare. This did not prepare most of us for a professional life in programming.
同行评议的重要性在美术作品中得到了反映,在美术作品中,关于你决策的语义学反馈是任何课程的重要组成部分。 但是,在学习编程时,您通常会收到一系列针对个人消费的封闭式问题,而且很少对代码进行同行审查。 这并没有让我们中的大多数人为编程的职业生涯做好准备。
Reading the code others have written, understanding it, and providing constructive criticism is a subtle skill. Adding to this difficulty, the individuals being critiqued are often introverts. Thus, when I am reading code written by a student or someone on my team, I have three primary concerns:
阅读其他人编写的代码,理解它,并提供建设性的批评是一项微妙的技能。 更加困难的是,被批评的人往往是内向的人。 因此,当我阅读学生或团队成员编写的代码时,我有三个主要关注点:
Team Dynamics: how do I improve my working relationship with this person and their code? 团队动力学: 我如何改善我与这个人和他们的代码的工作关系?
Code Standards: how does this code conform to how it should look? 代码标准: 这个代码应该是什么样子的?
Reusability/Extensibility: how easily/effectively can this code be expanded upon, maintained, and rebuilt in the future? 可重用性 / 可扩展性: 将来如何轻松 / 有效地扩展、维护和重建这些代码?
Team Dynamics 团队动力
Team dynamics are important in software development because nobody can know everything. A software development team usually consists of developers with experience and skills enabling them to build approximately the same things.
团队动力学在软件开发中很重要,因为没有人可以知道所有的事情。 软件开发团队通常由具有经验和技能的开发人员组成,使他们能够构建大致相同的东西。
Most software teams that I have worked on are culturally diverse. Once, my Indian boss told me, "Where I grew up, if you weren't in the top 5% by the time you were 12, you were screwed." Thus, as a wide variety of experiences leads to different communication styles, communication and soft skills are an important part of a developer's skill set.
我工作过的大多数软件团队都是文化多元化的。 有一次,我的印度老板告诉我,"在我长大的地方,如果你 12 岁的时候没有进入前 5% ,你就完蛋了。" 因此,由于各种各样的经历导致不同的沟通风格,沟通和软技能是开发人员技能集的重要组成部分。
Soft Skills and Emotional Intelligence 软技能与情商
Sometime in the 60's or 70's the US Army coined the term 'soft skills.' Now, often referred to as 'Emotional Intelligence,' (for further reading, the work of Daniel Goleman is fairly approachable) these skills are different from raw, memorized knowledge.
在 60 年代或 70 年代的某个时候,美国陆军创造了"软技能"这个词 现在,通常被称为"情感智力"(对于进一步的阅读,丹尼尔 · 戈尔曼的作品是相当平易近人的) ,这些技能不同于原始的记忆知识。
Programming consists of many 'hard skills' (e.g. C driver programming, MongoDB querying, and Apache server administration) — most of them are fairly ephemeral in comparison to a career. Anyone can copy JavaScript off the Internet and make a flashing button.
编程由许多"硬技能"组成(例如 c 驱动程序编程、 MongoDB 查询和 Apache 服务器管理)ーー与职业生涯相比,它们中的大多数都是相当短暂的。 任何人都可以从互联网上复制 JavaScript 并制作一个闪动按钮。
Convincing someone their flashing button is poorly constructed or aesthetically ugly is often more difficult. Soft skills are important in building a consensus motivating forward progression, and maintaining that consensus regarding forward progression. And the easiest, most effective way I have found to convince people to move forward is this: say something nice first.
让别人相信他们的闪动按钮是粗制滥造或美观丑陋的往往更加困难。 软技能对于建立共识、推动向前进步、保持向前进步的共识非常重要。 我发现最简单、最有效的说服人们前进的方法就是: 先说点好听的。
Say Something Nice First 先说点好听的
O'Reilly once assembled a book called, Beautiful Code, and I can't remember many people in the book citing their own code for samples.
O'reilly 曾经汇集了一本书,叫做《美丽的代码》 ,我不记得书中有多少人引用他们自己的代码作为样本。
This means if you say something nice to somebody about their code, it may be the first nice thing they've ever heard about it. When you start out with, "Wow, this solves problem X very elegantly, right here," you are building a little goodwill within your team. Also, if you have to look hard for this positive point, you've learned something. Often a comparatively awkward approach merely appears that way because it has an entirely different set of priorities and steps. In addition, when an approach looks ineffective to me, when I look for something worth salvaging, I end up making a specific list of issues within the code.
这意味着,如果你对某人说了一些关于他们代码的好话,这可能是他们听到的第一件好事。 当你开始说,"哇,这很好地解决了问题 x,就在这里,"你就在你的团队中建立了一点善意。 另外,如果你不得不努力寻找这个积极的观点,你已经学到了一些东西。 通常情况下,一个相对尴尬的方法仅仅是因为它有一套完全不同的优先事项和步骤。 此外,当一种方法对我来说无效时,当我寻找一些值得挽救的东西时,我最终会在代码中列出一个具体的问题列表。
Be Specific in Your Commentary and Criticism 在你的评论和批评中要具体
Speaking in very specific terms about awkward code is an effective way to help someone improve it, as well as learn from each other. If you look at the classic FizzBuzz post at Coding Horror, you will see that there are a thousand ways to make even the simplest program go, in all sorts of languages. Here are two pseudocode functions for finding the last day of a month:
用非常具体的术语谈论笨拙的代码是帮助别人改进代码以及相互学习的有效方法。 如果你看一下 Coding Horror 上的经典 FizzBuzz 帖子,你会发现即使是最简单的程序,也有上千种方法可以用各种语言运行。 这里有两个伪代码函数用于查找一个月的最后一天:
Date returnLastDayIterative(DateTime dayIn):
Date myDate = dayIn.date
while (myDate.month < dayIn.month):
myDate.dateAdd (1 day)
Return myDate.day.dateAdd(-1 second)
Date ldy(DateTime i):
Date m = i.date
If m.dayOfMonth > 28:
m = m - 3
m.month = m.Month + 1
m.day = 1
Return m.dateAdd(-1 second)
What are the good and bad things you see about each?
你看到的每一件事的好处和坏处是什么?
Algorithm 1 is linear; it's a single for-loop in code, doesn't have much logic, and gets the right answer every time. It's also cross-calendar compatible for non-Gregorian calendars.
算法 1 是线性的; 它只是代码中的一个 for 循环,没有多少逻辑,每次都能得到正确的答案。 它也是交叉日历兼容的非公历日历。
Algorithm 2 is probably more efficient computationally, but depends on months being of uniform size within 3 days (Mars or Jupiter months might be longer) and requires two library functions (month_add and date_subtract).
算法 2 的计算效率可能更高,但是依赖于月份在 3 天内的大小是一致的(火星或木星的月份可能更长) ,并且需要两个库函数(月份加和日期)。
Both find a solution. On balance, since date-time functions can be heavy when applied to large datasets, I personally prefer algorithm 2 for its linear performance results. Semantically, these are simple functions but if I had to maintain one, I'd probably prefer to rewrite the first function over the second. To engender this kind of focused, productive communication, what will often help is code standards.
双方都找到了解决方案。 总的来说,由于日期-时间函数在应用于大型数据集时可能比较繁重,我个人更喜欢算法 2,因为它的线性性能结果。 从语义上讲,这些都是简单的函数,但如果必须维护一个,我可能更喜欢重写第一个函数,而不是第二个。 为了形成这种集中的、富有成效的交流,代码标准通常会有所帮助。
Code Standards 代码标准
Not every team has formal code standards (this is an understatement).
不是每个团队都有正式的代码标准(这是一个轻描淡写的说法)。
The default standard for many teams is: "This is what manager X of programmer Y accepted as gold code on release day."
许多团队的默认标准是:"这是程序员 y 的 x 经理在发布日接受的黄金代码。"
But when you are looking at someone's code and asking them to modify something in a way that requires their effort, code standards help. Most of the time, code standards are about things you don't want to care about so you can focus on what matters more. Rather than worrying about whether each file is indented with spaces or tabs, you can focus on not dereferencing that NULL pointer.
但是当你查看某人的代码并要求他们修改一些需要他们付出努力的东西时,代码标准会有所帮助。 大多数时候,代码标准是关于你不想关心的事情,所以你可以专注于更重要的事情。 与其担心每个文件是否使用空格或制表符缩进,不如专注于不取消对 NULL 指针的引用。
Code standards will be very different for different environments, though.
不过,对于不同的环境,代码标准会有很大的不同。
When I tested internal loan software at Wells Fargo, we had hundreds of end-to-end tests to run before putting a release on staging servers. In a tiny startup, though, your flagship product may have only a smattering of end-to-end testing (or none at all) that you run once before release. Or, more appropriately, a selective battery of unit tests run by Jeeves, TeamCity, or whatever tool before auto-migration, and a small set of well-considered hand-tests.
当我在富国银行测试内部贷款软件的时候,我们有数百个端到端的测试要运行,然后才把一个版本发布到登台服务器上。 不过,在一个小型的初创企业中,您的旗舰产品可能只有少量的端到端测试(或者根本没有) ,在发布之前只运行一次。 或者,更恰当地说,是由 Jeeves、 TeamCity 或者其他工具在自动迁移之前运行的一组有选择的单元测试,以及一小组经过深思熟虑的手工测试。
Code Standards Will Vary By Environment 代码标准因环境而异
Coding standards will change per environment, language, company, end-use, and testing requirements, so a discussion of which standard to use is important and can make communication clearer.
编码标准将根据环境、语言、公司、最终用途和测试需求而改变,因此讨论使用哪种标准是重要的,可以使沟通更加清晰。
"Hey, I see you used a couple variables here that were declared inline. Do you think we should do that, or declare them at the top of the function? It seems it would be easier to read that way, and agrees with [Agreed Upon Convention X]."
"嘿,我看到您在这里使用了一些声明为内联的变量。 你认为我们应该这样做,还是在函数顶部声明它们? 这种方式似乎更容易阅读,而且与《第十条约定》(Agreed Upon Convention x) 一致。"
But remember, this will change depending on the situation. When you write Java, it is a completely different animal from when you write SQL.
但是请记住,这会随着情况的不同而改变。 编写 Java 时,它与编写 SQL 时完全不同。
My team once hired a developer whose experience was extensive in Java but not Python — our primary language. We handed them a standard code-sample request. Instead of the fairly simplistic Django - Python - Postgres result we expected, we received something built with Spring. There were interfaces, and abstractions, and a factory or two.
我的团队曾经雇佣过一个开发人员,他在 Java 方面有着丰富的经验,但对我们的主要语言 Python 却不甚了解。 我们给了他们一个标准的代码示例请求。 我们没有得到我们期望的相当简单的 Django-Python-Postgres 结果,而是得到了一些用 Spring 构建的内容。 有接口、抽象和一两个工厂。
We examined it closely, because it was...baroque to us (well written Java is almost always going to look baroque to a Python programmer). Java programmers are trained to be relentlessly abstract, so their code is reusable in a wide variety of circumstances.
我们仔细研究了它,因为它... 对我们来说是巴洛克式的(编写良好的 Java 对于 Python 程序员来说几乎总是看起来是巴洛克式的)。 Java 程序员被训练成无情地抽象,所以他们的代码可以在各种环境下重复使用。
When you critique a (nowadays, probably logically generated) SQL block, in direct opposition, you want it to be simple.
当您批评一个(现在,可能是逻辑生成的) SQL 块时,您希望它是简单的。
"Can I read this, run it on a server, and know exactly what it does?"
"我能读取这个文件,在服务器上运行它,并确切知道它是做什么的吗?"
If I see a SQL schema with extra layers to it, or an SQL query nesting arrays in a table, my instinctive response is to remove the complexity. This is directly different from standard Java protocols; primarily for environmental considerations.
如果我看到一个带有额外层的 SQL 模式,或者 SQL 查询在表中嵌套数组,我的本能反应是去掉复杂性。 这直接不同于标准的 Java 协议; 主要是出于环境方面的考虑。
Watch for What's Inappropriate in a Specific Language 注意特定语言中什么是不恰当的
A simple JSON block or SQL query can cause a tremendous number of problems. If you think of all programming in state-based terms (almost all programs can be represented as Finite State Machines) the inputs and outputs that come from any program will change the state of all programs and users interacting with it.
一个简单的 JSON 块或 SQL 查询可能会导致大量问题。 如果考虑所有基于状态的编程(几乎所有程序都可以表示为有限状态机) ,来自任何程序的输入和输出都会改变所有程序和与之交互的用户的状态。
Thus, the environment you are working within is extremely important to understand when you look at any code chunk. If you look at someone's code, some of the easiest/most important questions to answer quickly are, "What are the inputs and outputs, and how did they change?"
因此,当您查看任何代码块时,您所处的环境对于理解它极其重要。 如果您查看某人的代码,一些最简单 / 最重要的问题需要快速回答,"输入和输出是什么,它们是如何改变的?"
Traditional database design started with hand-generated forms and reports representing data, and modern programming technique can learn from this approach. Looking at JSON input block A and comparing it to JSON output block B should allow you to ask important questions of your fellow programmer. Likewise with a series of SQL queries pointing at the tables in question.
传统的数据库设计始于手工生成的表单和表示数据的报告,现代编程技术可以从这种方法中学习。 查看 JSON 输入块 a 并将其与 JSON 输出块 b 进行比较,可以让您向其他程序员询问重要问题。 同样,一系列 SQL 查询指向相关的表。
Check if the Code Can be Easily Maintained 检查代码是否容易维护
When you start to talk about environments and tables, reusability and maintainability become fundamentally important. Maintainability presupposes success.
当您开始讨论环境和表时,可重用性和可维护性就变得非常重要。 可维护性是成功的前提。
"We will need to be ready to upgrade this code eight months from now because it will be useful enough to keep us all employed," is quite a confident statement. Telling someone that you believe their code is good enough for someone to pay for it not just today, but tomorrow and next month too is a massive compliment. I suggest saying something along those lines to them, right before you say, "But I can't tell how or why it does what it does because there is not a single comment inside."
"我们需要准备好从现在开始的 8 个月内升级这个代码,因为它将足够有用,以保持我们所有人的就业,"是一个相当自信的声明。 告诉某人你相信他们的代码足够好,不仅仅是今天,而是明天和下个月,这也是一个巨大的赞美。 我建议在你说"但是我不知道它是如何或为什么这么做的,因为里面没有一条评论"之前,对他们说一些类似的话
When you review code, you are reviewing it not just to learn and improve your skills, but to help the creator of said code improve your/their ability to change it later.
当您查看代码时,您查看代码不仅是为了学习和提高您的技能,而且是为了帮助上述代码的创建者提高您 / 他们以后修改代码的能力。
Reusability 可重用性
Would I want to be responsible for modifications to this code? 我想要对这个代码的修改负责吗?
A great place to start making code more flexible later is in your code standards.
以后开始使代码更加灵活的一个很好的地方是您的代码标准。
"This would be more readable if your variable names were not all variations of 'foo1,' 'foo2,' 'bar1,' and 'barA4X,'" is a very good comment that code standards will help with.
"如果您的变量名不是'foo1'、'foo2'、'bar1'和'barA4X'的所有变体,那么这将更具可读性",这是代码标准将帮助解决的一个非常好的注释。
Modifying or understanding large chunks of code is much easier when you follow consistent formatting and naming rules, as well as syntactic conventions.
当遵循一致的格式和命名规则以及语法约定时,修改或理解大块代码要容易得多。
I may not have written a bunch of Perl, but I certainly can cook up regular expressions that look like it, given time to brush the rust off. However, I have found writing three lines of code that do what one line of Perl-code-like regular expressions could do can save me a day of, "Whichever idiot let me do this eight months ago should be keelhauled," self-recrimination.
我可能没有写过一堆 Perl 语言,但我肯定可以编写出类似的正则表达式,只要给我时间刷掉锈迹。 然而,我发现,编写三行代码,做一行类似 perl 代码的正则表达式可以做的事情,可以让我省下一天的时间,"不管八个月前哪个白痴让我这么做,都应该受到惩罚"——自我指责。
Pointing this out to someone, or at least asking them to write five lines of documentation explaining their brilliant line noise can be enlightening for both of you. And once you're done with the simple stuff in code standards, I strongly suggest looking at the dependencies.
向某人指出这一点,或者至少让他们写五行文档来解释他们的妙语连珠,对你们两个都有启发作用。 一旦您完成了代码标准中的简单内容,我强烈建议您查看依赖项。
Reinventing the Wheel vs. Inheriting Unreliable Libraries 重造轮子图书馆 vs. 继承不可靠的图书馆
I don't particularly enjoy writing code. It's always buggy, and doesn't do exactly what I want. It needs to be rewritten repeatedly to handle special cases or additional inputs. Quite often, someone has run into one of my dumb problems and solve it in a way smarter than I am able to:
我并不特别喜欢编写代码。 它总是有问题,而且不能完全按照我想要的去做。 它需要反复重写,以处理特殊情况或额外的输入。 很多时候,有人遇到了我的一个愚蠢的问题,并用比我更聪明的方式解决了它:
Conceptualize quickly without effort, and 不费吹灰之力就能迅速形成概念
Implement without a ton of bugs in a reasonable amount of time. 在合理的时间内实现,避免出现大量的 bug
Thus, I don't write everything in machine language. Or hand-laser wafers to get the exact transistor chains I need onto a chip. Or, sometimes, write as much Python.
因此,我不会用机器语言写所有的东西。 或手工激光晶圆,以获得准确的晶体管链,我需要到一个芯片。 或者,有时候,写尽可能多的 Python。
Sometimes, however, I pick risky libraries. Or pick libraries that don't do what is expected, or have insufficient testing for my purposes. When I look at code other people have written, I want to know the libraries and external chunks they're working with to see if they are appropriate to the task at hand. It all boils down to is the implementer aware of the tradeoffs involved in using the selected references?
然而,有时候我会选择有风险的库。 或者选择没有完成预期任务的库,或者没有进行充分测试的库。 当我查看其他人编写的代码时,我想知道他们使用的库和外部块,看看它们是否适合手头的任务。 归根结底,实现者是否意识到使用选定引用所涉及的权衡?
Generalizing Code 泛化代码
Expansion vs. Refactoring for Compression 压缩的扩展 vs. 重构
After you understand what a chunk of code does and what it's built with, the fun part comes in: where can this go?
当你理解了代码块是做什么的以及它是用什么构建的之后,有趣的部分就出现了: 这个代码块能去哪儿呢?
This can actually be pretty inspiring for both of you. If the code you're reviewing has done its job properly, you can look at it with an eye for where it can solve other problems, and be generalized. For example, should someone write a function that solves the small problem of setting a default date based upon a date-based input? You can look at the kinds of defaults a system might want: next week, next month, last quarter, etc.
这实际上对你们两个来说都是非常鼓舞人心的。 如果您正在审查的代码已经正确地完成了它的工作,那么您可以从它可以解决其他问题的角度来审视它,并对它进行概括。 例如,是否应该编写一个函数来解决根据基于日期的输入设置默认日期的小问题? 您可以查看系统可能需要的默认类型: 下周、下个月、上个季度等等。
Conclusion 总结
Soft skills can make the difference between shipping a product and your source dissolving into code fiefdoms. Without a doubt, when you are working with a team, you will need to look through their code.
软技能可以使产品发布和源代码融入代码封地之间的区别。 毫无疑问,当您与团队一起工作时,您将需要查看他们的代码。
I have found that as I have become more effective at critiquing others' code more politely, the software I have produced has become better. The primary ways I try to support the teams I work with in critiquing their code are through improving the team dynamics, pushing for more consistent code, and trying to help developers produce code as reusable as possible.
我发现,随着我在批评别人代码方面变得越来越有效,我开发的软件也变得越来越好。 我试图支持与我一起工作的团队批评他们的代码的主要方式是通过改进团队动态,推动更一致的代码,并试图帮助开发人员生成尽可能可重用的代码。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: Archlinux 安装小记
下一篇: 面试技术岗 你真能讲明白技术吗?
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论