디자인 패턴에 대한 고민 (Atomic Design Pattern, Container / Presentational(Presenter) Pattern)

Janet·2024년 4월 15일
3

Web Development

목록 보기
14/19

1. Intro.


  • 유지 보수성 향상 및 효율적인 코드 구조화 방법에 대해 논의.
  • 애플리케이션 규모에 따른 고려가 필요.
  • 라우팅 관련과 비즈니스 로직의 분리.

2. Next.js 기본적인 폴더 구조 개념


2-1. 기본 폴더 구조

A. 필수: App Router를 사용하는 Next.js 프로젝트의 기본 폴더 구조는 다음과 같습니다. 아래 두 개 폴더는 Next.js 앱 구축 시 필수적으로 존재해야 해야 합니다.

  • app/: 애플리케이션의 핵심 파일들이 위치합니다. 모든 파일은 이 폴더와 관련된 경로로 구성(라우팅 관련만 구성)됩니다.
  • public/: 외부에서 직접 접근 가능한 정적 자원들이 위치하는 폴더입니다. (ex: 이미지 파일, favicon.ico, robots.txt 등)

B. 선택

  • app/api/: 라우트 핸들러를 위한 디렉터로 API 엔드포인트를 생성하며 서버리스 함수로 사용됩니다.
  • middleware/: 미들웨어는 서버, 클라이언트, 또는 엣지에서 페이지를 렌더링하기 전에 실행되는 코드가 위치하는 폴더입니다.

2-2. 추가적인 가능에 대한 폴더 구조화

  • components/: 재사용 가능한 UI 컴포넌트를 저장합니다.
  • styles/: 컴포넌트 레벨 또는 전역 스타일을 정의하는 CSS 파일을 저장합니다.
  • lib/ 또는 utils/: 애플리케이션 전체에서 사용되는 유틸리티 함수나 라이브러리를 저장합니다.
  • hooks/: 사용자 정의 훅을 저장합니다.
  • types/ 또는 interfaces/: TypeScript를 사용하는 경우 전역 타입 정의를 저장합니다.
  • tests/: 테스트 코드를 저장합니다.

3. 컴포넌트 분리 관련 디자인 패턴 적용


  • 여러가지 패턴들이 있지만, 대표적으로 2가지 패턴을 선정하여 정리해 봅니다. 실제로 적용해본 Atomic Design Pattern과 Container / Presentational(Presenter) Pattern에 대해서 정리해 보았습니다.

3-1. Atomic Design Pattern 적용기

Atomic Design Pattern을 도입한 이유?

아토믹 디자인을 도입하기에 앞서, 어떤 기준으로 컴포넌트를 분리 해야할까 고민을 하게 되었습니다. 컴포넌트화를 최적으로 할 수 있는 아토믹 디자인 패턴을 고려하게 되었습니다.

Atomic Design Pattern이란?

  • Brad Frost의 아토믹 디자인은 화학적 관점에서의 물질(원자, 분자, 유기체 등) 개념을 웹에 적용하여 인터페이스를 세분화한 디자인 시스템을 만드는 방법론입니다.
  • 아토믹 디자인의 구성 요소: Atoms -> Molecules -> Organisms -> Templates -> Pages

Atomic Design Pattern의 5단계

1. Atoms(원자)

  • UI에 적용되는 가장 기본적인 구성 요소(label, input, button 요소 등)

2. Molecules(분자)

  • 그 자체에 의미가 없거나, 의미가 약한 원자들을 결합하여 만들어진 요소
  • 여러 개의 atom을 결합하여 자신의 고유한 특성을 가지며, 한 가지 일을 하는 요소

3. Organisms(유기체)

  • atom, molecule, organism을 구성하여 그룹화 할 수 있는 요소.
  • 예를 들어 header 라는 컨텍스트에 logo(atom), navigation(molecule), search form(molecule)을 포함할 수 있습니다. atom, molecule에 비해 좀 더 구체적으로 표현되고 컨텍스트를 가지기 때문에 상대적으로 재사용성이 낮아지는 특성이 있습니다.

4. Templates

  • 템플릿은 page를 만들 수 있도록 여러 개의 organism, molecule로 구성할 수 있습니다. 아래 이미지와 같이 실제 컴포넌트를 레이아웃에 배치하고 구조를 잡는 와이어 프레임입니다. 즉, 실제 콘텐츠가 없는 page 수준의 스켈레톤이라고 정의할 수 있습니다.

5. Pages

  • 템플릿에서 완성된 레이아웃에 실제 데이터나 더미 데이터를 넣어 특정 인스턴스 페이지를 만드는 요소.
  • 유저가 볼 수 있는 실제 콘텐츠를 담고 있습니다. template의 인스턴스라고 할 수 있습니다.

Atomic Design Pattern 간소화

  • 프로젝트에서는 기존의 아토믹 디자인 패턴(5단계)에서 다소 모호하거나 중복되는 요소라고 생각되는 부분을 간소화하여 3단계 정도로 적용(Molecules와 Organisms 단계와 Templates와 Pages 요소를 합침)
  • 기존 5단계: Atoms -> Molecules -> Organisms -> Templates -> Pages
  • 간소화한 3단계: Atoms -> Organisms(Modules) -> Pages

Atomic Design Pattern의 효율을 높이기 위한 방법

  • 재사용성을 높이기 위한 Styled-component의 사용.
  • CSS in JavaScript 방식의 Styled-component를 사용함으로써 컴포넌트 생성과 동시에 스타일링을 하기에 스타일을 여러 곳에서 불러올 필요가 없어짐.
  • Props(속성) 값을 상속받아 적용 가능하므로 분기점(조건)에 따른 다양한 스타일링을 적용이 편리함.
  • 컴포넌트 별 반응형 스타일 지정이 편리함(디바이스별 Breakpoint를 설정하고 import하여 media query문을 작성 가능)
  • 스타일 테마 파일을 만들어 일관성있는 스타일 적용하고 관리.

3-2. Container / Presentational(Presenter) 패턴이란?

  • 소스코드를 Javascript(기능, 로직)와 JSX(UI)로 나누는 방법을 말합니다. 즉, 데이터 처리와 데이터 출력을 분리하는 방법입니다.
  • 비즈니스 로직(Logic)으로부터 뷰(View)를 분리하여 관심사의 분리(SoC, Seperation of Concerns)를 강제하는 것이 이 패턴의 핵심입니다.

1. Container Components

  • JavaScript(기능) 부분을 의미합니다.
  • 데이터 처리, 상태 관리와 기타 데이터를 책임지게 됩니다.

⬇️ 예시 코드

import React, { useState, useEffect } from 'react';
import axios from 'axios';

const UserContainer = () => {
  const [userData, setUserData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchUserData = async () => {
      try {
        const response = await axios.get('https://api.example.com/users');
        setUserData(response.data);
        setLoading(false);
      } catch (error) {
        console.error('Error fetching user data:', error);
        setLoading(false);
      }
    };

    fetchUserData();
  }, []);

  return (
    <div>
      {loading ? (
        <p>Loading...</p>
      ) : (
        <UserList users={userData} />
      )}
    </div>
  );
};

export default UserContainer;

2. Presentational(Presenter) Components

  • JSX(UI) 부분을 의미합니다.
  • UI를 담당하는 순수함수로 작성하게 됩니다.

⬇️ 예시 코드

import React from 'react';

const UserList = ({ users }) => {
  return (
    <div>
      <h2>User List</h2>
      <ul>
        {users.map(user => (
          <li key={user.id}>
            <span>{user.name}</span>
            <span>{user.email}</span>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default UserList;

Reference.

profile
😸

0개의 댓글