타르구덩이에서 빠져나오기 위한 여정 - 1

Table of Contents

1 Disclaimer

이 글은 개인적인 기록을 위한 글이며, 사견이 깊게 관여하고 있음.

2 프레드릭 브룩스

훌륭한 요리에는 시간이 필요합니다.혹시 저희가 기다리시게 했다면, 더 잘 섬겨 모셔서 만족을 드리기 위함입니다.

  • 미국 뉴올리언스 New Orleans 소재 앙투안 Antoine 레스토랑의 메뉴판

프레드릭 브룩스는 맨먼스 미신의 저자이다. 이며 맨먼스에 대한 설명으로 유명하다.

맨먼스 단위로 작업량 을 잰다는 것은 위험하고도 기만적인 미신과 같다. 거기에는 사람과 일정이 서로 교환 가능하다는 인식이 깔려 있다.

사람과 일정이 교환 가능한 유일한 경우는, 어떤 일을 여러 사람에게 나눠줄 수 있으면서 서로 간에 소통할 필요가 없는 경우다. 이것은 밀을 수확하거나 목화를 따는 일에는 들어맞겠지만, 시스템 프로그래밍에는 대략이라도 해당되지 않는다.

만약 작업의 성격상 순서가 있어서 나누기가 어렵다면, 거기에 어떤 노력을 더 쏟아 붓더라도 일정에는 아무런 영향을 미치지 못한다. 아기가 세상에 태어나려면 임신부가 몇 명이든 아홉 달이 필요하다.

버그를 찾고 고치는 것이 순차적으로 진행될 수밖에 없으므 로 소프트웨어 개발 작업은 이처럼 분할이 어려운 경우가 많다.

  • 맨먼스

3 타르구덩이

프레드릭 브룩스의 맨먼스 미신에서는 끈적한 타르구덩이에서 벗어나기 위해 안간힘을 쓰지만 몸부림이 거셀수록 더 얽혀들고 결국 가라앉고 마는 공룡을 묘사한다.

대규모 시스템 프로그래밍 분야에서 크고 작은 팀들이 타르 속에 얽혀들어가고, 처음에는 조금 느리게 움직일 수 있어서 별 지장이 없으나 결국 여러 상호작용으로 더욱 둔해진다.

문제를 알았을 때는 본질을 분별해내기 어려워진다.

우리는 문제를 해결하기 위해서는 먼저 무엇이 문제인지 노력해야한다고 말한다.

4 은 탄환은 없다

프레드릭 브룩스의 타르구덩이를 벗어날 방법을 알려주지 않았다.

오히려 우리에게 빠져나갈 수 없는 이유들을 [은 탄환은 없다] 라는 논문에 개시했다.

수 많은 사람들이 브룩스에게 편지를 보냈지만, 10년 후 그는 아직 은 탄환이 없는 것 같다는 글로 답했다.

