๐ŸŽ‰ berenickt ๋ธ”๋กœ๊ทธ์— ์˜จ ๊ฑธ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค. ๐ŸŽ‰
Back
NestJs
50-kubernetes-helm

1. Clean Architecture

cf. https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

  • Clean Architecture๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ์™ธ๋ถ€ ์‹œ์Šคํ…œ์„ ๋ถ„๋ฆฌํ•˜๋Š” ์•„ํ‚คํ…์ฒ˜๋‹ค.
    • Hexagonal Architecture์—์„œ ์˜๊ฐ ๋ฐ›์€ ํ˜•ํƒœ๋กœ
    • Robert Martin์ด๋ผ๋Š” ์‚ฌ๋žŒ์ด 2017๋…„์— ์ฑ…์œผ๋กœ ์ถœ๊ฐ„ํ•œ ๊ฐœ๋…์ด๋‹ค.
  • Hexagonal Architecture์™€ ๋งค์šฐ ์œ ์‚ฌํ•˜์ง€๋งŒ ์šฉ์–ด์™€ ๊ตฌ๋ถ„์ด ์•ฝ๊ฐ„ ๋‹ค๋ฅด๋‹ค

1.1 Clean Architecture Layers

  • Framework & Driver Layer
    • ์™ธ๋ถ€ ๋””ํŽœ๋˜์‹œ๋“ค์ด ์กด์žฌํ•˜๋Š” ์˜์—ญ์ด๋‹ค.
    • ์˜ˆ๋ฅผ๋“ค์–ด Database, REST API Call, UI, ํ”„๋ ˆ์ž„์›Œํฌ ์ฝ”๋“œ๋“ฑ์ด ๋  ์ˆ˜ ์žˆ๋‹ค.
  • Interface Adapters
    • Usecase์™€ Entities๋ฅผ ์œ„ํ•ด ์กด์žฌํ•˜๋Š” ๋ ˆ์ด์–ด๋‹ค.
    • ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋กœ์ง์ด ์ž๋ฆฌ์žก๊ณ  ์žˆ๋Š” Use Case์™€ Entities์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ๊ฐ€์žฅ ํŽธํ•œ ํ˜•ํƒœ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€ํ™˜ํ•˜๊ณ  ์ „๋‹ฌํ•œ๋‹ค.
  • Use Case
    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ํŠนํ™”๋œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ์ž‘์„ฑ๋˜๋Š” ์œ„์น˜๋‹ค.
    • ์‹œ์Šคํ…œ์˜ ๊ธฐ๋Šฅ๋“ค์„ ๊ตฌํ˜„ํ•˜๊ณ  ์ถ”ํ›„ ์†Œ๊ฐœ๋  Entities๋“ค์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์†Œํ™” ํ•  ์ˆ˜ ์žˆ๋„๋ก ์œ ๋„ํ•œ๋‹ค.
  • Entities
    • ๊ธฐ์—… ์ „๋ฐ˜์ ์œผ๋กœ ์ ์šฉ๋˜๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ์ž‘์„ฑ๋˜๋Š” ์œ„์น˜๋‹ค.
    • ๊ธฐ์—…์— ๋‹จ ํ•˜๋‚˜์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๋งŒ ์กด์žฌํ•œ๋‹ค๋ฉด ๋„๋ฉ”์ธ ๊ฐ์ฒด๋“ค ์ •๋„๋กœ ์ƒ๊ฐํ•ด ๋„ ๋œ๋‹ค.

1.2 Dependency Rule

  • ์›์˜ ๋‚ด๋ถ€์— ์žˆ๋Š” ๋ ˆ์ด์–ด๋Š” ๋ฐ”๊นฅ์˜ ๋ณ€๊ฒฝ์— ์˜ํ–ฅ์„ ๋ฐ›์œผ๋ฉด ์•ˆ๋œ๋‹ค.
  • ์™ธ๋ถ€ ๋ ˆ์ด์–ด๋Š” ๋‚ด๋ถ€ ๋ ˆ์ด์–ด์— ์˜์กด ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ๋‚ด๋ถ€ ๋ ˆ์ด์–ด๋Š” ์™ธ๋ถ€ ๋ ˆ์ด์–ด์— ์˜์กดํ•˜๋ฉด ์•ˆ๋œ๋‹ค.
  • ์˜์กด์„ฑ์˜ ์—ญ์ „์„ ์œ„ํ•ด Dependency Inversion์„ ์‚ฌ์šฉํ•œ๋‹ค

1.3 Use Case

  • Hexagonal Architecture์™€ ๊ฐ€์žฅ ๋‹ค๋ฅธ์ (?) ์ด๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
  • Clean Architecture๋Š” SRP (Single Responsibility Principle)์„ ๊ฐ•์กฐํ•œ๋‹ค.
    • ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๋ ˆ์ด์–ด์—์„œ ์‹คํ–‰ํ•ด์•ผํ•  ๊ธฐ๋Šฅ ํ•˜๋‚˜ ํ•˜๋‚˜๋ฅผ ํ•˜ ๋‚˜์˜ ํด๋ž˜์Šค์— ์ •์˜ํ•œ๋‹ค.

2. Hexagonal Architecture

2.1 Hexagonal Architecture๋ž€?

  • Hexagonal Architecture๋Š” Domain์„ ์ค‘์•™์— ๊ฐ์‹ธ๋Š” ์•„ํ‚คํ…์ฒ˜์ค‘ ๊ฐ€์žฅ ๋จผ์ € ๊ณ ์•ˆ๋œ ์•„ํ‚คํ…์ฒ˜ ์ค‘ ํ•˜๋‚˜์ด๋‹ค.
  • Port and Adapter ํŒจํ„ด์œผ๋กœ๋„ ๋ถˆ๋ฆฌ๋ฉฐ,
    • ๊ฐœ์ธ์ ์œผ๋ก  ์ด ๋ช…์นญ์ด ์กฐ๊ธˆ ๋” ์•„ํ‚คํ…์ฒ˜์˜ ํŠน์„ฑ์„ ์ž˜ ํ‘œํ˜„ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.
  • ๋”์ด์ƒ Layered Architecture์ฒ˜๋Ÿผ Top Down ํ˜•ํƒœ๊ฐ€ ์•„๋‹ˆ๋‹ค.
  • ๋„๋ฉ”์ธ์„ ์ค‘์‹ฌ์œผ๋กœ ์„ค๊ณ„๋˜๊ณ  ์™ธ๋ถ€ ์˜์กด์„ฑ๋“ค์„ Domain์˜ ์„ค๊ณ„์— ๋งž์ถฐ์„œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํ•˜๊ฒŒ ๋œ๋‹ค.
  • ๋„๋ฉ”์ธ์ด ์ค‘์‹ฌ์— ์žˆ๊ณ  ๋ฐ”๊นฅ์ด ๋‚ด๋ถ€๋กœ ์˜์กดํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ๊ฐ–๊ฒŒ ๋œ๋‹ค.
    • ๊ฐ€์žฅ ์ค‘์‹ฌ์—๋Š” ๋„๋ฉ”์ธ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋„๋ฉ”์ธ์€ ๊ทธ ๋ฌด์—‡์—๋„ ์˜์กดํ•˜์ง€ ์•Š๋Š” ๋…๋ฆฝ์ ์ธ ์กด์žฌ๊ฐ€ ๋œ๋‹ค.
    • ์ฆ‰, ์ค‘์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์€ ์™ธ๋ถ€์— ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๊ฒŒ ๋œ๋‹ค

