NHN FORWARD 2022

Yeony (Nayeon Kim) · 2022-11-25

개발자 인생 처음으로 개발 콘퍼러스를 다녀왔다. 온라인으로 진행하는 건 몇 번 듣긴 했으나, 오프라인은 이번이 처음이다.

NHN FORWARD의 섹션

프론트엔드 개발자로서 (당연히?) 프론트엔드 개발 분야에 관심 있었기 때문에 대부분 Track1 부분에서 머물렀다.
인상 깊었던 여러 내용들을 적어보고자 한다.

내가 참여한 섹션은 이랬다.

  • 거대한 서비스 쪼개서 마이크로 프론트엔드 만들기
  • 구글 사례로 짚어보는 디자인 시스템의 진화
  • 괴물같이 변한 Dooray! 웹앱 정리하기

거대한 서비스 쪼개서 마이크로 프론트엔드 만들기

거대한 서비스 쪼개서 마이크로 프론트엔드 만들기

몸이 성치 않았는데도 열심히, 재밌게 발표해주신 발표자님께 리스펙을...

먼저 Dooray!의 서비스를 간략히 소개받았다.

협업툴로서 드라이브, 메일, 위키 등 여러 서비스가 유기적으로 연결되어 있는 통합 서비스다. 발표의 예시에서는 드라이브와 메일 서비스 2가지 위주로 진행되었다.

Dooray!가 문제를 느낀 지점

  • 여러 서비스가 하나로 통합되어 제공되기 때문에 점점 복잡해짐
  • FE 엔지니어가 모든 도메인 지식을 배우기 어려움
  • 소스가 방대해지며 개발/빌드에 오랜 시간 소요
  • QA, 테스트 과정이 복잡해짐
  • 엔지니어의 기술 선택권

Dooray!가 원했던 개발

  • 하나의 서비스만 독립적으로 개발/배포할 수는 없을까?
  • 따로 프로덕션하고 Dooray! 내에서는 런타임 통합으로 제공하고 싶다.

이런 욕구를 해소하기 위해서는 여러 방법을 떠올릴 수 있었다.

하나의 서비스만 독립적으로 개발하려면?

  • Linked SPA
    • 즉, 서비스별 SPA를 따로 만들기.
    • 메일은 메일 SPA 프로젝트, 드라이브는 드라이브 SPA 프로젝트로 구성한 후 history API를 이용해 클라이언트 라우팅
    • -> 불필요한 소스코드의 엄청난 중복! 메일에서 드라이브로 넘어갈 때마다 새로 페이지를 로딩하기 때문에, SPA로서의 장점은 갖다 버린 게 된다.
  • Unified SPA
    • Application shell
    • 모든 하위 서비스들의 상위 애플리케이션 역할을 하나 만든다.
    • 들어오는 모든 요청을 라우팅에 맞게 하위 서비스에 연결
    • 공통 레이아웃 등을 상위로 분리
    • 서비스, 비즈니스 로직 포함하지 않음
    • 인증, 앱 전체 설정 관리

Dooray!가 서비스를 통합한 방법

메일 서비스에서 드라이브 컴포넌틀를 사용해야 하는 경우, 드라이브 서비스가 가지고 있는 함수를 Dynamic Import한다.

이 상황은 메일에서 파일을 첨부할 때, 드라이브에 있는 파일들을 업로드할 때 발생하는 상황을 가정 하에 설명되었다.

  • 드라이브 첨부가 가능한 경우 사용자에게 버튼이 보임 (드라이브 담당)
  • 드라이브 api 사용 (드라이브 담당)
  • 드라이브에서 넘어온 파일을 메일에 첨부 (메일 담당)
  • 메일 서비스에서 드라이브가 제공한 컴포넌트(드라이브 담당)을 lazy하게 가져옴
    • 이런 경우 Shared 폴더에 공유 파일 조각들을 넣어둔다. (드라이브 담당)

흥미로운 기술은 Webpack5 Module Federation 이었다. (참고: Module Federation Examples)

Dooray!가 마이크로 프론트엔드를 적용하는 이유 중 하나였던 서비스 별 독립적인 배포를 적용하기에 적합한 기술이었던 것.

  • webpack.config.js 를 드라이브 - 메인 서비스로 설정한 후
  • 연결고리(remoteEntry.js)를 생성

이런 방식으로 진행했다고 한다.

물론 특정 서비스만 재배포하는 경우 캐싱이 제대로 처리되지 않는 문제가 있었는데... 이것을 remoteEntry에 버전을 Date.now() 정도로 동적으로 사용하는 방식으로 바꾸어 처리했다고 한다. 들으면서 저렇게 파일을 계속 가져와도 되나? 하는 생각이 들었는데, 딱 그 부분을 명쾌하게 설명해주셨다. remoteEntry.js는 노출된 소스코드의 경로만 보여주기 때문에 가벼워서 매번 불러와도 성능에 무리가 없었다고.

코딩보다 중요한 것들

