백엔드라는 바람에도 흔들리지 않는 나의 코드

NinjaJuunzzi·2022년 6월 15일
35

우아한테크코스

목록 보기
17/21
post-thumbnail
post-custom-banner

글머리

여러 UI 코드가 API 서버가 정의한 응답 스키마에 철저히 의존하고 있을 때 응답 스키마가 변경된다면? 우리는 모든 remote data 호출 코드를 조사해 수정해주어야 합니다. 이러한 강한 의존성으로 인해 유지보수가 힘들어 질 때 즈음 새로운 아이디어를 얻게 되었습니다. 본문은 이 새로운 아이디어를 코드로 풀어내는 내용을 담고있습니다. 재미있게 봐주세요.

동기

Remote Data를 요청할 때 우리는 다음과 같이 fetcher 함수를 만들어 요청하게 됩니다.

// caching 함수는 이해하지 않으셔도 됩니다. 리모트 데이터를 캐시하는 동작을 하는 코드구나 라고 생각해주세요

export const getProductList = () => {
  const cacheKey = `${API_URL}/products`;

  return caching((): Promise<any> => {
    return productAPI.get('');
  }, cacheKey);
};

GET /products endpoint에서 반환하는 응답 스키마는 다음과 같습니다.

이 경우 상품 데이터를 보여주는 모든 UI 코드에서는 다음과 같은 코드들이 작성될 것입니다.


const {
  data: { products },
} = await getProductList();

renderProducts(products);

이러한 상황에서 응답 스키마가 다음과 같이 변경된다면 ?

{
  productList: [
    {
      id: 1,
      name: '과자',
      price: 1000,
      stock: 20,
      imageURL: 'http....',
    },
    {
      id: 2,
      name: '소주',
      price: 2000,
      stock: 15,
      imageURL: 'http....',
    },
  ],
};

또는

{
  product: {
    list: [
      {
        id: 1,
        name: '과자',
        price: 1000,
        stock: 20,
        imageURL: 'http....',
      },
      {
        id: 2,
        name: '소주',
        price: 2000,
        stock: 15,
        imageURL: 'http....',
      },
    ],
  },
};

우리는 상품 데이터를 출력하는 모든 UI 코드들을 조사해 다음과 같이 코드 수정을 진행해야합니다.

const {
  data: { productList:products },
} = await getProductList();

renderProducts(products);

// or

const {
  data: { product:{list:products} },
} = await getProductList();

renderProducts(products);

상품 리모트 데이터를 출력하는 코드가 몇군데 없다면 문제가 되지 않지만 매우 많다면?
일일히 노가다 해주어야하기에 휴먼에러를 발생할 수도 있고, 개발 비용(시간적인)을 낭비할 수도 있습니다.

새로운 아이디어와 구현

모든 리모트 데이터 사용처에서 백엔드의 응답 데이터를 참조하게 하기 보단 하나의 중간 다리를 두어 응답 데이터를 프론트엔드 입맛대로 가공하여 조회하게 하는 것은 어떨까? 그렇게 한다면 API 서버의 response schema 가 변경되더라도 중간 다리만 수정하면 되니깐 유지보수에 용이하지 않을까?

이를 위해 가공하는 어떠한 함수 혹은 클래스를 만들어 호출하는 코드를 짜볼까 하였으나 axios API에는 이미 이러한 동작을 하게끔 하는 옵션이 있다.

axios 문서에 따라 response를 프론트엔드 단에서 수정하는 코드를 작성해보자면 다음과 같다.

// fetcher

export const getProductList = () => {
  const cacheKey = `${API_URL}/products`;

  return caching((): Promise<any> => {
    return productAPI.get('', {
      transformResponse: transformer[getProductList.name],
    });
  }, cacheKey);
};
// response transformer

export const transformer = {
  getProductList: stringResponse => {
    const parsedData = JSON.parse(stringResponse);

    if (parsedData.error) {
      return parsedData;
    }
   
    return parsedData.products,
  },
};

위 같이 코드를 작성하게 되면 모든 productList 데이터 사용처의 코드는 다음 코드로 통일되게 된다.



const {
  data: products,
} = await getProductList();

renderProducts(products);

remote data를 요청하는 프론트엔드 단의 코드는 백엔드의 응답 스키마가 변경되어도 바꿀 필요없는 굳건한 코드가 된다. (실제 백엔드의 응답 데이터를 조회하는 것이 아닌 프론트엔드 단에서 수정한 응답 데이터를 조회하게 되므로)

응답 스키마가 변경되어도 transformer 함수만 수정하면 되므로 유지보수에 훨씬 용이한 코드가 된다!! (👻👻👻)

결론

무수한 관중들의 박수..(zzz 그냥 슬랙에 올라와서 이모지 반응한 것일지도 모르지만..)

난 이런거에 설렘을 느끼는 사람인가보다.. 뭔가 마약같다고 생각하게된다.. 이러한 관심 속 설렘이 자꾸 새로운 생각을 하게끔 해준다.. 나는 관종인가부다..👻!

Reference

profile
Frontend Ninja
post-custom-banner

18개의 댓글

comment-user-thumbnail
2022년 6월 15일

와 진짜 좋은 글입니다! 일일히 ctrl + shift + f 눌러서 바꿔줬었는데 꿀팁 감사해요!

1개의 답글
comment-user-thumbnail
2022년 6월 18일

잘 보고 가용 ㅎㅎ

1개의 답글
comment-user-thumbnail
2022년 6월 18일

React Query 쓰고 Custom Hooks에서 관리 하면 더 생산성 있을 것 같네여

1개의 답글
comment-user-thumbnail
2022년 6월 22일

What if the API server's response structure changes and several UIs depend on it? waffle game

답글 달기
comment-user-thumbnail
2022년 6월 22일

글 잘 읽었습니다! 👻👻👻👻

1개의 답글
comment-user-thumbnail
2022년 6월 24일

잘 보고 가요~

1개의 답글
comment-user-thumbnail
2022년 6월 24일

준찌 잘 읽고 가요~! 이 얘기 슬쩍 꺼내는 걸 들었었는데 그 후로 이런 고민 과정을 거쳤다니 대단해요 ✨

1개의 답글
comment-user-thumbnail
2022년 7월 11일

미춌다 역시 준찌

저도 적용해보고 싶네여

답글 달기
comment-user-thumbnail
2022년 8월 10일

If something doesn’t work right away, don’t give up! It may take time, but if you keep trying, eventually it will work out just fine! nerdle

답글 달기
comment-user-thumbnail
2022년 9월 23일

잘 보고 갑니더 :)

답글 달기
comment-user-thumbnail
2022년 10월 1일

안녕하세요! 좋은 글 감사합니다😊
혹시 axios 인터셉터가 아닌 transformResponse를 쓰신 이유가 있을까요?

1개의 답글