ソフトウェアの設計とアーキテクチャ

概要

ソフトウェア設計の言語化スキルを磨くこと|qsona|note

ソフトウェアのアーキテクチャ(特にそのアーキテクチャを選択するとなぜ良いのか)をちゃんと言語化して説明できてないなということで、一旦まとめたほうが良さそうと思ったのでまとめてみる。個人的な考えなのでこれが正しいとは思っていないし、悩んでる部分もたくさんある。 アーキテクチャはサービスが成長して、5年、10年してから良し悪しがわかる場合もあるので難しいなと思う。

前提

  • golangを使っている
  • リリースされなかったがプロダクション向けのコードを書いていた
  • アーキテクチャ設計の責任を負っていた

採用したアーキテクチャ

レイヤー

他にもDocker用のcontainerディレクトリやらがあったがレイヤーは以下のような感じだった

  • domain
  • interfaces
    • 外部との接点
    • HTTPリクエストやら
    • DBへの問い合わせやら
    • その他ストレージへの問い合わせやら
    • 外部サービスへのリクエストなど
  • usecases
    • 主にinterfacesから呼び出される
    • 入力は素直にこれが呼び出される
    • 出力はDIPに従って、usecasesに定義されたインタフェースを経由する
  • infrastructure
    • 独立したコンポーネント
    • 具体性が増す
    • 例えばDBでもPostgresqlとか
    • キャッシュでもRedisとか
    • 外部サービスのクライアントもここに実装してた
    • 例えばPostgresqlに書き込む場合は、直接ここのモジュールを呼び出すのではなくinterfacesを経由していた

仮にHTTPリクエストがあって、DBに書き込む場合以下のような流れを取っていた。

interface(入力) -> usecases -> interfaces(出力) -> infrastructure -> DB

良さ

  • レイヤーごとに差し替えやすい
    • 変更が限定的
    • 現時点での最良を選択しているつもりだが将来はわからない
    • 最良ではないが現時点で良さそうなものを選ばざるおえない場合もある
  • 再利用がしやすい
    • usecases、domainは基本的に無理だがその他は別のプロジェクトでも利用できる可能性が高い
    • プロジェクト内の再利用もDIによってしやすい
  • テストが書きやすい(mockingしやすい)
    • 差し替えやすいということはmockにも差し替えやすい
    • レイヤーによっては独立性が高いのでテストも書きやすい

悪さ(悩んでいること)

  • 実装量が増えやすい
    • レイヤー間でのデータのやりとりにそれぞれデータ構造が必要になる場合がある
    • インターフェースを用意する必要がある
  • 冗長すぎる感じがする
    • 差し替える可能性がほとんどなくても差し替えられるようにしている
    • レイヤーのためにただ他のレイヤーを呼び出すコードがたまにある
  • 変更しやすいとはいえ、場合によってはそれなりのコストがかかる
    • 根本的な処理の修正は結局、他レイヤーにまたがった修正になることがある
  • usecasesのテストなどはmockingだらけになりがちで意味が薄い感じがする
    • ほぼmockingされた処理になってしまう
    • 呼び出す順番しかテストしてない

まとめ

総じて良さのほうが上回っていると思うが、悩んでいる部分は無視できない