회고록/주간 회고

10월 2-3주차 회고

Woonys 2022. 10. 24. 02:10
반응형

Introduction

지난 주 카카오 화재 사건으로 티스토리까지 먹통이었다. 이를 변명삼아 복구되면 2주차 써야지..하던 게 결국 3주차 회고에 얹어서 쓰게 됐다. 이를 더 깊이 파고들어보면, 원인은 회고를 쓸 때마다 "이거 언제 다 쓰나.."하는 부담이 생기기 때문이다. 이를 위해서라도 회고글은 최대한 짧게 쓰는 것을 기본 원칙으로 삼아야겠다.

 

이번 회고부터 큰 변경사항 하나가 추가됐다. 바로 기존 프레임워크였던 KPT(Keep/Problem/Try) 회고에서 → KLT(Keep/Learn/Try) 회고 프레임으로 변경한 것. 회사에서는 이슈가 발생한 것이니 Problem을 써도 별 이상하지 않지만, 개인 관점에서 Problem을 쓰면 "난 늘 문제가 있는 사람"이라는 프레임이 알게 모르게 발생한다. 별 거 아닌 것 같아보여도 프레임 관리가 늘 중요하다. 예컨대 똑같은 로스쿨 1년차이더라도 "앞으로 나는 2년이나 수험생활이 남은 로스쿨생이여..."와 "난 2년 후 프로 무대에 설 예비 변호사다"라는 관점은 천지차이다. 하나는 학생이고, 다른 하나는 예비 프로이기 때문. 이는 개인의 에너지에도 영향을 끼친다. 생각해보면 학생의 에너지가 좋을까, 아니면 프로의 그것이 월등할까? 관점 관리는 늘 중요하기에 Problem이라는 워딩을 Learn으로 바꾸기로 했다.

 

Keep

데일리 리포트 작성

업무 시간에만 작성하고 퇴근하고 나면 거들떠도 안 보지만, 일단 이렇게라도 시작한 게 어디인가. 계속해서 관리할 수 있도록 하자.

스프링부트 실전 강의 시작

김영한님의 인프런 강의인 스프링부트 실전 강의를 시작했다. 사실 이쯤되면 다 아는 내용이다 싶지만, 이럴 때일수록 기본을 간과하면 안된다. 막상 강의 들어보니 제대로 모르고 쓴 것들이 천지였다. 항상 기본에 충실해야 한다. 기본 강의 꾸준히 듣도록 하자.

 

Message Queue 관련 튜토리얼 만들기 w/ Spring Boot

이전부터 Message Queue(MQ) 관련 기술을 다뤄보고 싶었는데, 마침 회사 테크톡 시간에서 Spring retry mechanism 구현 관련해서 이야기가 나와 정말 흥미롭게 들었다. 테크톡이 끝나고 밤 시간에, 이에 대해 다뤄볼 수 없을까 뒤적이다가 Spring 공식 가이드 페이지에 MQ 관련 튜토리얼 아티클을 발견한 게 아닌가! 신나는 마음으로 해당 튜토리얼을 학습했다. RabbitMQ는 도커 컴포즈로 띄운 뒤, 스프링부트와 메시지 큐 간에 통신으로 작업을 수행하는 튜토리얼이다. 당장은 코드만 짜둔 상태라, 공부하면서 ReadMe까지 작성할 예정. 이번에는 Spring Boot에서 제공하는 RabbitMQ 기술을 다뤘는데, 다음에는 Kafka 예제도 다뤄볼 작정이다. 너무 재밌겠다!!!!

 

예제 코드: https://github.com/woonys/blog-code/tree/SpringBootExample/SpringMessagingWithRabbitmqExample

 

Learn

테스트가 가능한 코드를 짠다는 것에 대하여 (Feat. TDD 마려워지기 시작)

사수 분과 페어 프로그래밍 시간에 이전에 진행했던 PR에 대해 함께 진행해보자고 제안드렸다. 덕분에 1시간 내내 실컷 두드려 맞았다 ㅎㅎ (이것이 사랑의 맴매) 이때 드렸던 질문 중 하나가 테스트 코드였다.

사수 분께서 내가 짠 테스트 코드를 유심히 보더니 무엇을 위한 테스트인지에 대해서 심도 깊은 대화를 나눴다. 결국 내가 내린 결론은 "이제까지 짠 테스트 코드는 테스트를 위한 테스트였다..."는 것.

