Detail
IT/Other

[Pair Programming] 페어 프로그래밍을 통해 본 개발자의 성장을 저해하는 나쁜 습관

by 추쿠아비 2021. 6. 30.

요즘 신입 개발자들과 하루에 몇 시간씩 투자해서 페어 프로그래밍을 하고 있다. 그 과정에서 느끼고 알게 된 나쁜 습관과 좋은 습관에 대해서 정리하려 한다. 


습관의 힘

나는 프로그래밍 능력좌우하는 것이 무엇인지 항상 궁금했다. 개발 센스가 좋은 사람이 있으면 나쁜 사람도 있는데 이걸 단순히 지능의 차이라고 치부해버리기엔 뭔가 아쉽다. 단순히 머리의 좋고 나쁨이 아닌 이 센스를 결정 짖는 무언가가 있지 않을까 생각하곤 했었다.


어느 날, 동료의 화면을 멍하니 쳐다보다가 순간 머릿속을 스치는 게 있었다. 동시에 주위 다른 개발자들의 화면을 둘러보고 알게 되었다. 아웃풋이 느린, 흔히 말하는 생산성이 낮은 사람일수록 스택 트레이스 화면을 작게 띄워놓는 경향이 있었다. 이건 따로 통계를 낸 게 아니라서 확실한 팩트는 아니지만 그 개발자의 사이클을 살펴보니 다음과 같았다.

 

  • 코드 작성
  • 코드 저장
  • 화면을 브라우저로 전환
  • 브라우저를 리로딩
  • 에러
  • 곧바로 코드 화면으로 전환

효율이 나쁠 수밖에 없다고 느꼈다. 나는 그에게 문법 체크(Syntax Check) 방법화면상에서 모듈을 실행하는 방법을 가르쳐주었다. 그리고 그걸 이용하여 단위 테스트(Unit Test) 코드를 작성하는 방법도 가르쳤다. 하지만 설명하다 보니 그는 이미 그 방법들을 모두 알고 있다는 걸 알게 되었다. 단지 그는 그냥 이 과정들을 귀찮다고 생각하고 있었다. "어차피 화면에 표시해야 되는 거니까 화면에서 확인하는 게 제일 빠르고 편하다."라는 것이었다.

이건 습관의 문제였다. 당시 우리 시스템에는 CI가 없었다. 그래서 테스트를 작성하는 습관이 없었던 것이다. 그 후, CI가 도입되고 테스트 코드를 무조건 작성해야 하는 환경이 되자, 그는 브라우저에서 동작시켜보고 하나하나 확인한 뒤, 테스트 코드를 작성하는 이상한 방식으로 작업을 하게 되었다. 이러한 작업 방식은 확인 사이클이 길어지고, 코드가 결합된 후에 에러가 발생하기 때문에 복잡한 형태로 에러 메시지가 표시된다. 하지만 그 에러 메시지 조차 제대로 읽지 않았기에 별로 신경 쓰지도 않는 눈치였다. 단위 테스트를 의식하지 않고 써서 그런지 코드 결합도 복잡하고 테스트 난이도도 높은 악순환의 연속이었다. CI는 생산성을 개선하기 위해 도입되었는데 그에게는 그의 나쁜 습관으로 인해 생산성을 오히려 떨어뜨리는 결과를 가져오게 되었다.


나쁜 습관

신입 개발자와 페어 프로그래밍을 하며 발견한 나쁜 습관을 소개하려 한다.

 

1. 코드 리딩(Reading) 비율이 낮다

프로젝트에 따라 다르겠지만, 프로그래밍에서 코드 리딩은 비교적 많은 시간을 필요로 한다. 때에 따라선 80%는 코드를 읽고, 20% 정도 코드를 작성할 만큼 큰 비중을 차지하기도 한다. 코드를 수정하거나 작성할 부분뿐만 아니라, 그 주변 코드, 프레임워크까지 이해하기 위해선 우선 코드 리딩이 필수다. 하지만 아웃풋만 확인하는 개발자는 소스를 읽지 않고 화면의 동작만 확인하려는 경향을 보인다.

