Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
TypeScript ではじめる Clean Architecture / Let's s...
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
dojineko
October 15, 2019
Technology
3.5k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
TypeScript ではじめる Clean Architecture / Let's start Clean Architecture with TypeScript
dojineko
October 15, 2019
More Decks by dojineko
See All by dojineko
コスパの良いAIの選び方 / Surviving the AI Era on a Budget
dojineko
0
34
ミニPCを買ってみた話/The Story of Buying a Mini PC
dojineko
0
41
WebXRのいま(2025Q1) / About WebXR (2025Q1)
dojineko
0
740
iOSのWebViewとClipboardAPI / WebView and ClipboardAPI on iOS
dojineko
0
150
最近のUnityとVRChat / About Unity and VRChat recently
dojineko
0
210
WebXRでポートフォリオを作ろう/Let's make your portfolio with WebXR!
dojineko
0
220
ペパボ ホスティング事業部のWebフロントエンドについて 2022 / About Web Frontend of Pepabo Hosting division 2022
dojineko
1
10k
Viteはいいぞ/Vite is Good
dojineko
1
820
はじめてでもできた!VR登壇への道 / Let's VR speech!
dojineko
0
490
Other Decks in Technology
See All in Technology
AI駆動開発を通して感じた、 AI時代のデザイナーの役割変化
whisaiyo
3
2.1k
RSA暗号を手計算したくなること、ありますよね?? (20260615_orestudy6_rsa)
thousanda
0
420
AAIFに入ってみた ~内から見えるコミュニティ動向~
sato4
0
230
ルールやカスタム機能、どう活かす?ハンズオンで体感するIBM Bobの出力コントロール
muehara
1
160
中期計画、2回作ってみた ~業務委託と正社員、両方の視点から~
demaecan
1
800
On-behalf-of Token exchange with AgentCore Identity
hironobuiga
2
210
気づかぬうちにセキュリティ負債を生むAPIキー運用
sgwrmctk
0
130
Claude Codeとのおしゃべりでセマンティックモデルの定義からダッシュボード作成まで完成させる
nic_sugiyama
0
110
Chainlitで作るお手軽チャットUI
ynt0485
0
240
Socrates × Looker 〜セマンティックレイヤーで進化するデータ分析エージェント〜
hanon52_
3
2.4k
小さくはじめるSLI/SLO ~育てながら組織に定着させる実践知~ / Starting Small with SLI/SLOs: Building Adoption Through Continuous Growth
nari_ex
7
1.9k
Oracle AI Database@Azure:サービス概要のご紹介
oracle4engineer
PRO
6
2k
Featured
See All Featured
Product Roadmaps are Hard
iamctodd
PRO
55
12k
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
160
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.8k
Crafting Experiences
bethany
1
180
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
65
55k
Build your cross-platform service in a week with App Engine
jlugia
234
18k
The Spectacular Lies of Maps
axbom
PRO
1
810
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
1.7k
Chasing Engaging Ingredients in Design
codingconduct
0
220
The Language of Interfaces
destraynor
162
27k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
Transcript
TypeScript ではじめる Clean Architecture Fukuoka.ts @ 2019-10-15
@dojineko GMOペパボ株式会社 ホスティング事業部 マネージドクラウドチーム よろず屋
クリーンアーキテクチャってなぁに?
「クリーンアーキテクチャ」とは? • アプリケーションを4層 大枠に分割して、責務と関心 分離を行い 疎結合な設計にするため コンセプト • 「Enterprise Business
Rules」 ◦ アプリケーションに依らない根本的なビジネスルール 層 • 「Application Business Rules」 ◦ アプリケーション的なビジネスルール 層 • 「Interface Adapters」 ◦ External Interface を可換にするインターフェースとデータ構造体 層 • 「Frameworks and Drivers」 ◦ データベースやキャッシュ、 APIなど 外部リソース 層
None
クリーンアーキテクチャによる制約 • クリーンアーキテクチャ 原則 依存を一方に統一すること • 依存できる実装 、常に円 中心方向へ み
◦ 逆方向へ 依存が発生する場合 interface を使用し、依存関係 逆転 (DIP)を活用する ◦ 「依存関係 逆転(DIP)」: 雑な解釈として 依存を抽象化し初期化時に実装を注入すること • 基本的に層をまたいで実装を使用すること しない ◦ 層をまたいでデータを引き渡す場合 専用型へ 詰め直しが必要になる (Data Structure などと呼 れる)
Enterprise Business Rules • アプリケーションに依らない根本的なビジネスルールを格納する • Entity と呼 れるクラス群が収まる層 •
同階層 クラス群以外に 依存しない コアなロジックしか書かない で 比較的小さなパーツになるよ
Application Business Rules • アプリケーション的なビジネスルールを格納する • UseCase や Interactor と呼
れるクラス群が収まる層 • Entity と同階層 実装に依存でき Interface Adapters interface を使用できる • 「依存する」と 言い換えると「実装を直接使用する」こと ◦ 「interface を使用する」こと 「依存していない」ことになる
Interface Adapters • データ 入出力や永続化処理、表示を抽象化する層 • Repository、Gateway、Presenter と呼 れるクラス群が格納される •
同階層 実装に依存でき Frameworks and Drivers interface を使用できる • 基本的にDIPにより依存関係 逆転した状態となる • ここに 直接永続化したりする処理 基本的に 書かない
Frameworks and Drivers • 外部リソースへ 具体的なアクセス手段を格納する層 • Driver や Infrastructure
と呼 れるクラス群が格納される • 基本的にDIPにより依存関係 逆転した状態となる • 外部フレームワークやDB ドライバへ 直接 依存ができる ◦ MySQLやPostgreSQL、Redisなど ドライバを直接使用するコード ◦ ORM や Web API フレームワークを直接使用するコード ◦ など
フロントエンドでも サーバーサイドも 普遍的に利用できる「設計手法」デス
なにがうれしいの?
なにがうれしいのか? • 層が意識された設計になることで、アプリ 構成要素が疎結合になる ◦ 構成要素: フレームワーク、データベース、ビジネスロジックなど • アプリケーション テストコードが書きやすくなる
◦ 単体テストでデータベースを要求するようなシーンが減る • コード変更 影響を最小限に抑えられ改修コストを下げられる ◦ 責務や関心が分離されている で副作用を出しづらい ◦ 継続的な開発に向いている設計
具体的なメリットの例は? • 特定 ライブラリを別 なにかに置き換えるときに楽できる ◦ アプリケーション固有 ロジックが、 フレームワークやライブラリから分離されている ことによるメリット。
◦ フレームワークやライブラリ側 EOLなど どうにもならないケースや、 後発 より良い実装に移りたいシーンなどにおいてかなり有用。 • 実際にデータベースを用意しなくてもロジックがテストできる ◦ データあるい データ構造とロジックが分離されている ことによるメリット。 ◦ 単体テストを書くときにやってしまいがちな、モックライブラリを多用しながら、 データベースへ 副作用を押し潰しながら実施するようなテストを書かなくて済む。 ◦ 必要であれ ライブラリを使用している層 みをテストしてあげれ 良い。
実例: ORMライブラリを置き換える例 • ORM を Sequelize から TypeORM に置き換えたい。 ◦
ライブラリ自体が TypeScript を想定した作りになっているため運用上メリットが大きい。 • Sequelize モデルにアプリケーション コアロジックが、 すでに大量に記載されており、移行 阻害要因になっている。 ◦ また、TypeORM に単にそ まま移行するだけで 、同じことが移行先でも起こる で メンテナンス性をあげるという点において 不十分。 ◦ コアロジックを適切に抽出して、ライブラリに依存しないようにする必要がある。 • 並行してクリーンアーキテクチャに整備していくことで、 全体 メンテナンス性を上げつつ、 他 ライブラリに置き換える際も楽ができるようになる。
デメリットは? • 素直にコードを書くより 圧倒的に記述量が増える ◦ interface や class を細かく分割して疎結合な構成を保つ仕組みな で
ファイル数や記述量が増えてしまう 致し方なし • コードをどこに書け いい か悩みがち ◦ 一部 キーワードが他 設計方法や フレームワークとかぶっていてややこしい • 「完全に理解する」に 少し時間が必要な場合も ◦ 逆を言うと、触れていれ 理解できるようになる メリット 大きいけど 最初だけちょっと大変 ...
解決策は? • クラスやファイルが多い問題 ◦ ある程度運用ルールが固まってくれ ジェネレータを作って 雛形生成するなどで対策可能 • コードをどこに書くか問題 ◦
大枠で層を分割することをまず意識しながらコードを書く ◦ 適切に層に分けられていない場合 テストがしづらいことなどで分かる で適宜見直して再配置する • 「完全に理解した」い問題(?) ◦ コードを書きながらコンセプト図をたまに見返して勘所を得る練習を繰り返す ◦ チーム開発なら 理解を得るためにメリットを説く普及活動も並行すると良い
TSでどうやってやるの?
おまたせしました
サンプルリポジトリをご用意しました https://github.com/dojineko/cleanarch-ts
サンプルコードの説明 • 機能概要 ◦ 登録されているユーザー データを一覧にする ◦ 単一 ユーザー プロフィールを表示する
• 起動時 指定で可換な機構 ◦ Webアプリフレームワーク : Koa.js or Express.js ▪ ライブラリ 置き換えを想定したサンプル ◦ データストア: 組み込み(Static) or ファイル(JSON) ▪ データベースをロジックから分離した場合 サンプル
Index アプリケーション エントリポイント。 起動に必要な環境変数を確認して機構 (Controller, Repository, Usecase, Driver)を 初期化する。 サンプルで
、Pure-TypeScript で書いてある で記載が冗長だが InversifyJS など DIコンテナ を活用することでスッキリ 書くことができるようになる。
Driver 外部ライブラリ 利用方法を格納する。 サンプルで 、Webサーバー DriverとしてKoa 版とExpress版 Driverが存在する。これら ServerDriver interface
を実装する。 同じくデータストア Driverとして、Json版と Static版 Driverも存在する。これら DataStore interface を実装する。 コアロジック Controllerよりも円 内側 コード にかかれており、Driverで Controllerと外部ラ イブラリ 橋渡しをする程度しか処理がない。 ※ コード src/drivers/koa および、 src/drivers/express などを参照 Express版 Koa版
Controller Driverから受け取った値と、自身が持つ UseCase と 連携を取り持つ。 Controller になにをすれ いい かを指示する と、UseCase
を呼び出して実際 処理が始ま る。 ※ コード src/adapters/controllers を参照 Controllerが使用するUseCase constructorで受け取る Controller 処理に応じた UseCase 実行関数を実行する
Repository データ 取得保存など永続化に関するロジックを 格納する。 Repository interface で DIP を適用する際に 使用できる。
注意する点 DataStore から得られる型をそ まま外に流出させないように Data Structure へ 詰め直しを行う点。 そ まま型情報を返却すると例え データベー ス 構造にコードが依存してしまう。 また、層による分割 ルールで、DataStore Response が直接 Entity になるようなこと 基 本的にない。 ※ コード src/adapters/repositories を参照 DataStore Response 型を改めて定義する Repository 実装で DataStore から得たデータを 定義した型に合うよう詰める
UseCase アプリケーション固有 ビジネスロジックを格納 する。 実 UseCase interface で実際 UseCase を実装する
Interactor というクラスが処理を行 う。 UseCase で データストアから、データ 取得を 行う必要があるが、依存関係 方向が逆向きに なってしまうため DIP を適用して、UseCase 初 期化時に Repository を注入している。 ※ コード src/applications/usecases を参照 UseCase自体 interface 実装 Interactor が行う 使用する Repository constructor で受け取る
Entity アプリケーションであることに依存しないコアロ ジックを記載する。 また基本的に、Entityで 外部ライブラリを直接 使用しないように、組み込み型や組み込み関数 など みでコードを記載する。必要応じて一部 ライブラリ 許可するなどしても良い。
サンプルコードで score に応じて ヘビーユー ザーかどうかを boolean で返す関数を実装して いる。 ※ コード src/domains/entities を参照 Entity コード 基本的に 外部ライブラリに依存しない。 (他 Entityを使用する OK)
▪ サンプル全体 大枠 構成図 Entity Repository (interface) Gateway UseCase (interface)
Interactor Controller Server (interface) Koa.js JSON DataStore (interface) Static Express.js
まとめ
まとめ • クリーンアーキテクチャ アプリケーション設計 コンセプト • フロントエンド、サーバーサイド問わず普遍的に活用できる設計手法 • 大切な 依存
方向を一方にし、責務と関心を分離すること • 結果としてアプリケーション 実装が疎結合になる • 実装が疎結合になると単体テストがしやすくなり、変更にも強くなる
心も体もコードも 健康にしていこう
ご静聴ありがとうございました