クリーンアーキテクチャはなぜフロントエンドに合わないのか

@Panda_Program

はじめに

昨年末にこんなツイートをしたら、ちょっとバズってしまいました。

ツイートの引用 https://x.com/Panda_Program/status/1864333831886786971

色々コメントを頂くことで考えを深めてブログを書きますと言っていて、まだ着手していなかったのでざっと書くことにします。ただ、今日はクリーンアーキテクチャが対象です。

簡単に自己紹介をすると、私は現職でフルスタックエンジニアをしています。また、「バックエンドのためのフロントエンド入門」 というテーマで登壇をしたり、自分のエンジニア人生を変えた書籍リストにクリーンアーキテクチャを挙げており、TypeScriptでクリーンアーキテクチャを実践する という記事では Web からでも CLI からでも動かせるアプリケーションを作ったことを記事にしています。

このためバックエンドの考え方とフロントエンドの考え方はある程度理解していると思います。

結論

さて、結論から書くと、クリーンアーキテクチャとフロントエンドの関係は以下です。

  • クリーンアーキテクチャは、ソフトウェアの中で変わりやすく重要でない部分と変わりにくい重要な部分を、オブジェクト指向プログラミングの機能を使ってオニオン型のレイヤーで分けようというアプローチ
  • クリーンアーキテクチャでは、フロントエンド(UI)やフレームワーク、Web、CLIといった外部と、ビジネスルールを表現する内部を分離、独立させることが重要と説いている
  • モダンフロントエンドは、HTML/CSS/JS をセットにした小さいコンポーネントを組み合わせたUI管理のためのフレームワークを使って、単方向なデータフローでスケーラブルなアプリケーションを作るというアプローチ

両者を比較するだけでも、UI構築を主戦場とするフロントエンドにクリーンアーキテクチャを持ち込むという発想自体がナンセンスであることがわかります。

クリーンアークテクチャとUIライブラリReactの定義を比較する

さらに、React 公式ドキュメントは React 自身を以下のように定義しています。

The library for web and native user interfaces

ウェブとネイティブのユーザーインターフェース(UI)のためのライブラリ

そしてこちらはボブおじさんの記事 The Clean Architecture から引用です。

Independent of UI. The UI can change easily, without changing the rest of the system. A Web UI could be replaced with a console UI, for example, without changing the business rules.

UIから独立していること。UIはシステムの他の部分を変更することなく容易に変更可能です。例えば、ビジネスルールを変更することなく、Web UIをコンソールUIに置き換えることができます。

両者を合わせると、ボブおじさんがいうクリーンアーキテクチャは、ウェブでもネイティブアプリでもそれ以外でも、UIに左右されないビジネスルールをUIやフレームワークから独立させることが主眼です。繰り返しになりますが、フロントエンドにクリーンアーキテクチャを持ち込むとは、そもそも無理筋な発想なのです。

しかし、ビジネスルールがフロントエンドにもあるのではないか、もしそうであればクリーンアーキテクチャを適用することは理にかなっているとも考えられると思います。そこで、フロントエンドにビジネスルールがあるかを次に検討します。

なお、ビジネスルール、ビジネスロジックとはソフトウェア上で業務ルールを表現し、データの整合性を保つためのロジックとここでは定義します。

ビジネスルールは React などのUIフレームワーク側にはない

クリーンアーキテクチャの記事の中では View も Presenter も詳細(details)とされており、また書籍では Humble Object として紹介され、守るべきビジネスルールとは区別されます。

ではフロントエンドにビジネスルールはないと言えるのでしょうか。これこそ本質に迫る問いであり、もしフロントエンドにビジネスルールがあれば、それは UI やデータベースから独立させるべきものとなり、クリーンアーキテクチャを適用することも考えられると思います。

まずフロントエンドの役割を見ると、以下の3つに分けられます。

  • 状態管理
  • イベントハンドラ
  • プレゼンテーションロジック

一つずつ見ていきましょう。

