Slide 1

Slide 1 text

KEPPLE DB リプレースにおける 技術的負債のバランス感覚 芹田 悠一郎 @株式会社ケップル KEPPLE CREATORS LAB

Slide 2

Slide 2 text

● 株式会社ケップル KEPPLE CREATORS LAB 所属 ● エンジニアとして働き始めてほぼ7年 ● ケップルにジョインして2年弱 ● フルスタック的に Web まわりのエンジニア をやっています ● とにかくコーヒーが好き 芹田 悠一郎 Yuichiro SERITA

Slide 3

Slide 3 text

背景

Slide 4

Slide 4 text

KEPPLE DB のフロント、 作り直しました

Slide 5

Slide 5 text

KEPPLE DB って何?

Slide 6

Slide 6 text

KEPPLE DB ● スタートアップ投資家向けのサービス ● スタートアップと投資家のデータベース ● 「スタートアップ」「投資家」「ニュース」などのデータに対して検索・フィルタ

Slide 7

Slide 7 text

KEPPLE DB

Slide 8

Slide 8 text

KEPPLE DB

Slide 9

Slide 9 text

KEPPLE DB の性質 ● スタートアップ・投資家の数は 2 万社くらい (どんどん増える) ● スタートアップ 1 社あたり、フロントで表示しているプロパティは ざっくり数十個くらいのオーダー (じわじわ増える)

Slide 10

Slide 10 text

KEPPLE DB の性質 (ビジネス観点) ● ケップルのプロダクト部門の投資家向けサービスの主力 ● ほぼ毎週ユーザーに見えるアップデートをしたい ● でっかい機能追加もしたい ● その上、長期間無理なく運用したい

Slide 11

Slide 11 text

Q. なぜ作り直した?

Slide 12

Slide 12 text

A. 技術的負債がキツい。

Slide 13

Slide 13 text

課題 ● KEPPLE DB は高頻度でリリースしたい が…… ● KEPPLE DB は KEPPLE CRM の一機能だった ● KEPPLE CRM はリリース時にサービス停止が必要 ● KEPPLE CRM は 2018 年リリースで、 リプレースを決断した時点で 5年間機能追加したり消したりしていろいろしんどくなっている

Slide 14

Slide 14 text

課題 (フロント) ● React で書かれている素の SPA で規模拡大に課題 ● いろいろなライブラリのバージョンが古い ● 魔改造されたコンポーネントが多くてバージョンが上げられない ● かつて Internet Explorer に苦しめられた結果残ったメンテしづらいコード

Slide 15

Slide 15 text

KEPPLE DB は独立させ リプレースしよう

Slide 16

Slide 16 text

旧構成 フロント バック データ ソース

Slide 17

Slide 17 text

新構成 フロント BFF バック データ ソース New!

Slide 18

Slide 18 text

新構成 BFF フロント NestJS GraphQL Next.js (Pages Router) Jotai Mantine Radix UI urql

Slide 19

Slide 19 text

本題

Slide 20

Slide 20 text

技術的負債のバランス感覚

Slide 21

Slide 21 text

技術的負債とは?

Slide 22

Slide 22 text

技術的負債とは (本セッションでの定義) ● 短期的に見ると便利だったが、時間が経つにつれ脚を引っ張るようになったもの ● あらゆるコードは必ず負債になる ● 負債になりづらいコードはあるが負債にならないコードはない ● 負債になりづらさを追求すると開発速度が落ちる (無借金経営)

Slide 23

Slide 23 text

技術的負債とは (本セッションでの定義) ● 短期的に見ると便利だったが、時間が経つにつれ脚を引っ張るようになったもの ● あらゆるコードは必ず負債になる ● 負債になりづらいコードはあるが負債にならないコードはない ● 負債になりづらさを追求すると開発速度が落ちる (無借金経営) バランス感覚が大事

Slide 24

Slide 24 text

負債になりづらさと開発速度

Slide 25

Slide 25 text

負債になりづらいコードとは?

Slide 26

Slide 26 text

逆に、負債になりやすいコードとは?

Slide 27

Slide 27 text

フロントで何が負債になっていたか? ● React Router と密に結合したロジック ● 既成の UI ライブラリを魔改造した独自コンポーネント ● URLクエリ文字列を直接触って状態を保存するコード ● 特定のブラウザ専用のロジック → 具体的なものに密に結合している

Slide 28

Slide 28 text

具体的なものに密に結合していると負債になりやすい ● ライブラリのバージョンアップ、移行で苦しむ ● 世の中の環境 (ブラウザ、トレンド) が変わったときに苦しむ ● 機能追加、バグ修正するときに抽象化してないと苦しむ

Slide 29

Slide 29 text

負債になりづらいようにしたい

Slide 30

Slide 30 text

具体的なものに依存しない コードを書く?

Slide 31

Slide 31 text

