🧳

package by featureのメリット・デメリット

2023/11/02に公開

前回の記事で、package by featureに関する記事をまとめました。

今回は、この手法自体のメリット・デメリットについて述べていこうと思います。

package by featureとは

要するにこうしよう、ということ

package by featureのメリット

仕組みとしては、単にfeatureという単位でまとまっているだけですが、そのことは色々なメリットを生みます。

外側から見た観点

全体が把握しやすい

これは、Screaming Architectureが言っていることと同じなのですが、パッと見でそのアプリケーションが何を含んでいるのかが分かる、というメリットがあります。

package by layerのようなスタイルの場合、フォルダ直下の登場概念は、あくまで実装の都合にすぎません。
そのアプリケーション自体の中に含まれる概念をなるべくそのまま直下のフォルダ名に表現できれば、全体像が掴みやすく、機能ごとの実装がどこに存在するかが明確にできます。

featureの内側の観点

差分が見やすい
feature単位でコードがまとまっているゆえ、差分が見やすいです。
プルリクなどでも、feat: 投稿をタグ分類できるようにしたといったプルリクがあれば、src/features/postの中に差分があるはずですし、あるいはsrc/features/tagが新規に作成されるでしょう。
そうでないところに差分があったら、なぜ修正が必要だったのか、という観点でレビューする際の注意点として捉えられます。

分担がしやすい
また、作業の分担も行いやすいです。複数人で開発する際に、異なるfeature上のタスクを担当する際にも、上記のようにプルリクとして見やすいですし、書く際だけでなく、単純に読む範囲がfeatureというスコープの内側に絞れる点が良いです。

新人の方や新規にアサインされたメンバーなどの最初のキャッチアップや、軽いタスクを振るといったコントロールもしやすいのではないかと思われます。
まずは規模の小さいfeatureに関わるタスクをお願いし、状況や必要に応じて複数のfeatureや、規模の大きいfeatureに関わってもらう、といった選択が取れそうです。

featureの境界の観点

極端な話、featureを跨いだ部分さえ正しく動いていればよいわけです。カプセル化と考えても良いでしょう。

境界をまたぐ事自体が情報になる

良いfeatureを設計できると、featureの境界をまたぐ部分が少なくなるでしょう。(というより、そのようなものを"良い"と言っています)
いわゆる、凝集が高いという状態ですね。

また、境界を跨ぐ部分が多すぎる時はcode smellとして捉えられます。

部分的にアーキテクチャを変えられる

たとえば、特定のライブラリを置き換えたいときに、まず特定のfeatureの中だけで試す、ということが選択が取れるかもしれません。

例: 「今使ってる古いformライブラリをやめて、別のものに置き換えたい」みたいなケース

一度にコードベース全体で変更を適用するのではなく、複数のデプロイで分けて適応できる方が、影響範囲を抑えてリスクを減らしたり、他の開発作業と並行して進めたりしやすいでしょう。

ただし、それらができるのは、そういったことができるようにfeatureを適切に切っておく必要があり、package by featureによって直ちにその手段が手に入るわけではありません。(もちろん、package by layerのままこれらをやるよりは、圧倒的に進めやすいとは思います)

過剰なアーキテクチャを避けられる

他にも、小さいfeatureの場合、レイヤー分けをするのが大げさなケースのときに、レイヤー分けをせず、少ないコードやコンポーネントで実装する選択肢が取れるのは良いことです。

必要になったタイミングで、レイヤーを分けることを検討することができます。

package by featureは、他のアーキテクチャとほとんど衝突しない

package by layerとpackage by featureが対立構造のように感じられていたかもしれませんが、実はそうではありません。
というのも、package by featureにおける個別のfeatureの内側は、package by layerそのもののはずです。

このUser featureの内側は、元のpackage by layerのときの構成要素である、model,service,repositoryなどがあるわけです。

MVCなら、src/features/userの中に、UserModel, UserController, UserViewが存在するでしょう。

featureとlayerという2つの軸で、どっちの軸で先にsortをするのかという話に過ぎず、package by featureの採用は、今使っているアーキテクチャを捨てるということを意味しません。

衝突すること、あるいは懸念すべきことは、以下のようなことだけです。

  • フォルダのsrc/の直下にどちらの観点でまとめるのか
  • 利用しているフレームワークの都合で、フォルダ構成に制約があって、導入できないか、あるいは設定やhack等が必要か

実行時のなんらかの要件とは関わりが無いはずで、あくまでファイルやモジュールの配置に関する議論に過ぎない、というところが良いところと言えます。

デメリット

処理の重複や、featureを跨いだ修正に対する対応漏れなどが比較的起きやすい印象があります。

package by layerの場合、その対応範囲が同じフォルダ上に存在する可能性が高く、開発者が気づきやすいということです。

重複

重複に関しては、気づいたタイミングで別関数でまとめれば良いと思います。
また、DRY(Don't Repeat Youreself)に対するカウンター意見としてのWET(Write Everything Twice)もあるように、共通処理をまとめるのは、早すぎる最適化であったり、本当はまとめるべきではない可能性もあります。
なので、重複に関してはそこまで気にしなくても良いのではないか、と個人的には考えています。

対応漏れ

あるfeature上で何らかの対応をした後、同一の対応を他のfeature上でもすべきだったが、それが漏れる可能性が、package by layerのときと比べると高いということです。

対応漏れに関しては、注意力(あるいは、コード上の検索網羅力)が必要になってしまうかもな、と思います。
(厳密に言えば、package by layerであるからといって、特定の修正対象がなんらかのlayerに閉じているかどうかは、推測あるいは状況証拠にすぎないのですが、比較するとpackage by layerのほうが早く)

まとめ

自分はpackage by feature推奨派で、殆どのケースで導入をしたほうがいいと考えています。

ただし、導入に関して考えるべきことは、メリット・デメリットだけではないです。

  • 開発者間の合意、理解の形成
  • 導入のコスト
  • 導入手順
  • フレームワークとの整合
    (ただし、これはpackage by featureに限らずいつでもそうですね)

次回以降でここについて述べようと思います。

Discussion