마무리하며 Dooray!의 사례만이 일반적인 것은 아니란 점을 짚고 넘어갔다.

  • 마이크로 프론트엔드는 구체적인 기술이 아니다.
  • 서비스가 커져서 복잡도가 늘어나면 선택할 수 있는 여러 대안 중 하나에 불과
  • 코드 중복은 어쩔 수 없는 문제. 이득에 초점을 맞추자.
  • 메일 FE엔지니어가 대화해야할 대상은 드라이브 FE엔지니어가 아니라 메일서비스 기획자, 메일서비스 BE엔지니어.

궁금했던 점

발표를 들으며 Dooray!가 죽어버린 앵귤러를 쓰고 있었다는 사실에 좀 놀랐다. 초기에 왜 앵귤러를 선택했는지, 그리고 왜 React가 아닌 Vue로 바꾸려 했었는지 그 의사결정의 과정이 궁금했다.



구글 사례로 짚어보는 디자인 시스템의 진화

나는 Figma에 관심이 좀 있고, 최근 UX 분야도 스터디를 하고 있기 때문에 무척 재미있었던 섹션이었다.

이 섹션은 비공개로 사진 촬영이 제한되어 있었다. 따라서 회사와 관련된 내용은 생략하고, 일반적인 내용만 적어보겠다.

디자인 시스템을 구축하는 이유

  • Effciency
    • 일관적인 용어 사용해 효율성, 생산성 상승
    • 개발과 디자인의 Sync가 이뤄진다.
  • Usability
    • 일관성 있는 UX
    • 복잡한 상황에서도 즉시 이해가능한 유저 플로우
  • Product Identity
    • 제품의 인상을 결정하는 Color, Typography 등을 통일

디자인 시스템, 언제 시작할까?

  • 디자인 시스템을 시작하기 좋은 신호들
    • 팀이 점점 커지고 그에 따라 일관성이 무너지는 경우
      • 사람 = document가 되는 경우 (ㅋㅋ)
        비슷한 색상이 너무 많은 경우 (gray 계열만 수십가지라면? 당연히 일관성이 없다.)
        유사한 아이콘이 너무 많은 경우 (단순 arrow 아이콘만 해도 수십 수백가지다.)
    • 프로덕트가 많아지면서 회사 차원의 Design Language가 필요한 시기
    • UX조직의 스케일이 커지고 역할을 확장해야 하는 시기
      • Research 강화
        A/B 테스팅 및 experiment 확대
        Product User Value 정의
        CUJ Model 도입
    • 제품의 전체적인 디자인 리프레쉬를 앞두고 있는 경우
    • 새로운 디자인 툴의 도입과 발맞춰...
      • Figma를 쓰기로 했는데 디자인 시스템을 구축 안하는 건 이상할 지경.

디자인 시스템, 적용 노하우와 팁

  • 디자인 시스템과 열정적인 엔지니어와 함께
    • 이름에 디자인이 들어갈 뿐, 디자이너만 리딩하는 것이 아니다.
    • 엔지니어 레벨에서도 디자인에서 알기 힘든 코드 레거시, 중복된 리소스 등을 알려줘야 한다.
  • 손에 잡히는 가시적인 마일스톤
    • 디자인 시스템은 긴 시간을 투자해야 하는 바닥 공사와 같다.
  • Product Impact를 초기부터 설정
  • Visibility를 생각하고, 팀을 키우기
    • 초기부터 사람들에게 공유하고, 피드백을 받기
    • 완벽함을 추구하기보다 당장 팀에게 도움이 되는 부분을 공유하면 더 큰 관심과 서포트를 받을 수 있다.
  • 열린 자세로, 여러 채널로 커뮤니케이션
    • 디자인 시스템이 때로는 Creativity를 구속하는 인상을 줄 수도 있다.
    • 더 좋은 제안과 아이디어를 언제든지 환영하는 방향으로, 또 자발적인 기여를 권장하는 쪽으로 나아가기
    • 업데이트된 내용에 대해서는 뉴스레터, 메일, 미팅, 문서 등 가능한 모든 채널을 동원해 전파하기
  • 디자인 시스템을 꾸준히 운영되는 모델로 만들기
    • 프로세스 자체가 디자인 시스템의 절반 이상

궁금했던 점

디자인도 도메인 별로 나눠서 만들까?



괴물같이 변한 Dooray! 웹앱 정리하기

괴물같이 변한 Dooray! 웹앱 정리하기

11시에 진행했던 마이크로 프론트엔드 구축기의 연장선 같았던 발표였다. 앗 시작 표지 못찍었다

왜? 정리를 시작했을까?

Dooray!의 웹앱을 정리할 때 생긴 고민을 이러했다고 한다.

  • 앵귤러와 뷰로 나눠진 컴포넌트를 어떻게 동일화할 수 있을까?
    • 하나씩 만든다. -> 쉬우나 번거로움 (앵 따로 뷰 따로)

Dooray!는 초기에 앵귤러로 개발되었고, Vue로 점진적으로 바꾸고 있었다고 한다.

하지만 그 바꾸는 Vue의 버전이 2.x대였는지... 역시나 타입 추론과 관리가 아주 어려웠던 듯 하다.

