
코틀린 디자인 패턴을 왜 아직도 배워야 하는지부터 먼저 정리해보겠습니다. 코틀린은 전통적인 패턴 구현을 더 간결하게 만들 수 있지만 설계 문제 자체를 없애지는 못합니다.
처음에는 코드가 단순합니다. 결제 수단도 하나이고, 알림 채널도 하나이고, 상태도 몇 개 안 됩니다. 그래서 when이나 함수 몇 개만으로도 충분해 보입니다. 그런데 기능이 늘어나기 시작하면 객체를 누가 만들지, 상태를 어디서 관리할지, 기능 확장을 상속으로 할지 조합으로 할지 같은 질문이 한꺼번에 튀어나옵니다.
바로 이 지점에서 코틀린 디자인 패턴이라는 주제가 다시 살아납니다. 코틀린에는 object, data class, sealed class, delegation, higher-order function 같은 강력한 기능이 있습니다. 그래서 많은 개발자가 “코틀린이 이렇게 많은 걸 해결해주는데, 굳이 디자인 패턴을 다시 배워야 하나?”라고 묻습니다.
이 질문에 대한 제 답은 분명합니다. 코틀린은 패턴을 없앤 것이 아니라, 패턴을 표현하는 방식을 바꿨습니다. 즉, 이 시리즈에서 다루려는 코틀린 디자인 패턴은 옛날 자바 문법을 다시 외우는 작업이 아니라, 객체를 어떻게 만들고 상태를 어떻게 나누고 협력 구조를 어떻게 설계할지를 코틀린답게 판단하는 기준을 잡는 과정에 더 가깝습니다.
코틀린 디자인 패턴의 유효성
코틀린은 분명 많은 것을 더 쉽게 만들어줍니다. Singleton은 object로 간결하게 표현할 수 있고, 닫힌 상태 집합은 sealed class로 더 분명하게 모델링할 수 있습니다.
data class의 copy()는 비슷한 객체를 조금씩 바꿔 만들 때 편리하고, delegation은 상속보다 조합을 선택하는 코드를 덜 번거롭게 만들어줍니다. 함수 타입과 higher-order function은 전략 교체나 공통 흐름 추상화를 더 유연하게 만드는 데 도움이 됩니다.
하지만 여기서 중요한 구분이 있습니다. 이런 기능은 코드를 짧게 만들고 보일러플레이트를 줄여주는 것이지, 설계 문제 자체를 대신 풀어주는 것은 아닙니다. 예를 들어 object가 있다고 해서 모든 전역 객체가 좋은 Singleton이 되는 것은 아니고, sealed class가 있다고 해서 모든 상태 분기 문제가 자동으로 좋은 설계가 되는 것도 아닙니다.
디자인 패턴은 원래부터 문법 기술이 아니라 설계 문제에 대한 반복 가능한 해법의 틀이었습니다. 그래서 언어가 바뀌면 구현 방식은 달라질 수 있어도, 패턴이 던지는 질문 자체는 여전히 남습니다.
- 객체 생성 책임을 어디에 둘 것인가
- 상태 변화에 따른 동작을 어떻게 분리할 것인가
- 기능 확장을 상속으로 할 것인가, 조합으로 할 것인가
- 여러 객체의 협력을 어떻게 느슨하게 만들 것인가
코틀린은 이 질문에 답하는 문법적 도구를 더 많이 주었습니다. 하지만 무슨 질문을 먼저 해야 하는지까지 대신 결정해주지는 않습니다.
문법 개선과 설계 문제
이 점은 실전 예시를 떠올려보면 더 분명합니다. 결제 기능을 만든다고 해보겠습니다. 처음에는 카드 결제 하나만 있으면 단순한 when으로도 충분해 보입니다. 하지만 계좌이체, 간편결제, 포인트, 쿠폰 결제까지 붙기 시작하면 상황이 달라집니다. 결제 수단 생성, 검증 규칙, 실제 처리 로직, 실패 복구 정책이 서로 다른 속도로 복잡해지기 때문입니다.
이때 문제는 문법이 부족해서 생기는 것이 아닙니다. 문제는 생성 책임과 실행 책임이 섞이고, 변경 이유가 다른 코드가 한곳에 모이는 것입니다. 알림 발송도 비슷합니다. 이메일, SMS, 푸시, 슬랙 알림이 함께 들어오면 채널마다 메시지 포맷이 다르고 실패 처리 방식이 다르고 동기/비동기 처리 기준도 달라질 수 있습니다. 이때 필요한 것은 문법 트릭이 아니라 구조입니다.
상태가 많은 화면도 마찬가지입니다. 로딩 중, 성공, 실패, 빈 상태, 재시도 가능, 권한 없음 같은 상태가 생기면 문제는 코드 길이가 아니라 상태와 동작의 관계가 흐려지는 것입니다. 어떤 상태에서 어떤 액션이 허용되는지, 어떤 상태 전이가 가능한지 정리하지 않으면 버그가 늘어납니다.
바로 이 지점에서 디자인 패턴이 의미를 가집니다. 패턴은 코드를 화려하게 만드는 장식이 아니라, 변경이 반복될 때도 구조가 무너지지 않게 설계 판단을 정리해주는 틀입니다. 다르게 말하면 패턴의 핵심은 구현 기교가 아니라 책임 배치입니다.
코틀린 문법과 설계 판단
이 시리즈가 강조하고 싶은 핵심도 여기 있습니다. 우리는 패턴을 자바 예제를 코틀린 문법으로 옮긴 번역본처럼 다루지 않을 것입니다. 대신 코틀린이 무엇을 더 쉽게 만들고, 무엇은 여전히 개발자의 판단으로 남겨두는지를 같이 보려고 합니다.
Singleton과 object
코틀린에서는 Singleton을 자바보다 훨씬 쉽게 표현할 수 있습니다. object 선언만으로 클래스 정의와 단일 인스턴스 생성을 함께 다룰 수 있기 때문입니다. 하지만 구현이 쉬워졌다고 해서 Singleton 남용 문제가 없어지지는 않습니다. 테스트가 어려워질 수 있고, 숨은 전역 상태가 늘어날 수 있고, 의존성 주입 구조와 충돌할 수도 있습니다.
즉, 코틀린은 Singleton을 쉽게 만들게 해주지만, Singleton을 써야 하는 상황을 판별하는 일까지 대신해주지는 않습니다.
Prototype과 copy()
data class의 copy()는 강력합니다. 같은 형태의 객체를 조금씩 바꿔 새 인스턴스를 만들 때 매우 편리합니다. 다만 Kotlin 공식 문서가 설명하듯 copy()는 shallow copy입니다. 내부에 참조형 프로퍼티가 있으면 원본과 복사본이 같은 내부 객체를 공유할 수 있습니다.
즉, copy()는 Prototype 패턴 논의를 가볍게 만들 수는 있어도, 복제 전략에 대한 고민 자체를 없애주지는 않습니다.
Sealed class와 상태 모델링
sealed class와 sealed interface는 가능한 하위 타입 집합을 컴파일 타임에 제한하고, when에서 모든 경우를 다루도록 만드는 데 큰 도움을 줍니다. 그래서 State, Visitor, 일부 분기 구조를 다루는 글에서는 코틀린다운 설명이 훨씬 자연스러워집니다. 하지만 이것도 “이제 패턴은 필요 없다”는 뜻은 아닙니다.
오히려 패턴이 다루는 구조를 더 분명하게 설명할 수 있는 언어적 기반이 생겼다고 보는 편이 맞습니다.
Higher-order function과 전략 분리
함수를 값처럼 다룰 수 있다는 점은 코틀린의 큰 장점입니다. 전략을 바꿔 끼우거나, 공통 흐름의 일부만 교체하는 문제를 더 간결하게 표현할 수 있습니다. 그래서 Strategy나 Template Method를 설명할 때도 인터페이스 기반 구조만 볼 것이 아니라, 함수형 대안까지 같이 봐야 합니다.
하지만 여기서도 핵심은 같습니다. 어떤 수준에서 정책을 바꾸게 만들지, 어떤 부분을 공통 흐름으로 묶을지, 언제 함수형 방식이 더 읽기 좋은지 같은 판단은 여전히 필요합니다.
Delegation과 조합 중심 설계
Kotlin 공식 문서도 delegation pattern을 implementation inheritance의 좋은 대안으로 설명합니다. by 문법은 인터페이스 구현을 다른 객체에 위임하는 코드를 훨씬 덜 장황하게 만듭니다. 이 덕분에 Decorator, Proxy, Bridge처럼 조합이 중요한 구조를 설명할 때 코틀린은 분명한 장점을 가집니다.
하지만 위임 문법이 있다고 해서 구조가 자동으로 좋아지지는 않습니다. 무엇을 감싸고, 무엇을 노출하고, 어디서 책임을 끊을지 결정하는 일은 여전히 설계의 영역입니다.
정리하면 이렇습니다. 코틀린은 패턴을 낡게 만든 것이 아니라, 패턴을 더 짧고 더 선명하게 설명할 수 있게 만든 언어입니다.
시리즈의 중심축: 설계 질문
이 시리즈는 GoF 패턴 전체를 다루지만, 목표는 이름을 많이 외우게 하는 것이 아닙니다. 각 패턴이 어떤 설계 질문에 답하려고 등장했는지, 그리고 코틀린에서는 그 답이 어떻게 달라지는지를 같이 보는 것이 더 중요합니다.
- 생성 패턴: 객체를 어떻게 만들고 생성 책임을 어디에 둘까
- 구조 패턴: 객체를 어떻게 연결하고 감싸고 단순화할까
- 행동 패턴: 상태 변화와 실행 흐름, 협력 구조를 어떻게 정리할까
초반의 Singleton, Factory Method, Abstract Factory, Builder, Prototype은 생성 패턴의 감각을 먼저 단단히 잡기 위한 순서입니다. 이 시리즈는 번호 순서대로 진행하고, 0편에서 전체 지도를 잡은 뒤 1편 Singleton, 2편 Factory Method, 3편 Abstract Factory, 4편 Builder로 이어질 예정입니다.

