2019年のwebAPIの設計を取り巻く問題と技術シリーズ そのに 「ビジネスロジック」は誰が持つべき?

前回の記事の続きです。

前回は、「時代が変わるとサーバーアプリケーションの役割も変わるよね。そうすると必要な要素技術も変わっていくよね」という話でした。今回は、じゃあ「サーバーアプリケーションがJSON喋るマンになって、クライアントアプリケーションとの協働でユーザー体験が実現されるようになってきた今、"ビジネスロジック"はだれが持つべきなの?」って話をしたいと思います。

基本的にはサーバーでもってあげたほうが楽

さて、サーバーサイドでなんでもやる牧歌的な時代は過ぎ去り、クライアントサイドとサーバーサイドがコラボレーションしてひとつの体験を提供するようになった昨今、「そのアプリケーションの体験を成り立たせるための"ロジック"をどっちに書くのか」という問題が立ち上がってきます。わたしの私見ですが、これはなるべくならサーバーサイドで請け負ってあげるのがよいのではないでしょうか。その理由は、クライアントサイドにはクライアントサイド特有の複雑な問題を抱えているため、そのほかの問題はサーバーサイドで抱えてあげたほうが全体の複雑さが減るからです。

HTTPというのは基本的にステートレスなプロトコルです。そのため、基本的にはサーバーサイドの状態は1リクエストごとに閉じています。リクエストを受け付ける時にはまっさらな状態で、レスポンスを返すまでには様々な状態をもちそれらに対して様々な計算をして、レスポンスをかえします。このとき状態は一度破棄され(あるいはRDBなどの外部に書き出され)、次のリクエストのときにはまたまっさらの状態でそのリクエストを処理し始めます。

一方、クライアントサイドでは、ブラウザSPAアプリならばブラウザをリロードするか別のサービスに遷移するまで、メモリ上に状態を持ってしまいます。とうぜん、これはネイティブアプリでも事情は同じです。やったことのあるひとにはわかると思いますが、この状態の管理は、それだけでけっこうめんどくさいものです。

また、その「状態」から複雑な画面を構築しなければいけないというめんどくさい問題も、クライアントサイドは抱えています。画面作るのほんとに面倒で、そこにユーザーインタラクションがからむともっともっと面倒です。そういうめんどくさい問題を抱えているのに、さらに複雑なビジネスロジックまで押し付けられるのはあまりに大変ですので、困難を分割するためにも、サーバが出来る限り複雑さを引き受けてあげるのがよいのではないかと思います。

また、サーバーサイドに複雑なロジックを持っておくことで、複数のプラットフォームでのアプリ展開がやりやすくなる、という面もあります。たとえばiOSアプリもAndroidアプリもwebアプリも作る、というような場合に、クライアントサイドにビジネスロジックを持っている場合、それぞれのアプリで毎度実装する必要が出て来ますが、サーバーサイドでロジックをもってあげればサーバーサイド一回の実装ですみます。

また、クライアントサイドで一生懸命複雑なことをやったとしても、サーバーにとってリクエストは「だれから送られてきたかわからないもの」なので、結局サーバーサイドでデータの不整合が起こらないように検証はしなくてはいけません。そういった検証はまさにビジネスロジックの一部であり、クライアントサイドでビジネスロジックを持った場合、サーバーサイドでも重複したロジックを書かなければならない、というようなことは容易に起こり得ます。

ファーストパーティに閉じたサービスとサードパーティに開かれたプラットフォームの違い

しかし、これらの状況は、そのサービスが、ファーストパーティに閉じたサービスなのか、それともサードパーティに対して開かれたプラットフォームを目指すのかによって、事情が変わってきます。

ファーストパーティに閉じたサービスの場合、APIは「このアプリ専用」に作ることができます。いわゆる「顧客-供給者の関係」ですね。アプリ側の都合に合わせてAPIを作ることで、「複雑なビジネスロジック」をサーバー側が引き受けることになります。

一方で、サードパーティに開かれたプラットフォームの場合、不特定多数のクライアントに対して応答する必要があります。そのときに、サーバーサイドは、あるクライアントが解こうとしている問題に特化したAPIを提供するわけにはいきません。そんなことをしたら、クライアントの数だけAPIの種類が増えてしまいます。そのため、サードパーティに開かれたプラットフォームでは、サーバーサイド側になるべくロジックをもってあげることが難しくなります。プラットフォーム側の「ビジネスロジック」は薄くなる傾向があるでしょう。

しかしこれは、考えてみると当然のことです。というのも、プラットフォームというのは、「ぼくたちのデータや資源を使って、きみたちの問題を解決してね」というサービスなわけで、そうなってくるとどうしても問題を解く主体は、プラットフォームではなくてそのユーザーとなるでしょう。つまり、ユーザーは、ユーザーごとに異なる問題と向き合うことになるわけです。そのときに「ドメインロジック」がクライアント側にもたれるようになることは、ある意味当然となります。もちろん、このときプラットフォームにとっての「クライアント」が、webブラウザであるとは限りません。プラットフォームのユーザの選択によっては、webブラウザだけで完結するかもしれませんが、あるいはプラットフォーム利用者が自前でサーバーを立てて、そのサーバーサイドアプリケーションがプラットフォームにとってのクライアントとなるかもしれません。しかし、プラットフォーマーが持つサーバーアプリケーションは、特定の問題のための「ビジネスロジック」を持たない、ということには変わりがないでしょう。

まとめ

というわけで、まとめると、

  • 基本的には複雑なビジネスロジックはサーバーにもってあげるのが筋がよいと思う
  • 一方で、サードパーティに広く開かれたプラットフォームの場合はクライアント側にビジネスロジックを持ってもらい、サーバーはファンダメンタルな操作を提供するほうがよい

という感じになります。

前者の場合、最近だとリソース指向なAPI(いわゆるRESTfulなAPI)よりも「ユースケース指向」なAPIが増えてきていると感じます。ユースケースと1:1になるようなエンドポイントが生えてるようなAPIですね。

一方で後者の場合はユースケースはクライアントに依るので、mutationに関してはリソース指向のAPIがマッチしそうです。一方、リソースの取得についてはクライアントによってほしいデータが違うという問題があり、そのあたりにはGraphQLの恩恵がききやすいのではないか、という理解をわたしはしています。

次回書く気になれば、次回は

  • サーバーサイドに寄せられた、複雑なロジックやミドルウェアとのやり取りと向き合うための技術
  • クライアントサイドに残された「状態管理」と「複雑な画面」と「ユーザーインタラクション」と向き合うための技術

あたりを書けたらいいなと思います。が、もしかしたらtwitterでバーっと書いて満足してしまうかも……。