天天看點

代碼注釋//_您應該停止編寫//的五個代碼注釋,并且//應該開始的一個注釋

代碼注釋//

提供來自您最喜歡和最受歡迎的開源項目的示例-React,Angular,PHP,Pandas等! (With examples from your favorite and most popular open source projects — React, Angular, PHP, Pandas and more!)

代碼品質與注釋之間的相關性 (The correlation between code quality and comments)

One of the first things we were taught in college was that comments are essential. We were also taught that there is a correlation between code quality and the number of comments a code has — the more comments you have, the better your code is. We were trained to believe that comments tell the story of the program we write, and that they express whatever code can’t provide. We learned that human language is best read by human, while machine language is best read by machines.

在大學裡我們被教導的第一件事是評論是必不可少的。 我們還被告知,代碼品質與代碼的注釋數量之間存在相關性-您擁有的注釋越多,代碼就越好。 我們受過訓練,相信注釋可以說明我們編寫的程式的故事,并且注釋可以表達代碼無法提供的内容。 我們了解到,人類最好閱讀人類語言,而機器最好閱讀機器語言。

Moreover, teaching that wasn’t enough and we were “punished” for handing in assignments without comments by a few points being deducted from our grades. If you somehow managed to avoid the human checks, your lack of comments was caught by scripts which were designed to check that.

此外,這還不夠,我們在交作業時不加評論就被“懲罰”了,從分數中扣除了幾分。 如果您設法以某種方式避免了人工檢查,則設計用來檢查該腳本的腳本會發現您缺少注釋。

也許相關是逆的 (Maybe the correlation is inverse)

As I gained more experience, I realized that not only is it that the opposite may be true — it’s possible that there is an inverse correlation between good code and the number of comments the code has. There are two main reasons why this can happen:

随着我積累了更多的經驗,我意識到,不僅相反的情況可能是對的-好的代碼與代碼的注釋數量之間可能存在反相關關系。 發生這種情況的主要原因有兩個:

  1. Too many times comments are just an excuse for writing bad code. Instead of writing good code, programmers believe that if they write dirty code with some weird hacks, and describe it with a 5 lines of comments — that the code is readable and well written. I beg to differ — the code is actually still bad. If your colleague needs to read a long commented story in order to understand it, then you’re doing it wrong. If your code is not self explanatory, it is best to improve it and not use comments to describe it.

    注釋太多次隻是編寫錯誤代碼的借口。 程式員認為,如果他們用一些怪異的hacks編寫肮髒的代碼,并用5行注釋來描述它,那麼它們就不會編寫出色的代碼,而是可讀且編寫得很好。 我要不同的是-代碼實際上仍然很糟糕。 如果您的同僚需要閱讀長篇評論故事才能了解它,那麼您做錯了。 如果您的代碼不能自我解釋,則最好對其進行改進,而不要使用注釋來描述它。

  2. Comments decay over time, which makes them wrong and misleading. They are true only when written, and even then they can’t be enforced efficiently. Over time, people will inevitably make logic changes, change types, and move things around. Some of them will notice the comment that should be changed, and some will not. Even if somehow you find a way to set a very rigid discipline around updating comments when code changes, this will break the first time you perform an automatic refactor. Think of a refactor that adds a parameter to a core function that is used more than 250 times — do you really want to go and manually change all those comments?

    評論會随着時間的流逝而衰減,進而使它們成為錯誤和誤導性的。 它們隻有在編寫時才是正确的,即使那樣,也無法有效實施。 随着時間的流逝,人們将不可避免地進行邏輯更改,更改類型并四處移動。 他們中有些人會注意到應該更改的評論,而有些人則不會。 即使您以某種方式找到了一種在代碼更改時為更新注釋設定非常嚴格的方法的方法,這也會在您第一次執行自動重構時中斷。 考慮一下将參數添加到已使用250次以上的核心函數的重構-您​​是否真的要去手動更改所有這些注釋?

您應該避免的最常見評論是什麼? (What are the most common comments you should try to avoid?)

All this doesn’t mean you should stop writing comments right away or try to reduce the number of comments you have at any cost. I would also not recommend going over your code, and trying to clean all of the unnecessary or misleading comments — this will take too much time and your time is better used elsewhere. Instead, I would recommend to be more thoughtful before you add your next comment and ask yourself these three questions:

