| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 |
- 속도개선
- js
- ui thread
- 비동기
- 데이터 로드 #텍스트 분할
- 정처기 준비물
- 정보처리기사
- nextJS
- BOUNDED CONTEXT
- 빌딩 블록
- sharedvalue
- 불변식
- HTML
- TS
- 디프만 #디프만17기 #depromeet
- Aggregate
- Expo
- typeScript
- 이펙티브 타입스크립트
- react natvie
- 타입스크립트
- React Native
- rniap
- 애그리게이트
- in app purchase
- DDD
- 정처기 자격
- PR
- rn
- IAP
- Today
- Total
nika-blog
NHN FORWARD 본문

거대한 서비스 쪼개서 마이크로 프런트엔드 만들기
대상- 프런트엔드가 거대해져 어떻게 해야 할까 고민하는 모든 직군- 마이크로 프런트엔드 도입을 고민하는 분
이웅재 - NHN Dooray
Dooray!의 프런트엔드는 거대한 모놀리식 SPA로 구성되어 있었습니다.
최근에 디자인을 리뉴얼하며 실험적으로 마이크로 프런트엔드를 도입하였습니다.
이와 관련해 어떤 목표를 가지고 왜 그런 결정을 했는지, 구체적으로 어떻게 진행되었는지 다룹니다.
요약: React Monolithic SPA(트랙1-3 설명) 에 Micro Frontend 도입한 이야기
- 두레이 메인 서비스
- 7개 서비스 react, ts, vite, redux-saga, redux-toolkit
- 기존 시스템의 문제
- 도메인 지식을 갖추기 어려움
- 서비스 담당자로서 오너십 x
- 레거시 생성
- 소스 코드 방대해짐, 개발/빌드 길어짐
- 통합 QA 배포 과정 힘들어짐
- 엔지니어에게 기술 선택권 주고싶음
하나의 서비스로만 독립적으로 운영, QA, 배포 할 수 없을까?
- Linked single-page applications → 선택 x
서비스별로 SPA 따로 생성- 각 서비스는 url 시작으로 구분하여 독립적인 SPA
- 팀 내부에서는 history API 이용, 클라이언트 측 라우팅 사용
- 문제: 중복 코드가 많아짐, 서비스전환이 많아지면 복잡해진다.
- Unified single-page application → 선택 o
- app-shell 존재. 모든 하위 서비스들의 상위 애플리케이션 역할
- 들어오는 모든 요청을 라우팅에 맞게 하위 서비스에 연결
- 공통 레이아웃 (포함해도 되고 안해도 되고)
- 서비스 비즈니스 로직 포함 x
- 인증이나 앱 전체 설정을 다룸
- 페이지 내 통합
- 마이크로 프론트엔드 서적 참고
- Iframe
- linked pages
- Server-side intergration
- Ajax
- Universal intergration(server-and client-side)
- Client-side intergration(web components) → 시나리오
시나리오 : page 안에서의 서비스 간 통합
- 사례) Pages 와 Fragment, 그리고 상태의 분리- 코딩보다 중요한 것
- 상황
- 메일 쓰기 창에서 드라이브 서비스의 코드 조각을 사용
- 드라이브 첨부가 가능한 경우 버튼 보여짐
- 드라이브 서비스에서 작업한 첨부 모달을 띄우고 첨부한 파일을 선택합니다.
메일 서비스 담당자는 드라이브 서비스에 대해 지식이 부족하고, 알고 싶지 않음 - 메일 서비스가 드라이브에서 준 파일 정보를 가지고 실제 메일에 첨부합니다.
이것만 메일 서비스 담당자의 할일
- 해결
- 메일 서비스에서 드라이브 서비스가 오너십을 가진 함수를 Dynamic Import 합니다.
- Drive 서비스를 분리하고 shared 라는 곳에 다른 서비스로 공유되는 코드 조각들을 모음
- TypeScirpt 를 통해 컴파일 타임에 인터페이스에 대한 검증이 되기 떄문에 무리 없이 서로 코드만으로 사용법을 익힐 수 있습니다.
- Drive API 를 사용하는 경우에 Drive 서비스 작업으로 분리 (기준 : 어떤 API 를 사용하냐) 작업자의 범위가 명확하게 나누어지도록 기준 정함.
- Module Federation 기본 설정
- main-services에서 바로 컴포넌트 가져오기 : lazy 방식 이용
- 리액트 컴포넌트 가져오기
- 로딩
- 실패한 경우(런타임에러, 네트워크에러) : ErroBoundary
- 리액트 컴포넌트 가져오기
- remoteEntry.js 캐싱 문제
- drive 서비스만 재배포했는데 왜 해당 부분에 변경이 발생하지 않을까?
- main-services 와 drive 의 연결고리는 remoteEntry.js인데, remoteEntry.js 가 변경되지 않았음
- 해결 : remoteEntry.js?v=[Date.now()]와 같이 동적으로 url 사용
- drive 서비스만 재배포했는데 왜 해당 부분에 변경이 발생하지 않을까?
- 해결
- Drive 서비스에서 expose 한 page
- Drive 서비스에서 expose한 Fragments (Fragments 가 아닌 경우에도 Fragments전달하도록 하기)
- mail 서비스에서 drive 서비스가 제공한 리액트 컴포넌트를 lazy 하게 가져옴(조건에 따라 해당 컴포넌트 띄워줄지 말지도 알아서 리액트 컴포넌트안에서 판단)
- 전역 상태의 분리
- 시험중, redux, redux-saga 사용 예시
- 서비스 간의 전환에는 리듀서를 리플레이스 하여 새로운 상태 관리 시작
- 서비스 전체적으로 사용되는 리듀서와 특정 서비스에서 사용하는 리듀서 분리
- 만약 서비스 간에 사용되는 프레그먼트에서 리덕스 사용하고 있다면
- 최대한 로컬 스테이트만을 이용하도록 하는 것이 권장
- 그럴 수 없다면 해당 플레그먼트에서 사용하는 해당 프레그먼트의 리뉴서와 사가만을 없을 때만 로드하는 방법 사용
- 느낀점
- micro frontend는 구체적인 기술 x, 팀 구조를 변경한 것
- 서비스가 충분히 커져서 복잡도의 증가를 따라가지 못할 떄 선택할 수 있는 여러가지 대안 중 하나
- 아니면 개발자를 엄청 많이 뽑더지.. 모든 도메인을 다익혀..
- 마이크로 서비스는 개발도 중요하지만 운영하면서 나오는 요소들을 계속 고려하면서 발전 시켜야 합니다.
- 특정 코드 조각이 변경되었을 때 어디까지 테스트 해야할 지 명확
- 코드의 중복은 어쩔 수 없지만, 그보다 이득에 초점
- 코드 복사 두려워 하지 않아야 함
- mail 프론트엔드 개발자는 드라이브 개발자 대신 메일 기획자와 이야기하는 시간이 늘어남
구글 사례로 짚어보는 디자인 시스템의 진화
대상
- 디자인 시스템 구축에 관심이 많은 개발자 및 디자이너
이정영 - Google
프로덕트 조직에서 디자인 시스템을 적용하는 것은 더 이상 새로운 개념이 아니라 당연한 것으로 자리 잡았습니다. 하지만 프로덕트와 그 조직의 스테이지에 따라 전혀 다른 과제가 되기도 합니다. 라인에서 맨땅에서 디자인 시스템을 시작하고, 구글에서는 성숙한 상태의 디자인 시스템을 리딩한 경험을 바탕으로 디자인 시스템의 현재와 미래, 적용 노하우를 알아봅니다.
2개 회사 디자인 시스템 경헝
- Line Design System
- 제로 베이스 시작
- Google Search App Design System
- 상위 디자인시스템 존재
contents
why we need design system
- 구글의 과거 방식
- top-down 방식
- 개별 피처의 디자인 완성도에 집중
- 구글의 현재 방식
- 일정 x, 팀이 자신감이 생겼을 때 런칭
- 컴포넌트를 통한 테스트 환경 구축
- 구글 merterial update 내용
- 컬러 : 사용자의 개개인 컬러를 사용
- 따뜻한
- 사용자 input 에 따라 반응
- typography
- google sans 사용
- iconography
- img → font
- 한 파일에서 weight fill grade optical sizes 변경 가능
- shape
- 유저 최우선 배려
- 거의 모든 종류의 모양 지원
- motion
- 컬러 : 사용자의 개개인 컬러를 사용
- + ios 방향 : 한개 컴포넌트를 꾸준히 업데이트, 조금씩 다듬어 나감
- 디자인 시스템의 가치
- efficiency
- 일괄적인 용어 사용
- 조직 전체 효율성과 생산성
- usability
- 일관성 있는 ux 는 제품 팀의 효율성을 증가시키는 것에서 나아가 더 아는 사용자 경험 만듬
- 같은 컴포넌트는 같게 동작하기 때문
- product identity
- 회사와 제품이 추구하는 전체적인 가치를 유저에게 이야기함
evolving design system
Stage0 : Aligned design guideline
- 로컬파일 design only
- 디자이너들 사이에서도 명확하지 않은 싱크
- 리딩 주체 불명확
- Ps
stage1: cloud design library
- 클라우드 라이브러리 일관성 개선
- 클라우드를 통한 라이브러리 배포, 디자인 시스템 팀 셋업
- Design Legacy 개선, Design Foundation 정립
- UI refresh
stage2: code-design sync
- code & design sync, reusable component 제작
- documentation, ui migration, iteration process
- figma
stage3: company level design system
- 프로덕트별로 디자인시스템 존재/ 상속관계 정의/디자인 원칙 재정립
- design tokens 도입(엔지니어, 기획자, 디자이너 모두 같은 용어로 디자인을 명명)
- 크로스 플랫폼 커버
signals for design system
- 디자인 시스템이 필요할 때
- 팀이 커지고 그에 따라 일관성이 무너지는 경우
- colors : 500개 + 같은 의미의 여러개 아이콘 → system ui colors + extended colors, icon 전체 set
- 팀이 커지고 그에 따라 일관성이 무너지는 경우
- 프로덕트가 많아지면서 회사 차원의 디자인 시스템 언어가 필요한 시기
- UX 조직이 스케일이 커지고 역할을 확장해야 하는 시기
- 업무 효율 증가, 유저에게 임팩트를 줄 수 있는 경험 고민
- 제품 전체적인 디자인 리프레시를 앞두고 있는 경우
- 수업찾기 phase1, 홈개편 등..ㅎ
- 때로는 그저 새로운 디자인 툴의 도임과 발맞추어서
ex. Line
노하우와 팁
- 엔지니어와 디자이너의 협업
- 손에 잡히는 가시적인 마일스톤
- 중간중간 배포
- 프로덕트 임팩트를 초기부터 설정
- visibility를 생각하고 팀을 키우기
- 당장 팀에게 도움이 되는 부분부터
- ex. 모두 다른 애니메이션 효과 통일하기
- 당장 팀에게 도움이 되는 부분부터
- 열린 자세로, 여러 채널로 커뮤니케이션
괴물 같이 변한 Dooray! 웹앱 정리하기
대상- 웹앱이 복잡해져 어떻게 정리할지 고민하시는 분
김부승 - NHN Dooray
Dooray 웹앱이 커지면서 유지보수가 어려워지고, 이를 해결하기 위해서 정리해 나간 방법이 왜 필요했고 어떻게 바뀌었는지 공유합니다.
웹앱은 왜 괴물같이 변했냐?
- 어제의 코드는 오늘의 레거시
- dooray : angularJS 로 개발. -> vue 로 전환
- 예전 계획: 점진적으로 프론트엔드 프레임워크 교체하기
angularJS 위에 vue 컴포넌트 개발 -> 점진적으로 기존 컴포넌트 vue 로 변환 -> 최종 vue 로 전환.(우선순위 밀림)
현재까지 7개 중 2개 전환 : 총 9년 소요될듯.. -> 문제 발생 - 공통 컴포넌트 문제 (angularJS, Vue)
angularJS 와 vue 의 공통컴포넌트 : 각각 만든다. -> 기능 추가 2번, 버그 해결 2번
vue 에서 컴포넌트를 만들어서 angularJS 와 통신한다. -> 통신코드 1번, vue 코드 1번 2번 코드 수정 -> angular와 vue가 서로 다른 라이프사이클을 가지고 있어서 충돌 - vue 정리한 코드 문제점 (vue v2)
- 타입추론 x
- 빅 컴포넌트
- watch 코드 연쇄로 코드 추적 -> 디버깅 어려움
- 코드 스타일 파편화
- reset : zero 베이스 부터 react 로 쌓아올림
선택한 이유- 순수한 함수 형태 : 타입추론 잘됨
- 프론트엔드에서 가장 많이 사용
- 레퍼런스 들이 굉장히 많음
- 점진적 전환은 시간이 너무 오래 걸린다. (잠시 기능 개발을 멈추고 리뉴얼시작)
컴포넌트 정리하기
- 구성요소
- 값정리, 공유
- color
- typography
- 그림자
- 기본 컴포넌트 요소 -> 공통적으로 모아서 같이 사용(2번 작업필요 없음): story-book 사용, 중복 컴포넌트가 나오면 안된다. (자란다에서 정말 지켜져야 하는 부분이 아닐까..)
- 버튼
- 목록 요소
- 아코디언
- LMB 컴포넌트 요소
- ui 형성에 상태가 필요한 경우
- ui 형성에 상태가 필요하지 않은 경우
- 컨테이너/프리젠터 패턴
- ex. server 에 강아지 정보 저장
- container 에서는 fetch dogs 로 정보 가져옴 : 상태 책임
- presentional component 에 props 로 넘겨서 ui 보여줌
- 상위 컴포넌트가 랜더링 할때, 하위 컴포넌트가 랜더링 되지 않도록 React.memo 적극 활용
- 컨테이너 자식 > dogs props 넘김 메모 컴포넌트 1개 (dogs 가 A 로 같으면 리랜더 x B로 변경될 때만 랜더링)> 컴포넌트들을 모아서 화면 그림
- 프리젠트 컴포넌트 : 스토리북으로 세팅
- 값정리, 공유
데이터 정리
- 컴포넌트 안에서 데이터 = 상태
- ex. 열기/닫기, 임시보관함, 프로젝트 목록, 활성화 boolean -> 어디에 저장? 컨테이너 or 리덕스 같은 store
- 컨테이너에서 상태 저장했을 때 장점
- useState 사용, 상태 추가 쉬움
- 외부 상태 참조 어려움
- 계산 로직은 컨테이너에만 위치
- 비동기 로직 다루기 어려움
- ex. 컨테이너에서 api 호출할 때, 호출 완료 전 사용자가 페이지 이동하면? 컨테이너가 사라졌을 때 api response 상태 저장할 때가 없어서 에러날 수 있음
- 순서 : 사용자 동작 -> 상태 변경 -> (리)랜더링 -> api 호출
- store 사용
- 상태 추가 시 일이 많을 수 있음 리덕스 등
- 상태 참조 쉬움
- 계산 로직 위치 자유
- 비동기 로직 다루기 쉬움
- 순서: 사용자 동작 -> api 호출 -> 상태 변경 -> (리)랜더링
- ui 스토어, data 스토어로 분리
- ui 스토어
- 영역에 대한 상태 저장, 관련 엑션 처리
- data 스토어
- 도메인 정보를 저장하고 관련 api 호출하여 서버와 클라이언트 싱크 맞춤
- 리덕스 사가로 복잡성 감소
- 동작 흐름 제어
- 비동기 코드를 동기 코드처럼 작성
- 스레드 외부와 통신 : 별도 worker 를 띄워서 사용
- ui 스토어
- 장점
- 데이터 파편화 제거
- 로딩 화면 개선
- 도메인 데이터를 이용해서 미리 데이터를 보여줄 수 있음
- A페이지 -> B페이지 -> A페이지 보았을 때, 성능 향상 (백그라운드로 최신화 api 호출)
- 이전과 같은 데이터라면 컨터이너만 리랜더 되고 자식 컴포넌트들은 모두 유지
테스트 방법
- 프리젠터 컴포넌트 : 스파이 함수처리
- 로직 중요 x
- 화면에 어떻게 보이는지가 가장 중요
- 테스트 x, story-book 으로 확인
- 컨테이너 컴포넌트 : 테스트 대상
- 상태 : mock 으로 전달
- 사가 테스트
- 단위테스트 대신, 사가 함수를 실행하고 그 결과를 확인
- 액션에 의해서 상태가 어떻게 변경되었는지, 어떤 api 호출되었는지로 통합 테스트 작성
- 걱정 : 실행시간 : 191개 test 실행, 24초