iT邦幫忙

2021 iThome 鐵人賽

DAY 22
1
Modern Web

Javascript 從寫對到寫好系列 第 22

Day 22 - Formatter 與 Linter - 提升程式品質工具

  • 分享至 

  • xImage
  •  

前言

昨天講完 Code Review,團隊一致的寫 code 風格,可以大幅提升 review 的速度,也可以讓每個人的程式碼更好閱讀。

因此今天來聊聊兩個很容易被忽略,但其實在每一次儲存的背後,都扮演了重要角色的 Formatter & Linter。

Formatter

Formatter 是什麼呢?簡單來說就是「程式碼排版神器」啦!

舉例來說,對於帶有很多參數的 function,有些人是這樣寫:

const fetchUserOrder(startDate, endDate, userId, orderStatus) {
    // ...
};

但有些人更喜歡分行:

const fetchUserOrder(
    startDate, 
    endDate, 
    userId, 
    orderStatus
) {
    // ...
};

formatter 的優勢

如果整個程式都是自己寫還沒什麼問題,但如果一個團隊中出現兩種風格,往往 review code 的人會加倍辛苦,因為人畢竟是習慣的動物,舉個例來說:

  • 我可以看懂橫式書寫的文字












但是當
  這
  兩
  種混合在一起的時候,我
            會
            很
            痛
            苦

我打這個範例比較痛苦QQ

當然第一個想法就是:那就訂個規則,大家都橫式書寫,或者大家都參數都規定要換行,這樣就好了呀!

但事情沒那麼簡單:

  • 原本用直式書寫的人可能已經習慣了,會不自覺用直式
  • 從網路上 copy 回來的範例,可能還要花時間排版

因此,我們需要用到 formatter,可以幫我們自動完成「排版」這件事,就算你習慣直式書寫,也可以寫好之後按下 format,就自動排版成橫式書寫了!

工具 - Prettier

formatter 裡面最有名的,莫過於 Prettier 了!

Prettier 不僅支援很多語言,適用於常見的框架(如:Vue、React、Angular),也能夠整合進自己喜歡的編輯器(如:VS code、Sublime)。

而 Prettier 能做到的事情,就是上面提到 formatter 做的事情,想體驗可以親自去玩玩看 Playground

透過設定檔一次完成

Prettier 會在專案的根部建立一個 .prettierrc 的檔案,裡面就是個很簡單的 json 檔,比如像這樣:

{
  "arrowParens": "always",
  "bracketSameLine": false,
  "bracketSpacing": true,
  "embeddedLanguageFormatting": "auto",
  "htmlWhitespaceSensitivity": "css",
  "insertPragma": false,
  "jsxSingleQuote": false,
  "printWidth": 80,
  "proseWrap": "preserve",
  "quoteProps": "as-needed",
  "requirePragma": false,
  "semi": true,
  "singleQuote": false,
  "trailingComma": "es5",
  "useTabs": false,
  "vueIndentScriptAndStyle": false,
  "tabWidth": 4
}

更多設定參數可以參考 官方Doc

透過這樣一個簡單的設定檔,Prettier 就能夠根據你的設定,幫你的 code 排版。

觸發排版的方式也很多樣化,可以根據自己的編輯器偏好設定:

  • 按右鍵去 format document
  • format on Paste (貼上程式時排版)
  • format on Save (儲存程式時排版)

不曾注意過的小細節們

自從開始看別的人的程式碼,無論是團隊內部的,或者網路上的,都慢慢發現,很多原本習以為常的風格,原來跟別人都不太一樣:

箭頭函式一個參數要不要括號?

可以透過 arrowParens: "<always|avoid>" 來設定

  • always:要括號
const addOne = (a) => a + 1;
  • avoid:一個參數就不要括號
const addOne = a => a + 1;

字串要用雙引號還是單引號?

