寫不出這種代碼益涧,就等著被leader開除吧锈锤!

前言

在我們平時刷題的時候,你可能會寫過很多諸如

int a,b,c
int [] arrays=new int arrays[10];
if((numbers > 10 && flag == 'true') || flag =='false')

這種代碼闲询,對于我們自己練習(xí)編程或者解決一個算法題久免,當(dāng)然沒有問題。但是如果是在一個工程中扭弧,尤其是幾十上百人維護(hù)了幾年的工程中阎姥,還使用這種寫法,傾瀉自己天馬行空的才華鸽捻,保證leader不打死你哦呼巴。

所以,對于代碼的整潔性泊愧,可讀性伊磺,自古以來就有很多大神做出過總結(jié),比如這本《clean code》,中文名叫做《代碼整潔之道》删咱,今天屑埋,我們就來看看吧。

命名

命名思想

首先就是命名痰滋,命名可以說是一切程序的基礎(chǔ)摘能,如果用三個字來形容那就是——“有意義”。

你要做到敲街,當(dāng)一個人看到你的命名团搞,就知道這個變量/函數(shù)是干什么的

來看這一段代碼:

public List<int[]> getThem() {
  List<int[]> list1 = new ArrayList<int[]>();
  for (int[] x : theList)
    if (x[0] == 4)
      list1.add(x);
  return list1;
}

這段代碼非常簡潔多艇,但是非常模糊逻恐,我們不知道theList到底是什么,為什么x==4作為判斷峻黍,list1又是什么复隆?

現(xiàn)在我們來改一改:

public List<int[]> getFlaggedCells() {
  List<int[]> flaggedCells = new ArrayList<int[]>();
  for (int[] cell : gameBoard)
  if (cell[STATUS_VALUE] == FLAGGED)
  flaggedCells.add(cell);
  return flaggedCells;
}

從上面的代碼中,我們可以馬上看出來姆涩,flaggedCells表達(dá)的是標(biāo)致cell挽拂,而cell位于gameBoard中,就是一個游戲面板骨饿,只需要再通過文件名亏栈,知道這是一個【掃雷游戲】台腥,那么cell就是每一個格子,if語句中就是判斷每一個格子是否被點擊過绒北,如果是黎侈,就添加到flaggedCells中,我們顯然知道他想要干什么——搜集玩家點擊過的格子并返回镇饮。

但是蜓竹,上面的代碼嗎使用的是 int 數(shù)組,比如int[] cell储藐,每一個數(shù)組內(nèi)部的數(shù)表示cell的狀態(tài)俱济,可是cell并不需要那么多狀態(tài),而且這樣導(dǎo)致每次使用這個狀態(tài)的時候都要重新定義數(shù)組钙勃,狀態(tài)是cell的一個屬性蛛碌,所以,完全可以定義一個cell的類辖源,將他的狀態(tài)封裝進(jìn)入蔚携。

public List<Cell> getFlaggedCells() {
    List<Cell> flaggedCells = new ArrayList<Cell>();
    for (Cell cell : gameBoard)
    if (cell.isFlagged())
    flaggedCells.add(cell);
    return flaggedCells;
}

這樣子很清晰看出,gameBoard由Cell組成克饶,從gameBoard中取出標(biāo)記過的cell放入flaggedCells中酝蜒,這樣的代碼是不是感覺渾然天成,自然而然呢矾湃?

命名規(guī)范

