「フロントエンドの技術的負債 みんなで学ぶ Lunch LT 」の登壇資料です https://findy.connpass.com/event/281811/
© Chatwork巨大なSPAの技術的負債と向き合い続けるテクニック2023年05月17日フロントエンド開発部マネージャー 澁谷 哲也Chatwork株式会社
View Slide
自己紹介2Chatwork株式会社澁谷 哲也 Tetsuya Shibutaniフロントエンド開発部 マネージャービジネスチャットツールを作っています@shibe_23
ChatworkのWebFrontendについて
ChatworkのWebFrontendの特徴● 巨大なSPA、かつ利用中ほとんどリロードされずに使われるアプリケーション● 双方向性があり、ユーザーからのアクション以外で状態が変わる● JavaScriptだけで16万行● CSSも1万7千行○ Styled-Componentを利用しているため、実際にはもっと多い巨大なコードベース● ブラウザベースのアプリケーションとしては珍しく、URL単位でアプリケーションとして分割されていない● 再読み込みのない一枚のページで全UIが動作している純粋なSinglePageApplication● Webサイトベースの「入力 ->確認 -> 完了」と情報が一方向なWebアプリではない● Google SpreadSheetのようなGUIアプリとしての複雑さを持つGUIアプリとしての複雑性4
技術的負債の状況● jQuery -> React + DDD -> React + Reduxの3世代に渡るアーキテクチャ● jQuery製のUIとReact製のUIが混在している○ 全体のうち約2万4000行がjQuery製● 認知的複雑度(Cognitive Complexity)の合計は、およそ9,000○ jQuery世代はおよそ5,000● 各世代ごとの詳細は下記を参照ください組織フェーズを見据えたWEBフロントエンドのアーキテクチャと変遷(JS Conf 2021)
技術的負債についての考え方● 技術的負債は「アプリケーションのあるべき姿と現状との差分」○ 現状からあるべき姿に到達するまでに掛かる時間(= リソース)と向き合っている● あるべき姿は時代の変化によっても変わる○ jQuery全盛期にReactの登場は予測できなかった○ 現在のベストプラクティスも、新しい技術の登場によってあるべき姿から遠ざかる● 負債は無くすものではなく、様々な要因を加味してコントロールするもの技術的負債と継続的に向き合う仕組みづくりが重要
技術的負債と継続的に向き合う方法71. 段階的に返却するためのテクニック2. 安全にリリースするための仕組み今回は具体例をいくつかご紹介します
段階的に返済するテクニック
jQueryの世界とReactの世界を分離する● jQuery製のコードとReact製のコードの間に腐敗防止層を設ける● interfaceをReact側から提供することで依存関係を制御する● Reactの世界にjQueryが侵入することを防ぎ、古いコードを捨てやすくしているjQuery時代のアーキテクチャをReact化するために大切なACL層のお話
jQuery製のUIとReact製のUIを混在させる● 段階的にリファクタリングするためにUIごとにReact化したい● ReactDOM.renderを使った時の課題○ Context APIを全てのレンダリングツリーに流し込む必要性○ デバッグ時にレンダリングツリーごとにしかプロファイルが取れない● ReactDOM.createPortal で同一の親コンポーネントを指定してマウントするようにした● 部分的な置き換えにおける注意点○ イベントハンドラの多重登録○ 再描画の度にjQueryで作成したDOMが残り続けることによるメモリリーク… React… jQuery
TypeScriptのStrict modeを有効にする● jQuery時代のコードはany型を一部許容している○ 一方で、普段のコードを書く時に暗黙的なany型の混入を防ぎたい● strictを有効にするために、TypeScript Compiler APIを使って型エラーが起きている箇所に@ts-expect-error を自動で追加した○ 新規で@ts-expect-errorを書かないようにpre commit時にチェックしている● 型エラーが隠蔽されるケースがあるので、トレードオフには注意
安全にリリースするための仕組み
技術的負債と継続的に向き合う = 小さく試して改善し続ける● コードを適切に処理できれば確実に不具合を回避することはできるか?○ できない○ 負債の影響は積み重なって予期しない不具合として現れる● リリースしなければ本当に問題がないかは確認できない○ 失敗の影響を最小限に抑えなければ、リファクタリングは重たいプロセスになってしまう● “どうコードをきれいにするか”も大事だが、 “小さく失敗できる体制をつくる“ことが最も重要
リリースフローの全体像● GitHub Flowを採用● mainブランチにマージされるとすぐに社内検証ユーザーにデプロイされる● 本番リリースされるのは、その時点のmainブランチの最新コミット● 先行して自分たちが触ることで、ユーザーにとって致命的な不具合がリリースされることを回避社内検証ユーザーにリリースmainfeature-x社内検証されたものが本番リリース
コミットハッシュごとのスナップショットを生成する● PR作成時 / 更新時 / mainブランチへのマージ時にビルドしたjsファイルをS3にアップロードする● コミットハッシュをURLにパラメータとして付与することで、指定したバージョンでアプリを開いて検証できる仕組みがある○ バージョンごとの現象確認が容易● リリースブランチへマージされた履歴がjsファイルとして既に生成されている、というのがポイントcommit hash:c63df1b164b73d71…maincommit hash:f632892477af9be29…commit hash:ebbd2436080a165c…commit hash:8238f9b315116c5c0…
自前のリリースシステムで高速なリリース / 切り戻しを実現する● リリースは生成済のjsファイルを本番環境にコピーするだけ● mainブランチの過去の状態も保存されているため、切り戻しも容易● 緊急時の切り戻しは実行 -> リリース完了で約3秒※ 切り戻しの判断も必要なので、障害対応自体はもう少しかかります
Feature Toggleで安全にリリース内容を制御する● Feature Toggleで社内検証ユーザーにのみリリースすることができる● 大きめのリファクタリングなど、本番環境へのリリースを阻害することなく検証期間を設けることができる● 非公開の制御もFeature Toggleをオフにするだけ● Feature Toggleによって分岐が増えて複雑化する場合もあるため要注意
まとめ
技術的負債と現実的に向き合うために● 技術的負債を解消するより、どのように距離を保つか○ 段階的に負債を返却するためのテクニック○ 安全にリリースするための仕組み● 未来は誰にも予測できない。だからこそ小さく試して改善し続ける○ “小さく失敗できる”体制が重要
今回の話に興味を持っていただいた方へ● エンジニアHub様掲載の記事もご覧くださいReact+Reduxによる状態管理とフロントエンドの技術的負債 ─ 長く継続するサービスのアプリケーション設計
最後に● Chatworkではフロントエンドエンジニアを募集しています● 巨大なSPAと一緒に向きあい改善し続けてくださる方、ぜひご応募ください!採用ページはこちら
働くをもっと楽しく、創造的に