- 개요
개발을 하다보면, 어떤 함수가 너무나도 길어 ‘뚱뚱하다’고 느낄때가 있다. 뚱뚱한 함수를 보면 어지러운 기분이 들고 어디부터 봐야할지 모르겠다는 마음이 든다. 할 일이 많아지면 검증해야할 것이 n개의 요소일 때 n!만큼 늘어나기 때문에 우리의 ‘직관’이 그 함수를 처리하기 어려워하는 것이다. 이렇게 뚱뚱한 함수를 작성하게 되면 ‘프로덕트의 요구사항’이외에 관리해야할 복잡성이 지나치게 증대된다. (사담: 버전 관리 도구인 Git을 개발자들이 사용할 때, Chore라는 태그를 사용하는 경우가 있다. Chore는 사전적 의미로 ‘하기 싫은 일’을 의미한다. 어플리케이션의 로직과는 큰 관련이 없지만, 구현하려면 어쩔 수 없이 해야하는 것을 부른다. 그만큼 사람들은 불필요한 복잡성의 증대를 매우 싫어한다.) 그렇게 되면 불필요한 관리에 리소스가 분산되고 업무 효율이 기하급수적으로 저하된다. 각 함수의 역할이나 프로세스에 대해 부가 설명이 필요함으로 커뮤니케이션 비용도 크게 증가하게 될 것이다. 그러니 개발할 때는 각자의 역할을 분리하여 각자의 문제를 보다 ‘단순’하게 만들어 주어야 한다. 이때 나오는 말이 ‘관심사의 분리’다. ‘관심사’는 프로덕트가 달성하고자 하는 목적을 위해 수반되는 로직들을 말하고, 비즈니스로직이라고도 한다. 조금은 추상적인 ‘관심사’는 그 구분점이 두드러지게 드러나는 것은 아니다. 보다 우리가 정하는 것에 가깝다. 기획을 통해서 어느 부분이 핵심적인 구분점이고, 어떤 순서를 통해서 문제를 해결해야하는지 정한 그 것이 관심사이자 비즈니스 로직이다. (이런 부분 때문에 프로덕트의 이해가 높은 개발자는 전체적인 구조를 잘 조망하고, 쉽게 개발할 수 있다.)
이렇게 구분하는 이유는 크게 두 가지 인데, 하나는 당연하게도, 프로덕트가 그런 요구사항, 즉 관심사의 집합이기 때문이다. 어떻게 만들지와 무엇을 만들지 가운데 중요한 것은 ‘무엇을 만들지’다. (물론 어떻게 만들었냐에 따라서 다른 프로덕트와 차별점을 가질 수있다고 말할 수도 있다. 하지만 여기서 말하고자하는 ‘무엇’은 그것 또한 포함하는 보다 큰 개념이다. 그 ‘어떻게 만들었냐’가 기획을 통해서 나온 ‘비즈니스 로직’이기 때문이다.) 그것 자체가 우리 팀이 세상에 보내는 문제에 대한 답이며, 세상 또한 그것을 기대하기 때문이다. 보다 관심있는 부분을 잘 핸들링 할 수 있으려면 그 부분이 기준이 되어 가치판단이 되어야한다. 그리고 그런 프로덕트가 시장에서 성공할 수 있다.
또 다른 하나는 ‘어떻게 할 지’에 대한 부분은 유동적이기 때문이다. 비즈니스 로직을 어떻게 구현할지에 대해서 다양한 방법이 있을 수 있다. 한 방법이 나중에 구식이 될 수도 있고, 여타 필요에 따라서 변경될 필요도 있을 수 있다. 하지만 프로덕트가 제공하는 가치는 그렇게 유동적이 될 수 없다. 그것 자체가 프로덕트의 목적이고, 핵심적으로 가져가고 있는 부분이므로 변경된다면 사용자가 큰 혼란을 겪을 수도, 시장에서 도태 될 수도 있다. (반대의 경우도 있지만, 많고 다양한 분야의 가치판단이 필요함으로 상대적으로 변화가 더딜 수 밖에 없다.) 유동적인 부분을 기준으로 삼게되면 너무 잦은 구조적 변동이 있을 수 있고, 프로덕트의 안정성이 크게 저해된다.
이렇게 관심사를 기준으로 구분하여 개발하면 다양한 장점을 가져다준다. 보다 인간의 언어, 팀의 언어에 가깝게 어플리케이션을 구성할 수 있고, 비즈니스 로직의 오류를 알아보기 쉬워지며, 문제를 단순하게 바라보기 쉬워진다. 언어가 보다 추상적일수록 고급 언어라고한다. 비슷한 의미에서 구현을 기반으로 구분하는 코드보다, 팀의 언어로 추상화한 코드가 보다 ‘고급’스럽다고 할 수 있다. 많은 의미를 내포함으로서 로직이 보다 추상적으로 변하지만 구체적인 구현명세보다, ‘구체적인 목적’이 제시 됨으로 창의적인 아이디어가 솓아날 여지를 만들어준다. 우리가 보통 일상속에 ‘고급진 어휘’라고 부르는 것들도 유사한 속성을 가지고 있다. 정확하게 유의 해야할 의미만을 남기고 나머지를 맥락적인 영역에 맡김으로 보다 핵심적인 사유를 가능하게 한다. 또, 개발자들의 은어와 같은 ‘구현 상세어’는 사라지고 팀의 언어에 가까워지면서 비개발자 직군과 언어가 매칭되며, 개념에 대한 이해가 동기화되기 쉬워진다.
앞서 말한 것 처럼 프로덕트에서 사람들이 중요하게 느끼는 건 ‘무엇을 하는지’에 대한 부분이다. 그런 의미에서 프로덕트의 오류라고 하는 것은 우리가 세운 프로덕트가 가치를 제공하는 비즈니스 로직의 오류를 말한다. 구현의 오류는 ‘정답’의 영역으로 컴퓨터가 쉽게 찾아내 잡아줄 수 있고, 개발자들은 그런 도구를 많이 가지고 있는 반면, 비즈니스 로직의 오류는 쉽게 알아채는 것이 어렵다. 맞다 틀리다의 영역이 아니라 팀의 가치판단을 기준으로 보다 낫다, 덜하다의 영역이기 때문이다. 인간의 언어, 팀의 언어로 추상화된 구분방식으로 개발하게 되면 ‘세세한’ 구현상의 디테일보다 전체적인 관점에서 로직의 흐름을 바라볼 수 있게 만든다. 그렇게 되면 컴퓨터가 캐치해내지 못하는 오류를 발견하기 쉬워지고, 좋은 프로덕트가 되기 쉬워진다.
그렇게 되면 실제로 구현할 때에는 프로덕트의 전체적인 구조를 생각하지 않아도 된다. 지금 당장 구현하고 있는 함수의 주제만 생각하면 되며, 그렇게 되면 ‘하나의 구현’에 집중하여 개발 할 수 있으므로 복합적으로 생각할 때는 너무나 복잡했던 문제가 매우 단순하게 변한다. 문제 해결이 단순해지면, 쉬워지고 리소스 또한 절약할 수 있게 된다. 이는 더 많은 일을 할 수 있게 됨을 의미하고, 구현의 난이도에 쩔쩔매는 대신 프로덕트를 위한 창의적인 아이디어를 낼 수 있는 여유를 가져다 준다.
구현에 집착하게 되면, 자칫 절차위주로 개발하게 될 수 있다. 절차를 기준으로 개발하게 되면, 오늘 날의 복잡하고 큰 프로젝트를 감당하기 어렵다. 절차라는 어휘 자체가 이미 맥락의 이해를 강요하기 때문이다. 전체적인 맥락을 이해하고 개발해나가야 의미가 있는 개발 방식인데, 경우의 수가 많아지고 복잡해지면 그 맥락을 사람이 이해하기 힘들어진다. (복잡도는 기하급수적으로 늘어나기 때문에) 각자의 구현은 각자에게 맞기고, 그 객체간의 관계를 조망하는 선언적 프로그래밍이 오늘 날 더 각광받는 이유다.
우리가 핸들링 할 수 있는 복잡성은 한계가 있지만, 그렇다고 우리가 복잡한 것을 만들어낼 수 없는 것은 아니다. 끊임없이 단순화 하는 과정을 거치면 된다. 목적에 따라 알아야 할 것을 정의하고 몰라야 할 것을 구분해낼 줄 알면 된다. 이미 수많은 프로덕트가 그렇게 개발되어 있으며, 우리는 부지불식간에 그 프로덕트들이 가져다주는 생활의 편의를 많이 누리고 있다. 자동차, 휴대폰, 컴퓨터의 내부를, 구조를, 구현을 몰라도 그것들이 가져다 주는 이점은 명백하고 단순하기 때문이다. 어떻게 하는지 보다, 무엇을 하는지, 그것을 위해 무엇이 중요한지, 그렇게 사고하는 토대 위에 우리는 더 많은 복잡한 일들을 보다 쉽게 해낼 수 있다.