通過以上事例亡脑,你應(yīng)該理解在寫工程項目時,諸如數(shù)組邀跃,鏈表霉咨,字典這些底層結(jié)構(gòu)應(yīng)該要封裝在User,Cell拍屑,Address這種類中途戒,使用的時候直接使用這些類即可,這是一種大局觀的思維僵驰,現(xiàn)在我們來做一些較為細(xì)節(jié)的落地規(guī)范喷斋。對于什么駝峰命名,匈牙利命名我相信你不會陌生蒜茴,但是我在這里再強(qiáng)調(diào)兩個地方星爪。

  • 類名

    • 類作為一個對象,需要的是名詞或者名詞短語矮男,gameBoard移必,Ueser都是如此室谚,不要使用模糊名詞(就是概念很大的名詞)毡鉴,比如Data崔泵,因為可以細(xì)分為UserData,MoneyData等猪瞬,對于可以細(xì)分的模糊名詞憎瘸,一定要用名詞短語。
    • 類名都是第一個字母大寫的名詞組合陈瘦。
  • 方法名

    • 方法作為具體干事的執(zhí)行者幌甘,當(dāng)然是使用動詞或者動詞短語了,同樣注意的是痊项,不要使用模糊動詞锅风,和上面不一樣的是,解決模糊名詞的方法是增加名詞修飾鞍泉,而解決模糊動詞的方法是【換更精準(zhǔn)的動詞】
    • 比如getInformation皱埠,就不好,因為get太大了咖驮,你的information是pull過來的還是clone過來的边器?是被動接受的還是主動去取的?Information這個詞也很模糊托修,所以可以根據(jù)情況拆分為直接取用戶數(shù)據(jù)——fetchUserData忘巧,上傳新數(shù)據(jù)再取用戶數(shù)據(jù)——uploadAndfetchUserData。
    • 不是不能用get睦刃,是說如果有更好的選擇砚嘴,盡量用更精準(zhǔn)的動詞。
    • 注意方法名第一個字母小寫眯勾。

函數(shù)

第一原則

短小

如果還有第二原則枣宫,那還是短小。

短小到什么程度吃环,最多20~30行吧也颤,

所以要求,一個函數(shù)郁轻,只做一件事情翅娶,

什么叫做只做一件事情呢?

就拿處理數(shù)據(jù)來說好唯,我們說【處理用戶數(shù)據(jù)】是一件事竭沫,你也可以說是做了三件事:

  1. 取數(shù)據(jù)
  2. 處理數(shù)據(jù)
  3. 返回數(shù)據(jù)

當(dāng)然,這個例子有點抬杠的意思骑篙,不過反映的現(xiàn)實是蜕提,代碼中各種邏輯往往你中有我,我中有你靶端,到底一件事情的邊界在哪里谎势?

這個因人而異凛膏,我只能提出書中的方法。

  1. 同一抽象級

    剛才那個取數(shù)據(jù)脏榆,就是在同一抽象級下完成的事情猖毫,就可以看做是一件事,如果再來一件——保存用戶數(shù)據(jù)须喂,顯然吁断,可以歸到前面,還是一件事坞生,如果再來一件——取車輛數(shù)據(jù)仔役,顯然,就是另外一個抽象的東西了是己。

  2. 分割判定與處理

    這個好理解骂因,就是立法與司法的分割,比如:

    if (set("username", "unclebob"))
      ...
    

    就讓人迷惑赃泡,他表達(dá)的意思是不是如果unclebob成功賦值給username就返回true呢寒波?還是說如果username為null時就用unclebob

    賦值進(jìn)入呢?username到底是屬性還是碰巧一個字符串叫做username呢升熊?隨便猜俄烁。

    但是我們這樣修改:

    if (attributeExists("username")) {
     setAttribute("username", "unclebob");
     ...
    }
    

    如果有username這個屬性,就賦值级野,非常清晰页屠,也就是說,判定與處理要分隔開蓖柔。

你可能會說辰企,對于像if,while况鸣,switch這種語句牢贸,往往動輒十幾行,短不了案渑酢潜索!

首先,這個原則不是鐵律懂酱,實在太長也沒辦法竹习。

其次,對于這些語句列牺,完全可以講里面的邏輯做一個封裝整陌,比如這種:

public static String renderPageWithSetupsAndTeardowns(
  PageData pageData, boolean isSuite) throws Exception {
  if (isTestPage(pageData))
    includeSetupAndTeardownPages(pageData, isSuite);
  return pageData.getHtml();
}

