추상화는 구현 세부사항을 숨기고 계층을 분리해 코드 복잡성을 낮춘다
업무 중에 코드 리뷰를 받으면서 “이 부분이 추상화가 안 됐네요”라는 피드백을 받은 적이 있다. 그 순간 추상화가 뭔지는 알고 있다고 생각했는데, 막상 뭘 어떻게 고쳐야 하는지 바로 떠오르지 않았다. 그래서 제대로 파보기로 했다.
추상과 구현의 스펙트럼
추상화를 이해하는 좋은 방법은 그라데이션처럼 생각하는 거다. 한쪽 끝에는 완전한 추상(인터페이스, 개념), 다른 쪽 끝에는 완전한 구현(메모리 주소, 하드웨어 제어)이 있다. 그 사이 어딘가에 우리가 작성하는 코드가 있다.
예를 들어 List.add(item)을 호출할 때, 호출하는 쪽은 내부에서 배열이 몇 번 복사되는지, 메모리 재할당이 언제 일어나는지 알 필요가 없다. 그 세부사항을 숨긴 게 추상화다.
데이터 흐름으로 바라보기
좋은 추상화를 연습하는 방법 중 하나는 데이터 흐름으로 문제를 바라보는 거다.
테트리스를 구현한다고 생각해보자. “블록이 떨어진다”는 행동을 중심으로 생각하면 메서드가 절차적으로 늘어난다. 반면 “보드는 2D 배열이고, 블록은 좌표를 가진 형태”라고 데이터부터 정의하면 구조가 명확해진다.
입력 데이터 → 처리 → 출력 데이터. 이 흐름을 명확하게 만드는 게 추상화의 핵심이다.
좋은 이름이 추상화를 완성한다
추상화는 코드만의 문제가 아니다. 이름 짓기가 반은 먹고 들어간다.
processData()는 뭘 하는지 모른다. calculateMonthlyRevenue()는 뭘 하는지 안다. 이름 하나로 구현 세부사항을 숨기고 의도를 드러낼 수 있다.
인터페이스 이름도 마찬가지다. UserRepository는 “사용자 데이터를 저장하고 가져온다”는 계약이다. 내부에서 MySQL을 쓰든 MongoDB를 쓰든, 호출하는 쪽은 몰라도 된다.
Git의 4대 오브젝트가 추상화의 교과서
Git을 이해하면 추상화를 눈으로 볼 수 있다. Git은 파일 시스템을 4종류의 오브젝트로 추상화한다:
- Blob: 파일 내용
- Tree: 디렉토리 구조
- Commit: 특정 시점의 스냅샷 + 메타데이터
- Tag: 커밋에 붙이는 라벨
우리가 git commit을 실행할 때, 내부에서는 blob → tree → commit 오브젝트가 생성되고 SHA-1 해시로 연결된다. 이 복잡한 과정이 git commit -m "message" 한 줄 뒤에 숨어있다. 이게 추상화다.
추상화 수준을 어떻게 결정하나
실무에서 가장 어려운 질문이다. 너무 추상화하면 오히려 코드를 따라가기 어렵고, 너무 적으면 변경이 어렵다.
경험상 기준이 되는 질문은 이거다: “이 세부사항이 바뀔 가능성이 있나?” 데이터베이스가 바뀔 수 있다면 Repository 인터페이스로 추상화할 가치가 있다. 절대 안 바뀌는 로직이라면 추상화보다 단순하게 두는 게 낫다.
YAGNI(You Aren’t Gonna Need It)를 여기서도 적용해야 한다. 미래에 쓸지 모른다는 이유로 지금 쓰지 않는 추상화를 만드는 건 과잉 설계다.
연결
- Git은 분산 버전 관리와 4대 오브젝트 시스템으로 병렬 개발을 가능하게 한다 — Git의 4대 오브젝트는 파일 시스템을 추상화한 대표 사례