프론트엔드 개발에서의 디자인 패턴

st_hwang·2022년 12월 8일
1

팀프로젝트를 진행하면서 다른 프론트엔드 개발자들과 프론트엔드에서의 디자인 패턴을 어떻게 가져갈 것인가에 대한 이야기를 나누게 되었다. 혼자 개발을 한다면 자신만의 스타일대로 코드를 작성하겠지만, 협업을 하면서는 어떻게 코드를 작성하는지를 먼저 결정하고 그 방법론대로 개발을 하는 것이 가독성, 유지보수성, 재사용성 측면에서 더 좋을 것이라 생각했다. 근데 막상 생각해보니 디자인 패턴에 대한 개념이 모호했다. 소프트웨어 아키텍처? 디자인 패턴? 헷갈리는 용어도 많고 많은 패턴들이 있어서 이번 기회에 개념을 명확하게 잡아보고 싶었다.

소프트웨어 아키텍처와 디자인 패턴의 차이

처음에는 같은 의미인줄로만 알았던 소프트웨어 아키텍처와 디자인 패턴이라는 용어. 이 둘의 차이점을 알아보기 위해 각각의 정의에 대해서 알아보았다.

소프트웨어 아키텍처 : 유연성, 확장성, 실현가능성, 재사용성, 보안성과 같은 소프트웨어의 특성들을 기술적, 사업적 기대사항에 맞는 구조화된 솔루션으로 만들어가는 과정으로 아키텍처 특성(architecture chararteristic), 아키텍처 결정(architecture decision), 설계 원칙(design principle)이 결합된 시스템의 구조(structure)

  • 아키텍처 특성 : 시스템의 기능과 직교하는 시스템의 성공 기준 (성능, 확장성, 신뢰성, 활용성, 유지보수성, 접근성, 보안성, 사용성 등)

  • 아키텍처 결정 : 시스템 구축에 필요한 규칙들을 정하는 것. 시스템의 제약 조건을 형성

  • 설계 원칙 : 시스템 구축에 필요한 가이드라인을 정하는 것.

소프트웨어 디자인 패턴 : 코드 레벨의 디자인 (각각의 모듈이 어떤 역할을 수행하는지, 클래스 범위, 함수의 목적 등). 소프트웨어의 특정 구현을 직접 제공하지는 않지만, 반복되는 문제 상황들을 최적화된 방법으로 해결하도록 돕는 역할

각각의 정의를 살펴보면 디자인 패턴은 소프트웨어 아키텍처보다 작은 범위에 속하는 어떻게 코드를 작성할 것인가에 대한 방법론이라고 할 수 있을 것 같다.

어떤 디자인 패턴을 사용할 것인가?

디자인 패턴의 종류를 살펴보니 굉장히 많은 디자인 패턴들이 있었다. 처음에는 뭣도 모르고 많은 책들과 글들을 읽어보았는데 고전적인 디자인 패턴들은 모두 객체 지향 프로그래밍(OOP)를 중심으로 한 디자인 패턴이었다. 예전에는 프론트엔드와 백엔드가 나누어져 있지도 않았으니... 생성, 구조, 행동 패턴으로 나뉘어지는 GOF 패턴에는 다양한 패턴(23가지)이 있었는데 살펴보니 모두 클래스와 객체의 관계를 중심으로 한 객체 지향성 디자인 패턴이었다. 프론트엔드에서 사용할만한 패턴들은 아니라고 생각했다. 당연히 일부 개념은 나도 모르게 사용하고 있었을 수도 있지만. 애초에 GOF 패턴이 나온게 30년 전이다.

프론트엔드가 백엔드로부터 분리된 것보다 훨씬 오래된 이런 고전적 패턴들을 살펴보고 비교해보는 것은 맞지 않다고 생각되었다. 그래서 MVC로 대표되는 MV* 모델(MVC, MVVM), FLUX 패턴, 아토믹 패턴 등을 살펴보았다.

MVC 패턴

