본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 26. 20:38

Back to Code | Ep 02: Autopsy — 완벽해 보였던 거짓말

요약

AI가 생성한 코드가 겉보기에는 깔끔하지만, 과도한 외부 의존성으로 인해 테스트가 불가능한 문제를 다룹니다. 이를 해결하기 위해 비즈니스 로직과 인프라를 분리하는 육각형 아키텍처(Hexagonal Architecture) 도입 과정을 설명합니다.

핵심 포인트

  • AI 생성 코드가 비즈니스 로직과 인프라를 혼재시킬 위험성
  • 외부 의존성이 과도한 코드는 테스트 불가능한 코드임
  • 육각형 아키텍처를 통한 도메인과 어댑터의 분리
  • 포트와 어댑터 패턴을 활용한 테스트 용이성 확보

인공지능이 만들어낸 환상에서 깨어나 실제 엔지니어링으로 돌아가는 기업, LogiFlow의 15주간의 기술적 사투.

이야기 (The Story)

오전 9:00. 워룸 (War Room)의 분위기는 장례식장만큼이나 엄숙했습니다. 팀원들은 AI의 자랑이자 기쁨이었던 route-optimizer-v2 서비스의 리드 코더(Lead Coder), Emre 주변으로 모여들었습니다.

"코드는 깔끔합니다." Emre가 말했습니다. "변수명은 의미가 있고, JSDoc 주석은 완벽하며, 에러 핸들링 (Error Handling)도 곳곳에 적용되어 있습니다. 저는 AI에게 '프로덕션 레디 (Production-ready), 견고하고, 깔끔한 코드'를 작성하라고 프롬프트 (Prompt)를 입력했습니다."

스태프 엔지니어 (Staff Engineer) Defne가 테이블 위에 커피 머그잔을 내려놓았습니다.

"Emre, 이건 인프라 팀의 문제가 아니에요. 문제는 당신이 '비즈니스 로직 (Business Logic)'이라고 생각하는 것이 실제로는 **인프라 수프 (Infrastructure Soup)**라는 점입니다."

기술적 부검 (Technical Autopsy)

물류 산업의 가장 중요한 규칙은 다음과 같습니다: 만약 트럭이 위험물 (Hazmat)을 운송한다면, 터널을 통과할 수 없으며 법적으로 4시간마다 2시간의 휴식 시간을 가져야 합니다.

// AI가 생성한 "깔끔하지만" 아키텍처적으로 부패한 코드
export async function calculateHazmatRouteAndEta(
  truckId: string, destination: Coordinates
...

Defne가 화이트보드로 몸을 돌렸습니다. "이 코드를 테스트하고 싶다고 상상해 보세요. 단순히 '위험물 트럭의 ETA (Estimated Time of Arrival, 도착 예정 시간)에 2시간이 추가되었는가?'를 묻는 간단한 유닛 테스트 (Unit Test)를 하고 싶을 뿐입니다. 우리는 무엇을 해야 할까요?"

Emre가 대답했습니다: "Prisma를 모킹 (Mock)할 겁니다. Redis 클라이언트를 모킹할 겁니다. nock을 사용하여 Mapbox API를 가로챌 겁니다."

"비즈니스 규칙을 테스트하기 위해 3개의 서로 다른 외부 의존성 (External Dependencies)을 모킹해야 한다면, 그 코드는 테스트 불가능한 (Untestable) 코드입니다."

수술: 육각형 아키텍처 (Hexagonal Architecture)

Defne는 화이트보드에 세 개의 동심원을 그렸습니다:

  1. 가장 안쪽 원 (도메인 (Domain)): 순수한 비즈니스 규칙. 데이터베이스나 HTTP가 무엇인지 알지 못합니다.
  2. 중간 원 (애플리케이션 / 유스케이스 (Application / Use Cases)): 비즈니스 워크플로우를 오케스트레이션 (Orchestrate)합니다. "포트 (Ports)"를 사용합니다.
  3. 가장 바깥쪽 원 (어댑터 (Adapters)): Prisma, Redis, Mapbox. 이것들은 단지 어댑터일 뿐입니다.

1. 도메인 (Domain) — 순수 비즈니스 로직 (Pure Business Logic)

// domain/RoutingPolicy.ts
export interface RouteCalculation {
  durationInMinutes: number;
...

2. 포트 (Ports) — 인터페이스 (Interfaces)

// ports/Repositories.ts
export interface TruckRepository {
  findById(truckId: string): Promise<TruckProfile | null>;
...

3. 애플리케이션 유즈 케이스 (Application Use Case) — 오케스트레이터 (Orchestrator)

// application/CalculateHazmatRouteUseCase.ts
export class CalculateHazmatRouteUseCase {
  constructor(
...

에피소드 2에서 얻은 교훈 (Lessons from Episode 2)

1. 인프라 수프 (Infrastructure Soup): AI는 빠른 결과를 위해 비즈니스 로직(Domain)을 데이터베이스 쿼리 및 API 호출 내부에 포함시키는 경향이 있습니다.

2. 목킹 비용 (Mocking Cost): 비즈니스 규칙을 테스트하기 위해 3개 이상의 외부 의존성(external dependencies)을 목킹해야 한다면, _의존성 역전 원칙 (Dependency Inversion)_이 누락된 것입니다.

3. 육각형 아키텍처 (Hexagonal Architecture): AI가 가장 취약한 부분은

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0