예를 들어, 프레임워크의 어떤 기능을 이용했는데 본인이 원하는 결과가 나오지 않았다. 프레임워크는 파라미터가 바르지 않다는 메시지를 제대로 리턴했지만, 그는 프레임워크의 해당 기능의 코드는 물론 에러 메시지조차도 확인하지 않았다. 그는 이런 행동을 했다.

 

  • 자신이 작성한 코드를 한참 들여다보고 오타나 실수가 없는지 막연히 찾아본다
  • 제대로 돌아가는 곳의 코드를 복사해와서 자신이 작성한 코드와 하나하나 비교해 본다

그리고 결국 해결하지 못하고 나에게 뭐가 잘못된 건지 물어왔다.

개선 방법
프레임워크에서 해당 코드의 위치를 찾을 수 있도록 가르쳐주고, 직접 찾아보도록 유도한다. 그리고 그 부분의 코드를 읽어보고, 왜 자신의 코드가 제대로 동작하지 않는지 확인하고 이해하도록 한다.

심리적 문제
왜 프레임워크 코드를 확인하지 않았는지 물어보니 "어려울 것 같기도 하고, 시간도 많이 걸릴 거 같아서요."라는 대답이었다. 이해도 된다. 규모가 큰 프레임워크는 복잡해서 전체를 파악하는 데에도 시간이 걸린다. 하지만, 그렇기 때문에, 더더욱 이렇게 하나씩 읽어가며 라이브러리, 기능에 대한 지식을 넓혀가야만 하는 것이다.

이 심리적인 저항을 털어내고 코드를 읽음으로써 문제를 간단히 해결할 수 있다는 경험을 시켜주는 것이 중요하다. 만약 당신이 멘토라면 "이 부분은 이해할 필요 없어. 그냥 쓰면 돼."라던지 "일단 돌려봐"라는 지도를 해서는 안된다. 코드를 분석하는 깊이개발자의 성장 한계를 결정하는 파라미터라고 생각한다.

 

2. 어려운 처리를 테스트 가능 단위로 분리하지 않는다

함수 나누기중요한 테크닉 중에 하나다. 어려운 처리를 왜 나누어야 하는지 간단히 설명하면 '나누어야 간단해지니까'이다. 하지만 숙련도가 낮은 개발자일수록 나누는 게 어렵다고 말한다.

 

 

이런 함수가 있다고 치고, 각각 처리를 추가하고 싶을 때, 숙련도가 낮은 개발자일수록 추가하고 싶은 위치에 그대로 처리를 추가하려는 경향을 보인다.

 

 

이처럼 추가하고 싶은 처리를 기존의 함수와 독립된 형태로 분리한다(Sproud Method). 이렇게 함으로써 베이스가 되는 함수의 복잡성을 배제하고 추가하고 싶은 처리를 독립적으로 테스트할 수 있게 된다.

개선 방법
기존 함수에 수정을 하기 전에 하고 싶은 처리를 잘라내서 함수를 만들도록 한다. 그 후 그 함수의 테스트 코드를 작성하는 사이클이 습관이 되도록 지도하고, 이 모든 과정이 결과적으로 가장 빠른 문제 해결 방법이란 걸 느끼게 한다.

심리적 문제
함수 나누기를 어려워하는 심리에는 '빨리 끝내야 한다'는 조급함이 존재하는 것 같다. 수정해야 하는 부분을 발견했으니 그곳에 처리를 살짝 추가하면 잘 돌아갈 것이라 생각하고, 처리를 분리하고 테스트 코드까지 작성하는 건 어렵고, 귀찮고, 여유가 있을 때 하는 일이라고 생각하기 쉽다. 하지만 오히려 이러한 수정은 코드를 더 복잡하게 만들고 테스트 패턴도 더 복잡해지게 만든다. 그 상태로 동작 & 에러 확인 & 수정을 반복하다 보면 자연스럽게 더 시간이 걸리고 생산성은 낮아질 수밖에 없다.

 