왜 소프트웨어는 어려울까? 그는 아래 4가지로 답변했다.

  1. 복잡성 : 소프트웨어의 복잡성은 우연이 아니라 본질적이다. 수학과 물리학은 기본 원리나 공리에서 출발하여 복잡한 이론을 구축한다. 반면 소프트웨어는 처음부터 복잡한 시스템을 다루며, 그 복잡성이 근본적이다.
  2. 호환성 : 소프트웨어는 비상식적인 외부 세계와 연결되어야 한다. 소프트웨어는 자연법칙이 아닌, 인위적으로 만들어진 규칙과 표준을 따라야 합니다. 이러한 복잡성은 인터페이스마다 다르다. 필요성 때문이 아니라 신이 아닌 그저 다른 사람이 설계했기 때문이다.

    시간이 지남에 따라 준수해야 하는 것들이 변하거나 추가된다.

  3. 변경가능성 : 소프트웨어는 다른 물리적 제품보다 훨씬 더 변화가 빈번하다. 모든 성공적인 소프트웨어는 변경된다. 두 가지 프로세스가 작동된다.
    1. 더 나아가기를 압력받다 : 소프트웨어 제품이 유용하다고 판단되면 사람들은 원래 영역의 가장자리 또는 그 너머에 있는 새로운 케이스에서 이를 시도한다.
    2. 따라오라고 압력받다 : 성공적인 소프트웨어는 처음 작성된 기계 수명이 다한 후에도 살아남는다. 변화하는 현실세계에 적응을 해야한다. (법규의 개정, 새로운 기술 등장, 프로토콜 변경 등)
  4. 비가시성 : 소프트웨어는 공간적으로 표현이 어렵다. 여러 방향의 그래프 구조로 이루어져 시각화가 어렵다.

    기하학적 추상화는 강력한 도구이다.

    건물의 평면도는 건축가와 고객 모두에게 공간, 교통 흐름, 전망을 평가하는데 도움이 된다. 모순과 누락이 분명해진다. 기계 부품의 축적 도면과 분자의 막대 모형도 추상화지만 같은 용도로 사용된다.

    소프트웨어는 본질적으로 공간에 내장되어 있지 않다. 토지에 지도, 실리콘 칩에 다이어그램, 컴퓨터에 연결 회로도처럼 기하학적 표현이 준비되어 있지 않다.

    소프트웨어 구조를 다이어그램화하려고 시도하는 순간, 우리는 그것이 하나가 아니라 여러 개의 방향그래프가 서로 겹쳐져 있다는 것을 알 수 있다. 즉, 제어 흐름, 데이터 흐름, 종속성 패턴, 시간 순서, 이름-공간 관계 등으로 연결되어있다는 것이다.

5 타르구덩이에서 빠져나오기

(벤 모즐리)Ben Moseley 와 (피터 마크스)Peter Marks 는 [Out of Tar Pit] 은 프레드릭 브룩스가 표현한 타르구덩이에서 빠져나올 수 있기를 희망하는 사람들의 노력이다. 이 백서는 완벽한 해답을 제시하지는 않지만, 나름이 답안을 만들어낸다.

이들은 프레드릭 브룩스가 설명한 소프트웨어가 어려운 이유 4가지중 '복잡성' 하나에 집중한다.

그 이유는 '복잡성' 만이 중요한 것이며 나머지는 복잡성의 형태 혹은 증상으로 분류될 수 있다고 주장한다.

5.1 복잡성의 종류

  1. 필수 복잡성(essential complexity): 필수 복잡성은 문제 자체에서 비롯되는 복잡성. 이 복잡성은 제거할 수 없으며, 소프트웨어가 해결하려는 문제의 본질에 내재해 있습니다. 예를 들어, 은행 시스템에서 거래를 처리하는 논리적인 복잡성은 필수 복잡성에 해당합니다.
  2. 우발적 복잡성(accidental complexity): 우발적 복잡성은 문제의 본질과는 무관하게 개발 과정에서 도입된 불필요한 복잡성을 말합니다. 이는 주로 소프트웨어 설계나 구현 방식에서 발생합니다. 예를 들어, 언어의 제한이나 시스템의 아키텍처적인 결정 때문에 발생하는 복잡성이 우발적 복잡성에 해당.

5.2 논문의 주요 주장

  • 복잡성의 주요 원인은 상태(state) 관리에서 발생하며, 이는 소프트웨어 개발에서 가장 큰 문제 중 하나이다.
  • 상태 관리 문제를 해결하기 위해서는 상태를 최소화하고, 불변성(immutability)을 적극 활용해야 한다.
  • 논문은 함수형 프로그래밍이 이러한 복잡성을 줄이는 데 유용하다고 주장. 함수형 프로그래밍 언어는 상태를 변경하지 않으며, 순수 함수(pure functions)를 사용하여 부작용(side effects)을 제거하므로 우발적 복잡성을 줄이는 데 도움을 준다고 봄.
  • 또한, 도메인 모델링의 중요성을 강조하며, 잘 정의된 도메인 모델이 필수 복잡성을 효과적으로 다룰 수 있다고 말함.

