코드숨 스프링 편 1주차 회고: 기본 HTTP API 만들기

Jake Seo·2022년 3월 27일
5

참고: 강의를 듣게 된 배경과 느낀점을 먼저 서술한 뒤에 구체적으로 어떤 것들을 피드백 받았는지 적었습니다. 코드숨 강의에 대해 간단히 느낀점만 궁금해서 들어오셨다면 위쪽 부분만 읽으시고 아래쪽은 무시하셔도 됩니다.

코드숨 강의를 듣게 된 배경

코드숨 과정은 포트폴리오 제작 과정까지 합쳐서 330만원이다. 누군가에게는 충분히 지불할 수 있는 돈이겠지만, 박봉을 받으며 일하는 나에게는 매우 큰 돈이다. 그럼에도 불구하고 코드숨 과정을 수강한 이유는 역시나 성장에 대한 갈증 때문이었다. 내가 현재 일하는 조직은 매우 작은 조직이며, 좋은 개발문화를 경험해본 사람이 없다.

나는 소위 네카라쿠배라 불리는 좋은 개발문화를 가진 회사에 입사해본 적이 없다. 코드 리뷰는 나에겐 유니콘처럼 먼 존재이며, 테스트코드 작성은 회사에서 나 외에는 하는 사람이 없다. 나도 그나마 테스트코드 작성 강의 영상을 보고 이것저것 따라하려 시도할 뿐, 제대로 하고 있는지는 모른다. 객체지향 설계, 좋은 코드, 설계에 대한 고민도 우리 회사에서는 현실과 동떨어져 있다.

과연 좋은 개발조직은 어떤 느낌일까? 너무 궁금해서 비싼 돈을 내고 코드숨 교육 과정을 듣게 되었다.

사실 비싼만큼 이 강의를 진짜 들어야할지 많은 고민을 하고 후기를 찾아보고 했는데, 결국 트레이너 중에 평소에 존경하던 개발자였던 종립님과 코딩의신 아샬님이 계신다는 것이 내 의사결정에 큰 영향을 미쳤다.

혹시나라도 코드숨 강의를 들을까 말까 고민하는 예비 수강생이 있을 수 있는데, 마지막 주차 때 내가 느낀 장점, 단점, 누가 들으면 좋을지에 대한 글도 정리해서 올리려 한다.

강의를 1주차까지 들으며 깨달은 것들

아직 1주차까지만 들어봐서 많은 깨달음을 얻지는 못했다.

작은 설계부터: 소프트웨어를 만들 때 내가 잘못 생각하던 부분을 깨달았다

위와 같은 커멘트를 받았는데, 내가 요즘 하고 있는 실수를 정확히 관통하는 이야기였다. 자기 개발을 위해 이것저것 강의를 보고 새로운 기술을 공부하고 난 뒤에 난 확실히 많은 기술들의 존재에 대해 인지하게 되었다. 그리고 그것을 실무에 적용시키려고 많은 노력을 했다.

그런데 때때로 내가 그 기술을 사용해보려고 마구잡이로 코드를 끼워맞추려고 할 때가 있었다. 장황하게 끼워맞추는 행위는 어쩌면 문제 해결이라는 소프트웨어의 본질에서 멀어지게 한다. 다음부터 이러한 실수를 하지 않도록 주의해야겠다.

동작하는 프로그램을 최소한의 설계로 만든 뒤에 지속적 리팩토링으로 소프트웨어를 개선해나가자.

테스트를 작성하는 습관을 들이는 게 확실히 이득이라는 것을 깨달았다

API 를 작성한 뒤에 Postman 이나 HTTPie 와 같은 도구로 계속 내 서버에 요청을 보내고 결과를 확인하는 나의 모습을 보았다.

사실 이건 애초에 요구사항을 받았을 때 해당 요구사항대로 테스트코드를 작성해놓았으면 굳이 서버키고 API 날려보고 눈으로 결과 하나씩 확인하고 할 필요가 없었던 것이다.

내가 작성할 프로그램의 동작 목표를 테스트라는 형태로 작성해두고 작성이 완료되었다면 테스트가 통과되는지 확인하는 식으로 프로그램을 작성해보자.

영어로 된 딱딱한 공식문서를 읽는 버릇을 빨리 들여야겠다는 것을 깨달았다

종립님이 해주신 말인데, '블로그에 글을 작성한 개발자는 나보다 더 초보개발자일 수 있다.'는 것이다. 종종 영어 읽기가 귀찮아서 한글로 검색하고 대충 작성된 글로 문제를 해결하려 하는 경우가 있는데, 번역기를 이용하더라도 공식문서 읽는 습관을 꼭 들여야겠다.

구체적 피드백들...

본격적으로 어떤 구체적 피드백들을 받았는지 정리해본다.

1주차 과제의 내용

  • 자바언어를 이용해 ToDo REST API 앱을 작성해야 한다.
    • HTTP Content 에 JSON 형식의 Input Output 을 통해 간단한 CRUD 를 제공한다.

과제에서 피드백 받은 것들

의도가 드러나지 않은 코드 리팩토링

