• Home
  • About
    • Zzu-h photo

      Zzu-h

      주니어 Android 개발자입니다.

    • Learn More
    • Email
    • Instagram
    • Tistory
    • Github
  • Posts
    • All Posts
    • All Tags
    • All Categories
  • Projects

GitHub Search App

11 Jul 2022

Reading time ~5 minutes

GitHub Search App

👀 Overview

   
한줄 소개 자신의 이슈와 알림을 받아볼 수 있으며, 키워드를 통해 깃헙 레포 검색을 할 수 있는 깃헙 앱
진행기간 2022.07.11 ~ 2022.07.22
Skills Retrofit2, Glide, Koin, Flow, LiveData
팀구성 Android 2
   

❓ 개발 목표

해당 프로젝트는 아래의 내용을 증명하는 것을 목표로 함.

  1. 협업을 배우고 같이 프로젝트를 진행하는 과정을 같이 수행하며 이를 익힘
  2. 최대한 많은 기술들을 학습하고 적용하는 것
  3. 코드를 최대한 한 사람이 작성한 것처럼 보이도록 협업을 잘 하는 것

🍀 서비스 내용

자신의 깃허브 아이디를 통해 로그인을 할 수 있습니다. 로그인을 통해 사용자는 직접 자신의 이슈와 알림을 받아볼 수 있으며, 궁금할 시 타인의 저장소도 검색해볼 수 있습니다.

🛠 기술 스택

Retrofit2

  • 서버로부터 데이터를 효율적으로 불러오기 위해 사용됨

Glide

  • Glide vs Coil
    • 참고
    • Glide
      • 반복되는 이미지가 많아서 캐시 데이터가 많이 필요할 때
      • 원본 이미지 사이즈와 ImageView 사이즈 간의 편차가 클 때
      • Warm Start가 자주 일어나는 환경일 때
      • 순간적으로 많은 이미지가 로딩됐을 때, 메모리 사용량 편차가 크면 안 되는 상황일 때
    • Coil
      • 메모리 사용량에 여유가 있고, 다양한 이미지를 사용해 캐시가 동작하기 어려울 때
      • Custom Image Transform을 사용하는 부분이 많을 때
  • 우리는 Glide를 선택함
    • Glide와 Coil의 실질적인 차이를 느끼지 못함
    • 그래서 가장 대중적이며, 인기가 많았기에 이를
  • Coil은 코틀린과 코루틴 기반이기에 향후 프로젝트에서 사용해보려 함

Koin

  • Hilt vs Koin
    • Hilt
      • 런닝커브가 높음
      • Dagger2에 기반한 라이브러리
      • 컴파일 타임에 의존성 주입
      • 보일러 플레이트 코드가 감소
    • Koin
      • 런닝커브가 낮음
      • 런타임에 의존성 주입
      • 의존 파악 어려움
  • 우리는 Koin을 선택함
    • 학습단계이기에 런닝커브가 낮은 Koin을 선택했고
    • 이후 프로젝트에 Hilt를 사용하면서 이와 비교하고자 한다.
    • 상세 내용은 다음과 같다.

Kotlin Flow & Live Data

  • Flow vs LiveData
    • Flow
      • 비동기 처리에 효율적
      • 안드로이드 플랫폼에 독립적
    • LiveData
      • UI와 데이터 상태의 일치 보장
      • 메모리 누수가 없음
      • 데이터 유지
      • 리소스 공유
  • 두 개 모두 장점들이 확실했고, 이 둘을 모두 사용할 수 있기에 우리는 장점만을 뽑아서 쓸 수 있도록 모두 사용하기로 결정함
    • 상세 내용은 다음과 같다.

