추상화는 현재의 생산성을 올리지만,
과하면 미래의 장애 분석 비용을 폭발시킨다.

 

1️⃣ “추상화는 힘이다” — 왜 맞는 말인가

추상화의 실질적 힘

  • 복잡성 은닉
  • 변경 지점 최소화
  • 코드 재사용
  • 협업 가능

자바/스프링에서의 예

  • 인터페이스
  • 서비스 레이어
  • 공통 모듈
  • 프레임워크(eGovFrame, Spring)

👉 지금 당장 개발 속도 + 팀 생산성은 추상화가 만든다.


2️⃣ “하지만 과하면” — 언제부터 독이 되는가

추상화가 과해지는 시점

① 레이어가 문제를 숨길 때

 
Controller → Service → Facade → Manager → Helper → Util
  • 장애 시 스택트레이스 50줄
  • “어디서 터졌는지” 바로 안 보임

② 행위보다 구조 설명이 더 어려울 때

 
processContext.execute( new AbstractProcessor() { @Override protected void doInternal(Context ctx) { ... } } );
  • 실제 비즈니스 로직: 3줄
  • 추상화 코드: 300줄

👉 코드는 DRY하지만, 사고는 WET


③ 디버깅 시 “개념 점프”가 많을 때

  • 인터페이스 → 구현체 찾기
  • 프록시 → 실제 클래스 추적
  • AOP → 실제 호출 흐름 복원

👉 디버깅 = 추상화 해체 작업


3️⃣ “미래의 디버깅 비용”이란 정확히 뭘 말하나

디버깅 비용 = 시간 × 인지 부하 × 불확실성

추상화 과다 시스템의 특징:

  • 로그가 추상 레벨에서 끊김
  • 실제 데이터 흐름이 안 보임
  • 호출 스택이 “프레임워크 코드”로 덮임

결과:

  • 원인 파악에 몇 시간
  • 수정은 5분

4️⃣ GC / 성능 이야기와 정확히 연결됨

이 문장은 GC 명언과 같은 계열입니다.

예시

  • 객체 생명주기 추상화
  • 컬렉션 감싸기
  • 범용 DTO
  • 이벤트 기반 추상화

👉 실제로는:

  • 객체 수 폭증
  • 메모리 사용 패턴 불투명
  • GC 로그 보고도 원인 추적 어려움

5️⃣ 실무에서 “과한 추상화”의 전형

❌ SI에서 자주 보는 패턴

  • 모든 걸 CommonService
  • 모든 응답을 ResultWrapper<T>
  • 모든 로직을 Strategy + Factory

👉 미래 유지보수자는 전부 역추적


6️⃣ 좋은 추상화 vs 나쁜 추상화

구분좋은 추상화나쁜 추상화
기준 변경 이유 디자인 패턴
깊이 얕고 명확 깊고 일반화
디버깅 따라가기 쉬움 추적 지옥
로그 구체적 추상적

7️⃣ 실무 기준 판단 문장 (중요)

“이 추상화가 없어지면
디버깅이 더 쉬워지는가?”

  • YES → 과한 추상화
  • NO → 유지할 가치 있음

8️⃣ 그래서 이 문장을 실무 언어로 번역하면

“지금의 깔끔함은
나중에 반드시 추적 비용으로 청구된다.”


9️⃣ 개발자 레벨 구분 명언으로 정리

  • 초급: 추상화를 믿는다
  • 중급: 추상화를 의심한다
  • 고급: 필요한 만큼만 남긴다

 

 

1) Spring에서 디버깅 지옥 만드는 추상화 TOP 5

TOP1. 과도한 AOP (특히 @Around 체인 + 예외 삼키기)

징후

  • 장애 났는데 스택트레이스가 CglibAopProxy, ReflectiveMethodInvocation으로 도배
  • 실제 비즈니스 예외가 래핑/변형되어 원인 소실
  • AOP에서 catch(Exception) { return default; } 같은 방어코드

왜 지옥이냐

  • 호출 흐름이 코드에 안 보임(런타임에 엮임)
  • “언제/어디서” 값이 바뀌는지 추적이 어렵다

가이드

  • AOP는 “로깅/트랜잭션/보안” 같은 횡단 관심사만
  • @Around는 최소화, 예외는 원형 유지(추가 정보만 붙여라)

TOP2. “범용” 응답/예외 래퍼 (ResultWrapper, BizExceptionFactory)

징후

  • 모든 API가 CommonResponse<T> / ApiResult<T>로 감싸짐
  • 예외가 항상 BusinessException(code=XXXX)로 치환됨
  • 로그에 진짜 예외가 안 남고 에러코드만 남음

왜 지옥이냐

  • 원인 분석이 “코드표” 읽기로 바뀜
  • 예외의 stacktrace 정보 가치가 급락

