Blog / Essay / 개발자 필독서 추천 7권 리뷰 — GoF, Effective C#,...
Essay

개발자 필독서 추천 7권 리뷰 — GoF, Effective C#, 종만북, 클린 코드, 리팩토링

개발자 책 추천 7권을 리뷰한다. GoF 디자인 패턴, Effective C#, 종만북, 클린 코드, 리팩토링의 핵심 내용과 읽는 순서, 책들 사이의 연결 관계까지 실제로 완독한 후기로 정리한다.

들어가며

개발 공부를 하면서 쌓아둔 기술 서적들이 있다. “책보다 프로젝트를 해라”라는 말이 절반은 맞다. 그러나 어느 순간부터는 코드만 써서는 풀리지 않는 질문들이 쌓인다. 왜 이렇게 짜야 좋은지, 지금 쓰는 패턴의 이름이 뭔지, 내가 고민하던 문제를 이미 누군가가 더 깔끔하게 정리해 두지는 않았는지. 그럴 때 잘 정리된 책 한 권은 수십 번의 시행착오를 아껴준다.

최근에 완독한 7권을 정리한다. 네 가지 축으로 묶인다.

설계 GoF의 디자인 패턴
언어 심화 Effective C#, Effective C# Advanced
알고리즘 프로그래밍 대회에서 배우는 알고리즘 전략 1, 2
코드 품질 클린 코드, 리팩토링 개정판

한 권씩 핵심과 감상을 정리하고, 마지막에 책들 사이의 연결을 다룬다.


1. GoF의 디자인 패턴

Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (1994)

핵심

23개의 패턴을 생성(Creational), 구조(Structural), 행위(Behavioral) 세 범주로 분류한 고전이다. Singleton, Factory Method, Abstract Factory, Builder, Prototype, Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy, Chain of Responsibility, Command, Iterator, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor, Interpreter. 지금은 이름만 들어도 익숙하지만, 그 이름들이 여기서 시작됐다.

책 자체가 전하는 가장 중요한 메시지는 패턴 목록이 아니다. “Program to an interface, not an implementation”“Favor object composition over class inheritance” 두 원칙이다. 이 두 줄이 책 전체의 뼈대다. 상속 대신 합성을 택하라는 조언은, 당시 C++의 다중 상속 지옥을 겪은 저자들의 처방이었다.

감상

솔직히 예제 코드(C++, Smalltalk)는 30년 묵은 문법이라 읽기 까다롭다. 최신 언어에 익숙한 상태로 보면 과하게 장황한 부분도 많다. 하지만 “왜 이 패턴이 필요한가”를 설명하는 Motivation 섹션은 여전히 강력하다. Decorator 패턴을 설명할 때 커피 주문 예제 같은 구체적인 상황이 먼저 나오고, 그 상황을 해결하는 구조를 끌어내는 전개는 설계서의 모범이다.

가장 인상 깊었던 패턴은 Visitor였다. 데이터 구조와 연산을 분리하면서 새로운 연산을 추가할 때 기존 클래스를 건드리지 않아도 되는 발상 — 처음 이해했을 때 “이런 발상이 가능하구나” 싶었다. 반대로 Singleton은 읽고 나니 오히려 경계하게 됐다. 이 책이 전파한 패턴 중 가장 남용되고, 가장 의존성 주입이라는 현대적 대안에 밀려난 패턴이다.

한 번에 다 소화할 수 있는 책은 아니다. 프로젝트에서 “어? 이거 GoF에서 본 그 구조 아닌가” 싶을 때 해당 챕터만 다시 펼쳐 읽는 사전식 사용이 맞는다.


2. Effective C#

Bill Wagner

핵심

50개 항목으로 구성된 C# 모범 사례집이다. 각 항목은 “~을 하라” 또는 “~을 이해하라” 형식으로 시작한다. var 사용법, readonlyconst의 차이, IDisposableusing 문, string vs StringBuilder, GetHashCode()의 올바른 구현, 제네릭 제약, LINQ 쿼리 연산자의 지연 평가 같은 주제가 이어진다.

대표적인 몇 가지 항목:

  • “as 연산자를 사용하라”: (MyType)obj 캐스트 대신 obj as MyType을 쓰면 null 반환으로 실패를 우아하게 처리할 수 있다
  • “readonly 참조 필드의 숨은 함정을 이해하라”: readonly는 참조만 고정하지, 참조된 객체 내부는 여전히 변경 가능하다
  • “Equals, GetHashCode, operator==, IEquatable를 구현할 때의 관계를 이해하라”: 하나를 건드리면 나머지 셋도 전부 맞춰야 한다