2.2 Domain์ด๋ž€?

  • Domain์ด๋ž€ ์†Œํ”„ํŠธ์›จ์–ด์—์„œ ํ•ด๊ฒฐํ•˜๊ณ ์žํ•˜๋Š” ํŠน์ • ๋น„์ฆˆ๋‹ˆ์Šค ์˜์—ญ์„ ์–˜๊ธฐํ•œ๋‹ค.
  • Domain์€ ์‹ค์ œ ๋น„์ฆˆ๋‹ˆ์Šค๋‚˜ ์‹œ์Šคํ…œ์˜ ๋ฌธ์ œ, ํ”„๋กœ์„ธ์Šค, ๊ทœ์น™ ๋“ฑ์„ ํฌํ•จํ•˜๋ฉฐ ์ด๋ฅผ ์†Œํ”„ํŠธ์›จ์–ด์— ๋ฐ˜์˜ํ•œ๋‹ค.

์†Œํ”„ํŠธ์›จ์–ด์—์„œ ํ•ด๊ฒฐํ•ด์•ผํ•˜๋Š” ํ•ต์‹ฌ ๊ด€์‹ฌ์‚ฌ๋‹ค.

  • ํ•ต์‹ฌ ๊ด€์‹ฌ์‚ฌ์ด๊ธฐ ๋•Œ๋ฌธ์— ํฐ ํ‹€์—์„œ ์ž์ฃผ ๋ฐ”๋€Œ์ง€ ์•Š๋Š”๋‹ค.
  • ์ „์ž ์ƒ๊ฑฐ๋ž˜ ์‹œ์Šคํ…œ์—๋Š” ์ฃผ๋ฌธ, ๊ฒฐ์ œ, ์žฌ๊ณ ๊ด€๋ฆฌ, ๊ณ ๊ฐ์ด ๋„๋ฉ”์ธ์ด ๋  ์ˆ˜ ์žˆ๋‹ค.
  • (๋งˆ์น˜ ์šฐ๋ฆฌ๊ฐ€ ์ƒ์„ฑํ•œ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค์ฒ˜๋Ÿผ)
  • ์˜๋ฃŒ ์‹œ์Šคํ…œ์—๋Š” ํ™˜์ž ๊ธฐ๋ก, ์˜ˆ์•ฝ, ์น˜๋ฃŒ ๊ณผ์ • ๋“ฑ์ด ๋„๋ฉ”์ธ์ด ๋  ์ˆ˜ ์žˆ๋‹ค.

๋„๋ฉ”์ธ์€ โ€œ์‹ค์ œโ€ ๋น„์ฆˆ๋‹ˆ์Šค์—์„œ ํ•ด๊ฒฐํ•ด์•ผํ•˜๋Š” ๊ด€์‹ฌ์‚ฌ์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐœ๋ฐœ์ž๊ฐ€ ์•„๋‹Œ ์‚ฌ๋žŒ๋“ค๊ณผ ์šฉ์–ด ์†Œํ†ต์ด ์šฉ์ดํ•˜๋‹ค.

  • ์ผ๋ฐ˜ ์‚ฌ๋žŒ๋“ค๋„ ์ดํ•ด ํ•  ์ˆ˜ ์žˆ๋Š” ์šฉ์–ด์ธ โ€œ์ฃผ๋ฌธโ€, โ€œ๊ฒฐ์ œโ€, โ€œ์žฌ๊ณ โ€๋“ฑ์ด ์šฉ์–ด๊ฐ€ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋น„๊ฐœ๋ฐœ์ž๋„ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๋‹ค.
  • ์ด๊ฑธ Ubiquitous Language (๊ณตํ†ต ์–ธ์–ด)๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค

2.3 Domain ๊ฐ์ฒด๋ž€?

  • Domain ๊ฐ์ฒด๋Š” Domain์„ ์ถ”์ƒ์ ์œผ๋กœ ํ‘œํ˜„ํ•œ ํด๋ž˜์Šค๋‹ค.
  • ์šฐ๋ฆฌ๊ฐ€ ์ง€๊ธˆ๊นŒ์ง€ ์ œ์ž‘ํ•ด์˜จ Entity๋“ค์ด Domain ๊ฐ์ฒด์™€ ๋งค์šฐ โ€œ๋น„์Šทโ€ํ•˜๋‹ค.
  • Domain ๊ฐ์ฒด๋Š” ํ”„๋กœ์ ํŠธ์—์„œ ๊ฐ€์žฅ ์ค‘์‹ฌ๋˜๋Š” ์ฝ”๋“œ์ด๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด, ์‡ผํ•‘๋ชฐ ์‹œ์Šคํ…œ์˜ ๊ฒฐ์ œ PG์‚ฌ๊ฐ€ A์‚ฌ์—์„œ B๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค๊ณ  ํ•˜๋”๋ผ๋„,
    • ๋„๋ฉ”์ธ ๊ฐ์ฒด์— โ€œ๊ฒฐ์ œโ€๋ผ๋Š” ๊ฐœ๋…์ด ์กด์žฌํ•ด์•ผํ•œ๋‹ค๋Š” ๊ฑด ๋ณ€ํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ๋„๋ฉ”์ธ์€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์˜ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์„ ๋‹ด๋‹นํ•˜์ง€๋งŒ, ์™ธ๋ถ€ ์˜์กด์„ฑ ์—†์ด ๊ฐ€์žฅ ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ ๋‹จ์ˆœํ•˜๊ฒŒ ๊ตฌํ˜„ํ•œ๋‹ค.
    • ๋„ค์ดํ‹ฐ๋ธŒ ์–ธ์–ด๋กœ ๊ตฌํ˜„ ๊ฐ€๋Šฅํ•œ ๋กœ์ง๊ณผ ๊ฒ€์ฆ์„ ์ฃผ๋กœ ๊ตฌํ˜„ํ•œ๋‹ค.

2.4 Domain ๊ฐ์ฒด ์˜ˆ์ œ

1
export class Order {
2
private readonly id : string;
3
private products: Product[];
4
private shippingAddress: Address;
5
private totalPrice: number;
6
private status: OrderStatus;
7
8
constructor(id: string, products: Product[], shippingAddress: Address) {
9
if (!id) throw new Error('Order ID๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.');
10
if (products.length === 0) throw new Error('์ฃผ๋ฌธ์€ ์‚ฌํ’ˆ ํ•˜๋‚˜ ์ด์ƒ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.');
11
if (!shippingAddress) throw new Error('๋ฐฐ์†ก์ง€ ์ •๋ณด๋Š” ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.');
12
13
this.id = id;
14
this.products = products;
15
this.shippingAddress = shippingAddress;
16
this.totalPrice = this.calculateTotalPrice();
17
this.status = OrderStatus.PENDING;
18
}
19
20
// ์—ฌ๊ธฐ๋ถ€ํ„ฐ Business Logic
21
addProduct(product: Product): void {
22
this.products.push(product);
23
this.totalPrice = this.calculateTotalPrice();
24
}
25
removeProduct(productId: string): void {}
26
changeShippingAddress(newAddress: Address): void {}
27
completeOrder(): void {}
28
cancelOrder(): void {}
29
calculateTotalPrice() : number {}
30
}

