これに従って実装すれば、見えるものがあるんじゃない?

詳しくいきましょうか。実装例がどういうものか?

右下の図がすごく大事という話をしましたよね。これをもっと細かくしましょう。そういう図が実はクリーンアーキテクチャのWebと書籍にもありました。Robert C. Martin、この人はかなり有名な人で、あのSOLID原則を定義した人です。Robert C. Martinがこのクリーンアーキテクチャというのを発表して、iOSクリーンアーキ……iOSのほうでかな。発表して(※のちに勘違いだったとYouTube説明欄で訂正)、その後書籍を書きました。それが『Clean Architecture 達人に学ぶソフトウェアの構造と設計』です。

ここにある図ですね。これをよく見ると、この図、緑と赤ありますよね。それぞれがこれに対応しています。左上がControllerです。右上のあのカラフルな図は……Controller左側じゃないですか。Presenterが左下にあって、右上の図だと上にあります。

(スライドを指し)ControllerとController、PresenterとPresenter。赤い文字でInterfaceのIがここにあるよね。何が言いたいかというと、これ上下逆、逆さまになっているんですけど、もちろん用語も違うんですけど、実は同じなんです。

この図はその右上の図よりもさらにわかりやすく細かく区分けしたものです。

というわけで、クリーンアーキテクチャ、もちろんRobert C. Martinが言っているのはわかっているんですよ。クリーンアーキテクチャ自体を特定の形じゃないとは言っています。でも、彼自身こうやってサンプルを出してくれているんですよ。じゃあこれに従って実装すれば見えるものがあるんじゃない?

SOLID原則の話を突き詰めるとクリーンアーキテクチャになる

というわけで、じゃあ実装してみましょう。みなさんのわかりやすい感じにちょっと落としますね。いろいろなビジネスロジックがありますが、片や誰か知っているけど誰も知らないみたいな話をしちゃうと難しいじゃないですか。カートの話をしてもAmazonを使ったことがない人がいるかもしれない。なので、今回はユーザー作成機能。これなら言えるかな。

これでコードを確認して処理の流れを確認しましょう。順番に、まずはコードを確認していきます。それぞれのコードがどういったものか。そして、そのあと、処理の流れを確認していきます。1回コードをザーッと洗って、もう1回コードを当て込みながら順番を見ていきます。

まずコードの確認です。具体的にどういうコードを書くか? まずはどこからスタートするか? この左上のController、こういう図ですね。

(コメントで)「この図めっちゃわかりやすい」ですね。まさにそうそう。「SOLIDの原則知りませんでした」、SOLID原則はぜひとも調べてみて。

クリーンアーキテクチャの本を読むとわかるんですけど、本は22章ぐらいまでは「もう知っているよ、こんなこと」っていう話をしています。Robert C. MartinのSOLID原則にたどり着くまでの話をしていて、23章ぐらいからクリーンアーキテクチャの話、この図になってくるんですね。SOLID原則の話を突き詰めるとこのクリーンアーキテクチャの図になるよって話しています。だからクリーンアーキテクチャを理解するのにSOLID原則があれば、彼がこういうふうにこんなにクラス分けしている理由がわかるはずなんです。ぜひとも調べてみてください。

入力を変換して送るのがController

じゃあいきましょう。こういうものです。なんとなくオブジェクト指向プログラミングやったことがある人だったら読めるかなと思うんですけど、public class UserController。細かいところはどうでもいいんです。何をやっているかというと、アプリケーションが要求するデータに入力を変換する。入力を変換、Controllerなんですよ。

僕はいつもいろいろなところで言っていて、僕の「なるセミ」にある自分で作った動画にも書いてあるんですけど、Controllerの役目って僕の認識では司令官とかじゃないんですよ。

ゲームのコントローラは何をやっているかというと、ボタンを押したら、そのボタンを押した事実をそのまま送るんじゃなくて、ゲーム機にわかる信号に変換して送ります。Bボタンを押した事実は送れないですよね。Bボタンを押したことを電気信号に変えてコンピュータに送っているんです。コントローラがやっていることって入力の変換なんですね。コンピュータがわかるかたち、ゲーム機がわかるかたちに。

なので、このController、UserControllerがやっていることは、よくよく見るとこのcreateUser、入力ね、nameとroleId、String型をアプリケーション、addUseCaseっていうこのアプリケーション、ゲーム機が欲しがっているデータ、inputDataというのに変換しているんです。変換してそれを渡している。だからこれがController。

これSpring Bootじゃなくて、僕のサンプルコードは一応Play Frameworkです。Spring BootはちょっとMVCに慣れている人からすると、ちょっと取っつきづらかったので、Play Frameworkで書いています。

次、ここです。Input Data、入力データです。こういうやつね。右上に<DS>って書いてあるじゃないですか。DSって何かというと、Data Structure。つまりデータ構造体。

どういうものかというと、さっきのUserAddInputData、ユーザーの入力データ。そのままこうやってもう入力データをひとまとめにして、Input Dataとして定義しますってだけです。DTOとほぼ一緒ですよね。

ポートとアプリケーションロジック

次はInput Boundary。Input Portと呼ばれたものです。ポート・アダプターで言うところのポートですね。要するにポート。プラグを差すところです。

具体的にどういうものか? <I>がついているので、ただのインターフェースです。ダック・タイピングの言語だとインターフェースがないんですけど、要するにメソッドの実装がない、C++とかでいう仮想……Abstractクラスですよね。インターフェースを強制する。どういった引数、どういった入力データが必要なのかを定義する。

