이펙티브 소프트웨어 설계

실수와 트레이드오프로부터 배우는 현명한 소프트웨어 설계 가이드
$36.29
SKU
9791158395643
+ Wish
[Free shipping over $100]

Standard Shipping estimated by Tue 04/15 - Mon 04/21 (주문일로부 10-14 영업일)

Express Shipping estimated by Thu 04/10 - Mon 04/14 (주문일로부 7-9 영업일)

* 안내되는 배송 완료 예상일은 유통사/배송사의 상황에 따라 예고 없이 변동될 수 있습니다.
Publication Date 2025/03/06
Pages/Weight/Size 188*240*19mm
ISBN 9791158395643
Categories IT 모바일 > 컴퓨터 공학
Description
소프트웨어 개발의 난제, 트레이드오프 관점에서 해법을 찾다!

『이펙티브 소프트웨어 설계』는 애플리케이션 설계, 계획, 구현에 관한 더 나은 의사결정을 내리는 방법을 알려준다. 잘못된 트레이드오프 결정이 내려진 실제 시나리오를 분석하고, 어떻게 다르게 결정할 수 있었는지 설명한다. 이 책은 다양한 접근 방식의 장단점을 제시하고 소프트웨어 설계에 언제나 유효한 패턴을 탐구한다.

코드 중복이 시스템의 결합도와 진화 속도에 어떤 영향을 미치는지, 단순해 보이는 요구사항에 날짜나 시간 정보와 관련해 어떤 숨겨진 뉘앙스가 존재하는지 이해할 수 있다. 80/20 파레토 원칙에 따라 최적화 범위를 효율적으로 좁히고 분산된 시스템에서 일관성을 보장하는 방법을 살펴보자. 저자가 힘들게 얻은 경험을 여러분의 프로젝트에도 적용해 실수를 미연에 방지하고 의사결정 과정에서 신중한 접근 방식을 취할 수 있을 것이다.
Contents
▣ 01장: 도입

1.1 모든 결정과 패턴의 결과
__1.1.1 단위 테스트 결정 사항
__1.1.2 단위 테스트와 통합 테스트의 비율
1.2 코드 디자인 패턴과 그것이 항상 동작하지 않는 이유
__1.2.1 코드 측정하기
1.3 아키텍처 설계 패턴이 항상 동작하지는 않는 이유
__1.3.1 확장성과 탄력성
__1.3.2 개발 속도
__1.3.3 마이크로서비스의 복잡성
요약

▣ 02장: 코드 중복 대 유연성 - 코드 중복이 항상 나쁘지만은 않다

2.1 코드베이스 사이의 공통 코드와 중복
__2.1.1 코드 중복을 요구하는 새로운 비즈니스 요구사항 추가
__2.1.2 새로운 비즈니스 요구사항 구현
__2.1.3 결과 평가
2.2 라이브러리, 그리고 코드베이스 사이에서 코드 공유
__2.2.1 공유 라이브러리의 트레이드오프와 단점 평가하기
__2.2.2 공유 라이브러리 생성
2.3 독립적인 마이크로서비스로 코드 추출
__2.3.1 독립적인 서비스의 트레이드오프와 단점 살펴보기
__2.3.2 독립적인 서비스에 대한 결론
2.4 코드 중복으로 느슨한 결합 향상시키기
2.5 중복을 줄이기 위해 상속을 사용하는 API 설계
__2.5.1 기초 요청 처리기 추출
__2.5.2 상속과 강한 결합을 살펴보기
__2.5.3 상속과 합성 사이의 트레이드오프 살펴보기
__2.5.4 내재된 중복과 우연한 중복 살펴보기
요약

▣ 03장: 코드에서 신경 써야 할 예외와 오류 처리 패턴