2.5 Domain Business Logic

1
export class Order {
2
// ์ƒ๋žต
3
addProduct(product: Product): void {
4
this.products.push(product)
5
this.totalPrice = this.calculateTotalPrice()
6
}
7
8
removeProduct(productId: string): void {
9
this.products = this.products.filter((product) => product.id !== productId)
10
// ๊ฒ€์ฆ
11
if (this.products.length === 0) {
12
throw new Error('์ฃผ๋ฌธ์€ ์ตœ์†Œ ํ•˜๋‚˜์˜ ์ƒํ’ˆ์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.')
13
}
14
this.totalPrice = this.calculateTotalPrice()
15
}
16
17
changeShippingAddress(newAddress: Address): void {
18
this.shippingAddress = newAddress
19
}
20
21
completeOrder(): void {
22
if (this.status !== OrderStatus.PENDING) {
23
throw new Error('์ฃผ๋ฌธ์„ ์™„๋ฃŒํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. Pending ์ƒํƒœ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.')
24
}
25
this.status = OrderStatus.COMPLETED
26
}
27
28
cancelOrder(): void {
29
if (this.status !== OrderStatus.PENDING) {
30
throw new Error('์ฃผ๋ฌธ์„ ์ทจ์†Œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. Pending ์ƒํƒœ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.')
31
}
32
this.status = OrderStatus.CANCELED
33
}
34
35
private calculateTotalPrice(): number {
36
return this.products.reduce((total, product) => total + product.price, 0)
37
}
38
}
  • ๋„๋ฉ”์ธ์˜ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋…ผ๋ฆฌ๋“ค์„ ๋‹ด๊ณ ์žˆ๋Š”๋‹ค.
  • ๊ฐ€์žฅ ์ค‘์š”ํ•˜์ง€๋งŒ ๋‹จ์ˆœํ•œ ๋กœ์ง์œผ๋กœ ํ–‰์‚ฌํ•œ๋‹ค.
  • ์™ธ๋ถ€ ์˜์กด์„ฑ์ด ์—†์–ด์•ผํ•œ๋‹ค.
    • ์™ธ๋ถ€์— ์˜์กดํ•˜๊ฒŒ ๋˜๋ฉด ์™ธ๋ถ€ ์˜์กด์„ฑ์ด ๋ณ€๊ฒฝ๋์„๋•Œ, ๋„๋ฉ”์ธ์ด ํ•จ๊ป˜ ๋ณ€๊ฒฝ๋ผ์•ผ ํ•œ๋‹ค.
    • ๋„๋ฉ”์ธ์€ ์ ˆ๋Œ€๋กœ ์™ธ๋ถ€์— ์˜ํ•ด ๋ณ€๊ฒฝ ๋˜๋ฉด ์•ˆ๋œ๋‹ค.
  • ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์˜ ํฐ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์žˆ๋‹ค๋ฉด ์ด ๋ณ€๊ฒฝ์‚ฌํ•ญ์€ ๋„๋ฉ”์ธ์œผ๋กœ๋ถ€ํ„ฐ ํŒŒ์ƒ๋ผ์•ผํ•œ๋‹ค.
    • ๋‹ค๋ฅธ ์™ธ๋ถ€ ์š”์†Œ ๊ฐ€ ๋„๋ฉ”์ธ์„ ๋ณ€๊ฒฝ์‹œํ‚ค๋ฉด ์•ˆ๋œ๋‹ค.

fastcam-architecture_51-1

fastcam-architecture_51-2

fastcam-architecture_51-3

fastcam-architecture_51-4

  • Port๋Š” Adapter๊ฐ€ ์—ฐ๋™ ํ•  ์ˆ˜ ์žˆ๋Š” ์ŠคํŽ™์˜ ๋ช…์‹œ์ด๊ธฐ ๋•Œ๋ฌธ์— ํ•ญ์ƒ interface ํ˜•ํƒœ๋กœ ๊ตฌํ˜„ํ•œ๋‹ค.
    • (OOP์˜ interface๋ฅผ ๊ผญ ์จ์•ผํ•œ๋‹ค๋Š” ์ด์•ผ๊ธฐ๋Š” ์•„๋‹˜)
    • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ• ์ง€ ์ผ๋ฐ˜ํ™”๋œ ์ŠคํŽ™ (contract)๋ฅผ port์— ๋ช…์‹œํ•ด๋‘”๋‹ค.
    • Application ๋‚ด๋ถ€์—์„œ๋Š” ์ด ์ŠคํŽ™์— ๋”ฐ๋ผ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ๋‹ค. ์ด ๊ตฌํ˜„๋œ ๊ธฐ๋Šฅ์„ Adapter๊ฐ€ ์‚ฌ์šฉํ•œ๋‹ค.
    • Port์— ๋Œ€ํ•œ ์ŠคํŽ™์€ ๋ฐ”๋€Œ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— Application ๋‚ด๋ถ€๋Š” ์™ธ๋ถ€ ๋กœ์ง์— ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค.
    • ์ƒˆ๋กœ์šด Adapter๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋ฉด,
      • Port์˜ ์ŠคํŽ™์— ๋งž๊ฒŒ Adapter๋งŒ ๊ตฌํ˜„ํ•ด์ฃผ๋ฉด, Application ๋กœ์ง์€ ์ „ํ˜€ ๊ฑด๋“œ๋ฆด ํ•„์š”๊ฐ€ ์—†๋‹ค.
  • Application์—์„œ ์ž‘์—…ํ•œ ๋กœ์ง์ด Driven ์‚ฌ์ด๋“œ๋กœ ์–ด๋–ป๊ฒŒ ์ „๋‹ฌ๋ ์ง€ ์ŠคํŽ™์„ port์— ๋ช…์‹œํ•ด๋‘”๋‹ค.
    • Application ๋‚ด๋ถ€์—์„œ๋Š” ์ด ์ŠคํŽ™์„ ์‚ฌ์šฉํ•˜๊ณ  ์™ธ๋ถ€์—์„œ Port์— ๋Œ€ํ•œ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ๋‹ค

2.6 Dependency Inversion

  • ์–ด๋–ป๊ฒŒํ•˜๋ฉด ๋„๋ฉ”์ธ์„ ๊ทธ ๋ฌด์—‡์—๋„ ์˜์กดํ•˜์ง€ ์•Š๋„๋ก ๋งŒ๋“ค ์ˆ˜ ์žˆ์„๊นŒ?
  • ๋‹จ์ˆœํ•œ ์งˆ๋ฌธ์ด์ง€๋งŒ ์ฒ˜์Œ โ€œ์•„ํ‚คํ…์ฒ˜โ€์˜ ๊ฐœ๋…์„ ์ ‘ํ•œ๋‹ค๋ฉด ์–ด๋ ค์šธ ์ˆ˜ ์žˆ๋‹ค.
  • Layered Architecture๋Š” Top Down ๋ฐฉ์‹์ด๊ธฐ ๋•Œ๋ฌธ์— ์ธํ”„๋ผ๊ฐ€ ๋ณ€๋™๋˜๋ฉด ์–ด์ฉ” ์ˆ˜ ์—†์ด ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ด ๋ณ€๊ฒฝ๋œ๋‹ค.
    • ์šฐ๋ฆฌ๊ฐ€ ์ œ์ž‘ํ•œ ํ”„๋กœ๊ทธ๋žจ์—์„œ ORM์„ TypeORM์—์„œ Mongoose๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด์ž.
    • ๋ชจ๋“  Service ๋กœ์ง์„ ๋‹ค์‹œ ์ž‘์„ฑํ•ด์•ผ ๋  ๊ฒƒ์ด๋‹ค.
  • ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์˜ ์œ„์น˜๊ฐ€ ์˜์กด์„ฑ์˜ ๋์ด ์•„๋‹Œ๋ฐ ์–ด๋–ป๊ฒŒ ์–ด๋””์—๋„ ์˜์กดํ•˜์ง€ ์•Š๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„๊นŒ?
    • ๋‹ต์€ Dependency Inversion์— ์žˆ๋‹ค

