atomic 디자인 패턴 적용기

Mincho·2023년 8월 13일
2

React

목록 보기
14/15
post-thumbnail

시작하며..

  이전에 컴포넌트 UI구성에 있어서 Atomic Pattern을 도입할 것을 예고 하였습니다. Atomic패턴을 도입함으로써 장단점등 경험했던 것들을 작성하고자 합니다. Atomic패턴에 대해 궁금한 사항이 있으시면 이전 글 Atomic Pattern을 참고해주세요.


기본 컴포넌트 설계

  디자인 패턴을 본격적으로 도입하기 위해서 컴포넌트 설계부터 철저하게 할 필요가 있었습니다. 저번 글에서 사용했던 Idol정보에 대한 Card입니다. 이 카드의 경우 어떠한 방식으로 컴포넌트 설계를 할 수 있을까요??

  저는 이러한 구조를 이용하여 설계를 하였습니다. 그리고 Card안의 3가지 요소에 대해 molecules로 분류를 하였습니다. 곧 세 요소를 합친 Card는 Organism으로 보았습니다.


제일 작은 단위인 Atoms

  molecules를 구성하기 위한 atoms들은 위와 같이 기본적인 html시멘틱 태그들과 외부 라이브러리에서 제공하는 UI를 기본 구성요소로 구성하였습니다.

/** ../atoms/input/InputAtom.tsx*/
import { Input, InputProps } from "@chakra-ui/react";
import React from "react";
import { UseFormRegisterReturn } from "react-hook-form";

interface InputAtomProps extends InputProps {
  register?: UseFormRegisterReturn;
}

const InputAtom = ({
  placeholder,
  size,
  onChange,
  fontFamily,
  w,
  h,
  fontSize,
  margin,
  register,
  type,
  accept,
  cursor,
  pos,
  opacity,
}: InputAtomProps) => {
  return (
    <Input
      placeholder={placeholder}
      accept={accept}
      cursor={cursor}
      pos={pos}
      opacity={opacity}
      size={size}
      type={type}
      onChange={onChange}
      fontFamily={fontFamily}
      w={w}
      h={h}
      fontSize={fontSize}
      margin={margin}
      {...register}
    />
  );
};
export default InputAtom;

  저 중 InputAtoms.tsx를 살펴보겠습니다. input 프로퍼티의 타입을 지정해 놓고 그때 그때 상황에 맞게 custom하도록 하였습니다.(보통은 styled-component를 사용하는 경우가 많았음.)


Template 구성

  위의 설계했던 3가지 요소를 합쳐 만든 Card컴포넌트가 IdolInfoCard입니다. Flex박스에 Organism들을 모아 놓습니다. soloTemplate의 경우에는 organism요소가 하나밖에 필요하지 않았습니다.

반대로 GroupMemberTemplate은 MemberSection을 추가된 구조입니다. 앞에서 IdolInfoCard의 props를 주입하여 재사용도 하는 것을 확인 할 수있었습니다.



Pages

import SoloTemplate from "@/component/template/SoloTemplate";
import { getIdolSolo, getIdolSoloAlbum } from "@/utils/API/SSGSetting";
import { SoloType, albumType } from "@/utils/interface/interface";
import React from "react";

interface SoloPageProps {
  searchParams: { idol: string };
}

const SoloPage = async ({ searchParams }: SoloPageProps) => {
  const idolName: string = searchParams.idol;

  const soloData: SoloType = await getIdolSolo(idolName);
  const albumData: albumType[] = await getIdolSoloAlbum(idolName);

  return <SoloTemplate soloData={soloData} albumData={albumData} />;
};

export default SoloPage;

  마지막으로 Pages입니다. Page는 가장 큰 단위로 모든 요소들을 모아놓은 구조입니다. 결론적으로 클라이언트에게 보여지는 모습입니다. page에서는 data를 fetching해오고 그 data를 구성요소들에게 주입하였습니다. 저의 경우 nextJs의 sever Component에서 data를 fetching을 하였습니다.

  또한 Page의 경우 폴더를 따로 구성할 수 있었지만 nextJs의 폴더 기반 page routing으로 그대로 구성하였습니다.

사용후기

