스토리플레이 안드로이드 분해해보기

설채은

업데이트:

StoryPlay Android

StoryPlay : 선택형 스토리

스토리플레이는 선택형 스토리 게임입니다. 유저는 앱에서 스토리를 플레이하며 자신이 택한 선택지들에 의한 결말을 얻게 되죠. 이러한 스토리들을 제작할 때는 스튜디오, 제작된 작품을 등록할 때는 어드민을 사용합니다.

image

에디터들은 스튜디오를 통해서 작품을 창작하고, 창작된 작품을 어드민에서 등록합니다. 그러면 서버에 작품이 등록되어서 사용자들은 앱에서 작품을 감상할 수 있죠.

저는 이중에서도 제가 개발중인 안드로이드 앱에 대해서 설명할 예정입니다!

  • StoryPlay 에 사용된 기술 스택들
    • Kotlin : 당연하게도 스토리플레이의 모든 코드는 Kotlin으로 이루어져 있습니다.
    • Firebase
      • 분석을 위해선 Analytics, 모니터링을 위해서 Crashlytics, 푸시를 위해 사용하는 Messaging, A/B Test 등 Firebase의 다양한 기능이 스플에서 사용됩니다.
      • 스토리플레이에서는 개발 환경을 위한 Firebase와 운영 환경을 위한 Firebase가 구분되어 있습니다.
    • Git-Flow
      • 스토리플레이는 조금 변형된 git-flow 전략을 사용하고 있습니다.
      • 스플은 스프린트가 앱의 업데이트 버전 단위로 이루어지고 있는데, 그래서 스프린트의 버전과 앱의 버전이 같습니다!
      • 스플에서는 기능별로 feature 브랜치를 따지 않고, 스프린트가 시작될 때 해당되는 스프린트 버전의 feature 브랜치를 따서 시작합니다. 예를 들자면… 스플은 얼마전에 1.12 스프린트를 마쳤는데요, 1.12 스프린트는 앱의 1.12 버전의 기능들을 개발하는 스프린트였어요. 그래서 스프린트 시작 전에 feature/v1.12 라는 브랜치를 가장 먼저 생성하고, 이 브랜치를 기본으로 지라의 이슈 단위로 feature 브랜치를 생성해서 작업하고 있습니다!
    • Apollo, GraphQL
      • 스플에서는 REST API 가 아닌, GraphQL을 사용하고 있습니다.
      • REST API를 사용하면 결과 데이터는 서버에서 주는 대로 정해져 있지만, GraphQL은 내려온 결과를 토대로 클라이언트 개발자들이 필요한 정보를 조합해서 사용합니다.
      • 필요한 정보들을 조합할 때 우리는 GraphQL의 fragments를 사용합니다. Fragments는 쿼리에서 사용되는 필드들을 재사용할 수 있게 도와주는데, 그래서 우리는 쿼리를 더 간결하게 작성할 수 있게 되는 것이죠.
      • Apollo 는 .fragment 확장자 파일을 바탕으로 API를 생성해서, 선언된 fragment 객체들을 Dto code를 생성해줍니다. 그래서 graphQL 파일들을 수정하면 새로 빌드를 해줘야 변경된 Dto정보들을 빨간줄 없이 가져올 수 있어요!
    • RxJava : 비동기 통신을 위해, rx를 사용하고 있습니다.
    • Moshi : 작품의 스크립트는 JSON 형태로 내려오는데, 이를 JSON 객체로 변환해주는 역할을 Moshi가 해줍니다. Moshi가 생성해준 객체들은 다시 앱 안에서 사용하는 데이터로 변경되는 과정을 거치게 됩니다.
    • Dagger Hilt
      • Android Component 에 속하는 Class 의 Module 과 Component 를 없앨 수 있게 해줍니다!

      image

      • 한 화면을 생성하려면 Fragment, ViewModel, Component, Module 총 4개의 파일을 생성해야 했는데, 이제는 Fragment, ViewModel 의 2개 파일만 생성하면 되어 매우 편리해졌습니다.

      image

      • 스플에서는 Dagger Hilt를 적용하여 1622줄의 코드가 줄어들었습니다!
    • Room : 스플에서는 최근 본 작품의 기록에 대한 정보와, 스토리를 진행하다가 얻은 새로운 아이템이나 업적을 표시햐주는 빨간 마크에 대한 정보를 Room을 통해 앱에서 사용하는 기기의 로컬 데이터베이스에 저장하고 있습니다.
    • MediaPlayer : 스플의 효과음, BGM을 재생하는데 사용됩니다. 스플의 앱 특성상 소리의 종류가 다양하고, 길게 재생 혹은 동시 재생되는 경우가 있어서 MediaPlayer가 스토리플레이에는 더 적합하다고 판단했어요. 그래서 우리는 SoundPool 대신에 MediaPlayer를 사용하여 효과음, BGM을 구현하였습니다.
  • Storyplay Architecture
    • 스플은 SplashActivity와, MainActivity로 이루어져 있는, 사실상 Single Activity Architecture에요.
    • 기본적으로 스플은 MVVM모델을 지향하고 있습니다.
    • Layer 구조

      image

      • DataLayer
        • API, DB, Preference 등 데이터의 IO 를 담당합니다.
        • API 에서 받은 정보를 가공합니다
          • 스플의 경우 작품의 스크립트의 json 파일 까지 가공하는 역할을 합니다.
        • {XXX}Dto 라는 형태로 최종 가공된 데이터 모델이 생성됩니다.
      • UseCaseLayer
        • 실제 비지니스 로직에 맞춰서 데이터를 가공합니다.
        • {XXX}Dto에서 {XXX}Entity 라는 형태로 모델이 생성됩니다.
      • UI Layer
        • 실제 뷰에 관련된 로직을 담당합니다.

    아래의 이미지는 사용자가 작품을 읽기 시작하면 앱에서는 어떤 일이 일어나는지 간단히 표현해봤습니다

    image

    • 모듈 구조
      • app
        • Activity, Fragment와 같은 UI
        • UI에서 사용되는데 필요한 로직
        • UI에서 그려지는 데이터들에 대한 Model
        • {XXX}Entity를 Model로 바꿔주는 Mapper
      • app:core
        • 하단 Bottom Sheet, Popup Dialog, Progress bar와 같이 공통으로 사용되는 뷰
        • 주인공의 이름을 유저가 입력한 이름으로 대체, 격조사 적용과 같이 필요한 Utils
      • app:usecase
        • Usecase의 구현
        • {XXX}Dto를 {XXX}Entity로 생성해주는 Mapper
        • Usecase를 사용했을 때의 장점?
          • ViewModel에서 Usecase를 통해서 어떤 API가 호출되고, 이 화면에서는 무슨 동작을 하는 지 쉽게 알 수 있습니다
          • 일일이 ViewModel에서 함수를 작성하지 않고, 똑같은 동작을 수행하는 함수에 대해서 동일하게 작성되어서 유지보수하기가 쉽습니다.
      • app:data
        • {XXX}Dto 클래스
        • API, DB, Preference I/O
    • SubModule : AutoBindListAdapter
      • 스플은 곳곳에 RecyclerView가 사용됩니다. 기존의 RecyclerView adapter의 경우, 새로운 홀더가 추가될 때 마다 adapter의 코드를 수정해줘야 하고, 홀더의 구성이 adpater클래스의 안에 들어가야 볼 수 있어 주요한 로직이 되는 RecyclerView Holder의 구성 파악이 Fragment의 레벨에서 한번에 되지 않는 문제점을 해결하고자 AutobindListAdapter가 구성되었습니다.
      • 이렇게 구성된 AutoBindListAdapter를 Common Kit 로서 띵스플로우의 다른 안드로이드 서비스에도 쓰이도록 SubModule화 시켰습니다.
      • 구조
        • AutoBindHolderFactory : type 에 맞는 홀더를 생성하는 역할을 합니다.
        • AutoBindListAdapter : AutobindHolderFactory 를 사용하여 holder 를 생성하고 AutoBindViewHolder 에 데이터를 bind 해줍니다.
        • AutoBindViewHolder : AutoBindListAdapter 에 사용가능한 홀더입니다. 홀더를 만들때 해당 클래스를 상속받아야 합니다.
        • HolderEvent : Holder 의 이벤트를 외부로 내보내기 위해 사용되는 인터페이스 입니다.
    • SubModule : GraphQL
      • 스플은 API 쿼리 언어로 graphQL을 사용합니다.
      • GraphQL은 REST와 달리, 클라이언트 단에서 사용할 결과 데이터를 조합합니다. 그래서 iOS와 안드로이드가 각자 가져가는 데이터가 달라 테스트를 하다가도 데이터가 달라서 버그로 인지된 적이 있었는데, 알고보니 서로 다른 쿼리문의 결과를 가져와서 발생하는 문제였습니다.
      • 위와 같은 경우를 방지하기 위해, 스플에서는 GraphQL을 SubModule화 시켜서 iOS와 안드로이드에서 같은 graphQL 쿼리문을 사용하고, 같은 결과를 가져오게 했습니다.
      • 앞으로도 차차 iOS와의 데이터를 맞춰나가기 위해 점진적으로 모든 graphQL 쿼리문에 적용시킬 예정입니다.
  • 배포 전략
    • StoryPlay Android Git-Flow

    image

    • Master 브랜치 : 현재 마켓에 출시된 최신 코드가 반영되어 있는 브랜치입니다!
    • Hotfix 브랜치 : 예상치 못한 버그가 발생하거나 할 경우, 핫픽스를 진행합니다! 이럴 경우. Master 브랜치에서 Hotfix브랜치를 따와서 작업을 진행합니다
    • Develop 브랜치 : 개발이 진행되는 브랜치로, 최신 개발된 버전이 반영되어 있어요
      • Release 브랜치 : 스프린트가 끝난 후에 해당되는 버전의 release 브랜치를 develop으로 부터 따와서 QA를 진행합니다. QA가 끝난 후에 이 브랜치는 master, develop에 반영됩니다.
      • Feature 브랜치 : 위에서 설명했듯이, 스플에서는 스프린트 버전이 앱의 버전과 같습니다. 그래서 feature/v1.12 와 같은 스프린트버전 feature 브랜치를 따서 스프린트를 시작합니다. 스플팀은 Jira를 사용하고 있는데요, 그래서 Jira 이슈 단위로 feature 브랜치를 생성하여 작업 합니다. 또한 큰 이슈안에 여러 작은 이슈들로 쪼개어서 작업을 진행 할 경우에는 큰 이슈의 Feature 브랜치로부터 작은 이슈의 Feature 브랜치를 따서 작업을 진행합니다. 모든 개발이 끝아면 feature 브랜치들은 develop 브랜치에 merge 됩니다.
  • CI/CD : GitHub Actions
    • 스플 안드로이드는 GitHub Actions를 사용하여 CI/CD가 구축되어 있어요.
    • Android CI/CD For Prod QA : 운영 QA를 할 때는 운영 환경의 Firebase App Distribution에 앱이 업로드 됩니다.
    • Android CI/CD For Dev App : 개발중인 어느 브랜치에서도 테스트 앱을 개발환경의 Firebase App Distribution에 업로드 할 수 있도록 되어있습니다.
      • 스플은 개발 중인 기능에 대해서 PO, 디자이너, 에디터 등 다른 직무의 동료와의 얼라인을 위해 수동으로 GitHub Action이 동작되도록 하고 있어요.
      • 모든 개발이 완료 되었으면, master 브랜치에 반영된 내용이 테스트 앱에도 적용되어야 하기 때문에, 개발 환경의 Firebase App Distribution에 올리게 됩니다. 그래야 에디터 분들이 새로 개발한 기능을 활용하여 작품을 만드실 수 있기 때문이죠!
    • Android CI/CD For Release : Release v1.12 과 같은 커밋 명을 통해, 구글 플레이 비공개 테스트로 자동 업로드 합니다.

마치며…

이 블로그에 처음 개발 인턴십 후기를 올린게 엊그제 같은데, 벌써 1년이 지났네요. 스플도 많이 발전했고, 저 또한 스플과 함께 많이 발전한 거 같습니다. 저의 1년에 대한 후기가 궁금하시다면 우당탕탕 안드로이드 개발자 시작 글을 읽어주세요! ㅎㅎ 새삼 시간이 많이 지났다는 걸 실감하게 되네요. 앞으로 스플도, 저도 많이 더 발전했으면 좋겠습니다!

띵스플로우 팀은 자기의 일을 좋아하고 잘하는 사람들 입니다. 사용자와 서비스를 중심으로 빠르게 실행하고 학습하며, 다양한 직무의 사람들이 협업을 통해 시너지를 내고 있습니다. 다양한 콘텐츠 혁신을 이루고 있는 띵스플로우 팀에 함께할 분을 찾습니다! 언제든 people@thingsflow.com로 이메일을 주시기 바랍니다!

태그: , , , , , ,

카테고리:

업데이트:

댓글남기기