状態管理

状態管理をするのにも React 周りで変遷があります。React公式が提供している状態管理の方法以外にも、各種ライブラリが独自の状態管理の方法を提供しています。

  • クラスコンポーネントの setState
  • Redux
  • useState
  • XState
  • Recoil / Jotai / Zustand etc.

最近 Recoil がアーカイブされ、他の状態管理ライブラリに乗り換えたという話を聞きます。このような変更の影響を受けずに独立させたい、何なら Vue でも Svelte でも他のフレームワーク上でも同じように使いまわしたいロジックがあれば、それはビジネスルールである可能性があります。

ただし、UIライブラリは状態管理をパーツの表示制御などUIのために使われることが一般的であり、その場合はビジネスルールではなく単にUI管理のためのロジックであると思います。

イベントハンドラの中のロジックも同様だと思われます。イベントはユーザーがブラウザ上やスマホの画面上で起こす、クリックやドラッグアンドドロップ、タップやスワイプといったあくまでも機械的な操作イベントです。これらのイベントに応じて発火するロジックは、業務ルールとそれに付随するイベント(ドメインイベント)とそのリスナーのロジックとは別物として考えると良いだろうと思います。

プレゼンテーションロジック

React 以外の各種UIライブラリでも同様に使いまわせるロジックがビジネスルールの可能性があると上記で書きました。しかし、そのほとんどがプレゼンテーションロジックに分類されると思います。

プレゼンテーションロジックは以下のようなものです。

  • 相対的な日時での表示(ex. 1ヶ月前)
  • 文字の省略表示(ex. 80文字以上なら … で省略する)
  • フォームのバリデーションエラーの表示
  • ログインしていない場合は記事の本文は途中までしか読めない(状態管理+表示) etc.

他にもバリデーションのロジックは一見ビジネスルールのように思われます。しかし、フロントエンドでフォームのバリデーションをするのはエラーメッセージを表示したいというUI管理に直結した要求があるからです。

フロントエンドでバリデーションを書いた上でAPIサーバーのバックエンドでも、同じバリデーションを書くことがある理由は目的が異なるからです。前者はUI管理のため、後者はデータの整合性を保つためです。

また、現代ではフロントとバックエンドは密結合ですが、Web APIとは本来どのようなクライアントからでもコールされる可能性があります。ここまで考えると「フロントエンドでバリデーションをしているから、バックエンドでは不要」というアイデアは簡単に捨てられるでしょう。

データフェッチの方法

データフェッチの方法にも触れると、React とその周辺ライブラリだけでも以下のように変遷しています。

  • componentDidMount
  • useEffect
  • SWR / React Router
  • Relay / Apollo Client
  • Server Component

Next.js でもデータフェッチの方法はダイナミックに変わってきました。

これらのデータ取得の変更の影響を最小限にするために、データフェッチのためのレイヤーを設けることが一般的です。fetcher にはJSONからコンポーネントで使いたいデータを抜き出すデータマッピングの役割を持たせることもあります。

しかし、それは単なる1レイヤーであり、データマッピングのロジックもデータフェッチや例外に関するロジックもビジネスロジックではないことは明らかです。

よって、これまで見てきた「状態管理」「イベントハンドラ」「プレゼンテーションロジック」「データフェッチ」のどこにもビジネスルールはないと思われます。

ただし、ビジネスルールがフロントに存在するケースはあるはず

ただ、フロントエンドにはビジネスルールが全くないとまで言えないのではないかとも思います。

例えば、Supabase では API のスキーマがそのままデータベースのスキーマになっています。例えば、あるエンドポイントに POST リクエストで JSON を送ると、その JSON はそのままテーブルに1レコードとして挿入されます。このように API とデータベースを近づけたサービスでは、ビジネスルールもフロント側に存在するのでしょう。

なお、ブラウザゲームやデザインツールのCanva、Webサイト構築ツールのStudioような、フロントエンドこそがビジネスの競争力だというソフトウェアであれば、上記の議論は当てはまらないだろうとも思います。

