DirectPath

주니어 개발자들을 위한 패턴 언어 - 복잡한 미로를 걷어내고 문제와 해결책 사이의 최단 거리를 찾는 법

The Story: The Maze of Indirection vs. The Straight Line

두 명의 개발자, 민수와 하나가 '사용자 이름 조회' 기능을 구현하고 있다.

민수의 설계 (The Maze): 민수는 "확장성"을 중요하게 생각했다.

  1. UserDTO를 정의한다.

  2. IUserRepository 인터페이스를 만들고 UserRepositoryImpl을 구현한다.

  3. IUserService 인터페이스를 만들고 UserServiceImpl을 구현한다.

  4. UserController가 서비스를 호출하고, 서비스는 저장소를 호출한다.

단순히 DB에서 이름 하나 가져오는데 5개의 파일과 10개의 메서드 호출이 얽혀 있었다. 나중에 버그가 생겼을 때, 민수는 데이터가 어디서 어떻게 변하는지 찾기 위해 수많은 파일을 넘나들며 길을 잃었다.

하나의 설계 (The Straight Line): 하나는 "명확함"을 선택했다. "지금은 복잡한 추상화가 필요 없어. 그냥 컨트롤러에서 필요한 데이터를 바로 가져오자." 하나는 불필요한 인터페이스와 추상 레이어를 걷어냈다. 입력(Request)이 들어오면 바로 데이터(DB)에 접근하여 결과(Response)를 내보내는 직선 경로를 만들었다. 코드는 단 몇 줄뿐이었고, 누가 읽어도 데이터의 흐름이 한눈에 보였다. 하나는 나중에 정말로 확장이 필요할 때, OrganicGrowth의 원칙에 따라 그때 레이어를 나누기로 했다.

Context

StrongCenter를 중심으로 기능을 구현하고 있다. CleanIsolation을 위해 의존성을 관리하려고 노력 중이다. 하지만 어느 순간부터 코드가 너무 많은 레이어와 "위임(Delegation)"으로 가득 차기 시작한다.

일상적인 상황:

당신은 지금 미래의 유령과 싸우느라, 현재의 명확함을 희생하고 있다.

Problem

과도한 간접성(Indirection)과 레이어는 시스템의 흐름을 가리고 인지 부하를 높인다.

Solution

입력에서 출력에 이르는 경로를 가리는 불필요한 레이어를 제거하고, 가능한 한 직접적으로 표현하라.

추상화는 공짜가 아니다. 그 비용을 지불할 가치가 있을 때만 도입하라.

Principle 1: Eliminate Empty Layers (깡통 레이어 제거)

단순히 다음 단계로 넘겨주기만 하는 클래스나 서비스는 과감히 삭제하라.

Principle 2: Value Clarity over "Best Practices" (관행보다 명확성)

"레이어드 아키텍처는 4계층이어야 한다"는 교과서적 원칙에 얽매이지 마라.

Principle 3: Short Feedback Path (짧은 피드백 경로)

코드의 경로가 짧을수록 TightLoop가 쉬워진다.

Principle 4: Flatten the Abstraction (추상화 납작하게 만들기)

너무 깊은 상속 구조나 중첩된 함수 호출을 경계하라.

Real Examples

Example 1: Implementation-only Interface

민수:

interface UserService { User find(Long id); }
class UserServiceImpl implements UserService { ... }

(구현체가 하나뿐인데 인터페이스를 만듦)

하나:

class UserService { User find(Long id); }

(직접 클래스를 사용. 나중에 Mock이 필요하면 그때 인터페이스를 뽑아내거나 프레임워크의 기능을 활용함)

Example 2: Data Transformation Hell

민수: UserEntity -> UserVO -> UserDTO -> UserResponse. 데이터가 각 레이어를 지날 때마다 똑같은 필드들을 복사해서 옮긴다.

하나: UserEntity를 필요한 곳까지 직접 전달하거나, 꼭 필요한 경우에만 최소한의 변환을 수행한다. 경로를 단순화하여 필드 추가/삭제의 고통을 줄인다.

Common Pitfalls

"But I need to hide implementation!" (구현을 숨겨야 하는데요!)

구현을 숨기는 목적은 **변경의 영향을 줄이기 위해서**다. 그런데 레이어를 너무 많이 만들어서 오히려 변경할 때마다 모든 레이어를 다 고쳐야 한다면, 당신은 구현을 숨긴 게 아니라 복잡성을 노출한 것이다.

Fear of "Dirty" Controller

"컨트롤러에 로직이 있으면 안 돼!"라는 강박. 하지만 5줄짜리 로직을 위해 새로운 서비스 클래스와 인터페이스를 만드는 것이 더 "지저분한" 결과일 수 있다. 로직이 작다면 그 자리에 두어라. 커지면 그때 옮겨라.

Connection to Other Patterns

Signs of Success

The Ultimate Insight

가장 완벽한 설계는 더 보태 것이 없을 때가 아니라, 더 뺄 것이 없을 때 완성된다. (생텍쥐페리)

추상화라는 미로를 만드느라 에너지를 낭비하지 마라. 문제와 해결책을 잇는 가장 짧고 투명한 길을 만들어라. 그 길 위에서 코드는 가장 강력한 힘을 발휘한다.


CategoryPatternLanguage CategoryProgramming CategoryDesign CategorySimplicity