2020-09-09

제 코드에 문제가 있어요! 도와주세요!




파이썬 커뮤니티에선 맞닥뜨린 문제로 인해 고통받는 영혼들의 울음소리가 끊이질 않는다. 대개 코딩 좀 할 줄 안다는 사람들은 이미 현업에서 뛰고 있다 보니 바빠서 답변을 해주지 못할 수도 있겠다. 그래서 파이썬 중급자를 자처하는 난 그들의 문제를 함께 마주보고 해결해주기 위해 부단히 노력한다. 봉사정신을 키우고 싶어서 그렇게 행동한다기보단 (나도 그렇게 시간 남아도는 사람이 아니거니와, 그렇게 착해빠진 사람도 아니다) 나도 처음 보는 그 문제를 통해 더 많은 문제를 접하고 해결해나갈 방법을 고민할 기회를 얻는다는 데에 더 큰 의의를 두고 있다. 실제로 다른 사람의 문제를 함께 고민하는 것은 나의 실력 향상에 많은 도움이 되었다. 그래도 딴에는 중급자라고, 그들의 코드를 보면 한숨이 나오곤 한다.

왜 코드를 이렇게 짰지…?’

분명히 바퀴가 4개 달려있는 자동차는 맞는데 바퀴 두개는 아래에, 나머지 두개는 천장에 달려있다. 그래놓곤 이 자동차가 왜 멀쩡하게 다른 자동차들처럼 굴러가지 않느냐고 묻는다. 이쯤 되면 커뮤니티의 사람들은 이렇게 반응한다.

구글에 자동차를 검색해서 어떻게 생겼는지 보고 오세요

이는 운송수단인 자동차가 보편적으로 어떤 골격을 가지고 있는지를 보고 배우라는 의미이다. 프로그래밍 언어들은 자신만의 자료형과 문법을 가지고 있다. 문자열, 정수, 실수, 리스트, 배열 등등 어느 언어에서나 자주 사용되는 자료형은 대개 특징들이 비슷하고 문법도 비슷하다. 문법도 마찬가지다. 연산자, 반복문(while문 포함), if, try/except, 함수의 결과값 반환 등 프로그래밍 언어에게 지시하는 방법도 어느정도 효율적인 방식이 정립되어 있다. ~고급 사용자들은 이미 키보드를 쳐볼 만큼 쳐봤기 때문에 기본적인 사용법은 숙지하고 있다. 하지만 초보자들은 이제 막 배우는 단계이기 때문에 프로그래밍 언어들이 이러한 명령문들의 흐름으로 이루어져 있다는 개념 자체를 배우는 것만으로도 머리에 과부하가 걸릴 것이다. 그 막막함은 나도 이해한다, 나도 새로운 무언가를 배울 때마다 느끼는 감정이니까.
많은 중~고급자들은 힘들어하는 초보자들의 이상한 자동차를 당장 굴러가는 자동차로 수정해주려는 경향이 있다. 그래서 그들이 수정해준 코드는 다음과 같다.


바퀴가 부족하니까 안 굴러가죠. 바퀴 4개가 땅바닥에 붙어있어야 굴러가죠.’

틀린 말은 아니다. 바퀴 수가 불필요하게 많아졌지만 아무튼 굴러간다. 심지어 이 수정된 자동차는 무려 천장으로 달릴 수도 있다(!). 중력이 거꾸로 된 세계(거꾸로 된 파테마)에서도 문제없이 운행 가능하다.
그런데 질문자는 이제와서 다음과 같은 요구사항을 추가하게 된다.

이거 사실 정글에서 쓰일 이동수단이었거든요. 이 자동차는 제 목적과 부합하지 않아요.’

미치고 팔짝 뛸 노릇이다. 애초에 그런 목적이었더라면 자동차가 아니라 궤도전차를 구상했을 것이다. 그제서야 질문자의 자동차 디자인에 조금 납득이 가기 시작한다. 천장에 달아놓은 바퀴는 그저 덩굴을 헤쳐나가고 싶은데 마땅한 디자인을 만들 여력이 없어서 이렇게 만들었겠거니도달해야 할 목적지가 설산 꼭대기라면 스노우 모빌을, 해변이었다면 수륙양용 호버크래프트를, 하이퍼루프였다면 자기부상열차를 디자인했을 것이다.
이렇게 조용히 디자인을 상상하던 내게 질문자는 또다시 놀라운 조건 하나를 추가하게 된다.

정글의 산에 터널을 뚫을 이동수단이 필요해요

그가 필요했던 것은 TBM이었다.