2.7 Repository Pattern

์ž ๊น ๋‹ค๋ฅธ ์ด์•ผ๊ธฐ๋ฅผ ํ•ด๋ณด์ž. ์ด๋ฏธ ์šฐ๋ฆฌ๊ฐ€ ์ต์ˆ™ํ•œ ์ฝ”๋“œ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ดํ•ดํ•˜๋Š”๋ฐ ๋„์›€๋œ๋‹ค

  • TypeORM์€ ์šฐ๋ฆฌ๊ฐ€ ์—ฐ๊ฒฐํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ๊ด€๊ณ„ ์—†์ด ๋ชจ๋‘ ๊ฐ™์€ API ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
  • ์šฐ๋ฆฌ๊ฐ€ Layered Architecture์—์„œ ์ •์˜ํ•œ ๊ฐœ๋…๋“ค์„ ์ƒ๊ฐํ•ด๋ณด๋ฉด, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ๋ฐ”๋€Œ๋ฉด ์œ„ ๋ ˆ์ด์–ด์˜ ๋กœ์ง์— ๋ณ€ํ™”๋ฅผ ์ฃผ๊ฒŒ๋œ๋‹ค.
    • ๊ทธ๋Ÿฐ๋ฐ TypeORM์€ ๋ฐ์ดํ„ฐ๋ฒ  ์ด์Šค๋ฅผ ํ†ต์งธ๋กœ ๋ฐ”๊ฟ”๋„ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ „ํ˜€ ์ˆ˜์ •ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.
  • ์–ด๋–ป๊ฒŒ ๊ฐ€๋Šฅํ•œ ํ‘๋งˆ๋ฒ•์ธ๊ฐ€?

๐Ÿ’ก์˜์กด์„ฑ ํ๋ฆ„

Controller โ†’ Service โ†’ Repository(e.g. Postgres, MySQL, mongoDB)


2.8 Repository Pattern

fastcam-architecture_51-5

  • ํ‘๋งˆ๋ฒ•์€ interface๋กœ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • TypeORM์—์„œ TypeORM๊ณผ ์—ฐ๋™ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฃฐ์„ interface ๋กœ ์ •์˜ํ•œ๋‹ค.
  • ์ด ์ •์˜๋“ค์ด ๋ฐ”๋กœ find, findOne, update, delete ๊ฐ™์€ ํ•จ์ˆ˜๋“ค์ด๋‹ค.
  • TypeORM์„ ์ง€์›ํ•  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋“ค ์€ ์ด ๋ฃฐ์— ๋งž์ถฐ์„œ ๊ฐ ์‹œ์Šคํ…œ์˜ ์ฟผ๋ฆฌ๋ฅผ ์™„์„ฑํ•˜๋ฉด ๋œ๋‹ค.
  • TypeORM์ด ๊ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์˜์กดํ•ด์•ผํ–ˆ๋˜ ์ƒํ™ฉ์—์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋“ค์ด TypeORM ์— ์ •์˜๋œ ๋ฃฐ ์— ์˜์กดํ•˜๋Š” ์ƒํ™ฉ์ด ๋œ๋‹ค.
  • ์ด๊ฒŒ ๋ฐ”๋กœ Dependency Inversion ์ด๋‹ค

2.9 Dependency Inversion

fastcam-architecture_51-6


3. Layered Architecture

Layered Architecture๋Š” ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ์—ฌ๋Ÿฌ๊ฐœ์˜ ๋ ˆ์ด์–ด๋กœ ๋‚˜๋ˆ„๋Š” ์„ค๊ณ„๋‹ค.

  • ๊ฐ ๋ ˆ์ด์–ด๋ณ„๋กœ ํŠนํ™”๋œ ์˜์—ญ์„ ๋‹ด๋‹นํ•œ๋‹ค.
  • ๋ชจ๋“  ๋ ˆ์ด์–ด๋Š” ๋ฐ”๋กœ ์•„๋ž˜์˜ ๋ ˆ์ด์–ด์—๋งŒ ์˜์กดํ•œ๋‹ค.
  • ๋ ˆ์ด์–ด๋ฅผ ์–ด๋–ป๊ฒŒ ๋ช‡๊ฐœ๋กœ ๋‚˜๋ˆŒ์ง€์— ๋Œ€ํ•œ ์ •๋‹ต์€ ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค.
    • (ํ•˜์ง€๋งŒ ์–ด๋А์ •๋„ ํ‹€์€ ์กด์žฌํ•œ๋‹ค..!)

fastcam-architecture_51-7

(1) Presentation Layer๋Š” ์ง์—ญ์ ์œผ๋กœ ํ•ด์„ ํ–ˆ์„๋•Œ UI๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

  • ํ•˜์ง€๋งŒ ์•„ํ‚คํ…์ฒ˜๋Š” ์–ด๋–ค ๋ฌธ๋งฅ์ด๋“  ์ ์šฉ ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋ƒฅ ์ตœ์ „๋ฐฉ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋œ๋‹ค.
  • ์ฆ‰, NestJS์˜ ๋ฌธ๋งฅ์—์„œ๋Š” Controller๊ฐ€ ๋œ๋‹ค.
1
@Controller('orders')
2
export class OrderController {
3
constructor(private readonly orderService: OrderService) {}
4
5
@Post()
6
async createOrder(@Body() createOrderDto: CreateOrderDto) {
7
return this.orderService.createOrder(createOrderDto);
8
}
9
10
@Get(':id')
11
async getOrder(@Param('id') id: string) {
12
return this.orderService.getOrder(id);
13
}
14
}

(2) Business Layer๋Š” ์‹ค์ œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๋‹ด๋‹นํ•˜๋Š” ์˜์—ญ์ด๋‹ค.

  • โ€œ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์งโ€์€ ๋ง ๊ทธ๋Œ€๋กœ โ€œ๋น„์ฆˆ๋‹ˆ์Šคโ€์˜ โ€œ๋กœ์งโ€
  • ์ฆ‰, ํ˜„์‹ค ์„ธ๊ณ„์˜ ์กด์žฌํ•˜๋Š” ๋ฌธ์ œ๋“ค์„ ํ•ด๊ฒฐํ•˜๋Š” ๋กœ์ง์ด๋ผ๊ณ  ์ƒ๊ฐ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • NestJS์—์„œ๋Š” Service๊ฐ€ ํ•ด๋‹น๋œ๋‹ค.
