소프트웨어와 복잡성
* 이 글은 liftIO2023 에서 발표한 내용 [Betting on Clojure] 을 요약, 각색하여 작성했습니다.
우리가 해야하는 질문
셀파스의 작년 6월을 생각해봅니다. 당시는 우리 앞에 어떤 어려움이 앞에 있는지도 모르는, “Unknown unknown”이 가득한 상태였습니다. 소중한 투자금과 시간을 어디에 어떻게 활용해야 이 거친 스타트업의 망망대해를 헤쳐갈 수 있을지 감이 잡히지 않았습니다. 어떻게 해야 사랑받는 제품을 만들고 성공할 수 있을까요?
그 즈음, 전설적인 투자자 찰리 멍거(Charlie Munger, 1924~2023)의 영상을 우연히 접했습니다. 그의 조언은 단순했지만 깊은 울림이 있었습니다. ‘어떻게 하면 성공할 수 있을지 생각하지 말고, 어떻게 하면 실패할 수 있을지를 생각하라. 그리고 그것을 하지 마라!'
성공이라는 이벤트가 임계점을 지나 발현되기까지는 무수히 많은 변수 - 팀, 아이디어, 문화, 자본, 열정, 타이밍 등 - 가 개입합니다. 이 모든 것을 잘 하고 싶은데, 시작부터 막막합니다. 여기서 고(故) 멍거의 조언은 가장 큰 리스크를 관리하도록 하여 고민의 차원을 줄여주고, 그 토대 위에서 우리가 원하는 것에 집중하게 하는 효과가 있습니다.
그럼 질문을 바꿔보겠습니다. 개발의 관점에서, 어떻게 하면 제품이 확실히 실패할 수 있을까요?
개발을 실패로 이끌기 위한 방법
실패로 가는 길은 다양합니다.
- 코드의 가독성을 무시하고 복잡한 구조를 만듭니다.
- 테스트를 작성하지 않거나 불충분하게 작성합니다.
- 기술 부채를 계속 쌓아갑니다.
- 문서화를 소홀히 합니다.
- 팀 내 의사소통을 최소화하고, 지식 공유를 하지 않습니다.
- 새로운 기술만을 쫓아 불필요한 복잡성을 추가합니다.
- 도메인에 대한 이해 없이 개발을 진행합니다.
- 확장성과 유지보수성을 고려하지 않은 설계를 합니다.
- 코드 리뷰와 품질 관리 프로세스를 무시합니다.
- 사용자 피드백을 무시하고 개발자 중심의 사고만 합니다.
이러한 방법들을 통해 개발 프로세스는 점점 더 복잡해지고 관리하기 어려워질 것입니다. 결국 제품의 품질 저하, 개발 속도 감소, 팀 사기 저하 등으로 이어져 프로젝트는 실패합니다. 위의 예시들을 종합하면, 결국 [복잡성]이 핵심임을 알 수 있습니다. 이를 적절히 다루지 않으면 실패에 크게 기여할 수 있습니다.
개발 영역에서의 복잡성은 아래 특징들이 가지는 복잡성의 합으로 정의될 수 있습니다.
첫째, 개발은 정신적인 활동입니다. 인간이 하는 모든 일은 결국 정신 활동이지만, 개발은 그 대상이 좀 더 직접적입니다. 나와 다른 사람의 결과물을 이해하고, 전체적 맥락을 파악해서 효율적이고 단순한 설계를 위해 노력하는 일의 반복입니다. 언어로 구성된 빽빽한 논리의 숲을 지키고, 가꾸며, 넓히는 일의 연속입니다.
둘째, 개발과정은 본질적으로 집단적 활동입니다. 한 프로젝트에 개발자가 두명 이상 투입되어 함께 일하는 경우가 흔하지만, 한명뿐이라도 과거의 내가 쓴 코드를 읽으며 미래의 나를 위한 코드를 작성해야합니다. 다른 전문성과의 협업 지점 또한 다양하며, 소통의 비용은 협업 지점에 기하급수적으로 비례합니다.
셋째, 개발의 결과물은 유연(soft)해야 합니다. 외부의 변화에 빠르게 대응할 수 있기 위해선, 쉽게 부수고 자신있게 새로 만들 수 있어야 합니다. 그 과정에서 많은 시간적, 인적 자원이 투입된다면 회사는 운영에 어려움을 겪게 될 것입니다.
복잡성의 종류
복잡성에는 크게 두 종류가 있습니다.
첫번째는 도메인에서 오는, 피할 수 없는 문제 그 자체의 복잡성입니다. 양자역학을 공부한다면 슈뢰딩거의 방정식을 피할 수 없고, SaaS 관리 서비스를 만든다면 각기 다른 SaaS의 주기적인 결제일을 잘 예측하고 관리해줘야 합니다. 더 이상 단순하게 환원될 수 없는 성질이 여기에 속합니다.
두번째는 우발적 복잡성입니다. 문제의 고유한 속성이 아니기에 우리가 조절할 수 있는 부분입니다. 문제의 해결에 직/간접적으로 관여하지만 문제 자체와는 독립적인 변수이며, 그러기에 확실한 관리가 필요한 부분입니다.
우리가 마주한 복잡성이 필연적인지, 우발적인지를 구분하는 것은 중요합니다.
필연적 복잡성에는 사활을 걸어야 합니다. 도메인 복잡성을 덜어주는 만큼의 가치를 고객이 지불할 것입니다. 우발적 복잡성은 탐지 후 제거해야 합니다. 더 중요하게는, 그것이 발생하지 않는 구조적 환경을 만들어야 합니다.
그 맥락에서 앞으로 블로그에서 풀어갈 이야기는 크게 세 가지 입니다. 모두 우발적 복잡성에 대한 인식과, 이것을 최소화하기 위한 사고적, 구조적 방법에 뿌리를 두고 있습니다.
첫번째는 함수형 프로그래밍입니다.
함수형 프로그래밍 패러다임이 어떻게 정신적 활동의 인지부하를 줄이며, 자연스럽게 생산성 증가로 이어질 수 있는지 이야기합니다. 개발팀에서 선택한 함수형 프로그래밍 언어인 Clojure의 특징은 무엇이며, 어떤 실용적인 도움과 즐거움을 주고 있는지 알아보겠습니다.
두번째는 도메인을 생각하는 개발 과정입니다.
제품을 개발하는 구성원들의 도메인에 대한 공통의 이해는, 의사소통 비용을 낮출 뿐만 아니라 제품 자체의 단순성에도 영향을 미칩니다. 코드가 어떻게 도메인 지식을 잘 반영할 수 있을지, 그렇게 하기 위해서 개발팀에선 어떤 노력을 하고 있는지도 소개합니다.
세번째는 테스트입니다.
유연한 소프트웨어를 위한 든든한 버팀목이 되고 있는 테스트에 대한 생각과 방향을 공유합니다. 개발팀이 직접 개발하고 유지보수하고 있는 Siheom(시험) 프레임워크부터, 프런트/백엔드를 아우르는 전방위적 테스트를 어떻게 작성하고 관리하고 있는지 소개합니다.
끝마치며 : Complexity Saga
복잡성은 한자어로 겹옷(複, 복)이 뒤섞인(雜, 잡) 상태를 뜻하며, 영어(complexity) 또한 com-(같이) + -plect(꼬이다)의 의미로 뒤섞이고 꼬여있는 상태를 의미합니다. 그렇다면 꼬여있지 않고, 뒤섞이지 않으면 복잡성은 사라집니다.
Clojure의 창시자 리치 히키는 [Simple made easy]에서 이 상태를 단순하다(Simple)라 표현하고, 쉬움(Easy)과 확실히 구분했습니다. 대체로 어떤 일을 손에 잡히는 대로 쉽게 하면 복잡성에 기여합니다. 단순하게 만드는 일은 쉬운일이 아니며, 구성원 모두의 합의된 인식과 의식적 노력이 투입되어야 합니다.
앞으로 블로그에서 풀어나갈 이야기들을 기대해주세요.
그럼, 또 봐요!
작성자: 김상현 - 소프트웨어 엔지니어