Dog-Foot-일기

API 개발자는 갑인가?

JumBack2 2024. 10. 30. 18:07

오늘의 주제

 

최근에 코드 리뷰 중 나왔던 주제를 공유해보려고 한다.

우선 클릭 아키택쳐를 기반으로 설계를 하였고, 레이어 관계에 대한 룰을 의논하면서 부딪친 내용이다.

 

우선 기본적인 질문을 하고 가자. API 개발자는 갑인가? 라는 질문이다.

 

어떤 선배는 말했다. 개발자가 갑이다. API 제공자의 의도에 따라가야 된다.

예를 들어 네이버 로그인 API를 사용할 때, 내가 사용하는 방식에 따라 바꿔달라고 요청할 수 없지 않은가?

 

또 다른 선배는 말했다. 그래도 오픈 API가 아니라면 협업 단계에서 유연하게 대처할 수 있다고 생각한다.

 

수 많은 오픈 API가 이미 인터넷 상에서 지원 되고 있다.

그러나 꼭 오픈 API만 있는 것이 아니다. 각 회사나 필요에 의해 만들어진 프라이빗한 API들도 존재한다.

 

그렇다면 API를 개발 할 때 개발자는 어떤 것들을 고려하고 API를 설계할까?

 

자 그럼 우리는 이제 이 주제에 대해 생각해보자.

 

모놀리식 페이지를 3 Tier 구조로 마이그레이션

 

기본 회사에서 웹 어플리케이션을 마이그레이션 작업을 시작하였다고 가정하자.

 

기존에는 MVC 패턴의 모놀리식 페이지라서, 단일 어플리케이션에서 웹 서비스를 지원하고 있었다.

그러나 3 계층 구조로 변경하면서 레이어가 프레젠테이션 레이어와 비즈니스 레이어로 바꾸는 작업을 한다고 생각해보자.

 

 

 

 

비즈니스를 담당하는 API서버는 클린 아키택처 구조를 사용한다.

 

API의 내부는  진입점을 담당하는 API(Controller 레이어) 레이어와  어플리케이션(비즈니스 레이어) 레이어, 인프라 레이어, Domain 레이어 로 나뉘어 진다 가정하자.

 

 

 

물론 구조가 바뀌었으니 새로 개발해야 하지 않냐는 나쁜 말은 하지 않기로 하자.

기존 로직을 변경하면 테스트나 QA에 리소스가 더 많이 들게 되기 때문이다.

 

API 레이어와 Application 레이어의 관심사 분리 

클린 아키택쳐의 개념대로 만든다면 

고수준의 레이어는 저수준의 레이어를 참조하지 않도록 해야하며 모든 의존성은 바깥에서 안 쪽으로 향해야 한다.

이유는 저수준의 레이어는 언제든 갈아껴질수 있어야 하기 때문이다.

 

예를 들어 지금은 API 레이어가 Rest API로 만들어져서 사용하나 필요에 따라 GRPC 통신이나 다른 호출 방법의 API로 언제든지 변경할 수 있어야 하기 떄문이다. 

 

API 레이어에는 지극히 단순한 Application의 호출만 존재하여야 한다.

어플리케이션  레이어에도 간단한 분기와 인프라와 도메인 호출이 존재하여아 하고 모든 메인 비즈니스는 DDD의 관점으로 도메인으로 올려보내야 하지만 그 이야기 까지 하면 길어지니 여기선 이야기 하지 않겠다.

비즈니스 로직은 어플리케이션 레이어에 있다고 생각하자.

 

문제는 기존 코드를 새로 만드는 개념이 아니기 때문에 최소한의 변경으로 마이그레이션을 한다는 것이다.

기존 코드에는 컨트롤러에 모든 비즈니스 로직과 View 관련 로직이 함께 있다.

 

비즈니스 코드는 잘 발라서 어플리케이션으로 옮겨놨지만

컨트롤러에는 어플리케이션의 응답 결과에 따라 뷰의 분기나 메시지 분기 코드가 존재한다. 

 

//Controller

