조합 즉, ‘Composition’은 Compose가 UI를 그리는 과정 중 하나가 아닌, 객체지향 프로그래밍에서 객체들을 조합하여 복잡한 기능을 구현하는 Composition을 의미한다. 상속을 통한 재사용과는 달리, 객체를 조합하여 구조를 설계하는 방식으로 유연성과 재사용성을 높일 수 있다. (참고: Effective Kotlin Item 36: Prefer composition over inheritance 또한, 본문에서 언급하는 ‘컴포넌트’는 Jetpack Compose의 UI 컴포넌트를 가리키며, 이는 하나의 컴포저블(Composable) 함수 단위로 정의된다.
이유가 같은지에 따라 판단 - 만약 두 코드가 동일한 이유로 수정되어야 한다면 중복이지만, 수정되는 이유가 다르면 중복이 아님 - 컴포넌트 내 조건문 추가는 서로 다른 수정 이유를 갖는 컴포넌트들이 묶였다는 뜻 - 해당 로직은 재사용에 적합하지 않음 == 변경에 유연하게 대응할 수 있는 UI 구조 필요
() -> Unit = {}, actions: @Composable RowScope.() -> Unit = {}, ... Slot 패턴 활용 사례— Compose Material Design Components 만약 String이였다면? 다른 UI 요소(아이콘, 도형)를 추가하기 위해 요구 사항을 만족하는 컴포넌트를 새로 만들어야 한다
외부에서 이들을 조합 - 부모 컴포넌트가 상태를 관리, 자식 컴포넌트는 상태를 받아 UI 렌더링 - 자식 컴포넌트들은 상태 관리 로직에서 분리되어 UI 표현에만 집중 - React에서는 Context API를 통해 구현하는 것이 일반적이지만, Compose에서는 Lambda Receiver를 활용하여 구현할 수 있음
Toolbox(...) } } @Composable fun PublicProfile( user: User ) { UserProfile(user) { Location(...) Bio(...) } } Compound Component Pattern 새로운 요구 사항이 생겨도 자식 컴포넌트를 유연하게 조합 가능 자식 컴포넌트들은 부모 컴포넌트의 상태를 공유하면서도, 부모 컴포넌트에 직접 의존하지 않음
연결된 경우 복잡도가 증가함에 따라 Scope 관리가 어려움 - UI는 동일하지만 UI에서 참조하는 클래스가 변경되는 경우 (Scope 인터페이스 수정, 관련된 모든 자식 컴포넌트에 영향) - 부모의 상태가 변경되더라도 자식들은 그 변경을 감지할 수 없는 경우가 있을 수 있음 - 컴포넌트의 상태가 자주 변경될 가능성이 있는 경우 State Wrapping 고려 - 변경될 수 있는 상태를 들고 있는 Scope interface를 선언해야 하는 경우, 불안정한(Unstable) 상태로 인한 리컴포지션 트리거에 주의 @Stable interface UserProfileScope { val user: State<User> }
{ HeaderTitle() } items(users) { user -> PublicProfile(user = user) } item { Footer() } } } LazyListScope는 item, items, stickyHeader 등 리스트를 구성하는 데 필요한 함수들을 제공한다. LazyColumn을 사용하는 개발자는 세부적인 상태 관리 로직에 대해 알지 못해도, 각 항목의 UI 구성에만 집중할 수 있다.
아니라 상호 보완적인 관계 - Slot 패턴은 컴포넌트의 재사용성을 위한 기반을 마련, Compound Component 패턴은 이를 바탕으로 더욱 유연한 UI를 구축 가능 - Stateless 컴포넌트는 UI에 집중, Stateful은 상태 관리 로직 캡슐화 - Compound Component 패턴은 이러한 Stateful 컴포넌트를 효과적으로 관리하고 활용할 수 있는 구조를 제공한다.
하단 액션 바 예시 - 음소거, 비디오 토글, 통화 종료 등의 옵션 제공 - 누구는 카메라 버튼을 왼쪽에 위치하고 싶어하고, - 누구는 마이크 버튼을 중앙에 위치하고 싶어하고, - 누구는 마이크 버튼이 없어야 한다고 생각할 수 있다. - 이러한 다양한 SDK 고객의 요구를 충족하기 위해 Slot 형태의 UI를 구성했다.
상태와 개별 제어 동작을 UI 로직과 분리할 수 있다. - SDK 고객의 다양한 요구 사항을 충족하기 위해 유연한 설계가 가능하다. - 오픈소스 프로젝트를 통해 디자인 패턴과 소프트웨어 아키텍처를 비롯한 다양한 모범 사례를 무료로 보고 아이디어를 얻을 수 있다. (개발자 커뮤니티에 기여 👍)
a single, unambiguous, authoritative representation within a system. — The Pragmatic Programmer. “중복은 코드의 겉모습이 아닌, 코드 수정의 이유가 같은지에 따라 판단” 되돌아보기: 조건문이 정말 나쁜가?