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
86
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
フロントエンドでDDDやってみた
「#Webフロントエンド なんでもLT 会 #5」での発表内容です。
https://ncdc-dev.connpass.com/event/248156/
ak2ie
July 03, 2022
More Decks by ak2ie
See All by ak2ie
Claude Codeはレガシー移行でどこまで使えるのか?
ak2ie
1
1.6k
SVG完全に理解してグラフ書いてみた
ak2ie
0
60
Go言語CLIツールで生産効率UPした話
ak2ie
0
120
Goではじめるバックエンド開発
ak2ie
0
83
Notion APIと学ぶNext.js
ak2ie
0
590
NestJSのはじめ方
ak2ie
0
160
初心者がシビックテックに参加してみた
ak2ie
0
130
Firebase についてとことん語りたい
ak2ie
0
130
D3.jsでグラフを描いてみた
ak2ie
0
120
Other Decks in Technology
See All in Technology
NAB Show 2026 動画技術関連レポート / NAB Show 2026 Report
cyberagentdevelopers
PRO
0
150
「気づいたら仕事が終わっている」バクラクAIエージェント本番運用の裏側 / layerx-bakuraku-aie2026
yuya4
19
11k
チームで進めるAI駆動アジャイル×ウォーターフォール
kumaiu
0
140
Oracle AI Database@Azure:サービス概要のご紹介
oracle4engineer
PRO
6
1.9k
RSA暗号を手計算したくなること、ありますよね?? (20260615_orestudy6_rsa)
thousanda
0
110
AI活用を推進するために ファインディが下した、一つの小さな決断
starfish719
0
290
Reliability in the Age of AI: Engineering for AI Velocity
rrreeeyyy
0
120
あなたの AI ワークスペースに、 専門コーダーを連れてくる - Amazon Quick Desktop 最新情報
kawaji_scratch
1
130
DevOps Agentで始めるAWS運用 〜フロンティアエージェントが変える運用の現場〜
nyankotaro
1
360
FDE という解 ― 暗黙知と明示知をつなぐ、伴走型エンジニアリング ―
otanet
0
110
2026TECHFRESH畢業分享會 - Lightning Talk - 資料也要 CI/CD? 用 Airbyte 自動化資料同步
line_developers_tw
PRO
0
570
失敗を資産に変えるClaude Code
shinyasaita
0
180
Featured
See All Featured
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.3k
Discover your Explorer Soul
emna__ayadi
2
1.1k
Raft: Consensus for Rubyists
vanstee
141
7.5k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
150
Statistics for Hackers
jakevdp
799
230k
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
200
A Tale of Four Properties
chriscoyier
163
24k
Writing Fast Ruby
sferik
630
63k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.1k
WCS-LA-2024
lcolladotor
0
620
Claude Code のすすめ
schroneko
67
230k
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
160
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] }
まとめ • コード全体の見通しがよくなった • テスト対象範囲が狭くなり、テストが書きやすかった • コード量が多くなってしまった