#5 Bend, or Break

5장 구부러지거나 부러지거나

💻 실용주의 프로그래머: Topic 28

결합도 줄이기 (Reduce Coupling)


1. 핵심 개념 — “서로 덜 연결될수록 더 바꾸기 쉽다”

“우리가 어떤 것 하나만을 골라내려 해도, 그것이 우주의 다른 모든 것과 얽혀 있음을 깨닫게 된다.” — 존 뮤어(John Muir)

결합도(Coupling)가 높은 코드는 바꾸기 어렵다. 그 이유는 한 부분의 변화가 다른 부분까지 연쇄적으로 영향을 미치기 때문이다. 코드를 수정할 때마다 여러 모듈을 동시에 수정해야 한다면, 이미 결합도가 높다는 신호다.

💡 좋은 설계란, 변경의 파급 범위가 좁은 설계다.


2. 개념 비유 — “단단한 연결 vs 유연한 연결”

  • 단단하게 얽힌 구조(삼각형 그물망)는 하나만 바꿔도 전체가 흔들린다.

  • 반대로 유연하게 연결된 구조(선형 연결)는 일부만 교체 가능하다.

소프트웨어도 마찬가지다. 모듈 간 연결을 최소화해 독립적 변경이 가능한 형태로 만들어야 한다.


3. Tip 44 — “결합도가 낮은 코드는 바꾸기 쉽다”

결합도가 높은 코드에서는 다음 문제가 반복적으로 발생한다.

  • 연쇄 호출(Train Wreck): 객체를 계속 점으로 연결하며 내부 상태에 접근

  • 글로벌 상태(Global State): 전역 변수나 싱글톤으로 인해 의존성 확산

  • 상속 남용: 부모 클래스 변경이 모든 자식에게 파급

💬 “한 모듈의 변경이 시스템 전체로 퍼질 때, 그건 ‘결합도 폭발’이다.”


4. 사례 — “열차 사고(Train Wreck)”

이 코드의 문제:

  • 고객(Customer), 주문(Order), 총합(Totals) 객체가 직렬로 연결되어 있음

  • 변경이 발생하면 전부 수정해야 함

  • 한 모듈의 수정이 여러 객체에 의존함


5. Tip 45 — “묻지 말고 말하라 (Tell, Don’t Ask)”

객체의 내부 상태를 묻고 직접 조작하지 말라. 대신 객체 스스로에게 무엇을 하라(Tell) 고 요청하라.

이 원칙은 캡슐화(encapsulation) 를 강화하고, 연쇄 호출을 없애며, 한 객체의 책임을 명확히 분리한다.


6. 데메테르 법칙 (Law of Demeter, LoD)

“메서드는 오직 가까운 친구와만 이야기해야 한다.”

LoD 원칙: 메서드 내에서는 다음 대상에게만 메시지를 보낼 수 있다.

  • 같은 클래스의 메서드

  • 파라미터로 받은 객체

  • 자신이 직접 생성한 객체

  • 전역 변수 (지양)

즉,

같은 코드는 LoD 위반이다.


7. Tip 46 — “메서드 호출을 얽지 말라”

. 하나를 줄이는 것이 결합도를 낮추는 시작이다.”

이처럼 중간 접근을 캡슐화하면 결합도가 줄고 코드 변경 시 영향 범위가 작아진다.


8. 글로벌 상태의 해악

전역 변수나 싱글톤은 모든 코드가 공유하는 결합 지점이다. 이로 인해 테스트가 어려워지고, 변경 시 시스템 전체가 흔들린다.

💡 전역 데이터는 “코드의 진흙탕”이다. 모든 함수가 엉켜 있기 때문에 어디서 문제가 발생했는지 추적하기 어렵다.


9. Tip 47 — “전역 데이터를 피하라”

  • 전역 변수 대신 의존성 주입(Dependency Injection) 을 사용하라.

  • 테스트 중에는 Mock 객체로 대체하라.

  • 전역 데이터를 쓸 수밖에 없다면, 접근을 제한하는 래퍼(wrapper) 를 만들어라.


