大阪開発拠点でマネーフォワード クラウド会計Plus(以下、会計Plus)プロダクトのフロントエンドエンジニアをやってます、しばもとです。好きな食べ物は、ポンデリングです。
私が所属する会計PlusのWebフロントエンドで改善活動を行いました。その改善活動としてビルド時間の短縮、バンドルサイズの削減、Jestの実行時間短縮など同じフロントエンドエンジニアの方の役に立つと思ったので紹介させていただきます。
簡単な会計Plusの技術的な紹介
会計Plusのフロントエンドでは、次のツールを使用しています。
- バンドルツールに、webpack
- テストフレームワークに、Jest
これらのツールは、CI/CDのサービス CircleCI上で動かしています。また、フロントエンドライブラリとしてReact、型にTypeScriptを使用しています。
※ 説明の都合上、必要最小限の紹介をしています。
改善内容
実際に行った改善内容は、次の3つです。
- webpack
1.ビルド時間 高速化
2.バンドルサイズ 削減
- Jest
- 3.(CircleCI上で) 実行時間 高速化
それぞれ、簡単に紹介します。
webpack ビルド時間 高速化
会計PlusのProduction向けwebpackビルド時間が、1分34秒かかっていました。ビルド時間が長いと、デプロイ実行時間が伸びてしまい、結果、リリース時間も伸びてしまうという課題があります。
CI/CDのプロセスを高速に回したいため、ビルド時間を1分以内に短縮したいと思いました。ビルド時間の目標値については、明確なゴールを持っていなかったため、きり良く1分としました。
やったこと
- 各種ローダーのアップデート
- ts-loader, css-loader, url-loader, etc
- ts-loaderのtranspileOnly設定 (Production時のみ)
- 各種ローダーのアップデート
結果
- 1分34秒 → 19秒 (約80%減)
計測
改善前(Before)と改善後(After)のSpeed Measure Pluginログを載せます。
// Before SMP ⏱ General output time took 1 min, 34.36 secs SMP ⏱ Loaders ts-loader took 1 min, 1.15 secs module count = 383 mini-css-extract-plugin, and css-loader, and postcss-loader, and sass-loader took 44.45 secs module count = 99 css-loader, and postcss-loader, and sass-loader took 43.95 secs module count = 99 modules with no loaders took 41.93 secs module count = 1433 url-loader took 0.16 secs module count = 17 // After SMP ⏱ General output time took 19.64 secs SMP ⏱ Loaders ts-loader took 6.66 secs module count = 383 mini-css-extract-plugin, and css-loader, and postcss-loader, and sass-loader took 8.42 secs module count = 99 css-loader, and postcss-loader, and sass-loader took 7.99 secs module count = 99 modules with no loaders took 6.1 secs module count = 1433 url-loader took 0.024 secs module count = 17
General output time took
が 1 min, 34.36 secs
から 19.64 secs
に短縮されていることが分かります。
webpack バンドルサイズ 削減
会計PlusのWebpackのバンドルは、サードパーティ製のvendorと、アプリケーションコードのbundleの2つで分割しています。vendorのバンドルサイズが1.9MiBと巨大になっており、推奨サイズ (250 KiB) を大きく上回っていました。
CompressionWebpackPlugin を使い、gzで 505 KiB まで圧縮していますが、それでもなんとかバンドルサイズを減らせないかと思いました。
- やったこと
- tsconfig の compilerOptions.module を commonjs から esnext に変更
- require構文からimport/export構文へ切り替えたことによる、TreeShaking効果で、デットコード削除
- tsconfig の compilerOptions.module を commonjs から esnext に変更
- 結果
- vendorファイルのバンドルサイズ 削減
- 1.9 MiB → 649 KiB (約66%減)
- bundleファイルのバンドルサイズ 削減
- 600 KiB → 490 KiB (約19%減)
- vendorファイルのバンドルサイズ 削減
- 計測
- Webpackの標準出力
改善前(Before)と改善後(After)の webpack build標準出力ログを載せます。
// before Assets: bundle-c3cf39f29f182f0cf63b.js (600 KiB) vendor-6b7bb5650011d7d589c2.js (1.9 MiB) vendor-6b7bb5650011d7d589c2.js.gz (586 KiB) // after Assets: bundle-d21e45c581d2913ef503.js (490 KiB) vendor-211cffabccdad2e2c634.js (649 KiB)
特に、vendorのファイルサイズが大きく減少(1.9 MiB → 649 KiB
)していることが、分かります。
CircleCI Jest 実行時間 高速化
ローカルマシン(MacBook Pro)でJestのテストを動かすと2分未満で完了するのに、CircleCI上では5分以上かかってしまっています。これは、ローカルマシンとCircleCIのマシンリソースの違いが原因と推測しています。 私が使用しているMacBook Proのマシンリソースは 8 CPU, 64 GB に対して、CircleCIは2 CPU, 4GB のマシンリソースです。
テストの早期フィードバックによって、フロントエンド開発をスピーディに行いたいため、CircleCI上のJestの実行時間を短縮したいと思いました。
- やったこと
- 結果
- 5分22秒 → 1分43秒 (約69%減)
- 計測
- CircleCI上のUI
CircleCIのテスト関連のワークフロー
Before
フロントエンドテスト(client_run_tests) が、改善前(Before)から改善後(After)で、5m22sから1m43sに削減できていることが、分かります。
改善を通して感じたこと
これらの改善は、特に目新しいことをしていないと思っています。遅いなと思う所で 計測→公式資料を読む→試す
を繰り返しただけです。特別なツールを使ったわけでも、チューニングにコードをゴリゴリ書いた訳ではありません。シンプルに、公式資料の言うことを、そのまま試しただけです。
にもかかわらず、小さなコストで大きな改善ができました。これらの改善時間は、5営業日ぐらいです。
そこから学んだことは、特殊なことをせずに 公式資料をちゃんと読むという、当たり前なこと が、とても大切だと思いました。
以降では、当たり前な気づきを紹介します。
大前提として計測しよう
いきなり改善活動すると、どこまでやればゴールなのか迷ってしまいますし、オーバーエンジニアリングに陥ってしまうかもしれません。まずは、定量的に計測できるものを見つけて、計測してみましょう。
また可能であれば、可視化もしてみましょう。数値で表すよりも、全体の傾向などをつかめたりすると、何か新しい発見があるため、可能なら可視化もしてみましょう。
今回、使ったのは次のものですが、こだわりはありません。npm trendsで人気なものを選んだだけです。
- webpackのビルド時間を計測したい
- webpackのバンドル後ファイルに占める割合を見たい
- package.jsonで、モジュールサイズを知りたい
- package.jsonで、モジュールバージョンが古い・使われていないか知りたい
当たり前改善1: 使われていないものは、捨てましょう
使われていないアプリケーションコードや、開発プロセス等で使われないスクリプトやモジュールたちは、一掃しましょう。
使われていないから、アプリを利用するユーザーにとって困らないと思うかもしれませんが、開発するエンジニアにとっては困ります。
使われていないものは、存在するだけで様々なコストがかかってしまいます。例えば、次の困りごとがあると思います。
- コードリーディングするときに不要に読んでしまう
- 不要な範囲まで影響調査してしまう
- 使わないモジュールをアップデート対応してしまう
使われていないものは、ちゃんと捨てましょう。
当たり前改善2: ツールは最新にしよう
webpackやJestで実行時間を高速化したいと思ったとき、話題の爆速ツールを使ってみたくなる気持ちがあると思います(わかります)。その気持ちは、ぐっと抑えましょう。webpackやJestだって、素晴らしいツールです。
今回使っているフロントエンドツールはOSSであるため(ありがたい)、ツールを最新化することで、コントリビュータの方々からの改善を享受できます。その中には、パフォーマンス改善も含まれているやもしれません。
webpackやJestなどのバージョンを、大胆に最新版にあげて試してみましょう。
当たり前改善3: 公式資料を読みましょう
改善するときに、どうやったら改善できるか手段を調べると思います。その際、個人で書かれているTipsを発見することがあります。それはそれでとても貴重ですが、最初に見るべきではありません。まずは、webpackやJestなどの公式資料を読んでみましょう。往々にして、そこにヒントがあるはずです。
実際に参考になったものを、共有します。
- webpackでビルド時間を高速化したい
- https://webpack.js.org/guides/build-performance/
transpileOnly: true
というのが、ここに書いています
- https://webpack.js.org/guides/build-performance/
- webpackのバンドルサイズを減らしたい
- https://webpack.js.org/guides/tree-shaking/
- webpackにTreeShakingの情報があり、tsconfigのmoduleを見直しました
- CircleCI上で、Jestの実行時間を短縮したい
公式資料通り、標準に従ってシステムやアプリケーションを設計しておくと、先人の知恵を大いに享受できるため、できる限りはカスタマイズせずに、標準に合わせることは、あらゆる面でメリットがあります。
終わりに
改善活動は、一足飛びでやることではありません。一つ一つ順を追って改善していくことが大切です。ご参考になれば幸いです。
会計Plusでは、フロントエンドエンジニアを大募集しています! また、カジュアル面談もやっていますので、お気軽にどうぞ!
- 【フロントエンドエンジニア】マネーフォワードクラウド(会計Plus)_大阪 | 株式会社マネーフォワード
- 【フロントエンジニア】マネーフォワードクラウド(会計Plus)_京都 | 株式会社マネーフォワード
- 【カジュアル面談エントリー】 | 株式会社マネーフォワード
マネーフォワードでは、エンジニアを募集しています。 ご応募お待ちしています。
【会社情報】 ■Wantedly ■株式会社マネーフォワード ■福岡開発拠点 ■関西開発拠点(大阪/京都)
【SNS】 ■マネーフォワード公式note ■Twitter - 【公式】マネーフォワード ■Twitter - Money Forward Developers ■connpass - マネーフォワード ■YouTube - Money Forward Developers