「クリーンアーキテクチャ」? “優れたアーキテクチャはユースケースを中心にしているため、フレームワーク、 ツール、環境に依存することなく、……” “アーキテクチャはフレームワークに関するものではない(そうあるべきではない)。 アーキテクチャはフレームワークから提供されるものではない。フレームワークは 使用するツールであり、アーキテクチャが従うものではない。” “フレームワークはツールであり、生き方ではない” “Robert C.Martin,角 征典,高木 正弘. Clean Architecture 達人に学ぶソフトウェアの構造と設計 (Japanese Edition), 2018” 第21章 “叫ぶアーキテクチャ” より

Slide 32

Slide 32 text

OK, OK, じゃあ…… React に依存しないコードを書こう!

Slide 33

Slide 33 text

とはならない (とくにフロントエンドは)

Slide 34

Slide 34 text

ライブラリに依存しないコードを書くのは無理 ● React (と Next.js) を使う以上はがっつり乗っかっていくしかない ● たとえば UI コンポーネントライブラリを使うなら「そのライブラリの流儀」に 従わないとつらい ● ライブラリの流儀に添うことで負債になりやすくなるが開発スピードは上がる

Slide 35

Slide 35 text

ライブラリに依存しないコードを書くのは無理 ● React (と Next.js) を使う以上はがっつり乗っかっていくしかない ● たとえば UI コンポーネントライブラリを使うなら「そのライブラリの流儀」に 従わないとつらい ● ライブラリの流儀に添うことで負債になりやすくなるが開発スピードは上がる このトレードオフのバランスを取りたい

Slide 36

Slide 36 text

KEPPLE DB におけるバランス ● 負債を踏み倒せないので、開発スピードに全振りはできない ○ 長く続けるサービスなので長くメンテできるようにする ○ リプレースは今回限りにしたい。定期的に作り直す式年遷宮方式にはしない ○ 返済できない負債を作ってはいけない ● 開発スピードが必要なので、負債になりづらさに全振りはできない ○ リプレース作業の間、通常の機能追加のペースが落ちてしまう

Slide 37

Slide 37 text

フロントエンドの状況の整理

Slide 38

Slide 38 text

(ライブラリ・フレームワークからの) 独立させやすさと開発速度 ※ここでの「独立させやすさ」≒直接依存させないこと、負債になりづらさ

Slide 39

Slide 39 text

ライブラリからの 独立させやすさ ライブラリからの 独立してほしさ ドメインロジック UIの挙動 データフェッチ ディレクトリ構成 フォーマット処理 ルーティング 独立してほしさと独立させやすさ (ざっくり) UIライブラリのス タイリング

Slide 40

Slide 40 text

ライブラリからの 独立させやすさ ライブラリからの 独立してほしさ ドメインロジック UIの挙動 データフェッチ ディレクトリ構成 フォーマット処理 ルーティング 副作用 副作用 副作用 独立してほしさと独立させやすさ (ざっくり) UIライブラリのス タイリング

Slide 41

Slide 41 text

ライブラリからの 独立させやすさ ライブラリからの 独立してほしさ ドメインロジック UIの挙動 データフェッチ ディレクトリ構成 フォーマット処理 ルーティング ユーザーに 見える 独立してほしさと独立させやすさ (ざっくり) UIライブラリのス タイリング

Slide 42

Slide 42 text

ライブラリに依存で 開発速度向上 ドメインロジック UIの挙動 UIライブラリのス タイリング データフェッチ ディレクトリ構成 フォーマット処理 ルーティング ※あくまで KEPPLE DB の場合です ライブラリに依存するメリット (ざっくり)

Slide 43

Slide 43 text

ひとつひとつ見ていく

Slide 44

Slide 44 text

UIの挙動・UIライブラリのスタイリング ● 独立させやすさ低、独立してほしさ中〜低 ● ライブラリ・環境の破壊的変更が多めなので剥がしやすくしたい ● クロスブラウザ対応、アクセシビリティ対応を考えると自作は厳しい ● UIライブラリを使うとUIライブラリのデザインシステムに乗っかることになる ● ヘッドレスではないUIライブラリは、流儀に従う以外の選択肢がほぼない

Slide 45

Slide 45 text

ルーティング ● 独立させやすさ中〜低、独立してほしさ中〜低 ● どの Router ライブラリを使っても依存を剥がしづらい ● Next.js Pages Router 採用してる時点でがっつり依存するのが確定 ● もし方式を変えるなら (ルーティングまわりは) 諦めて作り直したほうが早い

Slide 46

Slide 46 text

データフェッチ ● 独立させやすさ中〜低、独立してほしさ中〜低 ● 各ライブラリで似た API ではあるが、ラップして吸収しきれるほどではない ● 流儀に沿った方がラク ● もし剥がしたくなっても機械的に書き換えられる

Slide 47

Slide 47 text

ディレクトリ構成 ● 独立させやすさ中〜低、独立してほしさ中〜低 ● ファイルシステムベースのルーティングのところ以外は比較的自由にできる

Slide 48

Slide 48 text