3. 작업 사이클이 정리되어 있지 않다

습관의 힘에서도 언급했지만, 가능한 한 가장 빠른 확인 사이클 테크닉을 익히는 것이 중요하다. 그리고 최종적으로는 자동화도 되어 있어야 한다.

페어 프로그래밍을 시작하고 알게 된 건데, 그는 항상 코드를 작성하고 한참 동안 그 코드를 들여다보곤 했다. 뭘 하는 건지 몰라서 물어보니 "확인하고 있습니다"라는 대답이 돌아왔다. 오타가 없는지, 뭔가 잘못 작성한 코드가 없는지 한줄한줄 확인하고 있었던 것이다.

"Syntax Check 돌려 보지?"라고 말하니 "Syntax Check는 뭔가요?"라는 답변이 돌아왔다. 방법을 가르쳐 줬더니 조금 지나서 "괜찮을까요?", "이게 맞나요?"라고 물어왔다. 나는 "못 미더우면 한번 천천히 살펴봐."라고 말해주었지만 여전히 뭔가 이해가 안 되는 표정이었다. 동작 확인 이외에 테스트&검증 작업을 해본 적이 없어서 그런 거란 걸 그때 처음 알게 되었다.

 

단위 테스트(Unit Test)는 유효성을 가지도록 설계해야 하기 때문에 다소 복잡한 준비가 필요하기도 해서, 테스트 퍼스트 실천자가 아닌 이상 실질적인 작업이 늦어지기도 한다.

개선 방법
Syntax Check를 에디터에 등록하고 적절한 타이밍에 실행시킨다. 필요하면(속도가 괜찮다면) 저장할 때마다 자동으로 실행되도록 하는 것도 좋은 방법이다. 우리는 에디터가 Vim이어서 syntastic과 같은 플러그인을 도입해서 실행하도록 했다.


클래스, 함수 단위로 실행할 수 있는 환경을 만들고 동작을 확인하도록 한다. 정상적인 동작을 확인하면 그것을 테스트 파일로 옮기는 습관을 익히도록 한다. "이게 맞나요?"라고 확인하기 전에 정해진 사이클을 빠짐없이 수행하도록 지도한다.

 

익숙해지면 fswatch를 활용하여 작은 CI환경을 만들어 저장할 때마다 테스트가 실행되는 환경을 만들도록 유도하는 것도 좋은 방법일 것 같다.

심리적 문제
사실 이러한 환경설정과 관련된 문제는 아는 만큼 가능한 것이라서 심리적인 문제와는 관련이 없어 보인다고 생각할 수도 있지만 세세하게 살펴보면 자신의 힘으로 무언가를 작성하려 하기보다, 처음부터 다른 곳에 있는 잘 돌아가는 '코드'를 복사해오려 하는 경향을 보인다.

사실 절대적으로 바른 코드라는 것은 존재하지는 않는다. '복사&붙여넣기'를 자주 사용하는 사람이 가지기 쉬운 편견으로 '복사&붙여넣기' 해서 제대로 동작하지 않으면 뭔가 복사를 잘못해서 그런 거라 생각해버리고 복사하기 전과 복사한 후의 코드의 다른 부분을 찾아보는 작업을 프로그래밍 사이클에 넣어 놓고 있다.

한번 작성을 끝낸 코드를 마치 틀린 그림 찾기처럼 뭔가 틀린 부분이 없는지 찾아본다. 결국 그렇게 작성한 코드는 그냥 기호일 뿐 본인이 이해하고 작성했다고 할 수 없다. 단순히 복사해와서 한줄한줄 틀린 그림을 찾아보는 습관은 아주 나쁜 습관이라는 생각이 든다.

 

4. 에러 메시지, 로그를 읽지 않는다

프로그래밍 언어와 라이브러리에서 출력되는 에러 메시지는 문제 발생 장소원인특정할 수 있도록 인간이 인간을 위해 작성해둔 정보다. 성장이 느린 개발자는 이걸 잘 읽지 않는다. 그냥 '아 뭔가 문제가 있나 보다'라고 생각하고 마는 경향이 있다.