가이드

  • 래퍼는 최소 필드만(요청ID/에러코드/메시지)
  • 서버 로그에는 원본 예외 stacktrace 반드시 남기기
  • 예외 변환은 컨트롤러 어드바이스 단에서 끝내기

TOP3. “공통 서비스/매니저” 만능 계층 (CommonService, BaseManager)

징후

  • 모든 서비스가 BaseService 상속
  • 핵심 로직이 공통 레이어에 숨어 있음
  • override/extension hook이 난무

왜 지옥이냐

  • 소스 따라가다 상속 트리/훅 포인트에서 길 잃음
  • “이 기능은 어디서 결정되지?”가 매번 발생

가이드

  • 상속보다 조합(Composition) 우선
  • 공통은 유틸/컴포넌트로 빼고, 비즈니스는 서비스에 두기

TOP4. 동적 DI/전략 패턴 과잉 (Factory + Strategy + 문자열 key)

징후

  • strategyMap.get(type) 같은 분기
  • type 값이 DB/설정/요청에서 와서 런타임에만 결정
  • 케이스 누락 시 NPE/기본전략으로 조용히 흘림

왜 지옥이냐

  • 코드 리딩만으로 실행 경로가 확정되지 않음
  • 재현이 어려움(특정 데이터에서만 터짐)

가이드

  • 전략은 “진짜로 독립적인 변형”일 때만
  • key는 enum 고정 + default 금지(누락이면 바로 fail)

TOP5. 프록시/리플렉션 기반 인프라 추상화 (Proxy, Reflection, Generic DAO)

징후

  • “공통 DAO 한 방”으로 모든 테이블 처리
  • 리플렉션으로 VO 맵핑/검증
  • 런타임 타입 에러가 늦게 터짐

왜 지옥이냐

  • 컴파일 타임에 잡을 오류를 런타임으로 미룸
  • 장애는 늦게, 메시지는 모호하게 뜬다

가이드

  • 공통 DAO는 CRUD 정도까지만
  • 도메인별 Repository/Mapper를 명시적으로 둬라

2) eGovFrame 공통모듈이 위험한 이유 (공공 SI 관점)

eGovFrame 자체가 위험이라기보다, “공통화”를 명분으로 SI 조직이 남용하는 방식이 위험합니다.

위험 포인트 5개

① 프레임워크/공통모듈이 “표준”이라서 손대기 어려움

  • “표준이라서”라는 말로 개선이 막힘
  • 레거시가 성역화됨

② 디버깅 경로가 길어짐

  • 공통모듈 → 공통서비스 → 공통DAO → 공통로깅 → …
  • 장애 시 분석 범위가 폭발

③ 버전/종속성 락인

  • Java/Spring 업그레이드의 병목이 공통모듈에서 발생
  • “이거 올리면 다른 사업도 깨짐”으로 기술부채 고착

④ 예외/로그 정책이 공통에서 결정돼서 관측성이 떨어짐

  • 예외 래핑, 메시지 치환, 로깅 필터링이 공통에 박혀 있으면
  • 현장 서비스에서 필요한 증거가 안 남는다

⑤ “재사용”이 아니라 “재생산”이 된다

  • 공통모듈을 이해 못 해서 프로젝트마다 복붙/커스터마이징
  • 결국 공통이 여러 갈래로 포크됨(진짜 최악)

한 줄 요약

eGov 공통모듈의 위험은 “기술”보다 조직 운영 방식에서 온다.
공통이 표준이 되는 순간, 디버깅/개선이 막힌다.


3) ‘이 추상화는 지워야 한다’ 판단 체크리스트

아래 10개 중 3개 이상이면 제거 후보,
5개 이상이면 제거 우선순위 높음으로 보시면 됩니다.

제거 후보 체크 10

  1. 디버깅할 때 항상 그 추상화 안으로 들어간다 (매번 따라감)
  2. 그 추상화의 목적이 “재사용”이 아니라 **“멋” 또는 “패턴 적용”**이다
  3. 호출 흐름이 코드에 안 보이고 런타임에서만 결정된다(AOP/Map Strategy)
  4. 예외가 래핑되며 원본 stacktrace 가치가 떨어진다
  5. 로그가 “추상 레벨”에서 끊겨서 데이터/조건이 안 남는다
  6. 새 요구사항이 올 때마다 그 추상화에 if/flag가 늘어난다
  7. 그 추상화를 이해하려면 문서/구두 지식이 필수다 (코드만으론 불가)
  8. 팀원이 그 추상화를 피해서 우회 구현을 한다
  9. 테스트 작성이 어렵고, 대부분 통합테스트로만 검증한다
  10. 성능/메모리 이슈가 생기면 원인 추적이 안 되고 “대충” 옵션 튜닝으로 간다
LIST

+ Recent posts