본문 바로가기
Project/스타게이트

Atomic Design Pattern 도전기

by 이의찬 2023. 7. 31.

이번 포스팅은 SSAFY 2학기 공통 프로젝트에서 Atomic Design Pattern에 도전하다가 겪은 문제점과 그 결론이다. 참조한 글은 아래와 같다.

더보기

1. What is Atomic Design Pattern?

우선 Atomic Design Pattern에 대해서 먼저 설명하자면 컴포넌트를 Atom(원자), Molecule(분자), Organisms(유기체), Template(템플릿, Page(페이지) 5단계로 구성한 디자인 패턴이다. 5단계에 대한 설명은 아래와 같다.

  • Atom : 더 이상 분해할 수 없는 기본 컴포넌트, 가장 작은 단위의 컴포넌트
  • Molecule : 여러 개의 atom을 결합해서 생성, 자신의 고유한 기능을 가짐.
  • Organism : Molecules + Atoms을 모아서 만들며 사용자에게 의미와 역할이 존재하는 단위
  • Template : 최종 레이아웃의 형태, 여러개의 Organisms으로 구성되어있고 아직 Data 연결 X
  • Page : Template + Data가 되어 사용자에게 전달 되는 최종 디자인

React의 폴더 구조 종류 중 가장 유명하다고 할 수 있는 디자인으로, 웹 페이지의 구성 요소를 원자단위로 쪼개서 구상한다. 화학적 관점에서 영감을 얻어서 만들어졌다고 한다. 최소 단위에서 그 상위 단위로 묶고 다시 연관되는 것끼리 더 큰 단위로 묶어서 사용하는 디자인이다.


2. SSAFY 프로젝트에 직접 적용해보기

우리 팀은 컴포넌트의 재사용성 명확한 폴더구조의 단계를 위해 Atomic Design Pattern을 프로젝트에 적용시키기로 결정했다. 이론만 들여다보는 것 보다 직접 프로젝트에 적용하는게 훨씬 이해에 도움이 된다고 생각하기에, 우선 아래와 같이 목업에 적용시켜보았다.

우선 5단계를 모두 적용하기에는 너무 번거롭기도 하고 프로젝트의 사이즈를 고려했을때 오히려 마이너스 요소가 될 것으로 판단해 우선 Atoms, Organisms, Pages 3단계로 구성하였다. 또, 텍스트 같이 Tailwind CSS의 커스텀 클래스로도 충분히 처리 가능한 부분은 따로 atom으로 분류하지 않았다.

organisms의 경우는 위와 같이 목업을 보면서 형광색 사각형으로 묶어준 것을 하나의 organisms로 처리했다. 

├─public
└─src
    ├─assets
    │  ├─font
    │  └─image
    ├─atoms
    ├─hooks
    ├─organisms
    └─pages
        ├─admin
        │  ├─board
        │  ├─event
        │  └─signUp
        ├─auth
        ├─star
        └─user
            ├─board
            └─video

그 다음으로 폴더구조를 만들었다. atoms, organisms, pages 3단계 모두 /src폴더 바로 아래에 플랫하게 구성하였으며, Atoms와 Organisms는 상위 단계에서의 재사용성을 높이기 위해 따로 분리하지는 않았다.

 

'Atoms가 쌓이면 어떡하지,,'에 대한 걱정이 있긴 했지만, 나 포함 3명 중 2명이 atomic 패턴을 처음 사용해보는 것이기에 우선 사용해보고 추후에 바꾸기로 합의한 뒤 진행시켰다.


3. More Atoms, More Ploblems...

모든 Atoms와 Organisms를 플랫하게 두니 혼자 작성할때는 편리했다. Atoms와 Organisms만 나누면 되었고 Page에서는 Organisms를 가져와서 사용하면 끝! 이였고 그때까지는 계층별로 컴포넌트를 분리하는 것의 편리함을 만끽하고 있었는데, 서로 만든 것들을 Merge하면서 점점 이상함을 느끼게 되었다.

 

문제의 그 날이 생각보다 빠르게 다가온 것이다. 폴더 구조를 완성하고 작업에 들어간지 2주차가 되자 Atoms와 Organisms는 엄청나게 쌓여버렸는데, 때 우리 팀의 프로젝트의 상태는 아래와 같다.

    ├─atoms
    │      AdminBoardHeaderNav.tsx
    │      AdminBtn.tsx
    │      AdminInput.tsx
    │      AuthNumInputComponent.tsx
    │      BlackLayer.tsx
    │      BoardCard.tsx
    │      BoardHeaderNav.tsx
    │      BoardHeaderTitle.tsx
    │      BtnBlue.tsx
    │      BtnWhite.tsx
    │      DropDown.tsx
    │      InputComponent.tsx
    │      ManagementModalBox.tsx
    │      ModalPlusButton.tsx
    │      PolariodCard.tsx
    │      PWHidden.tsx
    │      PWShown.tsx
    │      TextButtonComponent.tsx
    │      TimeLeftComponent.tsx
    │      ToolTipComponent.tsx
    ├─organisms
    │      AdminBoardHeader.tsx
    │      AdminManagementModal.tsx
    │      AdminSignUpComponent.tsx
    │      AuthNumberComponent.tsx
    │      BoardCardBox.tsx
    │      BoardCardList.tsx
    │      BoardHeader.tsx
    │      IdinquiryComponent.tsx
    │      MeetingBottomSection.tsx
    │      MeetingLeftSection.tsx
    │      MeetingRightSection.tsx
    │      MyPageBox.tsx
    │      PasswordFormComponent.tsx
    │      PwinquiryComponent.tsx
    │      PwResetComponent.tsx
    │      SignInComponent.tsx
    │      SignUpComponent.tsx

패트와 매트도 놀랄만한 폴더 구조

겨우 1주일만에 Atoms와 Organisms 컴포넌트가 합쳐서 40개 가량 나오게 된 것이다. 이 시점에서는 찾고 싶은 컴포넌트가 있다면 하나하나 읽으면서 찾아내거나 최상위로 이동해서 컴포넌트를 찾을 수 밖에 없었는데, 예를 들어 myPage에서 사용중인 Atoms를 찾고 싶다면

myPage 코드 읽어보기 => Organisms 찾아서 이동 => Atoms 찾아서 이동

이라는 방식으로 코드를 찾아서 이동하게 되었다..


4. 그렇다면 어떻게 바꿀지?

팀원 모두가 잘못되었다는 것을 느꼈기에, depth를 주고 항목들을 세분화 하는 것은 합의했다. 하지만 이 과정에서 약간의 의견 대립이 있었는데, 다음과 같았다.

1안 : 4개의 기능과 common을 Atoms와 Organisms안에 새롭게 폴더를 만들어 배분하자!
2안 : 4개의 기능과 common 폴더를 components폴더를 새롭게 만들어 그 안에 넣어두고, 각각의 기능 폴더 안에 Atoms와 Organisms를 넣어두자!

양 쪽 다 2개 이상의 상위 단계에서 사용되는 component는 common폴더에 넣어두는 것으로 합의되어 있는 상황에서 Atoms와 Oranisms같이 단계를 처리한 것을 우선으로 분류할지, 혹은 기능을 우선으로 분류할지 생각할지에 대한 논쟁이 있었던 셈이다.

1안의 components 폴더가 없다는 것만 빼면 딱 이 상황이였음

우선 나는 어떤 프로덕트를 생각할 때 당연히 계층 구조보다는 기능을 먼저 보여주는 것직관적으로 이해할 수 있다고 생각해 2안을 주장했다.

 

반대로 1안을 주장하는 팀원의 의견은 다음과 같았다.

  1. 이미 목업을 기반으로 컴포넌트들을 Atoms와 Organisms로 나눠뒀기에, 기능이 아니라 단계를 우선으로 생각해도 충분히 직관적으로 이해 가능하다.
  2. 또한 단계를 우선적으로 컴포넌트를 분류하는 것이 컴포넌트의 계층화 측면에서는 기능 우선보다 오히려 더 직관적이다.

그 친구의 주장을 듣고 나니, 이미 목업을 기반으로 컴포넌트 단계별 분류를 완료한 현 상황에서는 계층을 우선적으로 나누는 것이 더 효율적으로 느껴져 1안으로 처리하기로 합의했다. 


5. 결론

다시 합의한대로 1안에 맞게 계층 - 기능별로 폴더를 분리했고, 2개 이상의 상위 기능에서 이용되는 component들은 common 폴더에 넣어두었다. 결과적으로 아래와 같은 폴더구조가 만들어졌다.

    ├─atoms
    │  ├─auth
    │  │      AuthNumInputComponent.tsx
    │  │      ToolTipComponent.tsx
    │  ├─board
    │  │      AdminBoardHeaderNav.tsx
    │  │      BoardCard.tsx
    │  │      BoardHeaderNav.tsx
    │  │      BoardHeaderTitle.tsx
    │  │      ManagementModalBox.tsx
    │  │      ModalPlusButton.tsx  
    │  ├─common
    │  │      AdminBtn.tsx
    │  │      BlackLayer.tsx
    │  │      BtnBlue.tsx
    │  │      BtnWhite.tsx
    │  │      InputComponent.tsx
    │  │      PWHidden.tsx
    │  │      PWShown.tsx
    │  │      TextButtonComponent.tsx
    │  │      TimeLeftComponent.tsx
    │  ├─event
    │  │      AdminInput.tsx
    │  └─remind
    │          PolariodCard.tsx  
    ├─organisms
    │  ├─auth
    │  │      AdminSignUpComponent.tsx
    │  │      AuthNumberComponent.tsx
    │  │      IdinquiryComponent.tsx
    │  │      PasswordFormComponent.tsx
    │  │      PwinquiryComponent.tsx
    │  │      PwresetComponent.tsx
    │  │      SignInComponent.tsx
    │  │      SignUpComponent.tsx
    │  ├─board
    │  │      AdminBoardHeader.tsx
    │  │      AdminManagementModal.tsx
    │  │      BoardCardBox.tsx
    │  │      BoardCardList.tsx
    │  │      BoardHeader.tsx
    │  │      MyPageBox.tsx 
    │  └─event
    │          MeetingBottomSection.tsx
    │          MeetingLeftSection.tsx
    │          MeetingRightSection.tsx
이렇게 완벽한 프로젝트를 만들었고, 우리의 Atomic 패턴 도전기는 끝났다.

 

라면 좋겠지만,, 개발하다보면 상황이 변하고 그에 따라 Best Practice도 변하기 마련인지라 추후에 또 모자란점을 깨닫거나 문제점이 발생하면 그 때 추가로 포스팅을 진행할 예정이다.


+a. 생각해봐야 할 부분,,

마지막으로 위에서 결정된 것을 Backend로 우테캠 참여중인 친구와 이야기를 나눌 때 말하니 흥미로운 질문 두 가지를 받을 수 있었다. 

1. 왜 A 기능에서 B기능의 atoms를 가져다 쓰면 안돼? 큰 프로젝트라면 common에 Atoms 200개씩 넣어둘거야?
2. 저렇게 단계를 우선으로 분리해놓으면 하위 단계라고 막 가져다 쓰기 좋아보이는데 그럼 결합도가 올라가지 않을까? 차라리 기능별로 분리해놓는게 더 나은 방법으로 보이는데?

 

첫 번째 질문의 문제점을 해결하기 위해서는 common의 정의를 바꾸고, 더욱 폴더의 depth를 깊게 하는 수 밖에 없는데, 현재 우리 프로젝트 규모로는 그게 더 번거로워서 굳이 그럴 필요를 느끼지 못했다. 

 

두 번째 질문도 마찬가지인데, 단계를 우선적으로 가져간다면, 그리고 common을 200개씩 사용할 생각이 아니라면 필연적으로 마주치게 되는 질문이다. 그리고 추후 고도화가 이뤄져 기능을 따로 분리하게 된다면 현재와 같이 단계를 우선적으로 구분한 모델은 확실히 기능을 우선적으로 구분한 것에 비해 번거로워 보인다.

 

둘 다 고도화가 일어나고 프로젝트 규모가 커지면 충분히 발생할 수 있는 문제점들로, 확실히 나보다 훨씬 큰 규모의 프로젝트를 많이 다뤄본 친구는 다르다는 것을 느꼈다. 이번 프로젝트는 이미 합의된 사항이 있으니 그대로 진행할 생각이지만, 추후 더욱 큰 프로젝트를 진행하게 된다면 다시 생각해봐야 할 문제점이다.


6. (추가 작성)후기

좋았던 점

Atomic하게 컴포넌트들을 분리하고 재사용성을 높인다. 라는 atomic 패턴의 컨셉 자체는 분명 효율적이였고, 애초에 Figma로 목업을 제작할 때 부터 이에 알맞게 가능한 재사용을 할 수 있도록 디자인을 해서 실제 작업에도 큰 도움이 되었다.

 

또 이렇게 atomic하게 구현할 부분을 나눠뒀기에 '큰 문제를 다룰때는 잘게 잘라서 작은 부분부터 접근하라'라는 말 처럼 우리가 문제를 대할 때 언제나 작은 부분부터 생각하게 해주었다.

아쉬웠던 점

하지만, 문제도 많았다.

  1. atom인데도 의존성을 지니거나 자체적인 동작을 가지게 되는 경우가 잦았다. 이로 인해서 재사용성이 떨어졌고, organisms에 이르면 거의 재활용이 불가능했다. 심지어 내가 만든 코드 중에는 organism안에 organism이 있는 경우도 있었다.
    organism인 modal안에 organism인 modalBox가 있는 모습이다....
  2. 또 atomic 패턴 특성 상 모든 data를 page에서 주고 받기에 page에서 atom까지 데이터를 내려주는 과정에서 atoms - organisms - pages로 나눠놓으니 props drilling이 발생했고, 중간에 상태를 제대로 추적하는데 어려움을 겪었다.

이 경우 외에도 data의 수가 늘어나면서 신경써야 할 부분이 많아졌고, 결국 Recoil 도입 organisms에서도 api를 호출하는 것(...)으로 해결했다.

 

프로젝트 전체 회고는 아래 링크를 참조해주세요.

https://cksxkr5193.tistory.com/7

 

(수정 중)Web RTC 비대면 팬사인회 서비스 스타게이트(SSAFY 프로젝트 우수상)

GitHub - Legitgoons/StarGate: [🏆 SSAFY 공통 프로젝트 우수] 비대면 팬사인회 서비스 StarGate [🏆 SSAFY 공통 프로젝트 우수] 비대면 팬사인회 서비스 StarGate. Contribute to Legitgoons/StarGate development by creating an

cksxkr5193.tistory.com