1
@InJectable()
2
export class OrderService {
3
constructor(
4
private readonly orderRepository: OrderRepository,
5
private readonly productRepository: ProductRepository,
6
) {}
7
8
async createOrder(createOrderDto: CreateOrderDto) {
9
const productPrices = await this.productRepository.getProductPrices();
10
11
const order = new Order(createOrderDto.customrId, createOrderDto.items);
12
const total = order.calculateTotal(productPrices);
13
14
await this.orderRepository.save(order);
15
16
return { message: 'Order created successfully', orderId: order.id, total };
17
}
18
19
async getOrder(orderId: string) {
20
return this.orderRepository.findById(orderId);
21
}
22
}

(3) Persistence Layer๋Š” ์ง์—ญํ•˜๋ฉด ์˜์†์„ฑ ๋ ˆ์ด์–ด๋ผ๊ณ  ๋ถ€๋ฅผ ์ˆ˜ ์žˆ๋‹ค.

  • โ€œ์˜์†์„ฑโ€์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์˜๋ฏธํ•˜๋Š”๊ฑธ๋กœ ์ƒ๊ฐ ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ,
  • ์ด ์ƒํ™ฉ์—์„œ๋Š” Database์™€ ์—ฐ๋™ํ•˜๋Š” ๋ ˆ์ด์–ด๋‹ค.
  • ๋งŒ์•ฝ์— Database Layer๊ฐ€ ๋”ฐ๋กœ ์—†์—ˆ๋‹ค๋ฉด ๋‘ ํฌ์ง€์…˜์„ ๋ชจ๋‘ ๋งก์„ ์ˆ˜ ๋„ ์žˆ๋‹ค.
1
@InJectable()
2
export class OrderRepository {
3
constructor(
4
@InjectRepository(OrderEntitiy)
5
private readonly repository: Repository<OrderEntity>
6
) {}
7
8
async save(order: Order): Promise<void> {
9
const orderEntity = this.repository.create({
10
id: order.id,
11
customerId: order.customerId,
12
items: JSON.stringify(order.items),
13
createdAt: order.createdAt,
14
})
15
await this.repository.save(orderEntity)
16
}
17
18
async findById(orderId: string): Promise<Order | null> {
19
const orderEntity = await this.repository.findOneBy({id: orderId})
20
if (!orderEntity) return null
21
22
return new Order(
23
orderEntity.customerId,
24
JSON.parse(orderEntity.items),
25
)
26
}
27
}

(4) DatabaseLayer๋Š” ๋ง ๊ทธ๋Œ€๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์˜์—ญ์ด๋‹ค.

  • e.g. Postgres, MongoDB, MySQL

3.1 Layered Architecture์˜ ๋ฌธ์ œ

  • ๋ชจ๋“  ์•„ํ‚คํ…์ฒ˜์˜ ๊ณตํ†ต ๊ด€์‹ฌ์‚ฌ๋Š” โ€œ์˜์กด์„ฑโ€์ด๋‹ค. ์–ด๋–ค ๋ฐฉํ–ฅ์œผ๋กœ ์˜์กด์„ฑ์ด ์ „ํŒŒ๋˜๊ณ  ์žˆ๋Š”์ง€๊ฐ€ ๋งค์šฐ ์ค‘์š”ํ•˜๋‹ค.
  • Layered Architecture๋Š” ์œ„์—์„œ ์•„๋ž˜๋กœ ์˜์กดํ•˜๋Š” ๊ตฌ์กฐ์ด๋‹ค.
    • Top Down ๋ฐฉ์‹์ด ์‚ฌ๋žŒ์—๊ฒŒ ๊ฐ€์žฅ ์ž์—ฐ์Šค๋Ÿฌ์šด ๊ตฌํ˜„์ด๊ธฐ ๋•Œ๋ฌธ์—,
    • ํ˜„๋Œ€ ์†Œํ”„ํŠธ์›จ์–ด์—์„œ Layered Architecture๋ฅผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋งŽ์ด ์‚ฌ์šฉํ•˜๊ฒŒ ๋œ๋‹ค.
  • Layered Architecture๋Š” ๊ฒฐ๊ตญ ๋ชจ๋“  ๋ ˆ์ด์–ด๊ฐ€ ๊ฐ€์žฅ ์•„๋ž˜์— ์˜์กดํ•˜๊ฒŒ ๋˜๊ธฐ ๋•Œ๋ฌธ์—,
    • ์†Œํ”„ํŠธ์›จ์–ด ์„ค๊ณ„๋ฅผ ํ• ๋•Œ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ค๊ณ„๋ถ€ํ„ฐ ์ƒ๊ฐํ•˜๊ฒŒ ๋œ๋‹ค.
    • ์šฐ๋ฆฌ๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœ ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ์ฒ˜์Œ ๋งŒ๋“ค๋•Œ๋ฅผ ์ƒ๊ฐํ•ด๋ณด์ž.
    • ๊ฐ€์žฅ ๋จผ์ € ์ƒ๊ฐํ•˜๋Š”๊ฑด โ€œํ…Œ์ด๋ธ” ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค์ง€?โ€๋‹ค.
  • ์—ฌ๊ธฐ์„œ ์˜๋ฌธ์ด ์ƒ๊ธฐ๊ฒŒ ๋œ๋‹ค. ์†Œํ”„ํŠธ์›จ์–ด๊ฐ€ ํ’€์–ด๋‚ด๋ ค๋Š” ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ฌธ์ œ๊ฐ€ Business Logic
    • ์ฆ‰, Business Layer์— ์žˆ๋Š” ๋ฌธ์ œ๋“ค์ธ๋ฐ ์ด ๋ถ€๋ถ„์ด ๊ณผ์—ฐ ์™ธ๋ถ€์ ์ธ ์š”์ธ์— ์˜ํ–ฅ์„ ๋ฐ›๊ฒŒ๋˜๋Š”๊ฒŒ ๋งž๋Š”๊ฒƒ์ธ๊ฐ€?
  • ์ด๊ฒŒ ์ž˜๋ชป๋๋‹ค ์ƒ๊ฐํ•ด์„œ ๋งŒ๋“ค์–ด๋‚ธ ์•„ํ‚คํ…์ฒ˜๊ฐ€ Clean Architecture์™€ Hexagonal Architecture๋‹ค.
    • ์ ˆ๋Œ€๋กœ ์ •๋‹ต์€ ์—†๋‹ค.
    • Layered Architecture๋Š” ๋ˆ„๊ตฌ๋‚˜ ์ง๊ด€์ ์œผ๋กœ ์ดํ•ด ํ•  ์ˆ˜ ์žˆ๊ณ  ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑ ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ํ•˜์ง€๋งŒ Clean Architecture ์™€ Hexagonal Architecture๋Š” ์‚ฌ๊ณ  ๋ฐฉ์‹๋ถ€ํ„ฐ ๋ฐ”๊ฟ”์•ผํ•œ๋‹ค.
    • ๊ฒฐ๊ตญ ์ธ๋ ฅ ํŠธ๋ ˆ์ด๋‹ ๋น„์šฉ๋„ ๋Š˜์–ด๋‚˜๊ณ  ๋‹จ๊ธฐ์ ์œผ๋ก  ๊ฐœ๋ฐœ ์‹œ๊ฐ„๋„ ๋Š˜์–ด๋‚œ๋‹ค.
    • ์ ˆ๋Œ€์ ์ธ ๊ฐ•์ž๋Š” ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค.
    • ์šฐ๋ฆฌ๊ฐ€ MSA๋ฅผ ๋ฐฐ์šฐ๋ฉฐ ๊นจ์šฐ์ณค๋˜ ์ ๋“ค์„ ๋˜๋Œ์•„๋ณด์ž

