▣ 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) 평가
요약