官术网_书友最值得收藏!

3.1 代碼風格與破窗理論

在2019年小米的一次發布會上,雷軍因為一句“我沒有寫過詩,但有人說我寫過的代碼像詩一樣優雅”登上熱搜,后來網上流傳出一份代碼的截圖,從中可以看到頂部的版權信息、摘要注釋、修訂記錄,最后才是工整的代碼,即便沒有學過匯編語言,相信大部分開發者都能感受到代碼中表現出的嚴謹和認真。

不好的代碼各有各的問題,而好的代碼卻存在很多共性:一致的語法風格、規范的命名方式、清晰的邏輯結構,簡潔且優雅。對比一下我們小時候誦讀的唐詩宋詞,或五言或七言,或絕句或律詩,不就是對語法風格的統一要求嗎?詞牌名的使用也是一種命名規范,至于邏輯清晰和簡潔優雅,詩詞本身就已經是完美的詮釋了。如果說代碼是開發者的文字,那么無論是看似呆板的代碼,還是優美動人的詩詞,對美的表達是有異曲同工之妙的。

要想提高整個團隊的代碼質量,僅僅依靠制定編碼規范是不夠的,這就好像統治者除了依靠道德約束之外,還需要依賴法律的力量才能維持社會穩定一樣。或許每個團隊都有自己的開發規范,但幾乎所有的團隊也都需要面對代碼維護的問題。我們最好能使用一些輔助工具,幫助開發者養成符合規范要求的良好的編碼習慣,并在不符合項出現時給予提示,同時制定一些強制的攔截策略,以阻止不符合要求的代碼入庫。同時,你還需要通過多種途徑,借鑒好的代碼和設計模式來提高自己的編碼水平。雖然用若干個嵌套在一起的for循環來實現某個業務邏輯并沒有違背任何編碼規范,但當你看到別人用map、filter、some等更具語義性的方法連在一起實現同一段業務邏輯時,立刻就會明白自己的代碼語義不夠清晰。你能夠看懂高手使用的每一個方法,卻無法寫出類似的代碼,很多時候這并不是代碼本身的復雜性造成的,而僅僅是你還沒有意識到原來還可以那樣寫。

很多時候初級開發者在開發中只是“用程序語言來翻譯業務邏輯”,而并沒有在進行“程序設計”,下面的示例或許能讓你更好地理解這種差異。

假設有這樣一個數組:

var dataList = [{
    id:0,
    name:'Tony',
    food:['apple', 'peach', 'coconut']
},{...},{...}];

現在需要將所有food字段的值用逗號連接起來,拼成一個字符串后發送給后臺,你會如何編寫代碼呢?下面我們來看一些常見的寫法:

/*版本一*/
var result = '';
for (var i = 0; i < dataList.length; i++){
    for (var j = 0; j < dataList[i].food.length; j++){
        result = result + dataList[i].food[j] + ',';
    }
}
result = result.slice(0,-1);
/*版本二*/
var result = [];
for (var i = 0; i < dataList.length; i++){
    for (var j = 0; j < dataList[i].food.length; j++){
        result.push(dataList[i].food[j]);
    }
}
result = result.join(',');
/*版本三*/
result = dataList.map(item=>item.food.join(',')).join(',');

對比上述三個版本,相信不需要多做解釋,你也能明白筆者想要傳達的東西。下面再來看一個例子,假設我們希望實現這樣的功能:將學生的考試成績轉化為用ABCD表示的等級,如表3-1所示。

表3-1 分數區間對應等級表

038-1

下面先來看一些常見的寫法(代碼中省略了邊界及類型檢查):

/*版本一 直譯業務邏輯*/
function transformScore(score) {
    if(score >= 60 && score < 70) return 'D';
    if(score >= 70 && score < 80) return 'C';
    if(score >= 80 && score < 90) return 'B';
    if(score >= 90 && score <= 100) return 'A';
}
/*版本二 使用對象+字典模式*/
function transformScore(score) {
    var resultMap = {
        '6':'D',
        '7':'C',
        '8':'B',
        '9':'A',
        '10':'A',
    }
    return resultMap[Math.floor(score / 10)];
}
/*版本三 使用字符串+字典模式*/
function transformScore(score) {
    return 'DCBAA'[(Math.floor(score / 10)) - 6];
}
/*版本四 使用ASCII碼轉換*/
function transformScore(score) {
    return score === 100 ? 'A' : String.fromCharCode(74 - Math.floor(score/10));
}