10. 외부 리소스도 전역 데이터다

데이터베이스, 파일 시스템, 외부 API 등은 모두 전역 상태를 가진 리소스다. 이 리소스를 사용할 때는 항상 명시적으로 관리 객체를 통해 접근해야 한다.

예:


11. Tip 48 — “전역적이어야 할 만큼 중요하다면 API로 감싸라”

정말 모든 곳에서 접근해야 하는 전역 리소스라면, 직접 노출하지 말고 명시적인 API 계층으로 감싸라.

✅ “중요한 전역은 감추고, 공개할 땐 제어하라.”


12. 상속은 결합도를 높인다

상속은 부모의 변경이 자식에게 즉시 전파되는 구조적 결합이다. 상속 대신 조합(Composition) 을 우선 고려하라.

💬 “상속은 재사용의 도구가 아니라 결합의 덫이다.”


13. 결합도의 최종 결론 — “결합은 시스템의 부패를 부른다”

결합도가 높을수록

  • 테스트가 어렵고,

  • 리팩터링이 불가능하며,

  • 변경 비용이 폭발한다.

결국 유지보수가 불가능한 시스템으로 이어진다.


“결합을 줄여라. 묻지 말고 말하라.” 느슨한 연결이 유연한 시스템을 만든다. Low coupling, high cohesion.

💻 실용주의 프로그래머: Topic 29

실세계를 갖고 저글링하기 (Program Close to the Real World)


1. 핵심 개념 — “세상은 동적이다. 코드도 그래야 한다”

“그냥 일어나는 일은 없다. 일어나도록 만들어진 것이다.” — 존 F. 케네디

과거에는 사람이 컴퓨터의 한계에 맞춰야 했다. 하지만 이제는 컴퓨터가 현실의 세계에 맞춰야 한다. 현실은 사건이 일어나고, 상태가 바뀌며, 사람들이 반응한다. 따라서 우리의 프로그램도 이 “동적인 세계의 리듬” 을 반영해야 한다.

💡 “반응형 시스템(Responsive System)”이란, 현실의 이벤트 흐름을 모델링하여 유연하게 반응하는 시스템이다.


2. 이벤트(Event)의 개념

이벤트란 “무언가가 일어났음”을 나타내는 신호이다.

  • 버튼 클릭

  • 데이터 갱신

  • 네트워크 수신

  • 센서 신호

  • 계산 완료

즉, 프로그램은 입력값만 다루는 것이 아니라 “시간상 발생하는 사건” 에 반응해야 한다.


3. 이벤트 기반 설계의 필요성

“이벤트를 중심으로 코드를 설계하면, 프로그램은 현실의 시간 축과 나란히 흐를 수 있다.”

이벤트 기반 구조는 시스템을 더 유연하게 만들고, 비동기 환경에서도 직관적인 동작을 유지시킨다.


4. 이벤트 처리 전략 — 4가지 핵심 기법

  1. 유한 상태 기계 (Finite State Machine, FSM)

  2. 감시자 패턴 (Observer Pattern)

  3. 게시-구독 (Publish–Subscribe)

  4. 반응형 프로그래밍과 스트림 (Reactive Streams)


5. 유한 상태 기계 (FSM)

FSM은 “현재 상태(State)”와 “이벤트(Event)”에 따라 다음 상태로 전이(Transition)되는 구조다.

예시 👇 웹소켓 메시지 수신을 FSM으로 표현:

  • 초기 상태: 대기 중

  • 헤더 메시지 수신 → “메시지 수신 중”으로 전이

  • 데이터 수신 → 계속 “수신 중” 유지

  • 트레일러 수신 → “완료”로 전이

  • 오류 발생 → “에러”로 전이

