티스토리 컴포즈 적용기

ricky_0_k·2021년 11월 23일
1
post-thumbnail

TMI
컨퍼런스에서 들었던 내용도 이제 Velog 에 정리하려 한다.

보통 강연을 들을 때 노션에다 정리하고 있다.
정리하면서 내 생각을 직접 언급하고 스크린샷을 남용하기 때문에
저작권 대외비 등을 고려하여 공유할 수 없는 빨간맛 문서가 될 때가 많다.

여기에 순화시켜 정리하면서 복습한다 생각하려한다 ~_~

바로 내용이 궁금하신 분은 티스토리 컴포즈 적용기 를 참고

적용 결정까지

개인적으로는 5월 beta 때부터 적용을 준비했다는 것이 놀라웠고 많은 생각이 들었다.

예전에 beta 나 0점대 버전 라이브러리를 1점대 안정화 버전으로 올리면서
사용 방법이라거나 함수명이 바뀌어서 안정화에 고초를 겪었던 기억이 있었다.

그런 경험이 있다보니 저 말씀의 의미가 무엇이고,
저걸 위해 어떤 부분을 고려해야했을지 약간은 예상되어 개인적으로 존경(?)스러웠다.

1. 브런치 Compose PR

스터디로 진행했으면 좋았겠지만 시간 부족으로 인해 연습용 PR 로 진행하였다고 한다. (with 라벨?)
그렇게 PR 은 올렸지만 리뷰는 불가능한 내역들도 있었고, 코드를 직접 설명 및 설명 첨부한적이 많았다고 한다

2. 라이트닝 토크

점진적 변경 방법에 대해서도 논의하였다고 한다.

3. 몹 프로그래밍

팀원들이 돌아가면서 Compose 작성

사실 모두가 익히기 위해서는 이게 최상의 솔루션일듯하다.

결론 : 합법적 적용(?)까지 나아갈 수 있었음

Compose 의 특징 간단히 맛보기

  1. Compose 뷰는 반환값이 없음 (이로 인해 일부 아키텍처(ex. MVP) 는 불가능)
  2. RxJava, 코루틴 모두 사용 가능 (하지만 코루틴 권장)
  3. Coil 이미지 라이브러리만 compose 를 공식 지원함 (Glide ㅠㅠ)
  4. min SDK 21, kotlin 1.5.10

티스토리에서는

TMI : 이미 티스토리에서는 Hilt 를 쓰고 있다고 합니다.

Tistory, Presentation, Domain, Data 모듈이 존재
Presentation 에서 (XML + DataBindingCompose) 작업 수행


Compose UI

  1. 선언형 (데이터의 변화에 맞춰 화면을 재구성함)

    아마 Flutter 을 경험했던 사람들은 반가울수도 있다.
    사실 선언형이라는 주제로 포스트 하나를 만들수도 있다.
    간단하게 차이만 차이점만 확인한다면 이렇게 표현할 수 있다. (해당 링크의 이미지 참조)

  2. 커스텀뷰 작성도 함수 형태로 작성 가능 (UI 의 확장은 함수들의 합성으로 수행됨)

    상기 언급한 선언형 과 연결되는 내용이기도 하다.
    직접 뷰의 정보들을 하나씩 선언해주는 특징이 있다보니
    뷰 하나를 만들고 그 값을 리턴하는 형태로도 함수를 만들 수 있다.
    (반복을 줄이기 위해 제법 많이쓴다.)


    위 내용은 Flutter 로 탭뷰와 각 탭에 있는 레이아웃을 명세한 코드이다.
    (2번째, 4번째에 Page 글자가 없어 불편할 수 있다.)
    각 페이지로 타고 들어가면 각 Page 에 대한 구현 및 반환하도록 되어 있으며
    Compose 에서는 완전 똑같진 않겠지만 이와 비슷하게 작성할 것이라 예상된다.
    (필자는 아직 Compose 를 안해보았다 ㅠ)

  3. 핫 리로드 일부 가능 (Flutter 정도까진 아님)
    필자는 Android 개발을 하다가 Flutter 를 하면서 편안함을 느낄때가 있다.
    대표적인 것이 실시간으로 UI 변경을 확인(hot reload) 할 때,
    경우에 따라 빌드 속도도 빠를 때(hot restart) 이다.

    Compose 에서도 이게 가능하다고 하니 눈이 좀 띠용했었다. ( ㅇ ㅅ ㅇ )
    하지만 Flutter 정도까진 아니라고 하니 50%정도 시무룩해졌다. ( / _ \ )

    Preview Annotation 을 통해 UI 보면서 직접 작업하며 핫 리로드를 느껴볼 수 있다고 하니
    개인적으로는 매우 기대가 되었다.

적용 방식 시나리오


오오 티스토리의 커스텀뷰 작성 방식이다 Android 에서 흔히 볼 수 있는 커스텀뷰 예제이다.
이걸 어떻게 하면 Compose 화 시킬 수 있을까?