4. Domain Driven Design(DDD) & Polyrepo MSA

4.1 Monorepo vs Polyrepo

  • Monorepository MSA๋Š” ํ˜„์žฌ ์šฐ๋ฆฌ๊ฐ€ ํ•˜๊ณ  ์žˆ๋Š”๊ฒƒ์ฒ˜๋Ÿผ ํ•˜๋‚˜์˜ ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋กœ ์—ฌ๋Ÿฌ๊ฐœ์˜ Microservice๋ฅผ ๊ฐœ๋ฐœํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.
  • Polyrepository MSA๋Š” ๊ฐ๊ฐ Microservice๋ฅผ ์›ํ•˜๋Š” ๊ธฐ์ˆ ์Šคํƒ์„ ์‚ฌ์šฉํ•ด์„œ ์ž์œ ๋กญ๊ฒŒ ๊ฐœ๋ฐœํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.
    • ๊ทธ ์–ด๋–ค ์ œ์•ฝ๋„ ์กด์žฌํ•˜์ง€ ์•Š๊ณ  ์šฐ๋ฆฌ๊ฐ€ ์ง€๊ธˆ๊นŒ์ง€ ๋ฐฐ์›Œ์˜จ ํ†ต์‹  ๋ฐฉ๋ฒ•๋“ค๋กœ ํ”„๋กœ์ ํŠธ๋ผ๋ฆฌ ํ†ต์‹ ํ•œ๋‹ค.
  • ํšŒ์‚ฌ์— ์ธ์›์ด ๋งŽ์•„์งˆ์ˆ˜๋ก Polyrepository ๋ฐฉ์‹์œผ๋กœ ๊ฐœ๋ฐœ ํ•  ์ˆ˜ ๋ฐ–์— ์—†๋‹ค.
    • ๋Œ€๋ถ€๋ถ„์˜ ํฐ ๊ธฐ์—…๋“ค์ด ์ด๋ ‡๊ฒŒ ๊ฐœ๋ฐœํ•˜๊ณ  ์žˆ๋‹ค.
    • ํŒ€์ด ๊ฐ€์žฅ ์ž˜ ๋‹ค๋ฃจ๋กœ ๊ฐ๊ฐ Microservice์— ๊ฐ€์žฅ ์ ํ•ฉํ•œ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•ด์„œ ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ชจ๋“  ํŒ€์ด ์ „๋ถ€ ์ž์œ ๋กญ๊ฒŒ ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•˜๋‹ค๋ณด๋ฉด Microservice๋ฅผ ๊ธฐํšํ•˜๊ธฐ์œ„ํ•œ ์ผ์ข…์˜ ์•ฝ์†๊ณผ ์‹œ์Šคํ…œ์ด ํ•„์š”ํ•˜๋‹ค.
  • ๋‹ค์–‘ํ•œ ๋ฐฉ๋ฒ•์ด ์กด์žฌํ•˜์ง€๋งŒ Domain Driven Design์ด ๋งค์šฐ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋œ๋‹ค

4.2 Domain Driven Design!?

  • ๋ณต์žกํ•œ ๋น„์ฆˆ๋‹ˆ์Šค์˜ ์š”๊ตฌ์‚ฌํ•ญ์„ โ€œ๋„๋ฉ”์ธโ€์— ์ง‘์ค‘ํ•ด์„œ ์„ค๊ณ„ํ•˜๋Š” ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ โ€œ์ ‘๊ทผ๋ฒ•โ€์ด๋‹ค.
  • ๋น„์ฆˆ๋‹ˆ์Šค ์š”๊ตฌ์‚ฌํ•ญ์„ ์ถฉ์กฑํ•˜๋ฉด์„œ โ€œ์œ ์ง€๋ณด์ˆ˜โ€ ๊ฐ€๋Šฅํ•˜๊ฒŒ ์‹œ์Šคํ…œ์„ ์„ค๊ณ„ํ•˜๋Š” ๋ฐฉ๋ฒ•๋ก ์ด๋‹ค.
  • Ubiquitous Language๋ฅผ ๋งค์šฐ ๊ฐ•์กฐํ•œ๋‹ค.
    • ๊ฐœ๋ฐœ์ž๋งŒ ์ดํ•ด ํ•  ์ˆ˜ ์žˆ๋Š” ์˜์—ญ์„ ์ตœ์†Œํ™” ํ•˜๊ณ ,
    • โ€œ๋„๋ฉ”์ธ ์ „๋ฌธ๊ฐ€โ€์™€ ํ•จ๊ป˜ ์†Œํ”„ํŠธ์›จ์–ด๋ฅผ ์„ค๊ณ„ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋””์ž์ธ ๋˜์—ˆ๋‹ค.
  • ํฐ ๊ทธ๋ฆผ์„ ์„ค๊ณ„ํ•˜๋Š” Strategic Design๊ณผ Tactical Design์œผ๋กœ ๋‚˜๋‰œ๋‹ค.
  • Strategic Design์€ โ€œ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š”๋ฒ•โ€ ๋ณด๋‹ค ๋„๋ฉ”์ธ์„ ์„ค๊ณ„ํ•˜๊ณ ,
    • ๊ฐœ๋ฐœ์ž๊ฐ€ ์•„๋‹Œ ์‚ฌ๋žŒ๋“ค์ด ์„ค๊ณ„์— ์ฐธ๊ฐ€ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฃฐ์„ ์ •์˜ํ•˜๊ณ  ์žˆ๋‹ค.
  • Tactical Design์€ DDD ๊ธฐ๋ฒ•์— ์˜ํ•ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•๋ก ์„ ๋‹ค๋ฃจ๊ณ  ์žˆ๋‹ค.
  • Strategic Design์œผ๋กœ ํฐ ๊ทธ๋ฆผ์„ ๊ทธ๋ฆฌ๊ณ  Tactical Design์œผ๋กœ ์„ธ๋ถ€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.
  • Clean Architecture, Hexagonal Architecture์˜ โ€œ๋„๋ฉ”์ธโ€์„ ์ž˜ ๋””์ž์ธ ํ•˜๊ธฐ ์œ„ํ•ด ํƒ„์ƒํ•œ๊ฒŒ ์•„๋‹ˆ๋‹ค.
    • ๊ตณ์ด ๋”ฐ์ง€์ž๋ฉด Domain Driven Design์ด ํ›จ์”ฌ ๋จผ์ € ๊ณต๊ฐœ๋˜์—ˆ๋‹ค.
  • Clean Architecture, Hexagonal Architecture, Microservice Architecture์ฒ˜๋Ÿผ
    • โ€œ๋„๋ฉ”์ธโ€์„ ์ค‘์‹œํ•˜๋Š” ์•„์ผ€ํ‹ฑ์ฒ˜๊ฐ€ ์ธ๊ธฐ๋ฅผ ๋Œ๋ฉฐ DDD๊ฐ€ ๋”์šฑ ๊ฐ๊ด‘์„ ๋ฐ›๊ฒŒ ๋๋‹ค.
  • ๋งŒ๋ณ‘ํ†ต์น˜์•ฝ์ด ์•„๋‹ˆ๋‹ˆ ๋งˆ์Œ๋Œ€๋กœ ๋จน์ง€๋Š” ๋ง์ž

