본문 바로가기

Dev/소프트웨어공학

지속가능한 SW 개발을 위한 코드 리뷰(우아한테크세미나) + @

지난 4월 우아한테크세미나에서 코드 리뷰를 주제로 세미나가 진행되었다.

이 세미나 내용을 중심으로 개인적인 경험과 생각을 덧붙여, 코드 리뷰가 무엇이고 어떻게 하는지에 대해서 정리를 해본다.

사실 세미나 듣고 바로 정리하려고 했지만 차일피일 미루다가 얼마 전 회사에서 PR(Pull Request)에 대한 설명을 해달라는 요청이 있었다. PR 사용에 코드 리뷰는 빠질 수 없는 내용이라서 겸사겸사 같이 정리해서 써먹어보려 한다. (씨익..)

그리고 이 글에서는 요즘 가장 많이 사용되는 코드리뷰 방법인 Pull Request(이하 PR)를 사용한다는 전제하에 설명한다.

 

세미나는 유튜브에서 다시 볼 수 있으며, 약 2시간 분량인데 1.5배속으로도 들을만해서 쪼금만 시간 투자해서 봐도 괜찮을 것 같다.


코드리뷰란?

[각주:1]">
코드리뷰[각주:2]

코드리뷰를 한 마디로 표현하면, "코드를 실행하지 않고 사람이 직접 코드를 검토하면서 결함을 찾아내고 개선하는 과정." 정도로 말할 수 있을 것 같다.

 

코드리뷰로 할 수 있는 일들을 나열해 보면 아래와 같다.

  • 주목적은 버그와 장애요소를 미리 파악하는 것
  • 오타 확인, 개발 표준 준수 확인
  • 하드 스킬(기술적인 내용) 공유 및 학습
  • 소프트 스킬(커뮤니케이션 능력, 리더십 등) 학습
  • 좋은 코드에 대한 칭찬
  • 코드에 대한 책임감 부여

코드리뷰의 필요성

(코드리뷰의 방법을 바로 알고 싶다면 이 부분은 넘어가도록 하자.)

우리가 살고 있는 시대

코드리뷰에 대해 알고자 하는데 갑자기 우리가 살고 있는 시대가 웬 말인가 싶지만 소프트웨어 시장(market)과 비즈니스, 개발의 연관성을 생각해보자.

 

현재 우리가 살고 있는 시대는 4차 산업혁명시대이다. 이 시대를 대표하는 세계관을 VUCA라고 하는데, VUCA에 대해 짧게 설명하자면 Volatility(변동성), Uncertainty(불확실성), Complexity(복잡성), Ambiguity(모호성) 각 단어의 앞글자를 딴 용어로 '불확실하고, 복잡하고, 모호하며 변화가 많은 세상'이라는 의미를 가진다.

 

만약, 본인이 네카라쿠배 처럼 큰 성공을 하겠다는 야망을 가지고 있어서 제품(소프트웨어나 서비스)을 만들려고 한다.

그런데 시시때때로 변화하는 VUCA 시장에서는 어떤 것을 만들어야 큰 성공을 할 수 있을지 감이 안 잡힌다.

제품을 만든다 해도 시장에서 원하는 것을 만들어야 하는데, 시시때때로 변화하는 시장이므로 앞으로 언제 무엇을 원하는지 예측하기 힘들다. 그래서 제품을 빠른 주기로 배포하고 시장의 피드백을 받아 빨리 적용하는 과정을 반복하는 형태가 되어간다.

 

'제품을 빠른 주기로 배포하고 하면서 시장의 피드백을 받아 빨리 적용하는 과정을 반복' 뭔가 익숙한 문장이다.

바로, 애자일 방법론!!

애자일 방법론이 요즘 소프트웨어 개발 프로세스로 사용되는 이유야 많겠지만, 이것도 하나의 이유가 아닐까라는 생각이 든다.

제품 출시 별 생산성

그렇다면 애자일스럽게 제품이 빠른 주기로 출시하는데, 출시될 때마다 좋은 생산성이 유지가 될까?

한 기업의 제품 출시 별 생산성과 소스코드 라인당 비용의 변화를 살펴보자.

[각주:3]">
출시별 생산성[각주:4]
[각주:5]">
출시별 코드 라인당 비용[각주:6]

출시 횟수 별 생산성은 떨어지는 반면, 코드 라인당 비용은 점점 증가하는 것을 볼 수 있다.

