프로젝트가 커질수록 파일 하나 고치는 게 점점 무서워집니다. 어디까지 영향이 퍼지는지 가늠이 안 되니까요.
빌드는 느려지고, 코드 리뷰 범위는 넓어집니다. 새 팀원은 어디서부터 읽어야 할지 막막해하고요.
모듈화는 이 문제의 가장 오래된 처방입니다. 한 문장으로 답부터 드리면, 모듈화란 큰 코드 덩어리를 독립적으로 이해하고 교체할 수 있는 단위로 나누는 일이에요.
이 글에서는 모듈화가 정확히 무엇을 나누는 건지, 좋은 모듈의 기준인 응집도와 결합도, 언제 나눠야 하는지까지 정리합니다.
핵심 요약부터 보고 갈게요.
- 모듈화는 코드를 “같이 바뀌는 것끼리” 묶어 경계를 세우는 작업입니다
- 좋은 모듈의 기준은 높은 응집도, 낮은 결합도입니다
- 나누는 목적은 빌드 속도보다 변경 비용 축소가 먼저입니다
- 경계가 불분명한 상태에서 나누면 오히려 복잡도만 늘어납니다
모듈화란 정확히 무엇을 나누는 걸까?
폴더를 나누는 것과 모듈을 나누는 것은 다릅니다.
폴더는 그냥 파일 정리예요. 어느 폴더의 코드든 다른 폴더의 코드를 자유롭게 가져다 쓸 수 있죠.
모듈은 여기에 강제력 있는 경계가 생깁니다. 모듈 밖에서는 그 모듈이 공개(public)하기로 한 인터페이스만 쓸 수 있어요.
모듈화의 본질은 파일 정리가 아니라, “밖에서 알아도 되는 것”과 “몰라도 되는 것”을 컴파일러가 강제하게 만드는 일입니다.
이 경계 덕분에 두 가지가 가능해집니다.
- 독립적 이해: 모듈 내부를 몰라도 인터페이스만 보면 쓸 수 있다
- 독립적 교체: 인터페이스가 같으면 내부 구현을 통째로 바꿔도 밖은 영향이 없다
1972년 데이비드 파나스(David Parnas)가 논문에서 제시한 정보 은닉(information hiding) 개념이 바로 이겁니다. 모듈을 나누는 기준은 기능이 아니라 “감추고 싶은 설계 결정”이라는 거죠.
좋은 모듈의 기준, 응집도와 결합도
모듈을 나눴는데 오히려 불편해졌다면, 대부분 이 두 지표가 어긋난 경우입니다.
응집도(cohesion)는 모듈 안의 코드들이 서로 얼마나 관련 있는지를 말합니다. 높을수록 좋아요.
결합도(coupling)는 모듈들이 서로 얼마나 붙어 있는지를 말합니다. 낮을수록 좋습니다.
간단한 판별법이 있습니다.
| 질문 | 신호 |
|---|---|
| 기능 하나 고치는데 모듈 여러 개를 동시에 수정하나? | 결합도가 높다 |
| 모듈 안에 서로 무관한 코드가 섞여 있나? | 응집도가 낮다 |
| 모듈 하나를 삭제하면 딱 그 기능만 사라지나? | 잘 나눠졌다 |
핵심 기준은 변경입니다. 같이 바뀌는 코드는 한 모듈에, 다른 이유로 바뀌는 코드는 다른 모듈에 두는 거예요.
어디서 많이 본 원칙이죠? SOLID의 단일 책임 원칙(SRP)이 말하는 “변경의 이유”가 모듈 단위로 확장된 겁니다.
모듈화하면 뭐가 좋아지나요?
변경 비용이 가장 먼저 줄어듭니다.
경계가 있으면 수정의 영향 범위가 모듈 안으로 갇혀요. 리뷰어도 “이 모듈의 공개 인터페이스가 안 바뀌었으니 밖은 안전하다”고 판단할 수 있고요.
팀 단위 분업도 쉬워집니다. 모듈별로 담당을 나누면 서로의 작업 영역을 침범하는 충돌이 줄어듭니다.
테스트도 가벼워져요. 모듈 하나만 떼어 테스트할 수 있으니, 전체 앱을 띄우지 않고도 검증이 가능합니다.
빌드 속도 개선도 따라옵니다. 바뀐 모듈만 다시 컴파일하면 되니까요. 다만 이건 결과이지 목적이 아닙니다. 경계 설계가 엉망이면 모듈을 나눠도 매번 전부 다시 빌드하게 돼요.
Swift로 보면 경계는 접근 제어자로 드러납니다.
// 모듈 밖에는 프로토콜만 공개
public protocol PriceFormatter {
func format(_ amount: Int) -> String
}
// 구현체는 모듈 내부에 숨긴다
final class KoreanPriceFormatter: PriceFormatter {
func format(_ amount: Int) -> String { "\(amount)원" }
}
밖에서는 PriceFormatter만 알면 됩니다. 내부 구현을 바꿔도 모듈 밖 코드는 재컴파일조차 필요 없는 상태가 이상적이에요.
언제 나누고 언제 참아야 할까?
모듈화는 공짜가 아닙니다. 경계를 만들면 인터페이스 설계, 버전 관리, 프로젝트 설정 비용이 따라와요.
| 상황 | 판단 |
|---|---|
| 기능 하나 수정에 여러 팀·여러 영역 코드가 함께 바뀐다 | 나눌 때가 됐다 |
| 빌드가 느려 개발 흐름이 자주 끊긴다 | 나누되, 변경 경계부터 설계 |
| 아직 도메인 경계가 자주 바뀌는 초기 제품 | 참는다. 경계가 굳은 뒤에 |
| 혼자 만드는 작은 앱 | 폴더 정리와 접근 제어자로 충분 |
경계를 잘못 그은 모듈화는 안 한 것보다 나쁩니다. 모듈 두 개가 항상 같이 바뀐다면 그 경계는 틀린 거예요. 합치는 게 맞습니다.
면접에서는 이렇게 물어봅니다
Q. 응집도와 결합도를 설명하고, 둘의 관계를 말해 보세요.
응집도는 모듈 내부 요소들의 관련성, 결합도는 모듈 사이의 의존 정도입니다. 좋은 설계는 높은 응집도와 낮은 결합도를 지향하는데, 관련 있는 코드를 한곳에 모으면(응집도 상승) 자연히 모듈 밖과 주고받을 것이 줄어들어 결합도가 낮아지는 상보 관계입니다.
Q. 모듈을 나누는 기준을 무엇으로 잡겠습니까?
변경의 이유를 기준으로 잡습니다. 같은 이유로 함께 바뀌는 코드는 한 모듈에 두고, 다른 이유로 바뀌는 코드는 분리합니다. 기능 목록이 아니라 “이 모듈이 감추는 설계 결정이 무엇인가”를 답할 수 있어야 올바른 경계입니다.
다음 글에서는 모듈을 나눈 뒤 반드시 마주치는 문제, 모듈 사이의 의존성 방향과 순환 의존을 다룹니다.
나누는 것보다 나눈 뒤의 관계 설계가 진짜 어려운 부분이거든요. 이 글의 응집도·결합도 감각을 갖고 보시면 훨씬 수월할 겁니다.
