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
フロントエンドでDDDやってみた
Search
ak2ie
July 03, 2022
Technology
0
75
フロントエンドでDDDやってみた
「#Webフロントエンド なんでもLT 会 #5」での発表内容です。
https://ncdc-dev.connpass.com/event/248156/
ak2ie
July 03, 2022
Tweet
Share
More Decks by ak2ie
See All by ak2ie
SVG完全に理解してグラフ書いてみた
ak2ie
0
34
Go言語CLIツールで生産効率UPした話
ak2ie
0
110
Goではじめるバックエンド開発
ak2ie
0
62
Notion APIと学ぶNext.js
ak2ie
0
540
NestJSのはじめ方
ak2ie
0
140
初心者がシビックテックに参加してみた
ak2ie
0
110
Firebase についてとことん語りたい
ak2ie
0
110
D3.jsでグラフを描いてみた
ak2ie
0
110
Flutterはじめます
ak2ie
0
150
Other Decks in Technology
See All in Technology
HiMoR: Monocular Deformable Gaussian Reconstruction with Hierarchical Motion Representation
spatial_ai_network
0
110
Understanding_Thread_Tuning_for_Inference_Servers_of_Deep_Models.pdf
lycorptech_jp
PRO
0
130
【5分でわかる】セーフィー エンジニア向け会社紹介
safie_recruit
0
26k
Observability в PHP без боли. Олег Мифле, тимлид Altenar
lamodatech
0
360
生成AIで小説を書くためにプロンプトの制約や原則について学ぶ / prompt-engineering-for-ai-fiction
nwiizo
4
2.3k
GeminiとNotebookLMによる金融実務の業務革新
abenben
0
230
PostgreSQL 18 cancel request key長の変更とRailsへの関連
yahonda
0
120
Claude Code Actionを使ったコード品質改善の取り組み
potix2
PRO
6
2.4k
標準技術と独自システムで作る「つらくない」SaaS アカウント管理 / Effortless SaaS Account Management with Standard Technologies & Custom Systems
yuyatakeyama
3
1.3k
Абьюзим random_bytes(). Фёдор Кулаков, разработчик Lamoda Tech
lamodatech
0
350
How Community Opened Global Doors
hiroramos4
PRO
1
120
AWS Summit Japan 2025 Community Stage - App workflow automation by AWS Step Functions
matsuihidetoshi
1
280
Featured
See All Featured
For a Future-Friendly Web
brad_frost
179
9.8k
Code Review Best Practice
trishagee
68
18k
Docker and Python
trallard
44
3.4k
Designing for humans not robots
tammielis
253
25k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
252
21k
Making Projects Easy
brettharned
116
6.3k
Six Lessons from altMBA
skipperchong
28
3.9k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
30
2.1k
Raft: Consensus for Rubyists
vanstee
140
7k
The World Runs on Bad Software
bkeepers
PRO
69
11k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Testing 201, or: Great Expectations
jmmastey
42
7.5k
Transcript
フロントエンドで DDDやってみた 2022/06/17
自己紹介 • 名前:ak2ie(あっきー) • システムエンジニア9年目 • 好きなもの:コーヒー、電車
DDD(ドメイン駆動設計)とは? • システムの対象領域(ドメイン)に焦点を当てた設定手法 • ValueObject、Entity、ドメインサービスを使ってドメインの知識を表現 • リポジトリ、アプリケーションサービス、ファクトリを用いてシステムを構成
DDD関連書籍 本家 実践的 入門
対象のプロジェクト • 自治体に納めた税金の使途を表示するサイト • 年収を入力すると、福祉や建築といった使途別に税額が表示される ※業務外のプロジェクトです
構成 • Nuxt(ver.2)、TypeScript • フォルダ構成 ◦ root ▪ components ▪
page ▪ plugins:DDD関連のコード ▪ store
ユビキタス言語 • 論理名と物理名を用語集としてまとめた • ドメイン知識を持った方は1,2名、チームメンバーは5名程度だったので、 大きなものは作らなかった
ValueObject • ドメイン固有の概念を値として表す • 「金額」や「税率」を ValueObjectとして定義 • 作成時の数値チェックや金額計算のミスを防止 export class
Price extends PrimitiveValueObject <number> { static create(value: number): Price { if (value < 0) { throw new Error('金額には0円以上を指定してください ') } return new Price(value) }
ValueObject • 加算:金額同士のみ public add(value: Price) { return Price.create(this.price +
value.price) } • 乗算:金額×税率 public times(value: TaxRate) { return Price.create(this.price * value.rate) }
Entity • 属性が変わっても変化しないもの • 「個人」をEntityとして定義 export class Person { private
salary: Price private homeType: HOME_TYPE }
ドメインサービス • ドメインに関する処理を行う • 年収から使途ごとの税額を計算する • 単体テストも書きやすい(Jestを使用)
ドメインサービス export class TaxService { /** * 一日当たりの税額算出 * @param
param * @returns 税額(単位 :円) */ public calcTax(param: { person: Person government : Government cofogCode : CofogCode }): Price | null { const taxAmount = this.calcAmountTax ({ person: param.person, government: param.government , })
ドメインのテスト const person = new Person({ salary: Price.create(10000000 ), homeType:
HOME_TYPE .SINGLE, }) const govFactory = new GovernmentFactory (wrapper.vm) const goverment = govFactory .Get() const service = new TaxService (wrapper.vm) expect( service.calcTax({ person, government: goverment , cofogCode: CofogCode .create({...}), }) ).toEqual(Price.create(((10000000 - 330000) * 0.06 * 2000) / 10000 / 365))
リポジトリ • StoreやAPIからのデータ取得はリポジトリを通して行うことで統一した export class HogeRepository { public GetStoreData(): Data
| null { const storeData = this.app.store?.getters['storeData'] } } export class HogeHogeRepository { public async GetAPIData(): Promise<APIResponse> { const apiResponse = await this.app.$axios.$get<APIResponse>(uri) } }
リポジトリの利用 • リポジトリ名の候補が効く
リポジトリの定義 declare module '@nuxt/types' { interface NuxtAppOptions { readonly $repositories:
<K extends keyof Repositories>(key: K) => ReturnType<Repositories[K]> } } declare module 'vue/types/vue' { interface Vue { readonly $repositories: <K extends keyof Repositories>(key: K) => ReturnType<Repositories[K]> } }
リポジトリの定義 export const repositories: Repositories = { cofog: CofogRepository, cofogData:
CofogDataRepository, budget: BudgetRepository, }
アプリケーションサービス • システムとして構成させるための処理 • APIへのリクエストなど
ファクトリ • リポジトリはファクトリを通して取得、使用するようにした • ファクトリを使うようにしたが、中身は少なかったので使う意味があまりな かったかも知れない export const apiRepositoryFactory =
{ get: (key: keyof Repositories) => repositories[key] }
まとめ • コード全体の見通しがよくなった • テスト対象範囲が狭くなり、テストが書きやすかった • コード量が多くなってしまった