Flutter에서 Dart를 사용하는 이유

KWANWOO·2023년 2월 12일
0
post-thumbnail

Flutter에서 Dart를 사용하는 이유

Flutter에서는 그 많고 많은 언어들 중에 왜 하필이면 Dart를 사용할까??

1. Flutter와 Dart

Flutter팀에서 초기 언어를 선택할 때 12개 이상의 언어를 평가했다. 그리고 가장 UI 구축 방식이 Dart와 일치하여 선택하게 되었다고 한다.

2. Dart가 많이 사용되지 않았던 이유

Dart는 2011년 Javascript를 대체하기 위해 발표되었지만 아래와 같은 이유들 때문에 많이 사용되지는 않았다.

Dart가 많이 사용되지 않았던 이유

  • Javascript를 대체하기 위해서라면 Typescript 등의 다른 언어를 사용할 수 있었다.
  • Dart만으로 이루어진 구현체가 마땅히 없었다.
  • 웹 브라우저에서 바로 Dart가 동작하는 것이 아니었다.
  • 언어적 특성이 세련되지 않았고 러닝 커브가 높았다.

3. Flutter가 Dart를 선택하게 된 Dart의 주요 기능

Flutter가 Dart를 선택하게 된 주요한 기능들은 아래와 같다.

Dart의 주요 기능

  • 두 가지 컴파일 지원 (JIT + AOT)
  • 핫 리로드 (빠른 개발 가능)
  • 초당 60 프레임의 훌륭한 애니메이션
  • 선제적 스케줄링, 타임 슬라이싱 및 공유 리소스
  • Lock 없이 객체 할당 가비지 수집 가능
  • 선언적인 방식의 레이아웃

Dart의 주요 기능들에 대해 하나하나 살펴보자!

두 가지 컴파일 방법 지원 (JIT + AOT)

Dart는 JIT와 AOT 컴파일러를 모두 사용한다.

  • JIT(Just In Time): 프로그램 실행 중에 컴파일이 가능
    • 빠른 개발 주기로 개발이 가능하다.
    • 실행 속도가 느려진다. (프로그램 실행이 시작될 때 코드를 실행하기 전에 분석 및 컴파일을 수행해야 하기 때문)

  • AOT(Ahead Of Time): 프로그램 작성 중(런타임 이전)에 컴파일을 실행
    • 개발 중에 AOT 컴파일을 수행하면 개발 주기가 느려진다.(프로그램을 변경 후 실행하여 결과를 봐야하기 때문)
    • 런타임 분석 및 컴파일을 위해 일시 중지하지 않고, 보다 예측 가능하게 실행할 수 있는 프로그램을 만든다.
    • 실행 속도가 더 빠르다.

Dart는 위의 두 가지 컴파일러를 모두 사용하는데 적합한 언어 중 하나이다.

개발 중에는 JIT 컴파일러르 사용하여 빠른 개발을 수행하고, 출시할 때는 AOT로 컴파일을 한다.

결과적으로 Dart는 매우 빠른 개발 주기와 빠른 실행 및 시작 시간이라는 두 가지 이점을 모두 제공한다.

핫 리로드

Flutter의 가장 유용한 기능 중 하나는 핫 리로드이다.

Flutter는 개발 중에 JIT 컴파일러를 사용해 일반적으로 1초 안에 코드를 다시 로드하고 계속 실행할 수 있다.

앱 상태는 가능할 때마다 리로드를 통해 유지되므로 앱이 중단된 시점부터 계속할 수 있다.

핫 리로드는 앱 개발의 생산성을 2배 이상 향상 시켜줄 것이라고 이야기 되곤 합니다.ㅎㅎ

초당 60 프레임의 훌륭한 애니메이션

Flutter는 훌륭한 애니메이션을 쉽게 만들 수 있는데 Jank를 유발하는 일반적인 것들을 피할 수 있다.

Jank
일반적인 모바일 앱은 GUI를 가지며 항상 사용자와 상호작용할 수 있어야 한다.

만약 어떤 테스트 처리에 16밀리 세컨드 이상 소요되어 GUI의 동작에 딜레이가 발생하거나 멈추는 현상이 발생하면 이러한 현상을 Jank라고 한다.

Jank가 발생하면 사용자가 불편을 느낄 수 있다.

60 fps로 실행되는 Flutter의 UI는 아주 매끄럽게 보인다. ReactNative처럼 브릿지를 사용하지 않고 직접 프레임워크 단에서 UI를 그리기 때문에 다른 크로스 플랫폼보다 빠르다.