해결 방안

  1. 함수형 프로그래밍: 함수형 프로그래밍 언어의 사용을 통해 상태를 줄이고, 불변성을 유지하며, 순수 함수를 사용함으로써 복잡성을 낮출 수 있습니다.
  2. 도메인 모델링: 문제의 본질을 잘 표현하는 도메인 모델을 설계함으로써 필수 복잡성을 명확히 하고, 우발적 복잡성을 최소화할 수 있습니다.
  3. 복잡성의 분리: 시스템의 각 부분이 복잡성을 독립적으로 다루도록 설계하여 전체 시스템의 복잡성을 관리할 수 있습니다. 예를 들어, 비즈니스 로직, 데이터 관리, 사용자 인터페이스를 분리하는 것이 한 예입니다.

5.3 상태의 종류 (이상적인 세계를 향하여)

가상의 이상적인 세상을 상상하자.

성능도 언어도 인프라까지 우리가 원하는 자원을 제공받는다. 우리는 이러한 배경에서 상태와 제어에 바라보는 것이다.

이상적인 세계는 상태의 주된 목표는 상태를 최대한 줄이는 것이다. 이상세계에서 생략할 수 있는 녀석이라면, 이 상태를 우발적인 상태로 식별할 것이다.

이런식별은 우리가 상태를 만들 때, 이것이 우발적인 상태인지 본질적으로 필수적인 상태인지 인지하는 것으로 우리가 어떤 복잡성을 허용했는지 인지하는데 도움이 될 것이라고 개인적으로 생각한다.

  1. 입력데이터 직접 제공(입력)된 데이터를 필수적이다. 이 데이터는 두가지 유형이 있다.
    1. (요구사항에 따라) 향후 시스템이 참조할 가능성이 있는 경우 : 이상세계에서도 필수상태에 해당한다.
    2. 가능성이 없는 경우 : 유지할필요가 없다.
  2. 필수 파생 데이터 - 변경 불가(Immutable)

    우발적인 상태이다. 입력데이터를 통해 언제든지 필요할 때마다 파생시킬 수 있다. 따라서 이상적인 세계에서는 저장할 필요가 없다.

  3. 필수 파생 데이터 - 변경 가능(Mutable)

    역시 우발적 상태.

    파생 데이터의 변경 가능성은 데이터를 파생하는 데 사용된 함수(로직)에 역함수가 있는 경우에만 의미가 있다. 파생된 데이터가 입력 데이터를 단순화하기 위한 재구조화를 나타내는 경우 역함수가 존재하는 경우가 많다.

    그렇지 않다면 이 데이터는 파생되 것으로 간주할 수 없으며 사실상 입력데이터로 간주한다.

  4. 우발적 파생 데이터

    시스템의 본질적 기능에 필수적이지 않지만, 구현 과정에서 도입된 불필요한 상태를 의미.

    예를들어 아래처럼 반복계산을 피하기 위한 캐싱처리 같은 것들이다.

    procedure int doCalculation(int y)
      // ’subsidaryCalcCache’ is declared and initialized
      // elsewhere in the code
      if (subsidaryCalcCache.contains(y) == false) {
        subsidaryCalcCache.y := slowSubsidaryCalculation(y)
      }
    return 3 * (4 + subsidaryCalcCache.y)
    

6 이상세계에 가까워지고 있다.

6.1 클라우드 컴퓨팅의 확산

우리는 무한정의 리소스를 합리적인 가격으로 사용할 수 있다.

물론 클라우드 서비스가 신은 아니지가 무한정 제공해줄 수는 없다. 하지만 우리가 N개의 리소스가 필요하고 클라우드 업체가 N+1 개의 리소스를 제공한다면 우리는 무한으로 체감할 수 있습니다.