이 과정을 코드로 나타내면 다음과 같다:

FSM은 복잡한 분기문을 단순한 전이표(transition table) 로 표현한다. 상태별 로직을 독립적으로 유지할 수 있어 확장성이 좋다.


6. 감시자 패턴 (Observer Pattern)

“누군가가 무언가를 보고 있다.”

이벤트를 발생시키는 쪽은 감시 대상(Observable), 이벤트를 처리하는 쪽은 감시자(Observer) 다.

Ruby 예시:

👉 여러 콜백을 등록하고, 한 이벤트 발생 시 모두 호출된다. 하지만 모든 감시자가 등록되어 있어야 한다는 제약 때문에 결합도가 높아질 수 있다.


7. 게시-구독 (Publish–Subscribe)

감시자 패턴의 결합도를 낮춘 형태. 발행자(Publisher)구독자(Subscriber) 가 직접 연결되지 않고, 채널(Channel) 을 통해 간접적으로 통신한다.

  • 발행자: 특정 채널에 이벤트를 보냄

  • 구독자: 관심 있는 채널을 구독함

  • 메시지는 채널을 통해 비동기적으로 전달됨

이 구조는

  • 느슨한 결합(loose coupling),

  • 병렬 처리,

  • 분산 시스템 이벤트 전달 에 모두 적합하다.


8. 반응형 프로그래밍과 스트림 (Reactive Programming & Streams)

“이벤트를 데이터처럼 다뤄라.”

이벤트가 연속적으로 발생한다면, 그것은 시간을 따라 흐르는 데이터 스트림(stream) 이 된다.

대표적인 구현이 RxJS.

📈 0.5초마다 동물 이름을 하나씩 출력하는 스트림이 만들어진다. 이벤트와 시간의 흐름이 “데이터 파이프라인”으로 결합된 형태다.


9. 비동기 스트림과 REST 결합

RxJS는 REST 호출도 스트림으로 연결할 수 있다:

여러 요청이 병렬로 실행되어, 각 응답이 독립적인 이벤트로 처리된다.

💡 동기/비동기를 하나의 추상화로 통합하는 것이 반응형 프로그래밍의 가장 큰 강점이다.


10. 어디에나 이벤트가 있다

이벤트는 단순히 UI 클릭만이 아니다.

  • 로그인이 성공했다

  • 파일이 수정되었다

  • 센서가 감지했다

  • 트랜잭션이 커밋되었다

모든 시스템은 “이벤트의 연쇄”로 움직인다. 이 이벤트를 중심으로 코드를 구성하면, 시스템은 실세계를 반영하는 유연한 흐름을 갖게 된다.


11. 관련 항목

  • Topic 28: 결합도 줄이기

  • Topic 36: 철판 (Concurrency & Synchronization)


“코드는 현실의 시간축 위에서 반응해야 한다.” 이벤트, 상태, 스트림을 저글링하라. Don’t fight the world. Model it.

🧩 변환 프로그래밍 — “프로그램은 결국 변환이다”

“자신이 하고 있는 일 하나의 과정으로 서술할 수 없다면, 자기가 뭘 하고 있는지 모르는 것이다.” – W. 에드워즈 데밍

✔️ 프로그래밍은 곧 변환 과정이다

우리는 코드를 짤 때 클래스 구조, 언어 문법, 알고리즘, 프레임워크 고민에 대부분의 시간을 쓴다. 하지만 정작 프로그램의 본질이 무엇인지는 생각하지 않는다.

📌 프로그램의 본질: 입력을 받아 출력으로 ‘변환’하는 것

  • 파일을 읽고 →

  • 특정 규칙을 적용하며 →

  • 결과를 출력한다

이 단순한 흐름이 모든 프로그램의 근본이다.

하지만 이 본질을 잊으면, 코드는 불필요하게 복잡해지고 “왜 만든 기능인지”조차 불명확한 구조가 된다.