감상

Unity를 오래 다루면서 C#을 “C++에서 가비지 컬렉터가 있는 언어” 정도로만 이해했었다. 이 책은 그 안일한 이해를 깨준다. C#에는 Java에도, C++에도 없는 고유한 관용구가 있고, 그것을 모른 채 쓰면 성능과 안정성 양쪽에서 손해를 본다.

특히 박싱(boxing)과 값 타입의 미묘한 동작에 대한 항목들이 기억에 남는다. structobject로 캐스트하는 순간 힙 할당이 일어나고, foreach로 순회하는 컬렉션이 IEnumerable로 박싱되는 순간 GC 압박이 시작된다. Unity에서 프레임 드랍을 쫓을 때 프로파일러가 가리키는 곳이 왜 거기인지를 이해하게 된다.

50개 항목 중 절반 이상은 “알고 있었지만 왜 그래야 하는지는 몰랐던” 것들이었다. 그 이유를 명확히 언어화해 준다는 점에서 가치가 크다.


3. Effective C# Advanced (More Effective C#)

Bill Wagner

핵심

Effective C#의 속편으로, 또 다른 50개 항목을 다룬다. 1편이 기본기라면 2편은 심화다. 제네릭 제약의 고급 활용, LINQ의 내부 동작, async/await의 함정, 병렬 처리, 동적 타이핑, 예외 처리의 예외적 상황들.

인상 깊은 항목들:

  • “async 메서드를 동기적으로 기다리지 말라”: .Result.Wait()는 데드락 지뢰다
  • “IEnumerable로 반환하고 LINQ 체인을 끊지 말라”: 조기에 ToList()를 호출하면 지연 평가의 이점이 사라진다
  • **“ValueTask로 빈번한 동기 완료를 최적화하라"**: 항상 비동기 경로를 타지 않는 경우 `Task` 할당 자체가 비용이다

감상

1편이 “모르면 버그를 만든다”였다면, 2편은 “알면 한 단계 위의 코드를 쓸 수 있다”에 가깝다. async/await 파트는 특히 밀도가 높다. 동기/비동기 경계에서 발생하는 데드락, ConfigureAwait(false)를 언제 써야 하는지, 취소 토큰을 어디까지 전달해야 하는지 같은 질문들에 대한 구체적인 답이 있다.

내가 가장 자주 다시 펼쳐 보는 파트는 제네릭과 식 트리(Expression Tree) 쪽이다. LINQ to SQL이나 ORM을 직접 만들어 본 적은 없지만, R3 같은 Reactive 라이브러리가 내부적으로 어떻게 타입을 다루는지 이해하는 데 큰 도움이 됐다.

1편을 읽고 2편을 읽으면 C# 언어 전체에 대한 관점이 생긴다. 이 언어가 어디에 신경 써서 설계됐고, 어떤 부분은 역사적 타협의 결과인지를 구별할 수 있게 된다.


4. 프로그래밍 대회에서 배우는 알고리즘 전략 1

구종만 (종만북 1권)

핵심

한국어로 쓰인 알고리즘 책 중 가장 완성도가 높다는 평을 듣는 책이다. 1권은 기초와 중급을 다룬다. 시간 복잡도 분석, 문제 해결 전략(분할 정복, 동적 계획법, 탐욕법), 큐/스택/트리/힙 같은 자료구조, 정렬과 탐색.

이 책의 가장 큰 강점은 문제 접근법에 대한 서술이다. 단순히 “이 문제는 DP로 푼다”가 아니라, “왜 이 문제를 DP로 인식해야 하는지, 상태를 어떻게 정의할지, 부분 문제 중복을 어떻게 발견할지”를 단계적으로 설명한다. 각 챕터 끝에는 연습 문제가 있고, 그 문제들의 해답 해설이 책의 또 다른 축을 이룬다.

감상

동적 계획법 챕터가 가장 오래 기억에 남았다. DP는 “외워서 푸는” 것이 아니라 “문제에서 부분 구조를 발견하는” 것이라는 관점을 명확히 해준다. 메모이제이션과 타불레이션의 차이, 상태 전이 식을 세우는 연습, 공간 최적화까지 — 단순 암기로는 절대 도달할 수 없는 층위까지 데려간다.