장점

  1. html 태그를 좀 더 sementic하게 세팅할 수 있었습니다.

    기존의 코드에서 리팩토링 과정에서 의미없는 html 태그 등을 남발했던 것을 atomic패턴을 사용하니 이런 의미없는 태그 사용을 쉽게 발견하고 효율적으로 코드를 줄여 나갈 수 있었습니다.

  2. atoms사용에서의 유연성

    input이나 button사용에 있어서 경우에 따라 컴포넌트를 따로 구성할 필요가 없어서 유연성이 높고 재사용할 수 있었습니다.

    프로퍼티에 따라 커스텀이 가능하였음.

  3. 직관적인 컴포넌트 네이밍

    보다 컴포넌트 설계에 있어서 치밀해야 하는 부분이 있었기 때문에, 각각 구성되어 있는 컴포넌트의 네이밍을 직관적으로 하여 팀 협업시에 효율적인 부분이 있을 수 있겠다는 생각을 하게 되었습니다.

단점

  1. 모호한 컴포넌트 구성 기준

    다음 사진에서 IdolInfoCard와 MemberSection, 즉 Organism 컴포넌트들이 구성되어 있습니다. MemberCard를 보면 MemberSection의 Molecules로 구성되어 있습니다. 뭔가 이상한 느낌이 오신다면 눈썰미가 좋으신 것입니다. 저는 처음 Card단락을 Oragnsims으로 구분해 놓았습니다.

    구분 요소가 달라 결국 MemberCard 네이밍을 변경하고 Molecules폴더로 분리하여 작업을 하였습니다. 다른 Reference에서는 Card를 더 작은 단위로도 봅니다. 결국 보는 사람마다 기준이 다르기 때문에 컴포넌트 구성에 있어서 같이 협업을 한 사람이 아니라면 기준이 다를 수 있습니다. 이렇듯 보통 직접적인 데이터 주입을 받지않는 atoms,molecules,organisms의 분기를 결정하는 것은 어려운 일입니다. 협업 과정에서 설계에 있어서 시간적 비용이 많이 소요가 될 것 같습니다.

  2. 데이터 주입시 Props Drilling문제

import SoloTemplate from "@/component/template/SoloTemplate";
import { getIdolSolo, getIdolSoloAlbum } from "@/utils/API/SSGSetting";
import { SoloType, albumType } from "@/utils/interface/interface";
import React from "react";

interface SoloPageProps {
  searchParams: { idol: string };
}

const SoloPage = async ({ searchParams }: SoloPageProps) => {
  const idolName: string = searchParams.idol;

  const soloData: SoloType = await getIdolSolo(idolName);
  const albumData: albumType[] = await getIdolSoloAlbum(idolName);

  return <SoloTemplate soloData={soloData} albumData={albumData} />;
};

export default SoloPage;

pages에서 data fetching이후 요소들에게 data를 주입할 때 5단계의 atomic pattern구성으로 인해 props drilling 문제가 생길 수 있게 됩니다. 그렇기 때문에 상태관리 라이브러리를 이용하거나 서버데이터의 경우 react-query + custom hook을 사용하여 해결하는 것이 현명해 보입니다.


결론

 현재 계속해서 다른 페이지에도 atomic pattern을 적용하며 컴포넌트를 구성하고 있습니다. 저 혼자하는 프론트엔드 역할을 맡아 하기 때문에 혼자 컴포넌트를 설계하고 네이밍을 하고 있지만, 팀 단위 협업을 하는 과정에서는 많은 커뮤니케이션 비용이 발생할 것으로 보입니다.

 또한 현재 atomic패턴의 5단계의 구성보다 좀 더 줄여 3가지 단계를 구성한다던지 기존의 문제점을 해결하고 있습니다.

Naver Line에서 도입한 atomic패턴

세간에서도 atomic패턴이 좋다 나쁘다, 어떻게 봐야한다 의견이 엇갈리고 있고 제가 atomic패턴을 적용하기 위해 참고한 reference에서도 방식이 다양하였습니다.

 사실 atomic패턴은 개발을 위해 만들어진 것이 아닌, 컴포넌트 구성에 있어서 도움을 주기 위해 화학용어를 빌려 사용한 것입니다.

 마지막으로 결국 컴포넌트 설계에 대해 atomic패턴의 5단계 설계 방식에 집중하기 보다는 이를 참고하여 컴포넌트 설계, 네이밍 등 협업을 하는 것이 좋은 방식이라고 느껴집니다.



Reference
https://yozm.wishket.com/magazine/detail/1531/
https://jbee.io/react/stop-using-atomic-design/
https://www.youtube.com/watch?v=33yj-Q5v8mQ

👍올바른 피드백은 언제든지 환영입니다~!

profile
사진찍는 개발자.

1개의 댓글

comment-user-thumbnail
2023년 8월 13일

글 재미있게 봤습니다.

답글 달기