if (login.경고 != null)
    return Ok(
        code: "1111", 
        message: "경고", 
        new {
            AccessToken = login.토큰,
            Reason = login.경고.Contents,
            Date = login.경고.RegDate
        });

if (login.상태 == 휴면)
    return Ok(
        code: "3333", 
        message: "휴면",
        new {
            AccessToken = login.토큰
        });


if (login.상태 == 비밀번호필수변경)
    return Ok(
        code: "5555", 
        message: "비밀번호 변경 필수",
        new
        {
            AccessToken = login.토큰
        });

if (login.결과 == 성공)
    return Ok(
        new
        {
            AccessToken = login.토큰
        });



throw new Exception("로그인 실패");

 

 

그럼 해당 뷰 메시지 분기 로직이 Controller에 존재하는 것이 맞는가?

아니면 분기도 비즈니스 로직이니 어플리케이션으로 올라가야 하는가?

아니면 UI적인 정보는 API 서버의 관심사가 아니니 클라이언트 서버로 내려주고 책임을 회피할 것인가?

그런데 그렇게 되면 API는 결과 모델을 그대로 내려줄 것인가?

그렇게 된다면 불필요한 데이터를 클라이언트 서버에 모두 주게 되고 그걸 회피하려면 다른 방법을 써야한다...

그러면 기존 코드를 또 고치거나 다른 DTO 추가 등을 고려해야 한다. 

 

 

 

아래는 팀원들끼리 논의한 생각들을 가볍게 정리해 보았다.

 

 

 

1. 해당 로직은 컨트롤러에 들어가야 한다 vs 어플리케이션으로 가야 한다. vs 프론트로 가야 된다.

  • 서버로 가야 한다
    • 프론트가 알아서 분기를 처리해야 한다.
    • 앱의 경우 서버가 수정되는 문제보다 클라이언트가 수정되면 심사를 다시 받아야 할 수도 있다.
    • 공용 API가 아니고 프론트의 부담을 덜 수 있다.
      • 컨트롤러에 들어가야 한다.
        • 이유는 저수준의 다른 모듈(ex:GRPC 컨트롤러)로 바뀌었을 때 UI의 분기까지 필요하지 않다.
        • 관심사 분리가 되어야 한다.
        • 앱에서도 사용할 경우 커맨드(어플리케이션)를 더 만들어야 한다.
      • 어플리케이션으로 가야 한다. 
        • 결국 분기도 비즈니스 로직이기에 컨트롤러는 비즈니스 로직을 피해야 한다
        • 기본 로직에 최대한 가깝게 유지할 수 있다. (오류 가능성 적다.)
  • 클라이언트 서버로 가야 된다.
    • 오로지 뷰를 위한 로직이다. 서버가 알 필요가 없다.
    • 프론트의 입맛대로 바꾸기 용이하다.
    • 서버의 관심사 분리로 부담이 덜어진다.

 

 

2. 컨트롤러에 여러 분기가 생겨도 된다 vs 그냥 통채로 줘야 한다.

  • 분기가 생겨도 된다.
    • 불필요한 데이터 없이 좁게 줘야 한다.
  • 통채로 줘야 한다.
    • 컨트롤러에 비즈니스 로직이 많아지면 곤란
    • 테스트 코드 작성에 어려움
    • 관리 포인트 많아짐

 

등등 여러 의견이 나왔다.

 

어떻게 하면 좋을까?

 

모든 것에 대응되는 은탄환은 없겠지만 확실한 건 API 개발자도 개발 의도에 다양한 고민을 담을 것이라는 거다.

한번 정해진 API는 약속이기에 변경되기가 어렵다.

 

물론 API 정의서를 확실히 만들고 설계대로 만드는 프로젝트라면 커뮤니케이션 리소스가 절약 될 수 있겠지만

그런 이상적은 프로젝트 보단 시간에 쫓기는 프로젝트를 진행하는 회사가 더 많을 것이다.

 

클라이언트 측에서 개발을 하다보면 API 개발자가 이렇게 만들면 더 좋겠다는 생각이 들 때가 있다.

어디까지 요청을 하고 어떻게 설득할 수 있을까?

 

어떤 근거를 들어야 개발자의 의도를 비틀 수 있을까?