4.3 Strategic Design

  • ์†Œํ”„ํŠธ์›จ์–ด ์„ค๊ณ„๋ฅผ ๊ฐ€์žฅ ๋†’์€ ์œ„์น˜์—์„œ ํฐ ๊ทธ๋ฆผ์„ ๊ธฐํšํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.
  • Ubiquitous Language๋ฅผ ์ •๋ฆฝํ•˜๋Š” ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์Šคํ…Œ์ด์ง€๋‹ค.
  • ๋„๋ฉ”์ธ์„ ์ฝ”์–ด ๋„๋ฉ”์ธ๊ณผ ์„œ๋ธŒ ๋„๋ฉ”์ธ์œผ๋กœ ๋‚˜๋ˆˆ๋‹ค.
    • ์ฝ”์–ด ๋„๋ฉ”์ธ์€ ํ•œ ๋„๋ฉ”์ธ์˜ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋„๋ฉ”์ธ์ด๋‹ค.
    • ์„œ๋ธŒ ๋„๋ฉ”์ธ์€ ์ฝ”์–ด๋„๋ฉ”์ธ ๋งŒํผ ์ค‘์š”ํ•œ ๋„๋ฉ”์ธ์€ ์•„๋‹ˆ์ง€๋งŒ ํ•„์ˆ˜์ ์ธ ๋„๋ฉ”์ธ์ด๋‹ค.
  • ์ด์™ธ์— ์ œ๋„ˆ๋ฆญ ๋„๋ฉ”์ธ ๋“ฑ ๋‹ค๋ฅธ ๋ถ„๋ฅ˜๋„ ์กด์žฌํ•œ๋‹ค.

fastcam-architecture_51-8

fastcam-architecture_51-9


4.4 Tactical Design

  • Tactical Design์€ Strategic Design ๋ณด๋‹ค ๋”์šฑ Low Level ๊ด€์ ์—์„œ ์„ค๊ณ„๋ฅผ ๋ฐ”๋ผ๋ณธ๋‹ค.
    • ์ฝ”๋“œ๋ฅผ ์–ด๋–ป๊ฒŒ ์ž‘์„ฑํ•˜๋ฉด ํšจ์œจ์ ์ผ์ง€ ์•Œ๋ ค์ค€๋‹ค.
  • Entity โ†’ Mutableํ•œ ๋ฐ์ดํ„ฐ๋‹ค.
    • ๊ผญ ID ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ–๊ณ  ์žˆ์œผ๋ฉฐ ID๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ๋‹ค๋ฅธ Entity๋กœ ๊ฐ„์ฃผ๋˜์ง€๋งŒ,
    • ๋‹ค๋ฅธ ํ”„๋กœํผํ‹ฐ๊ฐ€ ๋ณ€๊ฒฝ๋์„ ๋•Œ๋Š” ๊ฐ™์€ Entity๋กœ ์ธ์‹ํ•œ๋‹ค.
  • Value Object(VO) โ†’ ID๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋‹ค. ๊ฐ’์„ ๊ธฐ์ค€์œผ๋กœ ๊ฐ™์€์ง€ ๋‹ค๋ฅธ์ง€ ํŒ๋‹จํ•œ๋‹ค.
    • ์˜ˆ๋ฅผ๋“ค์–ด ์ด๋ฉ”์ผ์€ ๊ฐ’ ์ž์ฒด๊ฐ€ ์ •์ฒด์„ฑ์„ ๋ถ€๊ธฐ ๋•Œ๋ฌธ์— ID๊ฐ€ ๋”ฐ๋กœ ํ•„์š”์—†์œผ๋ฉฐ,
    • A๊ฐ์ฒด์˜ test@codefactory.ai์™€ B ๊ฐ์ฒด์˜ test@codefactory.ai๋Š” ๊ฐ™์€ ๊ฐ’์œผ๋กœ ์ธ์‹ํ•œ๋‹ค.
    • Mutable์ธ Entity์™€ ๋‹ค๋ฅด๊ฒŒ Immutable์ด๋‹ค.
  • Aggregate โ†’ Entity์™€ Value Object๋“ค์„ ์†Œ์œ ํ•˜๋Š” ๊ฐ์ฒด๋‹ค. Aggregate ๋‚ด๋ถ€์— ์žˆ๋Š”
  • Repositories โ†’ ์šฐ๋ฆฌ๊ฐ€ ์•Œ๊ณ ์žˆ๋Š” Repository์™€ ๋™์ผํ•˜๋‹ค. ๋ฐ์ดํ„ฐ ์˜์†์„ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๋Š” ๊ฐœ๋…์ด๋‹ค.
  • Services โ†’ ์—ฌ๋Ÿฌ๊ฐœ์˜ Aggregate๊ฐ€ ํ•จ๊ป˜ ์ž‘๋™ํ•ด์•ผํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ• ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.

4.4 Entities & Value Objects

fastcam-architecture_51-10


4.5 Aggregate & Transactional Boundary

fastcam-architecture_51-11

Transactional Boundary โ†’ Transactional Boundary์— ์†ํ•˜๋Š” ๊ฐ์ฒด๋Š” ํ•˜๋‚˜์˜ Transaction์œผ๋กœ ๋ณ€ํ™”๊ฐ€ ์ผ์–ด๋‚œ๋‹ค.


4.6 Repositories & Services

fastcam-architecture_51-12


5. ๋„๋ฉ”์ธ์ด๋ž€?

5.1 Microservice๋ฅผ ์–ด๋–ป๊ฒŒ ๋‚˜๋ˆ ์•ผํ•˜๋Š”๊ฐ€?

  • Microservice๋ฅผ ๋„๋Œ€์ฒด ์–ด๋–ค ๋‹จ์œ„๋กœ ๋‚˜๋ˆ„๋ฉด ๋˜๋Š”๊ฑธ๊นŒ?
  • Microservice์˜ ๋ชฉ์ ์€ ์„œ๋น„์Šค๊ฐ„์˜ ์˜์กด์„ฑ์„ ์ค„์ด๊ณ  ํšจ์œจ์ ์œผ๋กœ ๋…๋ฆฝ์  ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•˜๊ธฐ ์œ„ํ•จ์ด๋‹ค.
  • ๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•ด์„œ๋Š” ๊ฐ€์žฅ ์ž‘์€ ๋…ผ๋ฆฌ์  ๋‹จ์œ„๋กœ ์„œ๋น„์Šค๋ฅผ ๋ถ„ํ•ด ํ•  ์ˆ˜ ์žˆ์œผ๋ฉด ๊ฐ€์žฅ ํšจ์œจ์ ์ธ MSA๋ฅผ ์šด์˜ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ด ๊ฐ€์žฅ ์ž‘์€ ๋…ผ๋ฆฌ์  ๋‹จ์œ„๋ฅผ ์šฐ๋ฆฌ๋Š” ํ”ํžˆ โ€œ๋„๋ฉ”์ธโ€์ด๋ผ ๋ถ€๋ฅธ๋‹ค.
  • ๋„๋ฉ”์ธ์„ ์ค‘์‹ฌ์œผ๋กœ ๊ฐœ๋ฐœ์„ ํ•˜๊ฒŒ๋˜๋Š” โ€œDomain Driven Designโ€ (DDD๋Š” ์ข€ ๋‚˜์ค‘์— ๋ฐฐ์šฐ๋„๋ก ํ•˜์ž)์ด๋‚˜,
    • Clean Architecture ๋“ฑ์— ์˜ํ•˜๋ฉด ๋„๋ฉ”์ธ์€ ๋น„์ฆˆ๋‹ˆ์Šค์˜ ์ค‘์‹ฌ ๊ธฐ๋Šฅ์ด ๋˜๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง, ํ•ด๊ฒฐํ•˜๋ ค๋Š” ์ค‘์‹ฌ๋˜๋Š” ๋ฌธ์ œ ๋“ฑ์œผ๋กœ ํ‘œํ˜„๋œ๋‹ค.
  • ๋ณดํ†ต ์ด๋Ÿฐ ๊ฐœ๋…์€ ์˜์–ด์˜ ์ง์—ญ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ •์˜๊ฐ€ ๋ณต์žกํ•˜๊ฒŒ ๋А๊ปด์ง€์ง€๋งŒ ์‚ฌ์‹ค ํฌ๊ฒŒ ์–ด๋ ต์ง€ ์•Š๋‹ค.
    • ๋‹ค์Œ ์Šฌ๋ผ์ด๋“œ์—์„œ ์˜ˆ์ œ๋ฅผ ๋ด๋ณด๋„๋ก ํ•ด๋ณด์ž