Moshi

  • gson vs. moshi vs. kotlin serialization
    • gson
      • Default Value에 대해 무시하고 0 or Null로 처리된다.
    • kotlin serialization
      • 변수에 프로퍼티를 포함하고 있지 않으면 null 대신 기본 값
    • moshi
      • 파싱 실패에 대한 더 나은 실패 메시지를 확인이 가능하다.
  • 우리는 Moshi를 선택함
    • 데이터가 적절히 처리가 되지 않았을 때 자세한 오류 메시지로 어디서 발생한 것인지를 더 잘 확인할 수 있음.
    • 대중적인 Gson과 Kotlin 기반의 Kotlin Serialization도 매력이 있기에 이후 프로젝트에서 고려해볼만한 대상인 듯 하다.

🖥 개발 내용

Notification 화면

동기 처리와 비동기 처리

  • 알림 화면에서 Github Notification API를 활용해 알림 내역들을 받아오되, 커멘트 갯수나 기타 정보들은 하나의 API에서만 있는 것이 아니기에 각 아이템에 대한 기타 정보를 얻기위해 2개의 API를 통해 요청을 했습니다.
  • 이때 주로 신경썼던 부분은 리스트의 아이템에 대해서 비동기 처리와 각 아이템의 추가 정보를 받아올 땐 동기처리를 해 데이터를 받아오는 것에 최대한 효율적으로 동작하게끔 만들고자 노력했습니다.
  • 이때 비동기 처리를 위해 코루틴을 활용했으며, 각 아이템에서 동기적으로 데이터를 받아오기 위해 Defered를 이용해 결과값을 받아오고 데이터를 파싱해 뷰로 전달하게 했습니다.

페이징 처리

  • 페이징 처리를 위해 페이징 라이브러리가 아닌 페이징 관리 클래스를 따로 만들어서 페이징 처리를 구현할 수 있었습니다.
  • RecyclerViewScrollMediator라는 RecyclerView와 끝에 도달했을 때 수행할 함수를 받아와 이를 관리하는 클래스를 만들었습니다.
  • 이 클래스는 RecyclerView.OnScrollListener를 상속받아 RecyclerView가 끝에 도달했을 때를 감지하고, 그때 새로운 페이지를 호출하는 메소드를 수행합니다.

스와이프 후 캐싱처리

알림 아이템을 스와이프를 했을 때 결과를 즉시 수행하는 것에 문제가 있었습니다.

  • 특정 위치의 아이템이 지워졌다면, 현재 사용자가 가지고 있는 리스트의 n개와 서버의 첫 번째 페이지의 n개의 데이터는 불일치 할 것입니다.

우리는 크게 3가지의 해결 방안을 고안했습니다.

  1. Swipe 후, 현재 페이지 전체 호출
  2. 현재 페이지의 마지막 데이터 호출
  3. 모션 처리 후, 삭제 데이터 캐싱 처리

위에서 1,2의 경우 api 요청이 1번씩 더 요청이 되기에 비효율적이라고 판단해 3번으로 결정했습니다.

  • 그래서 스와이프 된 아이템은 viewModel에 캐시로 데이터를 저장해두고 있다가
  • 해당 화면을 벗어나게 되면 백그라운드에서 삭제 처리를 수행합니다.

Profile 화면

  • 이는 데이터 바인딩을 통해 화면을 구현하고 없는 데이터에 대해서 뷰를 보여지지 않도록 삼항 연산자를 이용해 개발했습니다.

📈 성장 경험

협업 경험