6.2 마이크로 서비스

  1. 리소스를 유동적으로 변화시킬 수 있다는 점과 마이크로서비스의 번영
    • 리소스의 유동적 변화: 클라우드 컴퓨팅의 가장 큰 장점 중 하나는 필요에 따라 컴퓨팅 자원(메모리, CPU, 스토리지 등)을 유동적으로 할당하고 조정할 수 있다는 점이다.
    • 마이크로서비스의 번영: 마이크로서비스 아키텍처는 큰 애플리케이션을 여러 작은 독립적인 서비스로 나누어 관리하는 접근 방식이다. 각 서비스는 독립적으로 배포, 확장, 유지보수할 수 있어야 한다. 클라우드의 유동적인 리소스 관리 기능은 이러한 마이크로서비스의 요구사항을 충족시켜 주며, 필요한 경우 각 서비스를 개별적으로 확장하거나 축소할 수 있게 해줍니다. 이로 인해 마이크로서비스 아키텍처가 더욱 번영할 수 있는 환경이 조성된 것이다.
  2. 도메인 단위로 서비스 만들기와 클라우드의 역할
    • 도메인 단위 서비스: 도메인 주도 설계(DDD)에서는 시스템을 비즈니스 도메인 단위로 나누어 각 도메인에 맞는 서비스를 설계하고 구현. 이러한 서비스는 독립적이며, 각각의 도메인이 다른 도메인과 적절히 격리되어 운영될 수 있도록 설계됩니다.
    • 클라우드의 기여: 클라우드 환경은 이러한 독립적인 도메인 단위 서비스를 손쉽게 배포하고 관리할 수 있게 해줍니다. 각 도메인 서비스는 클라우드 인프라에서 독립적으로 운영될 수 있으며, 필요에 따라 별도의 리소스를 할당받아 운영될 수 있습니다. 클라우드는 이러한 서비스의 유연한 확장성, 높은 가용성, 손쉬운 배포를 가능하게 하여 도메인 단위로 서비스를 만들고 분리하는 작업을 더 효율적으로 할 수 있게 해준다.

6.3 함수형 프로그래밍

  1. 함수형은 리소스가 많이 필요하다.
    • 불변성(immutability): 함수형 프로그래밍에서는 데이터가 불변으로 다뤄지기 때문에, 상태 변경을 할 때마다 새로운 데이터 구조가 생성된다. 이는 추가적인 메모리 사용을 요구한다. (또한 이것은 Persistant Data Structure 라는 자료구조가 제시되면서 함수형 시대의 태동이 되었다고 볼 수 있다. 이 자료구조는 나중에 시간이 되면 소개하도록 함)
    • 재귀와 고차 함수: 함수형 프로그래밍에서는 반복 대신 재귀를 많이 사용하며, 고차 함수는 더 복잡한 계산을 수행할 수 있도록 합니다. 이러한 접근은 코드의 가독성과 재사용성을 높여주지만, 복잡한 계산이 반복되면서 더 많은 메모리와 CPU 자원을 필요로 한다.
    • 게으른 평가(lazy evaluation): 게으른 평가 전략은 필요할 때까지 계산을 지연시키는 방식으로 자원을 최적화하지만, 특정 시점에 갑작스런 리소스 소비를 유발할 수 있다.
  2. 초기 컴퓨팅 환경의 한계
    • 초기 컴퓨터의 제한적인 리소스로는 비효율적인 자원 사용을 초래한다.

6.4 데이터베이스는?

처음 out of tar pit 에 설명한. essential data 즉, input data 만 저장해야하며 파생데이터는 계산만해서 사용하는 세상에 우리는 살고 있는가? 우리의 데이터베이스는 불변한가?

하지만 우리는 변화를 원한다. 구글에서 동일한 값을 검색하면, 1년 전 데이터와 동일한 결과를 원하지 않는다. 시간이 지남에 따라 리턴값은 변화해야 한다.

