關於如何編寫 Clean Code 的 6 個簡單技巧

160

做者:Alex Deverojavascript

翻譯:承香墨影java

編寫簡潔代碼(Clean Code)不是一件很是容易的事情,爲了保持代碼整潔,你須要嘗試不一樣的技巧和作法。問題是,在這個問題上,有太多的作法和技巧,是須要大量的重構的。所以,開發者很難選擇出適合本身項目的作法和技巧。程序員

讓咱們來簡化這個任務,在本文中,咱們將討論編寫整潔代碼的一些好處,而後再來看看咱們總結的 6 個技巧和實踐,以便讓開發人員理解,編寫 Clean Code 最常使用的一些技巧。算法

1、編寫簡潔代碼的好處

讓咱們先看看編寫簡潔乾淨的代碼有什麼好處。其中一個主要的好處是,簡潔乾淨的代碼能夠幫助咱們最大限度的減小閱讀和試圖理解代碼的時間。凌亂的代碼風格,具備難以想象的能力,能夠加大開發人員的工做效率,讓它們的工做變的更加困難。代碼越是混亂,開發人員維護起來須要的時間越多。並且,若是代碼太亂,維護的開發人員可能會決定停下來,而後重構它。編程

1.1 更容易開始,也更容易繼續

讓我舉一個簡單的例子來講明這一點。設計模式

假設咱們在很長一段時間以後,從新維護咱們以前開發的某一個項目。也許,是咱們之前的某個客戶,聯繫了咱們並從新須要咱們對其進行繼續的擴展與維護。函數

如今,咱們能夠想像到,若是在項目開發階段,咱們沒有使用簡潔代碼的技巧編寫簡潔的代碼,而是寫下了相反的代碼。你將第一次知道,你的代碼是多麼的糟糕和混亂。並且這個時候你會發現,從新維護一個以前的項目,是多麼的艱難。學習

所以,咱們如今必須在這個項目上,花費更多的時間,由於咱們須要從新瞭解咱們以前編寫的代碼。而這並非必要的,咱們能夠從一開始就堅持編寫簡潔代碼,來徹底避免它。字體

如今咱們必須增長成本,並且,咱們的舊代碼如此的混亂不堪,若是咱們決定從頭開始。我想這不是你的客戶們樂意聽到的,由於這表明了成本的增長和工期的延長。優化

Clean Code 就不會有這樣的問題,想像一下前面的例子,狀況就會恰好相反。如今,咱們以前的代碼是乾淨且優雅的。那咱們須要多長時間才能理解它?也許只須要幾分鐘,簡單閱讀一下代碼,瞭解以前是如何工做的。最後咱們在這個基礎上,花費一段時間進行維護或者擴展新的功能。此次投資的成本和時間,將會小得多,咱們的客戶可能都不會注意到你作了什麼。

這就是咱們討論堅持使用 Clean Code 編碼技巧的第一個好處。並且,這不只僅是爲了咱們本身維護的項目,也是爲了其餘開發者。Clean Code 可以讓咱們更快的上手,咱們或者其餘開發者,都不須要花費數個小時的時間來研究它。咱們能夠更快的進入到工做之中。

1.2 更容易讓人加入團隊

Clean Code 的另外一個好處是與第一個緣由密切相關的,它將加快新人接手項目的速度。

個人意思是,假設咱們須要聘請另一個開發人員,須要多長時間才能理解代碼並學習如何使用它?這取決於,若是咱們的代碼自己很混亂,寫的很差,他將須要更多的時間來完成首次接手的工做。而若是咱們的代碼是保持簡潔的、易讀的,這將很是的易於理解,那麼他就能更快的接手而且開始編寫新的需求。

有些人可能以爲這不是一個問題,由於咱們還在這裏,咱們能夠幫助他更快的理解,雖然這真的能夠加快他的上手速度。可是,咱們的幫助只應該花費咱們很短暫的時間,一兩天或者三天,而不該該是一週或者很頻繁的。

當咱們決定招募另外一位開發人員,是爲了加速咱們的項目研發,而不是放緩它。咱們的目標不是幫助他學習如何在咱們以前編寫的代碼之上繼續編碼,這將會消磨咱們更多的時間。

1.3 更容易保持規範

