해당 파트에서는 마이크로서비스를 설계하는 것에 초점을 맞춰서 설명하고 있습니다.
초기에 설정할 수 있는 작업들에 대해서 다루고 있습니다. 간단하게 정리하고 넘어가겠습니다.
먼저, 마이크로서비스를 설계할 때 서비스에 대한 적절한 수준의 세분화(granularity)를 어느정도로 할 것인가를 결정하는데 어려움을 겪는 경우가 많습니다.
올바른 세분화 수준에 대한 정답을 구하려고 다음 개념들이 설명되어 있습니다.
그렇다면 적절한 크기인지 확인하는 방법은 무엇이 있을까요?
먼저, 너무 큰 마이크로서비스는 다음 징후가 있습니다.
너무 작은 서비스는 다음 징후가 있습니다.
서비스의 인터페이스는 직관적이어야하고 개발자는 애플리케이션의 서비스 중 한두 개를 완전히 이해함으로써 모든 서비스가 어떻게 동작하는지 규칙을 습득해야 합니다.
일반적으로 다음 지침을 참고할 수 있습니다.
여기서 대부분의 경우 1, 2, 3번은 잘 적용한다고 판단을 합니다. 실제로 제가 프로젝트를 진행할 때도 3개는 필요성에 대해 느끼고 팀원들과 회의를 통해 적용해 나갔습니다.
물론, 완벽하게 적용한 것은 아닐테지만 프로젝트를 진행하면서 크게 문제된 부분 없이 마무리가 되었습니다.
하지만, 4번의 경우 결정 과정에서 사실 혼동도 있었고 고민 끝에 결정을 한 방식이 결국 잘못된 방식이였어서 수정을 몇 차례 했습니다.
간단하게 말하자면, 4번에서 혼동이 온 이유는 "Custom Status Code" 즉, "Error Code"의 용도 때문입니다.
대부분의 Reference(블로그)에서 Error Code를 사용하고 있습니다.
Error Code의 목적은 상태 코드가 추상적인 경우가 많기 때문에 상황에 맞게 좀 더 구체적으로 사용하기 위해 Error Code를 사용합니다.
상태 코드를 단순하게 설정하여 통일성 있는 로직을 만들고 분기점 작업 처리를 쉽게 하려고 했습니다. 예외에 대한 처리는 예외 코드만을 활용하여 처리를 하고 성공 응답 코드는 복잡하게 상태 코드를 활용할 필요가 없다고 생각했습니다.
하지만 서버 간의 통신을 하기 위해 RestTemplate의 기능 구현 도중 예외 처리 응답을 처리하기 위한 로직을 구현하고 있었는데, 문제가 생겼습니다.
RestTemplate의 경우 실패 상태 코드(4XX, 5XX)가 날라올 경우 내부 로직에서 예외를 던지게 됩니다. 이 과정은 body의 데이터가 디코딩되기 전에 수행됩니다.
이것은 사실 타당한 로직인데, Client가 호출한 Server에서 예외가 발생하여 보낸 Response는 body를 담아 보낼 필요가 없고 body를 담아서 보내게 된다면 그것은 무언가를 Client에게 알리기 위함이 있어야 합니다.
즉, 목적이 있어야 하는데 그 목적은 예외 코드의 목적과 동일할 것입니다. 즉, 예외 응답이 날라왔을 경우에 Client 서버에서 예외 처리 분기 로직이 필요로 하다면 예외 코드가 필요할 수도 있을 것 같습니다.
하지만, 그 경우를 제외하고는 예외 코드는 사실 필요로 하지 않고 "상태 코드"만을 활용해도 충분합니다.
예외 코드를 활용하는 것도 신중하게 고민을 해서 결정을 해야되는 부분입니다. 클라이언트에게 예외 코드를 주는 것만으로도 보안 취약점이 될 수 있다는 것을 명심해야 합니다. 가능하다면 클라이언트에게 추상적으로 응답을 보내주는 것이 좋은 것 같습니다.
📌 TIP: 왜 마이크로서비스에 JSON을 사용하는가?
- 매우 가볍다.
- 사람이 읽고 사용하기 쉽다.
- REST 기반 애플리케이션에 적합하다.
참고로 서버 호출 간 전송할 데이터의 크기를 최소화할 필요가 있다면 바이너리 프로토콜도 고려해보는 것도 좋다고 합니다.
이후에는 서비스에 국제화 추가하기와 스프링 HATEOAS 구현이 나옵니다.
국제화 추가하기는 그다지 어려운 내용이 없어서 넘어가고 스프링 HATEOAS 구현에 관련된 내용는 REST API와 엮어서 다른 페이지에서 정리를 할 예정입니다.