뷰로 정리한 코드의 문제점도 들을 수 있었다.

  • Vue 2.x 대는 타입 추론이 어려움
  • 빅 컴포넌트
  • watch 코드 연쇄로 코드 추적 어려움
  • 코드 스타일 파편화

Vue도 사용하는 입장에서 매우 공감되었다. 템플릿, 스크립트, 스타일이 모두 vue 하나에 들어가고, 상태 변화를 감지하기 쉽다보니 엉키는 경우가 많다.

따라서 Dooray!는 리액트로 점진적이지 않은 새로운 구축을 시도했다고 한다.

리액트를 도입하며 바뀐 부분은 이러하다.

  • 명시적으로 코드를 호출
  • 순수한 함수의 호출 형태(타입 추론이 잘 된다!)

컴포넌트는 어떻게 정리했을까?

  • 공통 컴포넌트 공유
    • 중복적인 컴포넌트가 나오면 안됨
  • 상태가 있는 것과 없는 것을 구분하기?!
    • 상태를 주입하는 껍데기 컴포넌트를 생성.
    • 컨테이너/프레젠터 패턴
    • 컴포넌트 메모
      • 컴포넌트가 동일한 props, 동일한 결과를 렌더링해낸다면, React.memo를 호출하고 결과를 메모이징하는 것이 중요했다.
      • 불필요한 리렌더링을 줄이는 포인트
      • 참고 (React.memo() 현명하게 사용하기)
  • 스토리북 사용

인상 깊었던 부분은 상태를 주입하는 껍데기 컴포넌트 만들기였다.

지금까지 나는 비슷한 형태지만 상태 유무가 다르면 다른 컴포넌트로 간주하고 작성을 하거나, 혹은 무조건 상태가 있는 거로 작성을 하고 상태를 사용하지 않았다. Dooray!에서 적용한 방식은 컴포넌트의 확장을 잘 이용한 사례 같아서 적용하고 싶어졌다.

데이터는 어떻게 정리했을까?

컴포넌트의 데이터는 대개의 경우 상태다. 따라서 Dooray!는 상태관리에 무척 공을 들인 것 같았다.

아무래도 여러 서비스들이 유기적으로 데이터를 주고 받는 통합 서비스다 보니 더욱 그랬을 것이라 생각했다.

  • 상태 저장
    • 컨테이너
      • 상태 추가 쉬움 (useState 사용)
      • 외부 상태는 참조하기 어려움
      • 계산 로직은 컨테이너에만 위치
      • 비동기 로직은 다루기 어려움
        사용자가 api를 호출하고 데이터 return이 완료되기 전에 다른 페이지로 이동해 버리면? 데이터가 반영될 컴포넌트는 이미 화면에서 사라진 상태.
    • 스토어
      • 상태 추가 시 일이 많음
      • 상태 참조 쉬움
      • 계산 로직 위치 자유로움
      • 비동기 로직 다루기 쉬움!
        컨테이너의 api 호출과 달리, 스토어는 화면이 사라지더라도 사라지는 값이 아니다. 따라서 비동기 로직을 다룰 때 쉽다.
    • 역할
      • 프레젠터 : 화면을 그림
      • 컨테이너 : 스토어의 상태를 프레젠터에 연결. 프레젠터에서 동작 시 스토어에 연결
      • 스토어 : 모든 데이터를 저장
  • 예시
    • 프로젝트 목록 컴포넌트가 있는 경우
    • 프로젝트 = 프로젝트 ID + 프로젝트 Data 라는 2개의 상태로 나눌 수 있다.
    • 성격이 다른 스토어를 관리하기 위해 UI 스토어, 데이터 스토어로 나누었다.image image
      • 장점1. 데이터 파편화를 막을 수 있다.
        장점2. 로딩 화면이 개선된다. 다른 페이지에 다녀와도 이미 데이터는 스토어에 저장되어 있음.
      • 단점이라면 최신 데이터가 아니라는 점.
        하지만 최신 api 를 호출해 최신 데이터가 기존 데이터와 다르지 않으면, 컨테이너는 re-rendering 되더라도, 컴포넌트 자체는 다시 렌더링되지 않는다.
  • 모든 데이터를 리덕스로 몰아서 관리하다보니, 로직 복잡도는 올라간다.
    • 이것을 리덕스 사가로 컨트롤해 액션을 관리.
    • ex) 사용자가 '클릭'해야 하는 경우에 '더블클릭'하는 경우, 사가를 통해 흐름제어.
    • 동기 코드처럼 작성.

궁금했던 점

Dooray! 기술블로그!! 왜 없는거죠? 만들어주시죠...!! 😭

전체 후기

유익한 발표를 들을 수 있어서 좋았다. 기술을 좀더 잘, 많이, 깊게 배우고 싶은 욕구가 생겼다.

NHN FORWARD

내년에도 갈 수 있다면, Dooray!의 마이크로 프론트엔드가 어떤 방식으로 변화했는지 꼭 듣고싶다. 😊


etc
Loading script...
© 2022 Nayeon Yeony Kim