테스트란 무엇인가? 우리가 개발한 코드가 제대로 동작하는지 확인하기 위해 짜는 코드이다. 그렇다면 테스트는 무엇에 집중해야 할까? 질문이 잘못됐다. 그 이전에 우리는 요구사항이 어떻게 동작하는지부터 명료하게 생각해야 한다. 예컨대 client라는 엔티티 내에 해당 클라이언트를 불러오는 날짜를 저장하는 필드인 fetchedAt이 있다고 하자. 이 fetchedAt을 수정하는 updateFetchedAt() 메소드를 만들려고 한다. 해당 메소드의 요구사항은 아래와 같다.

 

/*
    테스트 하고 싶은 것: updateFetchedAt()를 호출했을 때 fetchedAt이라는 날짜 필드가 수정되는지
      	* fetchedAt이 수정되는지
        * DB 에도 저장되고,
        * JVM Heap 객체 안에도 저장
      clientService.updateFetchedAt()
       1. DB에서 client를 가져온다.
       2. 수정할 fetchedAt 날짜를 계산한다
          1) forceExpire : "현재 시간" 기준으로 "31일" 전
          2) !forceExpire : 인자로 받은 날짜 및 시간
       3. 기존 fetchedAt을 2에서 계산한 날짜로 수정한다.
       4. DB에 client를 저장한다.
 */

그렇다면 우리의 테스트 코드는 번호인 1-4 각각에 대해서 제대로 동작하는지 코드를 분리해서 짜야할 것이다. 그래야 단위 테스트로서 제대로 역할을 수행할 수 있을 것이다.

이전에 내가 짠 테스트 코드는 사실상 1-4를 한 테스트 안에 우겨 넣은 상태였다. 그러니 사실상 내부 단위가 제대로 동작하는지에 대해서는 디테일하게 확인할 수가 없던 것. 문제는 그렇다고 기존 코드를 갖고서 저렇게 나누려니 그것 역시 까마득하긴 마찬가지였다는 점이다. 이때서야 "TDD가 왜 필요한지" 깨달을 수 있었다. 꼭 테스트 먼저 짜는 것이 아니더라도, 테스트가 가능한 코드를 짠다는 것에 대해 무지했다는 것을 깊이 깨달을 수 있었다.

스스로 짜는 모든 코드를 이해하고 있어야 한다

이번 깨달음 역시 컸다. (그만큼 뼈 아프기도 했지만..) 문제는 2번 연속 동일한 짓을 저질렀다는 점이다.

 

첫 번째는 어노테이션이었다. 내가 만든 DTO에 @AllArgsConstructor와 @NoArgsConstructor 두 어노테이션을 달았는데, 문제는 왜 이 어노테이션이 필요한지도 모르고 스택 오버플로우의 말을 그대로 따랐다는 것. 대번에 지적당했다..

그 당시 @AllArgsConstructor, @NoArgsConstructor를 붙였을 때 왜 이 문제가 발생했는지를 먼저 체크했으면 바로 @Value를 붙이는 식으로 넘어갈 수 있었을 것. 어떻게 해결할 것인지를 고민하는 건 필요하지만 그 이전에 왜 이 문제가 발생했는지에 대해 고민할 필요가 있다. 이번 케이스는 어떻게? 만 고민했기 때문에 발생한 문제이다.

 

두 번째도 케이스만 다를 뿐 본질은 똑같았다. int array를 int Set으로 바꾸는 과정에서 스트림을 사용한 로직을 스택 오버플로우 검색을 통해 가져왔다. 문제는 이 스트림이 어떻게 구체적으로 동작해 array를 set으로 바꿔주는지에 대해 디테일하게 찾아보지 않았다는 것.

 

Set<Integer> intArrayToSet = IntStream.of(intArray).boxed().collect(Collectors.toSet());

 

한 번은 그럴 수 있다 쳐도 두 번이나 이러는 건..진짜 아니다. 엔지니어로서 가져야 할 마인드에 한참 벗어나있다. 기술적 스펙 맞추는데 급급하기만 하고 정작 비즈니스적으로 왜 이 작업을 해야하는지에 대해 근본적으로 생각하지 않는 엔지니어 마인드를 비판해왔던 나로서는, 정작 반대로 단기적 해결에만 급급하고 기술적으로 내부 원리에 대해 탐구하지 않는 것에 대해 까이는 것이 더욱 부끄러울 따름이다.

 

하지만 이번 회고부터 Problem을 Learn으로 바꾸지 않았나. 크게 배웠고, 앞으로는 이렇게 실수하지 말자. 내가 짜는 모든 코드를 이해해야 한다는 걸 명심하자. 반대로 이해하지 못한 코드는 절대 갖다 써서는 안 된다. 향후 유지보수 관점에서 큰 문제를 야기할 수 있기 때문. 나 혼자만의 프로젝트가 아님을 명심해야 한다.

 

Try

  • PR 올리기 전에 체크리스트 작성: 내가 짠 모든 코드에 대해 설명 가능한가요?
반응형