개발 회고: 테스트와 코드 리뷰에 대해서

프로덕트 사이클이 한 번 끝나면서 이번 사이클에서 부족했던 부분을 회고해보려고 한다. 그리고 어떻게 하면 개선할 수 있을지 대해서 정리해보려고 한다.

테스트

다양한 상황 테스트

여기서 말하는 테스트란 코드로 작성된 유닛테스트, 통합테스트를 말하는 것이 아니다. 유닛테스트와 통합테스트는 당연하게 작성해야한다고 마인드를 가져야한다.

그런데 시간 문제 때문에 모든 상황에 대해서 테스트 코드를 짜는 것은 상당히 힘들다. 그래서 핵심 로직에 대해서 테스트 코드를 짜는 경우가 많은데, 이 마저도 모든 예외 상황에 대해서 테스트 코드를 짜는 것은 상당한 노력이 필요하다.

여기서 상당한 노력이란, 시간 문제뿐만아니라 ‘이 정도면 괜찮겠지’라는 순진한 생각을 떨쳐내는 것을 포함한다.

그래서 기본적으로 테스트 코드를 작성하고나면 실제로 돌려보면서 잘 돌아가는지 확인해보는데, 이러한 과정도 테스트 케이스를 작성하는 것만큼이나 중요하다.

실제로 돌려보는 과정에서 중요한 것은 다양한 상황에 대해서 테스트를 하는 것이다. 이번에 프로덕트를 만드는 과정 중 테스트와 관련해서 반성할만한 상황이 몇 가지 있었다.

가장 기본적인, 그런데도 그것을 지키지못해 너무 부끄러워졌던 상황을 꼽자면 다양한 인자에 대해서 테스트를 못해본 것이다.

API를 변화하는 요구사항에 따라 조금씩 여러번 고쳐나갈 때가 있었다. 그 중 어떤 엔티티를 생성하는 API가 있었는데 그것을 생성하기 위한 JSON body 데이터는 100줄이 조금 넘었다. 그래서 너무 부끄럽지만 고백하자면 시간이 지날수록 잘되는 상황에 대해서만 테스트를 했었다. 이전에 모든 경우에 대해서 테스트해서 통과했던 기억으로 ‘지금도 잘될거야’라는 너무 순진한 생각을 했다.

융통성을 가져야하겠지만 git diff에 꽤 변화가 보인다면 꼭 모든 상황에 대해서 테스트해보자. 그래야 다른 사람한테도 ‘요구사항에 맞춰 다 수정했다’고 자신있게 말할 수 있다. 빨리 만드는 것도 좋지만 안전하게 만드는게 더 중요하다. 너무 기본적인 것이지만 자꾸 빨리하고 다음으로 넘어가려는 본성때문에 이 원칙이 잘 지켜지지 않을 때가 있다. ‘잘 될거야’라는 말은 진짜 하지 말자.

스트레스 테스트

예외 상황이 발생했을 때 잘 죽고, 잘 복구되고 다양한 상황에서 기본적인 기능들이 제대로 동작한다면, 스트레스 테스트는 꼭 해보자.

예를 들어 Kubernetes pod에 어떤 서비스를 얹어서 클라이언트에게 제공한다면 어느 정도 커넥션을 감당할 수 있는지 확인해보는 경우가 있을 것이다. 혹은 클라이언트마다 pod이 뜬다면 현재 production cluster에 몇 개의 pod이 뜰 수 있는지 확인해보는 것이 있을 수 있다.

어느정도 부하를 감당할 수 있는지 파악하고 있어야 나중에 사용자 수에 따라서 필요한 대처를 할 수 있다.

위에서 얘기한 것이 부하의 강도에 대한 것들이라면 이에 못지않게 중요한 것은 서비스를 한 번 띄웠을 때 오래동안 별 문제 없이 살아있느냐도 확인해볼 필요가 있다.

대부분의 경우 개발과정에서는 ‘오랫동안 무언가를 한다’는 것에 대해 테스트를 하지 않는다. 그래서 잠깐 동안 모든 기능들이 제대로 동작하는 것이 길게도 가능한지 한 번 확인해볼 필요가 있다.

이번 사이클에서는 어떤 경우에 클라이언트와 30분마다 소켓 연결이 끊어져서 애먹은 경우가 있었는데 이런 테스트가 없었다면 모든 게 정상적으로 동작한다고 생각했을 수도 있다. 예전에는 정상적으로 동작하는 것처럼 보이는 시스템이 며칠 뒤에 뻗었는데 살펴보니 로그 파일을 관리하는 프로그램이 제대로 동작하지 않아 로그 파일이 디스크를 모두 차지했기 때문이다.

중요한건 마음가짐