if 語句之后做了一件includeSetupAndTeardownPages的事情,不僅極大增強(qiáng)了可讀性,而且代碼短了不少泌辫。

關(guān)于參數(shù)

當(dāng)你看jdk源碼或者是android源碼的時候并炮,你會發(fā)現(xiàn)他們經(jīng)常做調(diào)用,尤其是同名的方法重載甥郑,在看《算法》這本書的時候,也是荤西,比如關(guān)于快速排序的:

public static void quickSort(int [] arrays){
  quickSort(arrays,0,arrays.length-1);
}
private static void quickSort(int [] arrays,int left,int right){
  ...
}

我在一開始接觸的時候澜搅,覺得雖然好看,但未免麻煩邪锌,隨著經(jīng)驗的提升勉躺,這是一種非常好的編程習(xí)慣。

首先觅丰,對于用戶來說饵溅,他想要進(jìn)行快排,想傳的只有數(shù)組妇萄,左右邊界都包含進(jìn)去了蜕企,你為什么要他多傳參數(shù)?同時第一個方法使用的是public冠句,就表示這是暴露給用戶的轻掩。

其次,第二個方法在第一個方法中被調(diào)用懦底,用private保護(hù)了起來唇牧,避免了無數(shù)麻煩

所以聚唐,越是業(yè)務(wù)層的邏輯丐重,越要寫參數(shù)少的代碼,如果參數(shù)必須要很多杆查,那就用一個private的函數(shù)封裝起來扮惦,你讓用戶擁有一百個參數(shù)輸入,對他來說亲桦,那不是自由径缅,那是災(zāi)難。

蘋果和微信的使用體驗就是將這種哲學(xué)貫徹到極致的代表烙肺。

注釋

最好的注釋纳猪,就是代碼本身

用代碼能解釋清楚的事情桃笙,盡量少用注釋氏堤,如果注釋太多,只能證明代碼寫得爛……

不過有些地方還是有必要寫代碼的。

位置

最好寫在方法頂部鼠锈,不插入到實際代碼中闪檬,比如那個面試幾乎必問的String中的equals方法,源碼如下:

 ... 
 * @see  #compareTo(String)
 * @see  #equalsIgnoreCase(String)
 */
