Slide 1

Slide 1 text

       © Chatwork 巨大なSPAの技術的負債と 向き合い続けるテクニック 2023年05月17日 フロントエンド開発部マネージャー 澁谷 哲也 Chatwork株式会社

Slide 2

Slide 2 text

自己紹介 2 Chatwork株式会社 澁谷 哲也 Tetsuya Shibutani フロントエンド開発部 マネージャー ビジネスチャットツールを作っています @shibe_23

Slide 3

Slide 3 text

ChatworkのWebFrontendについて

Slide 4

Slide 4 text

ChatworkのWebFrontendの特徴 ● 巨大なSPA、かつ利用中ほとんどリロードされずに使われるアプリケーション ● 双方向性があり、ユーザーからのアクション以外で状態が変わる ● JavaScriptだけで16万行 ● CSSも1万7千行 ○ Styled-Componentを利 用しているため、実際に はもっと多い 巨大なコードベース ● ブラウザベースのアプリケー ションとしては珍しく、URL単 位でアプリケーションとして分 割されていない ● 再読み込みのない一枚のページ で全UIが動作している 純粋なSinglePageApplication ● Webサイトベースの「入力 -> 確認 -> 完了」と情報が一方向 なWebアプリではない ● Google SpreadSheetのような GUIアプリとしての複雑さを持 つ GUIアプリとしての複雑性 4

Slide 5

Slide 5 text

技術的負債の状況 ● jQuery -> React + DDD -> React + Reduxの3世代に渡るアーキテクチャ ● jQuery製のUIとReact製のUIが混在している ○ 全体のうち約2万4000行がjQuery製 ● 認知的複雑度(Cognitive Complexity)の合計は、およそ9,000 ○ jQuery世代はおよそ5,000 ● 各世代ごとの詳細は下記を参照ください 組織フェーズを見据えたWEBフロントエンドのアーキテクチャと変遷(JS Conf 2021)

Slide 6

Slide 6 text

技術的負債についての考え方 ● 技術的負債は「アプリケーションのあるべき姿と現状との差分」 ○ 現状からあるべき姿に到達するまでに掛かる時間(= リソース)と向き合っている ● あるべき姿は時代の変化によっても変わる ○ jQuery全盛期にReactの登場は予測できなかった ○ 現在のベストプラクティスも、新しい技術の登場によってあるべき姿から遠ざかる ● 負債は無くすものではなく、様々な要因を加味してコントロールするもの 技術的負債と継続的に向き合う仕組みづくりが重要

Slide 7

Slide 7 text

技術的負債と継続的に向き合う方法 7 1. 段階的に返却するためのテクニック 2. 安全にリリースするための仕組み 今回は具体例をいくつかご紹介します

Slide 8

Slide 8 text

段階的に返済するテクニック

Slide 9

Slide 9 text

jQueryの世界とReactの世界を分離する ● jQuery製のコードとReact製のコードの間に腐敗防止層を設ける ● interfaceをReact側から提供することで依存関係を制御する ● Reactの世界にjQueryが侵入することを防ぎ、古いコードを捨てやすくしている jQuery時代のアーキテクチャをReact化するために大切なACL層のお話

Slide 10

Slide 10 text

jQuery製のUIとReact製のUIを混在させる ● 段階的にリファクタリングするためにUIごとにReact化したい ● ReactDOM.renderを使った時の課題 ○ Context APIを全てのレンダリングツリーに流し込む必要性 ○ デバッグ時にレンダリングツリーごとにしかプロファイルが取れない ● ReactDOM.createPortal で同一の親コンポーネントを指定してマウントするようにした ● 部分的な置き換えにおける注意点 ○ イベントハンドラの多重登録 ○ 再描画の度にjQueryで作成したDOMが残り続けることによるメモリリーク … React … jQuery

Slide 11

Slide 11 text

TypeScriptのStrict modeを有効にする ● jQuery時代のコードはany型を一部許容している ○ 一方で、普段のコードを書く時に暗黙的なany型の混入を防ぎたい ● strictを有効にするために、TypeScript Compiler APIを使って型エラーが起きている箇所に @ts-expect-error を自動で追加した ○ 新規で@ts-expect-errorを書かないようにpre commit時にチェックしている ● 型エラーが隠蔽されるケースがあるので、トレードオフには注意

Slide 12

Slide 12 text

安全にリリースするための仕組み

Slide 13

Slide 13 text

技術的負債と継続的に向き合う = 小さく試して改善し続ける ● コードを適切に処理できれば確実に不具合を回避することはできるか? ○ できない ○ 負債の影響は積み重なって予期しない不具合として現れる ● リリースしなければ本当に問題がないかは確認できない ○ 失敗の影響を最小限に抑えなければ、リファクタリングは重たいプロセスになってしまう ● “どうコードをきれいにするか”も大事だが、 “小さく失敗できる体制をつくる“ことが最も重要

Slide 14

Slide 14 text

リリースフローの全体像 ● GitHub Flowを採用 ● mainブランチにマージされるとすぐに社内検証ユーザーにデプロイされる ● 本番リリースされるのは、その時点のmainブランチの最新コミット ● 先行して自分たちが触ることで、ユーザーにとって致命的な不具合がリリースされることを回避 社内検証ユーザーにリリー ス main feature-x 社内検証されたものが 本番リリース

Slide 15

Slide 15 text

コミットハッシュごとのスナップショットを生成する ● PR作成時 / 更新時 / mainブランチへのマージ時にビルドしたjsファイルをS3にアップロードする ● コミットハッシュをURLにパラメータとして付与することで、指定したバージョンでアプリを開いて 検証できる仕組みがある ○ バージョンごとの現象確認が容易 ● リリースブランチへマージされた履歴がjsファイルとして既に生成されている、というのがポイント commit hash: c63df1b164b73d71… main commit hash: f632892477af9be29… commit hash: ebbd2436080a165c… commit hash: 8238f9b315116c5c0…

Slide 16

Slide 16 text

自前のリリースシステムで高速なリリース / 切り戻しを実現する ● リリースは生成済のjsファイルを本番環境にコピーするだけ ● mainブランチの過去の状態も保存されているため、切り戻しも容易 ● 緊急時の切り戻しは実行 -> リリース完了で約3秒 ※ 切り戻しの判断も必要なので、障害対応自体はもう少しかかります

Slide 17

Slide 17 text

Feature Toggleで安全にリリース内容を制御する ● Feature Toggleで社内検証ユーザーにのみリリースすることができる ● 大きめのリファクタリングなど、本番環境へのリリースを阻害することなく検証期間を設けることが できる ● 非公開の制御もFeature Toggleをオフにするだけ ● Feature Toggleによって分岐が増えて複雑化する場合もあるため要注意

Slide 18

Slide 18 text

まとめ

Slide 19

Slide 19 text

技術的負債と現実的に向き合うために ● 技術的負債を解消するより、どのように距離を保つか ○ 段階的に負債を返却するためのテクニック ○ 安全にリリースするための仕組み ● 未来は誰にも予測できない。だからこそ小さく試して改善し続ける ○ “小さく失敗できる”体制が重要

Slide 20

Slide 20 text

今回の話に興味を持っていただいた方へ ● エンジニアHub様掲載の記事もご覧ください React+Reduxによる状態管理とフロントエンドの技術的負債 ─ 長く継続するサービスのアプリケーション設計

Slide 21

Slide 21 text

最後に ● Chatworkではフロントエンドエンジニアを募集しています ● 巨大なSPAと一緒に向きあい改善し続けてくださる方、ぜひご応募ください! 採用ページはこちら

Slide 22

Slide 22 text

働くをもっと楽しく、創造的に