CodeZine(コードジン)

特集ページ一覧

新規開発を止めずにブラックボックス化したJavaScriptコードを改善するには? 自信を持ってリファクタリングできる環境の実現に向けて【デブサミ2018】

【15-D-2】属人化したフロントエンドのJavaScriptを、‘新規機能開発を止めずに’改善するために行った取り組みについて。及びその経過報告。

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2018/04/12 14:00

 開発担当者の間で大きな問題となりつつあるJavaScriptコードの属人化。ブラックボックス化したフロントエンドに対し、パーソルキャリア株式会社Innovation Lab. MyReferグループの鈴木潤氏は、ReactやESLintなどを使用しながら、「新規機能開発を止めずに」開発環境の刷新を行った。その過程での奮闘ぶりと成功した点、失敗した点などを紹介した。

パーソルキャリア株式会社 Innovation Lab. MyReferグループ エンジニア 鈴木潤氏
パーソルキャリア株式会社 Innovation Lab. MyReferグループ エンジニア 鈴木潤氏

ブラックボックス化したJavaScriptコードを可視化

 特定の人しか修正できないJavaScriptコードは、まさにブラックボックスであり、技術的負債といえる。長い目で見れば、機能追加や品質改善に大きな支障となることは明らかで、誰もが解決したいと考えるはずだ。しかし、多くの企業ではサービスの改善や機能追加が優先され、技術的負債の回収・改善は後回しにされがちだ。むしろ負債を返す作業こそ、新規開発の足かせと考えられていることすらある。

 本セッションに登壇した鈴木潤氏も、そうした課題を感じていた。鈴木氏は、転職サイト「DODA」や求人情報サービス「an」を手がけるパーソルキャリア株式会社(旧社名:株式会社インテリジェンス)で、リファラル採用活性化サービス「MyRefer」といった新規サービスの開発を担当。迅速な新規機能の追加を業務成果としてきた。

鈴木氏が開発に携わったリファラル採用活性化サービス「MyRefer」
鈴木氏が開発に携わったリファラル採用活性化サービス「MyRefer」

 「技術的負債の問題は明らかながら、MyReferはサービスとしてまだまだ成長段階にあり、顧客企業の業務を円滑に進めるためにも、急ピッチで新規機能を開発することが必須。『新規機能開発を止めずに』並行して技術的負債を返す取り組みを考える必要があった。そこで『課題の明確化』『どう解決するか』『改善の方針』の3ステップでアプローチした」と鈴木氏は語る。

 鈴木氏以外の開発メンバーも「なんとなく開発しづらい」と漠然と感じながら、その原因がわからないストレスを抱えていた。そこで、メンバー全員が集まり「どのような問題が生じているか」を付箋で書き出すワークショップを開催。さまざまな声が上がる中で、JavaScriptに関するものをまとめていった結果、大きく以下2つの問題に集約されていったという。

  1. 複数のファイルをまたがっていることによる複雑さ
  2. DOMとイベントリスナが離れすぎている

二大課題をwebpackとReactの活用によって解決

【問題1】複数のファイルをまたがっていることによる複雑さ

 この問題について、鈴木氏は関数処理時の手間を挙げる。例えば、ひとつの処理が複数のファイルにまたがって書かれており、そのどこかで定義されている「Hoge.fuga関数」を修正しなくてはならない場合、大量のタグの中から定義部分を探し出さなければならない。

どのファイルで関数が定義されているかわからない
どのファイルで関数が定義されているかわからない

 この問題を解決するには、複雑な検索を行わなくとも、大量のScriptタグの中で「どこで定義しているのか」がわかる必要がある。具体的にはECMAScript 2015のimport構文で書くと、1~2ファイルに絞り込める。これを可能にするため「webpack」を導入し、依存関係を解決できるようにした。webpackとは、JavaScriptファイルの冒頭に記載されているimportをたどり、複数行のコードをひとつのファイルにして出力できるツールだ。

importをたどって複数行のコードをひとつのファイルにして出力
importをたどって複数行のコードをひとつのファイルにして出力

 webpackが必要だった理由に、サポートブラウザの問題があった。MyReferではサポートブラウザとしてECMAScript 2015のimport構文に対応していないIE11を含めており、import構文を使用したコードをIE11上で実行しても動作しない。そのため、webpackを使用してimport構文を使用しているJavaScriptの依存関係を解決し、出力されたファイルをHTMLから読み込む方法をとった。

【問題2】DOMとイベントリスナが離れすぎている

 そしてもうひとつ、「DOMとイベントリスナが離れすぎている」問題。例えば、よくあるHTMLとjQueryのソースコードでも、セレクタ「js-hoge-button」が変数に格納されていることや、動的に出力されていることがある。これではコードとしてわかりにくい。

「DOMとイベントリスナが離れすぎている」問題
「DOMとイベントリスナが離れすぎている」問題

 そもそもHTMLとjQueryのクリック時の処理が、ひとつのファイルにまとめて書かれていればこの問題は解決できる。そこで、MyReferではReactを導入。ボタン要素とクリック時の関数をひとつのファイルに記載することによって解決を試みた。

ボタンタグとクリック時の関数がひとつのファイルに書かれている
ボタン要素とクリック時の関数がひとつのファイルに書かれている

 さらにChromeのReact Developer Toolsであれば、ツリー状にコンポーネント名を確認できる。クラス名がわかるため「ボタンを押した際の挙動がわからない」問題が解決できたという。

 そうなると「jQueryは完全にもう使わないのか」という疑問が生じるが、鈴木氏は「jQueryで書かれているソースコードは容易に捨てられない。MyReferではReactライフサイクルメソッドの中に閉じ込める形で利用している」と説明した。

