[Flutter 디코딩 하기 시리즈] 1. hot reload?!

ricky_0_k·2023년 3월 19일
0
post-thumbnail

서론

첫 단원이다. Youtube 가 임베드가 안 되어 살짝 불편하긴 하다.

소개

https://youtu.be/sgPQklGe2K8?list=PLjxrf2q8roU1fRV40Ec8200rX6OuQkmnl

hot reload 에 관련 내용을 정리하는 영상이었다.

hot reload

간단하게 이야기하면, 화면 수정 사항을 즉시 볼 수 있는 기능이다.
이해가 안된다면 바로 아래 gif 를 보자

기존 android, iOS 네이티브에서는 변경 내역을 확인하려면,
빌드 과정을 거치고, 직접 특정 화면을 들어가서 확인 할 수 있다.

하지만 hot reload 는 실행만 하면 위와 같이 앱 화면에서 직접 볼 수 있다. 그 것도 실행 즉시 말이다.
몇 분 이상 소요될 수 있는 확인 작업을, flutter 에서는 몇 초 내로 확인할 수 있다.

이게 왜 가능할까?

hot reload 시 실제 실행되는 내용

hot reload 는 코드 변경 사항을 구동중인 dart 가상 머신에 업데이트 하고
위젯 트리의 루트 위젯에서부터 위젯 트리를 다시 빌드 (build)한다.

오롯이 build() 만 재실행하기 때문에, main() 또는 initState() 을 다시 실행하지 않는다.
아래에 예를 몇가지 들어보았다. 아래의 경우엔 hot reload 하더라도 변화가 없다.

  1. main() 에 runApp 하는 루트 위젯을 변경
  2. build() 이외 함수 (ex. initState(), dispose()) 에 추가 작업
  3. 정적 변수 추가
  4. StatelessWidget -> StatefulWidget

위의 경우에는 재시작 개념인 hot restart 를 사용하면 된다.
hot restart 를 통해 state 까지 새로 설정하여 루트 위젯 빌드가 가능하다.
여기는 hot reload 관련 내용이니 깊게 설명은 하지 않고 넘어간다.

hot reload 가 안 되는 경우

dart 가상 머신에 들어가는 코드 또는 앱 자체에 문제가 있을 경우 hot reload 를 사용할 수 없다.
수정한 코드에 오류가 있다거나, 앱이 종료된다거나, dart 이외의 영역(Kotlin, swift 등) 을 수정하면 hot reload 는 동작하지 않는다

기타 특정 케이스도 존재한다.

그 외에도 다양한 경우는 공식 문서에 설명되어 있다.

How it works

hot reload 가 호출되면 호스트 시스템은 마지막 컴파일 이후 편집된 코드를 확인한다.
이후 다음 라이브러리가 다시 컴파일되는 방식으로 실행된다.

소스 코드는 커널 파일로 컴파일되어 모바일 장치의 Dart VM 으로 보내진다.
이후로 실행되는 내용은 위의 hot reload 시 실제 실행되는 내용 과 같다.

다른 플랫폼에서는 왜 불가능할까?

이게 가능한 이유는 dart 의 컴파일 방식 덕분이다.

dart 에서는 경우에 따라 컴파일 방식을 다르게 할 수 있는데
디버그용 앱에서는 JIT(Just-In-Time) 방식, 릴리즈 앱에서는 AOT(Ahead-of-time) 방식으로 컴파일 할 수 있다.

  • JIT : 프로그램을 실행할 때 컴파일
  • AOT : 프로그램 실행 전 에 컴파일

비유할 수 있는 걸 생각해봤는데 음... 짜장면을 받는다고 할 때

  • JIT 는 면과 짜장 소스를 따로 받는 경우?
  • AOT 는 이미 소스에 비벼진 짜장면을 받는 경우?

로 비유할 수 있을 것 같다. (짜장면을 비비는 과정을 컴파일로 비유할 수 있을 것이다 🫠)

기왕에 비유법을 활용한 거 좀 더 깊게 들어가보자.
만약 짜장면이 나왔는데 내용물에 벌레가 나와서 다시 받는 상황을 가정해보려 한다.

일단 화가 나겠지만 참고... 우리는 당장 배고프기 때문에 짜장면을 다시 받아야 할 것이다.
각 방식은 어떻게 짜장면을 다시 받을 수 있을까?

AOT 는 이미 비벼진 짜장면에서 벌레가 나왔기 때문에 다시 짜장면을 받아야 할 것이다.
면부터 소스까지 새로 만들고 비벼서 받아야 할 것이다.

JIT 는 어떨까? 소스나 면 둘 중 하나에서 벌레가 나왔을 것이다.
그러면 면과 소스 중 벌레 나온 것을 바꾸고, 비벼 먹으면 될 것이다.
(물론 소스를 비비는 도중에 소스에서 나왔다 등 특이한 경우에는 AOT 처럼 해야할 수도 있다)

어쨌거나 JIT 는 전체 구성 변경 없이 일부만 바꾸어서 처리가 가능할 수도 있다.
여기서 일부build() 함수 내용들로 대치해서 생각해본다면
우리는 비로소 JIT 방식을 활용해 hot reload 가 왜 가능한지 알 수 있다.

참고로 위에서 살짝 언급한 hot restart 도 JIT 방식 덕분에 활용이 가능하다.

기타

다트에서 사용하는 컴파일 이름도 따로 있다
dart2native 이며 관련 내용은 따로 언급하지 않겠다.

그리고 안드로이드에서도 예전엔 JIT 방식을 지원했었다.
하지만 특정 버전 이후 (21 인지 기억이 가물..) AOT 방식으로 변경 및 획일화 되었다.

당시에 JIT 방식을 경험하면서 온갖 버그들을 많이 경험했던만큼
당시 안드에서 hot reload, restart 가 가능했어도 별 감흥은 없었을 것 같다.

마무리

글이 길어졌지만 결국 JIT 컴파일 방식 덕분에 우리는 hot reload 를 사용할 수 있다.
이 덕분에 우리는 Flutter 에서 UI 개발을 하는데 걸리는 시간을 줄일 수 있다.

참고

profile
valuable 을 추구하려 노력하는 개발자

0개의 댓글