책소개
데이터 지향 프로그래밍은 데이터를 데이터로 다룬다는 간단한 발상에 기반해 단순하면서도 최신의 해결책을 알려주는 책이다. 이해하기 쉽도록 이야기 식으로 전개되는 이 책은 우리가 그동안 지나치게 복잡한 기술을 사용해서 데이터 중심 애플리케이션을 만들고 있었고, 그 때문에 불필요한 복잡성에 빠져 있었다고 일깨워준다. 그리고 네 가지 데이터 지향 프로그래밍 원리로 단순하게 문제를 푸는 방법을 설명한다. 책 서두에 제시된 원리를 대규모 시스템이나 팀 개발에 적용하는 현실적인 도전에 대한 의외의 답을 접하면서 사고의 틀이 확장됨을 경험할 수 있을 것이다.
목차
1부 유연성
1장 객체지향 프로그래밍의 복잡성
1.1 OOP 설계: 정통인가? 고전인가?
1.1.1 설계 단계
1.1.2 UML 기초
1.1.3 클래스도 상세 설명
1.1.4 구현 단계
1.2 복잡성의 근원
1.2.1 다량의 클래스 간 관계
1.2.2 예상치 못한 코드 동작
1.2.3 쉽지 않은 데이터 직렬화
1.2.4 복잡한 클래스 계층 구조
요약
2장 코드와 데이터 분리
2.1 DOP 시스템의 두 부분
2.2 데이터 개체
2.3 코드 모듈
2.4 이해하기 쉬운 DOP 시스템
2.5 유연한 DOP 시스템
요약
3장 기본 데이터 조작
3.1 데이터 모델 설계
3.2 맵으로 관리되는 레코드
3.3 범용 함수를 사용한 데이터 조작
3.4 검색 결과 연산
3.5 이종 자료형의 레코드 처리
요약
4장 상태 관리
4.1 다중 버전 시스템 데이터
4.2 구조적 공유
4.3 구조적 공유 구현
4.4 데이터 안전성
4.5 변경의 반영 단계
4.6 시스템 상태 무결성 보장
4.7 이전 상태 복원
요약
5장 기본 동시성 제어
5.1 낙관적 동시성 제어
5.2 동시 변경 조정
5.3 컬렉션 축소
5.4 구조적 비교
5.5 조정 알고리듬 구현
요약
6장 단위 테스트
6.1 간결한 데이터 지향 테스트 케이스
6.2 데이터 조작 코드의 단위 테스트
6.2.1 함수 호출 트리
6.2.2 끝 단 함수의 단위 테스트
6.2.3 트리 중간 노드의 단위 테스트
6.3 조회 함수의 단위 테스트
6.4 변경의 단위 테스트
다음 단계
요약
2부 확장성
7장 기본 데이터 유효성 확인
7.1 DOP의 데이터 유효성 확인
7.2 JSON 스키마 소개
7.3 유연하고도 엄격한 스키마
7.4 스키마 합성
7.5 데이터 유효성 오류 상세 정보
요약
8장 고급 동시성 제어
8.1 복잡한 잠금
8.2 스레드 안전한 원자 계수기
8.3 스레드 안전한 원자 캐시
8.4 원자 기반 상태 관리
요약
9장 영속 자료구조
9.1 영속 자료구조의 필요성
9.2 영속 자료구조의 효율성
9.3 영속 자료구조 라이브러리
9.3.1 자바 영속 자료구조
9.3.2 자바스크립트 영속 자료구조
9.4 실무 영속 자료구조
9.4.1 영속 자료구조를 사용한 조회 코드
9.4.2 영속 자료구조를 사용한 변경 코드
9.4.3 직렬화와 역직렬화
9.4.4 구조적 비교
요약
10장 데이터베이스 작업
10.1 데이터베이스에서 데이터를 가져오는 작업
10.2 데이터베이스에 데이터 저장하기
10.3 단순한 데이터 조작
10.4 복잡한 데이터 조작
요약
11장 웹 서비스
11.1 또 다른 기능 요청
11.2 외부와 동일한 내부 구축
11.3 맵으로 표현되는 클라이언트 요청
11.4 맵으로 표현되는 서버 응답
11.5 정보 전달
11.6 실제 검색 결과 보강
일정 준수
요약
3부 유지보수성
12장 고급 데이터 유효성 확인
12.1 함수 인자 유효성 확인
12.2 반환값 유효성 확인
12.3 고급 데이터 유효성 확인
12.4 데이터 모델 도식 자동 생성
12.5 스키마 기반 단위 테스트 자동 생성
12.6 새로운 선물
요약
13장 다형성
13.1 다형성의 핵심
13.2 단일 디스패치 다중 메서드
13.3 다중 디스패치 다중 메서드
13.4 동적 디스패치 다중 메서드
13.5 실운영 시스템에 다중 메서드 통합
요약
14장 고급 데이터 조작
14.1 풍부한 표현의 맵 값 갱신
14.2 중첩된 데이터 조작
14.3 최적의 도구 사용
14.4 배열 필드 해체
요약
15장 디버그
15.1 프로그래밍 결정론
15.2 숫자와 문자열을 사용한 재현
15.3 모든 데이터 유형에서 재현
15.4 단위 테스트
15.5 외부 데이터 테스트
작별
요약
부록 A 데이터 지향 프로그래밍 원리
부록 B 정적 타입 언어의 범용 데이터 접근
부록 C 패러다임의 발전과 데이터 지향 프로그래밍
부록 D 로대시 요약
저자소개
출판사리뷰
◈ 이 책에서 다루는 내용 ◈
◆ 데이터와 코드의 분리
◆ 일반화 자료형을 사용한 데이터의 표현
◆ 데이터 변경 없는 상태 관리
◆ 대규모 시스템의 동시성 제어
◆ 데이터 지향 단위 테스트 작성
◆ 데이터 규격 지정
◈ 이 책의 대상 독자 ◈
자바, C#, C++, 루비, 파이썬 같은 고급 프로그래밍 언어를 사용한 경험이 있는 프론트엔드, 백엔드, 풀 스택 개발자를 위한 책이다. 객체지향 프로그래밍 개발자라면 이 책에서 제시하는 몇 가지 발상이 다소 불편할 수 있고 이미 익숙한 프로그래밍 패러다임을 버려야 할 수도 있다. 함수형 프로그래밍 개발자는 이 책을 좀 더 쉽게 소화할 수 있다. 하지만 그들에게도 놀랄 만한 요소는 있을 것이다.
◈ 지은이의 말 ◈
2000년부터 소프트웨어 엔지니어로 일했던 내게는 2012년 이전과 이후가 명확하게 나뉜다. 2012년이 기준인 이유는 내가 클로저를 발견한 해가 2012년이기 때문이다. 클로저를 만나기 전까지 프로그래밍은 내 직업이었다. 그러나 클로저를 만난 후에 프로그래밍은 내 열정이 됐다.
몇 년 전, 클로저의 어떤 특징이 이 프로그래밍 언어를 내 스스로 큰 희열의 원천으로 여기게 했는지 문득 궁금해졌다. 그래서 나와 동일한 열정을 지닌 클로저 커뮤니티 회원들에게 이 질문을 공유했고, 클로저를 이토록 특별하게 만들어준 것은 언어의 특징이 아니라 원리에 있다는 사실을 알아냈다.
클로저의 핵심 원리를 정제하는 일에 착수하자, 이 원리가 사실 다른 프로그래밍 언어에도 적용 가능하다는 것을 깨달았다. 그때부터 이 책에 대한 발상이 떠오르기 시작했다. 내가 클로저에서 좋아하는 것들을 전 세계 개발자 공동체와 나누고 싶었다. 그러려면 클로저를 모르는 개발자들에게 생소한 아이디어를 분명히 표현할 수단이 필요했다.
이야기를 지어내는 것을 항상 좋아하던 나였지만, 프로그래머들이 내가 생각해낸 대화를 진지하게 받아들여줄지 확신이 없었다. 물론, 플라톤은 스승의 가르침을 전달하려고 ‘소크라테스 대화편’이라는 이야기를 지어냈다. 마찬가지로, 랍비인 유다 할레비(Judah Halevi)도 유대교의 토대를 설명하고자 카자르 왕의 이야기를 지어냈다. 하지만 이 두 작품은 사고의 영역에 속한다. 현실이 아니다.
그때 몇 년 전에 읽었던 경영 관련 서적인 『THE GOAL』(동양북스, 2019)이 떠올랐다. 엘리 골드렛(Eliyahu Goldratt)은 ‘제약 조건 이론(theory of constraints)’의 원리 덕에 공장을 살린 한 공장 관리자의 이야기를 지어내 그 책을 썼다. 플라톤, 유다 할레비, 엘리 골드렛은 이야기를 써서 발상을 나누고 싶다는 내 뜨거운 욕망을 정당화해줬다.
◈ 옮긴이의 말 ◈
마틴 클레프만(Martin Kleppmann)은 『데이터 중심 애플리케이션 설계』(위키북스, 2018)에서 소프트웨어가 이미 한 프로세스 또는 클러스터를 벗어나 다른 차원으로 확대됐다는 것을 명확히 보여줍니다. 다양한 이벤트(입력)를 다량으로 받아 빠르고 가볍게 처리해서 바로 응답(출력)해야 하는 현대의 시스템에서 개별 프로세스는 정교하고 복잡한 모델을 갖고 무거운 연산을 수행하기보다 단순히 데이터를 조작하면서 고도의 동시성과 반응성을 달성하는 것이 더 중요할 수 있습니다.
이 책은 문제를 단순하게 푸는 방법을 제시합니다. 시스템의 복잡성은 두 가지 측면에서 구분해볼 수 있습니다. 한 측면은 구조의 복잡성입니다. 어떤 시스템의 기존 구조가 단순할 수도, 복잡할 수도 있습니다. 또 다른 측면은 구성의 복잡성입니다. 한 시스템이 소수의 요소만으로 구성돼 단출할 수도, 여러 이질적인 요소가 마구 섞여 잡다할 수도 있습니다. 후자는 복합성이라고 달리 부를 수도 있겠습니다. 어떤 시스템은 복잡성은 높지만 복합성은 낮고, 어떤 시스템은 복잡성은 낮지만 복합성은 높습니다. 당연히 둘 다 높거나 낮은 시스템도 있습니다.
어떤 기술은 (구조가) 복잡한 문제는 잘 해결하지만 (구성이) 복합적인 문제를 푸는 데 그리적합하지 않을 수 있습니다. 단순하지만 복합적인 시스템은 함수와 데이터 수는 많고 추상화 깊이는 낮습니다. 복잡한 문제에 적합한 기술을 복합적인 문제에 사용하게 되면 본질적 복잡성(해결하려는 문제 자체의 복잡성)에 우발적 복잡성(사용되는 기술 자체의 복잡성)까지 더해져 시스템 구축이 지나치게 복잡해질 수 있습니다.
저자는 오랫동안 클로저 커뮤니티에서 경험한 효과적이고 단순한 문제 해결 방식이 다른 프로그래밍 언어에서도 그대로 적용 가능하다고 생각하고, 그 원리와 구현 방식을 정리해 ‘데이터 지향 프로그래밍(DOP)’이란 이름을 붙여 소개합니다.
책을 읽는 많은 객체지향 프로그래밍(OOP) 개발자와 함수형 프로그래밍(FP) 개발자가 어쩌면 화를 낼 지도 모릅니다. OOP 개발자에게는 FP를 다른 이름으로 포장해 설명하면서 지금까지 쌓아온 OOP를 섣불리 무너뜨리려는 것으로 보일 테고, FP 개발자에게는 잘못된 유사 FP를 가르치는 시도로 보일 것입니다.
저자가 통상의 OOP가 시스템을 복잡하게 만드는 경향이 있다며 보여주는 OOP 설계 예시가 확실히 좋은 설계라고는 할 수 없습니다. 하지만 흔히 보게 되는 (능숙하게 적용되지 못한) OOP인 것은 맞습니다.
저는 자바를 주로 사용합니다. 자바는 처음 세상에 소개될 때 OOP 언어를 표방했고, 급속히 가장 인기 있는 언어로 자리매김한 이유도 OOP의 인기에 편승했다는 점에서 찾을 수 있을 것입니다. 클래스를 만들지 않고는 동작하는 코드 한 줄도 작성하지 못하는 자바의 OOP에 대한 입장은 아주 견고해 보였습니다. 이런 자바도 자바 8 이후로 지난 10여 년간 람다식, 메서드 참조, 함수 인터페이스, 스위치식, 패턴 매칭, 레코드, 밀봉 클래스(sealed class) 등 OOP와 상관없어 보이는 여러 언어적인 개선을 이루고 있습니다.
자바의 이런 변화는 사실 당연한 듯 보입니다. 자바를 제외하고는 대부분의 언어가 다중 패러다임의 길을 걷기 때문입니다. 어찌 보면 자바는 사람들의 성원에 못 이겨 애써 따라가는 형세이므로, 아무도 이런 변화에 의문을 던지지 않는 분위기입니다. 하지만 이런 개선 사항을 어떻게 활용할지를 두고 토론이 벌어지면 저마다 생각이 다릅니다.
누군가는 이제 자바도 FP를 할 수 있게 됐다면서 FP를 해야 한다고 주장합니다. 다른 한편에서는 그저 화려한 표현이 추가됐을 뿐 프로그래밍 방식에 아무런 영향이 없다고 생각합니다.
새로운 언어 변화를 어떻게 사용하면 좋을지 안내하는 지침이 없다 보니 성급한 사람들은 최대한 최신 표기법을 적용하고 싶어 안달이고, 조심스러운 사람들은 성능과 가독성 등을 문제 삼으면서 이런 분위기를 불편해합니다.
자바 아키텍트이면서 앰버 프로젝트를 이끄는 브라이언 게츠(Brian Goetz)는 2022년 인포큐(InfoQ)에 ‘자바 데이터 지향 프로그래밍(Data-Oriented Programming in Java)’이란 글을 기고하면서 이것이 자바 8 이후의 개선 사항을 적절하게 활용하는 패러다임이라고 소개합니다. 게츠는 복잡한 문제는 기존의 OOP를 활용해 풀고 단순한 문제는 단순하게 풀라면서 자바 최신 개선 사항으로 DOP를 적용하는 예를 보여줍니다.
애플리케이션 전체가 아닌 일정 계층이나 영역에 DOP를 적용하는 것도 좋습니다. 예를 들어, 도메인 모델은 객체지향 모델링을 적용하더라도 외부와 통신하는 계층만 DOP를 적용하는 것을 고려할 수 있습니다. 경계를 구분할 때는 OOP의 캡슐화를 적극적으로 활용하고 세부 구현에는 DOP를 적용하는 것도 가능합니다.
상속 계층이 깊거나 클래스 내부에 은닉되는 구현이 복잡하고 클수록 OOP는 장점이 부각됩니다. 반면에 상속 깊이가 얕거나 내부 구현이 단순할 때 OOP는 비용만 많이 들고 별 도움이 안 된다고 느껴질 수 있습니다.
OOP가 특별히 도움이 되지도 않고 부담이 되지도 않는, 그래서 어느 프로그래밍 패러다임을 사용해도 상관없는 중간 지대도 상당히 클 것입니다.
게츠가 소개한 DOP와 이 책의 DOP는 완전히 동일하지 않습니다. DOP가 클로저 커뮤니티에서 도출된 만큼 DOP의 네 가지 원리에는 클로저 또는 클로저의 모태가 되는 리스프(Lisp)의 특성이 반영돼 있습니다. 클로저는 범용 자료구조를 적극적으로 사용하고 동적 타입이면서 함수형 프로그래밍을 지원하는 현대적인 리스프 방언입니다.
게츠는 DOP의 네 가지 원리에서 두 가지는 수용하면서 정적 타입 언어와 맞지 않는 두 가지는 적절하게 정적 타입 언어의 특징으로 흡수하는 유연성을 보입니다. 그리고 여전히 OOP를 기본으로 삼으면서 DOP를 보조로 사용하도록 권합니다. 게츠가 제시했던 자바용 DOP는 최근에 다음과 같은 (이 책에서 제시하는 원리와 다른) 네 가지 원리로 정리됐습니다.
■ 데이터를 불변하면서도 투명하게 모델링하라.
■ 데이터를 온전히 데이터 그 자체로 모델링하라.
■ 잘못된 상태가 발생하지 않게 하라.
■ 데이터와 동작을 분리하라.
이런 자바의 데이터 지향 프로그래밍 도입 시도는 다른 다중 패러다임 언어에서도 참고가 될 것입니다.
이 외에도 DOP를 실무에 적용하기 위한 부가적인 기법을 함께 소개하지만, 자바의 DOP는 자바의 최신 개선 사항을 소개하는 수준에 머물러 있어 추가적인 논의가 필요합니다.
책을 읽는 동안, 동의하지 않는 부분이 있더라도 일단 책의 안내에 따라 인내심을 갖고 끝까지 따라가볼 것을 권합니다. 특히 부록의 내용은 유용합니다. 이 책의 부록은 본문이 대화를 통한 이야기 형식이라 담아내지 못한 이론적인 내용이 잘 정리된, 또 다른 본문입니다. 이렇게 다 읽고 나서 책의 개념을 어떻게 적용할지 고민해보길 바랍니다.
어떤 분야(또는 어떤 언어)에서는 책에서 제시하는 네 가지 원리를 모두 적용하는 것이 의미가 있을지도 모릅니다. 반면 어떤 경우에는 한두 가지만 의미가 있을 것입니다.
개인적으로 범용 자료구조(특히 이종 맵)와 범용 함수는 (책에서 의사코드처럼 쓰인) 자바스크립트와 같이 맵 리터럴이 있는 동적 타입 언어에서는 자연스러울 수 있어도 정적 타입 언어(적어도 자바)에서는 적잖이 고민하게 될 것입니다. 부록에서는 정적 타입 언어에서 범용 자료 구조와 함수를 사용하는 방법을 모색하지만, 다소 억지스럽고 한계가 있습니다. 저자의 주장과 달리 자바용 범용 함수 라이브러리 같은 생태계도 그리 건실하지 않습니다.
마지막으로, 마이클 T. 나이가드와 라이언 싱어가 쓴 ‘추천의 글’을 이 책을 읽기 전과 후에꼭 읽어보길 바랍니다. 이렇게 책의 의미를 잘 소개한 추천사를 지금껏 본 적이 없다고 느낄 정도로 훌륭한 추천사이기 때문입니다. 특히 나이가드의 추천사는 그의 연륜이 느껴질 정도로 깊이가 있습니다(이 ‘옮긴이의 말’은 두 추천사를 읽을 것을 권하는 이 문단 외에는 쓸모없다고 해도 과언이 아닙니다).
마지막으로, 부족한 번역으로 인해 불편을 끼칠 것에 대해 미리 사과합니다. 그래도 부단히 노력한 결과인 만큼 즐거운 여정에 도움이 되길 바랍니다.