윤준서의 블로그

선언형 UI에 대한 나의생각

태초의 개발

안드로이드를 개발하면서 XML을 이용하여 UI를 작성하는데 가장 귀찮은 점이 기본 Material을 벗어나서 Custom UI를 개발할 때다.

작은 UI 쪼가리를 개발하기 위해 많은 시간과 코드를 소비하는데, 정말 작은 기능인데도 불구하고 작게는 30분 길게는 하루를 UI에 시간을 소비했던 적이 있다. 특히 ToggleGroup과 Checkbox는 귀찮은 작업이다. 또 동일한 로직을 가지고 있는 화면에서 사용하기 위해 Fragment를 사용하는데 파일이 또 늘어나고, 처리해야 하는 코드도 동시에 늘어난다. 눈앞이 캄캄해진다.

디자이너랑 일할 때는 더 답답했다. "이 부분만 조금만 더 왼쪽으로" 한마디에 XML 파일 열고, 속성 찾고, 값 바꾸고를 몇 번씩 반복했다.

선언형 UI의 등장

그러다가 선언형 UI라는 개념을 접하게 되었다. 처음에는 그저 트렌드로만 생각했는데, 실제로 사용해보니 개발 방식이 완전히 달라졌다. 명령형(Imperative) UI에서는 "어떻게 그려야 하는가"에 집중했다면, 선언형 UI에서는 "무엇을 그려야 하는가"에 집중하게 된다.

집 짓는 걸로 비유하면, 명령형은 "벽돌 쌓고, 시멘트 바르고..."를 하나하나 시키는 거고, 선언형은 "방 3개, 화장실 2개짜리 2층집"이라고 말하는 거다. 나오는 집은 같아도 일하는 방식이 완전히 다르다.

Jetpack Compose 사용

Flutter를 쓰기 전에는 안드로이드의 Jetpack Compose를 먼저 사용해 보았다. 상태와 함께 무엇을 렌더링할 것인가만 생각하면 작업하기 쉬웠기 때문에 금방 적응을 했다. 하지만, 느리다. 안 그래도 느린 맥북과 안드로이드 스튜디오가 내 혈압을 상승시키는데 Compose의 장점이라고 할 수 있는 Preview가 코드를 한번 작성(수정)할 때마다 끊기기 시작하니 참을 수 없는 분노가 찾아왔다.

그래도 한 번 작성해둔 UI를 다른 곳에서 쉽게 사용하고, 눈에 보이는 UI 코드를 작성할 수 있어서 좋았다. 특히 재사용 가능한 컴포넌트를 만드는 것이 훨씬 쉬워졌다. 기존에는 XML로 작성한 레이아웃을 재사용하려면 복잡한 과정이 필요했지만, Compose에서는 단순히 함수를 호출하는 것만으로도 가능했다.

몇 번 사용해 보니 좋았는데 다시 옛날 프로젝트를 봐야하는 상황이 찾아왔었다. 이럴 수가 Compose를 그리워할 줄은 몰랐다.

임시방편으로 아래처럼 코드를 작성하기 시작했다.

addLinearLayoutVertical {
    addCheckBox("동의합니까?") {
        setOnCheckedChangeListener { button, isChecked ->
            // 체크 처리
        }
    }
}

그렇다. 모든 UI들을 코드를 이용하여 작성하기 시작했다. Kotlin으로 작성했기 때문에 Compose처럼은 아니지만 머릿속에서 그리면서 작성할 수 있었다. 직관적이고 빨랐다. 스스로 생산성이 올랐다고 칭찬했다. 하지만 미리볼 수 없었기 때문에 확인을 위해서 실제 스마트폰을 이용하여 확인할 수밖에 없었다.

하나의 프로젝트를 이런 식으로 코드만 작성해서 처리해 버린 적도 있다. 해보니까 꼭 Compose 같은 프레임워크가 있어야 선언형으로 쓸 수 있는 건 아니었다. XML이든 코드든 "무엇을 그릴지"가 바로 보이게만 쓰면 된다.

Flutter

사이드 프로젝트를 시작했다. 이왕 시작하는 거 그냥 iOS까지 배포하고 싶었다. 그런데 iOS를 안 한 지 조금 오래되어서 다시 시작하려니 약속하지 못할 것 같아서 크로스 플랫폼인 Flutter를 선택했다.

Compose와 크게 다르지 않아서 어떤 식으로 작성하는지 어떻게 동작하는지만 파악하고, 바로 작업에 들어갔다. 뭐든 해보면 된다.

가장 큰 장점은 빠르다. 기존에 작업하는 방식과는 비교할 수 없을 만큼 빠르고, UI를 구현함에 있어서 개발자가 신경 써야 할 게 많이 줄어들었다. 상태관리만 잘 해주면 의도대로 작동하는 것이다. UI의 일부를 변경하고, 제거하고, 추가하는데 많은 비용이 들지 않는다.

개인적으로 Jetpack Compose와 Flutter를 많이 써보진 않았지만 Flutter가 훨씬 낫다. 답답함도 별로 없고, HotReload 기능을 가지고 있기 때문에 바로 확인할 수 있다. 네이티브 기능을 위해서 MethodChannel을 이용해야 하는 것은 사소하게만 느껴질 뿐이다.

마무리

Compose도 Flutter도 아직 많이 써본 건 아니다. 그래도 작은 UI 쪼가리 하나에 하루를 쓰던 XML 시절로는 돌아가고 싶지 않다.

#essay