🔍 1970년대로 돌아가 파이프라인을 보자

옛 유닉스 환경에서는 에디터도 부실했고, C 컴파일러조차 불편했다. 그래서 *“잘게 나뉜 프로그램들을 파이프로 연결해 복잡한 작업을 완성”*하는 방식이 자연스럽게 발달했다.

대표적인 예:

이 명령은 여러 변환 단계를 연결해 원하는 결과를 만들어낸다.

단계별로 쪼개보면?

1) find . -type f

→ 디렉터리 내 모든 일반 파일 목록을 출력

2) xargs wc -l

→ 각 파일의 줄 수를 구한다

3) sort -n

→ 줄 수 기준 오름차순 정렬

4) tail -5

→ 가장 줄 수가 많은 다섯 개만 출력

이렇게 보면, 전체는 단순히 **연결된 변환들의 연속(line)**일 뿐이다.


📦 데이터 공장처럼 생각하기

책에서는 이 구조를 **“공장 조립 라인”**에 비유한다.

입력(원자재)을 넣으면 → 변환 단계를 거쳐 → 완성된 결과물이 나온다.

이 사고방식은 코드를 작성할 때도 그대로 적용된다.


🧠 변환 모델로 생각하기

책에서는 이를 파이프라인(pipeline) 철학으로 정리한다. 각 단계는 다음 작업의 입력이 되어 흐른다.

예시 그림 구성:

이 단계를 통해 **“가장 줄 수가 긴 파일 5개”**라는 결과가 나온다.


🧩 예제: 애너그램 탐색기 만들기

이제 실전 예제로 ‘애너그램(anagram)’ 프로그램을 만든다고 해보자. 입력된 단어로 만들 수 있는 조합, 사전 검색, 분류 작업을 변환 단계로 나눠본다.

변환 단계 요약

단계
변환 내용
예시

단계 0

초기 입력

"lyvin"

단계 1

모든 글자 조합 구하기

lv, ly, lvy, …

단계 2

각 조합을 정렬한 signature 만들기

ilv, ilny, …

단계 3

사전에서 signature에 맞는 단어 찾기

ivy, yin, vinyl …

단계 4

길이 기준으로 묶기

3→ivy, 4→liny, 5→vinyl

이 전체 흐름이 하나의 변환 파이프라인이다.


🧪 실제 코드 예시(엘릭서)

책에서는 엘릭서로 파이프라인을 구현한다.

예: 가능한 조합 생성

이런 식으로 각 단계를 하나의 변환 함수로 만들고 마지막에 연결해 하나의 파이프라인을 완성한다:


🛠 오류 처리는 어떻게?

세상은 완벽하지 않기 때문에 변환 도중 오류가 날 수 있다.

책은 이를 간단한 wrapper(튜플)로 처리한다:

  • 성공: {:ok, 결과}

  • 실패: {:error, 이유}

변환 단계 중 어느 단계에서든 에러가 나면 그 이후 단계는 실행되지 않고 {:error, 이유}가 그대로 파이프라인을 지나간다.

이 방식은 명확하고, 테스트하기 쉽고, 확장이 용이하다.


🧭 왜 이것이 중요한가?

프로그램이 복잡해지는 이유는 대부분 “데이터 흐름”이 아니라 “구조, 클래스, 메서드 호출 관계”에 집착하기 때문이다.

하지만 책이 강조하는 핵심은 단 하나:

프로그램은 입력을 받아 출력으로 변환하는 과정이다.

이 관점으로 전환하면,

  • 기능 설계 명확해지고

  • 테스트가 쉬워지고

  • 오류 처리 구조가 간단해지고

  • 대규모 리팩토링이 쉬워진다


📝 실용 정리

✔️ 변환 중심으로 사고하라

입력 → 단계별 변환 → 출력 이 흐름만 명확하면 코드는 단순해진다.

✔️ 복잡도는 구조가 아니라 흐름에서 줄인다