public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = length();
        if (n == anotherString.length()) {
            int i = 0;
            while (n-- != 0) {
                if (charAt(i) != anotherString.charAt(i))
                        return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

警示的注釋

這里可以寫一些告誡他人的代碼购笆,讓后來的接盤俠能夠引起重視粗悯。

//When I wrote this, only God and I understood what I was doing
//Now, God only knows

簡單說就是,下面的代碼一定有用同欠,但是我也看不懂了样傍,你別碰O(∩_∩)O哈哈~

在知乎上看到還有這樣的。

//如果這段報錯铺遂,你在機(jī)器上裝一個360安全衛(wèi)士衫哥,相信我我
以為是開玩笑,結(jié)果裝了就真的好了襟锐。這個是前人留給我的撤逢。
//這個服務(wù)有問題的話,你可以問某某某粮坞,這段是他寫的蚊荣。
這個是在我離職交接時寫的,出賣了未離職的一個同事莫杈。
//執(zhí)行成功后發(fā)送一條通知短信妇押,穩(wěn)定后注釋掉
手機(jī)號是寫死的,我看到這段的時候還沒有注釋姓迅,這一年每天凌晨他都能收到短信敲霍。

作者:hll
鏈接:https://www.zhihu.com/question/296123587/answer/498701733
來源:知乎

這些人水平怎么樣另說,但是對于后人還是用心的丁存。

TODO注釋

這個就不說了肩杈,很常用。


看完了有用的注釋解寝,我們來看看沒用的注釋

多余的

// Utility method that returns when this.closed is true. Throws an exception
// if the timeout is reached.
public synchronized void waitForClose(final long timeoutMillis)
  throws Exception
  {
        if(!closed)
    {
  wait(timeoutMillis);
    if(!closed)
        throw new Exception("MockResponseSender could not be closed");
  }
}

這就是把代碼做了什么又描述一遍扩然,沒有任何意義。

被注釋掉的代碼

InputStreamResponse response = new InputStreamResponse();
response.setBody(formatter.getResultStream(), formatter.getByteCount());
// InputStream resultsStream = formatter.getResultStream();
// StreamReader reader = new StreamReader(resultsStream);
// response.setContent(reader.read(formatter.getByteCount()));

相信很多人都有這樣的行為聋伦,在自己寫算法題的時候用來測一測沒有任何問題夫偶,但是對于后來者來說,他該怎么辦觉增?

他一定會想:也許是有用的呢兵拢?不然為什么之前要寫。

但是他又看不懂或者覺得沒必要看逾礁,于是就留了下说铃,然后這樣的代碼就會越來越多,最終成為傳說中的祖?zhèn)鞔a。

不用心

注釋要清楚腻扇,如果注釋還要寫注釋來解釋债热,根本沒有意義。

比如下面這個幼苛,為什么要用200窒篱?

/*
* start with an array that is big enough to hold all the pixels
* (plus filter bytes), and an extra 200 bytes for header info
*/
this.pngBytes = new byte[((this.width + 1) * this.height * 3) + 200];

小結(jié)

對于多數(shù)人來說,命名函數(shù)與注釋基本上就是程序的主要組成部分舶沿,能夠處理好這三樣就能寫出非常好的代碼了墙杯,當(dāng)leader看到你的提交的時候,看到的是如此優(yōu)雅的代碼暑椰,我想,他也會覺得是一種享受吧荐绝,就和詩歌一樣一汽。

作者簡介:小松漫步,一個剛?cè)肼毜男氯说吞玻⑿殴娞枴拘∷陕健空偌校恼聟⒖甲浴洞a整潔之道》,公眾號回復(fù)【代碼整潔之道】即可獲取資源恕沫,一起加油吧监憎。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市婶溯,隨后出現(xiàn)的幾起案子鲸阔,更是在濱河造成了極大的恐慌,老刑警劉巖迄委,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件褐筛,死亡現(xiàn)場離奇詭異,居然都是意外死亡叙身,警方通過查閱死者的電腦和手機(jī)渔扎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來信轿,“玉大人晃痴,你說我怎么就攤上這事〔坪觯” “怎么了倘核?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長即彪。 經(jīng)常有香客問我笤虫,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任琼蚯,我火速辦了婚禮酬凳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘遭庶。我一直安慰自己宁仔,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布峦睡。 她就那樣靜靜地躺著翎苫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪榨了。 梳的紋絲不亂的頭發(fā)上煎谍,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天,我揣著相機(jī)與錄音龙屉,去河邊找鬼呐粘。 笑死膳帕,一個胖子當(dāng)著我的面吹牛巷送,可吹牛的內(nèi)容都是我干的砾淌。 我是一名探鬼主播纫塌,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼拼坎,長吁一口氣:“原來是場噩夢啊……” “哼谐丢!你這毒婦竟也來了狮崩?” 一聲冷哼從身側(cè)響起彪见,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤枢步,失蹤者是張志新(化名)和其女友劉穎沉删,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體醉途,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡丑念,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了结蟋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脯倚。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖嵌屎,靈堂內(nèi)的尸體忽然破棺而出推正,到底是詐尸還是另有隱情,我是刑警寧澤宝惰,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布植榕,位于F島的核電站,受9級特大地震影響尼夺,放射性物質(zhì)發(fā)生泄漏尊残。R本人自食惡果不足惜炒瘸,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望寝衫。 院中可真熱鬧顷扩,春花似錦、人聲如沸慰毅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽汹胃。三九已至婶芭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間着饥,已是汗流浹背犀农。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留宰掉,地道東北人呵哨。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像贵扰,于是被迫代替她去往敵國和親仇穗。 傳聞我的和親對象是個殘疾皇子流部,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,864評論 2 354