개발자라면 한 번쯤은 아찔한 실수를 경험해 본 적이 있을 겁니다. 우리는 일상적으로 크고 작은 실수들을 하게 됩니다. 아무리 컴퓨터를 다루는 전문가라고 하더라도 컴퓨터는 아니니까요. 심지어 컴퓨터조차도 오류가 있는걸요!
사람인 이상 누구나 실수를 하기 마련이지만 "실수 좀 할 수도 있지 어쩌라고!"와 같은 태도는 좀 곤란합니다. 같은 실수가 반복되면 그게 곧 자신의 실력이 되는 법입니다. 또, 모든 원인을 개인이 신중하지 못한 탓이라고 보고 막연하게 "꼼꼼히 하라"는 조언은 별로 도움이 되지 않았습니다. 그래서 주니어 개발자의 입장에서 실수는 왜 하게 되는지, 어떻게 하면 실수를 줄일 수 있을지 고민해 본 결과를 나눠보려 합니다.
실수 같지만 사실은 실수가 아닌 것
실수(失手, mistake)란 '조심하지 아니하여 잘못함'이라는 뜻을 가지고 있습니다. 잠깐의 방심으로 평소라면 하지 않았을 잘못을 저지르게 된 경우를 말합니다. 개발자 입장에서 잘못이란 곧 에러, 오류를 말합니다. 다양한 에러의 원인 중 실수와 구별해야 하는 것으로 '무지'와 '강요된 실수'가 있습니다.
무지는 말 그대로 지켜야 할 절차나 방법에 대해 잘 몰랐던 경우를 말합니다. 누군가가 한 번쯤 이야기를 해줬다 하더라도 실제로 겪어보고 나서야 체감할 수 있는 경우가 많죠. 무지로 인해 잘못을 저질렀을 때는 해결이 그리 어렵지 않습니다. 다음부터는 잘 알고 하면 됩니다. 보통 처음 어떤 일을 할 때 겪게 되는 것이므로 경험치가 좀 쌓이면 자연스레 해결이 될 수 있습니다. 하지만 '안다'라는 것이 인간에게는 영구적이지 않습니다. 반복적으로 하는 일이 아니라면 금방 잊어버릴 수 있고, 이후에 같은 잘못을 하게 되면 더 이상 몰랐다는 변명을 할 수 없게 됩니다. 이건 실수라고 할 수 있습니다. 따라서 계속 기록하고 환기하는 작업과 함께 끊임없이 학습하는 것이 필요합니다.
강요된 실수는 난잡하게 설계된 코드베이스, 혼란스러운 업무 환경 등 통제하기 어려운 외부의 영향에 의해 발생하게 된 실수를 말합니다.
저는 개발을 진행하는 도중에 새로운 일이 계속 끼어드는 환경에서 일을 하고 있습니다. 그러다 보니, '내가 뭘 하고 있었지?'라는 질문을 자주 합니다. 저뿐만 아니라 같이 일하는 사람들 대부분에게서 이런 증상을 발견할 수 있었습니다. 예를 들어, 어떤 문제점을 발견하고 수정하려던 순간에 긴급건이 치고 들어와서 정신을 쏙 빼놓고 나면 해결하려던 문제에 대해서는 까맣게 잊게 되는 경우가 있습니다. 어떤 아이디어가 떠오르려던 순간에 방해를 받아 흐름이 끊기는 경우도 있고 뭔가 잘못된 것 같다는 느낌이 들었지만 더 살펴보지 못하고 그냥 넘어가게 되는 경우도 있습니다. 다시 1시간 전의 나로 돌아가기 위해 코드를 읽고 생각을 정리하는 데 시간을 쓰다 보면 생산성이 떨어지는 것 같기도 합니다. 이렇게 정신없이 일하는 상황에서는 생각보다 잃는 것이 제법 많은 것 같습니다.
이럴 때는 자신의 상황을 최대한 설명하고 환경 개선을 요구할 필요가 있지만 한국 사회에서는 어쩔 수 없으니 참고 견디라는 답변이 되돌아오는 경우가 많을 겁니다. 아무리 통제할 수 없는 요인의 영향을 받았다고 하더라도 개인의 잘못이 없다고 할 수도 없고, 현실적으로 책임을 져야 하는 것도 자기 자신이기 때문에 각자 본인이 처한 환경에서 최대한 실수를 줄일 수 있는 방법을 모색하는 수밖에 없습니다.
실수를 피하기 위한 기본자세
보통 실수를 하고 난 뒤에는 다음과 같은 메커니즘을 거치게 됩니다.
부정 > 책임 회피 > 자책과 절망
제가 개발한 프로그램에 문제가 있다는 소식을 듣게 되면 '사용자가 잘 몰라서 그렇겠지, 뭔가 잘못했겠지'라는 생각이 먼저 듭니다. 실제로 50% 정도는 그런 케이스였기 때문이기도 하지만, 내가 작성한 프로그램에서 오류가 발생했다는 것은 자존심이 상하고 부끄러운 일이기 때문이기도 합니다.
정말 오류가 있는 것 같다는 생각이 들면 내가 그랬을 리 없다는 생각에 커밋 히스토리를 살피기 시작합니다. 사실 몇 달 지나서 소스를 다시 보게 되면 기억이 잘 나지도 않을뿐더러, 그 당시의 나와 지금의 나는 다르기 때문에 대체 왜 이렇게 했는지 이해가 되지 않을 때가 많습니다.
아무리 찾아봐도 손댄 사람이 본인 밖에 없다는 사실을 깨닫게 되면 자책을 하기 시작합니다. '내가 왜 그랬지? 이런 바보 같은 실수를 하다니! 이런 멍게 해삼 말미잘!'
여기서 멈춘다면 달라지는 것은 아무것도 없습니다. 막연하게 다음부터는 조심해야겠다 생각하고 넘어가면 언젠가 또 비슷한 실수를 하고 자책을 하게 되겠죠. 한 걸음 더 나아가 회고를 통해 원인 분석을 하고 되풀이하지 않게끔 잘 정리해 두고 필요할 때마다 꺼내보는 것이 필요합니다.
입력을 의심하라.
개인적인 경험에 비추어 보아 아마도 제일 처음, 그리고 가장 자주 하는 실수는 '예상하지 못한 입력이 들어왔을 때 예외처리를 하지 않는 것'이 아닐까 합니다.
프로그램은 입력을 받아서 목적에 맞게 처리한 결과를 출력합니다. 일반적으로 어떤 로직으로 처리할 것이냐에 더 집중하게 되기 때문에 입력값이 없거나 이상한 값이 들어오는 경우를 간과하기 쉽습니다.
코딩테스트를 준비하다 보면 알고리즘을 짜는 것 자체보다도 어렵게 느껴지는 것이 테스트 케이스를 만드는 일입니다. 일반적인 예시에는 잘 동작하는데 미처 대비하지 못한 히든 케이스를 만나게 되면 오류 또는 오답을 내뱉는 경우가 다반사입니다. '이렇게 하면 되지 않을까? 어 되네?' 하며 기뻐하고 끝낼 것이 아니라 '이렇게 해도 되나? 저렇게 해도 되나?' 계속해서 의심하고 확인해 볼 필요가 있습니다.
물론 모든 경우의 수에 대비할 수는 없습니다. 지금은 문제가 없지만 사용되는 환경이 달라짐에 따라 새로운 입력이 나타나는 경우도 있습니다. 그런 의미에서 모든 프로그램은 오류의 가능성을 내포하고 있다고 해도 과언이 아닙니다. 하지만 시간이 허락하는 한도에서 최대한 넓은 시야를 가지고 가능한 많은 경우에 대비해서 개발할 필요가 있습니다.
유형이나 형태는 조금씩 다르지만 개발 중 발생하는 대부분의 실수는 이렇듯 시야가 좁아서 발생하는 경우가 많습니다. 경험과 연륜이 쌓이면 자연스레 시야도 조금씩 넓어질 거라 기대하기 마련이지만, 시야를 넓히려는 의식적인 노력 없이는 평생 자기가 보고 싶은 것만 보고 살게 될 수도 있습니다.
다양성을 고려하라.
서로 다른 유형의 아이템들이 하나의 페이지를 공유하게 되는 경우가 있습니다. 예를 들어, 하나의 게시판 페이지를 가지고 여러 가지 게시판을 표현할 수 있습니다. 게시글 목록을 불러올 때 쿼리만 조금씩 다르게 하면 되기 때문이죠.
SELECT * FROM post
WHERE type = {postType}
이렇게 변수 postType
을 조건으로 걸어주면 공지사항 게시판의 링크로 들어오는 경우에는 공지사항만 불러오고 Q&A 게시판으로 접속을 하면 Q&A 게시글을 가지고 올 수 있습니다.
어느 날 Q&A 게시판을 1:1 문의 게시판으로 바꾸어달라는 요청이 들어왔습니다. 그리 어려운 일은 아닙니다. post 작성자가 접속한 회원과 일치하는지 여부를 검사하는 조건 하나만 추가해 주면 됩니다.
SELECT * FROM post
WHERE type = {postType}
AND author = {userId}
별 거 아니구먼 하면서 깃헙에 올렸고 테스트 결과도 이상이 없었습니다. 여러분은 이상한 점을 발견하셨나요? 못 하셨다면 이 코드가 배포된 다음 날 쏟아지는 문의에 당황하시게 될 겁니다.
이 게시판 페이지는 Q&A 뿐 아니라 공지사항도 함께 사용하고 있습니다. 공지사항의 author
는 당연히 관리자일 것이기 때문에 관리자를 제외한 일반 회원들은 공지사항을 볼 수 없게 됩니다. 아무도. '이런 실수를 한다고? 사람이야?' 하는 생각이 드실 수 있겠지만, 얼마 전 제가 아는 사람이 실제로 겪은 일이고 실제 코드는 이것보다 훨씬 복잡하기 때문에 지금처럼 한눈에 들어오지 않을 수 있습니다.
무언가를 수정하기 전에 내가 지금 손봐주려는 친구 말고 이 코드에 얽혀있는 또 다른 친구가 있는지 반드시 확인할 필요가 있겠습니다. 마찬가지로 테스트를 할 때에도 개발하려는 1:1 문의 게시판이 잘 되는지만 볼 것이 아니라 공지사항 게시판도 눌러볼 필요가 있겠죠. 더 나아가 다양한 조건들을 미리 명세해 놓은 문서가 있다면, 더 바람직하게는 테스트 코드가 있으면 이런 불상사를 방지하는 데 도움이 됩니다.
맥락을 파악하라
당연한 말이지만 코드의 일부를 수정하기 전에 해당 코드가 어떤 역할을 하는지 정도는 정확히 파악을 하고 있어야 전체 프로그램에 장애가 발생하는 것을 막을 수 있습니다. 앞면만 보고 수정을 했다가 내가 생각하지 못했던 뒷면 때문에 오류가 발생할 수 있습니다. 적어도 해당 코드가 포함된 페이지 또는 파일 정도는 찬찬히 읽어보고 이해할 필요가 있습니다.
더 범위를 넓혀 해당 프로그램을 호출하거나 직, 간접적으로 영향을 주고받는 모든 부분에서 수정되기 전과 후에 어떤 차이가 생기는지 적어도 한 번쯤은 고려해보아야 합니다.
커밋을 자주 하자
저희 회사에서 형상 관리를 도입한 지 1년이 채 되지 않았고, 아직 개발 문화가 확립되지 않은 상태입니다. 하루 안에 끝나는 개발 건이 많고 보통 건 단위로 커밋을 하다 보니 사실 형상 관리의 이점을 온전히 활용하고 있지는 못한 것 같습니다. 수정된 부분들에 대한 히스토리가 남지 않기 때문에 문제가 있어 보이는 부분을 무슨 의도를 가지고 작성한 것인지 파악하기도 어렵습니다.
검색해 본 결과, 보통 커밋 주기가 30분 ~ 1시간 정도라고 합니다. 물론 시간 단위로 하는 것은 아니고 의미 있는 변경이 있을 때마다 커밋을 한다고 하더라고요.
커밋을 자주 하면 문제가 생겼을 때 돌리기도 쉽고, 그 자체가 후세인들이 참고할 수 있는 소중한 기록이 됩니다. 그렇기 때문에 커밋 메시지를 잘 작성하는 것도 중요합니다. 그동안 참고할 만한 기록이 없었던 경우라면 여러분의 회사에서 코딩의 역사를 기록한 최초의 인류가 될 수 있는 기회를 놓치기 마시기 바랍니다.
리팩토링을 하자
기존 코드가 복잡하고 눈에 잘 들어오지 않는 상태에 놓여있다면 리팩토링을 진행하면서 코드를 조금 더 잘 이해하고 기능 추가 또는 수정을 원활하게 진행할 수 있습니다.
바빠도 한 번 더 보자
테스트는 매우 지루하고 귀찮은 작업입니다. 창의력을 발휘해 개발을 하면서 느끼는 성취감이나 재미 같은 것들이 전혀 없기 때문이죠. 개발이 어느 정도 완성 단계에 이르면 테스트팀이 알아서 잘해주겠지라고 생각하며 떠넘기고 싶은 마음이 자연스레 생기지만, 자기 손을 떠나기 전에 코드를 다시 한번 읽어보고 꼼꼼하게 테스트하는 것이 중요합니다. 물론 물리적으로나 심적으로 그럴 여유가 많지 않은 게 사실이지만 기한이 정해져 있는 게 아니라면 하루 더 빨리하는 것보다 문제없이 마무리 짓는 게 본인에게 더 이득이라고 생각합니다.
궁극적으로는, 인간이 하는 실수의 영향을 최소화할 수 있도록 설계하고 업무 환경과 코드를 개선해 나가는 작업이 필요합니다. 또 테스트 단계에서 충분히 실수가 걸러질 수 있도록 정비할 필요도 있습니다. 하지만 그에 앞서 우리가 할 수 있는 것이 있다면 뭐라도 해보는 것이 진정한 프로로서의 자세겠죠!
'Issues & Trends' 카테고리의 다른 글
오픈 소스라고 막 쓰면 안 돼요 (0) | 2023.02.20 |
---|---|
Javascript CDN을 피해야 하는 이유 (0) | 2023.01.17 |
댓글