아래를 포함한 몇 가지 과정을 거치면 아래의 Compose 형태의 뷰를 만들 수 있게 된다.
1. TextView → Text, ImageView → Image
2. 선언형으로 작성 가능
3. margin 개념은 spacer 또는 padding 으로 처리
....

Modifier

  1. 글자 크기 등의 속성을 정함
  2. chaining 함수여서 입력받은 순서대로 속성이 적용되므로 주의 필요
    (코드의 예 : 패딩 적용 -> 색상 적용색상 적용 -> 패딩 적용 은 동작이 다르다)
    (실생활 예 : 참깨빵 위에 패티 2장패티 두장 위에 참깨빵 은 아예 다르다. 싸움 날 수도 있다.)

Compose 필수요소

재구성

데이터의 변경에 따라 UI 를 다시 그리는 것을 지칭
state 와 remember 에 기반함

State
데이터의 변경을 알리는 역할 (as like LiveData)

Remember
화면이 유지되는 동안 데이터를 저장하고 다시 복원하는 역할
전환된 값은 Composable 이 살아있는 동안은 그대로 유지됨

예시

분석
1. state 와 remember 은 변수와 연결되어 사용되는 듯
2. View 가 재구성되어도 값이 유지되어야 할 때 remember 을 사용하는 듯 (값 유지)
3. StateFul 이라고 함 (이건 Flutter 과 존똑)
4. Flutter 에서 GetX 의 Rx 변수와 비슷해보이기도 한다.

StateFul, Stateless

상태를 직접 관리 : StateFul
상태를 가지지 않음 : Stateless

막상 이렇게 보면 Flutter 과 별 차이 없어보이기도 한데,
함수를 보니 Stateless 는 Flutter 과 좀 다른 개념 같았다.

Flutter 의 경우 StatelessWidget 자체만으로는 클릭하더라도 숫자 갱신이 안되었던 것으로 기억하는 데 (아예 view 를 바꿔치기 해주어야 하거나 StateFulWidget 내에서 활용하여 setState() 를 사용해야하는 것으로 기억한다)
Compose 에서는 가능한듯보여 이는 한번 확인해봐야겠다.

State hoisting 이라는 용어는 처음 봐서 이런 용어도 있구나 생각했다.

Compose 특징과 장점

  1. Kotlin 을 base 로 작성하며 함수로 구성되어 있음

    사실 이거 하나만으로 엄청난 장점일거라 생각한다.
    이제 언어부터 다른 xml 과 잔 선언이 많은 커스텀뷰의 늪에서
    탈출할 수 있다는 것만으로도 큰 메리트라 생각한다.

  1. View 에 대한 리턴값이 존재하지 않으므로 외부에서 의도치않은 접근을 막음
    (자연스럽게 사이드 이펙트가 최소화됨)

    막연하게 아키텍처 관점에선 괜찮겠다고 생각이 든다.

  2. 간단하게 공통 컨테이너 작성 가능 (재사용성 뿜뿜)

  3. UI 뿐만 아니라 다양한 이벤트 처리 로직도 재사용이 가능

  4. 높은 호환성을 가지고 있음

    사실 이게 개인적으론 제일 궁금했었는데 높은 호환성을 가진다니 다행이라 생각했다.
    이거 덕분에 반쪽자리 기능은 절대 안 될거라 생각했다.

    하지만 직접 사용해봐야 알 것 같은 내용도 있어
    과거의 네이티브 프로젝트에서 직접 적용해보면서
    무슨 차이가 있는지 확인해봐야겠다는 생각이 들었다.

    1. ComposeView

      xml 에 ComposeView 를 선언해두고, 앱(Kotlin) 내에서 Compose 클래스 변수 선언하기
      (xml 에 ComposeView 선언하고 선언해둔 뷰 가져오기로 이해했다.)

    2. AbstractComposeView

      xml 기반 커스텀 뷰 내에 Compose 사용하고 싶을 시 AbstractComposeView 상속받기
      (커스텀 뷰 내에서도 활용이 가능한듯했다.)

    3. 기존 xml 컴포넌트 호출

      Compose 클래스 내에서 AndroidView 사용하기

      • factory : View 를 생성하는 함수
      • update : 재구성 시에 동작
        (Compose 내에서도 기존의 UI 를 쓸 수 있겠다고 생각했다.)
    4. 기타
      직관적, 코드 감소, 빠른 개발, 더 강력한 API
      (머터리얼 디자인, 다크모드, 애니메이션, 이벤트, 접근성 등)

문제점들

하긴 좋은점만 있진 않겠지 생각했다.

결론부터 이야기하면 직접 구현하거나 코드를 뜯어 가져오는 사례로 해결한 게 많았다.
이 부분을 보면서 뷰에 대해 높은 지식이 필요하겠다는 생각이 들었다.

