質問: 以下質問における Hidenori GOTO さんの回答 を読みました。そこではサービスはこのようなものだと説明されていました。 MVCモデルにおけるサービスの役割について教えて下さい しかしこれだけ見ると、ユーティリティクラスとの違いがわかりません。 Wikipediaの ユーティリティー には英単語で「役に立つもの」「有用性」「効用」「公益」などの意味だと書いてありました。役に立つものをある程度のまとまりとして集めたクラス(ユーティリティークラス)と共通処理を何かの観点でまとめたクラス(サービスクラス)にどのような違いがありますか? * Controllerに記述していた共通処理を何かの観点でまとめるのに使う * Modelに記述していた共通処理を何らかの観点でまとめるのに使う * テンプレートのために必要な共通処理を何らかの観点でまとめるのに使う
回答: はじめに ==== 非常に答えにくい問題になります。 話しているコンテキストや、扱うフレームワーク、話者によって意図が変わるからです。 私も仕事現場で大変混乱し、`サービス`という言葉を状況に応じて比較的臨機応変に理解できるようになったのは、初めてその言葉を聞いてから10年以上たっています。 サービス ==== 私が初めになんとなくサービスというのを理解したとき まず私が理解した`サービス`というのは下記の記事で紹介されているような場面です。(あくまで私がなんとなく理解はじめたころの話です) 名詞の王国 - あどけない話 大抵の`オブジェクト指向`の命名規則として、 `クラス名`は`名詞`、`メソッド名`は`動詞`にするというのが プログラマー間の共通認識としてあります。 しかし、状況によってこの記事のように`動詞`を`クラス名`にしたいことがあります。(したいことがあります。と書いてますが、私自身はそう思ったことはほぼなく、そういう流派で書かれたプロジェクトを何個も経験して、そいういうプロジェクトもたくさんあるよねという感覚です。とはいえ、モックオブジェクトを作りやすいなど様々な利点があるような気もします。) そのような場面では、`GetHogeService`(Hogeを得るクラス)`PostHogeService`(Hogeをポストするクラス)というような`クラス名`(`動詞 + 目的語 + Service` もしくは `動詞 + Service`)にして、この`クラス`は、`execute`(もしくは`run`)といったメソッドを、ただ1つを持つという流派です。(記事内は、クラス名に動詞を使ってメソッド名に`execute`を持つような例です。`動詞+Service`という命名規則ではないので、この記事はあくまでそういう場面を想定した参考記事です) 余談ですが、似たような場面でHogeManagerというようなマネージャークラスを導入するケースもあります。私の感覚としては、マネージャークラスを導入した場合は同プロジェクト内でサービスを使うことは稀な気がします。マネージャクラスは関連する複数のメソッドを持つことが多いです。 アーキテクチャ的な観点 アーキテクチャと呼ばれる考え方があります。 そのアーキテクチャをいろいろな人が提唱していて、いろいろな捉え方があります。 MVCもアーキテクチャのひとつと言えると思いますが、他にもDDDやIDDD、PofEAA、クリーンアーキテクチャ等あります。 MVCにこれらのアーキテクチャをプラスアルファしていく考え方や、そもそも違うアーキテクチャであると捉えてシステムを作っていくというようにどのようなものであるとひとことではなかなか言い表せません。 余談ですが、MVCにはMVCとMVC2があるという話も昔盛んに言われたりなどしています。 たとえば今検索してみても、下記のような記事がヒットしました。 * Javaの道:基本事項(1.開発モデルMVC2) * MVCをWebに適用した「MVC2」 | Java好き * MVC と MVC2 について改めて考えてみる - スタジオ・アルカナ技術ブログ ### DDDやIDDDやPofEAA `DDD`では`サービス`と言うと、`ドメインサービス`のことを指すのが一般的な気がします。 では、`ドメインサービス`というのは何かという話になりますが、まず`DDD`の`ドメイン層`の話を説明しないといけなくなりそうなので、本質問の回答から離れてしまいそうですので、あまり多くは書けません。 ただ、言えることは、私が経験したプロジェクトでは、やはりこの`ドメインサービス`は `動詞 + Service` という命名規則になっており、内部には`ただ1つのメソッド`を持っていました。(ここまで`ただ1つのメソッド`と書いてきましたが、あくまでこれは私が経験したことであり、必ずしも`ただ1つのメソッド`でなければならないということではないと思います) ちなみに`DDD`では「動詞 + UseCase」というクラス名のクラスの中に`ただひとつのメソッド`を持つというものも経験しました。これは`ユースケース層`の話しですので、クラス名を動詞にしたいからという理由で何でもかんでも「動詞 + Service」という命名規則にはならないようです。 加えてDDDにはIDDDというものもあり、 ドメイン駆動設計: IDDDに登場するサンプルコードのModule構成をまとめてみた にあるとおり、 にサンプルコードがあるので、こちらでどのようにサービスと呼ばれるものがあるのか見てみるのも良いかもしれません。これはDDDの例ですが、これをMVCの中に取り込んで使っていくという考え方もあるはずです。 DDDの話の流れから、関連(?)するものとしては、PofEAAのサービスを参考にアーキテクチャを構築している場合もありますので、その場合はPofEAAのサービスについてプロジェクト参加者は話しているかもしれません。参考資料としては、次のような記事がありました。混乱しがちなサービスという概念について ### Rails `Rails`(これも`MVC`のフレームワークとされています)などで`サービス`と呼ばれるものは、`Rails`でいう`Model`(`Active Record`のことです)内に書く量が多くなったときに、`CreateHogeServie`というようなクラス名でModel内の処理から肥大した部分を`サービス`として切り出す場面が多いです。(リファクタリング的な文脈やモデルが肥大化しないように、そもそもそのように作るという設計の文脈で語られる事が多いですが、そもそも書く場所が変わっただけで、モデルが肥大していることと本質的には変わらないのではないかと私は考えています) またこれだけだと、`Rails`の例が足りないかもしれないので、有名な のコード内にもサービスと名のつくクラスがあるので、そちらも参考になるかもしれません(実際に私がこのコードを読んだのは少しなので、ここで回答できるほど、どのような場面でサービスとなっているか説明すると間違えてしまうかもしれないので、あまり多くは書けません。おそらくモデルの中が肥大化したからという理由だけではなさそうな気がしますが...) compare_service.rb や cohorts_service.rb なんかは `execute` メソッドを持っていますね。 ban_service.rb なんかは持っていないようにみえますが、親クラスが banned_user_base_service.rb なので、`execute` メソッドを持っているのではないでしょうか。 またdev.toのServiceクラスについてDDDとPofEAAを読んで考察してみたでは、DDDやPofEAAをからめてRailsの例が記述されているので、参考になるかもしれません。 次のような記事もありました。俺が悪かった。素直に間違いを認めるから、もうサービスクラスとか作るのは止めてくれ ### Spring `Java`の`Springフレームワーク`は`MVC`のフレームワークですが、@Serviceというアトリビュートを持っており、Springフレームワークを使っている文脈でサービスと言われると、このアトリビュートやそれを用いたクラスを指すでしょう。(が、`Java`のプロジェクトは`DDD`で作られていることも多いので、文脈によっては前述のとおりドメインサービスのことを話者間では話していることもあると思います) さらにややこしい話として、 @Component、@Service、@Repository、@Controllerの違いについて - Qiita に下記とあるように > > Springアノテーション「@Component、@Service、@Repository、@Controller」について、動きとして基本的同じであり > > > 「コンポーネント」「サービス」「リポジトリ」「コントローラ」は**Springフレームワークの**`アトリビュート的`には基本的に同じであり、「コンポーネント」「サービス」「リポジトリ」「コントローラ」はどのように違い・どのように使い分けるのかという文脈でSpringフレームワーク話者間では、語られたりまします。 (ちなみに私は、Springを使うときは、サービスを他の文脈でのユースケース層の代わりとして使っていますが、私個人のやり方だけかもしれませんし、他に同じやり方をしている人がいるかもしれません) ### CakePHP 私はCakePHPの経験はありませんが、ご質問の参考にされている回答のひとつに > > 質問に単純に回答するならばCakePHPではComponentがService層に該当します。 > > > 自分も同じ疑問に当たった際にCakePHPコア開発者のJoseが書いた下記のエントリに行き当たりました。 > > > や > > MVCモデルとサービス層を明確に分ける定義は無いですが、CakePHPにおいてはComponentとして実装するのがすっきりします。 > > > とありますので、もしかしたら私の知っている流派とはすこし違うもののように感じます(前述した通り、Springフレームワークでは、コンポーネントとサービスは基本的に同じものですが、違うものと捉えることもできます。というか捉えたほうが、コードを読んだり書いたりしやすいはずです。)(CakePHPの経験がないので、私の理解が間違っている可能性もあります)。 このように文脈やフレームワークによって捉え方が変わります。 ### アンドロイド もっと違う話(もはやMVCやアーキテクチャの文脈ではないかも)をするとアンドロイドにはサービスというのがあり、アンドロイドアプリをMVCで作っている場面で、サービスという単語を聞いたら、DDDのサービスの話かなと思いきや、アンドロイドのこのサービスの話しをしているなんて場面もあり、違う用法で使われている例を上げだすときりがありません。 ユーティリティ ======= ざくっりとした説明 `ユーティリティ`はあまり積極的に使われている印象はなく(?)、プロジェクト全体で、何か便利に共通して使われる関数や定数を収納しておく場所として使われていることが多いような気がします。ユーティリティが`Utility`というクラス名になっていることもあれば、`Utility`という名前の単なるフォルダになっていることもあり様々です。関連する基本的なプロジェクトをインポートする形で使い、この基本的なプロジェクトのことを俗称としてユーティリティという場合もあります。 ただ、これもでは何が共通で便利に使われる関数等にあたるのかという話になりますが、現場によります。 アーキテクチャ的な観点 アーキテクチャ的な観点では下記の記事がありました。 持続可能な開発を目指す ~ ドメイン・ユースケース駆動(クリーンアーキテクチャ) + 単方向に制限した処理 + FRP > > utility ― どの層でも使うようなライブラリなど。例:FRPのライブラリ > > > レイヤードアーキテクチャ(もしくはレイヤードアーキテクチャのような別のアーキテクチャ)という考えがありますので、そのどの層(レイヤー)でも使うようなものという説明になっています。 ざっくり言うと、前述したとおり「プロジェクト全体で、何か便利に共通して使われる」モノです。 まとめ === DDD,PofEAA,Springそれぞれでサービスという言葉の意味は違っているので、一つ一つを自分なりの理解で深めていくことをおすすめします。 そもそもMVCはModelとViewとControllerに分けましょうという話しなので、サービスやらユーティリティについては、別の概念だと私は考えています。MVCという考え方にDDDなどの考え方などを乗せていくイメージです。 本質問もどれだけ調べても、ネットの記事によって言ってることが違うということでこのご質問になったのではないかと推測し、少しでも役に立つのではないかと思い回答しました。 結局ここまで書いて、ご質問者さんが参考にしている回答に > > 「サービス」は用語として混乱しているので、目的から理解しよう > > > とあるので、同じような意味合いを私も記載しただけになったかもしれません。 私の印象としては、話者感が違う意味で捉えていると会話のはじめのうちは何となく話が合っていた気がするのに途中から会話が混乱の渦に巻き込まれていく感じがします。一方、比較的コンテキスト(話者感の前提条件・文脈)があっていると、会話がスムーズにいく場面が多いような気もします。