deVlog

[항해 플러스 백엔드 6기] 챕터2(3주차 ~ 5주차) 서버구축 회고 본문

Study/항해플러스 백엔드 6기

[항해 플러스 백엔드 6기] 챕터2(3주차 ~ 5주차) 서버구축 회고

은루밍 2024. 10. 25. 00:03

목차

     

     

     📄 개발 전 설계 문서

    항해를 하면서 Mock API와 시퀀스 다이어그램을 처음 적용해봤다. Mock API는 처음 접하는 개념이었고, 시퀀스 다이어그램은 알고 있었지만 실무에서 많이 적용해본 적은 없었다. 서버 구축을 시작하며 시퀀스 다이어그램을 그리기 시작했을 때, 생각보다 시간이 오래 걸렸다. “이걸 실무에서 할 시간이 있을까?”라는 고민도 들었다.

     

    시퀀스 다이어그램을 작성하면서 든 생각은 아래와 같다.

    • 시퀀스 다이어그램을 작성하는 과정에서 코드 구현이 자꾸 떠오르며, 코드 구현을 그림으로 나타내는 느낌이다. 세세한 코드 구현을 다이어그램으로 표현하는 것이 맞는지, 아니면 더 추상적으로 작성해야 하는지 모르겠다..
    • 시퀀스 다이어그램에서 모든 에러 사항을 표현해야 하는지, 아니면 정책 관련 비즈니스 에러 같은 중요한 에러만 다루는 것이 맞는지

     

    지금 와서 생각해보면 코드 구현이 떠오를 수 밖에 없는 건 당연한 것 같고, 너무 세세하게 작성하는 것보다는 간소화해서 작성하는게 더 나은 것 같다는 생각이 든다. 그리고 모든 에러 사항을 다루는 것보다는 주요한 비즈니스 에러만 표현해도 충분할 것 같다. 

     

    시퀀스 다이어그램을 작성하면서 너무 코드를 생각하게 되어 내가 지금 설계를 하는 건지, 코드를 머릿속으로 작성하는 건지 계속 헷갈렸다. 설계에 익숙치 않아 시간이 많이 걸렸던 것 같다. 하지만 4, 5주차에서 코드를 구현할 때 이 시퀀스 다이어그램이 큰 도움이 됐다. 다이어그램에 그려진 대로 코드만 구현하면 됐으니까! 아, 이래서 설계 문서를 작성하는구나 하고 체감하게 됐다. 설계 문서를 남기지 않고 진행하다보면 구멍도 많이 생길 것 같고, 문서화가 안 되니 “왜 이렇게 했지?”라는 고민과 정리 좀 해놓을 걸.. 이라는 후회가 계속될 것 같다. 앞으로는 설계 문서를 좀 더 세세하게 정의할 수 있도록 노력해보려 한다.

     

    Mock API의 경우, 항해에서 배운 것을 지금 회사에서 새로 하는 프로젝트에 적용해봤다. 프론트엔드 개발자들과 인터페이스를 먼저 정의하고 Mock API를 미리 제공하는 방식으로 진행했다. 아직 피드백은 받아보지 못했지만, 받게 된다면 다시 글을 써보려고 한다. 어쨌든 배운 걸 바로 적용하니까 뿌듯했다. 그동안 API는 개발 후 마지막에 주는 걸로 해서 빨리 개발해야 한다는 부담감이 있었는데, Mock API를 먼저 제공하니까 그 부담감이 덜어진 것 같다.

     

     

    🌻 RestFul 한 API 설계 해보기

    이 부분에 대해 많이 고민했었다. RestFul하게 API를 설계하려면 어떻게 해야 할까?

    현업에서도 이 부분은 많이 지키려고 노력하고는 있는 중이다. API 를 설계하면서 코치님께 질문드렸던 내용은 아래와 같다.

    • API 를 최대한 restFul 하게 작성하려 했습니다. 작업을 하면서 각 자원을 어디에 위치해야 할지가 고민이었습니다.
    • 자원 표현 방법
      1. path 에 포함한다.
      2. query parameter 에 포함한다.
      3. requestBody 에 포함한다.
    • 자원을 나타낼 때 선택하는 기준이 있으신가요?? GET 의 경우 1, 2번 방법만 가능한데, 각각 적합한 경우는 어떠한 경우가 될까요?
    • POST  경우 무조건 RequestBody  포함이 되어야 할까요?

     

    답변해주신 내용은 아래와 같다.

    • 저는 GET 요청이더라도, 다양한 프로퍼티를 통해 요청 질의해야 한다면 이를 명시하고 의도적으로 POST 로 작성할 때도 많습니다. ( 예를 들면 뭐를 조회하는데, 쿼리에 필요한 다양한 요구사항을 수용하는 경우 )
    • GET 에서 RequestBody 를 사용안하는 게 표준이나, 리소스 위계로만 표현하면 API 가 종류별로 나와야하는 등 이런 점을 저는 좋아하지 않아서..
    • 특정 동작을 트리깅하거나, 별도의 리소스가 필요하지 않은 경우 POST  RequestBody  포함하지 않아도 됩니다. ( 이건 표준 )

     

    현업에서는 GET 요청에 다양한 프로퍼티를 통해 데이터를 전달하는 경우가 많은데, 이러할 때 의도적으로 POST로 작성할 때도 있으시다라는 답변을 받고 '그럼 이게 Restful한 API 라고 할 수 있을까?'라는 생각이 들었다. 물론 GET API에서 조건이 너무 많아지면 Request Body를 쓰고 싶을 때도 있지만, 결국은 취향 차이인 것 같다. 그리고 이런 부분은 회사나 팀 내 문화나 규칙이 중요한 것 같다. 이 부분은 경험이 더 쌓이면 나만의 기준이 생기지 않을까 싶기도 하다!

     

    내가 작성한 API 스펙은 아래와 같다. 최대한 RestFul 하게 짜려고 노력했지만, 나중에 보면 마음에 안들겠지..?

     

     

     

    🕵🏻‍♀️ 서블릿 필터와 스프링 인터셉터의 차이는 뭐고 언제 사용을 해야하지?

    이번에 필터와 인터셉터를 구현하면서 평소에 궁금했던 부분이 좀 해소된 것 같다. 둘 다 API 요청 전후로 전역적으로 동작한다는 점에서는 비슷하지만, '비즈니스 로직은 어디에 넣어야 할까?'라는 부분에 집중하면 차이를 명확히 알 수 있을 것 같다.

    서블릿 필터(Servlet Filter)

    • Java EE에서 제공하는 기능으로, 요청과 응답 객체를 가로채어 사전 및 사후 처리를 수행한다.
    • 필터는 요청이 서블릿이나 JSP에 도달하기 전에 동작한다. 즉, 서블릿 컨테이너의 가장 초기 단계에서 요청을 처리한다.
    • HTTP 요청/응답과 관련된 기본적인 작업을 수행하는 데 유리하지만, 비즈니스 로직과 관련된 세부적인 처리에는 제약이 있을 수 있다.

    스프링 인터셉터(Spring Interceptor)

    • 스프링 MVC에서 제공하며 요청이 컨트롤러에 도달하기 전에 가로채어 전처리(PreHandle), 후처리(PostHandle), 완료 후 처리(AfterCompletion) 등을 수행한다.
    • 요청이 DispatcherServlet에 도달한 후, 실제 컨트롤러에 전달되기 전에 작동한다.
    • 스프링 MVC 구조 내에서만 동작하며, 비즈니스 로직에 밀접하게 연결되어 있다.
    • Spring의 HandlerMapping과 DispatcherServlet을 기반으로 하기 때문에, 인증, 인가, 권한 체크 등 비즈니스 로직을 간편하게 추가할 수 있다.

     

    내가 생각하기에 서블릿 필터와 스프링 인터셉터의 가장 큰 차이는 비즈니스 로직이 실행되어야 하는 위치를 이해하면 알 수 있는 것 같다.

     

    그렇다면 콘서트 대기열 토큰 검증은 어떤 방법을 선택해야 할까?

    대기열 토큰의 만료 기간 및 활성화/비활성화 상태를 검증하는 작업은 웹 애플리케이션의 보안 및 비즈니스 로직과 깊은 관련이 있다. 그래서 스프링 인터셉터를 사용하는 것이 적합하다고 생각한다.

     

    아래와 같은 이유로 인터셉터로 대기열 토큰을 검증하는 것을 구현했다.

    • 비즈니스 로직과의 통합: 대기열 토큰 검증은 애플리케이션의 비즈니스 로직에 깊이 연관되어 있다. 스프링 인터셉터는 컨트롤러와 직접 연관되어 있어서, 요청이 실제 비즈니스 로직에 도달하기 전에 필요한 검증을 수행할 수 있다. 이는 인터셉터의 주요 기능 중 하나로, 요청이 처리되기 전 사전 검증을 통해 토큰의 유효성을 확인할 수 있다.
    • 일관된 에러 처리: 스프링의 @RestControllerAdvice를 사용하면, 컨트롤러에서 발생한 예외를 일관되게 처리할 수 있다. 하지만 서블릿 필터에서 발생한 예외는 @RestControllerAdvice에서 처리되지 않으므로, 예외 처리 로직을 별도로 구현해야 한다. 반면, 스프링 인터셉터는 필터와 달리 스프링 MVC의 흐름 안에서 작동하므로, 예외처리를 보다 일관되게 관리할 수 있다.

     

    😎 테스트 코드 이제 좀 알 것 같다..!

    항해를 시작하기 전에는 테스트 코드 작성에 관심은 많았지만, 어떻게 작성해야 할지, 어느 부분까지 테스트해야 할지 고민이 많았다. 테스트 커버리지를 높이는 것보다는 유의미한 테스트 코드를 작성하는 게 중요한데, 어떤 기준으로 해야 할지 몰랐다. 이번에 테스트 코드를 베이스로 과제를 진행하면서 그런 고민들이 많이 해소되었고, 테스트 코드에 대한 두려움도 많이 사라졌다.

     

    코치님들과의 멘토링을 통해 나만의 테스트 코드 작성 규칙도 정의해보았다.

    1. 도메인에 대한 테스트 코드는 기본이다.
    2. 비즈니스 로직이 있는 경우에만 단위 테스트를 작성한다.
    3. 단위 테스트를 많이 작성하자.
    4. 테스트는 각각 독립적으로 실행될 수 있어야 하며, 서로 영향을 주어서는 안 된다.
    5. 시간 관련된 로직은 테스트 작성이 편리하도록 파라미터로 주입받도록 하자.
    6. 레포지토리는 단위 테스트 하지 않는다. (DB 의존성이 있으므로, 단위 테스트는 의미가 없다)

     

     

    시간이 지나면 더 추가될 것 같지만, 지금은 이 규칙을 바탕으로 하고 있다. 멘토링에서 @DirtiesContext나 TestConfig를 사용하는 대신, 파라미터로 받는 방식을 선호하신다는 피드백도 받았다. 그 이유는 @DirtiesContext와 TestConfig를 사용하면 애플리케이션 캐싱을 재활용할 수 없어, 매번 테스트 실행 시 리소스를 더 많이 소모하게 되기 때문이다. 그래서 파라미터로 값을 주입받는 방식이 더 효율적이라고 하셨다. 이런 점을 고려해서 다음 작업에서는 더 개선된 테스트 코드를 작성해보려 한다.