이건 깔끔한 코드에 대한 얘기가 아니다. 깔끔한 행위에 대한 것이다. 어떻게 하면 '깔끔하게 프로그래밍' 할 수 있을까? 어떻게 하면 '삽질'을 하지 않을 수 있을까?
먼저 내가 삽질하는 두가지 방법을 정리해보기로 했다. 당연히 일부러 이 방법으로 삽질을 한 건 아니다.(그럴 능력이 있었다면 아예 삽질을 안 했을텐데!) 코드를 짜다보니 내가 이러고 있었다.
개별적인 특수한 사실이나 원리로부터 그러한 사례들이 포함되는 좀 더 확장된 일반적 명제를 이끌어내는 것을 귀납(歸納, induction)이라 하며, 이러한 귀납적 추리의 방법과 절차를 논리적으로 체계화한 것을 귀납법이라 한다. -두산백과 두피디아
귀납법은 여러 예시들에서 공통점을 찾아내 결론을 도출하는 방식이다. "이거 이렇게 해보니까 잘 되던데?", "다른 애들 전부 다 이랬으니까 얘도 그렇겠지?", "데이터 1만개, 10만개, 100만개 처리하는데 3초, 5초, 10초 걸렸으니까 200만개는 15초쯤 걸리겠지?"
연역(演繹, deduction)이란 이미 알고 있는 하나 또는 둘 이상의 명제를 전제로 하여 명확히 규정된 논리적 형식들에 근거해 새로운 명제를 결론으로 이끌어내는 추리의 방법이다. -두산백과 두피디아
연역법은 반대 방향으로 흘러간다. 귀납에서는 개별 사례로부터 일반적인 원리를 이끌어내지만, 연역에서는 이미 알고 있는 일반적인 원리에서 개별 사례나 새로운 원리를 도출한다. "소크라테스는 사람이다. 사람은 죽는다. 따라서 소크라테스는 죽는다.", "ExternalTaskSensor 는 BaseSensorOperator 를 상속 받는다. BaseSensorOperator 는 이렇게 동작한다. 따라서 메소드 오버라이딩을 하지 않았을 때 ExternalTaskSensor 도 똑같이 동작할 것이다."
바로, 귀납적 추론을 위해 몸소 온갖 실험을 해야 할 때와 연역적 추론을 했으나 그게 타당하지 않은 추론인 경우다. 무슨 소리냐고? 귀납쪽부터 먼저 살펴보자.
새로운 프레임워크나 라이브러리를 사용하고 싶다. 공식적으로 지원하는 문서 양이 너무 방대해서 이걸 다 읽고 있을 시간이 없다! 난 당장 다음달에 기능 출시 해야하는데! 그래서 곧장 IDE를 열고 코드를 짜기 시작한다.
당연히 처음 접해보기 때문에 내 손으로 직접 적을 수 있는 코드가 없다. 이럴 땐 역시 구글신을 찾아간다.
이런 내용의 책이 전혀 아니지만, 도서관에서 봤던 '구글 신은 모든 것을 알고 있다'를 속으로 외치면서 구글링한 코드를 찾아 어찌저찌 코드를 끼워맞춰본다. 환경이 달라서 제대로 돌아가지 않아도, 버전이 달라서 deprecated 된 함수가 있어도 끄덕없다. 이것도 구글링하면 나온다.
하지만 이런식으로 구글에 의존해서 코드를 짜다보면 결국에는 막히는 시점이 생긴다. 에러 메세지를 아무리 구글링해봐도 나오는 글이 없고, 스택오버플로우에 있던 나와 비슷한 동료들도 어느 순간 모두 사라져있다. 구글 신은 더이상 모든걸 알 수 없다. 내 환경과 내 상황, 내 요구사항은 오직 나의 것이기 때문이다. 이제 내게 남은건 돌아가지 않는 코드와 3시간이 훌쩍 지나버린 시계뿐이다.
그럼 이제 다른 방식을 사용해보자. 귀납이 아닌 연역으로 가는 것이다. 이번에는 공식 문서의 Get Started 페이지를 읽어보고 튜토리얼을 따라하면서 기본적인 사용법까지는 익혔다. 문서를 읽으면서 내 상황을 해결하기 위해 어떤걸 써야 할지도 골라놨다. 가이드에는 친절하게도 TO DO 와 NOT TO DO 목록까지 제공하고 있고 이것도 읽어봤다. 문서가 안내하는 길을 그대로 따라 걸으면서 코드를 적었고, 이제 제대로 돌아가는지 테스트만 해보면 된다.
하지만 가이드에서 눈을 씻고 찾아봐도 나오지 않는 오류와 맞닥뜨리게 되었다. '그래, 어떻게 한 방에 되겠어?'라는 생각으로 침착하게 오류 메세지를 읽어본다. 잘 모르겠다. 어쩔 수 없이 에러 메세지를 검색해본다. 나와 같은 길을 걸었던 수많은 사람들을 발견한다. '문서에는 이런 얘기가 없지만, 이 버전에서는 이렇게 동작합니다.' 누군가 적어놓은 한 줄기 빛과 같은 글을 보고 문제를 해결한다.
이제 살짝 불안해지기 시작한다. 이 문서를 믿어도 될까? 이 글만 보고 코드를 짜면 내가 생각하는 그대로 동작하는게 맞을까? 이걸 어디까지 테스트해야 할까? 순식간에 몇 시간이 사라졌던 귀납법의 악몽이 되살아나기 시작한다. 큰 성과 없이 몇 시간을 날려보내는 경험은 확실히 정신건강에 해롭다.
그렇다면 우린 대체 어떻게 해야 할까? 어떻게 하면 순식간에 몇 시간 단위의 시간을 흘려보내지 않고 안전하게 코드를 짤 수 있을까? 여기에 대한 정답을 찾지는 못했다. 흔히들 얘기하는 '삽질'을 하지 않을 수 있는 방법은 아직 찾지 못했다. 하지만 삽질을 줄이는 길은 분명히 있다.
새로운 프레임워크나 라이브러리를 접하는게 좋았다. 그러니까 귀납법과 연역법을 같이 쓰는 것이다. 이렇게 하면 정신건강이 그나마 덜 다치고, 시간도 적게 소요되었다.
자주 테스트하면서 맞닥뜨리는 에러를 해결 할 때는
에러를 빠르게 해결하기 위해 에러 메세지를 대충 읽고 곧바로 구글링했을 때보다, 에러 메세지를 정확하게 해석하고 의미를 파악했을 때 삽질을 방지할 수 있었다. (적고보니 아주 당연한 얘기지만 성질이 급한 사람으로써 이 못된 버릇을 자각하기까지 시간이 꽤 걸렸다.🥲)
오픈소스라면 공식 문서조차 의심해봐야 한다는걸 airflow 만지면서 깨달았다. 문서에 적혀있지 않은 내용도 있고, 중의적 표현이 많아 여러가지 뜻으로 해석될 수 있는 문장도 꽤 있다. 결국 오픈소스가 어떻게 돌아가는지 직접 파악하기 위해서는 테스트를 해야 하는데 우리가 일일이 그걸 하고 앉아있을 시간이 없다. (그 시간이 있었다면 오픈소스 컨트리뷰터를 했겠지!)
그리고 정신건강을 보호하는 또 다른 방법은 '삽질 로그'를 작성하는 것이다. 개발 경력이 10년을 훌쩍 넘어가는 분이 새벽 내내 안 되는걸 되게 만드려고 삽질했다는 얘기를 듣고 깨달았다. 개발자의 길을 걷기 시작한 이상 삽질을 피할 수 없겠구나. 그러면 어떻게 하면 좀 더 현명하게 삽질을 할 수 있을까?
작년 4월에 적기 시작한 삽질 로그는 2023년동안 9개가 쌓였다. (올해는 과연 몇번의 삽질을 하게 될지 두근거린다.)
삽질 로그에는 이런걸 적는다.
20230906 이건 삽질까진 아니고 조금 아쉬웠던거.
20231220 내 로컬 브랜치가 최신이 아니라서 버그를 재빠르게 발견하지 못한 건에 대하여
kafka consumer 다룰 때는 메세지부터 의심해보자.^^...................!!!! 제발.
설정 파일을 작업할 때는 환경별로 다르다는걸 떠올리자.
저 에러 문구를 보면 일단 ts 부터 의심하고 보자.
삽질 로그에서는 버그나 에러를 다루지 않는다. 대신 나의 행동을 다룬다. 내가 어떤 생각을 했고, 그 생각 때문에 어떤 결과가 나왔으며, 좀 더 나은 결과를 위해서 앞으로 어떻게 해야 할 지 생각해보는 것이다.
무엇보다 중요한건 삽질로그를 쓴 다음 주기적으로 다시 들어가서 읽어보는 것이다. '설정 파일을 작업할 때는 환경별로 다르다는걸 떠올리자.
' 라고 적어봤자 나는 컴퓨터가 아니기 때문에 또 비슷한 실수를 반복하고 말 것이다.
어쩔 수 없다. 우리는 모두 훌륭한 삽질가(?) 가 되어야 한다. 삽질을 피해서도 안 된다. 직접 경험해봐야만 깨달을 수 있는게 분명 있기 때문이다. 내 손으로 직접 코드를 적고 직접 에러를 발생시켜보면서 무엇이 되고 무엇이 안 되는지 겪어봐야 하는 것이다. 그리고 나는 이런 크고 작은 경험들이 쌓여서 '저 N년차 개발자에요' 하고 자신있게 말할 수 있는 내실이 다져진다고 믿는 편이다. 피할 수 없다면 즐기자. 삽질을 하면서 내가 어떻게 하는지 관찰하고 더 나은 방향을 찾다보면, 어느 순간 나의 경험으로 다른 사람의 삽질을 도와줄 수 있는 때가 오지 않을까.