try(OutputStream responseBody = exchange.getResponseBody()) {
    exchange.sendResponseHeaders(httpResponse.getStatusCode(), httpResponse.getContent().getBytes(UTF_8).length);
    responseBody.write(httpResponse.getContent().getBytes(UTF_8));
    responseBody.flush();
}
  • 위 코드에서 exchange.sendResponseHeaders(httpResponse.getStatusCode(), httpResponse.getContent().getBytes(UTF_8).length); 부분에서 갑자기 왜 length를 넘기는지 한 눈에 이해가지 않을 수 있다.
    • 그 외에도 .이 너무 많고 글자가 많아서 한 눈에 들어오는 코드가 아니다.
exchange.sendResponseHeaders(httpResponse.getStatusCode(), httpResponse.getContentLength());
responseBody.write(httpResponse.getContentAsByte());

HttpResponse 객체에 getContentLength() 라는 메서드를 만들어 코드의 의도를 좀 더 명확히 해주었다.

개발자는 보통 작성된 코드를 읽으며, 한줄 한줄이 어떤 의도를 가지고 작성되었는지 생각하는 과정을 거치고 자신의 코드를 적절한 위치에 삽입한다. 소위 말하는 '읽기 어려운 코드'를 작성할수록 협업과 거리가 멀어지고, 생산성도 떨어진다. 나 자신도 며칠 뒤에는 내 코드를 이해할 수 없는 상황을 맞딱뜨리지 말자.

switch 문에서 default 의 누락

switch... case문에서는 반드시 default를 작성해주자.

헷갈리는 메서드명

parseJsonToTaskparseTaskToJson는 이름이 매우 비슷하다. 헷갈리는 이름을 자제하고 의도를 좀 더 명확히하자. 위 경우에는 최종에는 getJsongetTask로 짧게 바꾸었다. from A to B와 같이 이름을 지을 필요가 없는 이유는 파라미터가 이미 from을 알려주고 있기 때문이다.

이 경우도 위와 마찬가지의 이유였다.

에러메세지 작성 방법

에러 메세지는 1. 무엇이 잘못된지 알려주고 2. 어떻게 해야 하는지 알려주어야 한다.

시그니쳐만 보고 알아보기 힘든 메서드

일단 여기서 지적받은 점은 함수가 무엇을 하는지 함수의 시그니쳐만 보고 이해하기 어렵다는 것이었다.

내가 처음 지었던 메서드 이름은 장황하게도 processPathVariablesTaskIdWithStrategy이다. 내가 이렇게 길게 메서드 이름을 짓게 된 이유는 메서드가 하는 일을 명확히 표현하는 메서드 이름을 짓고 싶어서였다.

그런데 메서드 이름이 이렇게 길게 나온다는 것은 한 메서드에서 가진 책임도 그만큼 많다는 뜻일 것이다. 모든 코드는 덩어리가 커질수록 이해하기 어려워진다고 믿는다. 그래서 적절히 객체, 메서드 단위로 관심사별 코드 분리를 해야 할 것이다.

해당 메서드 내부에는 많은 책임이 있었는데,

  1. 올바른 PathVariable 이 들어왔는지 검증한다.
  2. 올바른 PathVariable 이 들어왔다면, PathVariable 이 제공하는 taskId는 실제로 존재 하는지 찾아보고 없다면, 예외를 던진다.
  3. 해당 taskId를 이용해 Task 객체를 찾는다.
  4. 찾은 Task 객체를 이용해 Strategy에 따른 코드를 적용한다.
  5. 적용 결과를 HttpResponse로 반환한다.

간단히 살펴봐도 5가지나 책임을 가지고 있었다. 나중에 하나하나 잘게 분리하니 훨씬 알아보기가 쉬워졌다.

UPPER_SNAKE_CASE 에 대한 잘못된 사용

UPPER_SNAKE_CASE 는 멤버 필드 중 static final을 가진 경우에만 사용하는 것인데, 메서드 내부 final 변수에 UPPER_SNAKE_CASE 를 잘못 적용했다.

위는 오라클 공식문서에 있는 내용이다. 클래스 상수와 ANSI 상수에만 적용하라고 되어있다.

생성자에서 너무 많은 일을 한다.

생성자에 너무 많은 코드를 넣는 것을 피하자. final 로 된 멤버 변수들을 채우려다가 생성자를 너무 복잡하게 만들어버리는 우를 범했다.

일단 간단한 메서드명으로 의도는 명확히 정리해두었는데, 아직 답이 안달려 어떻게 해야하는지 정확히 모르겠다.

객체 내부에서 객체의 속성을 하나도 사용하지 않는 코드를 작성했다.

위 경우 사실상 해당 객체와 연관이 없는 코드일 수도 있으니 항상 주의해야 한다. 위의 코드도 어떻게 고쳐야 하는지 아직은 피드백을 받지 못했다.

객체 내부에서 객체의 속성을 하나도 사용하지 않는 코드는 응집도가 낮은 코드일 수 있으니 주의하자.

의존성을 추가하고 주석을 남기지 않았다.

profile
풀스택 웹개발자로 일하고 있는 Jake Seo입니다. 주로 Jake Seo라는 닉네임을 많이 씁니다. 프론트엔드: Javascript, React 백엔드: Spring Framework에 관심이 있습니다.

0개의 댓글