3.1 예외의 계층 구조
__3.1.1 모든 예외를 잡는 방식 대 더 세분화된 오류 처리 방식
3.2 당신이 소유한 코드에서 예외를 처리하기 위한 우수 사례
__3.2.1 공개 API에서 확인된 예외 처리하기
__3.2.2 공개 API에서 확인되지 않은 예외 처리하기
3.3 예외 처리에서 주의할 안티 패턴
__3.3.1 오류가 발생할 경우 자원 닫기
__3.3.2 애플리케이션 흐름을 제어하기 위해 예외를 사용하는 안티 패턴
3.4 타사 라이브러리에서 오는 예외
3.5 멀티스레드 환경에서 주의할 예외
__3.5.1 프라미스 API를 사용한 비동기식 작업 흐름의 예외 처리
3.6 Try로 오류를 처리하는 함수형 접근 방식
__3.6.1 실제 양산 서비스 코드에서 Try 사용하기
__3.6.2 예외를 던지는 코드와 Try를 섞어서 사용하기
3.7 예외 처리 코드의 성능 비교
요약

▣ 04장: 유연성과 복잡성 사이의 균형

4.1 탄탄하지만 확장성은 떨어지는 API
__4.1.1 새로운 컴포넌트 설계
__4.1.2 가장 직관적인 코드로 시작
4.2 클라이언트에게 자신만의 메트릭 프레임워크를 제공하게 허용하기
4.3 훅을 통한 API의 확장성 제공
__4.3.1 훅 API의 예기치 못한 사용 방어하기
__4.3.2 훅 API의 성능 영향
4.4 리스너를 통한 API의 확장성 제공
__4.4.1 리스너 사용 대 훅 사용
__4.4.2 설계의 불변성
4.5 API의 유연한 분석 대 유지보수 비용
요약

▣ 05장: 섣부른 최적화 대 핫 코드 경로의 최적화 - 코드 성능에 영향을 미치는 의사결정

5.1 섣부른 최적화가 나쁠 때
__5.1.1 계정 처리 파이프라인 생성
__5.1.2 잘못된 가정에 기반한 처리 최적화
__5.1.3 성능 최적화 벤치마크
5.2 핫 코드 경로
__5.2.1 소프트웨어 시스템 컨텍스트에서 파레토 법칙 이해하기
__5.2.2 주어진 SLA를 위해 동시 사용자(스레드) 숫자 구성하기
5.3 잠재적인 핫 코드 경로가 존재하는 단어 서비스
__5.3.1 오늘의 단어 얻기
__5.3.2 단어가 존재하는지 검증하기
__5.3.3 HTTP 서비스를 사용해 WordsService를 외부에 공개하기
5.4 핫 코드 경로 탐지
__5.4.1 개틀링을 사용해 API 성능 테스트 생성하기
__5.4.2 MetricRegistry를 사용해 코드 경로 측정하기
5.5 핫 코드 경로의 성능 개선
__5.5.1 기존 해법을 위한 JMH 마이크로벤치마크 생성
__5.5.2 캐시를 사용한 word-exists 최적화
__5.5.3 더 많은 입력 단어를 받기 위한 성능 테스트 변경
요약

▣ 06장: API를 유지보수하기 위한 비용 대 단순함

6.1 다른 도구에서 사용되는 기본 라이브러리
__6.1.1 클라우드 서비스 클라이언트 만들기
__6.1.2 인증 전략 탐색
__6.1.3 구성 메커니즘 이해하기
6.2 의존성 라이브러리의 설정을 외부에 직접 공개하기
__6.2.1 배치 도구 구성하기
6.3 의존성 라이브러리의 설정을 추상화하는 도구
__6.3.1 스트리밍 도구 구성하기
6.4 클라우드 클라이언트 라이브러리를 위해 새로운 설정 추가하기
__6.4.1 배치 도구에 새로운 설정 추가하기
__6.4.2 스트리밍 도구에 새로운 설정 추가하기
__6.4.3 UX 친화성과 유지보수성 측면에서 두 해법을 비교하기
6.5 클라우드 클라이언트 라이브러리에서 설정을 더 이상 사용하지 않기로 결정하거나 제거하기
__6.5.1 배치 도구에서 설정 제거하기
__6.5.2 스트리밍 도구에서 설정 제거하기
__6.5.3 UX 친화성과 유지보수성 측면에서 두 해법 비교하기
요약

▣ 07장: 날짜와 시간 데이터로 효율적으로 작업하기

