카테고리 없음

[Design Patten] 관심사의 분리

고래강이 2023. 12. 11. 11:58

개요

  • 주요 개념
  • 관심사 분리의 장점
  • 주의사항 및 요점

 

주요 개념

직교성)

 A와 B가 직교하는 경우 A를 변경해도 B는 변경되지 않아야하며 반대상황도 마찬가지다.
ex) 라디오의 볼륨 조절과 채널 조절은 서로에게 영향을 주면 안된다.

 

이렇듯 좋은 React 애플리케이션 디자은은 다음과 같은 관심사가 직교한다.

  • UI 요소 (presentaion component)
    • 레이아웃 (layout)
    • 데이터 페치 컴포넌트 (stateful)
    • 데이터 렌더링 컴포넌트 (stateless)
    • 서스펜스 / 에러바운더리 (statefull)
  • 데이터 가져오기(fetch 라이브러리, REST or GraphQL)
  • 글로벌 상태관리 (Redux, Recoil, ContextAPI)
  • 영속성 로직 (localstorage, cookie...)

이러한 직교성을 통해서 변경사항은 격리되고 하나의 컴포넌트에 집중이 가능해 예측 가능하고 개발하기 쉬운 시스템을 만들 수 있다.

 

데이터를 가져오는 과정을 분리해보자)

import React, { useState } from 'react';
import axios from 'axios';
import EmployeesList from './EmployeesList';
function EmployeesPage() {
  const [isFetching, setFetching] = useState(false);
  const [employees, setEmployees] = useState([]);
  useEffect(function fetch() {
    (async function() {
      setFetching(true);
      const response = await axios.get("/employees");
      setEmployees(response.data);
      setFetching(false);
    })();
  }, []);

  if (isFetching) {
    return <div>Fetching employees....</div>;
  }
  return <EmployeesList employees={employees} />;
}
출처: https://itchallenger.tistory.com/541#google_vignette [Development & Investing:티스토리]

suspense를 이용해서 data fetch과정을 분리할 것임.

 

1. 완성

import React, { Suspense } from "react";
import EmployeesList from "./EmployeesList";

function EmployeesPage({ resource }) {
  return (
    <Suspense fallback={<h1>Fetching employees....</h1>}>
      <EmployeesFetch resource={resource} />
    </Suspense>
  );
}

// fetch 로직을 포함한 컴포넌트
function EmployeesFetch({ resource }) {
  const employees = resource.employees.read();
  return <EmployeesList employees={employees} />;
}
출처: https://itchallenger.tistory.com/541#google_vignette [Development & Investing:티스토리]

 

 

UI와 hook을 분리해보자)

import React, { useState, useEffect } from 'react';
const DISTANCE = 500;
function ScrollToTop() {
  const [crossed, setCrossed] = useState(false);
  useEffect(
    function() {
      const handler = () => setCrossed(window.scrollY > DISTANCE);
      handler();
      window.addEventListener("scroll", handler);
      return () => window.removeEventListener("scroll", handler);
    },
    []
  );
  function onClick() {
    window.scrollTo({
      top: 0,
      behavior: "smooth"
    });
  }
  if (!crossed) {
    return null;
  }
  return <button onClick={onClick}>Jump to top</button>;
}
출처: https://itchallenger.tistory.com/541#google_vignette [Development & Investing:티스토리]

 

UI로직과 스크롤 리스너 로직(useEffect 내부 로직)를 분리할 것임

 

1. hook을 통한 리스너 로직 분리

import { useState, useEffect } from 'react';
function useScrollDistance(distance) {
  const [crossed, setCrossed] = useState(false);
  useEffect(function() {
    const handler = () => setCrossed(window.scrollY > distance);
    handler();
    window.addEventListener("scroll", handler);
    return () => window.removeEventListener("scroll", handler);
  }, [distance]);
  return crossed;
}
출처: https://itchallenger.tistory.com/541#google_vignette [Development & Investing:티스토리]

 

2. UI로직

function onClick() {
  window.scrollTo({
    top: 0,
    behavior: 'smooth'
  });
}
function JumpToTop() {
  return <button onClick={onClick}>Jump to top</button>;
}
출처: https://itchallenger.tistory.com/541#google_vignette [Development & Investing:티스토리]

 

3. 격리를 위한 추가 컴포넌트

function IfScrollCrossed({ children, distance }) {
  const isBottom = useScrollDistance(distance);
  return isBottom ? children : null;
}
출처: https://itchallenger.tistory.com/541#google_vignette [Development & Investing:티스토리]

 

4. 완성

import React from 'react';
// ...
const DISTANCE_NEWSLETTER = 300;
function OtherComponent() {
  // ...
  return (
    <IfScrollCrossed distance={DISTANCE_NEWSLETTER}>
      <SubscribeToNewsletterForm />
    </IfScrollCrossed>
  );
}
출처: https://itchallenger.tistory.com/541#google_vignette [Development & Investing:티스토리]

 

변경될 수 있는 사항을 별도의 컴포넌트로 분리를 하는 것이 직교성의 핵심이다!


 

장점

  • 모든 변경사항이 컴포넌트 내에 격리가 되어 쉽게 변경사항에 대해 쉽게 조절할 수 있다.
  • 컴포넌트가 한 개의 역할만을 수행함에 따라 쉽게 이해할 수 있다.
  • 단일 책임구현에만 집중을 하므로 컴포넌트가 올바르게 수행하는지 테스트 할 수 있다.

 

주의사항

직교 설계는 You aren't gonna need it 원칙에 따라 균형을 이루므로 실제로 필요할 때 구현하고 미리 구현하지 마세요!
  • 극단적인 설계를 피하고 필요에 따라 생성하는 것이 좋다.
  • 변화를 예측하고 필요한 부분을 파악하는 능력을 길러보자!
가장 좋은 디자인의 핵심 원칙은 가장 변경 될 가능성이 높은 논리를 분리하는 것임 그렇기에 로직이 직교하도록 만드는 것
이러한 직교를 통해서 변경사항이나 새로운 기능 요구에 유연하게 적응할 수 있다.

 

 

참고자료 : 블로그