2024.12.19
システムの穴を運用でカバーしようとしてミス多発… バグが大量発生、決算が合わない状態から業務効率化を実現するまで
リンクをコピー
記事をブックマーク
では処理の流れを確認していきましょう。どういった処理の流れでやるか。いろいろなものがありましたけど、なんとなくこのData StructureとInterfaceがあって、あと実装クラスはいっぱいあるなということだけわかればいいです。
最初はどこからいくかというと、まずControllerから入りますよね。Controller、UserController、ここで入力のデータを生成しています。具体的にはボタンを押した事実を、コンピュータがわかる、ビジネスロジックがわかるかたちに、アプリケーションがわかるかたちに、Input Dataに変換しています。インスタンス化して。そしてそれをInput Boundaryを呼び出すことで、引き渡している。Callしています。
そしてInput Boundaryはこういうコードでしたよね。インターフェースです。だから、これが実際に処理するのは、これが処理するんじゃなくて、これを移譲して、実際に処理するのはUse Case Interactor。この処理ですね。さっきのデータベースにデータを保存したりする処理です。
やっていることは、ドメインオブジェクト、Entityと呼ばれるもの、ビジネスのオブジェクトを生成して、これをまたData Access Interfaceを呼び出すんですよ。そいつに対して「保存お願いします」って呼び出します。
そうすると、Interfaceなので、このインターフェースはそれの処理の実装クラスに処理を移譲します。Repositoryクラスの中で実際に……O/Rマッパーなりなんでもいいです。とにかくデータを保存すればいい。保存するために、これはO/Rマッパーを使ってデータベースにアクセスしています。ここまでいいかな。
インターフェースを実装すると複雑になるって言う人もいるんですよね。慣れの問題ではあると思いますよ。クラスをいっぱい書くことに慣れていない方はやっぱり複雑に感じちゃうよね。
重要なのは、単純なことがシンプルじゃないってことなんですよね。「複雑さ」の反対って「単純」ってよく言われるんですけど、「複雑」と「シンプル」だと思っていて、やっぱりそこはちょっと違うのかな。けっこう慣れなので、なんとかやるしかないですよね。
データを保存する処理を投げて、そのあとです。出力データを生成します。結果、今回で言うと、生成したユーザーのuuid、今回ランダムに作っています。それを返すために生成します。それを出力データとして作って、その出力データをOutput Boundaryに渡す。Output Boundaryはインターフェースなので、それの実装クラス、PresenterにDelegateします。処理を移譲します。
これ、こういう流れです。あとはもう Viewに渡すだけ。今の流れ、アーカイブがあるので、また読んでください。もしくはスライド見るだけもわかると思います。
そうそう、(コメントで)「こうやって全体図がわかれば、コードの量が多くてもかえって見やすくなる」、まさにそうです。重要なことは、何がどこに書いてあるかわかること。まとまっていることはわかりやすくないんですよ。例えば1万行って書いてあったらみんな引くでしょう? それが100行のクラス、100個なのが……。
で、整理整頓されている場合なんですよ。重要なことは、整理整頓されているかどうか。されていないと、1つの……例えばよくあるのが、みんなフォルダー作るのが怖いんですよ。俺フォルダー切りまくるんですね。1つのフォルダーに100個クラスあると、すごいわからない。何を見ていいかわからない。名前でなんとか制御していてもやっぱり見づらいんですよ。でも、それを「フォルダー作って、10個に分けて、10個に分けて」ってやるだけでも、100個が1つフォルダ10個ずつ、ちゃんと分けていればわかりやすくなるってイメージですね。
話を戻します。今日はクリーンアーキテクチャの話をするんじゃないです。クリーンアーキテクチャをどうしたかって話なんです。今日の先行開発どうやってやるのかというと、とりあえずフロント組みたいなってときに……わかるこれ?
さっきのInteractor。実際にユーザーを生成する処理。生成して保存する処理というところを、Stub、仮の動きをするオブジェクトを作っておくんですよ。そうすると、この処理で実際にデータ保存されないんですよ。データストアがないし保存されないけど、testってIDは返ってきますよね。
プログラム、フロントエンドをとりあえず作っておけば、サーバロジックできてなくてもtestってフロントに返せますよね。フロントを動かせる。
あとは、例えば例外のときの動作確認。例外ってけっこう動作確認難しいんですよ。実際のデータベースを使って例外を起こそうとすると、整合性のあるエラーのデータを作らなきゃいけなくて、それってすごく難しいんですよね。しかもそれ本番でやりたいんだとすごく大変ですよね。
そのときにどうすればいいかというと、こうやってクラスを作ってすぐ例外を投げちゃえばいい。もちろん例外がちゃんと投げられたらテストは別にしなきゃいけないんですけど、「フロントでこのRuntimeExceptionが出たときの動き見たいな」とかできるんですよね。なんとなくメリットある感じしてきましたよね。
ほかにも、今日の最初の話で、データベースはまだ選定中だけど、ロジックを組みたいときにどうすればいいかというと、これはデータベースがなくても動くんですけど、さっきみたいにこのインメモリ、このMapね。ハッシュテーブルを使ってとりあえずデータを保存するやつ。
インメモリなので、このプログラムずっと常駐して……常駐はしているんですけど、……シングルトンね。このオブジェクトを使い回すんですけど、そのロケールデバッグ中はインメモリに保存できます。だから、サーバを落としたら消えますが、とりあえず仮でデータ保存してテストはできるんですよ。
そう、今Twitterのほうでね、「Interfaceを含めた全体像を図で俯瞰できると……」、そうそう。今の流れが見えるとインターフェースが必要なのが客観的に理解できると思います。そうそう、今おっしゃってくれた、「UseCaseのStubを作っておいて、フロントで動作確認できるようにすると……」、そう、まさにそのとおりです。
いや、これならすばらしいじゃないですか。もう勝ったな、ガハハ……本当に?
みなさん、Controllerのときに実はこの「return ?????????????」ってなかったんですよ。何が言いたいかというと、我々がWebアプリを作っているときは、必ずMVCフレームワークってレスポンスを返さなきゃいけないんですね。つまり、さっきの出力をPresenterに渡してViewを表示するということは、うまく動かない。
もともとクリーンアーキテクチャ自体はiOSクリーンアーキテクチャって、iOS向けに作ったんですよね(※のちに勘違いだったとYouTube説明欄で訂正)。iOSはもちろんPresenterがうまく機能します。Webアプリ、WebはHTTPリクエストレスポンスなので、どうしても、Presenterってリターンしなきゃいけないんで、Presenterがそぐわない。
今ちょっとね、Twitterのほうでも、DIコンテナとか、あと今コメントでもいただいた、「インターフェースの実装クラスは差し替えどうやるんだろう?」ってあるんですけど、どうやってやるかというと、例えば設定ファイルにDI、実際に使うユースケースとかを設定するクラスを作るんですね。プロダクションのとき、本番のときは実際に本当のやつを登録。ローカルで動かすときはモックのものを使うように登録する。
そのDIコンテナってご存じかな。DIコンテナがどういったものかというと、さっきの……ちょっと戻るね。ちょっとわからなかった方がいるので。これ……あっ、そう、これこれ。これuserAddUseCaseはインターフェースです。なので、ここに設定されるものは何も決まっていません。
Javaの場合、こうやって@Injectってやると、インターフェースをどこかで、例えばプロジェクト、サーバのスタートアップで設定しておいたオブジェクトがここに入る。もしくは生成してバインドされる。代入される。そういうDIコンテナというのがあります。
要するに何が言いたいかというと、毎回毎回ここを自分で設定するんじゃなくて、プロジェクトの初期段階、実際実行した瞬間に設定しておける機能があります。
詳しくはコードにも実際それやっているところあるので、それをあとでお見せするか、GitHubを見ればたぶんわかると思うんですけど、スタートアップのところで設定しています。1回設定しておけばそれがずっとそのサーバ起動中使い回されるので、もう毎回毎回そのインスタンスを決めなくていいよね、というものです。
設定ファイルとか扱ったり、実際クラスでそのままやったりすることもあります。ローカルで実行するときはモックのユースケースをバインドするように、このInjectの中に代入するように設定します。
本番のときはプロダクション用のUse Case……あのInteractor、実際の実装クラス。あとインメモリで動作するデータベースとかを使うようにしなさいとか、実際にMySQLを使って保存するモジュールを使いなさいとか、そういう感じでやっていきます。なんとなくわかったかな。
DIコンテナを初期で設定する。ちょっとね、先に、これはたぶんそこが気になっちゃうと意外に進めないかもしれないので、ちょっと今コードを見せよう。ちょっとごめんね。
みんなわかっている、ここらへんすでにいろいろやっている人はわかっていると思うんだけど、けっこう気になっちゃうとあんまり進めなくなっちゃうからね。今パッと出てきたのがC#なんですけど、C#とJavaほぼ一緒だから大丈夫だよね。
(プログラム例を見せながら)例えばなんですけど、今これはインメモリなので、デバッグで動く用ですね。とにかく本番でデータベースに保存しなくても動くようにしたいパターンですね。データを保存するとき、テストのときはこうやってインメモリで動くモジュールを使ってくださいねって設定します。
反対にじゃあ本番のときどうするかというと、本番は例えばUserRepository、データを保存するモジュール、インターフェースが求められたら、SQLのユーザーリポジトリ、SQLでユーザーを保存するようなリポジトリ使ってくださいね、モジュール使ってくださいねという設定ができます。そういうイメージです。
このMVCフレームワークがあんまり合っていないという問題が1つあります。そして次、これ。さっき言ったDIの設定でこうやってDIをいっぱいする。MVCフレームワークを使うコントローラって、アクションがいっぱい書いてありますよね。このアクションごとにユースケースを作る。
つまり、それぞれこうやって@Injectする。DIする。フィールドにユースケースをもつ。これ@Inject Hellとよく言うんですけど、これつらいよね。だってユースケース作るたびにControllerを修正するんだよ。これは大変だよね。アクションが増えるたびに。
あともう1個は、まずこれで1個のロジックをつくるときに何をやらなきゃいけないか、思い浮かべてほしいんですよ。まずControllerを作ります。それはいいでしょ。必要だから。
その次。Input Dataを定義します。そして、Input Boundaryを定義します。さっきのInterfaceね。Input Interface。そしてUse Case Interactorで実際処理するところを作ります。出力のためのデータ構造体を作ります。出力インターフェースを作ります。そして、Presenterを作ります。そのあとView Modelを定義して……つらいよね。つらいよねー。
これ明らかに嫌がられるやつだよね。こんだけファイル定義しているのに「よろしく!」ってやってもさ、みんなやりたくないよね。
じゃあ今回のついに主題ですよ、やっと。どうするか? 今のが課題です。
関連タグ:
2024.12.20
日本の約10倍がん患者が殺到し、病院はキャパオーバー ジャパンハートが描く医療の未来と、カンボジアに新病院を作る理由
2024.12.19
12万通りの「資格の組み合わせ」の中で厳選された60の項目 532の資格を持つ林雄次氏の新刊『資格のかけ算』の見所
2024.12.16
32歳で成績最下位から1年でトップ営業になれた理由 売るテクニックよりも大事な「あり方」
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
PR | 2024.12.20
モンスター化したExcelが、ある日突然崩壊 昭和のガス工事会社を生まれ変わらせた、起死回生のノーコード活用術
2024.12.12
会議で発言しやすくなる「心理的安全性」を高めるには ファシリテーションがうまい人の3つの条件
2024.12.18
「社長以外みんな儲かる給与設計」にした理由 経営者たちが語る、優秀な人材集め・会社を発展させるためのヒント
2024.12.17
面接で「後輩を指導できなさそう」と思われる人の伝え方 歳を重ねるほど重視される経験の「ノウハウ化」
2024.12.13
ファシリテーターは「しゃべらないほうがいい」理由 入山章栄氏が語る、心理的安全性の高い場を作るポイント
2024.12.10
メールのラリー回数でわかる「評価されない人」の特徴 職場での評価を下げる行動5選
Climbers Startup JAPAN EXPO 2024 - 秋 -
2024.11.20 - 2024.11.21
『主体的なキャリア形成』を考える~資格のかけ算について〜
2024.12.07 - 2024.12.07
Startup CTO of the year 2024
2024.11.19 - 2024.11.19
社員の力を引き出す経営戦略〜ひとり一人が自ら成長する組織づくり〜
2024.11.20 - 2024.11.20
「確率思考」で未来を見通す 事業を成功に導く意思決定 ~エビデンス・ベースド・マーケティング思考の調査分析で事業に有効な予測手法とは~
2024.11.05 - 2024.11.05