#1で発表した資料になります。slideこんにちは。それでは早速はじめさせていただきます。~」というタイトルでお話しさせていただきます。マサカリ投げ放題みたいな内容なんですけど、皆さんくれぐれもお手柔らかにお願いします。本題に入る前にふたつ質問させてくださいあまりに有名な図ですが、この図を見たことあるかた良かったら挙手していただけますか?じゃぁもう一つ、この書籍読破したよって方挙手していただけますか?読んでいない方、掛け値なしの名著だと思うのでまだ読まれていない方は、今すぐ購入して読みましょう。個人的にはというわけで、本セッションの目指すところでが今日は、この場にいる皆さんが「クリーンアーキテクチャチョットデキル」という状態になっていただくことを目指します。自信ない方は今のうちにご退席ください。いうわけで、本セッションの概要ですがクリーンアーキテクチャについて、おもに次のふたつの事をお話しさせていただきます。ひとつは、クリーンアーキテクチャの誤解されがちな二つのことに対する解説。ひとつは、私がクリーンアーキテクチャについて、本当に重要だと考えているふたつの事について、お話しします。本題に入る前に、少し注意事項があります。今回お話しするのは、あくまで私の解釈です。極端に要約しているので、今日お話しすることがすべてではないことはご理解ください。書籍の記載とやや異なる説明もします。それでも私は著者が本当に言いたかったこと、クリーンアーキテクチャでもっとも大切なことは今日お話しする二点にあると考えています。異論・反論は大歓迎です。オンラインでご意見をいただいても良いですし、この後直接お話しさせていただくのも歓迎です。寝不足なので、その辺で死亡してなかったらですがwぜひ議論してさせていただけると嬉しいです。本題に入る前に最後にひとつ。簡単に自己紹介させてください。リコージャパンのソリューション開発部ってところで、主に金融機関向けの受託開発でアーキテクトをやってます。「持続可能なソフトウェア」というテーマで色々考えるのが最近の趣味です。今年の目標の一つは今日でクリアしましたので、あとはテストのハンズオン開催ができると良いなと思ってます。「誤解されがちな二つのこと」です。この図をご覧になったことのある方は多いんじゃないかと思います。実はこの図が良くできてい過ぎることが、大きな誤解を招く要因になっていると私は考えています。いうことでしょうか?ひとつは、この図は決してソフトウェアの関心をControllerやUseCase、Entityに分離しろという意味でもなくレイヤーをこの4つに分割しろという意味ではないということですそしてふたつ目は右下のこれです。これもPresentationを古典的なMVCのように設計しろという意味ではないですしデータや処理の流れを一方通行にしろと言っている訳でもありません。いう意味でしょうか?先の図で本当に大切なことは依存性は、外から中だけに向かっていなくてはいけない。いうたった一点にあります。Entitiesの状態が変わったことで、UIを受動的に変化させたいみたいな中から外を呼ばなければいけないときはどうすれば良いの?という疑問が、すぐに湧いてきますよね?右下の図は、内側の変化に応じて外側を呼び出したい場合に依存性は外から中に向けたまま、処理の流れとして中から外に戻すにはどうすればよいのか?を例示しているものです。そんなこと言っても、本当にあってるのか?って今皆さん思いましたよね?はい。そもそも著者は書籍の先頭でこう明言しています。日本語版では帯にも書かれていますよね。Adapterレイヤーの間だけで発生するわけがないですし・中央がEntitiesじゃなくちゃだめで、DDDするななんてそんな分けないですよね?書籍を読めば、ちゃんと先の図があくまで例示であると書かれています。クリーンアーキテクチャの発表前は、ヘキサゴナルアーキテクチャとかオニオンアーキテクチャが広く共有されていました。それらのアーキテクチャには類似の共通点があることも知られていました。クリーンアーキテクチャの解説には、それらの著名なアーキテクチャは、先ほどの図のように記述することで単一のアイディアに統合することを例示するために書かれた図なんです。クリーンアーキテクチャというのは、どんなソフトウェアにも適用可能な普遍的なアーキテクチャなんです。言うと、クリーンアーキテクチャを採用しないという選択肢は、基本的には「あくまで基本的には」無いといって差し支えありません。先の図のように実装することがクリーンアーキテクチャではないとしたらクリーンアーキテクチャについて何を抑えたらよいのでしょうか?私はつぎのふたつこそ、本質的に重要なことだと考えています。ひとつめは先ほども話しました。ソフトウェアは、より上位レベルの方針にのみ依存せよということふたつ目はひとつめを実現するために、依存性を制御の流れから分離してコントロールするということです。ことで、ここからは具体例を見ながら解説したいと思います。Worksを利用します。こちらにER図がありますが、これらのテーブルからプロダクト別の総売り上げをCSVに出力するコンソールアプリを作ります。アーキテクチャはもちろんクリーンアーキテクチャです。コードを見てみましょう!さて、先ほどのコードをモデル化したのがこちらになります。全体的にそう悪くないようにも見えるんですが、少なくとも二つは問題があります。ひとつは、ぱっと見から分かりますね。この部分でUsecaseからPresenterに依存関係ができてしまっています。依存関係はPresentaerからUsecaseである必要があります。逆になっちゃっていますね。いう訳で修正してみましょう。これでクリーンアーキテクチャになったでしょうか?先ほどのモデルで見直してみましょう。IPerenterが移動したことで依存方向がPresenterからUseCaseに移動しました。右下の図の通りになりましたね。処理の流れは一方通行で、でもすべての依存は外から中に向いています。厳密にいうとまだ中から外へ依存が向かっている箇所があります。Gatewayがデータベースに依存しています。GatewayはDatabaseに依存するという選択肢はもちろんありだと考えているのですがまぁ今回はせっかくなので、ここもDBからGatewayに依存するようにしてみたいと思います。GatewayはDBを呼び出さないといけないしDB操作にはSQLが必要ですよね?GatewayがDBに依存しないなんて実現可能なのでしょうか?勿論可能ですがちょっと意味が異なります。SQLを利用しないという意味ではないですしRDBというアーキテクチャに依存しないという意味ではないですシステム固有の永続かされたデータのスキーマに依存しないという意味ですこの部分を見てください。Repositoryの実装ではProductテーブルとSalesOrderDetailに対応するクラスを作ってDBアクセスし、Repositoryの中でProductSalesインスタンスを生成していましたよね?これらのクラスをよく見てみましょう。現在の実装は、リポジトリが完全にデータベースの文脈で記述されているのが見て取れます。結構な列数がありますよね。今回は、この4項目しか本来は必要ありません。テーブル構造にダイレクトに依存してしまうと、テーブル変更の影響をダイレクトに受けてしまいます。他の機能の影響で列が増えて、実際にはほぼ影響がないのに回帰テストをしないといけない。みたいな事に陥ったことはありませんか?そこでここの依存関係がDBからGatewayに向いていれば少なくともGatewayには影響がないことが担保できます。実際にはどうするか?制御の流れと依存方向は分離することで、コントロールできます。大切なのは文脈ですGatewayがDBへ依存しているというのはつまりGatewayのクラス設計がDBのスキーマに依存していることを指しているのですそうではなく、DBがGatewayの文脈で定義されていればよいという事になります。言え、これらのテーブルは別にこの機能のためだけにある訳じゃありませんよね。すれば良いのか?最も一般的な回答は、CQRSを使いましょうという事になります。CQRSとは、端的にいうとデータベース操作を更新と参照に責務を分離しなさいという方法論のことで今回はQueryに該当します。Gatewayの文脈に合わせたQuery用のオブジェクトをDB側に用意すればよいということになります。CQRSを完ぺきに適用しようというのは簡単じゃないです。既存のシステムに組み込むには多大な努力が必要になりますし、そこまでしてもケースによってはやりすぎになってしまいます。そこで、今回はDBのビューを使った手軽な方法を詳解したいと思います。サンプルコードを見てみましょう。結果的にこうなりました。DBにはEntityのPdoructSalesの文脈に適用したViewを作成して、Repositoryからはそれを参照します。することで、DBつまり外から中に依存するように文脈が書き換えられました。完ぺきにこのアーキテクチャを実現していますね!さて、あらためて整理しましょう。CQRSと類似したものにCQSという概念があります。CQRSはデータベースに対するパターンだったのに対してCQSはクラス、つまりコードにたいするパターンです。DBの文脈をGatewayで吸収する選択をする場合はCQSも検討してみると良いかもしれません。大切なのはやはり制御の流れから依存関係を分離することにあります。一般的に依存方向は制御の流れに引っ張られがちです。これらは分離してコントロールすることが可能です。そのためには二つの依存関係の間のコントラクト、つまり契約・仕様・お約束を文脈によって制御する必要があります。抽象的なコントラクトを導出することで、それぞれの具象概念はどちらも、抽象概念であるコントラクトに依存することになります。このコントラクトをどちらの文脈で定義するかによって具象概念間の依存関係を自由にコントロールすることができるようになります。「アーキテクチャのルールはどれも同じである」という真意が何となく伝わってきたでしょうか?そもそもソフトウェアは良くフラクタルのようだと言われていますよね。1クラスとクラスがまとまってコンポーネントとなり2コンポーネントとコンポーネントがまとまってサブシステムになります。3サブシステムとサブシステムがまとまってシステムになります。エンティティと呼ぶことにします。5ソフトウェアエンティティのすべてにおいて、ここまでした話の内容は適用できます。APIになったりするでしょうけどどの要素間であっても、コントラクトの文脈を管理する事で制御の流れと依存関係は制御することが可能です。こちらに各ソフトウェアエンティティごとの代表劇なコントラクトを上げてみました。なんならシステム間でのやり取りがCSVとか固定長テキストであっても、そのファイルがどっちのシステムの文脈によってるかによって、システム間の依存関係はコントロールできるわけです。文脈によって、制御の流れと依存方向は分離し制御することが可能です。クリーンアーキテクチャがあらゆるソフトウェアにおいて「アーキテクチャのルールはどれも同じである」ことを受け入れていただけましたか?とうわけで、今日のお話は終わりになります。最後に簡単にまとめましょう。1クリーンアーキテクチャは、どんなソフトウェアにも適用可能な普遍的なアーキテクチャです2クリーンアーキテクチャの代表的な図は、誤解されがちです3クリーンアーキテクチャの本質的で本当に大切なことが二つはあってひとつは依存性はより上位レベルの方針、つまりオニオンアーキテクチャであれば外から中にだけ依存するべきであることそしてもう一つは制御の流れと依存方向は分離してコントロールできるということですという訳で、本日の内容は以上になります。ご清聴ありがとうございました。Architectureの次の点についてお話させていただきます。本質だと思っています。異論・反論大歓迎です。オンライン・オフラインいずれでも、ぜひご意見を聞かせてください。向かっていなければいけない。etc...)には類似の共通点が見られるとある。続けてこう記載されている。Gatewayの文脈でQuery用のDBオブジェクトを用意します。完ぺきなCQRSを適用するのは難しい。場合によってはオーバースペックでさえある。ClipboardCancelSave。