이유는 초기에 출시되는 제품은 대부분이 새로 작성되는 코드이고, 구현되는 모든 내용이 출시에 포함되기 때문에 생산성이 높고 비용도 낮게 측정이 된다. 하지만, 출시가 될수록 새로운 기능이 추가되거나 기존 기능의 개선과 버그 수정이 작업이 늘어나기 때문에 제품 자체의 변화는 적어지기 때문이다.

이는, 제품의 유지보수가 필요해지면서 유지보수 비용이 많은 부분을 차지하는 것이라 짐작할 수 있다.

유지보수 비용

[각주:7]">
소프트웨어 개발 비용 비율[각주:8]

유지보수 비용은 왜 많이 드는 걸까? 여기서 비용은 금전적인 것만 말하는 것이 아닌 인력, 시간 등의 비금전적 요소도 포함이 된다.

오류가 발생한 경우 어떤 상황에서 발생하는지 원인을 분석하고 해당 부분의 소스코드를 수정하게 되는데, 수정을 위해서 해당 부분의 소스코드를 읽고 이해하고 수정해야 한다. 

해당 부분을 이전에 작성한 사람과 수정하는 사람이 같더라도, 한 개발자가 여러 부분을 개발하는 경우에는 어제 작성한 코드도 또렷이 기억하기가 힘든 경우가 많아서 다시 읽고 이해하는 과정이 필요하다.

이처럼 한 번 작성된 코드는 여러 사람에게 수 없이 읽히게 되는데, 이 과정에서 소스코드를 읽고 이해한 뒤 수정하는 데 걸리는 시간은 처음 소스코드를 작성하는 것보다 10배 정도의 비용이 필요하다고 한다.

소스코드를 읽고 이해하는 비용을 줄이기 위해서는 높은 수준의 코드 품질을 유지해서 어떤 사람이든 쉽게 읽고 이해하도록 해야 하는데, 그 방법 중 당장 적용하기 쉬운 방법이 바로 코드 리뷰이다.

"The only way to go fast, is to go well" - Robert C. Martin

코드리뷰 절차

코드리뷰 절차

  • 저자(Author): 소스코드 작성, 리뷰 요청
  • 리뷰어(Reviewer): 요청받은 소스코드를 읽고 merge 가능한지 결정
  • 변경 내역(Change List, Pull Request): 저자가 리뷰를 요청하는 소스코드의 일련의 변경사항에 기술한 내용

코드리뷰 방법

코드리뷰를 대하는 자세

코드리뷰를 사용하지만 꾸준히 하지 못하는 이유 중 큰 부분이 코드리뷰에 대한 마음가짐을 충분히 못 가진 것이 큰 것으로 보인다.

어떤 마음가짐이 필요한지 알아보자.

코드리뷰의 대상은 소스코드

비판적인 성격의 리뷰가 들어오면 개발자 특유의 방어본능에 의해 날카롭게 대하는 경우가 종종 있을 수 있다. 물론, 정말 악의적인 리뷰는 예외이다.

하지만 소스코드의 품질을 높이기 위해 코드에 대해 비판을 하는 것이지, 저자를 비판하는 것이 아님을 인지하자.

나에 대한 비판이라고 생각하는 순간부터 리뷰어와 감정적인 대립이 생기게 되어 돌이킬 수 없는 일이 발생할 수도 있다.

글에도 감정 한 스푼

생각을 글로 전달할 때는 표정이나 목소리가 없기 때문에 감정 표현이 어렵다. 그래서 글의 작성자의 의도와는 다르게 읽는 사람이 오해할 수 있는 상황도 발생할 수 있다.

예를 들면, "You forgot to close the file handle."이라고 리뷰를 작성했는데, 저자 입장에서는 “I can’t believe you forgot to close the file handle! You’re such an idiot!"의 뉘앙스로 받아들이는 오해가 발생할 수 있다.

이런 오해를 줄이기 위해 이모지를 사용해서 감정을 간접적으로 표현하거나, 부드러운 말투로 작성하는 방법이 있다.

코드리뷰는 서로서로 지식을 공유하는 장소

코드리뷰가 리뷰어의 수고만을 필요로 한다고 오해해서 코드리뷰를 꺼리는 사람도 간혹 존재한다.

리뷰어는 다수가 지정될 수 있는데, 이 리뷰어 중에는 저자보다 지식과 경험이 많은 사람도 있지만 적은 사람도 있다.

