주도적으로 설계하는 MFA

HyunHo Lee·2024년 2월 14일
8

프론트

목록 보기
55/57
post-thumbnail

서론

필자는 B2B 서비스를 제공하는 팀에 속해있다. 이 서비스는 과거부터 개발이 되어, 기능이 늘어남에 따라 규모도 커졌다. 이제 프론트엔드라는 직무를 떠나서, 현재 구조에서 개발하기 어려운 요구 사항들이 생겼다. 이 요구사항을 현재 서비스에서 충족하려면, 다시 만들어야 하는데.. 와 같은 부분들 말이다. 이를 해결하기 위해서 새로운 버전의 서비스를 설계하기로 결정했다. 즉, 다시 만든다는 의미이다.

새 프로덕트를 만든다는 결정이 되고, 팀 내에서 정말 많은 의견을 나누었다. 어떤 프레임워크 및 라이브러리를 사용할 것인지 부터, 개발 방법론, 아키텍쳐 구조, 컨벤션 등을 고민했다. 이 중에서 오늘 소개할 부분은 아키텍쳐이다.

결론부터 말하자면, MFA(Micro-Frontend Architecture) 를 설계하기로 결정했다. 이전에 디자인 토큰으로 설계하는 디자인 시스템에서 언급했던 것과 비슷한 이유다. 서비스가 거대해지면서 복잡성 관리 및 유지보수에 힘이 부치기 시작했다. 이제는 모든 기능들이 하나의 프로젝트에 있는 모놀리식으로는 한계가 있는 것이다.

현재 서비스는 Vue2(Optional API)로 구성되어 있다. 새로운 프로젝트에서는 React도 고려 대상이었지만, Vue3(Composition API)로 결정 되었다. Vue2에서 Vue3로 넘어가면서, 클래스형에서 함수형을 위주로 사용할 수 있었고, setpup script 문법이 나름 매력적이었기 때문이다.

이제 우리는 Vue3를 사용하며, 마이크로 프론트엔드 아키텍쳐를 구현하기로 결정했다. 그런데 가만히 생각해 보면 중요한 점이 빠져있다. 그래서 MFA를 구현하기 위해서는 어떤 방법이 있고, 이 많은 방법중 어떤 것들이 팀에 맞는 방법이며, 어떻게 적용할 것인지 말이다. 그리고 팀원들 중 누가 할 것인지도... 그런데 그게 바로 나였다.

사실 우리팀에서 Vue3를 본격적으로 사용해본 개발자나 MFA를 경험해본 개발자는 없었다. 그래서 담당 개발자로 정해졌을 때, 걱정 70% 기대 30% 정도 기분이었다. 그래도 팀장님께서 믿고 맡기신 만큼, 우리 팀에게 더 좋은 환경을 제공하겠다는 집념으로 설계했다. 이제 자료 조사부터 실제 프로젝트 셋팅까지 완성한 눈물 겨운 이야기를 시작하겠다.


Micro Frontend와 Multirepo/Monorepo

마이크로 프론트엔드를 설계하기 전에, 멀티 레포와 모노 레포에 대해 이해와 공감이 있어야 한다. 팀이 어떤 이유로 이 아키텍쳐를 도입하려는 것인지 분석해볼 필요가 있다. 서비스가 크다는 이유에서 조금 더 들어가보자.

웹 서비스에서 특정 기능들을 묶은 대분류의 카테고리들을 메뉴라고 부르겠다. 우리 팀에서 제공하는 메뉴들은 각각의 메뉴마다 하나의 회사가 있을만큼 기능이 굵직하다. 예를 들면, 고객 관계 관리 서비스인 CRM이 우리의 서비스에서는 하나의 메뉴가 된다.

이처럼 서비스가 크다 보니, 공통 컴포넌트와 도메인 성격을 지닌 컴포넌트들을 구분하기 애매한 부분들이 많아졌고, 서비스 전체에 영향을 미치는 무언가를 추가하는 경우 부담이 크게 되었다. 또한, 배포를 하기 위해서는 점점 더 많은 시간이 필요하게 되었고, 특정 메뉴에 대한 수정이 전체 배포로 이어진다는 부분이 불필요하게 느껴졌다.

특정 메뉴에서 bug fix를 하거나 새로운 feature 개발 하는 경우, 다른 메뉴들까지 전부 배포해야 한다는 모놀리식의 한계점이 보이기 시작한 것이다.

우리팀은 유지보수 하기 좋고, 메뉴마다 분리되며, 하나의 서비스에서 동작하는 웹 서비스 구조가 필요했다. 그것이 MFA였고, 이 아키텍쳐를 설계하기 위해 멀티레포와 모노레포를 결정할 차례인 것이다. 기존의 프로젝트는 모놀리식(Monolithic)으로 구성되어 있었다. 그래서 멀티레포(Multirepo)와 모노레포(Monorepo)의 장단점을 경험으로 느껴보지는 못했다. 대신에, 수 많은 관련 해외 자료부터 국내 기업들의 기술 블로그들을 정독해본 결과 모노레포에 마음이 기울어졌다. 우리 팀에서는 모노레포에서의 코드 공유와 유지 보수가 생산성에 더 유리하다고 생각했기 때문이다.