결국 변환들이 잘 연결되어 있으면 프로그램은 자연스럽게 이해된다.

✔️ 파이프라인은 언어에 상관 없다

어떤 언어든 변환 철학만 있으면 적용 가능하다.

🧱 Topic 31 — 상속세: 상속은 왜 이렇게 위험한가

“당신이 원한 것은 바나나였지만, 당신이 받은 것은 바나나를 들고 있는 고릴라와 정글 전체다.” — 조 암스트롱

“객체지향 언어를 쓰면 당연히 상속을 써야 하지 않나?” 많은 개발자가 이렇게 생각한다. 하지만 현실에서 상속은 막강한 만큼 위험하고, 대부분의 경우 적합하지 않다.

이 글에서는 상속이 왜 문제를 일으키는지, 그리고 상속 없이도 더 깔끔하게 구조를 설계하는 방법을 살펴본다. 코드는 모두 10년차 코틀린 개발자 관점으로 재구성했다.


🕰️ 상속의 역사: Simula67이 의도한 것

처음 상속이 등장한 시절, 목적은 지금과 달랐다. Simula67에서 상속은 단순히 “여러 타입을 하나의 리스트에 담기 위한 편의 기능”이었다.

초기 개념은 대략 이런 느낌에 가까웠다:

  • 여러 객체를 한 리스트에 넣고 싶다

  • 공통 필드를 prefix로 갖고 있으면 편하겠다

  • 그래서 “상속 비슷한 것”이 등장

지금 우리가 사용하는 “부모 클래스—자식 클래스” 구조는 그 이후 스몰토크와 C++에 의해 굳어진 형태다.


⚠️ 상속이 위험한 이유 1: 결합 폭발

상속을 쓰면 자식 클래스는 부모 클래스의 구현에 강하게 결합된다. 부모의 필드, 메서드, 내부 로직, 심지어 변경 이력까지 전부 자식에게 흘러들어온다.

아래는 책의 Ruby 예제를 코틀린 버전으로 재구성한 것이다.

❗ 잘못된 상속 예 (코틀린)

이 코드의 문제를 보자.

  • Vehicle의 moveAt() 구현이 변경되면 Car는 그대로 영향받는다

  • Car가 Vehicle의 내부 구조를 “상식적으로” 안다고 착각한다

  • Vehicle이 API를 바꾸면 Car는 바로 고장난다

  • Car는 Vehicle이라는 설계 결정에서 벗어날 수 없다

코드 재사용처럼 보이지만, 사실 결합도 급증이다.


⚠️ 상속이 위험한 이유 2: 타입 분류를 위해 상속을 쓰는 것은 부적절

많은 사람이 상속을 “타입 분류”라고 착각하지만, 현실의 도메인은 훨씬 복잡하다.

예를 들어 Car는 Vehicle이지만 동시에:

  • 보험 대상(InsuredItem)

  • 대출 담보물(Collateral)

  • 회계상의 자산(Asset)

이 될 수 있다.

단일 상속으로는 현실의 다중 정체성을 반영할 수 없다. 그래서 옛날 C++이 다중 상속을 만들었지만 그것은 더 큰 혼란만 만들었다.


🧩 상속의 대안 1 — 인터페이스 / 프로토콜

상속 없이도 타입을 통합할 수 있다. 코틀린에서는 **인터페이스 + 기본 구현(default method)**로 충분하다.

✔️ 다형성 목적이라면 인터페이스가 정답

장점

  • 다중 구현 가능

  • 필요 함수만 강제

  • 상속 트리 없음

  • 도메인 정체성 충돌 없음


🧩 상속의 대안 2 — 위임(Delegation)

코틀린은 위임을 언어 차원에서 지원한다 (by 키워드 제공).

✔️ Repository 기능을 상속하지 않고 위임으로 해결

