デブサミ参加レポート - エンジニアリングで負債を返済するための勘所 ― 事業特性にあわせたリファクタリング/リアーキテクティング/リプレイス

2021年2月19日に開催されたDevelopers Summit 2日目の参加レポートです。

[本セッション](https://event.shoeisha.jp/devsumi/20210218/session/3052/)は[テスト駆動開発](https://www.amazon.co.jp/dp/B077D2L69C/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)(オーム社)の訳者である和田卓人（t_wada）さんとほか3名の方々とのパネルディスカッション形式で実施されました。

# 負債のメタファ
事業をすすめる中で、技術とビジネスの乖離が生まれ、事業のスピードについていけなくなる。といった技術的な負債があると思います。
負債が溜まっていくと同じことをするにもだんだん時間がかかるようになっていきます。

そのような技術的負債に対処する一般的なアプローチとして以下の３つの方法があるかと思います。

- リファクタリング
    - ボトムアップにコードをきれいにしていく
    - ローリスク／ローリターン
- リアーキテクティング
    - 大きなシステムをサブシステムに分解し、サブシステム単位で置き換えていく
- リプレイス／リライト
    - ゼロから書き直す
    - ハイリスク／ハイリターン


ここからの内容は、登壇者の3名のサービス概要と遭遇した技術的負債、及び技術的負債に対照した際のBefore-Afterについての発表と、最後にパネルディスカッションです。

# 登壇者の方々の3つのサービス

## 事例１
   - 広告配信サービス
   - メディアで利用される仕組み
   - SSP Supply-Side Platform 

リファクタリングは日々やっている。
リアーキテクティング

- Before
    - データを使う配信サーバのソースを見てもデータの中身が分かりづらい
        - 1GB程度のバイナリ
    - 広告配信設定
    - ドキュメントが大したものがない
- After
    - 実施内容
        - Protocol Buffersでスキーマを定義
        - 一部の新しいデータのみPB版を提供
        - 徐々に移し替えて移行していく
    - 効果
        - スキーマを見ればどんなデータがはいっているのか分かる
        - スキーマを前提とした単体テストも書ける

- リアーキテクティング時のポイント
    - 顧客がいるため、一気にサービスを落としてビックバンリリースはできない。
    - 後戻りできるような形で進めていく必要がある。
    - 止めず、壊さず、ですすめるために徐々に移していった


## 事例２
- システム情報
    - テーブル450
    - コード250万行程度
    - 広告枠・掲載管理・広告本体の3層のシステム構成になっている。

- Before
    - 広告枠と掲載管理と広告本体と、重複機能が多数ある
- After
    - 重複を葬り or 集約
    - リファクタリングとリアーキテクティングで
    - インターフェース層を設けて、機能間依存性を管理


- 広告枠や広告管理を葬る（なくす）という選択をとったというのは特徴的。どうして？
    - 2004年に事業スタート
    - フルリプレイスはしていない。
    - サービスを徐々に追加してきた。
    - 実は使っていない箇所、が多い傾向にあった。
    - 全体像を使っているエンジニアであれば、使っていないところの勘所があり、選択をとった。
- じゃあ考える順番は治す前に葬る？
    - 必ずやる。
    - 相互レビューの機会があり、そのタイミングで葬ることができるか自然とチェックがはいる。
- エンジニアだけで判断するわけではないものもあると思うが？
    - 事業レベルと機能レベル、コードレベルがある。
    - コードレベル→エンジニア
    - 機能レベル以上→顧客に提供している、マネージャーや事業担当者と会話する

## 事例３
就活生と企業のマッチングを創出するサービス
現在は新卒の就活支援に特化している。

契約企業と就活生をつなげる、なんらかのシステムの集合体。
- サポーターズ主催イベント
- 企業主催イベント
- 個別紹介など

### リプレイス
サービスの特性上、就活生の卒業年に応じて新旧システムの入れ替えをしやすかった。
卒業年によって違うシステムを提供することで影響範囲を限定した。

- Before→After
    - API層を挟むことで複数のクライアント実装に対応しやすくした
    - iOS版は書籍出版後の2020年11月にリリース

事業特性を鑑みて、リプレイス／リライトを戦略的に実施した。


# パネルディスカッション
- サービスを継続しながらリアーキテクティングするのは難しいと思いますが、気をつけていることはありますか？　今までに失敗から学んだことは何ですか？
    - だめだったときに戻れるようにしておくことに気をつけている。
    - ダメそうと思うパターン。→開発について誰からもプルリクエストが来ない。
- リファクタリングの必要性など、ビジネスサイドの方に理解されないのですが、パネリストの方がどのようにご説明されているのか教えてください。
    - コードレベルは任せてもらっている。説明不要。
    - サブシステム、事業レベルの場合は、技術的負債の返済についてはボリューム感を伝える。
    - テーブルの1/4を削ることで生産性が上がる。と伝えると伝わる。
    - 返済だけでなく、ビジネス的な効果を伝える。収益が上がる、コストを抑える。など
    - 事業KPIに合わせてそういった項目を織り込む
    - 企画の段階で伝える。
- 技術的負債に対する定量的評価、やりたいんですけどいい方法はありますか
- 負債を「負債」と認識する線引はありますか？（感覚的なものでも）
    - 明らかにパフォーマンス劣化があった。
    - CSVダウンロードを分割ダウンロードして結合するのに数時間。。。
    - 処理量が多いとサーバが止まって最後にエラーが発生することも。
    - XX時間がかかっているので問題がある。という声が上がる。
- あるときに急に遅くなる？じわじわ遅くなる？
    - 計測する。がお手本だと思うが、事業サイドから「最近XXXが遅い」と声がかかって気づくこともある。
    - そういうことを伝えてもらう関係性もポイントになりそう。
- サービス開始時はサービスを成長させるために全力かと思います。成長していく中で、ここで負債を返さなきゃいけないというタイミングはどのように判断していますか？
    - 技術的な定量化にはあまり重きを置いていない。
    - 事業をやっていく上でどういう困り事があるか。→そこから定量化を考える。
    - 事業上の問題の解決にあたって、技術面が問題なのかどうか。がポイントだと思う
    - 「負債を返さなきゃ」
- 既存のサービス・機能を葬るときに、他部署などからの抵抗はなかったのでしょうか？
    - コンウェイの法則がありがち。
    - 15年、20年事業をしていると成熟期に入ってくる。
    - 部署ごとにミッションをつくるというよりは、ビジネス全体のやり方自体を見直していくことになる。
    - 全体の生産性が上がればみんな喜ぶ。
- リプレースの際に、いわゆるセカンドサービスシンドローム、旧システムで実現できなかったことのてんこ盛りにならない様に工夫したことなどありましたか？
    - 口をすっぱくして、「本当にこれがいるの？」を数ヶ月に渡ってひたすらやっていた。
    - リプレースをやろうとして失敗した経験が過去にある。
    - そのときに懲りたのでは。事業責任者レベルで盛り込みすぎると失敗する経験があった。
- 並行でリアーキテクティングしていく場合、データ層の分割（同期）が課題になる気がします。現行システムとの連携などはどのように実施していますか？
    - こうならないように、なるべく小さくリリースする。
    - リリース感覚は細かい。
    - 6ヶ月で開発。2ヶ月は細かくリリースしていった。
    - データ同期はどうしても一発で切り替えるタイミングが発生する。
    - なるべくそうならないような設計になるよう意識している。。


# 感想
- リファクタリングはよく耳にしてますが、リアーキテクティングという考え方も１つ学びになりました。
- そもそも不要になっている機能は葬り去るというアプローチは、その後のサービスの複雑化を防ぐ良いアプローチだなと思いました。ただ、漠然と「なくす」というのに拒否反応を示す日強もいるような気がするので、ステークホルダーとのコミュニケーションには注意が必要だと同時に感じました。
- リプレースというとリスクが大きいイメージがあります。事業特性とうまく組み合わせてタイミングを考慮するという考え方もあるのだと気づきになりました。