在工作中如何優化前端程式碼?

方應杭在飢人谷發表於2018-11-16

此為知乎問答,我把我的答案稍作整理放到這裡來了。


原則

首先說一個最重要的優化原則:程式碼優化是每天都要進行的,而不是一兩個月做一次大優化,那時做就已經晚了。另外由於優化是每天做的,所以你不需要一次的就過度優化,保持小步快跑即可。

這個原則為什麼重要?因為很多程式設計師會在寫程式碼的時候說「先不優化了,等不忙的時候再優化」,然後……就沒有然後了。

基本上「爛程式碼」就是因為「不忙的時候再優化」造成的。

別給自己寫爛程式碼找理由

如果只要每天優化一點點程式碼,就能保持你的程式健康,你,能做到嗎?

據我觀察,90% 的程式設計師做不到。他們每天都會在心裡找出如下理由來寫出爛程式碼,或者對現有的爛程式碼視而不見:

  1. 這個專案我只維護幾個月,沒必要把程式碼寫那麼好,反正有人接盤。
  2. 這個專案是從別人手裡接下的,程式碼真爛,要怪就怪之前的人,不是我的錯,我胡亂加一些程式碼就行了,能用就行。
  3. 這是一個短期專案,沒必要把程式碼寫那麼好
  4. 這是一個長期專案,明年再優化程式碼,現在能用就行

所以你看,不管我告訴他們多少優化程式碼的技巧,他們根本就不會去用的,這才是問題所在。

很多程式設計師抱怨公司程式碼爛,卻從來不去嘗試解決問題。(就像很多程式設計師抱怨培訓班教出來的人水平差,自己卻不寫新人教程一樣)

過手就變好

如果你不想變成上面那樣的程式設計師,你只堅定一個信念:只要是經過我的手的程式碼,質量就會比原來好一點。

那麼你很快就能把程式碼寫好了。你可能急於聽到把程式碼寫好的技巧,但是我告訴你,技巧真的不重要,這個信念才是最重要的。

接下來就是技巧。

第一步:不要寫爛程式碼

方方你是傻了嗎,問的是「如何優化程式碼」,你的答案居然是「不要寫爛程式碼」?!

沒錯,把程式碼寫好的第一步就是不要寫爛程式碼,也就是你要知道「什麼樣的程式碼是爛程式碼」:

如何寫出無法維護的程式碼 - 酷 殼

上面這篇教程非常好,把市面上的爛程式碼基本都總結出來了,大概有這麼幾類:

  1. 爛變數名
  2. 爛註釋
  3. 爛設計
  4. 不寫測試(所有沒有單元測試的程式碼都是爛程式碼,快點學習單元測試!)

基本上所有新人天天都在寫爛變數名、爛註釋和爛設計,而且還不寫單元測試。

而且他們還不知道自己程式碼多爛!

所以第一步就是明白一個真相:你80%的程式碼都是爛程式碼。

你只需要把這些程式碼改得不那麼爛,就是優秀的程式碼了……

再說一次:第一步至關重要,搞清楚什麼樣的程式碼是爛程式碼。

第二步:避免重複

也就是 Don't Repeat Yourself 原則。如果你發現有兩行程式碼重複出現了好幾次,你就應該把這兩行程式碼封裝成一個函式,放在一個恰當的地方,然後呼叫這個函式。

第三步:表驅動程式設計

如果你的程式碼有很多 if ... else ... 結構,你不知道怎麼優化,你就應該使用表驅動程式設計。

優化前:

howManyDays(year, month){
    if(month === 1 ||
        month === 3 ||
        month === 5 ||
        month === 7 ||
        month === 8 ||
        month === 10 ||
        month === 12
    ){
        return 31
    }else if(month === 2){
        return isLeapYear(year) ? 29 : 28
    }else{
        return 30
    }
}
複製程式碼

優化後:

howManyDays(year, month){
    const table = {
        1: 31, 3: 31, 5: 31, 7: 31, 8: 31, 10: 31, 12:31,
        4: 30, 6:30, 9: 30, 11: 30,
        2: isLeapYear(year) ? 29 : 28
    }
    return table[month]
}
複製程式碼

優化前:

function calculateGrade(score){
    if(score>=90){
        return 'A'
    }else if(score >= 80){
        return 'B'
    }else if(score >= 70){
        return 'C'
    }else if(score >= 60){
        return 'D'
    }else {
        return 'E'
    }
}
複製程式碼

優化後:

function calculateGrade(score){
    const table = {
        100: 'A', 
        90: 'A',
        80: 'B',
        70: 'C',
        60: 'D',
        others: 'E'
    }
    return table[Math.floor(score/10)*10] || table['others']
}    
複製程式碼

第四步:用套路

設計模式就是一些程式設計套路,Unix 程式設計原則也是一些程式設計套路。

瞭解所有的套路,然後遇到問題選擇正確的套路即可。

比如模組通訊一般用事件模式或者命令模式;

比如解耦一般用中間層;

比如生命週期一般都支援鉤子或切面;

比如效能優化一般都是加快取;

比如 API 設計一定要正交;

比如複雜資料系統一般使用命令查詢職責分離;

比如拿空間換時間拿時間換空間;

……

這一塊還挺複雜的,夠你糾結很久了,而且沒有通解。唯一的通解就是 tradeoff。

第五步:堅持每天優化

我在課上說過,「每天優化」才叫重構,「每年優化」那叫重寫。

優化的重點是「越來越好」,重點不是「一次寫好」。

一旦你放鬆對自己程式碼的要求,你的程式碼就會迅速變成爛程式碼,而且很難恢復。

每當需求變化的時候,你都要重新審視你的整個系統,哪裡有問題你就改那裡,不允許「先臨時改一下以後再優化」,你的程式碼就可以保持健康和活力。

可惜,大部分人做不到。就算我自己也會在需求太多的時候放鬆對程式碼的要求。

以上內容在我的《JS深入淺出》課程中有所涉及,課程講義在此

相關文章