설명하기 쉽게 지식과 경험이 많은 사람을 시니어, 적은 사람을 주니어로 표현한다면 리뷰어가 시니어인 경우 저자는 리뷰를 통해 부족했던 기술을 습득하여 발전할 수 있다. 리뷰어가 주니어인 경우에는 비록 리뷰 내용은 부족할지 모르지만 주니어 입장에서는 PR의 소스코드를 보고 기술(하드 스킬)을 습득할 수 있는 기회가 생긴다.

 

그렇다고 시니어가 아무것도 얻는 것 없이 희생만 하는 입장인 것은 아니다.

코드리뷰로 리뷰하는 과정도 커뮤니케이션이다. 시니어는 주니어와 계속 소통을 하면서 어떻게 설명해야 쉽게 이해하는지, 오해하지 않고 받아들이는지 등의 커뮤니케이션 능력과 리더십을 쌓아갈 수 있다.

결정은 저자(Author)의 몫

PR에는 다양한 리뷰가 작성된다. 하지만 리뷰 내용을 적용할지는 PR 저자가 판단해야 한다.

저자가 작성한 코드보다 더 빠른 동작을 하는 기술을 리뷰어가 작성해주었다고 해도 지금으로도 충분한 속도라면 지식은 습득하되 리뷰에 적용하지 않아도 된다.

그러므로 리뷰어가 자신이 작성한 기술적인 리뷰가 적용되지 않더라도 마음에 상처입지 말자.

효율적인 PR 방법

단순 노동은 컴퓨터에 맡기자

컴퓨터로 자동화할 수 있는 unused import 처리, fomatting 같은 작업은 툴을 사용하여 자동화하자. 충분히 자동화 할 수 있는 작업을 리뷰어가 리뷰하기에는 그 시간이 너무 아깝다.

만약, 어쩔 수 없이 그러한 PR을 작성한다면 해당 부분만 별도의 PR로 분리해서 리뷰가 불필요한 PR임을 명시해주어 리뷰어의 시간을 절약하자.

스타일 가이드를 통해 스타일 논쟁 해소

사람마다 말투가 다르듯 개발자마다 작성하는 코드 스타일도 제각각이다. 이런 스타일 때문에 코드리뷰 과정에서 불필요한 논쟁이 발생할 수도 있다. 이럴 땐 표준이 있으면 가장 확실하다.

팀 또는 프로젝트 단위로 스타일 가이드를 작성해서 통일된 스타일을 정해놓으면 논쟁을 방지할 수 있다.

모든 PR은 리뷰어를 위한 것

코드리뷰는 적지 않은 시간이 필요한 작업이므로, PR을 작성할 때는 리뷰어의 입장을 생각해서 작성할 필요가 있다. 변경된 소스코드에 대해서 가장 잘 아는 사람은 작성자 본인이다. 최대한 많은 정보를 주석으로 남겨 리뷰어의 시간을 아껴주도록 하자.

예를 들면, 변경 이유나 방법, 소스코드의 주석, 수정해서 동작하지만 아쉬운 부분, 리뷰어가 주의 깊게 봐주었으면 하는 부분 등 소스코드 이해에 도움이 되는 정보라면 어떤 것이든 좋다.

 

또한, PR에 포함된 변경사항은 적을수록 좋다. 그래야 리뷰어는 PR 처리하는 시간을 절약할 수 있다.

저자가 생각하기에 이 PR을 리뷰하는데 얼마나 걸릴지 생각해보고 너무나 많은 시간이 필요한 경우에는 PR을 나눌 수 있다면 나누어보자.

PR의 크기를 아래와 같이 팀이나 프로젝트에서 정하는 것도 방법이다.

  • 저자가 반나절 정도 작업한 양
  • 최대 4시간 안에 리뷰할 수 있는 양

위와 비슷한 맥락으로 커밋도 의미 있는 단위로 나누어 작성하자.

하나의 PR이라도 커밋이 나뉘어 있다면, 리뷰어가 커밋마다 보고 확인할 범위가 줄어들어 좀 더 시간을 절약할 수 있다.

커밋을 나누는 일은 작업 세분화를 얼마나 잘하는지와 연관이 있으므로 꾸준히 연습할 필요가 있다. 

리뷰어는 가능한 많이

리뷰어가 많을수록 문제점을 찾아낼 확률은 자연스레 높아지고, 코드 품질도 많이 향상될 수 있다.