所有這些并不意味着您應該立即停止寫評論或嘗試不惜一切代價減少評論的數量。 我也不建議檢查您的代碼,并嘗試清除所有不必要的或誤導性的注釋-這将花費太多時間,您的時間最好在其他地方使用。 相反,我建議您在添加下一條評論并問自己以下三個問題之前,請多加考慮:

  1. Is this comment really required and what value does it add?

    此評論是否确實需要,它增加了什麼價值?

  2. Is there a way to improve the code so this comment is unnecessary?

    有沒有一種方法可以改進代碼,是以不需要此注釋?

  3. Am I only covering my a** by adding this comment?

    我隻是通過添加此評論來覆寫我的a **嗎?

To help you out, I’ve identified the top 5 bad comments I’ve seen over time — these types of comment should raise a red flag before you add it. I used some very common open source projects to get some examples. Don’t get me wrong, I don’t think these project are poorly written. On the contrary, those are my favorite projects. But nothing in life is perfect; all code can be improved.

為了幫助您,我确定了我在一段時間内看到的前5條不良評論-在添加之前,這些類型的評論應該會出現一個紅色标記。 我使用了一些非常常見的開源項目來擷取示例。 别誤會我的意思,我認為這些項目的撰寫不正确。 相反,這些是我最喜歡的項目。 但是生活中沒有什麼是完美的。 所有代碼都可以改進。

1.說明明顯 (1. Stating the obvious)

These are comments that explain what your code does. You’ve probably seen some of these around:

這些注釋說明了您的代碼的作用。 您可能已經看到其中一些:

An example from react.js:

來自react.js的示例:

getHasteName() {
   // We never want Haste.
   return null;
}
           

And another one from vscode:

vscode中的另一個:

// Avoid Monkey Patches from Application Insights// Avoid Monkey Patches from Application Insights
bootstrap.avoidMonkeyPatchFromAppInsights();
// Enable portable support
bootstrap.configurePortable();
// Enable ASAR support
bootstrap.enableASARSupport();
// Load CLI through AMD loader
require('./bootstrap-amd').load('vs/code/node/cli');
           

Believe it or not, people reading your code are coders themselves. It is highly probable that they work at the same company as you or on the same project. They have some context, and are pretty smart (hopefully… if you believe you are surrounded by idiots, you might want to consider updating your Linkedin). They can read code, even without footnotes. If your variables, functions, and classes have meaningful names, then don’t clutter them with pointless explanations that will be outdated in the next code change or refactor.

信不信由你,閱讀您的代碼的人都是程式員。 他們很有可能與您在同一家公司或同一項目中工作。 他們有一定的背景,并且非常聰明(希望……如果您認為自己被白癡所包圍,則可能要考慮更新Linkedin)。 即使沒有腳注,他們也可以閱讀代碼。 如果您的變量,函數和類具有有意義的名稱,請不要用無意義的解釋使它們混亂,這些解釋在下一次代碼更改或重構時将過時。

Disclaimer: Like many others, I have comment-blindness. I ignore comments and will most likely never notice there was a comment which should be updated when changing or refactoring the code.

免責聲明:與其他許多人一樣,我也有盲目性。 我會忽略注釋,并且很可能永遠不會注意到有注釋在更改或重構代碼時應進行更新。

Back to the example — what happens if we removed all of the comments in the code above? would it really be much harder to read?

回到示例–如果我們删除了上面代碼中的所有注釋,會發生什麼? 真的會更難閱讀嗎?

2.解釋您的代碼 (2. Explaining your code)

If your code is clean and uses the right level of abstraction, you don’t need to explain what it does. If you still find yourself explaining the code, it might be the result of some habit you picked up over the years. You might want to consider getting rid of it, or have to endure a code that is not self-expressive

如果您的代碼是幹淨的并且使用了正确的抽象級别,則無需解釋它的作用。 如果您仍然發現自己在解釋代碼,則可能是多年來您養成某種習慣的結果。 您可能要考慮擺脫它,或者必須忍受非自我表達的代碼

Look at this code from react.js:

檢視來自react.js的這段代碼:

if (!existsSync('./scripts/rollup/results.json')) {
  // This indicates the build failed previously.
  // In that case, there's nothing for the Dangerfile to do.
  // Exit early to avoid leaving a redundant (and potentially      confusing) PR comment.
  process.exit(0);
}
           

Wouldn’t this be cleaner if we refactored it like this:

如果我們這樣重構它,那會不會更幹淨:

if (buildFailedPreviously())
  process.exit(0);
           

Another common example can be naming; either functions, variables, or classes. Good naming is one of the hardest things to do, but that doesn’t mean we need to unconditionally raise a white flag, and use comments to describe what our code does. Look at this code from php:

另一個常見的例子是命名。 函數,變量或類。 良好的命名是最難的事情之一,但這并不意味着我們需要無條件地舉起白旗,并使用注釋來描述代碼的作用。 從php看這段代碼:

struct stack_control_header
{ 
  long shgrow:32;    /* Number of times stack has grown.  */
  long shaseg:32;    /* Size of increments to stack.  */
  long shhwm:32;     /* High water mark of stack.  */
  long shsize:32;    /* Current size of stack (all segments).  */
};
           

If you pass it around and then try to use it, you might not immediately understand what shgrow, shaseg and other fields are. What if we wrote it this way:

如果将其傳遞然後嘗試使用,則可能不會立即了解什麼是shgrow,shaseg和其他字段。 如果我們這樣寫:

struct stack_control_header
{
  long num_of_time_grown:32;
  long size_of_inc:32;
  long high_water_mark:32;
  long current_size:32;
};
           

See? Much better. The reader can better understand what each field does without needing to jump to the struct definition and read the comments.

看到? 好多了。 讀者可以更好地了解每個字段的作用,而無需跳轉到結構定義并閱讀注釋。

3.長評論 (3. Long comments)

Long comments that are used to describe every decision you’ve made. These comments may explain each line in detail: why you chose to write it that way, what were the alternatives, what is the code history that led to it. It made it really hard to read the code fluently, and it can cause the reader further confusion. Ultimately, causing more damage than good. Try to keep comments as short as you can with minimal context.

長注釋用于描述您所做的每個決定。 這些注釋可能會詳細解釋每一行:為什麼選擇以這種方式編寫它,替代方法是什麼,導緻它的代碼曆史是什麼。 這使得很難流暢地閱讀代碼,并且可能引起讀者進一步的困惑。 最終,造成的傷害大于好處。 嘗試在盡可能少的上下文中使評論盡可能簡短。

If the reason you add a comments is because the code is hacky or complicated, then make it readable by refactoring it — not by adding another confusing layer. Choose better names, break functions to do one thing, and use abstractions. Whatever you need to make your code more readable, do it with code, not comments.

如果添加注釋的原因是由于代碼太過亂或太複雜,則可以通過重構代碼使其變得可讀-而不是添加另一個令人困惑的層。 選擇更好的名稱,破壞函數以做一件事,并使用抽象。 為了使代碼更具可讀性,無論需要做什麼,都可以使用代碼而不是注釋來完成。

An example from vue.js:

來自vue.js的示例:

// Async edge case #6566 requires saving the timestamp when event listeners are
// attached. However, calling performance.now() has a perf overhead especially
// if the page has thousands of event listeners. Instead, we take a timestamp
// every time the scheduler flushes and use that for all event listeners
// attached during that flush.
export let currentFlushTimestamp = 0
// Async edge case fix requires storing an event listener's attach timestamp.
let getNow: () => number = Date.now
// Determine what event timestamp the browser is using. Annoyingly, the
// timestamp can either be hi-res (relative to page load) or low-res
// (relative to UNIX epoch), so in order to compare time we have to use the
// same timestamp type when saving the flush timestamp.
if (inBrowser && getNow() > document.createEvent('Event').timeStamp) {
// if the low-res timestamp which is bigger than the event timestamp
// (which is evaluated AFTER) it means the event is using a hi-res timestamp,
// and we need to use the hi-res version for event listeners as well.
getNow = () => performance.now()
}
           

This will probably require more refactoring to move the focus from comments to the actual code.

這可能需要更多的重構才能将焦點從注釋移到實際代碼。

4.标題,标題和其他“美化” (4. Titles, headers and other “beautifications”)

Writing pretty code is essential, but that doesn’t mean you should decorate it like a book. We occasionally tend to creates blocks of code and give them titles, in order to differentiate one block from another. Let’s see this example from angular.js:

編寫漂亮的代碼是必不可少的,但這并不意味着您應該像書一樣裝飾它。 我們有時會傾向于建立代碼塊并給它們命名,以區分一個塊與另一個塊。 讓我們從angular.js看這個例子:

...
build: function(config, fn) {
var files = grunt.file.expand(config.src);
  // grunt.file.expand might reorder the list of files
  // when it is expanding globs, so we use prefix and suffix
  // fields to ensure that files are at the start of end of
  // the list (primarily for wrapping in an IIFE).
  if (config.prefix) {
    files = grunt.file.expand(config.prefix).concat(files); 
  }
  if (config.suffix) {
   files = files.concat(grunt.file.expand(config.suffix));
  }
  var styles = config.styles;
  var processedStyles;
  //concat
  var src = files.map(function(filepath) {
    return grunt.file.read(filepath);
  }).join(grunt.util.normalizelf('\n'));
  //process
  var processed = this.process(src, grunt.config('NG_VERSION'), config.strict);
  if (styles) {
  processedStyles = this.addStyle(processed, styles.css, styles.minify);
  processed = processedStyles.js;
  if (config.styles.generateCspCssFile) {
    grunt.file.write(removeSuffix(config.dest) + '-csp.css', CSP_CSS_HEADER + processedStyles.css);
  }
}
//write
grunt.file.write(config.dest, processed);
grunt.log.ok('File ' + config.dest + ' created.');
fn();
...
           

If you find yourself doing this, your function undoubtedly does more than one thing. It is probably too long, explicit, and lacks some levels of abstractions. In the example above, the function has at least four parts: fetch files, concat, process, and write. Each of these parts appears with detailed implementation, that creates long functions that are also hard to read. This can be fixed by expanding each block to a different function.

如果您發現自己這樣做了,那麼您的功能無疑會做更多的事情。 它可能太長,太明确,并且缺乏某些抽象層次。 在上面的示例中,該函數至少包含四個部分:擷取檔案,concat,程序和寫入。 這些部分中的每一個都有詳細的實作,會建立冗長的功能,這些功能也很難閱讀。 可以通過将每個塊擴充為不同的功能來解決此問題。

build: function(config, fn) {
  files = this.fetch_files(config)
  var src = this.concat(files)
  var processed = this.process(src)
  write(processed, config)
}
           

As code grows, the “headers” are not bold enough. This is where we get creative and add additional “beautifications” to our comments — line of asterisk, dashes, equals sign, etc. Take a look at this code from pandas:

随着代碼的增長,“标題”不夠大膽。 這是我們發揮創意的地方,并在注釋中添加了其他“美化”功能—星号,破折号,等号等。請看一下pandas的代碼:

...
# --------------- #
# dtype access    #
# --------------- #
def _ensure_data(values, dtype=None):
...
def _reconstruct_data(values, dtype, original):
...
def _get_hashtable_algo(values):
...
# --------------- #
# top-level algos #
# --------------- #
def match(to_match, values, na_sentinel=-1):
...
def unique(values):
...
def isin(comps, values):
...
# --------------- #
# select n        #
# --------------- #
class SelectN(object):
...
class SelectNSeries(SelectN):
...
class SelectNFrame(SelectN):
...
# ------------ #
# searchsorted #
# ------------ #
def searchsorted(arr, value, side="left", sorter=None):
...
# ---- #
# diff #
# ---- #
_diff_special = {
...
}
def diff(arr, n, axis=0):
...
           

The module includes a list of functions, variables, and classes all mixed together in one bundle with coupled dependencies. This could be avoided using one simple rule — if you feel that you need titles to gather functions or classes together, this would be a good time to break your code to smaller parts.

該子產品包括函數,變量和類的清單,這些函數,變量和類全部混合在一起并具有耦合的依賴項。 使用一條簡單的規則可以避免這種情況-如果您認為需要标題來将函數或類收集在一起,那麼這是将代碼分解為較小部分的好時機。

If your class has “groups” of method from different types — each group of functions should be a class of its own. If your file has too many classes or functions that require grouping, it’s time to break each group to its own file.

如果您的類具有不同類型的方法“組”,則每個函數組都應是其自己的類。 如果檔案中有太多需要分組的類或函數,那麼該将每個分組拆分為自己的檔案了。

The code above could be much easier to understand and navigate if we break it to files. By doing this we also decouple the dependencies, so we can import only the code we need:

如果我們将其分解為檔案,則上面的代碼可能更易于了解和導航。 通過這樣做,我們還解耦了依賴關系,是以我們隻能導入所需的代碼:

date_acces.py:
def _ensure_data(values, dtype=None)
def _reconstruct_data(values, dtype, original)
def _get_hashtable_algo(values):
top_level_algos.py
def match(to_match, values, na_sentinel=-1):
def unique(values):
def isin(comps, values):
selectn.py
class SelectN(object):
selectn_series.py
class SelectNSeries(SelectN):
selectn_frames.py
class SelectNFrame(SelectN):
search_sorted,py
def searchsorted(arr, value, side="left", sorter=None):
diff.py
_diff_special = {
...
}
def diff(arr, n, axis=0):
...
           

5. / * TODO:* / (5. )

from react.js:

來自react.js :

// TODO: decide on the top-level export form.
// This is hacky but makes it work with both Rollup and Jest
module.exports = ReactDOMServer.default || ReactDOMServer;
           

Whether it’s , #TODO, or <! — TODO →, one thing is for sure — no one will ever do it. Yes, even if you add a name next to it and assign it to someone. The assignee will leave the company long before they’ll fix this issue. I’ve never heard anyone anywhere saying something like: “hey folks, we have some free time, why don’t we fix all of the todos in our code?” (If you have some time for that, then your company has a bigger problems, but we’ll leave that one for another post).

是/ * TODO * /, # TODO還是<! — TODO→,可以肯定的是,沒有人會這樣做。 是的,即使您在名稱旁邊添加了一個名稱并将其配置設定給某人。 受讓人将在解決此問題之前離開公司。 我從未在任何地方聽到有人說過這樣的話:“嘿,我們有一些空閑時間,為什麼不在代碼中修複所有待辦事項呢?” (如果您有時間這樣做,那麼您的公司會遇到更大的問題,但我們會将其留給另一篇文章)。

The main problem with todos is that it’s not only an excuse for writing a bad code, but also it’s unclear to the reader what is the state of that code — Is it going to be changed soon? Was this already fixed and the author forgot to remove the comment? Is there a pull request waiting that should fix this issue? Did the code author leave it for us to fix? — Make a decision, either fix it, or accept the consequences.

todos的主要問題在于,它不僅是編寫不良代碼的借口,而且讀者不清楚該代碼的狀态是什麼—它将很快被更改嗎? 這個問題已經解決了嗎,作者忘了删除評論? 是否有等待處理的拉取請求可以解決此問題? 代碼作者是否将其留給我們修複? —做出決定,或者修正它,或者接受後果。

The one exception is if you are working on a feature and want to break your code changes into multiple commits. In that case, add the todo comment and add your task number/link to a real task in your task management system. This way, you can track it and make sure it is on your roadmap. If for some reason you decided not to handle the task, don’t forget to also delete the comment

一個例外是,如果您正在使用某個功能,并且希望将代碼更改分成多個送出。 在這種情況下,請添加待辦事項注釋,并将您的任務編号/連結添加到任務管理系統中的實際任務。 這樣,您可以跟蹤它并確定它在您的路線圖中。 如果出于某種原因您決定不處理該任務,請不要忘記也删除注釋

最後,這是您應該寫的評論 (Finally, here are the comments you should write)

A rule of thumb — use comments to answer “Why?” and the code to answer “How?”

經驗法則-使用評論回答“為什麼?” 以及回答“如何?”的代碼

Even if the code is self explanatory, the reason we decided to take one approach is not always clear, especially if the reader has no context. It might be due to product requirements, system limitation, efficiency or just a bad code that you didn’t have time to refactor.

即使代碼是自我解釋的,我們決定采用一種方法的原因也并不總是很清楚,尤其是在讀者沒有上下文的情況下。 可能是由于産品要求,系統限制,效率或您沒有時間重構的錯誤代碼所緻。

Using comments to highlight why you did something the way you did is good, but keep it short and focused. If you want to document, use a wiki; if you want talk broadly about your decision making use a doc; if you want to log the code changes history, that’s what git comments are for.

用注釋突出說明為什麼您以自己的方式做某件事是好的,但要簡短而專心。 如果要記錄文檔,請使用Wiki。 如果您想使用文檔廣泛地談論您的決策; 如果您想記錄代碼更改曆史記錄,那就是git注釋。

A good example from linux:

linux的一個很好的例子:

/*
Apply the selected BCJ filter. Update *pos and s->pos to match the amount of data that got filtered. NOTE: This is implemented as a switch statement to avoid using function pointers, which could be problematic in the kernel boot code, which must avoid pointers to static data (at least on x86).
*/
static void bcj_apply(struct xz_dec_bcj *s, uint8_t *buf, size_t *pos, size_t size)
           

If there is one thing you should take from this post — use code to tell your story and comments to turn “WTF ?” to “OHHHH… ?”

如果您應該從這篇文章中學到一件事,請使用代碼講述您的故事和評論以轉為“ WTF ?” 到“ OHHHH…”? ”

Thanks for spending a few minutes of your time. If you liked it, feel free to ? or respond with

感謝您花幾分鐘的時間。 如果您喜歡,請随意? 或回複/ *評論* /

-Alon

-阿隆

Special thanks to:

特别感謝:

  • Rina Artstain and Keren for proofreading, reviewing this article and giving awesome technical feedback

    Rina Artstain 和Keren進行校對,審閱本文并提供了 出色的 技術回報

翻譯自: https://www.freecodecamp.org/news/5-comments-you-should-stop-writing-and-1-you-should-start-4d66a367cd2c/

代碼注釋//