可以透過 singleQuote: <bool> 來設定

  • true:單引號(')
const fruit = 'apple';
  • false:雙引號(")
const fruit = "apple";

tab 是兩格空格還是四格?

可以透過 tabWidth: <number> 來設定

  • 2:兩格空格
const doOrder = () => {
  console.log('傳送交易資料到主機預計 2 秒...');
  setTimeout(() => {
    console.log('傳送完成,開始配送預計 10 秒...');
    setTimeout(() => {
      console.log('包裹已送達!');
    }, 10000);
  }, 2000);
};
  • 4:四格空格
const doOrder = () => {
    console.log('傳送交易資料到主機預計 2 秒...');
    setTimeout(() => {
        console.log('傳送完成,開始配送預計 10 秒...');
        setTimeout(() => {
            console.log('包裹已送達!');
        }, 10000);
    }, 2000);
};

以上只是稍微列舉了幾個我自己遇到的,甚至也經常遇到在 A 專案用這套,在 B 專案又要換一套的狀況。

但在 formatter 面前,一切都像切菜一樣簡單,只要設定檔一次性設定,到哪個專案都可以用自己習慣的寫法!

Linter

比起 Prettier 這樣,比較偏向美觀、排版的工具,Linter 則更像一個「隨身教練」,會到處跟著你,糾正關於語法、效能等很實際的問題!

舉例來說:

let fruit = 'apple';
const price;

console.log(frult);

這段 code 看起來好像很和平,但其實問題不少,你有發現嗎?

  • fruit 沒有修改過,其實應該用 const 宣告
  • priceconst 宣告卻沒有初始值
  • frult 是個 typo,沒宣告的變數卻直接取值

當程式的規模大起來,這些小細節很容易就會忘記,等到程式跑起來才發現怎麼東錯西錯,會報錯、會 crash 的都還好發現,最恐怖的就是那些不報錯的,可能在背景默默消耗你的效能!

工具 - ESLint

用來檢查程式碼的工具,如果是用在 Javascript 的話,最推的就是 ESLint 了!

一樣也有個 Playground 可以體驗!

同時,我們可以用設定檔(.eslintrc)來指定,有哪些 rule 要被包含進去:

未使用的變數

這應該算是數一數二常遇到的了,可以透過 no-unused-vars 設定:

let price = 500; 
let price2 = 1500;
console.log(price2);

// 'price' is assigned a value but never used.

誤改到 function 參數

這個我們在 Day 6 談 參數優化時提過,其實也是 side effects 的一種,程式運行上不會出錯,但很容易造成意想不到的結果,可以透過 no-param-reassign 抓出來:

const addSalary = (obj) => {
    obj.salary += 2000;
};

const person = {
    name: 'Joey',
    salary: 30000
};

addSalary(person);

// Assignment to property of function parameter 'props'.

改成有效的 function

這個更厲害了,大部分的 bug 是因為疏忽,但這個 bug 則是單純因為我們不知道 NaN 如何被判斷,所以寫下這個錯誤的相等比對。

雖然我們在 Day 18 已經學會了,但即便你不知道,仍然可以透過 use-isnan 這個 rule 告訴你:

const price = parseInt('apple', 10);
if (price === NaN) {
    console.log('價格有問題');
}

// Use the isNaN function to compare with NaN.

其他還有一卡車的 rule,很多都是真的踩到了才發現「啊!原來這樣不行啊?」,可以自行到官網 Doc 看看。

但其實沒有一定要全部 rule 都遵守,這部分依然是團隊風格的一部份,每個團隊可以自己打造 config!

甚至,我們還可以直接套用其他大型公司的 lint rule,不用自己一條條規則寫,直接讓程式教練跟大公司一樣耶!最有名的就是 Airbnb

Formatter 與 Linter

一個在乎美觀、排版、風格,另一個則在乎語法、效能、正確性

雖然筆者也確實遇過,Prettier 跟 ESLint 都裝上去,套用設定檔之後,Prettier 說要做 A,ESLint 說不要做 A 的窘境。

不過大多時候,兩者其實是相輔相成的,因為如果團隊中的成員都能夠套用相同的程式碼風格,可以讓 code review 容易不少。

reviewer 不用去注意是不是有沒用到的變數,或者函式內的參數被修改了,而是可以把心思放在修改的內容上,是否符合 ticket 範圍,修改是否合理,能夠大幅提升 review 速度,看起來也不會那麼傷眼,formatter 跟 linter 完全是幕後功臣(當然團隊成員也要配合啦!)。

結語

不瞞各位說,我在學會這些方便的工具之前,不僅要手動在那邊一行一行按 tab 排版,還甚至「矯正」了自己原本用雙引號的習慣,慢慢變成習慣單引號,現在看到這些工具真的是相見恨晚啊!

順帶一提,筆者是四格 tab 派(看我的範例不順眼的人應該有發現XD)

無論晴雨
總是以最美麗的姿態
徜徉大海與天空

參考資料

prettier-vs-eslint


上一篇
Day 21 - Code Review
下一篇
Day 23 - 開發人員工具的日常
系列文
Javascript 從寫對到寫好30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
TD
iT邦新手 4 級 ‧ 2021-10-12 09:51:16

結果 eslint 用久了,自己就會養成寫出遵循 eslint rules 的習慣了 XD

ycchiuuuu iT邦新手 4 級 ‧ 2021-10-12 12:11:43 檢舉

真的!我看到紅線就很討厭,所以經常不等 eslint,自己就手動調整,久了就連紅線都沒了,覺得舒坦XD

我要留言

立即登入留言