DEVIEW Review(2018.10.13)
1. React Native: 웹 개발자가 한달만에 앱 출시하기
(발표자료: https://www.slideshare.net/deview/121react-native)
React Native
Facebook, Instagram, Discord 등 많은 플랫폼에서 React Native가 사용되고 있다. 네이티브 앱에서 React Native로 전환한 후 많은 덕을 보았다.
빠른 개발속도, 98%에 육박하는 iOS, Android간의 코드 공유 등 탁월한 선택이라고 이야기함.
React Native의 장점은 투입한 개발 리소스에 비해 결과물의 퀄리티가 좋다는 점과 플랫폼간 공유 코드를 생성함으로써 유지 보수비용이 낮아진다는 점이다.
‘단 기간에 프로덕션 레벨의 크로스 플랫폼을 만들어야 할 때 고려할 수 있는 여러 선택지 중 가성비가 가장 좋은 프레임워크!’
Structure
네이티브 영역과, 자바스크립트 스레드, 그 둘을 이어주는 다리역할을 하는 브릿지(Bridge)로 구성되어있음.
— Bridged
- Asynchronous
- Serializable — 직렬화, 네이티브 영역과 JS스레드간 데이터 공유의 많은 관리 이슈로 인해 데이터를 직렬화, 역직렬화하여 통신한다. but, 간결해진 구조 대신 성능저하가 발생함.
- Batched — 네이티브가 호출될때마다 앞서 말한 직렬화, 역직렬화가 일어나면서 부하가 발생함 -> 큐에 담아서 5ms단위로 일괄 처리함으로써 성능 개선
MessageQueue.spy함수로 Bridge를 모니터링할 수 있다.
— Handling Event
함수에서 setState와, API호출을 사용한다고 가정하자.
- Event occurred: Native module
이벤트가 발생하고, setState를 통해 UI 업데이트가 필요해져 네이티브 호출이 일어나고 메시지 큐에 담김. - Serialize event: Bridge
메시지 큐에 담긴 일들을 받아 JS스레드로 전달. - Process event, Call native method: JS thread
API호출을 통해 내부적으로 네이티브 함수들이 호출되고, 메시지 큐에 담김. - Serialize command: Bridge
메시지 큐에 담긴 일들을 네이티브모듈로 전달해줌. - Process command, Update UI: Native module
전달받은 일들을 수행함.
Tips
- 작업 시 복잡한 애니메이션이나 인터랙션은 안드로이드로 확인해본다.
( iOS에 비해 성능이 떨어져 잘 안돌아갈 수 있으므로 꼭 확인하길…! ) - Optional chaining 가용
- babel-plugin-root-import를 통해 import 경로지옥 탈출! ( 절대경로 사용 )
- 패키지 버전을 고정하자 ( 버젼 앞 ^를 빼거나 설치 시 exact키워드 사용 )
- 타입 시스템으로 Flow 사용
- TypeScript도 좋지만 아직은 Flow를 사용하는것이 더 편하다. 추후 TS지원이 더 많아지면 그땐 TS를 쓰자.
- 가끔 Flow가 지원하지 않는 문법들이 있는데, ( ex. Optional chaining ) 이는 //$FlowFixedInNextDeploy 주석을 사용하여 회피하자. - react-native-fast-image를 사용하면 기존 Image태그의 몇 가지문제점을 해결해줌
- JavaScriptCore ( JSC )의 동작 오류
- 디버그 모드는 V8, 빌드된 앱은 JSC로 동작하여 Date객체 등의 동작이 다를 수 있으니 꼭 확인해야함 ( moment.js등의 라이브러리로도 해결 가능)
- 안드로이드가 오래된 JSC를 사용하여 차이가 있을 수 있음 ( 플랫폼 별 컴포넌트 스타일링을 통해 해결하자! ) - 안드로이드가 Text에 자동으로 위 아래 padding을 삽입함으로 플랫폼간 차이 발생
- includeFontPadding스타일 속성 false값으로 두면 해결된다.
- 공용 <Text />컴포넌트를 만들어 속성을 미리 정의하는것도 좋은 방법. - 최소 터치 영역 44px보장하기
- hitSlop속성을 통해 실제 터치영역을 확장할 수 있다. - render()함수가 최초에 한번 실행됨을 까먹지 말자! ( React에도 해당하는 이야기! )
- state에 isLoading변수를 두어 불필요한 초기 렌더링을 제거하자 - setInterval등의 함수는 clearInterval함수를 호출하지 않으면 컴포넌트가 언마운트되어도 백그라운드에서 계속 실행되므로 조심하자.
- 애니메이션 동작에서 60 FPS을 보장하기
- default인 JSDriver를 사용하면 Bridge를 거쳐야 함으로 성능저하가 발생한다. 애니메이션 내부 useNativeDriver속성의 값을 true로 해주면, Bridge를 거치지 않고 UI업데이트가 일어나 효율적이다.
- but, NativeDriver가 모든 스타일을 지원하지 않으므로 적정 선에서 타협할것. - 반복되는 애니메이션으로 인해 실행시점의 문제나 코드실행의 문제가 발생할 수 있으니 무거운 연산은 다음 프레임으로 실행지연시켜 앱 반응성을 개선하자 ( 무슨 말인지 모르겠다… )
- FlatList에서 높이가 고정된 구성이라면 getItemLayout속성을 사용하자.
- 레이아웃의 크기가 매번 계산되지 않아 성능이 개선된다. - React.createRef()를 권장. ( 기존 방식이 deprecate되었다. )
- babel-plugin-transform-remove-console을 통해 console을 제거하자.
- 이미지를 최적화하자. ( TinyPNG, OptiPNG )
- <LottieView />로 Adobe After Effects로 작업한 애니메이션을 JSON형식으로 가져와 export할 수 있다.
Q&A
- Bridge 통신과정 중 직렬화로 인해 성능저하가 발생하므로 큰 영상파일 등은 네이티브 모듈을 사용하는것이 좋을 것 같다.
2. 책에서는 맛 볼 수 없는 HTML5 Canvas 이야기
(발표자료: https://www.slideshare.net/deview/122-html5-canvas)
How browser draw image?
Rendering Engine이 우리가 작성한 태그들을 어떻게 그릴지 알고있다.
- Parsing DOM, CSS( 어떤 모양을 그릴지 결정 )
- Layouting ( 위치와 사이즈를 결정 )
- Layerization ( 그리는 순서를 결정 )
- Rendering Engine에 의해 그리는 방법(순서 등) 결정
- 어떤 모양으로, 어느 위치에 어느정도 크기로, 어떤 순서로 그릴지.
How Canvas draw image?
Canvas도 HTML element이기에 위와 동일하게 그려짐.
But, 캔버스의 내부를 어떻게 그릴지는 개발자의 손(JS 코드)에 달려있다.
- 렌더링 엔진이 script태그 내 JS코드를 읽음.
- JS Engine이 코드를 해석.
- 해석한 결과를 다시 렌더링 엔진에 넘김
- 그래픽 라이브러리를 호출함으로써 이미지가 그려짐
Problem of Canvas
캔버스의 목적은 다이나믹하게 변하는 그래픽 즉, 애니메이션 처리에 있다.
— VSync
60fps를 유지하기 위해 우리는 약 16.6ms마다 한번씩 렌더링 할 수 있어야 함.
but…만약 렌더링할게 너무 많아서 연산이 무거워지면, 시간을 초과할 수 있음 ( 렌더링의 모든것이 Main thread에서 일어나기에 너무 바쁘다… )in
— Optimization in browser
브라우저 단에서 최적화가 진행되어 성능이 많이 개선됨.
- 최신 브라우저는 Canvas를 Raster thread(GPU) 에서 처리함 (그리는것을 이야기함. canvas에 대한 JS코드는 여전히 메인 스레드에서 담당함.)
— Optimization with developer
- Fullscreen Canvas를 사용하여 DOM 조작을 줄이기
- WebGL로 렌더링
- Background Canvas 사용하기 (미리 그려놓기)
이러한 노력과 개선에도 불구하고, 아래의 문제점들이 있음.
- JS엔진과 렌더링 엔진간의 binding overhead
- GPU의 도움을 받아도 여전히 발생하는 그래픽 라이브러리 내부 overhead
- DOM렌더링을 하기에도 여전히 Main thread는 바쁨…
Offscreen Canvas!
DOM Rendering과 분리되어 다른 thread인 Web Worker에서 렌더링 할 수 있기 때문에 매우 큰 성능 향상을 보인다. ( canvas 를 그리는 JS코드 해석까지 web worker를 통해 렌더링함. )
case study
발표자료 뒷부분 참고( p90 ~ )
Example
canvas 애니메이션이 동작하는 와중에 무한루프를 돌린다면 어떻게 될까?
- normal한 canvas로 그리는 애니메이션은 메인 스레드의 과부하로 동작이 멈춘다.
- but, Offscreen canvas로 그리는 애니메이션은 메인스레드가 아닌 다른 스레드에서 담당하므로 그대로 동작이 유지된다.
3. Javascript 배틀그라운드로부터 살아남기
(발표자료: https://www.slideshare.net/deview/123javascript)
빠르게 많은 양의 정보를 설명해주셨다.
발표자료를 보면 된다.
4. 네이버에서 사용되는 여러가지 Data Platform, 그리고 MongoDB
(발표자료: https://www.slideshare.net/deview/124-data-platform-mongodb)
NAVER’s Data Flatform
초창기에는 web server ← → RDBMS server의 2 tier 구조였으나 서비스가 점점 커짐에 따라 DB쿼리가 복잡하고 무거워졌다.
그에 따라, 빠른 응답을 보장하기 위해 Cache를 추가했다.
빅데이터성 데이터의 저장을 위해 HBase를 사용하였다. ( RDBMS로는 공간, 비용의 문제 발생)
MongoDB
기존의 데이터 플랫폼으로는 커버되지 않는 영역이 필요해지고, 각 개발팀들이 mongoDB를 이용해 자체적으로 운영함에 따라 지원하게 되었다.
— Needs
- Schema-less
- 장점: 사전에 데이터에 대한 구조나 정의를 하지 않아도 된다.
RDMS로는 공통적인 부분을 플랫폼화 할 때, 각 팀들의 요구사항이 조금씩 다를테니, 서비스 별 별도 table로 관리해야 해서 overhead 발생.
- 단점: 미리 데이터에 대한 구조(스키마)를 정의하지 않았기 때문에 디비가 무슨 데이터가 들어올지 알 수가 없다. 따라서 들어오는 데이터들을 key, value쌍으로 저장해야 하는데, 이에 따라 RDBMS에 비해 훨씬 많은 저장 용량을 사용하게 된다. ( 또한 테이블마다 id값이 기본적으로 내장되어 있어 추가로 12byte가 사용된다 ) - Sharding
- 데이터 사이즈가 증가함에 따라 Scale up(단일 서버의 스펙을 증가시키는 것)의 한계가 대두되면서 Scale out(여러대의 서버로 데이터 분산)이 필요해짐
- RDBMS에서도 샤딩으로 scale out 구현 가능하나 확장성이 떨어지고, 개발 및 관리의 overhead가 발생한다.
- 따라서 Auto Sharding이 가능한 데이터 플랫폼이 필요하게 되었다. (mongoDB는 오토샤딩을 지원한다)
- 여기서 샤딩이란 대용량의 데이터를 처리하기 위해 데이터를 그룹단위로 분해하여 각각의 샤드가 자신의 그룹에 대한 저장 및 처리를 담당하게 하는 것을 말한다 - Secondary Index
- HBase는 물리적 분리라 불가능하고 MongoDB는 논리적 분리라 가능하다는데 잘 모르겠다. - Transaction ….못알아들었다.
- JSON 지원
웹서버와 디비서버간에 JSON형식으로 데이터를 주고받을 수 있다.
이 특징 때문에 mongoDB가 NoSQL 데이터베이스라고 불리는 듯 하다. - IDC DR
- 디비에 중요한 데이터에 들어갈수록 한 곳에만 저장되어있으면 위험성이 커진다. 따라서 DR ( disaster recovery ) 재난 복구 시스템이 필요함!
- mongoDB는 auto failover(자동 장애조치)가 가능하다.
mongoDB가 이러한 네이버의 니즈에 맞아아 사용을 결심했다고 한다.
Episode about using mongoDB in NAVER
뭔 이야긴지 하나도 모르겠다…
Future of mongoDB
- NoSQL과 RDBMS의 특징을 고루 가지고 있는 데이터 베이스이다.
- 성능문제 등 문제점이 많다.
- 사용처는 확대될 것 같으나 RDBMS에 비해 ACID(하나의 데이터베이스 트랜잭션이 안전하게 수행된다는 것을 보장하는 성질)와 안정성이 떨어짐으로 인해 메인이 될 것 같지는 않음.
5. 웹 성능 최적화에 필요한 브라우저의 모든 것
(발표자료: https://www.slideshare.net/deview/125-119068291)
summary of how browsers work
- HTML 문서를 파싱하여 DOM트리를 만든다.
- DOM트리는 html문서의 구조화된 표현이다.
- 우리는 JS를 통해 DOM구조에 접근하여 구조, 스타일, 내용 등을 변경한다. - Recalculate Style
- CSS문서를 파싱한 결과(CSSOM)를 렌더 트리에 적용한다.
- html은 단순 문서이다. 각 엘리먼트들의 렌더링의 관한 정보는 css가 가지고 있다. - JavaScript Engine
- 최신 브라우저들, 강의에서는 구글 크롬의 JS엔진인 V8을 예로 들었다.
- 소스코드를 파싱하여 JIT 컴파일러로 머신코드를 생성하고, 실행한다.
- JIT컴파일은 dynamic translation이라고도 하는데, 인터프리트 방식과 정적 컴파일 방식을 혼합한 방식이라고 생각할 수 있다. 런타임에서 인터프리터처럼 한줄한줄 읽어가며 머신코드를 생성하면서 그 코드를 캐싱하여 같은 함수가 여러 번 반복되어 불릴 때 캐싱된 머신코드를 사용하여 매번 머신코드를 생성하는 것을 방지한다. - Render Tree
- DOM트리 + CSSOM트리
- DOM트리와 1대1구조를 이루지 않는다.
예를들어 <a><b><b/></a>에서 a에 display: none속성이 정의되어 있으면 렌더트리에는 b가 없음 ( 실제 화면위에 렌더링할, 보이는 요소들을 중심으로 구성되어 있다. ) - Layout
- 생성된 렌더트리의 노드들에 대한 좌표를 계산하는 과정이다.
- Global Layout(윈도우 사이즈나 폰트 변경 시. 약간 글로벌한 느낌나는것들을 변경하는 것.)과 Incremental Layout(그 외 모든것)이 있다. - Paint
렌더트리를 기반으로 화면에 보여준다.
— New version of browser’s main flow
최신 브라우저에서는 두가지의 과정이 추가되었다.
- Update Layer Tree ( Layout 과정 직후 )
- 렌더링에 사용될 레이어들을 계산하여 생성한다.
- css에서 3d Transform, Animation / canvas나 video태그 / position이 relative, absolute인 것들 에 대해서 레이어가 생성된다고 한다. (적어놓은 것 이외에도 레이어 생성 조건이 많다. ) - Composite Layers ( Paint 과정 직후)
- 레이어 트리에 생성된 레이어들을 합성하여 한장의 bitmap으로 만든다.
- Paint는 각 레이어별로 그리고, Tiled Backing Store기법을 사용한다.
( 잘은 몰라도 레이어 하나씩 그려서 그 타일을 저장해놓는다는 것 같다. )
How the browser makes a frame?
위에서 말했듯 메인 스레드에서 하는 일이 너무 많아 VSync를 지키기 어렵다.
- Compositor thread를 통해 레이어 합성과정, 마우스 스크롤, 줌, 애니메이션 등을 메인 스레드에서 분산하여 처리한다.
- Raster thread에서 Graphics Command를 Bitmap으로 만듦 (픽셀로 구성된 우리의 화면에 출력하기 위해 도형으로 구성된 이미지를 가져와서 도트형식으로 만들어낸다는 말인것 같다.)
chrome://tracing에서 개발자도구보다 더 자세하게 위의 과정들을 볼 수 있다고 한다.
Rendering pipeline stage costs
- 렌더링 파이프라인에서
Layout은 width, height, font등을 사용할 때,
Painting은 color, background등을 사용할 때,
Composite은 opacity, transform등을 사용할 때 다시 수행되어야 한다. - 렌더링에는 순서가 있으므로 파이프라인 앞쪽인 Layout을 건드리게 되면 그 이후의 작업들이 모두 다시 수행되어야 하므로 비용이 크다.
- Layout과정은 약 1000개의 DOM 엘리먼트가 효율적이고, 애니메이션은 transform이나 web animation을 사용하여 파이프라인 뒤쪽의 Composite 단계에서 수행하도록 하자.
- Paint과정은 GPU Rasterization을 사용하면 대략 10배정도 빨라진다.
<meta name=“viewport” />만 추가해도 이 성능향상을 누릴 수 있다. - Composite과정은 Layer가 과다해지면 메모리를 많이 잡아먹고 성능이 떨어진다. 대략 30개 정도의 레이어를 유지하는 것이 가장 효율적이다.
최적화를 통해 VSync안에 모든 일들을 수행하도록 하여 60FPS를 보장하는 멋진 FE가 됩시다!