はじめに
エンジニアになって2〜3ヶ月、LT会で5分間の発表をしてきました。テーマは「クリーンアーキテクチャとDI(依存性注入)」。
正直、自分にはまだ早いテーマかもと思いつつ、「わからないからこそ調べて話す」のが一番勉強になると思って挑戦しました。この記事では、発表の内容と準備を通じて学んだことを振り返ります。
発表の内容
クリーンアーキテクチャの核心は「依存ルール」だけ
クリーンアーキテクチャは同心円の図が有名で、レイヤーがたくさんあって複雑に見えます。でも調べていくうちに、本質は1つのルールだけだとわかりました。
「依存は外から内へ。内側は外側を知らない。」
構成例でいうと:
リクエストの流れ: Client → Controller → UseCase → Domain
データ取得の流れ: Port ◀ Gateway → Driver → API
上の段(リクエスト)は外から内に自然に流れるので問題ない。問題は下の段(データ取得)です。UseCaseがAPIからデータを取りたいとき、直接GatewayやAPIの実装を呼んでしまうと、内側が外側を知ることになる。
そこで**Port(契約書)**を挟みます。Portはinterfaceで、「このメソッドが使えますよ」という約束だけを定義したもの。Gatewayはこの契約書の通りに実装する。こうすることで、外側(Gateway)が内側(Port)に依存する形になり、依存の向きが内向きに統一されます。
DI(依存性注入)とは何か
LTではカフェの例えを使って説明しました。
DIなしの場合:
店員が自分で仕入先Aに豆を買いに行っている状態。これだと:
- 仕入先Aが潰れたら店員は仕事できない
- 仕入先Aの豆でしか練習できない
- 仕入先をBに変えたいだけなのに、店員の淹れ方まで変えないといけない
DIありの場合:
店員は豆を外から渡されるだけ。仕入先がAでもBでも、店員の仕事は変わらない。練習用の安い豆でも本番と同じ動きで練習できる。
この「外から渡す」がDI(Dependency Injection=依存性注入)です。
コードで見る問題と解決
❌ DIなし:UseCaseがfetchに直接依存
class FetchUserUseCase {
async execute(id: string) {
const res = await fetch(`/api/users/${id}`);
return res.json();
}
}
これはカフェでいうと「店員が自分で豆を買いに行ってる」状態。テストでこのUseCaseを動かすと、本物のAPIサーバーが動いてないとテストが通りません。fetchを別のHTTPライブラリに変えたいだけでも、UseCaseのコードを書き換える必要がある。
✅ DIあり:契約書(interface)を挟んで外から渡す
interface UserRepository {
findById(id: string): Promise<User>;
}
class FetchUserUseCase {
constructor(private repo: UserRepository) {}
async execute(id: string) {
return this.repo.findById(id);
}
}
UseCaseは「findByIdというメソッドがある」という契約だけ知っている。fetchなのか何なのかは知らない。テスト時はダミーデータを返すMockを渡せばいいし、ライブラリの差し替えもUseCase側はノータッチ。
準備で学んだこと
「説明できない=理解してない」を痛感した
準備していて一番大きかったのが、自分が理解していない部分がどんどん出てきたこと。
- 「interfaceって何?」
- 「なぜGatewayが外側なの?」
- 「Portを実装するってどういうこと?」
スライドを作る段階で「これ自分で説明できないな」と気づいて、一つずつ潰していきました。LTの準備は、自分の理解度チェックとしてめちゃくちゃ有効だと実感しました。
例え話の威力
最初は同心円の図とコードだけで説明しようとしていましたが、途中でカフェの例えを入れることにしました。抽象的な概念は、身近なものに置き換えると一気にわかりやすくなる。自分自身の理解も深まったし、発表でも反応が良かったのはこの部分だったと思います。
5分LTは「何を捨てるか」が大事
最初はReactでの実装例やBefore/After図解も入れていましたが、情報を詰め込みすぎると何も伝わらない。最終的に「依存ルール → DIとは何か → コードで見る」の3本柱に絞りました。「あれも言いたい」を我慢して削る作業が、一番内容を磨く工程だったかもしれません。
発表の振り返り
緊張した、でも思ったより反応が良かった
冒頭で「まだエンジニアになって2〜3ヶ月なので、すごく緊張してます」と正直に言ったのは良かったと思います。聴衆の空気が柔らかくなった気がしました。
発表後に「初心者が躓くところだよね」と声をかけてもらえました。自分が理解に苦しんだポイントを取り上げたのは間違ってなかったんだなと。
ただ、LT会に参加するくらいなので周りのレベルは高くて、経験年数が長い人が多かった印象です。正直、自分の発表内容は参加者にとっては既知の内容だったと思います。それでも「そこ大事だよね」という反応をもらえたのは、初LTとしては良い経験でした。
外部の人と話せたのが一番の収穫だったかもしれない
発表そのものと同じくらい価値があったのが、LT会を通じて社外のエンジニアと話せたことでした。
普段は社内のメンバーとしか開発の話をしないので、どうしても視野が限られてくる。LT会には自分とは全然違う環境で働いているエンジニアが集まっていて、同じ「設計」というテーマでも、現場によってアプローチが全く違うことを知れました。
たとえば、自分はクリーンアーキテクチャを「教科書的に正しい設計」として捉えていたけど、「チームの規模や開発速度によってはもっとシンプルな構成のほうがいい」という意見をもらったり、「うちではこういう理由でDIコンテナを使ってる」みたいな実務ベースの話を聞けたりして、視野がかなり広がりました。
あと純粋に、他の人の発表を聞くのも刺激になりました。自分より経験の浅い人が堂々と発表していたり、逆にベテランの人がめちゃくちゃわかりやすく噛み砕いて話していたり。「こういう伝え方があるのか」という発見がいくつもあって、発表を聞く側としてもすごく勉強になりました。
社内にいるだけだと得られない刺激がLT会にはあると思います。まだ参加したことがない人がいたら、聞く側からでもいいのでぜひ一度行ってみてほしいです。
社内でもLT会やりたい
今回の外部LT会を経験して、社内でもLT会をやったほうがいいと強く感じました。
メンバーそれぞれが持っている知見って、普段の業務だけだと意外と共有されない。「あの人こんなこと知ってたんだ」みたいな発見は、LTのような場がないと生まれにくいと思います。
それに、発表する側にとっても大きなメリットがある。今回の準備を通じて実感しましたが、「人に説明する」という前提があると、理解の浅い部分が全部あぶり出される。ただインプットするだけと、発表するつもりで学ぶのでは、身につき方が全然違いました。
まとめ
- クリーンアーキテクチャの本質は 「依存は内向き」 の1ルール
- DI = 必要なものを自分で取りに行かず、外から渡してもらうこと
- 契約書(interface)で「何を渡すか」の形だけ決めて、中身は外から注入する
- LTの準備は最高の学習方法。「説明できない=理解してない」がすぐわかる
エンジニア3ヶ月目でも、LTに挑戦して良かったです。次はDDD(ドメイン駆動設計)をテーマにしたいと思っています。今回クリーンアーキテクチャを調べる中でDomainという概念が出てきて、ドメインそのものへの興味も湧いてきました。次回のLTまでに実務で触れながら理解を深めていきたいです。