有一件事情咱們須要注意,瞭解和學習如何編寫代碼是一回事。可是,這只是一個開始,咱們還須要確保開發者可以而且願意遵循咱們的編碼規範,並將它持續的實踐在項目中。這將能保持項目是持續的乾淨整潔,而不會所以而凌亂下去。這一點很重要,由於咱們不只要編寫簡潔的代碼,還要保持這樣的代碼,無論未來有多少人會來維護它,咱們須要長期堅持和思考這個問題。

最後,若是咱們團隊的開發者之一,決定不遵循當前的編碼規範呢?

一般這個問題會被自行解決。假設咱們有一羣人在相同的項目代碼上進行工做,而且開始偏離既定的代碼規範。這可能會致使三個方向的發展。

首先,團隊的其餘成員會推進這名開發人員遵循標準,若是他不想離開團隊,他會接收的。

第二個方向是,開發人員可以說服團隊的其餘成員採用並遵循他的編碼規範。若是開發人員提出的編碼規範是更簡潔的,能帶來更好的結果,這應該是一件好事情。編寫並保持咱們的代碼簡潔,並不意味着咱們應該忽略任何改進它的機會。偏偏相反,咱們相信咱們老是應該質疑咱們目前的作法,並尋求改善的機會。

因此,若是一個開發者偏離了咱們的想法,並且他的作法更好,這樣的狀況下,咱們作出改變,多是最好的結果,而不是讓他來改變。我認爲,咱們審視和嘗試以前,咱們不該該忽視別人的方法。事情總有改進的餘地,咱們應該持續的尋找改進的方法,而不是固守成規。

最後一種也是咱們最不肯意看到的,開發者決定不採用咱們的規範,也不嘗試說服咱們採用他的規範。這可能致使他離開團隊。

2、編寫 Clean Code 的一些建議

以前,咱們在討論編寫簡潔代碼的一些好處,如今是時候學習一些技巧來幫助咱們作到這一點。

正如咱們將要看到的,擁抱簡潔的代碼並遵循這些建議進行實踐下去。這些咱們總結的作法,會使咱們的代碼更加清晰、可讀,更簡單而且易於理解。

固然,你並不須要實踐這些全部的建議,實踐而且遵循一兩個,就足以代碼有效的成果。

2.1 讓代碼可讀

是的,咱們編寫的代碼,最終會被機器解釋。可是,這並不意味着咱們應該忽略它的可讀性和可理解性。總會有另外的開發者有機會閱讀咱們的代碼,否者將沒法維護它。即便做爲獨立開發者堅持本身維護代碼,咱們也可能會在未來繼續維護咱們的項目。出於這些緣由,咱們應該保持咱們代碼的可讀性。

最簡單的方法是使用空格進行格式化,咱們在發佈代碼以前,將代碼壓縮(混淆)是能夠的。可是咱們並不須要編寫看起來像是被壓縮的代碼。相反,咱們可使用縮進、換行和空行,來使代碼的結構更具備可讀性。當咱們決定採起這個作法的時候,咱們代碼的可讀性和可理解性能夠顯著提升。

接下來,看一下咱們的示例代碼,就應該可以理解它了。

Code1:

// Bad
const userData=[{userId: 1, userName: 'Anthony Johnson', memberSince: '08-01-2017', fluentIn: [ 'English', 'Greek', 'Russian']},{userId: 2, userName: 'Alice Stevens', memberSince: '02-11-2016', fluentIn: [ 'English', 'French', 'German']},{userId: 3, userName: 'Bradley Stark', memberSince: '29-08-2013', fluentIn: [ 'Czech', 'English', 'Polish']},{userId: 4, userName: 'Hirohiro Matumoto', memberSince: '08-05-2015', fluentIn: [ 'Chinese', 'English', 'German', 'Japanese']}];

// Better
const userData = [
  {
    userId: 1,
    userName: 'Anthony Johnson',
    memberSince: '08-01-2017',
    fluentIn: [
      'English',
      'Greek',
      'Russian'
    ]
  }, {
    userId: 2,
    userName: 'Alice Stevens',
    memberSince: '02-11-2016',
    fluentIn: [
      'English',
      'French',
      'German'
    ]
  }, {
    userId: 3,
    userName: 'Bradley Stark',
    memberSince: '29-08-2013',
    fluentIn: [
      'Czech',
      'English',
      'Polish'
    ]
  }, {
    userId: 4,
    userName: 'Hirohiro Matumoto',
    memberSince: '08-05-2015',
    fluentIn: [
      'Chinese',
      'English',
      'German',
      'Japanese'
    ]
  }
];

code:

// Bad
class CarouselLeftArrow extends Component{render(){return ( <a href="#" className="carousel__arrow carousel__arrow--left" onClick={this.props.onClick}> <span className="fa fa-2x fa-angle-left"/> </a> );}};

// Better
class CarouselLeftArrow extends Component {
  render() {
    return (
      <a
        href="#"
        className="carousel__arrow carousel__arrow--left"
        onClick={this.props.onClick}
      >
        <span className="fa fa-2x fa-angle-left" />
      </a>
    );
  }
};

2.2 爲變量、方法取有意義的名稱

再讓咱們來看看第二個技巧,這將幫助咱們編寫易於理解的代碼。

這個技巧是關於變量、函數和方法使用有意義的名稱。有意義是什麼意思?有意義的名稱是具備描述性的名稱,不只僅是咱們,其餘人也可以看名稱就能理解,這些變量、函數和方法的目的。

換句話說,名稱自己應該就能夠提示變量、函數和方法的用途,或者它包含的內容。

接下來看個例子。

// Bad
const fnm = ‘Tom’;
const lnm = ‘Hanks’
const x = 31;
const l = lstnm.length;
const boo = false;
const curr = true;
const sfn = ‘Remember the name’;
const dbl = [‘1984’, ‘1987’, ‘1989’, ‘1991’].map((i) => {
  return i * 2;
});

// Better
const firstName = ‘Tom’;
const lastName = ‘Hanks’
const age = 31;
const lastNameLength = lastName.length;
const isComplete = false;
const isCurrentlyActive = true;
const songFileName = ‘Remember the name’;
const yearsDoubled = [‘1984’, ‘1987’, ‘1989’, ‘1991’].map((year) => {
  return year * 2;
});

可是,咱們應該知道,使用描述性名稱並不意味着咱們能夠自由使用盡量多的單詞來描述它。一個好的經驗法則是將名稱限制在三個或者四個單詞。若是咱們須要四個以上的單詞才能描述它,這也許是由於咱們一次嘗試讓它作太多的事情,這個時候咱們應該簡化咱們的代碼,而不是堅持使用它。

2.3 讓一個函數或者方法,只執行一個任務

當我開始寫代碼的時候,我曾經寫過相似瑞士軍刀的功能和方法。它們能夠處理和作任何事情。可是到了後期,其中的一個後果就是很難再找到一個好名字來擴展它。其次,除了我以外,幾乎沒有人知道這個和那個功能是什麼以及如何使用它,有時候我本身也會面臨這個問題,因此我不得不寫下注釋。第三,這些功能是不可預測的,而我所以寫了一段混亂的代碼。

而後,有人給了一個偉大的建議,讓每一個功能或方法只執行一項任務。這個簡單的建議改變了一切,並幫助我編寫簡潔的代碼,至少比以前更加乾淨簡潔。從那一刻開始,其餘人終於可以理解個人代碼了。或者說,他們不須要像之前同樣,花費那麼多的時間來理解個人代碼。個人功能和方法也變得可預測。在相同的輸入下,它們老是產生相同的輸出。並且,命名也變得更容易。

若是你很難爲你的函數和方法找到描述性名稱,或者你須要編寫冗長的註釋以便其餘人可使用它們,請考慮實時單一職責。讓每一個函數或方法只執行一項任務。若是你的函數和方法看起來像瑞士軍刀同樣大而全,也能夠實施這種作法。相信我,在編寫代碼上,任何多功能性都不是一個優點。任什麼時候候均可能會致使拔苗助長的效果,這是一個至關不利的因素。

注意:讓每一個函數或方法只執行一項任務的作法稱爲單一責任原則。羅伯特·C·馬丁(Robert C. Martin)將這種編碼實踐做爲五種面向對象設計原理之一(也稱爲SOLID)進行了介紹。

// Example no.1: 簡單的減法
function subtract(x, y) {
    return x - y;
}
// Example no.1: 簡單的乘法
function multiply(x, y) {
    return x * y;
}

// Example no.1: Double numbers in an array
function doubleArray(array) {
  return array.map(number => number * 2)
}

2.4 寫好註釋

無論咱們爲本身的變量,函數和方法,絞盡腦汁的相處有意義的名稱。咱們的代碼自己可能仍是有一些不清晰或者不易於理解的地方。多是有一些邏輯分支須要單獨解釋,這些可能不是它們很難理解和使用的緣由。相反可能只是一些歷史遺留問題。