そして、次にいきましょう、このUse Case Interactor。これはどういったものかというと、実際のアプリケーションロジック、ビジネスロジック。アプリケーションロジックですね。

見ていくとわかるんですけど、ビジネス上のUserオブジェクトを作って、それを保存して……userRepository、リポジトリパターン。これはちょっとあとで説明します。保存する。saveだけ見て、保存します。そして、結果、OutputDataをPresenterに対してouput、出力する。

やっていることは入力したデータを使って、さっき言ったアプリケーション、すでにある世界のドメインのビジネスの世界でオブジェクトを作って、それを操作して保存する。それまでUserを作って保存できなかったから、保存するアプリケーションです。それを出力データとして作ってPresenterに引き渡します。

Data Access Interface

次いきましょう。Presenterとかの話にいきます。今のここ、右下、Data Access Interface、これどういったものかというと、<I>って書いてありますよね。インターフェース。やっぱりインターフェースです。さっきのリポジトリとかいい例ですね。もちろんほかにもあります。APIのラッパーとかあるので、こういったものをデータにアクセスするためのインターフェースを作りましょうって言っています。

アプリケーションがデータを保存したりデータを復元したりするときのインターフェースですね。これを見るとユーザーリポジトリがやっていることは、データを保存したりデータを削除したり、そしてデータ全検索、あとユーザーIDで検索したり……ということをするインターフェースです。仮想メソッドで、これが何かするわけではなく、これを実装したクラスが実際にやります。

クリーンアーキテクチャでいうイメージ、ここですね、Gateways。中心から外に対してデータベースとかにアクセスするためのインターフェース。

じゃあこの下のData Access、何かというと、ちょっとこれ見づらいんですけど、ここに白抜きの矢印が書いてあるんですよ。今のData Accessインターフェースを実装したもので、実際にOracleとかMySQLとかに接続するものです。今回でいうと、これはO/Rマッパー使っていますね。O/Rマッパーを使ってデータを保存して、データベースにデータを保存しにいっています。

いいことは、インターフェースなので、例えばさっきも言った「Oracleだったけど、保守費用高いからMySQLにしたいな」ってときに、このオブジェクトを入れ替えればいい。

今回で言うと、あれですね、O/Rマッパーを使っているからO/Rマッパーの設定でうまくいきそうですけどね。生のJavaで書いてたりするときとか、あとO/Rマッパー自体を変えたいときに、このオブジェクトは残しておいて新たなものを作って差し替えができますというやつですね。

あとは、わかりやすいのがモックですね。とりあえずテストで動かすための仕組みをやるときですね。

ビジネスのルールが書かれたオブジェクト

Entities。どういったものかというと、例えばUserオブジェクト。ビジネスの例えばユーザー、名前変更ができますよね。changeNameとかそういうメソッドがあるビジネスのロジックのあるオブジェクト。

ただ、本当だったらもっと複雑です。今回Userというすごく簡潔なものに、簡単なものにしたので、これだけロジックがぜんぜんないんですけど、ここに例えば注文するロジック、注文の実際の具体的な処理かな。そういうのが入ってきますね。

《スライド:https://speakerdeck.com/nrslib/clean-architecture-with-java?slide=154》

なかなか例が難しいですね。そういったビジネスの表現したもの、トラックとか燃費とか、そういうオブジェクトのイメージですね。

ユーザー名、これはわかりやすいですね。これを見るとユーザー名の仕様がわかりますよね。ユーザー名が3文字より小さかったり10文字よりも大きかったときに例外を吐く。本当だったらもっと違う例外だろうけど、まあ例外吐くので、これでユーザー名の仕様がわかりますよね。「ユーザー名は3文字以上10文字以下」。こういうビジネスのルールが書かれたオブジェクト。

データモデルとは違います。ここ重要ね。データを保存するモデルは別で作ったりします。

Output Data

次にいきましょう。Output Data。これはどういったものかというと、これも<DS>って書いてありますよね。なので、UserAddOutputData。

やっていることは出力……今Userを保存してできあがったものを結果として、生成したユーザーのIDを返すために出力としてオブジェクト、Inputのときと同じようにDTOを定義しています。Data Structure。データ構造体。

そしてこれをOutput Boundary。これもまたインターフェースなんです。今の出力データを渡すときのインターフェース。そうそう、今Twitterのほうで「Interfaceで責任を分けてあげることで交換が容易になる」。まさにそのとおりです。

(コメントで)「注文するのはユースケースで、カートに100個までしか入らない」。あっ、それはドメインルールですね。そうそう。カートを実際作ったりするのはアプリケーションなんですけど、そこに対して入れるときのチェックとかはドメインオブジェクト側でやる感じです。

今、Presenter、インターフェースを作って、この出力……ここに対してoutputDataを渡します。これを実装したPresenter、どういったものかというと、これを画面に表示する。画面はなんでもいいですよ。コンソールでもいいし、HTTPでもいいから、とにかく画面に出力するということをやります。

そして、それを使ってView Model。またここで<DS>なんですよ。実際に出力するんじゃなくて、ここでやるのは出力のために変換をするんですね。今のView Model、これですね、Data Structure、ここに詰め込む作業をします。その詰め込んだView Modelを……Data Structureです。本当にこれも。これを実際のViewに引き渡すということをやっていきます。ここでやっとViewで表示される。

(Twitterで)「“データモデルとドメインモデルは違う”(復唱)」。いいですね、それ大事ですよ。(コメントで)「Output BoundaryとPresenterは試しに作ったけど、なんかうまく扱えなかったな」。その話はこのあとするので、楽しみにしてください。