장점

  • Account는 Persistence API 전체를 상속받지 않는다

  • 필요한 메서드만 노출

  • Persistence 구현 변경시 Account 영향 없음

  • 결합도 ↓, 유연성 ↑


🧩 상속의 대안 3 — 믹스인 / 트레이트 / extension

코틀린은 mixin은 없지만, interface + default method + 확장 함수 조합으로 믹스인을 충분히 구현할 수 있다.

공통 finder 기능 믹스인 예시 (코틀린 스타일)

mixin의 핵심 기능을 코틀린에서는 인터페이스 + 디폴트 메서드로 대체한다.


🧪 계층이 복잡해지면 위험은 기하급수적으로 증가한다

현실 시스템은 금방 복잡해진다.

  • 검증 로직이 많아짐

  • 정책마다 조건이 다름

  • API 규칙 다름

  • UI마다 제약 다름

상속 트리로 이 모든 것을 해결하려 하면 트리가 기괴하게 커진다.

책에서 나온 복잡한 상속 트리 그림은 코틀린 백엔드 개발자가 Spring에서 계층 구조를 잘못 설계했을 때 종종 보는 모습 그대로다.


🧩 도메인 검증의 현실: 상속보다 mixin/조합이 더 적합하다

예를 들어 "계정 검증"이라는 공통 기능이 있다고 하자.

코틀린에서는 이렇게 구현하는 것이 훨씬 자연스럽다:

➡️ 상속 트리가 늘어나지 않고, ➡️ 필요한 기능만 조립하며, ➡️ 검증 로직이 분리되며, ➡️ 변경의 충격이 국소적이다.


🎯 결론 — 상속이 답인 경우는 거의 없다

Topic 31이 전달하는 핵심 메시지는 매우 명확하다.

✔ 상속을 피하고 인터페이스·위임·믹스인을 먼저 고려하라

✔ 상속은 결합도를 급격히 증가시킨다

✔ 타입 정리는 상속 계층보다 조합(composition)이 맞다

✔ 공통 기능은 mixin/trait/interface default method로 해결하라

✔ 프레임워크가 강제하지 않는 이상 상속을 쓰지 마라

🧩 Topic 32 — 설정(Configuration): 코드 밖으로 빼라

“모든 물건은 제자리에 두고, 일은 모두 때를 정해서 하라.” — 벤저민 프랭클린

애플리케이션이 출시된 후, 바뀔 가능성이 있는 값에 코드가 직접 의존하고 있다면 그 값은 “코드 내부”가 아니라 **외부 설정(external configuration)**으로 관리하는 것이 올바르다.

  • 환경이 다르면 값이 달라진다

  • 고객마다 정책이 다를 수 있다

  • 인프라 환경이 변경될 수 있다

  • 서버 위치/로깅/포트/권한 같은 값은 실행 환경마다 다르다

따라서 설정을 외부로 빼두면 애플리케이션은 더 유연해지고, "코드가 환경에 종속되지 않는" 구조를 만들 수 있다.


🧭 Tip 55 — 외부 설정으로 애플리케이션을 조정할 수 있게 하라

일반적으로 설정 데이터에 들어가는 값들:

  • 외부 API/DB 인증 정보

  • 로그 레벨, 로그 저장 위치

  • 포트 번호, IP 주소, 기계/클러스터 이름

  • 특정 환경에서만 적용되는 검증 값

  • 배송비 같은 정책성 매개변수

  • 지역(국가/언어)에 따른 서식

  • 라이선스 키

➡️ 이 값들이 코드 안에 박혀 있다면 애플리케이션은 환경 변화에 매우 취약해진다.


🏗️ 정적(static) 설정: 파일이나 DB로 관리

현대 애플리케이션 대부분은 다음 방식 중 하나로 정적 설정을 관리한다:

  • YAML (application.yml)

  • JSON

  • Properties 파일

  • 데이터베이스 테이블

코틀린 + Spring이라면 자연스럽게 이러한 형태가 된다.