1. 있었지만 없는 기능

  1. includeFontPadding 존재하지 않음
    벌써부터 많이 쓰는 기능이 없다고 한다 ㅠ

    해결책

    1. AndroidView.factory 에서 기존 TextView 를 사용
    2. 직접 구현해서 해결 (Modifier 확장함수)
      1. Move
        1. onGlobalPositioned 를 통해 아이템의 현재 위치를 얻고 저장
        2. index 변경 시 저장해둔 위치값을 기반으로 이동하는 애니메이션 진행
          (LaunchedEffect)
        3. offset 통해서 값만큼 이동
      2. Add & Remove
        1. 아이템 생성 시 추가되는 애니메이션 실행 (Modifier)
        2. 아이템 제거 시 사라지는 애니메이션 실행 (Modifier)
      순서를 적으면서 약간은 이해했었는데 이걸 제일 먼저 해봐야겠다는 생각을 했다.
  2. RecyclerView → LazyList (LazyColumn) 에서 animation 기능 부재
    정리하면 애니메이션이 1도 없다고 한다.
    즉각적으로 화면을 재구성함 (아직 지원하지 않음)

    해결책

    1. 직접 구현해서 해결
      1. Move
        1. onGlobalPositioned 를 통해 아이템의 현재 위치를 얻고 저장
        2. index 변경 시 저장해둔 위치값을 기반으로 이동하는 애니메이션 진행
          (LaunchedEffect)
        3. offset 통해서 값만큼 이동
      2. Add & Remove
        1. 아이템 생성 시 추가되는 애니메이션 실행 (Modifier)
        2. 아이템 제거 시 사라지는 애니메이션 실행 (Modifier)

    순서를 적으면서 약간은 이해했었는데 이걸 제일 먼저 해봐야겠다는 생각을 했다. x 2

  3. ViewPager,2. ViewPager, SwipeRefreshLayout, WebView 등 주요 컴포넌트가 없음
    여기를 참고해봐도 좋을 것 같고, 버전 업데이트를 하면서 해결될 문제라고 한다. (하긴 다 구현하긴 어렵지)
    그리고 앞서 말한 호환성 파트에서 3번 케이스를 활용하면 될 것 같다는 생각을 했다.

2. 완벽한 머터리얼 가이드

구글에서 너무 스타일 상에 제약을 걸어두어서 문제도 있는듯하다.

  1. dp 사용 불가능한 fontSize
    개인적으로 반응형때문에 dp 를 많이 사용하고 편이다. 그런데 아예 막혀있다고 한다.
    (아니 그러면 반응형에 글자 개판되는 거 어케 대응해야 함?)

    해결책
    CompositionLocalProvider 를 통해 우회

    fontScale = 1f 를 통해 sp 를 dp 처럼 사용하도록 할 수 있다고 한다.
    깊게 보면 Kotlin 상에서 접할수도 있는 내용인듯하여 뷰에 대한 깊이가 필요하겠다는 생각이 들었다.

  2. Track, Thumb 크기가 조정되어 있는 Switch, 넓이 변경이 불가능한 NavigationDrawer

    Switch 를 예로 들어 설명해주셨는데, requiredSize 로 크기를 지정하면 외부의 설정 일절 안먹히고, 상속또한 불가능하다고 한다. 그런데 Switch 내에서는 그렇게 구현되어 있어 일절 커스텀이 불가능하다고 한다.

    해결책
    모든 코드 복사하여 수정하는 게 나음

어찌보면 스타일이 깨지는 것이기에 저렇게 제약하는 게 맞는거긴하겠지만 글쎄....
규약은 만들되 제약이 옵션이 아닌 필수인 것에 대해서는 개인적으로는 회의적이긴 하다

적용 후

코드라인 수 : 공통으로 사용할 view 들이 기존 코드, compose 코드 두 개로 구현되어 있어 증가
앱 번들 : compat 라이브러리들을 제거하지 않고 compose 를 추가하여 증가함
개발 속도 : Compose 의 장점(+) + 앞서 말한 문제점(-) ~= 0

이렇게 보면 소소해보인다고 할 수 있겠지만,
UI 까지 Kotlin 으로 작성하여 Kotlin 으로 모든 것을 한다는 것만으로도 의미는 크다고 생각한다.
그 외의 직관적임 등은 표현하지 않아도 알 수 있을 것이다.
(짧은 함수 몇줄을 순서대로 잇는 것 만으로 어떤 기능이 있는지 직관적으로 확인할 수 있음)

적용해도 될까요?

명확한 장점들이 많음
업무가 많거나, 부족한 리소스로 인한 문제가 더 클거라 봄


개인 결론

anko 나 다른 기능들과 다르게 이 기능은 무조건 활성화 될 거라 본다.

개발적으로도 배울 수 있는 부분이 많을 것 같다.
Compose 를 통해 View를 만들고 때로는 없는 기능을 만들면서 미처 놓쳤던 View 파트를 깊게 다루고,
Flutter 에서 느꼈던 편안함(선언형, 핫 리로드 등)도 간접적으로 느낄 수 있을거라 생각이 든다.

실무에 적용시키기에는 버전 제약이 있어 어려울 것 같고, 단기적으로는 개인 프로젝트에 적용해볼 수 있을 것 같다.
과거에 런칭했던 앱에 Compose 를 적용시켜보면서 익히고, 여유에 따라 시리즈 포스트도 올려볼까한다.

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

0개의 댓글