7.1 날짜와 시간 정보에 대한 개념
__7.1.1 컴퓨터 시간: 인스턴트, 에포크, 시간 간격
__7.1.2 상용 시간: 달력 시스템, 날짜, 시간, 날짜 간격
__7.1.3 시간대, UTC, 그리고 UTC 오프셋
__7.1.4 머리가 아파지는 날짜와 시간 개념들
7.2 날짜와 시간 정보로 작업할 준비
__7.2.1 범위 제한하기
__7.2.2 날짜와 시간 요구사항을 명확하게 만들기
__7.2.3 올바른 라이브러리 또는 패키지 사용하기
7.3 날짜와 시간 코드 구현하기
__7.3.1 개념을 일관성 있게 적용하기
__7.3.2 기본값을 피함으로써 테스트 가능성 개선하기
__7.3.3 텍스트에서 날짜와 시간 값 표현하기
__7.3.4 주석으로 코드 설명하기
7.4 명시하고 테스트해야 하는 특이한 경우
__7.4.1 달력 산술 연산
__7.4.2 자정에 시간대 변환
__7.4.3 모호하거나 건너뛴 시간 처리하기
__7.4.4 진화하는 시간대 데이터로 작업하기
요약

▣ 08장: 컴퓨터에서 데이터 지역성과 메모리 활용하기

8.1 데이터 지역성이란 무엇일까?
__8.1.1 계산을 데이터로 옮기기
__8.1.2 데이터 지역성을 사용한 처리 규모 확장
8.2 데이터 파티셔닝과 데이터 나누기
__8.2.1 오프라인 빅데이터 파티셔닝
__8.2.2 파티셔닝 대 샤딩
__8.2.3 파티셔닝 알고리즘
8.3 여러 파티션에서 가져온 빅데이터 집합을 조인하기
__8.3.1 동일 물리 컴퓨터 내에서 데이터 조인하기
__8.3.2 데이터 이동이 필요한 조인 작업
__8.3.3 브로드캐스팅을 활용한 조인 최적화
8.4 데이터 처리 과정: 메모리 대 디스크
__8.4.1 디스크 기반의 처리 과정
__8.4.2 맵리듀스가 필요한 이유
__8.4.3 접근 시간 계산하기
__8.4.4 램 기반의 처리 과정
8.5 아파치 스파크를 사용한 조인 구현
__8.5.1 브로드캐스트 없이 조인 구현하기
__8.5.2 브로드캐스트로 조인 구현하기
요약

▣ 09장: 외부 라이브러리 - 사용하는 라이브러리가 곧 코드가 된다

9.1 라이브러리를 임포트하고 설정에 대해 완벽하게 책임지기: 기본값에 주의하자
9.2 동시성 모델과 확장성
__9.2.1 비동기식 API와 동기식 API 사용하기
__9.2.2 분산된 확장성
9.3 테스트 가능성
__9.3.1 테스트 라이브러리
__9.3.2 가짜 객체(테스트 더블)와 목 객체로 테스트하기
__9.3.3 테스트 툴킷 통합
9.4 타사 라이브러리의 의존성
__9.4.1 버전 충돌 회피하기
__9.4.2 너무 많은 의존성
9.5 외부 의존성을 선택하고 유지 관리하기
__9.5.1 첫 인상
__9.5.2 코드 재사용에 대한 다양한 접근 방식
__9.5.3 공급 업체 종속
__9.5.4 라이선스
__9.5.5 라이브러리 대 프레임워크
__9.5.6 보안과 업데이트
__9.5.7 의사 결정을 위한 점검 목록
요약

▣ 10장: 분산 시스템에서의 일관성과 원자성

10.1 최소한 한 번 이상 데이터 소스 전송
__10.1.1 노드 하나짜리 서비스 사이의 트래픽
__10.1.2 애플리케이션 호출 재시도하기
__10.1.3 데이터 생성과 멱등성
__10.1.4 CQRS(Command Query Responsibility Segregation) 이해하기
10.2 중복 제거 라이브러리의 단순한 구현
10.3 분산된 시스템에서 중복 제거를 구현할 때 흔히 저지르는 실수
__10.3.1 노드가 하나만 있는 컨텍스트
__10.3.2 다중 노드 컨텍스트
10.4 경쟁 조건을 방지하기 위해 로직을 원자적으로 만들기
요약

