Upgrade to Pro — share decks privately, control downloads, hide ads and more …

카카오페이 앱 리빌딩 스토리

kakao
PRO
December 08, 2022

카카오페이 앱 리빌딩 스토리

#Android

카카오페이앱을 리빌딩하면서 겪은 과정들을 소개해 드리려고 합니다.

발표자 : skyler.shin
카카오페이 안드로이드 주식 서비스 업무를 맡고 있는 스카일러입니다.

eddy.kang
카카오페이 안드로이드 계정 서비스 업무를 맡고 있는 에디입니다.

kakao
PRO

December 08, 2022
Tweet

More Decks by kakao

Other Decks in Programming

Transcript

  1. 신문규 Skyler.Shin, 강진호 Eddy.Kang, 이호용 Yong.E
    카카오페이
    Copyright 2022. Kakao Corp. All rights reserved. Redistribution or public display is not permitted without written permission from Kakao.
    if(kakao)2022
    : DI, 모듈화, UI를 중심으로
    카카오페이 앱 리빌딩 스토리

    View Slide

  2. 앱 리빌딩 배경
    DI 개선 및 모듈화
    UI 완성도 올리기
    정리하기

    View Slide

  3. 앱 리빌딩 배경
    DI 개선 및 모듈화
    UI 완성도 올리기
    정리하기

    View Slide

  4. 앱 리빌딩 배경

    View Slide

  5. 0
    30
    60
    2019 2020.6 2021.6 2022.09
    서비스 증가
    서비스

    View Slide

  6. 개발팀 규모 증가
    0
    30
    60
    2019 2020.6 2021.6 2022.09
    인원
    서비스

    View Slide

  7. 빠르게 성장 중인
    안드로이드 개발팀 재정비

    View Slide

  8. 코드 품질

    View Slide

  9. 사용성
    코드 품질

    View Slide

  10. View Slide

  11. UI
    Architecture
    Network
    DI
    Module

    View Slide

  12. UI
    Architecture
    Network
    DI
    Module

    View Slide

  13. 앱 리빌딩 배경
    DI 개선 및 모듈화
    UI 완성도 올리기
    정리하기

    View Slide

  14. DI(Dependency Injection) 역할
    모듈 결합도 낮추기

    View Slide

  15. 모듈 결합도 낮추기
    :a :b

    View Slide

  16. 모듈 결합도 낮추기
    class A Interface B

    View Slide

  17. :a :b_interface
    :b_impl
    모듈 결합도 낮추기

    View Slide

  18. :a :b_interface
    :b_impl
    모듈 결합도 낮추기

    View Slide

  19. 카카오페이 앱 DI 구현 상황
    - Koin 라이브러리 사용
    - 쉽게 사용이 가능한 factory, single 함수 사용 빈도가 잦음
    - 올바른 scope로 객체가 생성 되었는지 알 수 없음
    // 호출할 때마다 객체를 새로 생성
    factory { PayPaymentOfflineLocalDataSource() }
    // 앱 내에 하나의 객체만 생성
    single { PayPaymentOfflineLocalDataSource() }

    View Slide

  20. DI를 바꾼다면?
    Koin Dagger Hilt
    실행 Runtime Compile Compile
    사용 현황 카카오페이 앱 카카오톡 / 카카오페이 비즈니스 없음
    사용 난이도 (Scope) 중간 중간 매우 쉬움

    View Slide

  21. DI를 바꾼다면?
    Koin Dagger Hilt
    실행 Runtime Compile Compile
    사용 현황 카카오페이 앱 카카오톡 / 카카오페이 비즈니스 없음
    사용 난이도 (Scope) 중간 중간 매우 쉬움

    View Slide

  22. Hilt 장점
    SingletonComponent
    @Singleton
    ActivityRetainedComponent
    @ActivityRetainedScoped
    ActivityComponent
    @ActivityScoped
    FragmentComponent
    @FragmentScoped
    ViewWithFragmentComponent
    @ViewScoped
    ViewComponent
    @ViewScoped
    ServiceComponent
    @ViewScoped
    ViewModelComponent
    @ViewModelScoped

    View Slide

  23. Hilt 도입의 어려운 점
    - Custom scope인 경우 hilt의 미리 정의된 scope와 맞출지 판단 필요
    Fragment
    Fragment
    Fragment
    Custom Scope

    View Slide

  24. - Custom scope인 경우 hilt의 미리 정의된 scope와 맞출지 판단 필요
    - Navigation graph scope로 문제 해결
    // parent fragment scope
    val viewModel: PayOfflineViewModel by
    navGraphViewModels(R.id.payment_offline_graph)
    // child fragment
    val parentsViewModel: PayOfflineViewModel by
    viewModels({requireParentFragment()})
    Hilt 도입의 어려운 점

    View Slide

  25. Feature based module
    :app
    :money :payment :stock :home
    :design§system :core :util
    NonïFeature
    Feature
    :core :resource
    :util :widget

    View Slide

  26. Feature based module
    :app
    :money :payment :stock :home
    :design§system :core :util
    NonïFeature
    Feature
    :core :resource
    :util :widget

    View Slide

  27. Feature based module
    :app
    :money :payment :stock :home
    :design§system :core :util
    NonïFeature
    Feature

    View Slide

  28. Features
    :payment
    :money
    :stock
    :account
    :offline
    :membership
    :history
    :presentation
    :domain
    :data

    View Slide

  29. Features
    :payment
    :money
    :stock
    :account
    :offline
    :membership
    :history
    :presentation
    :domain
    :data

    View Slide

  30. Features
    :payment
    :money
    :stock
    :account
    :offline
    :membership
    :history
    :presentation
    :domain
    :data

    View Slide

  31. Presentation 모듈로 분리
    :payment¶offline¶presentation
    :app
    Activity
    Fragment
    ViewModel

    View Slide

  32. Domain 모듈로 분리
    :payment¶offline¶domain
    :core¶domain
    UseCase
    Repository
    Model

    View Slide

  33. Data 모듈로 분리
    :payment¶offline¶data
    :core¶data
    Repository
    DataSource

    View Slide

  34. 화면과 화면 사이 연결하기
    - Navigator를 활용해 feature간 activity 실행 정리
    - Dependency graph 최적화 과정 필요
    :feature¶payment¶presentation
    :domain
    :data
    :core :design§system
    :feature¶money¶presentation

    View Slide

  35. 화면과 화면 사이 연결하기
    - Navigator를 활용해 feature간 activity 실행 정리
    - Dependency graph 최적화 과정 필요
    :feature¶payment¶presentation
    :domain
    :data
    :core :design§system
    :feature¶money¶presentation

    View Slide

  36. 화면과 화면 사이 연결하기
    - Navigator를 활용해 feature간 activity 실행 정리
    - Dependency graph 최적화 과정 필요
    :feature¶payment¶presentation
    :domain
    :data
    :core :design§system
    :feature¶money¶presentation

    View Slide

  37. 화면과 화면 사이 연결하기
    - Navigator를 활용해 feature간 activity 실행 정리
    - Dependency graph 최적화 과정 필요
    :feature¶payment¶presentation
    :domain
    :data
    :core :design§system
    :feature¶money¶presentation

    View Slide

  38. 화면과 화면 사이 연결하기
    - Navigator를 활용해 feature간 activity 실행 정리
    - Dependency graph 최적화 과정 필요
    :feature¶payment¶presentation
    :domain
    :data
    :core :design§system
    :feature¶money¶presentation

    View Slide

  39. 화면과 화면 사이 연결하기
    - Navigator를 활용해 feature간 activity 실행 정리
    - Dependency graph 최적화 과정 필요
    :feature¶payment¶presentation
    :domain
    :data
    :core :design§system
    :feature¶money¶presentation

    View Slide

  40. 화면과 화면 사이 연결하기
    - Navigator를 활용해 feature간 activity 실행 정리
    - Dependency graph 최적화 과정 필요
    :feature¶payment¶presentation
    :domain
    :data
    :core :design§system
    :feature¶money¶presentation

    View Slide

  41. 화면과 화면 사이 연결하기
    :feature¶payment¶presentation
    :navigator :navigatorImpl
    :feature¶money¶presentation
    height = 1

    View Slide

  42. 화면과 화면 사이 연결하기
    :feature¶payment¶presentation
    :navigator :navigatorImpl
    :feature¶money¶presentation
    height = 1

    View Slide

  43. Navigator로 Feature 사이 연결
    - Activity 실행 기능
    - Fragment 실행 기능
    - Scheme 실행 기능
    // Activity 실행
    navigator.start(this@PayHomeFragment, Direction.NotificationFeed)
    // Scheme 실행
    openSchemeList.collect {
    navigator.start(activity = this, directionsList = it)
    }

    View Slide

  44. Feature 기반으로 정리 된 모듈
    :money
    :app
    :stock
    :core
    :utils
    :navigator
    :offline
    :membership
    Feature

    View Slide

  45. 모듈화 전 모듈화 후
    빌드 시간 10m 48s 9m 32s
    Module 5 37
    kotlin line 186628 102138
    모듈화 결과
    Full build 기준 결과

    View Slide

  46. 모듈화 전 모듈화 후
    빌드 시간 10m 48s 9m 32s
    Module 5 37
    kotlin line 186628 102138
    빌드 시간 변화
    Full build 기준 결과

    View Slide

  47. 모듈화 전 모듈화 후
    빌드 시간 10m 48s 9m 32s
    Module 5 37
    kotlin line 186628 102138
    모듈 수 변화
    Full build 기준 결과

    View Slide

  48. 모듈화 전 모듈화 후
    빌드 시간 10m 48s 9m 32s
    Module 5 37
    kotlin line 186628 102138
    코드량 변화
    Full build 기준 결과

    View Slide

  49. 모듈화 전 모듈화 후 현재
    빌드 시간 10m 48s 9m 32s 21m 45s
    Module 5 37 122
    kotlin line 186628 102138 331325 1.8배
    23배
    2배
    개편 전 그리고 현재
    Full build 기준 결과

    View Slide

  50. 더 세분화 된 모듈
    :money
    :app
    :stock
    :core
    :utils
    :navigator
    :offline
    :membership
    Feature
    :bankAccounts
    :send
    :receive
    :charge

    View Slide

  51. 더 세분화 된 모듈
    :money
    :app
    :stock
    :core
    :utils
    :navigator
    :offline
    :membership
    Feature
    :bankAccounts
    :send
    :receive
    :charge

    View Slide

  52. 모듈화로 얻은 것
    생산성

    View Slide

  53. 앱 리빌딩 배경
    DI 개선 및 모듈화
    UI 완성도 올리기
    정리하기

    View Slide

  54. 디자인 시스템
    UI 완성도 올리기

    View Slide

  55. Why?
    “디자인 시스템이 필요한가요?”

    View Slide

  56. 브랜드
    Identity 확립

    View Slide

  57. 브랜드 사용자 경험
    Identity 확립 일관된 UI 제공

    View Slide

  58. 카카오페이 디자인 시스템
    Foundation Component Module Template
    Color
    Theme
    Resource
    TypoGraphy
    .
    .
    .
    Badge
    Button
    Chip
    Checkbox
    RadioButton
    .
    .
    .
    AppBar
    Tab
    TextField
    Dialog
    BottomSheet BridgePage

    View Slide

  59. android:id="@+id/btn_success"
    style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
    android:layout_width="0dp"
    android:layout_height="52dp"
    android:background="@android:color/transparent"
    android:insetLeft="0dp"
    android:insetTop="0dp"
    android:insetRight="0dp"
    android:insetBottom="0dp"
    android:minWidth="0dp"
    android:minHeight="0dp"
    android:padding="0dp"
    android:text="@string/pay_ok"
    android:textAppearance="@style/PayApp.Text.Medium.Bold"
    android:textColor="@color/pay_grey800_daynight"
    app:backgroundTint="@color/pay_grey200_daynight"
    app:backgroundTintMode="src_atop"
    app:cornerRadius="0dp"
    app:rippleColor="@color/pay_grey300_daynight" />
    Case1. 디자인 시스템 도입 전 버튼 활용 예시
    필요에 따라 일부 Style 및
    attribute로 작성

    View Slide

  60. - Color
    - Size
    - Typography
    android:id="@+id/btn_success"
    style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
    android:layout_width="0dp"
    android:layout_height="52dp"
    android:background="@android:color/transparent"
    android:insetLeft="0dp"
    android:insetTop="0dp"
    android:insetRight="0dp"
    android:insetBottom="0dp"
    android:minWidth="0dp"
    android:minHeight="0dp"
    android:padding="0dp"
    android:text="@string/pay_ok"
    android:textAppearance="@style/PayApp.Text.Medium.Bold"
    android:textColor="@color/pay_grey800_daynight"
    app:backgroundTint="@color/pay_grey200_daynight"
    app:backgroundTintMode="src_atop"
    app:cornerRadius="0dp"
    app:rippleColor="@color/pay_grey300_daynight" />
    Case1. 디자인 시스템 도입 전 버튼 활용 예시
    필요에 따라 일부 Style 및
    attribute로 작성

    View Slide

  61. CustomView + Style으로 간단하게 구현 가능
    Case1. 디자인 시스템 도입 전 버튼 활용 예시
    android:id="@+id/btn_success"
    android:layout_width="match_parent"
    android:layout_height="52dp"
    android:text="@string/pay_ok"
    style="@style/Widget.Fit.FitButton.Primary" />

    View Slide

  62. Case 2. 확장성이 고려되지 않은 Custom View
    특정 상황에 맞추어 개발이 되어 있음
    기능 추가 또는 수정이 어려움
    확장성이 낮다보니 새로운 View 개발

    View Slide

  63. Case 2. 확장성이 고려되지 않은 Custom View
    PaySelectInputView PayInputView PayTextInputView
    결제 멤버십 계정
    머니

    View Slide

  64. Case 2. 확장성이 고려되지 않은 Custom View
    FitTextField
    PaySelectInputView PayInputView PayTextInputView
    결제 멤버십 계정
    머니

    View Slide

  65. 디자인 시스템 Components

    View Slide

  66. 디자인 시스템 도입 결과
    1. 파편화 된 UI 코드 정리
    2. 개발 편의성 증가

    View Slide

  67. System Bar 활용하기
    UI 완성도 올리기

    View Slide

  68. View Slide

  69. Status bar 색상이 다름
    Navigation Bar 색상이 다름

    View Slide

  70. 기존 방식의 한계점
    - Background 색상이 달라지면, System Bar 색상도 변경해주어야 함
    - 휴먼 에러 발생 확률이 높음
    /
    / StatusBar 색상 변경
    setStatusBarColor(R.color.Red)
    /
    / NavigationBar 색상 변경
    setNavigationBarColor(R.color.Red)

    View Slide

  71. System Bar 활용하기

    View Slide

  72. System Bar 활용하기
    Status Bar
    ViewGroup
    Navigation Bar

    View Slide

  73. System Bar 활용하기
    Status Bar
    ViewGroup
    Navigation Bar
    WindowCompat
    .setDecorFitsSystemWindows(window, false)

    View Slide

  74. ViewGroup 확장하기
    Status Bar
    ViewGroup
    Navigation Bar
    WindowCompat
    .setDecorFitsSystemWindows(window, false)

    View Slide

  75. ViewGroup 확장하기
    ViewGroup
    WindowCompat
    .setDecorFitsSystemWindows(window, false)

    View Slide

  76. ViewGroup 확장하기
    ViewGroup
    ViewCompat.setOnApplyWindowInsetsListener(view) {
    view, insets ->
    val systemInsets =
    insets.getInsets(WindowInsetsCompat.Type.systemBars())
    view.setPadding(
    top = view.paddingTop + systemInsets.Top,
    bottom = view.paddingBottom + systemInsets.bottom
    )
    }

    View Slide

  77. ViewGroup 확장하기
    ViewGroup
    ViewCompat.setOnApplyWindowInsetsListener(view) {
    view, insets ->
    val systemInsets =
    insets.getInsets(WindowInsetsCompat.Type.systemBars())
    view.setPadding(
    top = view.paddingTop + systemInsets.Top,
    bottom = view.paddingBottom + systemInsets.bottom
    )
    }

    View Slide

  78. ViewGroup 확장하기
    ViewGroup
    ViewCompat.setOnApplyWindowInsetsListener(view) {
    view, insets ->
    val systemInsets =
    insets.getInsets(WindowInsetsCompat.Type.systemBars())
    view.setPadding(
    top = view.paddingTop + systemInsets.Top,
    bottom = view.paddingBottom + systemInsets.bottom
    )
    }

    View Slide

  79. ViewGroup 확장하기
    ViewCompat.setOnApplyWindowInsetsListener(view) {
    view, insets ->
    val systemInsets =
    insets.getInsets(WindowInsetsCompat.Type.systemBars())
    view.setPadding(
    top = view.paddingTop + systemInsets.Top,
    bottom = view.paddingBottom + systemInsets.bottom
    )
    }

    View Slide

  80. System Bar 활용 화면

    View Slide

  81. System Bar 활용 결과
    1. 유연한 화면구조 설계
    2. 휴먼 에러 감소

    View Slide

  82. 앱 리빌딩 배경
    DI 개선 및 모듈화
    UI 완성도 올리기
    정리하기

    View Slide

  83. DI
    Hilt
    정리하기

    View Slide

  84. Module
    DI
    Hilt Feature based
    정리하기

    View Slide

  85. Module
    DI
    Hilt Feature based
    UI
    Quality
    정리하기

    View Slide

  86. View Slide

  87. Action Items
    1. 모듈 세분화
    2. 빌드 시간 개선
    3. Compose 기반 디자인 시스템 개발

    View Slide

  88. E.O.D

    View Slide