또 다른 효과로는 PR 저자가 눈치 볼 사람이 많아지므로, 더 좋은 PR을 작성하게 되는 효과도 있다.

효율적인 리뷰 방법

리뷰를 미루지 말자

이상적인 코드 리뷰는 요청받은 후 수 분내에 하는 것이지만, 이 것은 이상일뿐이다. 대신 리뷰 라운드의 최대 시간을 하루가 넘진 않도록 하자.

차일피일 미루다 보면 끝도 없이 미뤄질 수도 있고, 저자는 계속 기다리는 수밖에 없다. 흔치 않지만, 해당 PR이 적용되지 않으면 다음 일을 진행할 수 없는 경우가 있을 수 있다. 업무가 너무 바빠서 하루 안에 리뷰가 불가능하다면 다른 리뷰어를 지정하는 것도 방법이다.

PR 리뷰로 본인의 작업이 힘들 것 같다면 하루에 리뷰 몇 번 또는 몇 개와 같이 리뷰 시간을 정하는 것도 좋은 방법이다.

리뷰는 고수준에서 저수준으로

PR에는 많은 의견이 리뷰로 작성되는데, 밑도 끝도 없이 리뷰가 있으면 많은 리뷰가 감사하긴 하지만 리뷰를 확인하고 적용해야 할 저자는 당혹스럽다. 리뷰 라운드 당 리뷰 수를 어느 정도 제한하거나, 라운드 시기 별로 리뷰 수준을 맞추어 이런 상황을 방지할 수 있다.

리뷰 수준이란 고수준부터 저수준으로 나눌 수 있는데, 고수준일수록 버그, 장애, 성능, 보안 등 반드시 처리해야 할 사항에 대한 것을 뜻하고, 저수준일수록 설계 및 성능 개선, 변수명, 주석 오류 등 이후에 처리해도 되는 것을 뜻한다. 

예제 코드 제공에 관대하자

저자에게 주는 선물 느낌으로 리뷰에 예제 코드를 작성해준다면 저자가 이해하기 쉽고 리뷰를 반영할 때도 좀 더 편할 수 있다.

어떤 경우에는 코드로 대화하는 것이 더 효율적일 수도?

 

과유불급. 예제를 제공하더라도 너무 과하게 주는 것도 조심할 필요가 있다.

과한 예제는 선물이 아니라 이렇게 적용해라는 듯한 억압적인 느낌을 주거나 저자가 코드를 작성할 수 없을 거라는 느낌을 줄 수도 있다.

태그 활용

리뷰에 사용할 수 있는 태그를 미리 정해두고 사용하면 이 리뷰는 어떤 리뷰인지 저자가 쉽게 파악할 수 있으므로 저자의 시간을 아낄 수 있다.

예를 들어 앞서 설명한 고수준, 저수준의 단계를 태그로 나누어서 이 리뷰는 반드시 확인할 사항이라던가 무시해도 되는 사항이라는 것을 표현할 수 있다.

한 두 등급의 코드 레벨만 올리는 것을 목표로

신입 개발자가 작성한 PR의 리뷰에 좋은 기술과 정보를 아무리 많이 준다 하더라도 받아들일 수 있는 양은 제한적이고, 무엇을 코드에 적용하는 게 맞는 것인지 오히려 난해할 수도 있다.

개발 역량이 단기간에 급성장하는 태생이 개발자가 아닌 이상, 일반인은 천천히 성장하므로 리뷰 내용도 저자가 받아들이고 성장할 수 있는 적당한 수준으로 작성해 주는 것이 좋다.

피드백 방법

칭찬도 리뷰

코드리뷰를 하다 보면 잘 못된 부분에만 집중하는 경향이 있다. 리뷰어는 코드를 트집 잡거나 감시하는 사람이 아닌, 서로 도와주려는 동료이다. 

PR에 좋은 변경이 있을 때는 진심 어린 칭찬을 남겨준다면, 저자가 리뷰에 대한 걱정이나 긴장감을 낮출 수도 있고 입장이 바뀌었을 때 칭찬이 되돌아오면서 선순환이 이루어져 좋은 코드리뷰 문화가 자리 잡을 수 있다.

I-message 대화법

리뷰(또는 대화)할 때 자신을 주어로 삼아서 이야기하는 I-message 대화법을 사용하면 나의 감정과 생각을 담아 이야기하게 되어 상대방의 감정을 상하게 하는 것을 막을 수 있다.