有時咱們可能不得不採起很是規的方式來解決問題,由於沒有別的辦法可行,或者咱們沒有足夠的時間來提出更好的解決方案。

這可能很難用代碼解釋。經過在咱們的代碼中,增長註釋能夠幫助咱們解決這個問題。註釋能夠幫助咱們向其餘人解釋爲何咱們寫了這段不合規的代碼,以及我面臨的問題和現狀。所以,其餘人在閱讀的時候就很清晰,沒必要猜想個人當時的想法。

更重要的是,當咱們解釋咱們的緣由時,其餘人可能會找到一個更好的方法來解決問題並改進代碼。這是可能的,由於他們可能知道問題是什麼,指望的結果是什麼。若是不知道這些信息,其餘人就難以創造更好的解決方案。否者,其餘人將不會嘗試優化解決它,由於他們不認爲有這個須要,他們可能認爲這就是咱們真實的想法。

因此,當咱們發現本身處於一種咱們決定使用一些很是規的方式,快速修復或繞過問題方法的來解決問題狀況下,咱們就應該用註釋來解釋爲何咱們面臨的是什麼問題,爲何要這麼作。用一兩行註釋來解釋它比強迫其餘人猜想更好。

也就是說,咱們應該只在有必要時才使用註釋,而不是解釋錯誤的代碼。不停的增長註釋,並不會幫助咱們將寫得差的代碼轉換成乾淨簡潔的代碼。若是代碼很差,咱們應該經過改進代碼來解決問題,而不是經過添加關於如何使用代碼的註釋。簡潔的代碼優先於使用註釋解釋。

2.5 保持一致

當咱們找到咱們喜歡的具體的編碼實踐或風格時,咱們應該堅持並在任何地方使用它。在不一樣的項目中使用不一樣的編碼規範或樣式不是一個好主意。它幾乎與不使用任何編碼規範或風格同樣無用。這將致使,回到咱們的舊代碼將不會如此平穩和天然。咱們仍然須要一些時間來理解咱們在該項目上使用的編碼規範,而後才能使用它。

最好的辦法是挑選一套編碼規範,而後在咱們全部的項目中堅持這些規範。那麼,回到咱們之前的代碼會更容易,並繼續咱們中止或改進的地方。嘗試新的編碼規範是一件好事。它能夠幫助咱們找到更好的方式來完成咱們的工做。

可是,在挑選編碼規範的時候,咱們應該多作一些嘗試,而且實際使用在多個地方。咱們應該花精力去驗證咱們的規範,來保證它整的適合咱們,只有在咱們對此感到滿意的時候,咱們才應該實施它。而且在所有項目中,使用這套規範。

2.6 定義檢查代碼,適時重構

這是我編寫乾淨的代碼的最後一個技巧。

簡單地寫簡潔的代碼並非一切。咱們的工做並不由於咱們使用了簡潔的風格編寫代碼而結束。下一步是保持咱們的代碼的簡潔。簡潔的代碼須要維護,當咱們寫代碼的時候,咱們應該按期回視檢查,清理垃圾代碼並進行改進。不然,若是咱們不檢查和更新舊代碼,它很快就會過期。就像咱們的硬件設備同樣。若是咱們想要保持最佳狀態,咱們須要按期更新它們。

對於咱們天天使用的代碼來講,狀況尤爲如此。代碼有變得愈來愈複雜和混亂的趨勢,而不是簡單和整潔。咱們要防止這種狀況發生,並保持咱們的代碼的簡潔。要作到這一點的惟一方法是按期檢查咱們的代碼。換句話說,咱們須要維護它。對於咱們再也不關心或沒有前途的項目來講,這可能不是必要的。對於其重要的項目來講,維護是咱們工做的一部分。

3、關於編寫 Clean Code 的總結

這篇文章到此就要結束了。

咱們今天討論的這六種作法可能不是那些影響最大或效果最顯着的作法。可是,他們是經驗豐富的開發人員最常提到的。這就是我選擇他們的緣由。我但願這些實踐或技巧足以幫助你開始編寫乾淨的代碼。

如今,像全部事情同樣,最重要的是開始。因此,選擇至少一個練習,並嘗試一下。

英文原文地址:

https://hackernoon.com/6-simp...

今天在承香墨影公衆號的後臺,回覆『成長』。我會送你一些我整理的學習資料,包含:Android反編譯、算法、設計模式、虛擬機、Linux、Web項目源碼。

推薦閱讀:

相關文章
相關標籤/搜索