-
플러터(Flutter)의 장점 (2) - 성능편앱개발이야기 2020. 2. 4. 02:08
지난 4개월 전에 "플러터의 장점"에 대해서 적은 글이 생각보다 많이 조회된 것을 보고 플러터의 인기가 올라가고 있음을 실감한다. 당시에 2달밖에 사용하지 않았기 때문에, 좀더 민감할 수 있는 성능이라던지 구조적인 부분에 대한 이야기는 되도록 적지 않으려고 노력했다. 모바일 앱 개발을 하기위해 크로스플랫폼 개발에 관심을 갖고 계신 분들이 좀더 나은 선택을 할 수 있도록 최대한 표면적인 부분에 대해 적었다. 아직 읽어보지 않으신 분은 아래 링크를 통해서 읽어보시기 바란다.
이 글을 적은지 어느덧 4개월이 지났고, 플러터를 사용한지는 대략 6개월이 되었다. 이번 글에서는 그동안 생각해왔던 플러터의 장점들중 하나인 성능에 대해서 조금 이야기 해보고자 한다.
플러터(Flutter) VS 리액트 네이티브(React Native) 성능
플러터의 성능에 대해서는 말이 많다. 결국은 네이티브가 아니고 다트라는 스크립트 언어로 구동되며 채널이라는 메시지 버스를 통해서 통신해야 하는등의 특성을 고려해 보면 리액트 네이티브보다 성능면에서 나은점이 있을지 의구심이 들게 마련이다. 본인도 이 성능에 대해서는 아직도 결론을 내리지 못하였다. 하지만 어느정도는 가닥이 잡혀가고 있다.
성능에 대해 이야기 하자면, 플러터와 리액트 네이티브의 가장 큰 차이점은 UI 렌더링이다. 리액트 네이티브보다 플러터가 더 유리하다고 생각되는 부분이고 앞으로도 끊임없이 개선 될 수 있다고 생각되는 것이, 플러터는 Skia 라는 자체 렌더링 엔진을 가지고 있다는 점이다. 아래 다이어그램을 보자.
리액트 네이티브의 UI layer는 매우 단순하다. 비즈니스 로직을 이루는 앱 전체가 자바스크립트로 구동되고, 각 UI 컴포넌트들이 화면에 그려지는 부분은 Javascript Bridge를 통해서 네이티브 로직들을 구동한다. 자바스크립트 단계에서 모든 UI Components들의 virtual DOM을 관리하고, 이중에서 화면에 그려야 하는 부분을 추출하는 과정을 거쳐 (reconciliation 이라고 한다) 자바스크립트 브릿지를 통해서 네이티브 렌더링 엔진에 명령을 내리는 것이다. 이러한 특징 덕분에 자유도가 어마아머하다는 장점이 있다. Android나 iOS외의 수많은 네이티브 레이어를 접목 시킬 수 있기 때문에 수많은 종류의 디바이스를 지원해야 하는 앱이라면 선택이 아닌 필수라 할 만큼 리액트 네이티브의 입지는 확고하다. 물론 현실적으로는 iOS, Android 그리고 웹만 지원해도 충분하기 때문에 이러한 특성이 장점이 되는 경우는 극히 드물다고 본다.
성능에 대해서 따져 보자면, React의 reconciliation 과정의 몇가지 비효율성 때문에 항상 완벽한 성능을 내는것이 쉽지 않다. 이부분은 React 17이 나오면서 많이 극복이 되긴 하겠지만 여전히 UI와 렌더링 엔진의 분리는 성능 면에서는 약간 불리하다는 생각이다. 이와는 별개로, 모든 코드가 Javascript로 구동되는 점 또한 앱의 성능 저하의 대표적인 원인이 될 수 있다.
플러터의 동작 구조 및 성능
리액트 네이티브와 플러터의 가장 큰 차이는 렌더링이다. 플러터는 내부적으로 Skia 라는 렌더링 엔진을 가지고 있다. 특정 UI Component를 렌더링 하기 위해서 플랫폼에게 요청할 필요 없이 즉시 렌더링을 할 수 있다는 의미이다. Skia 엔진의 렌더링 속도는 네이티브와 동일하다고 생각해도 무방하며, 각종 플러터에 포함되어있는 다양한 Widget들과 최적화 되어 있기 때문에 그 효율성은 React Native가 따라올 수 없이 좋다. React의 Reconciliation과 Layout Calculation 과정이 Javascript 엔진 내에서 이루어진다는것을 감안 했을 때, 플러터의 이 장점은 수많은 가능성을 열어준다. 리액트 네이티브로는 만드는것이 거의 불가능한 게임같은 앱도 플러터로는 만들 수 있다. 물론 게임을 만드는데 플러터를 사용할 이유는 없지만, 그만큼 효율성이 좋다는 것을 강조하기 위해서 이야기 한 것이다.
플러터가 리액트 네이티브에 비해 가지는 또다른 성능상의 장점(?)은 Dart이다. Dart는 일종의 스크립트 언어이지만, 네이티브 코드로 컴파일이 가능하다는 엄청난 장점을 가지고 있다. 물론 C++로 작성하여 컴파일한 네이티브 코드만큼 성능을 낼 수 있는것은 아니다. 하지만 자바스크립트의 런타임에 비하면 당연히 훨씬 빠르다. Dart는 AOT (Ahead-Of-Time) 와 JIT (Just-In-Time) 컴파일링을 모두 지원하기 때문에 개발 과정에서는 JIT, prod 빌드시에는 AOT로 두마리 토끼를 잡을 수 있다. Dart는 장점이 매우 많은 언어이며 앞으로 점점 수요가 많아질 것이라고 확신한다.
만일 이 두가지 장점으로 커버하기 부족한 무거운 코드를 구동해야 한다면, 당연히 백엔드 서비스를 만들기를 추천하지만, 그게 어려운 경우에는 Platform Channels 이라는 메시지버스를 이용하여 네이티브단에서 코드를 수행하고 그 결과를 UI 단으로 가져올 수도 있다. 플러터가 아직도 매우 초기인 것을 감안하면 앞으로가 매우 기대된다.
이론과 실제는?
필자는 개인적으로 리액트 네이티브와 플러터를 모두 다뤄보았다. 특히 리액트 네이티브는 렌더링 성능 문제로 상당히 많은 시간을 코어 파트를 파본 적이 있다. 그 결과 현재 리액트 16.x 에서는 분명히 성능상 한계를 극복하기 어렵다. 리액트 17에서 async rendering 이 확실하게 지원된다면 많은 변화가 있을 것으로 예상된다.
플러터는 확실히 빠르다. 본인이 제작한 타임스냅 카메라 의 경우 그래픽 리소스를 상당히 많이 사용하고, 다수의 이미지 프로세싱이 Dart 코드로 구현되어 있다. 그리고 첫 플러터 앱이라서 UI 구조가 상당히 주먹구구 식으로 되어 있고, 상태 관리도 상당히 비효율적이다. 그럼에도 불구하고 앱의 성능은 상당히 괜찮다. 개발에 사용하고 있는 단말은 5년전에 구입한 iPad air 와 iPhone 7 그리고 Note 8 이다. iPad air에서는 조금 버벅이고 iPhone7 에서는 정말 부드럽게 구동된다. Note8 에서도 아주 부드럽게 동작한다.
6개월의 경험이지만, 2년간 사용한 React Native보다 훨씬 마음에 든다. 크로스 플랫폼 개발을 염두에 두고 있다면 플러터를 사용해보라고 적극 추천하고 싶다.
단, Material UI 나 Cupertino UI 스타일 이외의 독자적인 UI를 가진 앱을 만들기 위해서는 꽤나 귀찮은 작업이 많이 필요할 것이다. 최악의 상황에서 모든 UI Components 를 직접 만든다고 가정하더라도, React Native에서 동일한 작업을 하는것 보다 몇배는 쉽고 성능문제에서 자유로울것으로 생각된다.
아래 글도 한번 읽어보길 추천한다.
재미있게 읽으셨다면 "공감" 버튼과 댓글로 응원해주세요. 로그인 없이도 됩니다. 😀
'앱개발이야기' 카테고리의 다른 글
[앱개발이야기] 애드몹(AdMob)에 app-ads.txt 설정하기 (3) 2020.04.12 [앱개발이야기] 인증샷 카메라 타임스냅 어플 현황 (0) 2020.04.11 [iOS 어플 현지화] 어플 이름과 권한 메시지 현지화 하기 (0) 2020.04.06 [자작 앱 홍보하기] #4, 구글 애드워즈 광고 효과와 주의점 (9) 2020.04.05 [앱소개] 타임스냅 - 예쁜 타임스탬프 인증샷 카메라 (0) 2020.01.10 [플러터 강좌] 새로운 프로젝트 생성 및 에뮬레이터로 앱 실행하기 (2) 2020.01.06 [플러터 강좌] 플러터(Flutter) 시작하기 - VS Code 필수 익스텐션 (0) 2020.01.06 [플러터 강좌] 플러터(Flutter) 시작하기 - 설치 하기 (3) 2020.01.06