ESLintの導入

 さらに鈴木氏は、JavaScript用静的検証ツール「ESLint」についても言及。当時のMyReferのコードではグローバルに存在する名前空間があり、それを当事者以外誰も知らないといった状況が発生していた。それだけでなく「var」「let」「const」などをつけ忘れたことで、意図せずグローバル変数化してしまうこともあった。

 この問題を解決するために導入したのがESLintだ。特別な理由がない限りグローバルな領域に変数を増やさないようにし、evalも禁止。また、実行時エラーを引き起こしかねないセミコロン忘れなども含めてチェックしている。

最終的な目標を定め、改善方針を策定

 では、これらの改善を新規機能の開発を止めずに行うにはどうすればいいか。MyReferの開発チームはルールを策定し、その徹底を図っているという。

MyReferの開発チームでの方針
MyReferの開発チームでの方針

 まず、新規で追加する機能はReactで開発。既存機能の改修に関してはReactを使用するかどうかをその都度検討している。そのほか、ESLintでエラーになったコードはpushしないといった基本的なルールも定めた。「実感としてブラックボックス化されたソースコードを読み解いて、影響範囲を気にしながら修正するよりも手間がかからなかった」と鈴木氏は印象を述べる。

 また、MyReferのフロントエンド全体をいきなりSPAにするのではなく、まずは画面ごとのReact化を完了させる。そして最終的に目指すのは「バックエンドはAPIのみを提供する」「APIはスマホアプリと同じものを使用するようにする」「Webのフロントエンドを最終的にはSPAにする」の3点。現在は最初のステップである「フロントエンドの改善/検証」に取り組んでいるというわけだ。

ステップを踏んで、最終的には全てSPAにする
ステップを踏んで、最終的には全てSPAにする

 なお、フロントエンドだけではなくバックエンドもGoで作り直し、順次APIを作成することを目指している。「フロントエンド、バックエンド共にステップ1の足並みがそろい次第ステップ2に移行し、Webとモバイルの両方でSPA化を完了させたい」と鈴木氏は意欲を見せる。

 こうした取り組みを進める中で、鈴木氏は「新規機能の開発についてはうまくいっている。また、既存機能の改修も『部分的に』うまくいっている」と評価。既存機能に関しては、仕様が単純な画面の改修はスムーズだったものの、複雑な画面のReact化は困難を極めているという。「複雑な既存コードを改善するところまでなかなか着手できていないというのが正直なところ。その理由は純粋にデグレードが怖いことにある」と語る。

経験と反省点をもとに、自信を持ってリファクタリングできる環境へ

 さらに鈴木氏は「実際、改善に取り組んでみると勉強不足だと感じた。最近になって知ったこともある」と振り返り、TypeScript2.3以降で使用できるJavaScriptファイルの型チェック機能の存在を紹介した。それまでMyReferのフロントエンドではBabelを使用していたが、TypeScriptのバージョン2.3からJavaScriptファイルのJSDocのアノテーションをもとに型チェックができるようになった。こうしたJavaScript用ユニットテストを使えば、コメント文の修正だけで既存のコードにも無理なくリファクタリングできる。「最初から入れておけば、と反省している」と鈴木氏は語った。

 さらに鈴木氏は「やってみてわかった失敗」として、未定義の変数利用についての手順ミスを挙げた。既存のコードの中でvarをつけ忘れて変数指定をしているものがあり、それまでは変数がグローバルに展開されるだけで、「一応」動いていた。しかしwebpackのインポートを使用すると、自動的にStrictモードになり、宣言されていない変数を使うと実行時エラーが発生してしまう。これが生じたのは、たまたまReact、webpack導入後にESLintを導入したため。鈴木氏は「webpack導入よりも先に、ESLintで未定義の変数の利用をチェックしておけば防げた」と振り返った。

 そして、取り組みにおけるMyReferチームでの連携強化のため、勉強会や共有会を数回にわたり実施。また、Visual Studio Codeなど各エディタの設定に関しては、ツールを導入する人がリーダーとなり情報共有を行った。いずれも誰かが率先して行う必要があるため、苦労があったという。

 最後に鈴木氏は「Reactとモジュール機能を使用することで、新規機能を中心に改善できた。ただし仕様が複雑なところに関しては、デグレードが怖くて着手できない部分が残っていた。それでもテストの仕組みやTypeScriptの型チェックを導入することで差分が生じていないことを確認できれば、自信を持ってリファクタリングできる環境を実現できるのではないか」とまとめた。そして「最終的には、MyReferのSPA化、アプリとWebに共有のAPI、バックエンドのAPIサーバーへの作りかえまで、時間がかかるかもしれないが、レガシーなフロントエンドの開発環境改善を実現させていきたい」と今後の改善に意欲を見せ、セッションを締めくくった。

お問い合わせ

 パーソルキャリア株式会社

  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • CodeZine編集部(コードジンヘンシュウブ)

    CodeZineは、株式会社翔泳社が運営するソフトウェア開発者向けのWebメディアです。「デベロッパーの成長と課題解決に貢献するメディア」をコンセプトに、現場で役立つ最新情報を日々お届けします。

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5