서비스를 모노레포 마이크로 프론트엔드 아키텍쳐로 설계한다고 상상해보자. 하나의 레파지토리에서 메뉴별로 마이크로 앱을 생성할 것이다. 이 마이크로 앱들을 이용하여 하나의 서비스로 구성하면, Monorepo MFA가 완성된다. 하나의 서비스로 구성하기 위한 방식이 크게 5가지가 있는데, 이것은 다음 섹션에서 알아보자.

위의 내용으로 마이크로 앱이 무엇인지 대충 느낌이 왔을 것이다. 다시 돌아와서 모노레포를 선택한 이유를 알아보자. 먼저, 하나의 레파지토리에서 마이크로 앱을 관리하기 때문에, Git 히스토리 파악에 유리하다. 마이크로 앱마다 브랜치를 생성하고, 해당 브랜치별 버전 관리로 더 체계적으로 Git을 활용할 수 있다. 더 나아가 새로운 마이크로 앱을 추가하거나, 마이크로 앱에 공통적으로 마이그레이션 하는 경우에도 멀티레포보다 유지보수하기 유리할 것으로 생각된다.

멀티레포와 모노레포는 팀의 취향차이라고 생각한다. 멀티레포의 단점이 모노레포에서는 장점이고, 그 반대도 마찬가지기 때문이다. 그러므로, 둘 중 하나를 선택해야하는 상황이라면 팀이 어떤 상황이고, 팀원들의 성향이 어떤지 커뮤니를 많이 해보는 것이 중요하다.


MFA 설계 방식

MFA를 설계하기 위한 대표적인 방법에는 iframe, web component, 단순 routing, build time 통합, runtime 통합이 있다. 이 5가지 방법 중 런타임 통합 방식을 선택했다. 현대 웹 생태계에서 iframe은 보안 이슈로 잘 사용하지 않아 제외시켰고, 우리가 원했던 MFA의 수준은 단순 routing이 아니여서 이 방법도 논외가 되었다.

web component 방식은 좋아보였지만, 시간적 여유가 부족한 우리에게는 부담이었다. 마지막으로 build time 통합 방식은 마이크로 앱이 변경 되었을 경우, 해당 앱만 배포하고 싶던 욕구를 해결할 수 없을 것 같아 runtime 통합 방식을 선택했다.

이제 번들러와 패키지 매니저를 선택할 차례이다.


번들러와 패키지 매니저

번들러에서 지원하는 Module Federation을 이용하면, 런타임 통합 방식으로 MFA를 설계할 수 있다. 대표적으로 Webpack과 Vite가 Module Federation을 지원한다. 나는 이 두가지 방법으로 MFA를 구성해보며, 장단점을 체감해보았다. 개인적으로 Webpack의 공식 문서가 보기 편했고, 실제로 구성하면서 참고할 레퍼런스도 많았다. 이 외에도 웹펙으로 결정한 이유가 한 가지 더 있는데, 패키지 매니저를 소개하면서 설명하겠다.

npm, yarn, yarn berry, pnpm 등의 패키지 매니저중 어떤것을 사용할지도 고민해야한다. 더불어 lerna, turbo와 같이 도움을 주는 친구들도 고려해볼 필요가 있다.

이 중에서 눈에 들어온 것은 yarn berrypnpm 이었다. 먼저 yarn berry는 zero-install, phantom dependency 제거 등의 큰 장점을 가지고 있었다. 하지만 장점이 확실한 만큼 직접 부딪혀가며, 전체적인 구조를 잘 설계해야 한다는 허들이 있었다. 그에 반해 pnpm은 비교적 간단하고, 원하는 기능도 모두 제공하고 있었다.

이 외에도 yarn berry의 node_module을 없애는 철학은 Module Federation과 애매한 부분도 있었다. 간단한 예시로, vite의 module federation으로 monorepo mfa를 구성하는 경우, node_module에 cache 디렉터리를 생성해버린다. 물론 세부 설정을 통해 해결할 수는 있지만, 이런 부분들이 얼마나 더 있을지 몰랐다. 이와 같은 이유로 monorepo, vue3, pnpm, webpack module federation으로 Monorepo MFA를 설계하기로 결정했다. 이제 해당 스킬들을 기준으로 우리 팀 입맛에 맞게 개척할 일만 남았다.

yarn berry는 packages 디렉터리 안에서 workspace들을 관리한다. 지금은 pnpm을 사용하지만, 추후에 yarn berry 기능이 더 강력해질 경우 마이그레이션 가능성을 열어두기 위해서 pnpm에서도 위와 동일한 구조로 동작하도록 구성했다.


마무리

오늘은 마이크로 프론트엔드를 구성하기 위해 결정했던 많은 요소들에 대해 작성해보았다. 다음에 기회가 된다면, 본격적으로 MFA를 어떻게 구성하면서 무엇을 고려했는지 다루어 볼 예정이다.

어떤 구조로 마이크로 앱들을 하나의 서비스에서 통합했는지, 공통 부분을 담당하는 마이크로 앱은 어떤식으로 설계했는지, 어디까지 마이크로 앱을 분리하는 전략을 가져갔는지, 마이크로 앱간 타입 추론은 어떻게 적용하였는지 등 고려해야 할 부분들이 정말 많았다. 또 언제 글을 작성할지 모르겠지만, 다음 글에서 소개하겠다.

profile
함께 일하고 싶은 개발자가 되기 위해 달려나가고 있습니다.

2개의 댓글

comment-user-thumbnail
2024년 2월 14일

최근에 MFA에 관심가졌는데 다음 글도 기대되네요 재밌게 읽었습니다!

1개의 답글