◆ 출판사 ◆
에이콘출판
◆ 책소개 ◆
데이터 지향 프로그래밍은 데이터를 데이터로 다룬다는 간단한 발상에 기반해 단순하면서도 최신의 해결책을 알려주는 책이다. 이해하기 쉽도록 이야기 식으로 전개되는 이 책은 우리가 그동안 지나치게 복잡한 기술을 사용해서 데이터 중심 애플리케이션을 만들고 있었고, 그 때문에 불필요한 복잡성에 빠져 있었다고 일깨워준다. 그리고 네 가지 데이터 지향 프로그래밍 원리로 단순하게 문제를 푸는 방법을 설명한다. 책 서두에 제시된 원리를 대규모 시스템이나 팀 개발에 적용하는 현실적인 도전에 대한 의외의 답을 접하면서 사고의 틀이 확장됨을 경험할 수 있을 것이다.
◆ 목차 ◆
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++, 루비, 파이썬 같은 고급 프로그래밍 언어를 사용한 경험이 있는 프론트엔드, 백엔드, 풀 스택 개발자를 위한 책이다. 객체지향 프로그래밍 개발자라면 이 책에서 제시하는 몇 가지 발상이 다소 불편할 수 있고 이미 익숙한 프로그래밍 패러다임을 버려야 할 수도 있다. 함수형 프로그래밍 개발자는 이 책을 좀 더 쉽게 소화할 수 있다. 하지만 그들에게도 놀랄 만한 요소는 있을 것이다.
◈ 추천의 글 ◈
프로그래밍 원리, 설계 방법, 아키텍처 방식, 심지어 언어의 기능조차 모두 (변화에) 적응하면서도 복잡성을 조직화하는 일과 관련돼 있다. 나는 2009년에 불변 데이터(immutable data)와 프로그램의 일부를 프로그램 자체 내부 데이터로 전환하는 두 가지 특성 때문에 클로저(Clojure)에 이끌렸고, 같은 이유로 최근에는 예호나탄 샤르빗이 쓴 이 책에 이끌렸다.
2005년에는 좋아하는 사람들과 함께 좋아하는 프로젝트 중 하나를 수행했다. 그 프로젝트는 자바 프로젝트였는데, 당시 자바 세계에서 일반적이지 않은 두 가지를 시도했다. 먼저, 핵심 데이터값을 불변으로 만들었다. 쉽지 않았지만, 효과가 아주 좋았다. 많은 클래스의 clone과 deepClone 메서드를 직접 작성했는데, 그로 인한 이득은 대단했다. 한 가지 예로, 사용자마다 개별화할 템플릿 문서가 필요하다고 가정하자. 전체 객체 트리의 복사본을 만들 수 있다면 객체 스스로는 자신이 템플릿 데이터인지 개별화된 데이터인지 알 필요가 없다. 결정은 그 참조를 가진 객체에 달렸다. 또 다른 큰 이점은 비교할 때다. 값이 불변이므로, 식별자가 동일하다는 것은 곧 값이 동등하다는 것을 의미한다. 따라서 동등성 확인을 매우 빠르게 할 수 있다.
두 번째 기법은 (예호나탄이 이 책에서 보인 정도까지는 아니지만) 범용 데이터(generic data)를 활용하는 것이었다. 어떤 계층에 클래스 계층 구조가 있다고 할 때, 인접한 계층은 이 클래스를 좀 더 일반적인 클래스의 인스턴스로 표현한다. 한 계층의 멤버 변수는 다른 계층에서 맵에 담긴 필드로 서술될 수 있다. 이런 방식은 분명히 팀에서 몇몇 사람이 잡담처럼 가볍게 제안한 의견에 영향을 받은 것으로 보인다. 이 또한 바로 이득이 됐다. 다양한 구성으로 객체를 조합하고 재조합할 수 있었기 때문이다.
이와 같이 데이터 지향 프로그래밍(DOP, Data-Oriented Programming)은 우발적 복잡도(accidental complexity)를 줄이고 작업하는 추상화의 수준을 높일 수 있다. 클래스에 범용 함수(generic function)를 만들어 넣은 결과, 프로그램의 반복되는 동작이 자연스럽지 않아 보일 것이다. 범용 함수가 있는 클래스는 프로그램 내부 값의 특정 부분 집합을 전담하는 작은 이름 공간(namespace) 같은 역할을 한다. 프로그램의 거의 모든 값은 맵과 리스트로 접어 넣을 수 있다. 객체 멤버의 이름(리플렉션 API를 사용해야 겨우 얻을 수 있는 데이터)은 맵의 키로 바꿀 수 있다. 이렇게 하면 코드가 조금씩 사라지는데, 이것이 깨달음의 첫 단계다.
이쯤 되면, 컴파일러가 컴파일하면서 멤버 이름을 사용해 코드에 오류가 없는지 확인하지 않느냐며 반대하는 사람이 있을 수 있다. 실제로 그렇다. 하지만 예호나탄이 컴파일 시점의 확인은 값에 오류가 없는지 확인하는 방법의 작은 하위 집합일 뿐이라는, 깨달음의 다음 단계로 우리를 안내할 것이니 믿어보자. 오류 확인 자체도 데이터로 만들 수 있다. 스키마를 프로그램 내부 값으로 만들 수 있을 뿐 아니라, 타입 시스템(type system)의 최전선에 있는 연구자들이 여전히 알아내려고 노력 중인 규칙도 적용할 수 있다. 이것이 두 번째 단계의 깨달음이다.
데이터 지향 프로그래밍은 특히 웹 API로 일할 때 빛난다. 통신에는 타입 시스템이 없으므로 요청에 포함된 데이터를 도메인 클래스에 그대로 매핑하려고 하면 구현이 복잡해질 뿐 아니라 쉽게 깨진다. 데이터를 데이터로 남겨두면 코드가 더 단순해지고 수백 메가바이트 크기의 프레임워크 라이브러리를 사용할 필요가 대폭 줄어든다.
그렇다면 캡슐화, 상속, 다형성이라는 객체지향 프로그래밍(OOP, Object-Oriented Programming)의 미덕은 이제 쓸모없는 것일까? 이 세 가지를 나눠 마치 ‘일품요리’처럼 각각 따로 맛볼 수 있다는 사실이 밝혀졌다(내 생각에 구현 상속은 이 중에서 가장 중요하지 않다. 종종 가장 먼저 배운 것임에도 그렇다. 나는 이제 프로토콜과 공유된 함수 서명을 통한 인터페이스 상속을 선호한다). 데이터 지향 프로그래밍은 전통적인 유형의 다형성을 제공한다. 첫 번째 인수의 자료형에 따라 여러 함수 중 하나로 디스패치(dispatch)하는 것이다(객체지향 언어에서 this는 암묵적인 메서드의 첫 번째 인자다. 생략된 첫 인자가 점(.) 앞에 올 뿐이다). 하지만 데이터 지향 프로그래밍은 스키마 확인처럼 더 많은 역동성을 허용한다. 처음 두 인자의 자료형에 따라 디스패치한다고 생각해보자. 또는 인자에 오늘 날짜가 들어가 있는 ‘생일’ 필드가 있는지에 따라 디스패치된다고 상상해보자. 이것이 깨달음의 세 번째 단계다.
캡슐화는 여전히 프로그램을 조직하는 논리에 적용해야 한다. 우리는 값이 아닌 하위 시스템을 캡슐화한다. 이 캡슐화는 데이비드 파나스(David Parnas)의 설계 결정 은닉(design decision hiding)을 구현한다. 하위 시스템 내부에서는 클래스가 강요하는, 단절된 이름 공간으로 데이터를 나누는 것을 그만둘 수 있다. 앨런 펄리스(Alan Perlis)는 “자료구조 열 개에 함수 열 개가 동작하는 것보다 자료구조 하나에 함수 100개가 동작하는 것이 더 낫다”고 말했다.
엔트로피와의 끝없는 전투 중에는 데이터 지향 프로그래밍으로 코드양을 줄여 싸움을 계속할 수 있고 추상화 수준을 높여 프로그램의 논리와 의미를 정확하고 명료하게 만들 수 있다. 데이터 지향 프로그래밍으로의 여정을 즐기고, 새로운 고원에 도착할 때면 잠시 멈춰 전망을 즐기면서 스스로에게 “데이터일 뿐이야!”라고 말하자.
-마이클 T. 나이가드(Michael T. Nygard)
『RELEASE IT: 성공적인 출시를 위한 소프트웨어 설계와 배치』(위키북스, 2007)의 저자
이 책을 만난 시점은 정말 적절했다. 나는 거의 20년간 객체지향 프레임워크로 웹 앱을 구축했다. 스스로를 프로그래밍 전문가라고 생각하지는 않았지만, 전형적인 비즈니스 문제를 파악하고 데이터 모델을 구상하고 MVC 방식의 앱을 구축할 정도로는 내가 쓰는 도구에 대해 충분히 알고 있었다.
프로젝트의 시작은 늘 흥분됐다. 나는 구성 요소를 서로 연결하고 앱이 생명을 얻는 것을 보는 느낌을 정말 좋아한다. 하지만 일단 앱이 돌아가기 시작하면 문제에 빠지고 말았는데, 앱의 일부만 변경하고 싶어도 모델을 전부 검토해야만 했다. 테스트를 작성해야 한다는 것은 알았지만, 테스트하려면 너무 많은 상태를 설정해야만 했으므로 테스트가 그만한 가치가 있다고 느끼지 못했다. 변경하기 어려운 코드를 더 작성하고 싶지는 않았다. 콘솔에서 간단한 코드를 실행해보려고 해도 번거로웠다. 메서드를 호출하려면 데이터베이스 상태를 만들어야 했기 때문이다. 내가 잘못하고 있다고 생각했지만, 정밀한 테스트 프레임워크와 같이 익숙한 기존 해법은 일을 처리하기 쉽게 만들기보다는 오히려 복잡도를 더하는 것 같았다.
그러던 어느 날, 유튜브에서 클로저의 창시자인 리치 히키(Rich Hickey)의 발표를 봤다. 그는 함수형 프로그래밍(FP, Functional Programming)을 설명하면서 이를 객체지향과 비교했는데, 객체지향을 ‘장소지향 프로그래밍(place-oriented programming)’이라고 부르면서 비꼬았다. 그의 주장이 맞는지는 확신할 수 없었지만, “당신이 아니라 당신의 언어가 문제입니다”라고 말하는 듯한 이면의 메시지에 흥미를 느꼈다. 결국 해당 주제와 관련해 찾을 수 있는 비디오는 모두 찾아봤고, 클로저가 답이 될 수도 있겠다는 생각을 하기 시작했다.
수년이 흘렀다. 나는 계속 클로저 영상을 보면서 함수형 원리를 가능한 한 적용하려고 시도해왔지만, 새로운 프로젝트를 시작할 때마다 손에 익은 프레임워크로 되돌아갔다. 완전히 다른 라이브러리 생태계를 가진 또 다른 언어로 바꾼다는 것은 너무나 큰 도약이었다.
그러다가 새로운 제품 개발을 막 시작하려던 시점에 이 책을 알게 됐다. 무엇보다 책 제목의 ‘데이터 지향(Data-Oriented)’이라는 단어가 마음을 울렸다. 예전에 봤던 클로저 비디오에서 프로그래머들이 이 말을 하는 것을 듣기는 했지만, 무슨 뜻으로 하는 말인지 명확히 이해하지는 못했다. 일일이 전용 객체를 만들기보다 맵이나 배열 같은 데이터 리터럴(data literal)을 사용해 시스템을 구축하는 것이 더 쉽다는 내용이었다. 내가 아는 언어는 데이터 리터럴을 훌륭하게 지원했으므로, 언젠가 클로저로 전환하는 대망의 날까지 나를 지탱해줄 만한 뭔가를 배워야 한다고 생각했다.
첫 깨달음의 순간은 도입 부분을 읽자마자 바로 다가왔다. 책의 서두에서 예호나탄은 자신이 클로저로 10년간 코드를 작성했음에도 이 책은 언어 중립적이고 예제는 자바스크립트로 제공될 것이라고 설명했다. 언어를 바꾸지 않고도 내가 프로그램을 작성하는 방식을 획기적으로 개선할 수 있다고 하니 믿을 수 없었다.
이 가능성에 너무 들떠 그 자리에서 책을 단숨에 다 읽어버렸는데, 그동안 보이지 않던 것이 보이기 시작했다. 내 코드는 테스트하기 어려웠다. 내가 ORM을 사용했고, 모든 기능이 데이터베이스 상태를 가정한 객체로 작성됐기 때문이다. 책에서 예제와 함께 설명된
내용을 도저히 무시할 수 없었다. 내게 필요한 것은 새로운 언어가 아니었다. 다른 프로그래밍 방식이 필요할 뿐이었다.
내가 대단하다고 생각하는 설계자들은 하나같이 좋은 설계란 분리해내는 것이라고 강조한다. 코드를 동작하게 만드는 일이 아니다. 엉겨 붙은 덩어리를 서로 다른 부분으로 떼어내고 전체에 영향을 주지 않고도 일부만 변경할 수 있게 해야 된다는 이야기다.
이 책에서는 코드와 데이터를 분리하며 그 결과는 놀랍고 흥미롭다. 더 나아가 특정 언어와 프로그래밍 방식을 분리하는 것으로 보인다. 나는 이제 클로저로 전환하지 않을 것 같고 더는 그래야 할 것처럼 느끼지도 않는다. 데이터 지향 프로그래밍은 내가 사용하는 언어의 새로운 가능성과 매일 등장하는 수많은 새 프레임워크를 보게 해줬다.
-라이언 싱어(Ryan Singer)
『Shape Up: Stop Running in Circles and Ship Work that Matters』의 저자
◈ 한국어판 추천의 글 ◈
소프트웨어는 물질적인 실체가 없습니다. 때문에다. 코드만 바꾸면 무궁무진하게 다양한 일을 해낼 수 있으므로 ‘손쉽게’ 변경 가능한 무른 무엇이라고 생각하기 쉽습니다. 하지만 실제 소프트웨어는 엄청나게 복잡하고 그로 인해 경화되곤 합니다. 클래스 계층 구조와 함수 흐름이나 데이터 간의 의존 관계, 내재된 시간적 선후 관계 등이 복잡하게 뒤얽히면서 고객의 수정 요청을 코드에 적용하기 어려운 경우가 아주 많습니다. 따라서 개발 초기부터 이런 본질적인 소프트웨어의 복잡도를 낮춰서 최대한 말랑말랑하게 유지하기 위한 다양한 방법이 존재합니다.
이 책은 이런 문제를 해결하는 방법으로 데이터 지향 프로그래밍(DOP)을 소개합니다. DOP를 소개할 뿐 아니라 DOP라는 개념을 처음 접하면 질문을 던질 법한 내용들인 상태 관리, 동시성 제어, 테스트, 데이터 유효성 관리, 영속화, 디버깅 등에 대해서도 실제 예제를 통해 차근차근 설명합니다. 이를 통해 DOP의 핵심을 쉽게 이해할 수 있고 우리 프로젝트에도 차근차근 적용할 수 있습니다. 데이터와 코드의 분리, 순수하고 불변적인 데이터 구조, 상태가 없는 함수, 동적 디스패치 등과 같은 DOP의 개념은 하나의 시스템에서 돌아가는 앱 뿐만 아니라 비동기적으로 여러 서버가 협력해 작동하는 분산 환경에서도 유용한 방법론이라고 생각합니다.
무엇보다도 부드럽고 자연스러운 번역 덕분에 이 책을 더 쉽게 이해할 수 있습니다. 여러 개발자에게 도움이 될 만한 좋은 책이 번역된 것이 무척 기쁩니다. 많은 분이 이 책을 읽고 좀 더 나은 개발자로 발전해 나갔으면 좋겠습니다.
-오현석
(주)모빌리티42 CTO, 기술 서적 번역가
(『순수 함수형 데이터 구조』(에이콘, 2019), 『Kotlin in Action』(에이콘, 2017),
『리액트 훅 인 액션』(책만, 2024) 등 프로그래밍 관련 다수의 책 번역)
‘자바 백엔드 개발은 웹 브라우저와 DB를 연결하는 인터페이스를 만드는 것에 불과하다’라는 자조적인 선언이 개발자 사이에 돌았던 기억이 있습니다. 비즈니스 로직은 DB가 담당하는 SQL과 저장 프로시저에 담겨 있고, 백엔드 코드는 웹 요청을 SQL로 만들어 DB에 전달하거나 DB에서 돌려받은 정보를 HTML, JSON, XML 등으로 변환하는 것이 전부라는 것이었죠. 결국 중요한 것은 데이터이고 애플리케이션은 데이터보다 수명이 짧으니 애플리케이션은 그저 DB 인터페이스로 만들면 충분하다는 이야기였습니다.
『데이터 지향 프로그래밍』이라는 제목을 봤을 때, 혹시 그때 들었던 이야기가 다시 반복되는 건 아닌가 하는 의심이 먼저 들었습니다. 하지만 책에서 설명하는 데이터를 지향하는 프로그래밍 방식은 전혀 달랐습니다.
저자는 행위라고 설명하는 애플리케이션 코드를 이용해 데이터를 다루는 놀랍도록 다양한 전략을 설명합니다. 백엔드 코드는 그저 DB 데이터의 포맷을 바꿔서 전달하는 인터페이스가 아니라, 범용적인 데이터로 표현되는 애플리케이션의 핵심 정보를 효과적으로 다루며 도메인과 애플리케이션 로직을 담을 수 있는 유용한 도구가 될 수 있다는 것을 보여줍니다.
가장 감탄한 것은 데이터를 처리하는 코드가 얼마나 효과적으로 동시성을 다룰 수 있으며 단위 테스트를 비롯한 다양한 테스트를 손쉽게 만들 수 있는지 보여주는 내용입니다. 이렇게 작성된 명료한 코드는 이해하기 쉽고 변경이 유연하며, 객체지향이 추구하고자 했던 것을 크게 포기하지 않으면서도 데이터를 잘 다루는 코드가 가능하겠다는 기대감을 갖게 합니다. 따라서 너무 많은, 비슷한 구조의 DTO 작성과 반복적인 단순 데이터 변환 코드에 지친다는 백엔드 개발자들에게 새로운 개발 전략을 찾기 위한 많은 힌트를 제공해줄 것입니다.
물론 대부분의 예제에서 사용한 자바스크립트나 그와 유사한 유연한 언어가 아니라면 분명 한계가 존재할 것입니다. 자바나 코틀린 개발자라면, 또 JPA와 같은 ORM에 익숙한 데이터 처리 기술을 포기할 수 없다면, 맵으로 표현한 데이터의 사용이 쉽지는 않으리라 생각합니다. 하지만 데이터를 다루는 언어 표현력의 발전에 도움을 받으면 새로운 길이 보이지 않을까 싶기도 합니다.
책에 나오는 대화의 많은 부분이 아마도 책을 읽는 기존 백엔드 개발 방식에 익숙한 개발자의 머리에 떠오를 것입니다. 이에 대해 저자가 어떻게 계속 설득하는지 따라가보면 꽤 많은 인사이트를 얻게 될 것입니다.
-이일민
이프릴(Epril) 대표, 『토비의 스프링』 저자
◈ 옮긴이의 말 ◈
마틴 클레프만(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. 나이가드와 라이언 싱어가 쓴 ‘추천의 글’을 이 책을 읽기 전과 후에꼭 읽어보길 바랍니다. 이렇게 책의 의미를 잘 소개한 추천사를 지금껏 본 적이 없다고 느낄 정도로 훌륭한 추천사이기 때문입니다. 특히 나이가드의 추천사는 그의 연륜이 느껴질 정도로 깊이가 있습니다(이 ‘옮긴이의 말’은 두 추천사를 읽을 것을 권하는 이 문단 외에는 쓸모없다고 해도 과언이 아닙니다).
마지막으로, 부족한 번역으로 인해 불편을 끼칠 것에 대해 미리 사과합니다. 그래도 부단히 노력한 결과인 만큼 즐거운 여정에 도움이 되길 바랍니다.
◆ 저자소개 ◆
예호나탄 샤르빗
저자 : 예호나탄 샤르빗
(Yehonathan Sharvit)
소프트웨어 엔지니어로 C++, 자바, 루비, 자바스크립트, 클로저, 클로저스크립트를 사용한 백엔드와 프론트엔드 프로그래밍에서 20년 이상의 경험을 쌓아왔다. 현재는 사이코그니토(Cycognito)에서 대규모 데이터 파이프라인의 소프트웨어 인프라를 구축하는 소프트웨어 아키텍트로 일하고 있다. 프로그래밍에 대한 열정을 블로그(https://blog.klipse.tech/)와 기술 콘퍼런스에서 공유하며, 엑스(https://x.com/viebel)에서 팔로우할 수 있다.
역자 : 박성철
중학교 2학년 때 이른바 ‘중2병’으로 컴퓨터에 푹 빠진 후 지금까지 40년가량 컴퓨터를 매개로 세상을 탐험하고 있다. 평생 혼자 살 운명이었으나 천사를 만나 구원받고 용인의 한적한 산기슭에서 아들과 함께 셋이서 행복한 가정을 꾸리고 산다. 지금은 컬리에서 멋진 개발자들과 함께 IT와 데이터 기술을 바탕으로 세상을 바꾸는 즐거운 퀘스트를 수행 중이다. 소프트웨어 개발에 대한 인식을 바꾸고 개발 현장을 개선하는 데 관심이 많다.