5.2 ์˜จ๋ผ์ธ ์‡ผํ•‘๋ชฐ ์˜ˆ์ œ

fastcam-architecture_51-13

  • ๊ฐ ๋„๋ฉ”์ธ์€ ์ฝ”์–ด ๋น„์ฆˆ๋‹ˆ์Šค ๊ธฐ๋Šฅ์„ ๋‹ด๋‹นํ•œ๋‹ค.
  • ๊ฐœ๋ฐœ์ž๊ฐ€ ์•„๋‹Œ ์ผ๋ฐ˜ ์‚ฌ๋žŒ์ด ํ•œ ๋„๋ฉ”์ธ์˜ ๋ช…์นญ์„ ๋ดค์„๋•Œ ๋ฌด์Šจ ์—ญํ• ์„ ํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ๊ฒŒ ๋ถ„๋ฆฌ ํ•ด์•ผํ•œ๋‹ค.
    • (Domain Expert:DDD)
  • ์ฒ˜์Œ๋ถ€ํ„ฐ ์™„๋ฒฝํžˆ ๋„๋ฉ”์ธ์„ ๋‚˜๋ˆŒ ํ•„์š”๊ฐ€ ์—†๋‹ค. ๊ฐœ๋ฐœํ•ด๊ฐ€๋ฉด์„œ ๋…๋ฆฝ ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ๋ถ€๋ถ„๋“ค์„ ๋ถ„๋ฆฌํ•˜๋ฉด ๋œ๋‹ค.
    • (Shipping ๋„๋ฉ”์ธ์— ์ผ๋ฐ˜ ํƒ๋ฐฐ, ํ•ญ๊ณต ํƒ๋ฐฐ๋ฅผ ๊ฐ™์ด ๊ตฌํ˜„ํ•˜๋‹ค๊ฐ€ ์„œ๋กœ ๊ด€๋ จ์„ฑ์ด ๋ฉ€์–ด์ง€๊ณ 
    • ๋„ˆ๋ฌด ์ปค์ง€๋ฉด ๋‚˜์ค‘์— ๋‚˜๋ˆ ๋„ ๋œ๋‹ค.)
  • ๋„๋ฉ”์ธ์„ ๋‹ค๋ฃฐ๋•Œ๋Š” ๊ทธ ๋„๋ฉ”์ธ ํ•˜๋‚˜์˜ ๊ด€์ ์—์„œ ์ž‘์—…์„ ํ•œ๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด, Order์—์„œ Customer ๊ณ ๊ฐ์ด ์กด์žฌํ•˜๊ณ  Payment์— Payer๊ฐ€ ์กด์žฌํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ๋‘˜์€ ๊ฐ™์€ ์‚ฌ์šฉ์ž๋ฅผ ์ง€์นญํ•˜์ง€๋งŒ ์„œ๋กœ ๋‹ค๋ฅธ ๋„๋ฉ”์ธ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Š” ์ค‘๋ณต์ด ์•„๋‹ˆ๋‹ค.

6. CQRS Pattern

6.1 CQRS Pattern์ด๋ž€?

fastcam-architecture_51-14

  • CQRS Pattern์€ Command Query Responsibility Segregation์ด๋‹ค.
  • ์„ธ์ƒ์˜ API๋Š” CRUD๋กœ ๋‚˜๋‰œ๋‹ค (X) โ†’ ์„ธ์ƒ์˜ API๋Š” โ€œ๋ช…๋ นโ€๊ณผ โ€œ์กฐํšŒโ€๋กœ ๋‚˜๋‰œ๋‹ค. (O)

6.2 CQRSโ€ฆ ๊ตณ์ด ์™œ?

  • Command์™€ Query๊ฐ€ ๋…๋ฆฝ์ ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋…๋ฆฝ์ ์œผ๋กœ ํ™•์žฅ ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด, ์‡ผํ•‘๋ชฐ ์•ฑ์„ ๋งŒ๋“ ๋‹ค๋ฉด ์กฐํšŒ ์š”์ฒญ์ด ์••๋„์ ์œผ๋กœ ๋งŽ๋‹ค.
    • ์กฐํšŒ ๊ธฐ๋Šฅ๋งŒ ๋…๋ฆฝ์ ์œผ๋กœ ํ™•์žฅํ•˜๊ณ  ๋ช…๋ น ์š”์ฒญ (์ฃผ๋ฌธ๋“ฑ)์€ ํ™•์žฅํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค.
  • ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ๊ฐ๊ฐ ์ตœ์ ํ™”๋œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์‚ฌ์šฉ ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ํŠนํžˆ, ์กฐํšŒ ๊ธฐ๋Šฅ์€ ๋ฐ์ดํ„ฐ๋ฅผ denormalize ํ•œ ์ƒํƒœ๋กœ ์ €์žฅํ•ด๋‘๊ณ ,
    • ์กฐํšŒ ์š”์ฒญ์ด ์žˆ์„๋•Œ ๋”ฐ๋กœ join๋“ฑ์˜ ๋ณต์žกํ•œ ์ฟผ๋ฆฌ ์—†์ด ์ฆ‰๊ฐ์ ์ธ ์‘๋‹ต์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Command์™€ Query์— ๋…๋ฆฝ์ ์ธ ๋ณด์•ˆ์„ ์„ค์ •ํ•ด์„œ ๊ฐœ๋ฐœ ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • Query๋Š” ์ƒ๋Œ€์ ์œผ๋กœ ๋ณด์•ˆ์„ ์•ฝํ•˜๊ฒŒ ์„ค์ •ํ•˜๊ณ  Command๋Š” ์„ธ์„ธํ•˜๊ฒŒ ๋ณด์•ˆ ์„ค์ •์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Microservice๋ฅผ ์šด์˜ํ–ˆ์„๋•Œ์˜ ์žฅ์ ๊ณผ ๋‹จ์ ์ด ๊ฑฐ์˜ ์ƒ์†๋œ๋‹ค.

6.3 CQRS

fastcam-architecture_51-15


6.4 Event Driven Architecture

fastcam-architecture_51-16