아, 이거 어렵네요.
개발자로 살아가면서 어려움을 겪는 것은 피할 수 없는 일입니다. 나의 기술적 실력이 모자라서 그럴 수도 있고, 개발하고 있는 분야에 대한 도메인 지식이 부족해서 그럴 수도 있죠. 또한 동료와의 커뮤니케이션, 정치적인 요소, 일정의 압박, 회사의 재정 상태처럼 개발 그 자체와는 직접적으로 상관이 없는 외부적인 요소로 인해 어려움을 겪기도 합니다.
오늘은 이러한 어려움의 유형 중에서도 문제 해결(Problem solving) 과정에서 겪는 어려움에 대해 집중해보려고 합니다. 왜냐하면 외부적인 요인은 개발자 개인의 노력과 능력 만으로는 통제할 수 없는 상황이 많으니까요. 반면 문제 해결 과정에서 겪는 어려움을 분석한다면, 내가 어떤 이유로 인해 혼란스러움을 겪고 있는 상태인지 를 알 수 있고 그에 맞는 적절한 해결 방법을 선택할 수 있을 것입니다.
사실 오늘 이런 주제를 선택하게 된 이유는, 회사에서 동료들이 각자의 업무를 처리하면서 겪는 어려움을 관찰하는 것 으로부터 시작했습니다. 각자 어려움 이라는 단어로 뭉뚱그려 말하고 있던 것의 본질을 깊게 들여다보니 미묘한 차이점을 발견했거든요. 그래서 문득 우리가 ‘문제 해결 과정에서 겪는 어려움을 특정 유형으로 묶어볼 수 있지 않을까?’ 라는 호기심이 들었고 그 생각을 며칠간 발전시켜 보았습니다.
그래서 오늘은 개발자가 문제 해결 과정에서 마주치는 어려움의 유형을 분석하고 각 어려움을 극복하는 방법에 대해 이야기해보려고 합니다. 이번 포스트를 통해 문제 해결 과정에서 어려움을 겪는 분 들께 도움이 되었으면 좋겠습니다. 참, 그리고 지금부터의 내용은 제 뇌피셜(…)이 많아서 사람에 따라 다르게 느끼는 내용이 있을 수 있다는 점을 미리 말씀드립니다.
TL;DR
제가 생각한 문제 해결 과정에서의 어려움의 유형과 판단 기준은 크게 세 가지입니다.
- 문제 그 자체의 복잡성이 높은 경우
- ‘하… 이걸 어떻게 구현해야 하지?’
- 문제 해결에 필요한 적절한 배경지식이 갖추어지지 않은 경우
- ’?? 이게 대체 무슨 용어지…?’
- 문제를 해결할 수 있는 방법이 여러 가지인 경우
- ‘이것 중에 뭘 골라야 잘 골랐다고 할 수 있을까…?’
문제 그 자체의 복잡성이 높은 경우
‘하… 이걸 어떻게 구현해야 하지?’
??? : 자, 여기 기획서 갖다 드리겠습니다
우리는 문제의 요구 조건을 살펴볼 때 그것이 복잡하다고 느끼는 경우가 종종 있습니다. 개발자에게는 이것이 기획서를 처음 읽는 순간이 될 수도 있고, 이미 개발 중인 프로젝트에서 새로운 요구 사항이 추가되었을 때가 될 수도 있겠네요.
문제 그 자체의 복잡성이 높다는 것은 곧 문제를 해결하기 위해서는 높은 수준의 추상화가 필요하다는 것을 의미합니다. 우리는 소프트웨어 개발에서 추상화라는 개념을 통해, 구현의 세부 사항은 숨기되 기능 제공에 초점을 맞추며 이를 통해 코드의 이해와 재사용성을 높이고 유지보수를 용이하게 할 수 있죠. 실세계의 복잡한 상황을 간결하고 명확하게 핵심 위주로 단순화시킴으로써 문제를 해결할 수 있게 되는 것입니다.
추상화 덕분에 우리는 저수준의 코드를 이해하거나 작성하지 않고도 제공되는 기능을 사용할 수 있습니다. 우리가 운영 체제에 대한 지식이 없더라도 Node.js API로 파일 입출력이 가능하게 하는 것부터 React의 커스텀 훅을 이용해 재사용 가능한 로직을 만드는 것까지요.
그런데 추상화를 적용한다고 해도 무조건적으로 문제를 간단하게 만들 수 있는 것은 아닙니다. 이해를 돕기 위해 지하철 노선도 예시를 들어보겠습니다.
지하철 노선도를 통해 우리가 해결하고자 하는 문제는 출발지에서 목적지에 도달하는 경로를 찾을 수 있는 지도를 제작하는 것 입니다.
1번 노선도는 실제 지형 지도에 노선을 표시했습니다. 현실과 가장 가깝긴 하지만, 지형이나 바다처럼 불필요한 정보가 들어있고 축척이 너무나도 크다 보니 글씨가 보이게 제작하려면 너무 큰 지면이 필요할 것입니다. 따라서 불필요한 정보는 제거하고 노선과 관련된 정보만 추출해 추상화를 거쳐 단순화한 노선도를 만들어야 합니다.
2번 노선도와 4번 노선도는 1번 노선도에 비교해 왜곡된 정보가 있습니다. 역간 거리가 실제와 다르고, 노선의 형태도 달라졌습니다. 하지만 출발지에서 목적지까지의 경로를 찾을 수 있고, 1번 노선도에 비해 훨씬 더 적은 지면을 차지하기 때문에 효율적인 추상화가 반영되었음을 알 수 있습니다. 4번 노선도는 2번 노선도에 비해 초록색 노선(2호선)을 중앙에 원형으로 배치해서 더 눈에 잘 띄게 만들었다는 점도 알 수 있습니다.
3번 노선도는 이전 노선도에 비해 더욱 추상화되었습니다. 글자가 생략되고 노선의 형태도 더욱 단순화되었기 때문에 보기에는 가장 편합니다. 하지만 우리는 이 노선도를 통해서는 지하철 경로를 찾을 수 없습니다. 복잡함을 제거하기 위한 추상화 과정에서 본래의 기능을 상실한다면 그것은 더 이상 의미 있는 추상화가 아니겠지요.
즉 추상화를 통해 복잡도를 줄이고 단순화를 할 수 있지만, 어떤 한계점 이하로는 추상화를 진행할 수 없다는 것입니다. 이러한 한계점을 넘어서면 추상화는 오히려 문제를 해결하는 데 방해가 될 수 있습니다.
추상화를 통해 문제의 복잡성을 줄일 수는 있지만, 그것이 항상 해결책이 되지는 않는다
위 예시를 통해 우리가 알 수 있는 점은 추상화를 통하더라도 문제의 복잡성을 해결하는 것에는 한계가 있다는 것입니다. 미국의 인지과학과 교수인 도널드 노먼(Don Norman)은 이를 두고 복잡함 보존의 법칙이라고 말했습니다.
1의 해결 방법
문제 해결에 영향을 주지 않는 요소는 배제하되, 작은 단위로 작업을 나누고 이를 조립하자
그렇다면 우리는 복잡도가 높은 문제를 어떻게 대해야 할까요? 복잡도가 높은 문제는 무조건 나쁜 것일까요? 그렇지는 않습니다. 사람들은 단순함을 외치면서도 복잡성이 제공하는 편리한 혜택을 포기하고 싶지 않아 하거든요. 핵심은 문제의 본질을 호도하는 혼란스러움을 문제로부터 분리하는 것입니다. 해결하고자 하는 문제를 올바르게 이해하고, 문제 해결에 영향을 주지 않는 선에서 불필요한 정보를 제거하며 문제를 단순화합니다.
혼란스러움이 분리하기 되었다면 문제를 작은 단위로 나눠가기 시작합니다. 문제를 나누었다면 가장 복잡도가 적은 문제부터 해결해 나가며, 작은 문제의 해결 방법을 찾았다면 추상화한 인터페이스로 제공합니다. 이 과정에서 테스트 코드를 작성할 수 있다면 TDD를 통해 문제를 해결하는 것이 더욱 효율적일 수 있습니다. 그 후에는 작은 문제들을 합쳐가며 전체 문제를 조금씩 해결해 나갑니다.
추상화는 곧 현실에서 우리가 겪는 문제를 해결하기 위한 도구입니다. 따라서 문제를 해결하기 위해서는 문제 상황을 올바르게 모델링하는 것이 중요한데, 이때 자료구조와 알고리즘, 그리고 디자인 패턴에 대한 지식이 갖추어져 있다면 문제를 빠르고 효율적으로 해결할 수 있습니다.
문제 해결에 필요한 적절한 배경지식이 갖추어지지 않은 경우
’?? 이게 대체 무슨 용어지…?’
문제의 복잡성은 높지 않지만, 문제 해결에 필요한 적절한 배경지식이 갖추어지지 않은 경우에도 어려움을 겪을 수 있습니다. 이는 도메인 지식이 부족한 상태 라고 할 수 있습니다. 여기서 도메인은 문제가 풀고자 하는 비즈니스의 영역일 수도 있고, 언어나 프레임워크, 라이브러리 등의 기술적인 영역일 수도 있습니다.
??? : 너 이거도 몰라?
우선 비즈니스 도메인입니다. 비즈니스 도메인에 대한 배경지식이 문제 해결에 영향을 특히 많이 주는 분야가 있는데, 금융과 의료, 법률, 교육 등이 그 예시입니다. 이러한 도메인에서는 우리가 일상생활에서 접하기 힘든 낯선 용어와 개념을 자주 사용하기 때문에, 개발자가 이러한 도메인에 대한 배경지식이 부족한 경우에는 어려움을 겪을 수 있습니다.
다음은 기술 도메인입니다. 기술적인 도메인 지식이 부족한 경우는 유사 경험이 있는지 없는지에 따라서도 서로 다른 어려움을 겪을 수 있습니다. 유사 경험이 없는 경우라면 ‘이게 대체 무슨 용어야?’ 와 같은 생소함을, 유사 경험이 있는 경우라면 ‘A에서는 이런 방법으로 해결했었는데, B에서는 그걸 어떻게 할 수 있지?’ 와 같은 혼란스러움을 겪을 수 있습니다.
- 프로그래밍 언어 관점
- ‘Node.js 를 처음 써보는데, 출력을 어떻게 해야 하지?’
- ‘Python에서는
sleep
함수로 코드 실행을 잠깐 중지할 수 있었는데, JavaScript에서는 안 되네?’- 프레임워크/라이브러리 관점
- ‘React에서 Props와 State의 차이가 뭐지?’
- ‘React에서는
useEffect
로 부수 효과를 처리하는데, Vue에서는 어떻게 하지?’- 인프라 관점
- ‘AWS 처음 공부하는데 EC2는 뭐고 S3는 뭐여’
- ‘AWS에 IAM 기능이 있었는데 GCP에서는 어떻게 사용하지?’
2의 해결 방법
일루와 봐, 형이 오늘 제대로 가르쳐준다
가장 좋은 방법은 도메인 지식에 대한 학습과 교육을 진행하는 것입니다. 아무래도 기술 도메인에 대한 지식은 개발자가 스스로 학습할 수 있는 범위가 넓기 때문에, 여유가 된다면 시간을 내서 학습하는 것이 중요합니다.
대표적으로 책이나 블로그, 유튜브, 온라인 강의 등을 통해 도메인 지식을 쌓을 수 있습니다. 만약 주변에 도움을 줄 수 있는 선배 개발자나 동료가 있다면 그들에게 도움을 요청할 수도 있구요. 없다고 해도 오픈소스 커뮤니티에서 도움을 받을 수도 있습니다.
이때 유사 경험이 없는 경우라면 차라리 책이나 강의, 문서처럼 잘 정리된 커리큘럼을 먼저 따라가 보는 것을 추천합니다. 방향을 정하지 않고 무작정 뛰어드는 학습과 질문은 비효율적일 수 있거든요.
반면 유사 경험이 있는 경우에는 기존의 배경 지식을 활용해서 프로젝트 경험을 빠르게 가져가는 것을 추천합니다. 이때 각 기술의 특징과 장단점을 비교해가며 학습한다면 내가 가지고 있는 지식을 더욱 확장할 수 있을 것입니다.
유사 경험은 많으면 많을수록 새로운 기술이나 도메인에 대한 학습을 빠르게 만들어주는 촉진제 역할을 할 수 있기 때문에, 새로운 기술이나 도메인에 대한 학습을 빠르게 진행하고 싶다면 다양한 프로젝트에 참여하거나 다양한 기술을 사용하는 것을 추천합니다.
다만 비즈니스 도메인 지식은 회사 외부에서 쉽게 얻을 수 없으므로, 사내에서 해당 분야의 전문가를 찾아 궁금한 점을 물어보고 이와 관련된 지식을 동료 개발자도 이해할 수 있게 문서화하고 공유하는 것이 필요합니다.
문제를 해결할 수 있는 방법이 여러 가지인 경우
‘이것 중에 뭘 골라야 잘 골랐다고 할 수 있을까…?’
마지막은 어떤 방법이 최선인지 판단하기 어려운 상황에서 반드시 선택을 내려야 하는 경우 입니다. 위의 두 가지는 문제 해결 방법을 찾는 과정에서의 어려움이었다면, 이번에는 발견한 해결 방법에서 선택을 하는 것에 대한 어려움이라는 점에서 성격이 다릅니다.
가장 대표적으로 기술 스택 선택이 있습니다. 새로운 프로젝트를 시작할 때 어떤 기술 스택을 선택해야 하는지 판단이 어려울 수 있습니다. 다양한 언어, 프레임워크, 라이브러리들이 존재하며, 각각의 장단점이 있기 때문입니다.
다른 예시로는 코드 컨벤션이 있습니다. 코드 컨벤션은 코드의 가독성과 유지보수성을 높이기 위한 목적으로 조직 내에서 통일한 규칙입니다. 하지만 어떤 코드 컨벤션을 선택해야 하는지를 판단하기는 쉽지 않죠. 개인이 선호하는 코드 스타일이나 팀의 코드 스타일, 또는 프로젝트의 특성에 따라 달라질 수 있거든요.
이처럼 정답이 정해져 있지 않다 보니, 논쟁이 가장 많이 발생하는 어려움이기도 합니다. 만약 나 혼자서 고민하는 것이라면 그냥 머리만 쥐어짜면서 고민하면 되겠지만, 팀과 회사 단위에서 고민을 해야 한다면 결국 모두가 만족하지 못하는 결정을 내리게 될 수도 있거든요.
3의 해결 방법
무조건 하나를 고르라고 하면, 가장 우선이 될 비교 기준을 정해보자
가장 애매한 상황이기 때문에 해결 방법이라고 제시를 하는 것도 가장 애매하네요. 어렵겠지만 결국 선택을 해야 하는 상황에서는 비교의 기준 간 우선순위를 정하는 것이 중요합니다.
가령 새로운 기술 스택을 도입할 때, 언어의 생태계나 커뮤니티, 채용 시장, 러닝 커브 등을 비교 기준으로 삼을 수 있겠죠. 이 기준들 중에서도 중요도 순으로 정렬을 해보고, 그중에서 가장 우선이 되는 기준을 세워야 할 것입니다.
일단 이런 상황에서 가장 일반적인 방법은 외부 레퍼런스를 참고하여 토론하는 것입니다. 다른 회사나 프로젝트, 커뮤니티에서 비슷한 상황에서 어떤 결정을 내렸는지를 참고할 수 있겠죠. 만약 팀 또는 주변에 시니어 개발자가 있다면 그들의 경험을 선택 기준으로 활용할 수도 있습니다.
한편으로는 각 선택지에 해당하는 방법을 직접 프로토타이핑 해보고 결과를 비교해 보는 것도 좋은 방법입니다. 사실 시간과 노력은 조금 더 걸리겠지만, 미처 개발 전까지는 몰랐던 장단점을 확실하게 파악할 수 있을 것입니다.
마치며
위와 같은 과정을 통해 개발자가 문제 해결 과정에서 겪는 어려움을 세 가지로 분류해 보았습니다. 각 어려움은 독립적으로 존재하는 것이 아니라 함께 존재할 수 있기 때문에, 여러 어려움이 중첩되는 상황을 만난다면 개인이 경험하는 불안감은 더욱 커질 것입니다. 이러한 경우에는 어려움의 유형을 하나씩 줄여나가는 것을 목표로 프로젝트를 진행할 수 있겠죠.
사실 해결 방법으로 제시한 것들 역시 다소 추상적인 개념이라 실질적인 해결책이 되지 못할 수도 있겠지만, 내가 어떤 유형의 어려움에 빠져있는지를 파악하고 다른 동료에게 진행 상황을 공유할 때 도움이 될 수 있을 것입니다. 다른 누군가가 내 어려움을 이해하고 있다면 적절한 도움을 받을 수도 있을 것이구요.