▣ 11장: 분산 시스템에서의 배송 의미론

11.1 이벤트 주도 애플리케이션의 아키텍처
11.2 아파치 카프카에 기반한 생산자와 소비자 애플리케이션
__11.2.1 카프카의 소비자 쪽 살펴보기
__11.2.2 카프카 브로커 설정 이해하기
11.3 생산자 로직
__11.3.1 생산자를 위한 일관성 대 가용성 선택하기
11.4 소비자 코드와 다양한 배송 의미론
__11.4.1 수동으로 소비자 커밋하기
__11.4.2 가장 처음 오프셋 또는 가장 최신 오프셋에서 재시작하기
__11.4.3 (사실상) 정확히 한 번 의미론
11.5 내결함성을 제공하기 위해 배송 의미론을 활용하기
요약

▣ 12장: 버전과 호환성 관리하기

12.1 추상적으로 생각해보는 버전 관리
__12.1.1 버전의 속성
__12.1.2 하위 호환성과 상위 호환성
__12.1.3 유의적 버전 관리
__12.1.4 마케팅 버전
12.2 라이브러리를 위한 버전 관리
__12.2.1 소스 코드, 바이너리, 그리고 유의적 호환성
__12.2.2 의존성 그래프와 다이아몬드 의존성
__12.2.3 호환성에 손상을 가하는 변경을 처리하기 위한 기법
__12.2.4 내부 전용 라이브러리 관리하기
12.3 네트워크 API를 위한 버전 관리
__12.3.1 네트워크 API 호출이라는 컨텍스트
__12.3.2 고객 친화적인 명료함
__12.3.3 일반적인 버전 관리 전략
__12.3.4 추가적인 버전 관리 고려 사항
12.4 데이터 저장소를 위한 버전 관리
__12.4.1 프로토콜 버퍼에 대한 간략한 소개
__12.4.2 호환성이 손상되는 변경 사항은 무엇일까?
__12.4.3 저장소 내에서 데이터 이주하기
__12.4.4 예상치 못한 상황을 예상하기
__12.4.5 API와 저장소 표현 분리하기
__12.4.6 저장소 형식 평가하기
요약

▣ 13장: 최신 유행을 따르는 방식 대 코드 유지보수 비용을 줄이는 방식

13.1 언제 의존성 주입 프레임워크를 사용할까?
__13.1.1 DIY(Do-it-yourself) 의존성 주입
__13.1.2 의존성 주입 프레임워크 사용하기
13.2 리액티브 프로그래밍을 사용할 때
__13.2.1 단일 스레드, 차단 처리 생성하기
__13.2.2 CompletableFuture 사용하기
__13.2.3 리액티브 해법을 구현하기
13.3 함수형 프로그래밍을 사용할 때
__13.3.1 비함수형 언어에서 함수형 코드 생성하기
__13.3.2 꼬리 재귀 최적화
__13.3.3 불변성 활용하기
13.4 지연(lazy) 평가 대 빠른(eager) 평가
요약
Author
토마스 레렉,존 스키트,박재호
전문적인 소프트웨어 공학 경력을 쌓는 과정에서 다양한 실제 상용 서비스, 아키텍처, 프로그래밍 언어(주로 JVM)를 작업해 왔다. 모놀리스와 마이크로서비스 아키텍처에 대한 실전 경험이 있으며, 수천만 명의 고유한 사용자와 초당 수십만 건에 이르는 연산을 처리하는 시스템을 설계해 왔다. 현재 현대적인 데이터 레이크하우스 솔루션을 만드는 드레미오(Dremio)에서 일한다.
전문적인 소프트웨어 공학 경력을 쌓는 과정에서 다양한 실제 상용 서비스, 아키텍처, 프로그래밍 언어(주로 JVM)를 작업해 왔다. 모놀리스와 마이크로서비스 아키텍처에 대한 실전 경험이 있으며, 수천만 명의 고유한 사용자와 초당 수십만 건에 이르는 연산을 처리하는 시스템을 설계해 왔다. 현재 현대적인 데이터 레이크하우스 솔루션을 만드는 드레미오(Dremio)에서 일한다.