또 하나 인상적이었던 것은 코드 스타일이다. 저자는 “대회용 짧은 코드”가 아니라 “명확한 구조와 이름”을 우선하는 코드를 쓴다. 책 전체의 C++ 예제가 일관된 스타일로 작성돼 있어서, 이 책을 따라가는 것만으로도 알고리즘 코드를 “읽기 좋게” 쓰는 감각이 생긴다.

국내 개발자 입장에서 가장 큰 장점은 한국어로 된 정확한 용어 정리다. 영어 원서로 알고리즘을 배우면 개념은 이해해도 용어가 혼란스럽다. 이 책은 용어 선택이 정교하고 일관돼서, 다른 사람과 대화할 때도 편하다.


5. 프로그래밍 대회에서 배우는 알고리즘 전략 2

구종만 (종만북 2권)

핵심

2권은 고급 주제를 다룬다. 그래프 알고리즘(BFS/DFS, 최단 경로, 최소 신장 트리, 강연결 요소, 네트워크 플로우), 문자열 처리(KMP, 접미사 배열, 아호-코라식), 계산 기하학, 조합 게임 이론, 수치 알고리즘.

1권이 “알고리즘으로 문제를 푸는 법”이라면, 2권은 “특정 영역의 전문 기법”에 더 가깝다. 각 장이 독립적이어서, 필요한 영역만 골라 읽어도 되는 구성이다.

감상

네트워크 플로우 챕터가 가장 충격적이었다. 처음엔 “이걸 실무에서 쓸 일이 있을까” 싶었지만, 읽고 나니 할당 문제, 매칭 문제, 최소 컷 문제가 전부 같은 프레임워크 안에 들어온다는 것이 놀라웠다. 문제를 그래프 플로우로 모델링하는 사고방식 자체가 강력한 도구다.

문자열 알고리즘도 의외로 자주 생각난다. KMP의 실패 함수를 직접 구현해 본 경험은 “패턴 매칭을 O(n+m)에 끝낸다”는 주장이 왜 가능한지 체감하게 해준다. 라이브러리를 쓸 때와 원리를 아는 것은 전혀 다른 이해다.

반면에 계산 기하학은 솔직히 어려웠다. 부동소수점 오차를 어떻게 다룰지, 벡터 외적으로 방향성을 판단하는 법 같은 내용은 필요할 때 다시 펼쳐 보는 레퍼런스로 활용하고 있다.

2권은 한 번에 완독한다기보다, 도구함으로 갖고 있는 책에 가깝다.


6. 클린 코드

Robert C. Martin

핵심

“깨끗한 코드란 무엇인가”에 대한 정의를 시도하는 책이다. 의미 있는 이름, 작은 함수, 불필요한 주석을 줄이기, 형식 맞추기, 객체와 자료 구조의 차이, 예외 처리, 경계, 단위 테스트, 클래스 설계, 냄새와 휴리스틱 — 17개 장에 걸쳐 각 주제를 다룬다.

핵심 주장은 단순하다. 코드는 짜는 시간보다 읽히는 시간이 훨씬 길다. 그러므로 읽기 쉽게 써야 한다. 함수는 한 가지 일만 하고, 이름은 의도를 드러내고, 주석 대신 코드 자체가 말하도록 한다. 이 책이 SOLID 원칙을 대중화했다.

감상

호불호가 갈리는 책이다. “함수는 4줄이 넘으면 너무 길다”는 주장은 극단적으로 느껴지고, Java 중심 예제와 저자의 강한 주관은 모든 상황에 맞지는 않는다. 그럼에도 이 책이 여전히 필독서로 꼽히는 이유는, “왜 그래야 하는지”에 대한 서술이 설득력 있기 때문이다.

가장 많이 생각난 구절은 “함수의 이름은 동사여야 하고, 클래스의 이름은 명사여야 한다“는 단순한 규칙이었다. 규칙 자체가 아니라, 이 규칙이 코드에서 의도를 얼마나 선명하게 만드는지 알게 된 게 중요했다.

개인적으로 가장 동의하지 못한 부분은 주석에 대한 지나치게 강경한 태도다. 저자는 대부분의 주석이 “나쁜 코드에 대한 변명”이라고 본다. 하지만 실무에서 “왜 이 순서로 호출해야 하는지” 같은 의도 주석은 코드만으로는 설명되지 않는다. 이 책의 조언을 문자 그대로 받아들이기보다, 원칙을 이해하고 맥락에 맞게 조절해야 한다.