"너는 ~"라는 형태로 시작하는 대화법(You-message)은 상대방에 대한 부정적 의미를 담는 경우가 많으므로 상대방에게 상처를 주는 경우가 많다.

You-message I-message
너는 어떻게 그렇게 얘기할 수 있니? 그렇게 얘기하시니까 제 마음이 서운하네요.

의견이 아니라 원칙에 기반

리뷰에 의견을 남길 때는 제안하는 의견과 변경의 이유를 모두 설명해서 상대방이 이해하기 쉽도록 하자.

저자가 PR을 작성할 때 상세히 적어주는 게 효율적인 것처럼, 리뷰어도 리뷰를 상세히 적어줄수록 저자에게 도움이 된다.

반복적인 패턴에 대해서 몇 가지만 대표로 피드백

개발자도 사람이기에 코드를 수정하다 보면 동일한 패턴의 실수가 발생할 수도 있다.

리뷰하다가 이런 경우가 있다면 모든 경우에 리뷰를 작성하지 말고 그런 패턴에 대해 2~3개 정도만 언급해주거나, 그 패턴에 대해 수정을 요구하는 리뷰를 남기도록 하자.

했던 말 자꾸 하면 하는 사람도 힘들고 듣는 사람도 힘들다.

교착상태 해결

발생하지 않는 게 좋지만 코드리뷰도 대화이다 보니 서로 의견이 대립되어 의견 수립이 되지 않는 교착상태가 발생할 수 있다.

일반적으로 아래와 같은 징조가 보이면 교착상태로 갈 수 있는 확률이 크기 때문에 주의하자.

  • 토론의 톤이 팽팽해지고 공격적으로 됨
  • 리뷰 라운드당 코멘트 수가 줄어들지 않음
  • 너무 많은 코멘트에 저항이 보임

교착상태가 발생했다면 잘 해결하는 게 중요하다. 계속 같이 일할 동료인데 해결이 원활히 되지 않는다면 서로 리뷰하는 기회가 줄거나 사라지게 되어 소스코드의 품질을 높이는데 문제가 생길 수도 있으며, 최악의 경우 어느 한쪽이 퇴사하는 일이 발생한다.

 

우선, 화상이든 회의든 만나서 얘기해본다.

앞서 얘기한 내용 중 글은 감정을 담기 힘들어 오해할 여지가 있다고 했었다. 이런 오해가 원인이라면 만나서 얘기해보는 걸로 대부분 해결된다.

 

만나서 얘기해도 해결될 기미가 보이지 않는다면, 내키지 않더라도 인정하는 방법도 있다.(Agree to disagree)

어떤 의견이든 문제가 되지 않는다면, 나의 의견을 양보하고 상대방의 의견을 존중해주어 해결할 수도 있다.

다만, 상대방에 대한 감정이 좋지 않아 의견을 피하려고 무심코 의견을 수용하다 보면, 저수준의 코드를 적용하는 경우가 발생할 수 있으므로 주의할 필요는 있다.

 

위 방법들을 사용할 수 없다면, 상급자인 팀장이나 테크 리더에게 요청하거나 다른 리뷰어를 할당하자.

그리고 관리자와 충분히 얘기하여 서로의 관계가 회복될 때 까지는 서로 PR을 하지 않는 등의 서로 간의 감정 휴식기간을 가지도록 해보자.


  1. Photo by Mr. Bochelly [본문으로]
  2. Photo by Mr. Bochelly [본문으로]
  3. 로버트 C. 마틴. 「클린 아키텍처 소프트웨어 구조와 설계의 원칙」, page 9. [본문으로]
  4. 로버트 C. 마틴. 「클린 아키텍처 소프트웨어 구조와 설계의 원칙」, page 9. [본문으로]
  5. 로버트 C. 마틴. 「클린 아키텍처 소프트웨어 구조와 설계의 원칙」, page 8. [본문으로]
  6. 로버트 C. 마틴. 「클린 아키텍처 소프트웨어 구조와 설계의 원칙」, page 8. [본문으로]
  7. Kadry, Seifedine. (2012). On the Improvement of Cost-Effectiveness: A Case of Regression Testing. Advanced Automated Software Testing: Frameworks for Refined Practice. 68. [본문으로]
  8. Kadry, Seifedine. (2012). On the Improvement of Cost-Effectiveness: A Case of Regression Testing. Advanced Automated Software Testing: Frameworks for Refined Practice. 68. [본문으로]