Taskify 리펙토링 3부

윤병현·2024년 5월 18일
0

Taskify

목록 보기
4/7
post-thumbnail

모듈화 & 추상화

  1. 모듈 : 소프트웨어 설계에서 기능단위로 분해하고 추상화 되어 재사용 및 공유 가능한 수준으로 만들어진 단위

  2. 모듈화 : 소프트웨어의 성능을 향상시키거나 시스템의 디버깅, 시험, 통합 및 수정을 용이하도록 하는 소프트웨어 설계 기법

  3. 추상화

  • 공통적인 부분을 취하고 차이점을 버리는 일반화 과정
  • 중요한 부분을 강조(사용)하기 위해 불필요한 세부 사항(구현)을 제거

멘토링 시간 때 멘토님께서 모듈화, 추상화 개념에 대해서 설명해주셨다.
설명을 듣고 내가 진행했던 프로젝트에서 어떤 로직을 고칠 수 있을까 고민했는데 마침 딱 고치기 좋은 로직이 있었다.




🔎 API 통신 로직

export async function signUp(data: object) {
  try {
    const response = await client.post("/users/", data);
    const result = response.data;
    return result;
  } catch (e: any) {
    console.log(e);
    const { method, url } = e.config; // axios의 error객체
    const { status } = e.response;
    Sentry.withScope((scope) => {
      scope.setTag("api", "signUp"); // 태그 설정
      scope.setLevel("warning"); // 레벨 설정
      scope.setFingerprint([method, status, url]);
      Sentry.captureException(new Error(e.response.data.message));
    });
    return e.response.data.message;
  }
}

export async function logIn(data: object) {
  try {
    const response = await client.post("/auth/login", data);
    const result = response.data;
    return result;
  } catch (e: any) {
    console.log(e);
    const { method, url } = e.config; // axios의 error객체
    const { status } = e.response;
    Sentry.withScope((scope) => {
      scope.setTag("api", "login"); // 태그 설정
      scope.setLevel("warning"); // 레벨 설정
      scope.setFingerprint([method, status, url]);
      scope.captureException(new Error(e.response.data.message));
    });
    return e.response.data.message;
  }
}

로그인, 회원가입을 기능을 수행할 때 사용되는 API로직을 예시로 들고 왔습니다. 다른 로직들도 이 코드와 거의 똑같이 구현되어 있다고 생각하시면 됩니다. 그렇게 되면 아래와 같은 문제점이 생깁니다.

❗️문제점

  1. 중복된 코드가 많음
  2. 문제가 발생했을 때 고쳐야할 코드가 많음
  3. 변경 사항에 유연하게 대응하기 어려움
  4. 확장성을 고려했을 때 너무 안 좋은 코드임

앞서말한 문제점말고도 정말 많은 문제가 발생할 수 있다고 생각이 듭니다. 그래서 리펙토링을 진행해보려고 합니다.




📌 HttpClient 로직 추가

import client from "./axios";
import * as Sentry from "@sentry/react";

export const baseHttpClient = () => {
  // T: response data type
  // P: API 통신시 필요한 Body data type

  async function get<T, P>(url: string, params?: P) {
    try {
      const response = await client.get<T>(url, { params });
      return response.data;
    } catch (e) {
      const { method, url } = e.config; // axios의 error객체
      const { status } = e.response;
      Sentry.withScope((scope) => {
        scope.setTag("api", "get"); // 태그 설정
        scope.setLevel("warning"); // 레벨 설정
        scope.setFingerprint([method, status, url]);
        Sentry.captureException(new Error(e.response.data.message));
      });
      return e.response.data.message;
    }
  }

  async function post<T, P>(url: string, data: P, headers?: string) {
    try {
      const response = await client.post<T>(url, data, {
        headers: {
          "Content-Type": headers,
        },
      });
      return response.data;
    } catch (e) {
      const { method, url } = e.config; // axios의 error객체
      const { status } = e.response;
      Sentry.withScope((scope) => {
        scope.setTag("api", "post"); // 태그 설정
        scope.setLevel("warning"); // 레벨 설정
        scope.setFingerprint([method, status, url]);
        Sentry.captureException(new Error(e.response.data.message));
      });
      return e.response.data.message;
    }
  }
  {...}
  
   return {
    get,
    post,
    put,
    delete: del,
  };
};
export default baseHttpClient;

GET, POST, PUT, DELETE 메서드 기준으로 추상화를 진행해 보았습니다.
API 통신을 할 때 필요한 URL, Params, BodyData등 통신에 필요한 요소들은 외부에서 주입할 수 있도록 바꿨습니다.
그리고 로직에서 내보내주는 Response 타입은 제네릭를 사용해 외부에서 타입을 지정해줄 수 있도록 하였습니다.

💡개선된 코드

const httpClient = baseHttpClient();

export async function signUp(data: SignUpRequestbody) {
  const response = await httpClient.post<UserInfoResponse, SignUpRequestbody>(
    "/users/",
    data
  );
  return response;
}

export async function logIn(data: LoginRequestbody) {
  const response = await httpClient.post<UserLoginResponse, LoginRequestbody>(
    "/auth/login",
    data
  );
  return response;
}

위와같이 추가한 HttpClient 로직을 사용해서 아까 처음에 봤던 로그인, 회원가입 리펙토링 시켜주었습니다.

확실히 코드의 양이 줄었고 앞으로 생길 변경 사항에 좀 더 유연하게 대응할 수 있을 거 같습니다.
그리고 만약 문제가 생기면 HttpClient 로직을 들여다 보면서 문제를 할 수 있기 때문에 유지보수도 더욱 편하게 진행할 수 있을 거 같습니다.

Sentry 로직 또한 반복되고 있기 때문에 바꿔볼 수 있을 거 같은데 이건 나중에 해보겠습니다. 🧐




📌 Taskify 깃허브 링크
https://github.com/taskify-team7/taskify

profile
프론드엔드 개발자

0개의 댓글

관련 채용 정보