마지막 장의 “냄새와 휴리스틱”은 그 자체로 체크리스트 역할을 한다. 내가 쓴 코드를 리뷰할 때 이 리스트를 훑는 것만으로도 개선 포인트가 보인다.


7. 리팩토링 개정판

Martin Fowler

핵심

1999년 초판을 JavaScript 기반으로 다시 쓴 개정판이다. 핵심은 “기능 변경 없이 코드 구조를 개선하는 작은 변환들의 카탈로그”다. 이름 바꾸기(Rename Variable), 함수 추출(Extract Function), 임시 변수 인라인(Inline Temp), 조건문 분해(Decompose Conditional), 클래스 추출(Extract Class) 등 약 60여 개의 리팩토링이 정리돼 있다.

각 리팩토링마다 동일한 구조로 기술된다. 동기(Motivation), 절차(Mechanics), 예시(Examples). 동기에서 “왜 이 변환이 필요한가”, 절차에서 “단계별로 어떻게 안전하게 적용할 것인가”, 예시에서 “실제 코드에서 어떻게 보이는가”를 보여준다. 이 3단 구성이 책 전체를 일관되게 관통한다.

코드 냄새(Code Smells) 챕터도 유명하다. 중복된 코드, 긴 함수, 큰 클래스, 긴 매개변수 리스트, 가변 데이터, 산탄총 수술(Shotgun Surgery), 특성 선망(Feature Envy) 같은 용어들이 여기서 나왔다.

감상

리팩토링 책의 진짜 가치는 카탈로그 자체가 아니라, “안전하게 변경한다”는 개념이다. 저자는 각 변환을 작은 단계로 쪼개고, 매 단계마다 테스트를 돌리라고 반복적으로 강조한다. 큰 변경을 한 번에 하지 말고, 아주 작은 변경을 여러 번 하라는 원칙 — 이건 단순한 기술이 아니라 태도의 문제다.

개정판의 JavaScript 예제는 Java로 쓴 초판보다 훨씬 읽기 편했다. 함수가 일급 객체라는 점을 활용한 리팩토링(함수를 매개변수로 넘기기, 함수를 명령으로 변환하기 등)이 자연스럽게 설명된다.

가장 실용적으로 와닿은 리팩토링은 “함수 추출(Extract Function)”이었다. 코드 냄새를 볼 때 첫 번째 대응은 거의 항상 “이 덩어리를 이름 있는 함수로 빼내자”다. 이름을 붙이는 순간 그 코드의 의도가 드러나고, 그 의도가 맞지 않으면 더 근본적인 문제가 보인다.

이 책의 리팩토링은 외우는 것이 아니다. 한 번 훑고, 실제 코드를 고칠 때 “이 상황에 맞는 리팩토링이 책에 있었던 것 같은데” 싶을 때 찾아보는 방식으로 쓰는 게 맞다. 그런 점에서 리팩토링 책은 GoF와 사용법이 비슷하다.


책들을 잇는 실들

7권을 따로 읽으면 각각 다른 주제 같지만, 함께 놓고 보면 서로를 완성한다.

클린 코드 × 리팩토링: 현재와 과정

클린 코드는 “좋은 코드가 어떤 상태여야 하는가”를 정의한다. 리팩토링은 “나쁜 코드를 좋은 코드로 바꾸는 과정”을 정의한다. 전자가 목표 상태라면 후자는 변환 절차다. 두 권 다 “코드 냄새”라는 개념을 공유하지만, 대응법이 다르다. 클린 코드가 “이렇게 쓰지 마라”라면, 리팩토링은 “이미 이렇게 써 버린 코드를 단계적으로 어떻게 고치는가”를 말한다.

두 권을 함께 읽어야 시야가 완성된다. 클린 코드만 읽으면 “이상적인 코드”에 집착하다 실무에서 길을 잃고, 리팩토링만 읽으면 “왜 고쳐야 하는가”에 대한 감각이 약해진다.

GoF × 리팩토링: 패턴은 목적지가 아니라 경로

GoF를 먼저 읽고 리팩토링을 읽으면 흥미로운 점이 보인다. 리팩토링 책의 여러 변환들이 GoF 패턴을 “향해서” 또는 “벗어나서” 움직인다는 점이다. Fowler는 “Replace Conditional with Polymorphism”이라는 리팩토링을 통해 State 패턴이나 Strategy 패턴으로 진화하는 과정을 보여준다.