순수한 vim이거나 web브라우저에 출력된 메시지라면 해당 위치로 점프하는 건 본인의 몫이지만, IDE는 에러가 발생한 해당 모듈의 해당 위치로 점프할 수 있게 해 준다. 편리한 세상이다.

읽지도 않고, 해당 위치로 점프해보지도 않고, 에러가 발생한 화면을 확인하는 시간도 극단적으로 짧다. 페어 프로그래밍을 하며 지켜보면, 너무 빨리 에러 창을 닫아서 내 동체시력을 테스트하는 건가 생각이 들 정도였지만, 아무튼 그가 에러를 확인하지 않은 건 확실했다.

결국 뭘 하는지 지켜보면 자기가 방금 작성한 부분을 하나하나 다시 살펴보고 있다. 오타는 없는지, 여기저기를 왔다 갔다 해본다. 결국 에러 메시지를 찬찬히 살펴보니 존재하지 않는 메서드를 호출하고 있다는 메시지였다.

에러 메시지를 확인하지 않고 문제를 해결하는 건, 사막에서 동전 찾기와 같다. 자신이 수정한 코드의 어딘가가 잘못되었다고 생각해서 자기가 손댄 부분만 확인하며 시간을 낭비하곤 한다.

개선 방법
같이 에러 메시지를 읽어보고 의미를 하나하나 확인해본다. 그리고 에러 메시지와 문제 해결 방법의 관계를 이해시킨다. 또 그러한 문제를 일으키는 최소 snippet을 만들어서 다양한 케이스를 생각해볼 수 있도록 한다.

심리적 문제
"에러 메시지가 영어여서 봐도 모르겠어요. 어려워요."라고 변명을 한다. 하지만 에러 메시지는 간결하게 쓰여 있어서 중학생 수준의 영어로도 해석이 가능하다.

사실, 에러 메시지는 그 언어와 프레임워크의 용어, 구조를 이해하고 있어야 제대로 의미를 파악할 수 있는 부분도 있다. 그래서 연습이 필요하다. 프레임워크의 이해, 언어와 관련된 지식, 그리고 소스 코드의 구조, 이 모든 걸 파악하고 있어야지 비로소 문제와 에러를 연결하 생각하고 해결할 수 있다. 스스로 할 수 있을 때까지 습관을 들이지 않으면 에러 메시지는 결국 그냥 기호일 뿐이다.

 

5. 문제가 어디서 발생했는지 모른다

실행 중에 에러가 발생하면 에러 메시지를 통해 어디에 문제가 있는지 알려준다. 그 말인즉슨 문제가 발생한 부분 직전까진 코드가 동작했다는 뜻이 된다. 즉, 에러가 나기 직전 부분까지 [printf]로 하나하나 값을 찍어보며 확인을 해볼 수 있다. 모듈에 뭐가 입력되고, 어떻게 바뀌고, 어디서 에러가 발생한 건지 쫓아갈 수 있다. 이런 식으로 콜 스택을 순서대로 따라가다 보면 문제가 발생한 부분을 금방 특정할 수 있게 된다. 이러한 테크닉이 없으면 문제를 파악하지 못한 채 문제의 늪에 빠져 시간을 낭비하게 된다. 

개선 방법
문제가 발생한 후에 바로 무언가 액션을 취하기보다 문제를 찾기 위한 전략을 생각하게 해 본다. 필요한 정보 수집을 어떻게 하는지, 에러가 발생한 시점에서 어디까지가 정상인지 질문을 하나씩 던지면서 전략을 세우도록 유도한다. 또 정보를 하나씩 얻어가며 이건 어떤 의미가 있는지, 전략을 바꾸어야 할지 같이 확인하며 너무 헤매지 않도록 유도한다.

