DEVIEW 2020 정리 - 묻고 한 벌로 가
해당 글은 제가 DEVIEW 2020의 발표 영상을 보면서 문서화한 글입니다. 발표 영상을 보시려면 아래 링크를 확인해주세요.
묻고 한 벌로 가
한 벌의 코드로 모바일 웹/모바일 앱/PC 웹 서비스 확장 개발기
- 여러 환경으로 서비스를 확장하면서 겪었던 시행착오를 공유
- 네이버 플레이스 서비스의 기술 스택: JavaScript 웹 fullstack
1. 왜 코드 한 벌을 여러 서비스에 넣었을까?
1.1 플레이스와 지도
- 플레이스와 지도는 원래 다른 서비스
- "검색에서 업종별 특화 화면을 보여주면 어떨까?"라는 생각에서 플레이스 서비스 시작
- 식당, 숙박, 미용실, 관광 명소 등
1.2 플레이스/지도 통합의 배경
- 플레이스 서비스의 성장 업종별로 특화 및 세분화
- 해수욕장, 은행, 병/의원, 주유소, 약국(공적마스크), 미용실(스타일 검색)
- 문제점: NAVER 검색 결과와 지도 검색 결과가 다르게 됨
1.3 어떻게 통합할까?
가장 빠르고 효율적인 방법 찾기
- 중복 개발 피하기 -> 플레이스 서비스를 지도 앱과 PC 지도에 넣자
- 코드 재사용할 수 있도록 기존 화면을 그.대.로. 집어 넣으면 어떨까?
- 지도앱에 Webview 형태로 플레이스 서비스를 넣으면 되지 않을까?
2. 지도앱(iOS/Android) 장소결과를 Native에서 Webview로 변경하기
2.1 어느 영역을 Webview로 전환하지?
설계 조건
- 사용자가 어색함을 느끼지 않아야 한다.
- 플레이스는 가급적 독립적인 영역으로 고립시켜야 한다.
- Native와 Webview의 장점을 잘 살릴 수 있어야 한다.
2.2 Webview 설계
장소 검색 결과는 플레이스 Webview가 담당하고 그 외는 지도앱에서 담당한다.
- 플레이스 목록 페이지 & 업체 페이지에서 가져오자!
- 지도앱 특화 기능들은 분기 처리로 대응한다.
2.3 지도앱 + 플레이스 검색 Flow
2.4 Webview -> Native 통신
목록 결과를 지도에 마커로 그려줘야 함
- Webview <-> Native 어떻게 통신할 것인가?
- (aOS) App scheme 사용 (inapp://)
- (iOS) webkit.messageHandler 사용
Native에서 Webview 호출 방식
- 기본: url 호출
- 문제: '현 지도에서 검색'터치 시 깜빡임
- 원인: Native -> Webview - url 변경 호출
- 서버로 요청이 넘어가서 SSR된 결과를 그린다.
- SPA인데?
- 보는 화면에서 목록만 업데이트 시켜주기
- 해결: Webview에서 Global 함수 제공
- SSR이 아닌 CSR로 업데이트
Webview 밑에 깔려 있는 지도판을 터치 할 수 있어야 한다.
- Webview 위에 touch 이벤트를 받을 수 있는 가상의 layer를 하나 더 두자
- Layer 사이즈는 Webview에서 전달하는 이벤트 기반으로 동작
- Webview가 스크롤 될 때마다 높이값을 Native에 전달
Q. 왜 Webview 영역 전체를 스크롤하지 않았나?
A. Webview 영역을 위로 올려 최상단이 되었을 때 내부 system scroll로 전환되는 사용성이 좋지 않음
Native 카드와 Webview를 묶어서 자연스럽게 보이도록 하자!
3. PC지도 서비스(Angular)에 플레이스 서비스(React) iframe 으로 집어넣기
3.1 어떻게 통합할 것인가?
- 1안) 플레이스는 API만 제공 & 화면은 지도웹에서
- 2안) 플레이스 화면을 재사용 & 지도웹은 마커
- 2-1안) Angular에 React Component 포함
- 2-2안) HTML import(link rel) -> deprecated
- 2-3안) iframe 으로 포함
3.2 iframe 괜찮을까?!
단점)
- url 문제
- debugging 어려움
- 보안 조심
장점)
- 두 영역을 분리하여 고립시키기에는 오히려 좋다.
- cross domain components 조합
3.3 Angular + React
지도 서비스(Angular)와 플레이스 서비스(React)의 공존
- iframe 사용으로 서비스 간 고립
- library/framework가 달라서 발생하는 문제는 없음
- 서비스 간에 통신을 어떻게 할 지가 더 중요
3.4 PC지도 + 플레이스 검색 flow
3.5 서비스간의 통신
단순한 통신 흐름 지향
- 지도 -> 플레이스
- iframe URL 변경
- 플레이스 -> 지도
- postMessage() 사용
3.6 PC서비스에서 모바일과 달라지는 점
1) 가로 스크롤
-
가로 system scroll
-
PC에서 가로 스크롤은 익숙하지 않음
-
IE11 스크롤 커스텀 노출이 어려움
- @egjs/flicking + 좌우 버튼 추가
2) 무한 스크롤 관련 처리
- 모바일: 무한 스크롤
- PC: 페이징
- wrapper component로 대응
3) PC만 지원하는 이벤트처리
- mouseenter 이벤트
- mouseleave 이벤트
4) 사용성 때문에 변경되는 부분
- 동작 환경과 사용성에 맞춰 변경
- 지도 탭 삭제, 뒤로가기 버튼 삭제, MY 탭 삭제 등
- 넓은 화면을 활용
- 포토뷰어 / 거리뷰
- 외부 페이지 이동
- iframe 내가 아닌 새 창에서 외부 페이지가 열림
- 로그인이 필요한 경우
- iframe 본 창에 로그인 처리 요청
- 본 창 & iframe 새로고침(로그인 쿠키 반영)
3.7 Internet Explorer 11 대응
Build target 변경
- 모바일
4. 한 벌의 코드로 여러 서비스 제공은 어떻게 할까?
4.1 플레이스 서비스 개발 스택
JavaScript Web Fullstack
- TypeScript
- Node.js with Koa
- React with hooks
- GraphQL with Apollo
- kubernetes with NCC
4.2 어떻게 분기처리 할 것인가?
지속 가능한 코드 = 유지보수하기 쉬운 코드
- 서비스 환경을 체크하는 if/else 분기는 되도록 적게
- component 단위를 작은 기능에 집중해서 작게 만든다.
서비스 운영이 쉬운 환경 구성
- 코드는 재사용
- domain & server & build는 분리
4.3 배포 환경 분리
독립된 별도 서버군으로 별도 도메인으로 대응
-
코드는 재사용하지만 서비스간의 독립성은 보장
- webpack build를 별도로 한다.
- 환경별로 entry 포인트를 따로 가져간다.
-
API 레벨의 분기
- GraphQL의 장점을 살리자
- GraphQL은 versionless 추구
- 하위 호환성을 지키기 위해 field type 변경 X
- 변경이 필요한 field는 신규로 추가하여 대응
- 화면별로 필요한 field를 정의하고 호출하는 것으로 정함
- GraphQL resolver는 client가 어떤 환경인지 몰라도 되도록 관리
- 분기의 권한은 client에게 있다.
- GraphQL query 레벨에서 device 별 분기 처리 진행
- @skip, @include 사용
- GraphQL은 versionless 추구
- GraphQL의 장점을 살리자
5. 성능 개선
5.1 이미지 사이즈를 줄여야 한다.
사진이 많은 건 좋은데 많이 느려졌다.
- 빠르고 가벼운 화면 VS. 사용자에게 좋은 정보
- 이미지 최적화
5.2. 첫 로딩 사이즈를 줄여야 한다.
이미지 lazy loading & Component lazy loading
- 화면에 보이는 부분만 loading
- DOM 최적화 + 이미지 load 최적화
- react-lazyload 사용
Dynamic Loading
- code splitting - asset size 최적화
- @loadable/component
- react-router와 조합 -> path 별 resource 분리
SSR인데 왜 화면이 늦게 보일까?
- 플레이스 페이지 노출여부 제어는 지도에서 한다.
- 플레이스 페이지 로드 완료는 message로 플레이스에서 지도로 전달
- 원인: message 전달 타이밍 이슈
- CSR 시점에 message 전달 -> SSR의 이점 못살림
- SSR load 후 바로 로드 완료 message 전달로 수정
- 단점
- 화면은 미리 보이지만 interaction은 CSR 후 가능
- "SSR과 CSR 사이의 시간 < 사용자가 화면을 인식하는 시간"이기 때문에 괜찮다고 판단
5.3 Rendering 최적화
스크롤 이벤트로 인한 React Component re-render 최적화
- 상위 Component에 걸려있는 scroll 이벤트로 인한 불필요한 re-render
- component 별로 스크롤 이벤트가 필요한 부분만 처리하는 hook 생성
5.4 스크롤 최적화
IntersectionObserver를 이용한 무한 스크롤 최적화
- 무한 스크롤 시 언제 추가 contents 로딩 할건지 확인
- 기존: scroll event + getBoundingClientRect() 사용
- 개선: IntersectionObserver() 사용 - async non-blocking API
장점
- frame 안정적, 저사양 폰에서 효과가 좋음
- 코드 개선 효과
6. 앞으로 해야할 일
- 개발 후 확인해야 할 환경이 많다 -> 테스트 자동화
- polyfill 관리 불편 -> 환경별 자동화
- 업종 추가/개선
- 끊임 없는 Refactoring/성능 개선/사용성 개선
'Devlog' 카테고리의 다른 글
가상 오피스: 폰출근의 시대 (0) | 2021.08.18 |
---|---|
돌고 도는 가트너의 하이프 사이클 (0) | 2020.12.10 |
DEVIEW 2020 WELCOME 패키지 (0) | 2020.11.22 |
코로나에 대처하는 지도앱의 자세 🗺 (0) | 2020.04.05 |
당신의 Github을 매력적으로 보일 수 있는 방법들 ✨ (0) | 2020.03.29 |
댓글
이 글 공유하기
다른 글
-
가상 오피스: 폰출근의 시대
가상 오피스: 폰출근의 시대
2021.08.18 -
돌고 도는 가트너의 하이프 사이클
돌고 도는 가트너의 하이프 사이클
2020.12.10 -
DEVIEW 2020 WELCOME 패키지
DEVIEW 2020 WELCOME 패키지
2020.11.22 -
코로나에 대처하는 지도앱의 자세 🗺
코로나에 대처하는 지도앱의 자세 🗺
2020.04.05