데이터베이스에서도 불변성을 유지하는 것이 가능하지만, 현실적으로는 데이터를 수정하고 업데이트하는 경우가 더 많다. C나 Java 같은 언어에서도 불변하게 코드를 작성할 수 있지만, 우리는 이 언어들의 자료구조를 불변이라고 말하지 않는다. 쉽게 변할 수 있는 구조이기 때문이다. 그렇기에 우리는 c,java의 자료구조를 불변하다고 말하지 않는다. 변하게 하는 방식이 너무 쉽기 때문이다.

database 도 마찬가지다. 우리는 불변하게 사용할 수도 있다. 하지만 그렇다고 우리가 사용하는 데이터베이스를 불변하다고 생각하지 않는다. 우리는 어떤 테이블의 구조를 보고 이것이 불변하다. 현재까지 한번도 수정이 일어난 적이 없다고 단정할 수 없다.

6.5 꼭 강제해야 하는가?

  • 구조적 프로그래밍은 제어흐름의 직접적인 전환에 부과되는 규율이다.
  • 객체 지향 프로그래밍은 제어흐름의 간접적인 전환에 부과되는 규율이다.
  • 함수형 프로그래밍은 변수 할당에 부과되는 규율이다.

이들 세 패러다임 모두 우리에게서 무언가를 앗아갔다. 각 패러다임은 우리가 코드를 작성하는 방식의 형태를 한정시킨다. 어떤 패러다임도 우리의 권한이나 능력에 무언가를 보태지는 않는다.

지난 반세기 동안 우리가 배운 것은 해서는 안되는 것에 대해서다.

– 클린 아키텍처 –

위처럼 제약을 가함으로서 우리는 다음과 같은 이점을 기대할 것이다.

  • 구조적 프로그래밍:
    • 코드의 가독성 향상
    • 로직의 명확한 구조화
    • 디버깅의 용이성
  • 객체 지향 프로그래밍:
    • 코드의 재사용성 증가
    • 복잡한 시스템의 모듈화
    • 유지보수의 용이성
  • 함수형 프로그래밍:
    • 부작용 최소화
    • 병렬 처리의 용이성
    • 테스트와 디버깅의 단순화

분명 C로도 함수형 프로그래밍이 가능하고, 객체지향 프로그래밍이 가능하다.

하지만 우리가 스스로를 제약하기 도와주는 언어를 사용할 때, 더욱더 쉽게 원하는 이상에 도달할 수 있다.

7 Datomic: 함수형 데이터베이스

데이터베이스에서 불변성의 이점을 얻을 수 있다고 주장하는 프로젝트가 있다.

Datomic 은 모든 데이터를 저장하며, 독자적인 방식(Datalog)으로 쿼리하여 SQL과 같은 데이터베이스 기능과 불변성의 장점을 모두 가지려고 한다.

Datomic 은 일반적인 데이터베이스와 많이 다르다.

일단 모든 트랜잭션을 병렬성을 제거하여 일렬로 세워서 처리한다.

싱글스레드로 볼 수도 있지만 실제 작업은 여러가지 단계별로 파이프라인이 형성되어있고, 각각은 비동기로 수행되기 때문에 병렬로 수행될 수 있다. 하지만 기본적으로 이 트랜잭션을 처리하는 작업은 동기로 처리되며 동시성을 지원하지 않는다.

이에 대한 내용을 설명하며, Datomic 은 이것이 생각보다 많이 느리지 않음을 주장하는데 그것에 대한 주장으로 스톤브레이커 교수(Michael Stonebraker)의 논문을 제시한다.

논문의 이름은 (The End of an Architectural Era) 이며 대충 기존 RDB는 OLTP에서는 맞지 않은 아키텍처를 가졌다는 것이다.(다른 강점이 있는 곳이 있다)