GoF는 “이런 구조가 있다”라고 보여주고, 리팩토링은 “현재 코드에서 그 구조로 가는 길”을 보여준다. 디자인 패턴을 “처음부터 그렇게 설계해야 하는 것”으로 오해하면 안 된다. 실제로는 대부분 리팩토링을 거치면서 도달하는 중간 결과다.

Effective C# × 종만북: 도구와 문제의 접점

얼핏 보면 무관한 조합이다. 한쪽은 언어 세부사항, 다른 한쪽은 알고리즘. 그런데 둘을 이어 읽으면 “문제를 푸는 도구로서의 언어”라는 관점이 생긴다.

종만북에서 배운 알고리즘을 실제 코드로 옮길 때, Effective C#에서 배운 컬렉션 선택, 제네릭 제약, 지연 평가, 값 타입 최적화가 차이를 만든다. List<T> vs Array, Dictionary<TKey, TValue>의 버킷 동작, struct의 박싱 회피 — 이런 세부사항이 알고리즘의 이론적 복잡도와 실제 성능 사이를 잇는다.

GoF × Effective C#: 언어에 녹아든 패턴

GoF 패턴 중 상당수는 현대 언어에 이미 내장돼 있다. C#의 IEnumerable<T> + foreach는 사실상 Iterator 패턴이고, eventdelegate는 Observer 패턴, LINQ의 지연 평가는 Lazy Initialization이다. Effective C#은 이런 내장 구조를 “정확히 어떻게 사용할지”를 가르친다.

GoF 시대의 개발자는 이런 패턴을 직접 구현해야 했다. 지금은 언어가 제공한다. 그럼에도 GoF를 읽는 이유는, “왜 이런 구조가 언어에 들어왔는지”를 이해하게 되기 때문이다. 그 이해는 라이브러리 API를 설계하거나, 왜 특정 API가 그렇게 생겼는지 분석할 때 직접적으로 쓰인다.

종만북 × 클린 코드: 명확함은 고급 기술이다

종만북의 예제 코드는 알고리즘 책답지 않게 깔끔하다. 구종만 저자는 “짧은 코드”가 아니라 “의도가 드러나는 코드”를 지향한다. 이 원칙은 클린 코드와 정확히 일치한다.

경쟁 프로그래밍 커뮤니티에서는 한 글자 변수명과 압축된 한 줄 코드가 흔하다. 그런 코드는 “빠르게 쓰기”에는 유리하지만 “읽기”에는 치명적이다. 종만북은 알고리즘 코드에도 가독성의 원칙이 적용된다는 것을 보여준다. 그 점에서 알고리즘 책이면서 동시에 일종의 클린 코드 교재다.


마무리

7권 모두 각자의 자리에서 부족함 없이 좋은 책이다. 그러나 가장 크게 배운 것은 각 책 안의 구체적인 내용이 아니라, “이 책들이 서로 어떻게 연결되는가”에 대한 감각이었다.

프로그래밍 공부는 특정 기술을 쌓아 올리는 방식으로만 진행되지 않는다. 서로 다른 영역의 책들이 같은 문제를 다른 각도에서 비추고, 그 각도들이 겹치는 지점에서 이해가 입체화된다. 리팩토링을 배우면 GoF가 다시 보이고, Effective C#을 배우면 종만북의 C++ 코드가 다시 보이고, 클린 코드를 배우면 내가 쓴 예전 코드가 다시 보인다.

모든 책은 언젠가 다시 읽어야 한다. 첫 독서에서 놓친 것이 많기 때문이 아니라, 나 자신이 변해서 다른 부분이 눈에 들어오기 때문이다. 이 7권 역시 몇 년 뒤 다시 펼쳤을 때 새로운 줄이 형광펜에 걸릴 것이다. 그때까지는 이 리뷰가 나의 지금 이해를 고정해 두는 역할을 할 것이다.


GoF, Effective C# 2권, 종만북 2권, 클린 코드, 리팩토링 — 7권을 읽으며 얻은 가장 큰 수확은 각 책의 지식이 아니라, 그 책들이 서로를 어떻게 완성하는지에 대한 지도였다.

댓글

블로그 목록으로
ACHIEVEMENT UNLOCKED
LOADING...
SCORE 000000
HITS
0