topic난이도 · 약 20

레이어드 · 헥사고날 · 클린 아키텍처

"도메인을 프레임워크·DB로부터 격리" — 변화에 강한 코드 구조 3단 진화.

#레이어드#헥사고날#클린아키텍처#관심사분리
왜 배우는가

AI가 만든 코드가 "이 파일이 API고, 이 파일이 DB고, 이 파일이 비즈니스 규칙" 섞여있으면 리팩토링 지옥. 계층 분리 감각이 있으면 "이 부분은 도메인 레이어로 빼줘" 같은 지시가 가능.

모든 아키텍처의 공통 목표는 '관심사 분리(Separation of Concerns)'. 3단계로 진화한다.

스타일핵심 아이디어계층
레이어드 (N-Tier)위→아래 단방향UI → Application → Domain → Infrastructure
헥사고날 (Ports & Adapters)도메인을 중심, 외부는 '어댑터'외부(DB·API·UI) ↔ Ports ↔ 도메인
클린 (Uncle Bob)의존성은 안쪽으로만Entities ← Use Cases ← Adapters ← Frameworks

공통 원리 — 의존성 규칙. "외부(프레임워크·DB·UI)가 내부(비즈니스 규칙)를 의존하지, 반대로는 절대 아님." 이 한 줄이 클린 아키텍처의 핵심.

typescript
// ━━━ 나쁜 예: 모든 계층이 섞임 ━━━
// app/api/users/route.ts
export async function POST(req: Request) {
  const data = await req.json();
  if (!data.email.includes("@")) return new Response("bad", { status: 400 });
  const { rows } = await pg.query("INSERT INTO users ...", [data.email]);
  await sendWelcomeEmail(data.email);    // SMTP 호출
  return Response.json(rows[0]);
}
// → HTTP·검증·DB·이메일이 한 함수. 테스트 불가능, 재사용 불가.

// ━━━ 좋은 예: 계층 분리 ━━━

// domain/user.ts  (순수 도메인 — 어떤 DB·HTTP도 모름)
export class User {
  constructor(public email: string, public name: string) {
    if (!email.includes("@")) throw new Error("invalid email");
  }
}

// application/use-cases/register-user.ts
export async function registerUser(
  email: string, name: string,
  repo: UserRepository,
  notifier: Notifier,
): Promise<User> {
  const user = new User(email, name);
  await repo.save(user);
  await notifier.welcome(user);
  return user;
}

// infrastructure/db/postgres-user-repo.ts
export class PgUserRepository implements UserRepository {
  async save(u: User) { await pg.query("INSERT ...", [u.email, u.name]); }
}

// app/api/users/route.ts (얇은 HTTP 어댑터)
export async function POST(req: Request) {
  const body = await req.json();
  const user = await registerUser(body.email, body.name, pgRepo, smtpNotifier);
  return Response.json(user);
}

도메인 계층은 테스트가 쉬움(DB·네트워크 목킹 안 해도 됨). 나중에 Postgres → MongoDB로 바꿔도 use-case는 안 바뀐다.

현실 타협점. 바이브코더 대부분은 Next.js + Supabase. 풀 클린 아키텍처는 과함. 최소한 "도메인 로직은 route.ts 바깥의 순수 함수로" 규칙만 지켜도 70% 효과. AI에게 "이 비즈니스 로직을 lib/domain에 순수 함수로 분리" 지시로 자동화.

실기 드릴 1문항
check_circle실기 드릴 · OX

클린 아키텍처에서 도메인 계층이 데이터베이스 드라이버를 직접 import해도 된다.