프론트엔드에 가까운 개발자로 2년에 가깝게 일을 하고, 백엔드 개발자 경력직에 도전 중이다. 모 기업 과제를 일주일 동안 진행하며 느낀점들을 간단하게 회고해보고자 한다.
과제에 대한 대응이라 썼지만, 일반적인 프로그램 작성에서도 생각해 볼 수 있는 내용일 것 같다.
무엇을 묻는지 아는 것이 중요하다. 왜냐하면, 프로그램에는 절대적 정답이란 것이 존재하지 않기 때문이다. 정답이라고 부를 수 있는 건 현재 상황에서 가장 사용하기 좋은 것일 뿐이다.
이런 점에서 상황에 대한 디테일한 이해가 선행되어야 한다. 디테일한 이해란 여러가지 사항을 포함할 수 있다. 누가 쓸건지, 어느 정도의 규모로 사용할건지, 요구하는 입출력 형식이 있는지 등. 이 과정에서는 소통이 중요하다. 과제에 대한 이해도는 이 문제를 발견하거나 만든사람이 더 높으므로, 이해가 안되는 부분들은 부끄러워 말고 적극적으로 물어보자.
개인적으로 Operating Systems: Three Easy Pieces 라는 책의 서술 방식을 좋아한다. 책에서는 목적과 메커니즘을 명확하게 분리하고 있다. 예를 들어, 프로그램의 진행 상태를 저장하기 위한 목적이 있다면, 그것의 메커니즘은 레지스터나 메모리를 활용하는 것이다.
시분할 시스템을 만들어서 여러개의 작업을 하나의 컴퓨터에서 진행할 수 있는 상태가 목적이라면 그것의 메커니즘은 context switching 일 것이다.
목적은 한단어로 집약적으로 정리하면 좋은것 같다. 이 프로그램이 대량의 데이터를 단 시간내에 처리하는 것이 목적이라면, 방점은 시간 효율성에 잡혀 있어야 한다. 그런것이 아니라 무조건 정확한 솔루션이면 된다하면 정확성에 무게를 둔 방식도 좋다.
이렇게 단순한 목적성 정의가 중요한 이유는 그것이 명확하면 명확할 수록 메커니즘의 구성이 쉬워지기 때문이다. 시간 효율성을 만족하기 위해서는 단순히 정확하기만한 메커니즘을 고려하지는 않을 것이다. 부정확한 솔루션을 여러개 레이어링을 해서 시간을 단축하거나 short circuit 과 같은 메커니즘도 이용해 볼 수 있을 것이다.
여기서 코드 복잡성을 줄이는 목적이 추가된다면, 단순히 컴퓨팅 자원을 추가하는 메커니즘도 고려해볼만 하다.
정확성에 무게를 둔 솔루션이라면, 효율성에 복잡한 솔루션을 넣을 필요는 줄어든다. 여기서 중요해지는 것은 오히려 면밀함이다. 정확함이라는 것은 예외상황을 최대한 많이 생각해내는 것이라고도 볼 수 있다. 어떤 오류 케이스 들이 발생할 수 있는지, 각 케이스는 전체에서 어느 정도 분량을 차지 할 지를 가늠해보고, 가장 해결가능한 것부터 출발해서 정확성을 합리적으로 올려가는 것이 좋다.
목적에 따라 적용할 메커니즘을 조사하는 단계이다. 방대한 자료에 길을 잃지 않게, 이 솔루션이 어떤 목적에 대응하는 것인지 정리하며 읽는 것이 도움이 된다.
개인적으로는, ChatGPT 와 같은 대화형 인공지능이 이 부분에서 많은 도움이 된다고 생각한다. 각 솔루션의 구체적 메커니즘을 알지 못해도 대화를 하며 목적과 한계에 대해서 빠르게 짚어 볼 수 있다.
이제 메커니즘을 어떤 순서로 적용할지 정하는 단계이다.
여기서 핵심은 해결 가능성이 높은 작업들을 먼저 하는 것에 있다. good is better than perfect 라는 자세가 상당히 중요해진다.
대부분의 프로그램에서 그다지 아름답거나 훌륭하지는 않아도, 요구사항을 만족할 수 있는 단계가 반드시 존재한다. 아름답거나 훌륭하지 않다는것은 보기 흉물스럽다는 것과는 다르다. 단순하고 정확도가 높지 않은 가정에 기반하고 있지만, 단순하기 때문이다.
단순함이 프로그램에서 좋은 이유는 구현하기 쉽고 이해하기 쉬우며 고치기 쉽다는 것이다. 그래서 마음을 비우고 가장 해결가능성이 높은 전략부터 수행하는 것이 좋다.
간혹 어려운 예외 사항에 꽂혀서 이 부분을 과도하게 생각하고 솔루션을 생각하는데 시간을 오래 보내는 경우가 있다. 납득은 되지만, 이런 시간 소모가 좋은 결과로 이어지는 경우는 드물다.
하지만, 늘 지키기 어려운 일이라 마음에 새기면 좋을 것 같다. 특히, 너무 잘하고 싶은 마음이 큰 경우나 중요한 과제인 경우에 이런 경향이 심해진다.
이럴때는 주변에 도움을 청하고, 자문을 구하는 것이 좋다. 꼭 누군가 답을 준다기 보다, 스스로의 행동을 객관화 하는데에 도움을 주기 때문이다.
가능하면 알고있는 가장 상위 수준의 언어로 솔루션을 빠르게 작성해 보는 것을 권장한다. 저수준의 언어를 사용하는 경우, 언어에 대한 숙련도가 높은 경우라도, 언어 자체나 구현 자체에 대해 처리하는 연산이 늘어난다.
여기에 두뇌 자원을 이용하게 되면, 주된 과제 해결에 쓰는 에너지가 줄어들게 되고, 이것이 결국 좋지 못한 솔루션으로 이어지게 된다.
따라서, 가능하면 고수준 언어로 목적을 명확하게 하면서 구현을 해보는 것이 아주 큰 도움이 된다.
구현에서 중요한 것은 적절한 피드백 환경이다. 내가 잘하고 있는지가 끊임없이 피드백 되는 환경이 가장 좋다. 가능하면 테스트가 항상 돌고 있는 상태를 만드는게 좋고, 결과물이 계속해서 보여지는 것도 좋다.
'피드백이 잘되는 것이 좋다'라는 점에서 착안하면, 적절한 행동의 크기도 자연스럽게 설정이 된다. 보통은 작으면 작을 수록 좋다. 큰 과제는 단순한 과제의 합에 불과하므로, 뭔가 복잡하다면 주석으로 적어보자. 주석에 대해서 각 과정을 설계해보고 테스트등을 통해 피드백 고리를 만들어보자.
마무리 단계에서 중요한 것은 전달이다. 내 솔루션의 장점과 한계 사항을 명확히 전달하고, 가장 사용하기 쉬운 형태로 전달해야 한다.
이때, 컨테이너 기술을 알고 있다면 상당히 도움이 된다. 어떤 환경이든 실행 가능한 솔루션이 되기 때문에 전달에 도움이 된다. 공개가 가능한 경우라면 GitHub 와 같은 호스팅을 이용해서, 코드 자체를 전달하는 것이 좋고, 작동 방법에 대한 설명을 최대한 자세하고 친절하게 적는 것이 좋다.