0. 들어가기 전에
•
문제해결(요구사항 구현)은 개발자들의 숙명이다. 아니, 과장을 조금 보태서 말해보면 문제 해결은 개발자 존재 자체의 근간이며 이유이다.
•
이와 같이 개발자의 근간이 되는 문제해결 방법에 대한 선택은 다양하다. 실제 업무에선 “이상적인 방법으로 해결되는 경우”는 흔치 않으며 대부분 조직내 제한사항으로 인해 “타협된 방법”으로 해결되는 경우도 많을것이다. 더 나아가서는 급한 PROD 이슈 해결을 위해 “잘못됐지만 돌아만 가는 코드를 사용하는 방법”을 사용할 수 도 있을것이다.
•
필자는 이 문제해결의 방법에 대한 고민, 고찰을 이야기해보려 한다. 이글에서는 문제 해결법은 어떻게 구분되는지, 어떤게 문제해결법이고 어떤게 문제해결법이 아닌지를 다뤄본다
1. 해결법의 종류
•
필자는 해결법은 “해결법”이라는 단어 하나로 해당하는 해결법의 성격을 충분히 설명할 수 없다고 생각한다. 문제의 해결 방법에는 여러가지 성격과 색깔을 가지고 있으며 그로인해 해결법을 크게 3가지로 나누었다.
1.
성능, 유지보수성, 가독성, 확장성 등을 고려한 최적의, 이상적인 해결법
2.
이상적인 해결법을 구현할 수 없는 상황에 최대한 성능, 유지보수성, 가독성, 확장성 등을 고려한 해결법
3.
Deprecated 된 API 사용 또는 비효율적인 알고리즘을 사용하여 문제의 “해결” 그 자체에만 집중한 해결법
•
필자는 위 세 가지 해결법은 이상적인 해결법(Ideal Solutions), 타협(절충)된 해결법(Compromised Solutions), 이상적이지 않은 해결법(Non-ideal Solutions) 세 가지로 명명했다.
•
우측에 잘 보이지 않는 Noise Cacelling은 해결법이 아니다.
2. 이상적인 해결법 (Ideal Solutions)
성능, 유지보수성, 가독성, 확장성 등을 고려한 최적의 이상적인 해결법으로, 패키지의 경우 메인테이너가 의도한 방법대로 해결한 방법
이상적인 해결법의 기준
•
이상적인 해결법의 기준은 개발자마다 편차가 심하다. 그도 당연할 게 개발자, 속한 그룹마다 “이상”이라는 코드의 기준이 매우 다르기 때문이다.
•
예를 들어 설명해 보겠다. 성능을 좀 감수하더라도 코드의 가독성을 위해 컴포넌트를 나누지 않는 상황이 있다. 컴포넌트를 나눈다고 무조건적으로 성능이 좋아지는 건 아니지만, 컴포넌트를 나누고 memoizing을 해야 성능이 개선되는 경우가 있다. 이때 그 memoizing조차 두 개의 차이점이 존재한다. 첫 렌더링에서 느리고 그 후 리렌더링 때 더 빠를 것이냐? 첫 렌더링에서 느리고 그 후 리렌더링 때 더 빠를 것이냐?
•
이때 의견은 두 개로 나뉠 수 있다. 필자는 두 개의 의견 모두 “이상적인 해결법”이라고 생각한다.
◦
“당연히 가독성보다 실제 유저들이 느끼는 성능이 더 중요하지. 첫 렌더링에 조금의 시간을 희생해도 이용자들은 첫 로드 후 해당 페이지에서 체류하는 시간이 훨씬 더 기니까 그 후의 성능을 신경 쓰는 게 맞아!”
◦
“여기서 성능을 위해 가독성을 해쳐서 코드를 이해하기 어렵게 만드는 게 더 잘못된 선택이 아닐까? 심지어 컴포넌트를 나눈다고 해도 그 차이는 유저가 절대 느낄 수 없는 10ms도 안 되는 차이이잖아.”
•
이와 같이 이상적인 해결법의 기준은 절대적이지 않고 매우 상대적이며 주관적이다. 절대적인 정답이 없으므로 구성원들에게 “내가 맞다고 생각하는 이유”를 설득해야 하며 구성원들이 “그들이 맞다고 생각하는 이유”를 설명할 때도 “내가 틀릴 수 있다”라는 자세로 받아들여야 한다. 모든 사람들은 각자 “중요하다”라고 생각하는 기준이 다르기 때문이다.
•
아래는 이상적인 해결법의 “주관적 성격을 띄는 특징들”의 일부분 이다. “주관적인 성격을 띄는 특징들”은 “절대적인 기준”이 아니며 “절대적일 수 없다.”
◦
가독성이 좋다.
◦
확장성이 좋다.
◦
유지보수성이 좋다.
◦
테스트하기 좋다.
◦
다른 선택지에 비해 Noticable하게 성능이 좋다.
3. 타협된(절충된) 해결법 (Compromised Solutions)
마주친 이슈에대하여 이상적인 해결법이 존재하지 않는 상황에서 최대한 성능, 유지보수성, 가독성, 확장성을 고려한 문제의 해결법
•
말그대로 타협, 절충한 해결법이다. 패키지로 예를 들자면 해당 패키지에 마주친 이슈, 요구사항에 대해 직접적인 해결법이 없을때 채택하는 해결법이 될 수 있다.
•
꼭 이상적인 해결법이 존재하지 않아도 상황적인 이유로 인해 선택적으로 타협된 해결법을 채택 할 수도 있다.
◦
실생활 예를 들어보자. 지금 필자가 사용하는 패키지에서 이상적인 해결법을 선택하기 위해서는 업그레이드를 해야하는데, 해당 패키지를 업데이트하면 현 개발환경에서 다른 패키지들은 호환되지 않아 많은 시간이 든다. 시간이 충분하다면 물론 모든 패키지를 업데이트하고 변경된 사항들을 적용하면 좋겠지만, 그렇지 않은 경우가 대다수 이다.
•
해당 방법으로 해결한 이슈나 요구사항은 지속적으로 추적 및 관리해야하며 본인 환경에서의(사용하는 패키지나 환경의 업데이트 e.g. browser API의 업데이트) 변화가 있을 경우 타협된 해결법으로 해결된 문제들을 이상적인 해결법으로 해결할 수 있다.
4. 잘못된 해결법(Non-ideal Solutions)
해결법 중 이상적인 해결법, 타협된 해결법 그 어디에도 속하지않는 해결법
•
이상적인 해결법도 존재하지 않는 상황에서 타협된 해결법에 해당되지 않고 빠른 패치 또는 “돌아가는 코드”를 집중한 해결법으로 주로 개발자의 Capacity로 인해 채택 되거나 또는 “최대한 빨리 대응”하기 위해 채택하는 방법이다.
5. 소음 죽이기 (Noise Cancelling)
에러를 그냥 죽이는 행위개발환경, 사용하는 패키지 그리고 개발언어에 대해 적절한 이해없이 또는 문제의 근원에 대한 파악없이
•
소음 죽이기는 문제를 해결하는 행위가 아닌 문제를 없애는 행위이다. 문제에 대한 이해가 우선되지 않고 LLM이나 웹에 떠돌아다니는 해결법만 적용하는 방법이다.
•
필자는 문제를 없애는 행위 자체는 모두가 할 수 있다고 생각한다. 특히 요즘과 같은 LLM 시대에는 구글과 같은 검색 엔진의 시대 때 보다 훨씬 더 쉽다 생각한다.
•
이런 해결법을 적용한 경우 높은 확률로 추후에 같은 이유 또는 비슷한 이유로 개발자를 괴롭힌다. 간단하게만 봐도 무조건 적으로 피해야 하는 문제해결법 중 하나이다.
해결법과 소음 죽이기의 차이
•
해결법과 소음 죽이기의 차이점은 문제의 원인에 대한 파악의 여부에 따라 구분 할 수 있다.
6. 해결법 구분의 제약사항
기술적 이해도 전제
•
위의 이상적인 해결법, 타협된 해결법, 비이상적인 해결법을 구분지을때는 구분짓는 개인의 평균이상의 기술적 이해도가 전제되어야한다. 최소한 자신이 사용하는 패키지, 개발환경 또는 언어에 대한 이해도가 필요하며 그 이상 넘어가 내부 동작방식까지 파악하고 이해할 수 있어야 각 해결 법의 기준을 결정 지을 수 있기 때문이다.
•
평균 이상의 이해도가 전제되지 않는다면 위의 해결법을 나누는건 사실상 불가능하다. 아니, 오히려 피해야할 구분법이다. “우물 안의 개구리” 패러독스에 갖혀 “이 방법이 최고야!”라는 망상에 빠질 수 있기 때문이다.
◦
필자도 물론 우물안의 개구리 패러독스에 종종 갖힐때가 있다. 다만 이제는 자기 객관화가 이전보다는 더 가능하여 우물안의 개구리 패러독스에 갖혀도 이전과 비교했을때 비교적 떠 빨리 빠져나올 수 있다.
절대적인 구분은 불가능하다
•
이전 단락에서도 많이 언급했지만 다시 언급해도 절대 모자라지 않는 부분이다. 개개인의 기준은 절대적일 수 없다. 매우 주관적이며 일시적이다. 하다못해 AI도 프롬프트, AI 에이전트에 따라 전혀 다른 “기준”을 적용하여 답을 해주는데 어떻게 수많은 변수, 서로 전혀 다른 삶을 살아온 서로다른 개인들이 같은 기준을 가질 수 있겠는가? 우리는 서로를 이해하려 노력해야한다. 개발자들이 서로를 이해해주지않으면 대체 누가 개발자들을 이해해줄 수 있겠는가.
•
위 이유의 연장선으로 “개인마다 다른 기준”으로 인해 필연적으로 아래와 같은 Gray zone들이 생겨난다. 표현상 한계로 인해 작게 표현했지만 각자의 기준에 따라 이 Gray zone은 더 커질 수 있으므로 서로간 기준의 간극을 메꾸는 노력도 많이 필요하다.
이상적인 해결법은 이상적이다
•
본인을 포함한 많은 개발자들이 범하는 실수 중 하나가 이상적인 해결법으로 문제해결하기 위하여 많은 노력을 한다는것이다. 이전 블로그 포스트에도 몇번 언급했지만 우리는 고용주에게 결과물을 제공할 의무가 있는, 돈받고 일하는 개발자이다. 모든 문제를 이상적인 해결법으로 해결하면 좋겠지만 모든 업무에는 Due Date가 존재하며 내가(대부분의 기능개발 업무에 마지막을 담당하므로 특히 Front-end 개발자에겐 더욱더 중요하다.) 늦어질경우 배포까지 늦어지므로 이 사실을 꼭 기억해야한다.
•
물론 필자는 “적당히 하자”를 말하는게 아니다. 필자 본인의 좌우명 중 하나가 “완벽이란 도달할 수 없는 이상임을 자각하며 그 완벽을 추구하자”이다. 이 뜻을 설명하기위해 좋은 단어가있는데 바로 “유토피아(Utopia)”이다. 고대 그리스어에서 유래한 이 단어는 모두가 알고있는 단어이며 많은사람이 그 뜻을 알고 있겠지만 고대그리스어로는 “존재하지 않는 곳”이다. 맞다. 이상향은 존재하지 않는곳이다. 그러나 “존재하지 않는다”라는 명확한 이해와 함께 이상향을 쫓는다면 적절한 타협과 그 타협에 따른 최선의 선택을 할 수 있다고 생각한다. 우리 모두 이런 자세를 가진다면 각박한 개발팀에 한줄기의 빛이 될 수 있지 않을까?
•
문제해결 시 이상적인 해결법을 쫓는게 아니라 “이상적인 해결법을 추구하며 비 이상적인 해결법을 최대한 피하는걸” 목표로 개발을 하는게 우리 개발자가 현실적으로 이룰 수 있는 이상향이라고 생각한다.
•
Web Frontend에 예를 들자면 사실상 이상적인 해결법의 한계를 잘 알아야한다. 하위호환성을 위해 존재하는 수많은 Paradox, OS/브라우저/브라우저 버전/ 기기 성능, 과 같이 심각하게 나뉘어진 환경 과 같은 환경적인 한계가 존재 하므로 애초에 달성하기 쉽지 않은 목표이기 때문이다.
7. 문제해결에 LLM 사용
•
필자는 LLM사용이 나쁘지 않다고 생각한다. LLM의 사용이 나쁘다는 말이 하고싶다는게 아니다.
•
위에 언급했듯이 LLM 시대에는 “그럴싸한” 정보를 찾기 쉬워지며 인간들은 더 나태해졌다. 쉽게 정보를 얻고 검증 없이 쉽게 사용하는 시대가 되어버렸다.
•
•
경험이 많이 없었을때는 “문제를 없애기” (또는 소음 죽이기)에 급했다. 그래도 나름 경험이란게 쌓이다 보니 문제 없애기에 더 이상 긴 시간을 쓰지않게 되며 저절로 “이상 적인더이상 소음죽이기가 아닌 더 나아가 “이상적인 해결”에 집
8. 혼자서 되묻기
모두 이상적인 해결법인 상황
•
React 사용 개발자의 예시로 들자면 DOM 변경 시 useState/useRef 사용과 같은 상황을 “모두 이상적인 해결법인 상황”이라고 부를 수 있다. 말그대로 “모두(둘다) 해결법인 상황”이기 때문이다.
◦
당연히 React, Frontend Ecosystem에 이해도가 높은 독자들이라면 둘 중 선택하기가 아주 쉽고 어디서 뭘 써야할지 잘알겠지만 useState/useRef는 예시이므로 본인이 “뭐가 옳은 선택인지” 몰랐던 과거의 자신이라고 생각하고 글을 마저 읽으면 이해하기가 쉽다. 쉽게 말하자면 “뭐가 옳은지 모른다”라고 가정하고 글을 읽어주길 부탁한다. 그게 정 힘들다면 요즘 본인이 겪고 있는 “모두 해결법인 상황”을 대입하여 글을 읽어도 좋다.
이상적인 해결법
•
개인적으로 “모두 해결법인 상황”은 항상 필자를 지치게한다. 항상 올바른 선택을 하고싶다는 강박이라 할까? GPT한테 물어보면 되잖아! 라고 할 수 있지만 글을 작성하는 현재 기준 LLM들은 아래와 같은 이유때문에 “이상적인 해결법”을 제대로 답할 수 없다.
◦
프롬프트에 따라 전혀다른 대답
◦
모든 컨텍스트를 파악할 수 없는 능력
•
1. 사용중인 (사용 예정인) 패키지 이해의 필요성의 예시로 들었던 DOM 변경 시 useState/useRef 사용 과 같이 “애매한” 부분에 대한 의사결정을 위해서는 명확한 이해가 선행되어야한다.
•
본인은 명확한 이해를위해서 “혼자서 되묻기”라는 방법을 사용한다. “비판적으로 질문하는 나”와 “대답하는 나” 둘이서 롤플레이를 하는것이다. (지금 이 글을 쓰는 본인조차 제정신이 아닌거 같다 라는 생각이 조금씩 들긴한다. Please bare with me)




