Files
2nd/10_Wiki/Topics/Architecture/객체 지향 소프트웨어 아키텍처 설계.md
T
2026-05-10 22:08:15 +09:00

6.2 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-객체-지향-소프트웨어-아키텍처-설계 객체 지향 소프트웨어 아키텍처 설계 10_Wiki/Topics verified self
OO architecture
OOA/D
Object-Oriented Architecture
none A 0.9 applied
oop
architecture
design
ddd
2026-05-10 pending
language framework
python ddd

객체 지향 소프트웨어 아키텍처 설계

매 한 줄

"매 behavior + state 의 cohesive object 의 cluster". 매 OO architecture 의 system 의 collaborating object 의 graph 의 model — 매 modern stack 의 DDD + Clean/Hexagonal + SOLID 의 layered.

매 핵심

매 Layered architecture

  • Domain: 매 entity, value object, aggregate root.
  • Application: 매 use case, 매 thin orchestration.
  • Infrastructure: 매 DB, queue, external API adapter.
  • Interface: 매 HTTP, CLI, gRPC.
  • Rule: 매 dependency 의 inward 의 only (Clean Architecture).

매 Building blocks (DDD)

  • Entity: identity 의 have (User#42).
  • Value object: identity 의 X, immutable (Money(100, USD)).
  • Aggregate: consistency boundary, 매 root 의 only 의 외부 의 expose.
  • Repository: aggregate 의 persist abstraction.
  • Service: stateless behavior 의 cross-aggregate.
  • Event: aggregate state change 의 broadcast.

매 Design principles

  • SOLID: SRP, OCP, LSP, ISP, DIP.
  • Composition over inheritance: 매 has-a > is-a.
  • Tell, don't ask: 매 behavior 의 object 의 push.
  • Law of Demeter: 매 don't talk to strangers.

매 응용

  1. E-commerce checkout (Order aggregate).
  2. Banking transfer (Account + Transaction).
  3. SaaS multi-tenant (Tenant boundary).
  4. Game state machine.

💻 패턴

Aggregate root + repository (Python)

from dataclasses import dataclass, field
from decimal import Decimal
from uuid import UUID, uuid4

@dataclass(frozen=True)
class Money:                                # value object
    amount: Decimal
    currency: str
    def __add__(self, o: "Money") -> "Money":
        if self.currency != o.currency: raise ValueError
        return Money(self.amount + o.amount, self.currency)

@dataclass
class OrderLine:
    sku: str
    qty: int
    price: Money

class Order:                                # aggregate root
    def __init__(self, id: UUID, lines: list[OrderLine]):
        self.id = id
        self._lines = lines
        self._events: list = []

    def add_line(self, line: OrderLine) -> None:
        if any(self.id == "shipped" for l in self._lines): raise RuntimeError
        self._lines.append(line)
        self._events.append(("LineAdded", line))

    def total(self) -> Money:
        return sum((l.price for l in self._lines), Money(Decimal(0), "USD"))

class OrderRepo:                            # abstraction (port)
    def get(self, id: UUID) -> Order: ...
    def save(self, order: Order) -> None: ...

Hexagonal port + adapter

from typing import Protocol

class PaymentGateway(Protocol):             # port
    def charge(self, amount: Money, token: str) -> str: ...

class StripeAdapter:                        # adapter
    def charge(self, amount: Money, token: str) -> str:
        return stripe.Charge.create(amount=int(amount.amount * 100), source=token).id

class CheckoutService:                      # application
    def __init__(self, orders: OrderRepo, payments: PaymentGateway):
        self._orders, self._payments = orders, payments

    def checkout(self, order_id: UUID, token: str) -> str:
        order = self._orders.get(order_id)
        return self._payments.charge(order.total(), token)

Domain event + handler

from blinker import signal
order_placed = signal("order_placed")

@order_placed.connect
def send_email(sender, order: Order):
    mailer.send(order.customer_email, "Receipt", order.total())

Strategy via composition

class ShippingPolicy(Protocol):
    def cost(self, order: Order) -> Money: ...

class FlatRate:
    def cost(self, order): return Money(Decimal(5), "USD")

class WeightBased:
    def cost(self, order): return Money(Decimal(order.weight() * 0.5), "USD")

# inject, not inherit
class Cart:
    def __init__(self, shipping: ShippingPolicy): self._shipping = shipping

Bounded context boundary

[Sales Context]                [Shipping Context]
  Order(customer, lines)  --→    Shipment(orderId, address)
  (own model, own DB)            (own model, own DB)
              ↕                            ↕
        Anti-Corruption Layer (translate DTOs)

매 결정 기준

상황 Approach
Complex business rules DDD aggregate
CRUD + thin logic Active Record / transaction script
Multi-team scale Bounded context split
External I/O isolation Hexagonal port/adapter
Cross-cutting policy Decorator / middleware

기본값: Clean Architecture + DDD lite + Hexagonal port.

🔗 Graph

🤖 LLM 활용

언제: aggregate boundary suggestion, code → DDD pattern mapping, layer violation detection. 언제 X: 매 over-engineering trivial CRUD — 매 LLM 의 DDD 의 over-prescribe 의 tendency, 의 push back.

안티패턴

  • Anemic domain: 매 getter/setter only data class + service 의 logic, 의 behavior 의 entity 의 push.
  • God aggregate: 매 한 aggregate 의 entire system, 의 split.
  • Leaky abstraction: 매 ORM model 의 domain 의 exposure, 의 separate.
  • Inheritance for reuse: 매 deep hierarchy, 의 composition.
  • Layer skipping: 매 controller → repository 직접, 의 application service 의 통과.

🧪 검증 / 중복

  • Verified (Evans "DDD" 2003, Vernon "Implementing DDD", Martin "Clean Architecture").
  • 신뢰도 A.

🕓 Changelog

날짜 변경
2026-05-08 Phase 1
2026-05-10 Manual cleanup — full OO architecture entry, DDD + Hexagonal patterns