옛날에 국비 교육을 받으면서 자바를 배울 때 강사님이 MVC 패턴이 얼마나 중요한지 반드시 이해해야 된다면서 열심히 설명해주셨던 기억이 난다... MVC 패턴은 Model - View - Controller 로 역할을 구분지어 분류해놓은 것이다. 각각의 역할은 다음과 같다.

  • Model : 데이터와 비즈니스 로직 영역
  • View : UI. 유저가 직접 마주하는 화면.
  • Controller : Model과 View의 조율자 역할. View로 부터 유저의 입력이 들어오면, Model의 데이터를 핸들링하여 결과를 다시 View로 보내는 역할

MVC 패턴은 굉장히 유명한 디자인 패턴인데다가, 나온지가 꽤 되었는데도 아직까지도 소프트웨어 개발에서 많이 쓰이고 있다. 그러면 프론트엔드 개발을 할 때에도 MVC 패턴을 활용할 수 있을까? 개인적으로는 별로 좋은 것 같지 않다. 일단 MVC 패턴에서 프론트엔드는 거의 View만을 담당하는데다가(물론 프론트엔드에서도 컨트롤러 역할을 하는 로직들이 있을 수 있다) MVC 패턴에서의 View는 그냥 단순히 화면을 보여주는 역할로 정의한 반면에 프론트엔드에서는 그 View에서 발생하는 수많은 이벤트를 처리하는 것이 중요하다. 그럼 이게 View인지 Controller인지 개념도 모호해지고...

현재 프론트엔드 개발을 할 때에는 많은 View가 존재하고 또 각각의 View에서 필요한 데이터가 많고, View에서 Model과 직접 소통이 필요한 경우도 많을텐데, Controller를 통해 접근할 수 밖에 없다면 Controller도 굉장히 커질 것 같다. 그리고 View를 잘 다루는 것이 프론트엔드 개발자가 할 중요한 일인데 View를 단순히 화면으로 보는 디자인 패턴으로 개발을 어떻게 함? 결론은 프론트엔드랑 MVC 패턴은 조금 안맞는 것 같다.

MVVM 패턴

기존의 MVC 패턴을 변형해서 Model, Veiw, ViewModel 로 바뀌었다. 가장 중요한 달라진 점은 Controller가 ViewModel로 바뀌었는데, View를 위한 모델인 것이다. 기존의 Controller는 View에서 데이터를 요청할 때마다 기능을 반복적으로 수행했다면, ViewModel은 VIew와 데이터 바인딩이 되어있다. 쉽게 말해서 Model에서 데이터가 변경되면 View에서도 자동으로 바뀐다. 앞서 MVC 패턴의 문제점이었던 View와 Model의 양방향 소통성을 해결하고, Controller가 방대해지는 것을 방지할 수 있다. 이러한 데이터 바인딩은 처음에 앵귤러에서 지원을 해서 주목받았다고 하는데 많은 프레임워크들이 지원하고 있는 기능이다.(앵귤러, vue, 리액트, 스벨트 등). 그런데 이러한 MVVM 패턴도 많은 View가 계층적으로 존재하기 때문에, 데이터를 공유하면서 발생하는 Props Drilling Problem 문제점을 해결하지는 못했다.

Redux와 Flux 패턴

Flux 패턴은 페이스북에서 발표한 개념으로 단방향으로 흐름을 제어하고 동작하게끔 하는 패턴이다. View에서 어떠한 입력을 통해 Action을 호출하게 되면 그 Action이 Dispatch를 통해 다시 store에 데이터를 전달하고, store에서 변경사항이 있으면 다시 View가 바뀌는 이러한 단방향적인 구조를 가진다. 사실 실제로 바로 쓰이지는 않았고 단방향성의 개념을 심어주는 것에서 그쳤다고 한다.

그리고 이러한 Flux 패턴을 활용한 Redux가 등장한다. 기존의 문제점이었던 Props Drilling Problem의 문제점을 해결하면서, Store, Dispatch, Reducer의 개념을 명확히 했다. Redux 패턴은 많은 컴포넌트로 나누어져 있던 View를 하나의 개념으로 봤다. 비즈니스 로직에서 완전히 View를 분리시켜서 View 단에서 UI 구성에 필요한 데이터들을 상태(state)라고 하고, 이러한 상태들을 관리하는 것이 상태 관리(state management)라고 하게 됐는데, Redux 등장 이후 많은 상태 관리 라이브러리들이 후속하여 등장하였다. 이때부터 상태 관리가 프론트엔드의 주요 아젠다로 떠오른 계기라고 할 수 있을 것 같다.