여기서 말하려고하는 ‘테스트를 꼼꼼히 하자’는 것은 분명 머리로는 알고 있는 것이고 말하는 것에서 그치면 아무런 소용이 없다. 몇 개의 원칙을 가지고 그것을 마음 속에 단단히 집어넣는 것이 더 중요할 거 같다.

코드 리뷰

이번 프로덕트 사이클에서 테스트만큼 많이 했고 아직 많이 부족하다고 느낀 것들 중 하나는 다른 사람의 ‘코드 리뷰’라고 생각한다. 카카오 리뷰 에 나온 글에서도 공감가는 부분이 많았고 리뷰하는 방법에 대해서도 배울 점이 많았다.

이번 회고글에서는 아직도 많이 부족한 점이 많지만 ‘다음 번에 리뷰를 이렇게 하면 좋겠다’라는 것들에 대해서 적어보려고 한다.

코드 리뷰에 대해 느꼈던 것은 코드 리뷰에 여러 계층이 존재한다는 것이다. 정말 간단한 변수명, 함수명에서부터 전체적인 시스템 관점에서의 리뷰가 있을 수 있다.

초반에는 어떤 것을 리뷰해야할까에서부터 명확한 기준이 서있지 않아 리뷰가 부족했거나 빠뜨린 부분이 있었다. 그래서 이번 회고에서는 코드 리뷰를 할 수 있는 여러 가지 면들에 대해서 정리해보려고 한다.

  • 코드 관점: 변수명, 함수명, 코드 컨벤션, 테스트 코드 유무와 같은 코드의 기본적인 것들
  • 기능 관점: 작성한 코드가 현재 도메인 지식에 맞춰서 제대로 동작하는가?
  • 아키텍처 관점: 현재 이 모듈이 여기 있어도 괜찮은가? 모듈 사이의 의존성, 관계

코드 관점

코드 관점 리뷰 같은 컴포넌트를 작업하는 팀의 개발자가 아니더라도 할 수 있는 리뷰이다. 변수명, 함수명의 경우도 봐야하는 코드와 알아야하는 지식이 클래스를 벗어나지 않기 때문이다. 파일 맨 위에 라이센스를 추가해달라, 테스트 코드를 추가해달라 모두 이에 포함되는 관점이다.

기능 관점

기능 관점은 코드 관점과는 다르게 해당 컴포넌트의 도메인 지식이 필요하기 때문에 다른 팀의 개발자가 기능 관점에서 리뷰를 하는 것은 어렵다. 기능 관점에서는 코드가 예쁘게 짜여졌더라도 컴포넌트들이 디테일한 요구사항에 맞춰서 동작하는지를 확인해야한다.

아키텍처 관점

아키텍처 관점은 기능 관점과는 또 느낌이 다르다. 기능 관점에서는 말 그대로 기능이 어떻게 동작해야한다는 디테일한 부분을 알고 있어야 리뷰를 할 수 있지만 아키텍처 관점에서는 좀 더 거시적으로 이 컴포넌트가 전반적으로 어떤 동작을 해야한다는 것을 알고 있으면 리뷰를 할 수 있다.

나의 코드 리뷰는 어땠나

코드 리뷰 관점을 위와 같이 세 가지로 구분 했을 때 이번 사이클에서 나의 코드 리뷰는 ‘기능 관점’에서 많이 부족했던 것 같다. 코드 관점과 아키텍처 관점에서만 보고 괜찮다고 생각하여 pull request approve를 했는데 다른 사람이 기능 관점에서 코멘트를 했을 때 아차했고 모든 부분을 보지 못했다고 생각하여 부끄러운 마음이 들었다.

기능 관점에서 좀 더 리뷰를 잘하기 위해서는 시시각각 변하는 요구사항을 잘 캐치하고 기억해야한다. 어쩌면 이 부분은 프로덕트에 대해 문서화를 잘하는 것과 관련이 있을 수도 있다. 혹시 잘 기억이 안나거나 내가 도메인에 대해서 잘 모르는 경우에는 pull request를 올린 사람에게 ‘이 기능을 구현한 것이 맞냐’라고 물어볼 수도 있다.

마치며

‘다양한 상황 테스트하기’의 경우 머리로는 분명 알고 있었다. 그런데 ‘터지면 어쩌지’라는 불안감, 근거 없는 자신감 등 심리적인 요소에 의해서 많이 빠뜨렸던 것 같다.

‘코드 리뷰’의 경우는 ‘어떤 것을 리뷰해야 될까’라는 것에 대해서 고민을 많이 했던 것 같다.

이번 프로덕트 사이클 회고를 정리하면 다음과 같다.

  • 조급해하지말고 다양한 상황들에 대해서 꼭 통합테스트를 해라
  • 안될 거 같은 상황을 꼭 테스트 해라. 안되면 고치면 된다. 잘못된 게 아니다.
  • 기능 관점에서 코드 리뷰를 더 잘하기 위해서 해당 컴포넌트 도메인을 정확하게 알고 있자.