使用重構件(Codemod)加速JavaScript開發和重構

玄學醬發表於2017-10-19
本文講的是使用重構件(Codemod)加速 JavaScript 開發和重構,

使用重構件(Codemod)加速 JavaScript 開發

在花園裡耕耘樂趣無窮,但如果除草不勤,最後收穫可能是一團揪心。漏掉一次除草本身可能並無大礙,但積少成多最後會毀掉整座花園。沒有雜草的花園讓維護工作神清氣爽。這個道理對程式碼庫也類似。

我通常討厭除草,經常忘記這事的結果就是一團糟。謝天謝地在程式設計界有像 ESLint 和 SCSS-Lint 這樣的好東西提醒我們勤理程式碼。但是如果面對的是大段大段的歷史程式碼,光是想想要手動調整成百十千萬的空格和逗號,悲傷便逆流成河。

8年來有幾百萬行 JavaScript 程式碼進入 Airbnb 的版本控制系統中。同時,前端界風起雲湧。新功能,新框架,甚至 JavaScript 本身都在快速進化。儘管遵循良好的程式碼風格會讓變革少些疼痛,但還是很容易累積出不再遵循最新”最佳實踐”的巨大程式碼庫。每一處程式碼風格的不一致都是一棵雜草,唯一歸宿就是被剷掉,化作春泥更護花,好讓開發團隊保持高效。來看看我們花園現在的樣子:

我執著於增加團隊效率,也深知保持一致性的程式碼能增速團隊反饋和減少無效溝通。我們最近開始了一個整理程式碼的專案,準備把許多陳舊的 JavaScript 程式碼轉化得符合我們的程式碼風格,亦使我們的程式碼檢驗器有更多用武之地。若全都手動完成,會是件十分無聊和耗時的苦差,所以我們藉助工具幫我們自動化此工作。雖說使用 eslint -fix 是個不錯的開始,但它現在所能有限。儘管他們最近開始接受修復所有規則的PR,也準備構建 JavaScript 的具體語法樹,但等這些功能完成還需要些時間。感謝上蒼我們發現了 Facebook 的 jscodeshift,這是一個重構工具(協助大型程式碼庫的自動化重構)。如果程式碼庫是個花園,那麼 jscodeshift 就像個除草機器人。

此工具將 JavaScript 解析為一棵 抽象語法樹,並在其上進行變換,然後輸出符合指定程式碼風格的新 JavaScript 程式碼。轉換過程是用 JavaScript 本身實現的,所以我們團隊很樂意使用此工具。尋找或是建立轉換程式碼能加速我們乏味的重構,讓我們團隊能夠專注於更有意義的工作。

執行幾個程式碼重構件後,我們的花園整潔了點:

策略

鑑於多數重構件能在一分鐘內處理上千檔案,我發現它是我打發主要工作的等待間隙(例如等程式碼審查)的不錯選擇。它幫我最大化提升了工作效率從而讓我能在更大和更重要的專案中有所建樹。

大規模重構主要面臨四大挑戰。溝通、正確性、程式碼審查以及衝突合併。我採取以下策略來應對這些挑戰。

重構件不總是能產出我需要的結果,因此對其結果的審查和改動十分重要。以下命令在跑完重構件後很有用:

git diff
git add --patch
git checkout --patch

保持每個提交和 PR 在小的體量是好的做法,對於重構件也不例外。我通常一段時間內進行一類重構,減少程式碼審查和衝突合併的麻煩。我亦經常讓重構件自動提交重構結果,而後若有必要,再手動清理。這樣在衍合分支時解決衝突會輕鬆點,因為我可以使用

git checkout --ours path/to/conflict

然後在那個檔案上再執行一次重構件,之後也不會弄亂我自己的手動提交。

有時重構件生成了很大的變動,我覺得在此情況下根據目錄或檔名來分成數次提交或 PR 會比較好。例如,一個提交重構 .js 檔案,另一個提交重構.jsx 檔案。這樣之後程式碼審查和衝突合併會相對輕鬆一點。謹遵 Unix 哲學,分批進行檔案重構簡單到僅需調整 find 命令的引數:

find app/assets/javascripts -name *.jsx -not -path */vendor/* | 
  xargs jscodeshift -t ~/path/to/transform.js

為避免和別人的程式碼衝突,我通常在週五早上才推送我的重構件生成的提交,然後週一趕在大家開始工作之前進行衍合和合並。這樣其他人週末放假前不被你的重構件阻礙,能好好整理自己的工作成果。

我們用得順手的重構件

雖然此工具還比較新,已然有了一些實用的重構件。以下是一些我們成功上手了的。

輕量級重構件

以下是些用著不那麼痛苦的,立刻上手感受成效。

js-codemod/arrow-function: 謹慎地把函式轉為箭頭函式

使用前:

[1, 2, 3].map(function(x) {
  return x * x;
}.bind(this));

使用後:

[1, 2, 3].map(x => x * x);

js-codemod/no-vars: 將 var`_ 安全轉化為 _const_ 或 _let`

使用前:

var belong = `anywhere`;

使用後:

const belong = `anywhere`;

js-codemod/object-shorthand: 把物件字面量轉為 ES6 的簡寫表示。

使用前:

const things = {
  belong: belong,
  anywhere: function() {},
};

使用後:

const things = {
  belong,
  anywhere() {},
};

js-codemod/unchain-variables: 分離連續宣告的變數。

使用前:

const belong = `anywhere`, welcome = `home`;

使用後:

const belong = `anywhere`;
const welcome = `home`;

js-codemod/unquote-properties: 移除物件屬性的引號。

使用前:

const things = {
  `belong`: `anywhere`,
};

使用後:

const things = {
  belong: `anywhere`,
};

重量級重構件

以下重構件或是改動很多程式碼引發合併和衝突之痛,或是需要更多後續的手動更改以保證程式碼還能看得下去。

react-codemod/class: 把 React.createClass 轉為 ES6 class 的實現。

此重構件在有 mixin 的時候不會變換,在類似於 propTypes、預設 props 和 initial state 定義這樣的必要轉換做得很好,還能將事件回撥函式繫結到構造器上。

使用前:

const BelongAnywhere = React.createClass({
  // ...
});

使用後:

class BelongAnywhere extends React.Component {
  // ...
}

react-codemod/sort-comp: 根據 ESLint react/sort-comp rule 重新組織 React component 的方法宣告順序。

這個會調整大量程式碼,git 不會自動合併衝突。我覺得在使用此重構件前最好最好跟隊友打個招呼,在不太容易發生衝突的時候(例如週末)進行重構。當我衍合此重構的提交且遇上衝突的時候,我會:

git checkout --ours path/to/conflict

然後再執行一次重構件。

使用前:

class BelongAnywhere extends React.Component {
  render() {
    return <div>Belong Anywhere</div>;
  }

  componentWillMount() {
      console.log(`Welcome home`);
    }
  }

使用後:

class BelongAnywhere extends React.Component {
  componentWillMount() {
    console.log(`Welcome home`);
  }

 render() {
    return <div>Belong Anywhere</div>;
  }
}

js-codemod/template-literals: 把字串的串聯轉換為字串模板字面量表示。

因為我們多處用到字串串聯,而且這個重構件盡其所能把所有字串都轉成模板,我發現很多轉換結果其實並不合理。我之所以這個重構件放到”重量級”列表裡,是因為它會改動很多檔案,而且之後我們還得進行大量的手動修改才能得到滿意的結果。

使用前:

const belong = `anywhere `+ welcomeHome;

使用後:

const belong = `anywhere ${welcomeHome}`;

資源

若你想寫自己的重構件,或是看看它能做什麼,可以看下下面的資源。

影響

在使用了一些現成的和我們自己寫的並貢獻給社群的重構件之後,我們的舊程式碼質量獲得很大的提升。我不費吹灰之力便重構了40000行程式碼,將舊程式碼調整至符合 ES6 程式碼風格。花園煥然一新,我們之後的工作也更有效率和樂趣。

使用已有的重構件僅是牛刀小試,只有在你拿起鍵盤寫出自己的重構件時,真正的能量才會釋放。無論是對程式碼風格重構,或是對失效 API 的調整,重構件都能大顯身手,你可以盡情想象發揮。這些技術值得學習投入,能省下你和使用你的專案使用者很多時間精力。






原文釋出時間為:2016年06月12日

本文來自雲棲社群合作伙伴掘金,瞭解相關資訊可以關注掘金網站。


相關文章