하지만 Redux 패턴도 치명적인 문제가 있는데 Redux를 사용해본 사람은 알겠지만 바로 보일러플레이트가 너무 많아요... Redux 공식 홈페이지에서는 보일러플레이트 줄이는 방법을 아예 하나의 챕터로 안내하고 있으며, 개선을 위해 Redux toolkit이 등장하기도 했다. 또한 복잡한 Redux를 쓰기보다는 더 간단하게 Props Drilling Problem을 해결하기 위한 방법으로 React 라이브러리에서 제공하는 Context API를 사용하기도 한다.

Atomic 패턴

아토믹 패턴은 컴포넌트를 잘 관리하기 위한 방법론으로 View를 원자(Atoms), 분자(Molecules), 유기체(Organisms), 템플릿(Templates), 페이지(Pages) 순으로 작은 것들을 만들고 결합해 더 큰 단위의 View를 그리는 방법이다.

  • 원자 : button, input, font 등 가장 작은 구성요소
  • 분자 : 여러 개의 원자 요소의 구성으로, 여기서부터 복잡한 요소를 구성하고 재사용하기 시작함
  • 유기체 : 사용자에게 더 의미 있는 정보를 제공하거나 인터랙션하는 정교한 인터페이스를 구성하는 원자 또는 분자의 조합
  • 템플릿 : 실제 콘텐츠가 입혀지기 전에 정해지는 와이어 프레임
  • 페이지 : 완성된 최종 View

이러한 아토믹 패턴에서 Atoms 개념을 따온 것이 Recoil 라이브러리에 도입되었는데, Recoil은 Redux 보다 간단한 문법으로 컴포넌트 외부에서 공통의 데이터를 set, get 할 수 있게 하면서 동시에 동기화를 할 수 있게 한다. Recoil에는 Atoms와 Selector라는 개념이 있는데, Selector는 다른 atom이나 selector를 입력으로 받아들이면서 상위의 atoms 또는 seletor가 업데이트되면 하위의 selector 함수도 다시 실행되며 컴포넌트들도 다시 렌더링된다. 이러한 방법은 Redux보다 성능적으로 우수하며 (O(1), Redux는 O(n)), 사용하기에 따라 상태 정의의 유지 관리가 더 쉬울 수 있다. (중앙집중식 vs 분산관리식). 단점은 미들웨어가 존재하지 않기 때문에 때에 따라 사용하기 적합하지 않는 환경이 있을 수 있다.

그 외에도 MVC 패턴에 리액트쿼리를 도입한 개념도 있는 것 같고, 다양한 디자인 패턴들이 필요에 의해 만들어지고 주장되는 것 같다. 디자인 패턴을 알아보다보면서 프론트엔드의 역사도 대략적으로 알게되고 시야가 조금 넓어진 것 같다. 결국 디자인 패턴은 하나의 방법론이고 필요한 것이긴 하지만 너무 타이트하게 패턴을 맞추려고 하다보면 오히려 패턴에 코드를 우겨넣는 일도 발생할 것 같다는 생각이 든다. 어떠한 패턴이 우리의 서비스에 더 알맞을 것인지 조금은 느슨하게 생각해볼 필요가 있다고 느꼈다.

참고

마크 리처즈, 소프트웨어 아키텍처 101, 한빛미디어(주), 2021

https://codeburst.io/software-architecture-the-difference-between-architecture-and-design-7936abdd5830

https://developer.mozilla.org/ko/docs/Glossary/MVC

https://velog.io/@teo/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C%EC%97%90%EC%84%9C-MV-%EC%95%84%ED%82%A4%ED%85%8D%EC%B3%90%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94

https://innovature.ai/react-state-management-with-redux/

profile
frontend developer

0개의 댓글