이 논문과 관련된 내용은 시간이 나면 정리하도록 해보겠다.

이 논문에서 멀티스레딩에 대한 리소스 제어에 대한 비용이 너무 크다고 지적합니다.

스톤브레이커 교수는 Postgresql 을 만드는데 큰 공헌을 하신분이기 때문에 허투로 발표하시는 분은 아닐 것으로 보인다.

실제로 RDB에서 사용되는 리소스에 대부분은 corrdination (bufferpool, locking, latching, recovery) 이 96%, only usefule work를 4% 를 수행한다고 주장한다.

그래서 이 기능들을 제거하는 것이 리소스를 효율적으로 사용하고 성능도 올린다고 말한다. (이에 근거하는 Database는 대표적으로 VoltDB인 것같다. 이것도 나중에 알아보도록 할 것이다.)

Datomic 결국 Datomic 은 트랜잭션을 처리하는 속도가 하나의 통로로 처리하면서 하나의 트랜잭터가 수행하는 속도가 놀라울 정도로 빨라진다고 주장한다. (뭐 결국 그 성능을 초과해야 한다면, 도메인을 나눠서 트랜잭터를 추가하거나, CPU 성능을 가능한만큼 올리면 속도는 더 올라갈 것이다)

Datomic은 데이터의 불변성이라는 제약을 통해 다음과 같은 이점을 제공한다:

  • 데이터 일관성: 불변 데이터는 동시성 문제를 크게 줄인다.
  • 시간 여행: 모든 변경사항을 기록하여 과거 상태로의 "시간 여행"이 가능하다.
  • 감사 추적: 모든 변경사항이 기록되어 완벽한 감사 추적이 가능하다.
  • 동시성 처리: 불변 데이터는 동시성 처리를 단순화한다.

이 서비스를 사용하는 회사들은 많지 않다. 무료화 되면서 조용히 쓰는 회사들도 많아졌지만, 공식 사이트에 보여지는 큰 회사들을 몇개 나열해보면

  • Facebook
  • Nubank
  • Netflix
  • Time Inc(megazine)

이중에서 Datomic을 주 데이터베이스로 사용하는 회사로는 Nubank가 유명하다.

우선 누뱅크(Nubank)는 2024년 1Q 기준 8200만 활성고객(전년도 대비 26% 증가), 활성 신용카드 고객 4120만명(전년도 대비 19% 증가) 를 가진 글로벌 은행이다.

그들의 유튜브 세미나를 보면 유저, 카드, 결제, 이체 등 대부분의 데이터를 불변으로 관리하며 이 모든 데이터를 Datomic 을 사용한다.

누뱅크는 초창기부터 Datomic 의 가능성을 보고 파괴적인 혁신을 하기 위해 메인 데이터베이스로 사용하기로 결정하고, 이 데이터베이스를 만드는 회사를 구매까지한 회사이다.

8 사견이 더해진 정리

  • 프레드릭 브룩스는 [은탄환은없다] 에세이로 프로그래밍은 복잡성이 항상 존재하기 때문에 이는 줄어들지 않을 것이고, 우리는 평생 고통받을 것임을 주장했다.
  • [out of tar pit] 논문은 브룩스가 말하는 복잡성을 해결하기 위해서는 여러가지를 제안했고 그 핵심에는 상태를 줄이는 것에 있다.
    • 함수형 프로그래밍으로 상태를 줄일 수 있기를 기대해본다.
    • 도메인 단위로 서비스 만들어 복잡도를 줄일 수 있을 것 같다. (상태로 인한 복잡도도 줄어든다)
  • 이를 넘어서 데이터베이스를 불변으로 만들어보려는 시도까지 존재한다. (Datomic)

Date: 2024-08-27 Tue 00:00

Author: Younghwan Nam

Created: 2024-09-25 Wed 07:42

Emacs 27.2 (Org mode 9.4.4)

Validate