여러 프레임워크에서 사용할 수 있는 공통 라이브러리를 어떻게 만들 수 있을 까요?

0

나만의 라이브러리를 만들어보고 싶은 생각, 한 번쯤은 해보셨죠? 개발자로서 다양한 문제를 해결하기 위해 라이브러리를 만들어보는 건 흥미로운 일입니다. 특히, 범용적인 라이브러리를 만들고자 할 때는 더욱 신중한 고려가 필요하죠. 오늘은 프론트엔드 개발에서 자주 언급되는 “Framework Agnostic”이라는 개념을 중심으로 이야기를 해보려고 합니다.

Framework Agnostic이란?

Framework Agnostic, 혹시 들어보셨나요? 이 용어는 소프트웨어가 특정 환경에 종속되지 않고 독립적으로 설계됨을 의미합니다. 즉, 특정 프레임워크에 묶이지 않고 다양한 환경에서 사용될 수 있는 라이브러리를 만드는 것이죠.

예를 들어, JavaScript 라이브러리에서 Framework Agnostic 접근 방식이라고 하면, 특정 프레임워크에 종속되지 않는 코드를 작성하는 것이라고 할 수 있습니다. 이렇게 하면 React, Vue 등 여러 프레임워크와 호환될 수 있기 때문이죠.

Tanstack Query

대표적인 라이브러리가 Tanstack Query입니다. 예전에는 React Query로 불렸지만, 이제는 다양한 프레임워크에서도 사용할 수 있는 Framework Agnostic한 라이브러리로 발전했습니다. 어떻게 가능했을까요?

Tanstack Query의 소스 코드를 보면, core 패키지와 각 프레임워크에 맞춘 어댑터 패키지로 구성되어 있습니다. 핵심 로직은 query-core에 담겨있고, React, Vue, Svelte 등 프레임워크에 특화된 부분은 각각의 패키지에 담겨있죠.

계산기, 직접 만들어볼까요?

이제 React에 강하게 결합된 계산기 라이브러리를 다양한 프레임워크에서 사용할 수 있도록 재설계해보겠습니다.

1. 코어 인터페이스 만들기

먼저, 코어 기능을 프레임워크와 독립적으로 정의합니다. 다음은 계산기의 연산 로직을 포함한 코어 클래스의 예입니다:

class Calculator extends EventTarget {
  private _result: number = 0;
  
  get result() {
      return this._result;
  }
  
  add(a: number, b: number) {
      this._result = a + b;
      this.dispatchEvent(new Event('update'));
  }
  
  subtract(a: number, b: number) {
      this._result = a - b;
      this.dispatchEvent(new Event('update'));
  }
  
  multiply(a: number, b: number) {
      this._result = a * b;
      this.dispatchEvent(new Event('update'));
  }
  
  divide(a: number, b: number) {
      this._result = a / b;
      this.dispatchEvent(new Event('update'));
  }
}

2. React 어댑터 만들기

이제 코어를 React에 연동해봅시다. React 상태와 라이프사이클을 연동하는 Hook을 만듭니다.

import { useEffect, useState } from 'react';

function useCalculator() {
  const [result, setResult] = useState(0);
  const calculator = new Calculator();

  useEffect(() => {
    const handleUpdate = () => setResult(calculator.result);
    calculator.addEventListener('update', handleUpdate);
    
    return () => {
      calculator.removeEventListener('update', handleUpdate);
    };
  }, [calculator]);

  return {
    result,
    add: (a, b) => calculator.add(a, b),
    subtract: (a, b) => calculator.subtract(a, b),
    multiply: (a, b) => calculator.multiply(a, b),
    divide: (a, b) => calculator.divide(a, b),
  };
}

어떤가요? 이렇게 생각보다는 쉽게 라이브러리를 만들 수 있답니다.

Framework Agnostic 설계의 장점과 단점

장점

  • 재사용성 증가:@b] 다양한 프레임워크에서 사용할 수 있어요.
  • 유지보수 용이:@b] 코어와 어댑터를 분리해 각자의 수정이 쉬워요.

단점

  • 개발 및 유지보수 비용 증가: 각 프레임워크별 어댑터를 개발하고 유지해야 해요.
  • 복잡성 증가: 코어와 어댑터 간의 인터페이스를 관리해야 해요.

결론

Framework Agnostic한 라이브러리를 만드는 것은 단순히 특정 환경에 종속되지 않는 코드를 작성하는 것 이상입니다. 핵심 로직과 프레임워크에 특화된 로직을 분리해, 유지보수와 확장성을 고려해야 하죠. Tanstack Query와 같은 사례를 통해 이 개념을 이해하고, 직접 적용해보는 것은 분명히 가치 있는 일이 아닐까요?

여러분도 범용적인 라이브러리를 만들어보고 싶지 않으신가요? 오늘 알려드린 내용을 활용해보는 것은 어떨까요?

답글 남기기