🌊

プロダクトコードの責務分割を行うことの意義

2 min read

この記事はGoodpatch Anywhereアドベントカレンダー18日目の記事です。

クリーンアークテクチャとか、DDDとか責務分割の方法論はいろんな方面であるのですが、ここでは個別のアーキテクチャに言及するのではなく、責務分割の意義について一言書いてみます。
プロトタイピング時に割とサボって後で大変みたいな事がよくあるのでその辺をサラッと行きます。

サービス開発あるある

プロトタイピングフェーズ

  • 毎日デザインが変わる
  • バックエンドは当然ないのでfirestoreあたりを使う
  • とりあえずFlux的なアーキテクチャに乗っかる
  • 責務に応じたレイヤー分けなどはせずひたすら高速に実装を進める
  • 少人数での開発で会話レベルのコミュニケーションで成立する
  • サービスリリースされたら作り直すんだ!と言う様な夢を抱いている
  • firestoreで無理にならない範囲でやろうと言う様な話で進める

プロトタイピング時の壁

  • firestoreでは不可能なクエリ条件の画面が現れるが、実装できないので別な案で進める
  • キーワード検索したくなる。algoliaあたりを利用するか検索機能を見送る

サービスがリリースされたあと

  • データのマイグレーションが必要になるが、Firestoreにはschemaがないのでマイグレーションができずロジックが複雑化する。
  • 既存コードの責務分割がなされておらず、追加メンバーがどこにが読み取れず、プルリクでレビューが跳ねられプルリク在庫が積み上がる
  • リリース時に見送った機能を開発するためリファクタリングが見送られる

ある程度落ち着いてくる

  • デザインの断片化が進んできて整理がしたくなる。
  • ちょっとコードを書き換えると何かバグが発生する様になる。
  • 課題はあるのに一向に解決されない
  • 開発陣は頑張っているのにリリースができない
  • デザイナーが新しい提案をしても開発に余力がなく開発されない
  • アウトプットが減り課題意識を持った経営陣が会議をひたすらする様になる

この辺はどこの組織に行ってもまぁ通る道だなぁと感じています。

問題は変化速度が下がっている事

変化をするためには試行が必要になりますが、一つの事柄を変化させるにも、責務の分割がなされていない、依存関係がスパゲッティなど、変更範囲が広かったり、複雑な修正がいるなどする状況に陥ると人は簡単に慎重になりますので、慎重になる頻度を下げる様な施策が必要になってきます。

フェーズ毎に目的が違うので最適な方法論は変わる

デザインも実装もフェーズに合わせて良いとする塩梅は変わってきます。
例えば、プロトタイプを開発している時と100人のユーザーがいるサービス、100万人のユーザーがいるサービスでは前提が異なります。規模に応じて開発組織も違えば力を入れる点も異なってきます、当然アーキテクチャも異なってくるのは自明の理です。

サービスは成長に合わせてアーキテクチャも変化をせざるを得ない

サービスの成長スピードは組織によって異なるでしょうが間違いなく成長はするのです。
こうなるとサービスの成長に応じてアーキテクチャを変更させていく必要が出てきます。
これは、作り手が組織化していく中で避けて通れない道になります。
アーキテクチャを変更できないまま進めると組織のスケールに合わなくなり、サービスの変化速度が下がっていきます。

最初は大雑把でもいい境界を作る癖をチームにつけよう

プロトタイピングフェーズでは、速度を求められるあまり、Presentation ComponentにViewとドメインロジックを混ぜがちですが、これはやはりやめるべきです。昔のjsではありません、現代ではimportと言う機能があります、ドメインロジック、インフラIO、viewは混ざらない様にしましょう。
Componentに全てを書くのではなく素直に呼び出すだけにしましょう。
全てはそれからです。

UIをCUIに変更しても別に作れるよねという作りは責務分離の指標になる

GUIでは画面に状態を持つため、ビジネスロジックが混入しがちですが、CUIのコマンドベースのUIは、コマンド実行時に状態を持つ事がないため、いつでも実行可能なロジックを順番にコールするだけのシンプルな構造になる、これをGUIを作っている最中でも維持できると、デザインの変更に対して、処理の積み上げの組み合わせを変えたり追加するだけと言う様になるので、変化速度を下げずに済む

プレゼンテーション層にimport firebase/**が見えたら要注意

Firestoreは便利ですが、別に多機能なわけではありません、都合に応じて、Firestoreから自前のAPIに切り替える事はよくあります、入れ替える際に問題になるのが、プラットフォーム固有の作法がコンポーネントやアプリケーションロジックの中で入っている場合です。
例えば、storeやコンポーネントでfirestoreのサーバーサイドタイムスタンプや、リファレンスドキュメントの取得を行うなどの事をしていると、restAPIへの変更の際に、その辺りを記述している箇所を全て書き換えなければなりません、typescriptなど静的にエラーが出るレベルはいいですが、実行時にしか検出できないエラーなどが発生する可能性が高く、変更に対して慎重になり、機能追加が後回しにされ、プロダクトの成長が遅れるなどの事に繋がってきます。
firestoreなどプラットホーム固有の作法や型は、一定のレイヤー(インフラ層)などの外に漏れ出ない様に最初から作ると言うのが先々への投資になります。
これは、大したコストを払うものではなありませんが、時間が経てば立つほど身動きが取れなくなくなるので早めに徹底する事をお勧めします。

最後に一言

責務分割を諦めないでください。
それは絶対に正しい事です。