아예 처음부터 뜯어고쳐야 했던 것이다. 기존의 코드를 수정하는 수준이 아니라 더 나은 (다른) 틀을 가져와서 내 목적에 맞게 개조해야 했던 것이었다. 이제야 질문자가 처음에 프로토타입으로 만들었던 자동차(?)가 왜 그런 모양이었는지를 깨닫는다.

이 과정에서 가장 핵심은 질문자가 만드려는 코드의 목적이었다. 어째서 이 코드가 필요한가, 이 코드가 궁극적으로 수행할 작업은 무엇인가, 그로 하여금 어떤 결과를 얻길 바라는가. 이러한 질문을 스스로에게 던져보고, 그 질문으로 검색을 해봐야 하며, 거기서도 답을 찾지 못했을 경우엔 창피해하지 말고 숙련자에게 질문해야 한다. 질문할 때엔 자신이 이런이런 목적으로 디자인했고, 원하는 결과물은 저런저런 모양이었는데, 그런그런 문제들이 터져서 고생했다는 식으로 자신의 상황을 적극적으로 알려야 한다.
코드를 직접 작성하지 않아도 되는 경우가 굉장히 많다. 팩토리얼(factorial)을 구하는 방법, 소수를 구하는 방법, n개의 요소를 갖고 있는 집합에서 조합 가능한 순열을 구하는 방법 등이 이미 사용 가능한 함수형 라이브러리로 제공되고 있다. 이러한 라이브러리들은 간편하고, 빠르고, 효율적이기까지 하며 검증도 완료되어 있다. 물론 공부를 하는 입장에서는 알고리즘을 직접 짜보는 연습을 해보는 편을 추천하고 있지만, 당장 발등에 불 떨어져서 결과를 만들어내야 한다거나 혹은 일반인으로서(비전문가로서) 깊게 파고들기엔 귀찮고 그냥 이런 기능을 하는 라이브러리가 있구나 하는 수준으로 넘어가고 싶은 사람들은 그 수준에서 사용해도 무방하다. 그걸 다 파고들어 공부하기엔 학습량이 기하급수적으로 늘어나거니와, 이걸로 논문을 쓸 생각이 아니라면 이 정도로 사용하는 것이 바람직하기도 하다. 프로그래밍 격언 중엔 이런 말이 있다: 바퀴를 재발명하지 마라(Don't reinvent thewheel)’ 그 라이브러리에 대한 이해는 필요하되, 그걸 내 손으로 만들어내기 위해 고생할 필요는 없다. 있으면 가져다 쓰자.
하지만 라이브러리가 모든 기능을 전부 수행해주는 것은 아니다. 자동차에 탑승했다고 알아서 목적지까지 데려다주던가? (자율주행차 얘기는 지금 하지 말자…) 시동을 걸고, 이리저리 핸들을 돌리고, 감가속을 하고, 다른 차량들과 경쟁(?)해서 살아남아야 비로소 목적적에 도착할 수 있다. 이러한 과정은 코딩에서도 마찬가지이다. 이 라이브러리를 여기에 배치하고, 저런 옵션을 주고, 디버깅을 해서 원치 않는 작동을 차단해야 목적을 이룰 수 있다. 이를 위해 운전자는 운전 스킬(코딩 스킬)을 숙달해야만 한다. 이는 결국 투자한 시간, 즉 경험으로 인해 노하우가 늘게 된다.

저와는 다르게 뚝딱뚝딱 검색해서 바로 해결하시는거 보고 대단하다고 생각했어요

목적이 명확하다면 해당 질문을 구글에 집어넣어 검색해보는 것만으로도 답이 나오는 경우가 많다. 내가 마주한 문제가 이 세상에서 유일한 문제일 가능성은 매우 희박하다. 이미 많은 사람들이 겪어보고 해결해나간 문제일 가능성이 높다. 코딩 능력의 절반은 검색 능력이라는 말이 있을 정도로 구글링은 높은 중요성을 갖는다. 다만, 질문을 영어로 해야 한다. 이 부분에 대해서도 할 말이 많지만, 내 수면시간이 부족한 관계로생략한다. 한국어로 검색해도 많은 자료들이 나오긴 한다. 기초적인 수준(예를 들어서, 반복문을 어떻게 쓰는지 모르겠다거나 등등)의 질문이라면 우리말로 잘 정리된 강좌들을 찾아보는 편이 훨씬 도움이 된다. 그러나 문제의 특이성(Specificity)이 높다면 한국어로 검색해서 해답을 찾을 가능성이 낮다. 그럴 땐 영어 실력이 부족하다고 포기하지 말고, 번역기라도 돌려서 영어로 검색하는 습관을 들이는 편이 좋다.

모른다는 사실조차 모르고 있는 상태에서 질문하기

고급 사용자들에게 질문을 던지면 대개 추상적이고 이해하기 힘든 단어들이 나열된 답변을 받게 된다. 그것은 어쩌면 내가 모른다는 것조차도 모르는 미지의 영역일지도 모른다. 나는 네트워크맵을 만들면서 다음과 같은 문제에 직면한 적이 있었다. 네트워크의 구성원이 될 노드는 사람들의 아이디가 된다. 각 노드를 연결할 엣지의 두께는 두 사람 사이에서 얼만큼 활발한 교류가 있었는지에 따라 결정된다. 그래서 그 교류가 많을수록 해당 노드의 크기도 크게 그린다. 내가 가진 raw data는 각각의 아이디가 어떤 활동을 했는지에 대한 정보이고, 같은 활동을 한 다른 아이디를 찾아낸 뒤 그 정보를 이용해 노드의 크기를 결정해야 했다. 그래서 구성원들 사이에 조합 가능한 순열을 얻어야 했는데, 이걸 알고리즘으로 구현하려니 머리가 지끈거리기 시작했다. 그래서 위의 상황을 설명하는 것 대신에 보다 문제를 간결하게 추상화하여 아래와 같이 질문했다.


리스트 ['A', 'B', 'C']가 주어질 때, 두 개로 가능한 모든 조합 ['AB', 'AC', 'BC']의 형태로 반환하는 함수를 짜려고 하는데, 뭐라고 검색하면 좋을까요?
파이썬에서는 itertools 패키지에 combinationspermutation 함수가 위의 연산을 수행해준다. 한국어로 질문도 던졌고, 영어로도 ‘combinations’이라는 단어를 떠올리지 못해서 ‘find all possible pair in list’처럼 검색했다. 그리고 나오는 결과를 닥치는 대로 읽어 내려갔다. 결국 질문해놓고 자문자답했다.
특정 수준에 이르게 되면 (특이점이 오면) 더 이상 커뮤니티에 질문을 올리지 않게 된다. 질문을 해도 답변이 돌아오지 못할 것이라 추측하기 때문이다. 그렇게 되는 몇 가지 경우들이 있다. 첫째, 프로젝트의 규모가 커지고 복잡도가 올라가면서 해당 코드의 쓰임새를 온전히 이해하는 사람이 본인 뿐인 경우이다. , 머릿속의 아이디어를 구체화할 주체가 다름아닌 본인일 경우이다. 다른 누군가에게 자신의 아이디어를 구체적으로 (아주아주 구체적으로) 설명해줄 수 있는 수준이 되면, 다른 누군가에게 맡기는 것보다 자신이 진행하는 편이 더 효과적이다. 둘째, 해결하려는 문제가 지나치게 어려운 경우. 아무리 고수들이 모인 커뮤니티라 하더라도 해결하기 쉽지 않은 문제들은 두루 있기 마련이다. 이런 문제들에 대해 고수들이 추상화된 답변을 해줄 수는 있을지언정 해당 문제 자체를 해결할 수 있도록 도와줄 수는 없다. 그 사람도 모르니까 배운 다음에 대답해줘야 할텐데, 그 정도로 친절한 사람은 이미 어딘가에 불려가서 남의 일을 도와주고 있다. 지나치게 고수준의 지식이 요구되는 질문은 답변자가 등장하지 않을 수도 있다. 이럴 때에는 본인이 공부해서 다른 이들에게 지식을 전파해주도록 하자. 셋째, 너무 많은 시간이 드는 경우. 해결 방법은 알겠는데, 그걸 해결하기 위해 투자해야 할 시간이 길게 예상되는 경우이다. 벽돌깨기 게임에 공 하나를 주고 벽돌 10만개 깨라고 하면 어떤 반응을 보여줘야 할지 상상해보자. ‘이건 외주를 맡겨야지 왜 나한테 도와달라고 하는거야라는 반응을 보이고 싶을 것이다.

숙련자들도 결국 그만큼 시간과 공을 들여서 도달한 경지일 것이다. 초보자들도 시간을 들이면 언젠가는 고수준의 코딩을 할 수 있다. 물방울로 바위를 뚫는다는 마음가짐으로 정직하고 꾸준하게 접근해보자. ‘와 어떻게 저렇게 쭉쭉 진행할 수가 있지라며 나의 존경심을 받는 그 사람, 아마 모르긴 몰라도 해당 작업에 익숙해지기 위해 많은 시간을 소비했으리라.

댓글 없음:

댓글 쓰기