저는 이 프로젝트를 통해서 협업 경험치를 크게 얻을 수 있었습니다.

  1. 프로젝트 수행 과정
    • 안드로이드 협업은 처음 겪었습니다. 그래서 어떻게 진행되는지 모르던 저를 팀원께서 이끌어주며 프로젝트의 흐름을 이해시켜주셨습니다.
    • 네이밍 컨벤션 정의 -> 깃 브랜치 전략 결정 -> 요구 사항을 정의 -> 사용할 기술 스택 선정 -> 프로젝트 구조 설계 -> 역할 분담 및 프로젝트 시작 -> 일일 회고를 통한 서로의 피드백 -> 코드 머지 등
    • 순서는 조금씩 변경될 수 있겠지만, 큰 흐름을 잡아준 것에 크게 성장할 수 있었습니다.
  2. 문서 작업
    • 백로그나 깃 위키를 사용하는 방법 등을 배울 수 있었습니다.
    • 백로그 작성을 통해 기능 세부사항들을 정의하고 각 세부사항들에 대해 어떤 기술이 들어갈지를 결정하는 과정을 배울 수 있었습니다.
      • 또한, 큰 범주를 나누면서 역할 분담이 수월하게 이루어 지는 것을 통해 백로그 작성의 이점을 이해할 수 있었습니다.
    • 깃 위키를 통해 해당 프로젝트에 관련된 문서 내용들을 손쉽게 작성하고 확인할 수 있음을 알았고,
      • 각종 트러블 슈팅, 스프린트, 스프린트 회고 등을 작성하면서 프로젝트 진행 과정들을 한 눈에 확인하며 지나온 행적들을 볼 수 있음을 알 수 있었습니다.
  3. 깃 사용
    • 이전엔 git add / git commit / git push밖에 사용할 줄 몰랐었습니다.
    • 하지만 이를 통해 Issue의 사용, Pull Request의 사용 그리고 commit 메시지의 상세 내용 작성 등을 할 수 있게 되었으며,
      • Github의 Milestone과 Project를 활용해 프로젝트 진행 상황들을 가시적으로 확인도 할 수 있었습니다.
    • 깃 브랜치 전략에 최대한 따르도록 해 깃 사용법을 더욱 익힐 수 있었습니다.
  4. 일일 회고
    • 하루가 끝나기 전 모두 모여 현재 어디까지 진행되었음을 이야기 할 수 있었고, 궁금했던 코드들은 이때 직접 물어볼 수 있었던 것이 좋았습니다.
    • 필요시에 이때 머지를 하며 하루를 마무리하는 개운함을 맛 볼 수 있었습니다.

페이징 처리

Paging Library를 사용하지 않고 직접 구현을 할 때 상당한 귀찮음을 안고 진행했습니다.
Paging Library의 편리함을 깨달았고, 직접 구현했을 때 아쉬운 부분은 다음과 같습니다.

  • 아이템을 처음 호출할 때 넉넉히 2배수 정도 더 불러오는 것
  • RecyclerView가 끝에 도달하기 전 즉, 마지막 아이템의 1~2번째 앞에 도달했을 때 미리 호출

위의 기능 2개를 같이 만들었다면, 바닥에 도달했을 때 뚝뚝 끊기는 느낌의 앱이 아니라 자연스레 무한스크롤 되는 앱을 개발할 수 있을 것이라 생각됩니다.

동기 처리와 비동기 처리

두 개의 다른 api요청을 하기 위해 어떨 때는 비동기 처리를 또, 어떨 때는 동기 처리를 수행해 정확한 데이터를 만들어야 했습니다.
이번 과정을 통해 적절한 시기에 비동기/동기 처리를 수행해 사용자가 원하는 결과를 만들 수 있게 되었습니다.

딥링크

OAuth 로그인 후 딥링크의 콜백을 받으면 이전 화면으로 돌아가는 것이 아닌 새로운 Activity를 만들어 버그를 발생시켰습니다.
그래서 이를 위해 SingleTask를 이용하여 버그를 해결할 수 있었습니다.

의존성

의존성 주입이 필요한 이유와 하는 방법들을 이해하고 적용할 수 있었습니다.

플로우

아직 플로우에 대해 심층적인 이해를 했다고 이야기 하기는 힘듭니다.
하지만 모든 상황에 LiveData를 쓰던 전, LiveData가 과연 전체를 커버하는데 가장 효율적인 방법인가를 다시 한번 생각할 수 있던 계기였고, 플로우와 LiveData의 조합을 통해 더 효율적인 성능을 뽐낼 수 있음을 이해했습니다.



project Share Tweet +1