ドメインロジックとフォーマット処理 ● 各独立させやすさ高〜中、独立してほしさ高〜中 ● 副作用のない純粋な関数 ● 容易に抽象化できる ● フルスクラッチは流石に手間なので、内部的にライブラリを使う

Slide 49

Slide 49 text

分類を踏まえて KEPPLE DB の方針 ● UIライブラリ、ルーティング、データフェッチはライブラリに依存し開発速度をとる ● ディレクトリ構成はライブラリに依存しないようにする ● ドメインロジック、フォーマット処理はライブラリに直接依存させない ● ライブラリの流儀に従いつつ剥がしやすいようにする ● 負債の返済をあらかじめ計画に入れておく

Slide 50

Slide 50 text

具体的に何を工夫したか

Slide 51

Slide 51 text

UIライブラリにどっぷり依存して開発速度を上げる ● クロスブラウザ対応、アクセシビリティ対応、デザインシステム構築の 工数削減の対価として、剥がしづらいデメリットは受け入れる ● どうせ依存が強いので Button や Text レベルの抽象化はしない (Atomic Design 的に言えば Atom は抽象化しない) ● feature を跨ぐコンポーネントの共通化は慎重に

Slide 52

Slide 52 text

UI ライブラリを魔改造しないで済むように進める ● 実現したい UI/UX がどうにも実現できない、という状況にしない ● 実現したい UI/UX の解像度が低いと魔改造に走りがち。 「前にできてたあれをそのままやりたい!」 リプレースあるある ● UI ライブラリのデザインシステムに従う。従うことができるように進める ● ビジネス側、デザイナーを巻き込んでライブラリを選定する ● Storybook で早くフィードバックをもらい、軌道修正する

Slide 53

Slide 53 text

ルーティングはライブラリにどっぷり依存する ● ただし、pages/ 以下のファイルは import した (いくつかの) 関数を 呼び出すだけにしておく ● そのうち App Router へ移行するなどの変更に耐えるための処置

Slide 54

Slide 54 text

データフェッチもライブラリにどっぷり依存する ● 薄くてシンプルなライブラリがよいなと考えて urql を選んだ ● クライアント側は urql の useQuery をそのまま叩いている ● その他のところは便利になるようにラップしてたりする

Slide 55

Slide 55 text

ディレクトリ構成はfeatureベースにする ● ディレクトリ構成はフレームワークに依存させずユースケースに合わせ、 feature ベースにする ● 種類別はフレームワークへの依存度が高い (種類別とは、component, hooks, libs, のよ うなディレクトリの下に機能名のディレクトリがぶら下がる方式を指しています) ● ルーティングだけは仕方ないのでフレームワークに従う。

Slide 56

Slide 56 text

ドメインロジックはライブラリに直接依存させない ● ドメインロジック、ビジネスロジックはバックに寄せる ○ フロントとバックの責務の分離の観点でバックに寄せる ○ バックはクリーンアーキテクチャ的な構造にしやすい ● ライブラリを使いつつ副作用のない処理を書いて純粋関数でラップする ○ 抽象化して剥がしやすく

Slide 57

Slide 57 text

フォーマット処理はライブラリに直接依存させない ● フォーマット処理は基本的にフロントに置いている ○ フロントとバックの責務の分離の観点でフロントに ● ライブラリを使いつつ副作用のない処理を書いて純粋関数でラップする ○ 抽象化して剥がしやすく

Slide 58

Slide 58 text

ライブラリの流儀に添いつつ剥がしやすくする ● 副作用がある処理はラップしてもメリットが薄い。 副作用があるということは、たいていライブラリの内部に依存している。 剥がしやすさの観点ではラップしなくてよい ● とはいえ使いやすさの観点から多少ラップすることが多かった

Slide 59

Slide 59 text

ライブラリの流儀に添いつつ剥がしやすくする ● 容易に剥がせないことがわかっているライブラリは枯れたものを採用 ○ App Router ではなく Pages Router を採用したのはそのため ○ (新しいライブラリや新機能を使いたい欲求は別プロダクトで……) ● 破壊的変更を頻繁にするライブラリは容易に剥がせるときのみ採用 ○ Storybook とか

Slide 60

Slide 60 text

ライブラリの流儀に添いつつ剥がしやすくする ● トレンドの変化が早そうなライブラリは容易に剥がせるように使う ○ たとえば Jotai が当てはまる。 グローバルな状態を使いたいところでだけピンポイントで使っている。

Slide 61

Slide 61 text

負債の返済をあらかじめ計画に入れておく ● 「負債の返済が不可欠である」 という認識をビジネス側と共有する ● スケジュールに負債の返済を織り込む ● KEPPLE DB チームでは毎週金曜日は返済日 ● 今回のリプレースでリリース頻度が爆増し、負債の返済の重要性が伝わった

Slide 62

Slide 62 text

まとめ

Slide 63

Slide 63 text

まとめ ● 技術的負債になりづらさは開発速度とトレードオフ ● KEPPLE DB ではうまく借金して開発速度を上げていく方針をとった ● 負債を返しやすい環境づくりが大事