심리적 문제
어디에 문제가 있는지 찾기 어려워하는 개발자는 자신이 일으킨 에러에 대해서 가벼운 '패닉'을 일으키는 경향이 있다. 잘 돌아갈 거라 생각했는데 돌아가지 않아서, 혹은 자신의 실수가 남에게 피해를 끼쳤다는 생각에 마음이 불안해지기 때문이다. 그 영향 때문인지 실패를 상정한 테스트를 피하는 현상으로 나타나기도 한다. 테스트의 가장 큰 가치는 일부러 실패해서 정보를 제공하는 것에 있기도 하다. 그리고 에러가 발생했다는 건 사실 완성에 한 발짝 다가갔다는 증거이기도 하다. 개발 환경에서 발생하는 에러는 아무에게도 피해를 끼치지 않는다. 오히려 유익한 에러이다. 이 부분을 제대로 경험시키고 이해시키는 것이 좋다.


좋은 습관

지금까지 소개한 나쁜 습관을 반대로 생각하면 좋은 습관을 알 수 있다.

 

  • 코드를 잘 읽고, 이해하는 데에 시간을 쓸 것
  • 눈앞의 문제를 단순화하는 능력을 기를 것
  • 에러를 두려워하지 말고 중요한 정보로 받아들일 것
  • 문제의 추적을 위해 명확한 행동지침을 세울 것

그 외에 조언하고 싶은 건

 

  • 툴의 개선 및 자동화
  • 보이스카웃 법칙을 따를 것
  • 다양한 언어를 배울 것
  • 체계적인 지식을 쌓을 것

이 있을 것 같다.

툴의 개선 및 자동화

좋은 습관을 정착시키는 데에는 툴의 기능을 활용하는 것도 도움이 된다. 예를 들어 표준 출력을 지원하는 Code Formatter를 사용하는 방법이 있다. IDE를 쓴다면 스타일도 간단히 조정해줄 것이다.

보이스카웃 법칙을 따를 것

자신이 지나온 곳을 깨끗이 청소할 것. 그것이 보이스카웃 법칙이다. 법칙에 따라 본인이 작성하거나 수정한 코드 주변을 정리하고 청소하자는 말이다. 코드를 제대로 읽고 이해한 후 깔끔하고 정확하게 수정하다 보면 자연스럽게 이해도 깊어지고, 코드도 전체적으로 깔끔해진다.

다양한 언어를 배울 것

하나의 언어만 배우면 이해하기 어려운 문제에 직면하게 되었을 때, 시야가 좁아지게 된다. 다양한 언어를 익히게 되면 하나의 문제에 대해 다양한 시각으로 접근할 수 있게 된다. 다른 언어의 새로운 개념이라고 해도 결국 어떤 특정 언어의 개념을 개선한 부분일 가능성이 높다. 하나둘씩 배워 가다 보면 다른 언어를 습득하고 능숙해지는 시간이 점점 짧아진다는 걸 알게 된다.

체계적인 지식을 쌓을 것

뭔가를 배우면서 핵심적인, 중요한 부분만 골라서 배우려 한다거나, 문법, 패러다임의 이해를 스스로 자기 나름대로 정리, 해석을 해두지 않는다면, 그건 본인의 지식이 아니게 된다. 이렇게 수박 겉핥기로 배운 것들은 결국 응용에 이르지 못하고 그냥 개념만 아는 수준에 머물게 된다. 하나씩 응용해보며 과제를 해결하면서 배워가면 프로그래밍의 질도 향상되어 갈 것이다. 


마지막으로

개발자의 재능이란 결국 좋은 습관의 축적이라고 생각한다. 습관을 개선함으로써 개발자로서의 능력도 향상시킬 수 있을 거라 나는 믿는다. 물론 습관의 개선에는 심리적 장벽도 있고, 행동과 결과를 통해 느끼는 바도 다를 것이다. 그로 인해 습관의 개선이 어려운 부분도 분명히 있으리라 생각된다. 그리고 습관을 개선한다 해도 단번에 슈퍼 엔지니어가 되는 것도 아니다. 이러한 과정, 즉, 새로운 것을 배우고 익히는 과정이 고통이 아닌 즐거움으로 받아 들일수 있는 자세가 가장 중요하다고 생각한다.


by Unsplash.


728x90

댓글