✔️ 실전 예 — application.yml

✔️ 실전 예 — Kotlin 구성 객체로 바인딩

이제 서비스 코드는 설정에 종속되지만 환경 파일만 바꾸면 애플리케이션 전체가 다른 정책으로 작동한다.


🚚 서비스형 설정(Configuration-as-a-Service)

기업 규모가 커지면, 설정을 단순 파일/DB로 관리하는 것만으로는 부족해진다. 이때 설정 서버(Config Server) 같은 별도 서비스가 등장한다.

예:

  • Spring Cloud Config

  • AWS AppConfig

  • Consul KV

  • etcd

  • Git 기반 설정 저장소

장점

  • 여러 마이크로서비스가 설정을 공유

  • 인증/권한 컨트롤 가능

  • 인스턴스 전체 설정을 동시에 변경 가능

  • 설정 변경을 실시간으로 동기화

실전 예 — 코틀린에서 설정 서버로부터 값 받기

이제 코드를 바꾸지 않고도 운영자가 AppConfig 값만 바꾸면 배송비 정책 전체가 바뀐다.


🦤 도도 코드를 작성하지 말라 (Dodo Code)

책에서는 “환경에 적응하지 못해 멸종된 도도새(Dodo)”를 비유로 사용한다.

➡️ 즉, 환경 변화에 반응하지 못하는 코드는 곧 죽은 코드다.

아래가 도도 코드:

  • 설정을 하드코딩한다

  • 값이 바뀔 때마다 코드 릴리즈가 필요

  • 빌드 → 배포 → 재시작을 반복해야만 한다

  • 여러 서비스가 다른 정책을 가져야 하는데 모두 코드로 박혀 있다

현대 백엔드 시스템에서 이런 코드는 생존할 수 없다.


🧾 실제 코틀린 서비스에서 자주 등장하는 설정 Anti-Pattern

❌ 1. 하드코딩된 URL, 포트, 토큰

❌ 2. 환경 별 if/else 분기

❌ 3. 운영 중 정책 변경을 배포로 해결

→ “배송비 좀 바꿔주세요” → 배포 필요 → 장애 위험 증가

이 모든 문제는 외부 설정화로 즉시 해결된다.


🛡️ 제대로 된 설정 구조를 설계하는 법

✔️ 1. 소스코드와 설정을 철저히 분리

설정은 YAML/DB/설정 서버에 두고 코드에서는 오직 “참조”만 한다.

✔️ 2. 모든 실행 환경에서 safe fallback 제공

  • 설정 서버가 죽으면 local YAML 값 사용

  • 존재하지 않는 키면 default 값 사용

✔️ 3. 설정 변경은 코드 배포 없이 반영

  • 설정 서버

  • 런타임 refresh

  • 메시지 기반 변경 알림 (Kafka/SNS)

✔️ 4. 설정도 테스트해야 한다

설정을 잘못 넣으면 서비스 전체가 망가질 수 있다.


🧪 실전 예: 정책을 외부 설정으로 빼기 (코틀린)

기존 나쁜 코드

➡️ 정책이 바뀔 때마다 반드시 배포가 필요하다.

개선된 코드

환경 파일만 바꾸면 끝.


📌 결론: 설정을 코드 밖에 두어라

Topic 32 전체의 핵심 메시지는 단 하나다.

코드는 로직을 담고, 설정은 외부에서 조정된다. 두 역할을 섞지 마라.

✔ 설정을 외부로 빼면…

  • 배포 없이 정책 변경 가능

  • 고객/환경별 동작 분리

  • 유지보수 비용 절감

  • 개발과 운영 분리

  • 재사용성, 이식성 증가

✔ 상시 변화하는 현대 서비스에는 필수다

  • 마이크로서비스

  • 서버리스

  • 글로벌 서비스

  • 고객별 정책

  • A/B 테스트

  • 환경별 다양한 런타임


Last updated