この項の見出しは「ビジネスルールは React などのUIフレームワーク側にはない」というものですが、素の JS/TS にはそれが存在する可能性があります。ただ、筆者の経験が乏しくこの辺りは詳しく語れません。この点は今後の課題です。

クリーンアーキテクチャとフロントエンドの時代背景

さて、クリーンアーキテクチャが提唱された時代とフロントエンドの歴史、当時の時代背景に少し触れてみましょう。

私は歴史が好きです。旅行では歴史的な史跡や歴史博物館を回ることが趣味です。歴史を知ることは現代に対する多角的な視点を手にいれ、今をよりよく理解することに繋がるからです。

まず、クリーンアーキテクチャがボブおじさんのブログで発表されたのは2012年です。当時、自分はまだソフトウェアエンジニアではなかったので時代を測るしかないのですが、この時は Rails をはじめとしたMVCフレームワーク隆盛期です。

2010年にRailsのバージョン3が公開されたり、2011年にCakePHPの2.0が公開されたりと、Railsに影響された様々なMVCフレームワークが生まれ、育ち始めた時期です。この当時はどのスタートアップも Rails Way に乗ってスピード感のある開発をしていたのだろうと思います。

MVCフレームワークの強い影響はフロントエンドにも及びます。当時のフロントエンドの状況を見ると、Backbone.js, Angular.js, Ember.js などのMV*フームワークが登場したとのことです(参照: React研修(2024))。

スライドの引用

MV*フレームワークとは、バックエンドのMVCフレームワークに触発されてフロントでMVC, MVP, MVVMといった構造を持ち込むことで、フロントエンドに秩序をもたらそうというものです。しかし、現代では非MV*フレームワークであるReactが主流であるため、この取り組みは時代から選ばれなかったことがわかります。

バックエンドにMVCフレームワークを取り入れたスタートアップはビジネスが拡大し、Fat Controller や Fat Model を生み出すのはまだ先の話です。このような時代背景の中で、ビジネスルールをフレームワークから独立させよというボブおじさんの主張には先見の明があったと言えるでしょう。

最後に

ソフトウェアエンジニア3年目あたりでクリーンアーキテクチャ本を読んだ時と、その後頻繁なプログラミング言語やフレームワーク、ライブラリのバージョンアップを間近で見ている今だと、重要なビジネスロジックを外部の変更から守ることの重要性に対する実感は全く異なります。そして10年以上フロントエンドで最前線を張っている弊社のテックリード曰く、「フロントエンドは全部置き換えられるから、ちゃんと作ったとしても結局は書き捨てに近い(だから適当に作っていいということではないけど、後生大事に守るという態度も違う)」とのことでした。

バックエンドで書かれたコードは10年前のコードであっても基礎に近いほど当時と同じコードで動いています。しかし、フロントエンドで10年前に書かれたコードが今もあるでしょうか。フロントエンドはJavaScript/TypeScriptの進化、エコシステムの発展、デザイン刷新プロジェクトと、バックエンドよりも変更に対する力が強く、カジュアルに変更されます。ビジネスルールは変わりにくいが、フロントエンドは変わりやすいのです。

さて、先週ある方から、2/28開催の勉強会でt-wadaさんがこのテーマで発表をされると聞きました。年末から放置していた自分の宿題を片付けることと、記事を先に出してから和田さんの発表を見ることで答え合わせをしたいと思って、臆見を記すことにしました(念のためですが、ビーフとかでは全くありません)。

勉強会の空き枠はまだありますので、ぜひオンラインでも参加してみてください。

Happy Coding 🎉

パンダのイラスト
パンダ

記事が面白いと思ったらツイートやはてブをお願いします!皆さんの感想が執筆のモチベーションになります。最後まで読んでくれてありがとう。

  • Share on Hatena
  • Share on Twitter
  • Share on Line
  • Copy to clipboard