上述代碼展示的四個版本中,版本三僅僅是轉換結果較為簡單時的一種特殊情況,相比之下,更推薦的做法是使用版本二的模式,盡管其看起來不如后兩種版本簡潔。也許有人會覺得版本四那樣的代碼很酷,但事實上它不僅增加了其他開發人員的理解難度,性能也不如其他幾種版本。沒有人會因為這樣的代碼而對你刮目相看,因為它怎么看都像是過分賣弄,好代碼的首要條件必須是清晰且可讀的。

犯罪心理學中著名的“破窗效應”并不僅僅適用于犯罪行為,符合這個法則的例子在生活中隨處可見,對于軟件工程來說也不例外。如果團隊中定期組織開發人員進行代碼檢視,每個人都堅持依照規范來修正自己代碼中不夠好的部分,長此以往,整個工程文件就會保持在一個相對規范的狀態,那么大家就可以把關注點聚焦在業務邏輯的復雜性和代碼的健壯性上。一旦有人放松要求,開始貢獻劣質代碼,很快其他人就會降低對代碼質量的要求,每個人都會覺得代碼整體質量的惡化不是自己一個人造成的,不久之后整個項目的代碼就會變得難以維護。很多時候,技術不得不為業務“開綠燈”,如果因為緊急情況來不及進行代碼檢視就發布上線,這時負責人最好讓相關開發者在接下來的一周內完成代碼檢視和問題修復并主動公示,否則你將會發現越來越多的人以此為借口來繞開代碼檢視的環節。

拓展知識

破窗效應[1]是一個犯罪心理學理論,它認為如果放任環境中的不良現象存在,則會誘使人們效尤,甚至變本加厲。以一幢有少許破窗的建筑為例,如果那些窗戶不及時修理好,可能就會引發破壞者故意破壞更多窗戶。最終他們甚至還會闖入建筑物內,如果發現無人居住,也許就會在那里定居或縱火。再比如,如果一面墻上出現了一些涂鴉并且沒有及時清洗掉,很快墻上就會布滿亂七八糟、不堪入目的內容;如果一條人行道上有些許紙屑,不久之后就會有更多的垃圾,最終人們會理所應當地將垃圾順手丟在地上。這些現象所表述的,就是犯罪心理學中的破窗效應。

在工程實踐中你會發現,即使花費再多的精力去制定和完善編碼規范,并不斷組織學習和宣講,也依然很難奢求此規范獲得所有人的重視,因為在很多開發者的眼里,這屬于“無關緊要的小事”。當一個人意識不到某些事情的重要性時,將事情的結果寄托在強制要求和自覺性上是一種不明智的做法。我們要做的是使用正確的工具來簡化這一過程,這就好比是不斷叮嚀別人吃蘋果與你把蘋果洗干凈遞到別人手里的區別——“不想吃蘋果”的意思其實只是“不想洗蘋果”而已。前端領域已經提供了很多成熟的工具,我們只需要學習其用法,并將團隊的開發規范融入進去即可,這樣做的好處非常明顯,具體說明如下。

  • 不同語言的開發者喜歡使用不同的開發工具,隨著現代化開發中多語言混合開發的場景日益增多,配置文件能夠幫助團隊成員突破編輯器的限制而遵循相同的規則。
  • 能夠節省代碼評審的時間,我們可以安全地忽略與代碼風格相關的所有問題,并專注于開發者真正需要關注的的事情,例如,代碼的結構、語義、耦合度等。
  • 能夠發現語法錯誤和一般類型錯誤、未定義的變量,等等,我們可以根據團隊的實際情況啟用不同的檢查規則,事實上,ESLint官方公布的可開啟和關閉的規則就多達200條。
  • 為工具設置配置文件幾乎是一次性的工作,但其節省時間的作用卻是持久化的。

下面就來學習如何利用各種輔助工具為團隊制定編碼規范。


[1]摘錄自百度百科。

主站蜘蛛池模板: 桓仁| 周口市| 涟水县| 汉阴县| 淳化县| 阳高县| 吉木乃县| 绵竹市| 旅游| 平罗县| 揭阳市| 台中市| 淅川县| 综艺| 奉贤区| 平湖市| 习水县| 广宗县| 南京市| 张家口市| 岳普湖县| 青河县| 沂水县| 额济纳旗| 武清区| 蓬安县| 黎川县| 丰顺县| 宝应县| 沈丘县| 万载县| 辛集市| 柳江县| 邵东县| 东乌| 鹤壁市| 宜都市| 浦东新区| 横山县| 林州市| 霸州市|