|
本文轉自公眾號 機器之心 選自 Medium 機器之心編譯 作者:Chris Blakely 如若轉載請聯系原公眾號 能把代碼寫出來是一回事,但是寫出整潔、可讀的代碼又是另一回事。然而,什么是「干凈的代碼」呢?怎么才能寫出「干凈的代碼」?為了解答這些問題,本文作者寫了一份針對開發(fā)者的干凈代碼指南。
不妨想象一下,你正在閱讀一篇文章,文章開頭段簡要概述了文章的內容。文中還有一些小標題,它們會引出各部分的段落。段落是通過將相關信息按照合理的順序組合起來而構成的,這樣文章就會變得「行云流水」,可讀性很強。 現在,你可以反過來再想象一下如果這篇文章沒有任何小標題。文中只有很多小段落,它們十分冗長并雜亂無章。那么你就無法快速瀏覽這篇文章,必須真正深入到內容中去,這樣才能對整篇文章有大概的了解。這確實會帶來很差的閱讀體驗! 你的代碼應該像一篇美文一樣,需要給讀者帶來很好的閱讀體驗。將你代碼的類/文件視為文章的小標題,將你的方法(函數)視為文章的段落。你代碼中的語句就相當于文章中的句子。下面本文將列出一些干凈代碼的特征: 干凈的代碼是專一的:每個函數、類和模塊都應該只做一件事,并且將其做好。 干凈代碼應該是優(yōu)雅的:干凈的代碼應該易于閱讀,閱讀干凈的代碼會讓你感到愉悅,它應該讓你認為「我確實知道這里的代碼在做什么」。 干凈代碼應該經常維護:我們需要花時間讓它保持簡單有序,并適當關注代碼的細節(jié)。 干凈代碼應該通過各種測試:會崩潰的代碼肯定不是干凈的!
那么現在主要的問題就是,作為一個開發(fā)者,你如何才能編寫出干凈的代碼?下面是一些實用的小建議。 使用一致的格式和縮進 如果行距不一致、字體大小不一、或到處都是換行,那么這樣的書肯定難以閱讀。代碼也是如此。 要使你的代碼清晰易讀,請確??s進、換行、以及格式是一致的。下面本文將給出一個優(yōu)秀范例和反面例子: 優(yōu)秀范例 
你一眼就可以看出函數中有一個「if/else」語句 大括號和一致的縮進讓代碼塊開始和結束的位置一目了然 大括號是一致的,請注意函數和 if 代碼塊的左大括號是和函數名和 if 關鍵字放在同一行上的
反面例子 
這里有太多不對勁的地方!
這個例子稍微有些夸張,但是它顯示出了使用一致的縮進和規(guī)范格式的好處。我不知道你怎么看,但我認為「優(yōu)秀范例」中給出的例子對我來說讀起來容易地多! 好消息是,你可以使用過許多 IDE 的插件自動規(guī)定代碼的格式。哈利路亞! VS Code:https://marketplace./items?itemName=esbenp.prettier-vscode Atom:https:///packages/atom-beautify Sublime Text:https:///packages/HTML-CSS-JS%20Prettify
使用清晰的變量名和方法名 在文章的開頭,我談到了讓你的代碼變得容易閱讀是多么的重要。要做到這一點,一個重要的方面就是你選擇的命名方式(這是我在菜鳥階段犯過的錯誤之一)。下面讓我們看一個好的命名的例子(JS使用小駝峰命名規(guī)則): 
這段代碼有下面 2 個優(yōu)點:
函數的命名很清晰,參數也被命名地很好。當開發(fā)者看到這段代碼時,他們的思路會很清晰?!溉绻医o出 studentId 參數,并調用 getStudentName() 方法,我將得到一個學生的名字」——如果沒有必要的話,我們不必再轉而查看「getStudentName()」方法! 在「getStudentName()」方法內部,對變量和方法的調用也被很清晰地命名了——可以很清楚地看到該方法調用了一個 api,得到了一個 student 對象,并返回了一個 name 屬性。太容易了!
對于新手來說,在編寫干凈的代碼時選取好的命名比你想象的要難。隨著你的應用程序不斷升級,請使用下面的規(guī)則確保你的代碼易于閱讀: 溫馨提示,如果你無法命名你的函數或方法,那就說明這個函數承載的任務太多了。請繼續(xù)將其分解為更小的函數!例如,如果你最終調用的是你的函數「updateCarAndSave()」,請分別創(chuàng)建兩個方法「updateCar()」和「saveCar()」。 在必要時使用注釋 人們常說:「代碼應該是自文檔化的」,這從根本上意味著,你的代碼應該足夠易讀,從而減少對注釋的需求。這個觀點貌似很有道理,我猜這種說法在理想世界是說得通的。然而,碼農的世界卻遠遠不是一個完美的世界,所以使用一些注釋還是很有必要的。 文檔注釋是描述某個特定的函數或類做了什么的注釋。如果你編寫了一個程序庫,這樣的注釋會對其它開發(fā)者們很有幫助。下面是「useJSDoc」中的一個注釋的例子: 
說明注釋對于可能需要維護、重構或擴展你的代碼的任何人(包括未來的你自己)都適用。通常而言,可以避免使用說明注釋,轉而采用「自文檔化代碼」。下面是一個說明注釋的例子: 
下面給出了一些你應該盡量避免使用的注釋。他們不會提供太多的有效信息,可能會誤導用戶,并使代碼變得混亂。 不增添有效信息的冗余注釋: 誤導性的注釋: 搞笑或輕蔑的注釋: 牢記「DRY」原則(Don't Repeat Yourself,不要做重復的事) 「DRY」原則可以被表述為: 每一小段知識在一個系統(tǒng)中必須擁有一個單一、清晰、權威的呈現。 最簡單地說,這從根本上意味著你應該致力于減少存在的重復代碼的數量。(注意,我這里說的是「減少」而不是「消除」——有些情況下,重復的代碼也并不是世界末日?。?/span> 對于代碼維護來說,重復的代碼可能是一場噩夢。讓我們來看看一個例子: function addEmployee(){ // create the user object and give the role const user = { firstName: 'Rory', lastName: 'Millar', role: 'Admin' }
// add the new user to the database - and log out the response or error axios.post('/user', user) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }); }
function addManager(){ // create the user object and give the role const user = { firstName: 'James', lastName: 'Marley', role: 'Admin' } // add the new user to the database - and log out the response or error axios.post('/user', user) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }); }
function addAdmin(){ // create the user object and give the role const user = { firstName: 'Gary', lastName: 'Judge', role: 'Admin' }
// add the new user to the database - and log out the response or error axios.post('/user', user) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }); }
假設你正在為客戶創(chuàng)建一個人力資源 web 應用程序。該應用程序允許管理員將扮演某種角色的用戶通過應用程序接口(API)添加到數據庫中。角色共有三種:雇員、經理和管理員。讓我們看看可能存在的一些函數: 這看起來似乎很酷!上面代碼的運行一切正常。但是,過了一會,我們的客戶跑過來說: 嘿!我們希望顯示出來的錯誤信息包含「此處有一個錯誤」這句話。另外,更麻煩的是,我們希望把 API 的端點從「/user」改為「/users」。謝謝! 在開始編程之前,讓我們先回顧一下。在這篇文章開頭,我曾經說過「干凈的代碼應該專一」(即做一件事,并把它做好)。這就是我們當前的代碼所具有的一個小問題。執(zhí)行 API 調用和處理錯誤的代碼重復出現了——這意味著我們必須在三個地方同時更新代碼,以滿足新的需求。這太煩人了! 那么,如果我們對代碼進行重構,讓它變得更專一呢?請繼續(xù)閱讀下面的內容: function addEmployee(){ // create the user object and give the role const user = { firstName: 'Rory', lastName: 'Millar', role: 'Admin' }
// add the new user to the database - and log out the response or error saveUserToDatabase(user); }
function addManager(){ // create the user object and give the role const user = { firstName: 'James', lastName: 'Marley', role: 'Admin' } // add the new user to the database - and log out the response or error saveUserToDatabase(user); }
function addAdmin(){ // create the user object and give the role const user = { firstName: 'Gary', lastName: 'Judge', role: 'Admin' }
// add the new user to the database - and log out the response or error saveUserToDatabase(user); }
function saveUserToDatabase(user){ axios.post('/users', user) .then(function (response) { console.log(response); }) .catch(function (error) { console.log('there was an error ' + error); }); }
我們已經將創(chuàng)建 API 調用的邏輯移到了它自己的方法「saveUserToDatabase(user)」中(這是個好名字嗎?看你怎么想嘍)。其它的方法將調用該方法來保存用戶信息。現在,如果我們需要再次變更 API 的邏輯,我們只需要更新一個方法。同樣的,如果我們必須添加一個創(chuàng)建用戶的方法,那么通過 API 將用戶信息保存到數據庫的方法就已經存在了。這真是太棒了! 使用我們目前所學的知識進行重構的一個例子 讓我們閉上眼睛,假設我們正在做一個計算器應用程序。該程序用到了一些可以分別讓我們做加法、減法、乘法、除法的函數,將運行結果輸出到控制臺。 下面是我們目前已有的代碼,在繼續(xù)閱讀本文接下來的內容之前,看看你能否自己發(fā)現代碼中存在的問題: function addNumbers(number1, number2) { const result = number1 + number2; const output = 'The result is ' + result; console.log(output); }
// this function substracts 2 numbers function substractNumbers(number1, number2){
//store the result in a variable called result const result = number1 - number2; const output = 'The result is ' + result; console.log(output); }
function doStuffWithNumbers(number1, number2){ const result = number1 * number2; const output = 'The result is ' + result; console.log(output); }
function divideNumbers(x, y){ const result = number1 / number2; const output = 'The result is ' + result; console.log(output); }
代碼中存在哪些問題呢? 縮進是不一致的——使用什么樣的縮進格式并不重要,只要格式保持一致 第二個函數有一些冗余的注釋——我們可以通過閱讀函數名和函數內的代碼來判斷發(fā)生了什么,所以我們真的需要這里的注釋嗎? 第三和第四個函數沒有使用良好的命名——「doStuffWithNumbers()」并不是用最恰當的函數名,因為它并沒有說明函數做了什么。(x,y)不是描述性的的變量,x 和 y 有作用嗎?它們是什么?是數字嗎?還是香蕉? 這些方法做了不止一件事——它們要執(zhí)行計算,但是也要顯示輸出。我們可以按照「DRY」原則將現實邏輯拆分為一個獨立的方法。
現在,我們將使用在這個為初學者編寫的干凈代碼指南中學到的東西來重構代碼,由此得到的新代碼如下: function addNumbers(number1, number2){ const result = number1 + number2; displayOutput(result) }
function substractNumbers(number1, number2){ const result = number1 - number2; displayOutput(result) }
function multiplyNumbers(number1, number2){ const result = number1 * number2; displayOutput(result) }
function divideNumbers(number1, number2){ const result = number1 * number2; displayOutput(result) }
function displayOutput(result){ const output = 'The result is ' + result; console.log(output); }
恭喜你!現在你可以在面試中和撰寫你光彩照人的簡歷時,談談你對編寫干凈代碼的認識了! 不要「過度清理」你的代碼 我經??吹介_發(fā)人員在清理代碼時矯枉過正。注意不要過度清理代碼,因為這會適得其反。實際上會讓你的代碼變得更難以閱讀和維護。如果開發(fā)者必須不斷地在許多文件/方法之間進行跳轉才能進行簡單的變更,那這樣也會影響生產效率。 要有編寫干凈代碼的意識,但是不要在項目的早期過多地考慮它。請確保你的代碼能正常工作,并很好地經過了測試。而在重構階段,你應該真正考慮如何使用像「DRY」這樣的原則來清理你的代碼。 在這篇為初學者編寫的干凈代碼指南中,我們學會了如何: 使用一致的格式和縮進 使用清晰的變量名和方法名 在必要時使用注釋 使用「DRY」原則(不要重復做一件事)
原文鏈接:https:///m/global-identity?redirectUrl=https%3A%2F%2Fmedium.freecodecamp.org%2Fthe-junior-developers-guide-to-writing-super-clean-and-readable-code-cd2568e08aae
|