즉, 이 연재는 패턴 백과사전이 아니라 설계 감각을 단계적으로 쌓는 코틀린 패턴 지도가 되어야 합니다.
읽는 기준
- 패턴 이름보다 먼저 어떤 문제를 푸는지 본다
- 코틀린이 무엇을 더 쉽게 만드는지 함께 본다
- 장점뿐 아니라 비용과 남용 위험도 같이 본다
좋은 패턴 공부는 장점 암기가 아니라 장점과 비용을 같이 보는 훈련이어야 합니다.
다음 글: Singleton
다음 글은 코틀린 디자인 패턴(1) – Singleton 패턴은 언제 쓰고 object는 어떻게 다를까입니다. 코틀린의 object는 많은 개발자가 가장 먼저 떠올리는 기능이고, 동시에 “간단히 만들 수 있다”와 “좋은 설계다”를 혼동하기 쉬운 지점이기 때문입니다.
그다음은 Factory Method, Abstract Factory, Builder 순서로 이어집니다. 이 초반 흐름을 따라가면 생성 패턴이 다루는 핵심 질문, 즉 객체를 어떻게 만들고 생성 책임을 어디에 둘지를 먼저 잡을 수 있습니다.
이 시리즈의 목표는 패턴 이름을 더 많이 아는 사람이 되는 것이 아닙니다. 코드를 볼 때 설계 문제를 더 빨리 알아차리고, 코틀린답게 풀 수 있는 기준을 갖게 되는 것입니다. 그 출발점으로 다음 편에서는 Singleton을 차분히 살펴보겠습니다.
공식 참고 자료로는 Kotlin object declarations, data classes, sealed classes, delegation, higher-order functions and lambdas 문서를 함께 참고하면 좋습니다.