선제적 스케줄링, 타임 슬라이싱 및 공유 리소스

Java, Kotlin, Object-C, Swift 등 여러 개의 동시 실행 스레드를 지원하는 대부분의 프로그래밍 언어는 선점 기법을 사용하여 스레드 간 전환을 수행한다.

선점 기법
각 스레드는 실행시간이 슬라이스로 할당되고 할당된 시간을 초과하면 다른 스레드로 넘어간다.

하지만 메모리와 같은 스레드 간에 공유되는 리소스를 업데이트할 때 선점이 발생하면 경쟁 조건이 발생한다.

경쟁 조건은 앱 충돌 및 데이터 손실을 포함한 심각한 버그를 유발할 수 있다.

경쟁 조건을 해결하는 방법은 다른 스레드가 실행되지 않도록 Lock를 걸어 공유 리소스를 보호하는 것이다. 하지만 Lock은 더 심각한 교착상태를 유발할 수도 있다.

Dart는 여기서 다른 방식으로 접근한다. isolates라고 하는 다트의 스레드는 메모리를 공유하지 않으므로 Lock이 필요하지 않다.

isolates는 채널을 통해 메세지를 전달해 통신한다.

즉, Dart는 기본적으로 단일 스레드에서 작동하므로 선점을 허용하지 않는다. 대신 스레드는 명시적으로 산출하는데 async/awaitFutures or Stream을 사용한다. (이 내용은 나중에 학습하고 정리하겠습니다!!)

이를 통해서 개발자는 실행을 보다 효과적으로 제어할 수 있다. 단일 스레딩을 통해서 개발자는 중요한 기능을 선점 없이 완료될 때까지 실행할 수 있다.

Lock 없이 객체 할당 가비지 수집 가능

성능에 영향을 끼치는 중요한 원인 중 하나는 가비지 컬렉션이다.

가비지 컬렉션
프로그래밍을 개발 하다 보면 유효하지 않은 메모리인 가비지(Garbage)가 발생한다.)

C언어를 사용하면 free()라는 함수를 통해 직접 메모리를 해제해 주어야 하지만 Java 등의 언어는 개발자가 직접 메모리를 해제해 주지 않아도 된다.

그 이유는 JVM의 가비지 컬렉터가 불필요한 메모리를 알아서 정리해 주기 때문이다.

가비지 콜렉션은 공유 리소스에 액세스하는 특별한 경우이며, 많은 언어에서 수행기간 동안 Lock을 사용해야 한다.

Lock되어 사용 가능한 메모리가 수집되는 동안 전체 앱 실행이 중지될 수도 있다.

하지만 Dart는 가비지 컬렉션을 Lock없이 수행할 수 있다.

Dart는 generational garbage collection and allocation scheme를 사용하는데 이 기법은 수명이 짧은 많은 객체들을 할당하는데 빠르다.

이러한 Dart의 가비지 컬렉션에 대한 자세한 내용은 아래의 링크를 참고
Flutter: Don’t Fear the Garbage Collector

선언적인 방식의 레이아웃

Flutter는 명령적인 방식이 아닌 선언적인 방식으로 UI를 작성한다.

Flutter는 JSX나 XML 같은 추가 템플릿이나 레이아웃과 언어 간에 레이아웃을 분할하지 않으며 별도의 시각적인 레이아웃 도구가 필요하지 않다.

아래는 선언형 프로그래밍과 명령형 프로그래밍의 차이이다.

선언형 vs 명령형

  • 선언형 프로그래밍(declarative programming)
    순서나 문제 해결 과정을 다루기보다 무엇을 나타내야 할지에 초점을 둔다.
  • 명령형 프로그래밍(imperative programming)
    언어 해석이 순차적이며 어떠한 방법으로 문제를 해결할지에 초점을 둔다.

이처럼 Flutter는 선언형 프로그래밍 방식을 사용하여 위젯을 변경해야 하는 상황이 생길 때 기존의 것을 변경하는 것이 아니라 지우고 새로 만든다.

선언형 프로그래밍의 장점은 아래와 같다.

선언형 프로그래밍의 장점

  • 가독성
  • 재사용성
  • 오류 복구: 특정 부분만 오류 체크를 할 수 있음
  • 참조 투명성: 다른 시스템에 영향을 주지 않음
  • 대체 가능성

이러한 이유로 Flutter는 Dart를 선택해 사용합니다. 😁😁

해당 포스팅에 후기는 따로 없습니다!!

📄 Reference

profile
관우로그

0개의 댓글

관련 채용 정보