Skip to content

✒ [AOS] 개발일지

박진성 edited this page Dec 14, 2023 · 11 revisions

기술적 고민

분류 정리
Navigation Navigation 적용과 고민
화면 이동 어플 전반 화면 이동의 흐름
위치 권한 위치 권한 허용 여부에 따른 기능의 동작
지도 마커 보여주기 필터를 변경할 때 지도 화면을 어떻게 이동시킬까?
DataStore 왜 DataStore 인가?
지도와 마커 ---
계층분리 Clean Architecture 도입 이유
Glide Glide 를 선택한 이유
MVVM 아키텍쳐 MVVM vs. MVP vs. MVC
네트워크 통신 Retrofit 과 Okhttp
비동기 Coroutine



간단한 논의

2023-11-13

주요 안건

  • 디자인 수정
  • 초기 세팅
  • 컨벤션 추가

회의 내용

  • git branch 관련 [] (괄호 부분에 대한 인식이 되지 않음)

    • 문제가 있어서 깃 branch관련 네이밍 수정

    • **feature/[aos/be]-기능명 를 feature/aos-기능명으로 수정 → 서버도 동일시 하게 적용**

  • 안드로이드 초기 셋팅

    • 사용할 기술(dependencies) 적용, 아키텍처 ,single vs multi 모듈에 대한 선택, 패턴 적용
  • 네이밍 논의

    • 권한요청, constant, 상수 끼리 비슷한 성질끼리 네이밍,

    • 공용함수 확장함수를 쓸때는 맛집 상세같은 global action같은것은 ui 하단에 파일로 만들어서 진행할지에 대한 고민

    • extension이랑 util의 분리?

    • uiState → 해당 패키지 내에서?

    • viewModel 의uiState , event | effect?

2023-11-14

멘토링 내용 정리

  • 마지막에는 기술에 대한 답변을 할 수 있어야한다. (최종 목표가 되어야 할 듯)
    • Glide 와 비교되는 라이브러리 몇개 있는데, 이것도 비교해서 왜 썼는지 질문 받았을 때 당황하지 않고 말할 수 있어야 한다.
    • Viewmodel factory 사용해서 주입하고 -> hilt 를 적용
  • Navigation 일단 써보자. 쓰다가 중간에 activitiy 로 바꾸고 싶을 수도 있다.
  • 프로젝트에 어떤 매력이 있나요?
    • Navigation 관련한 스토리텔링하면 매력적일것이다~
    • 모듈화도 매력일 수 있음
    • 배포를 위해 위치 정보 및 개인정보 약관을 확인하고 출시하는 과정을 고민하는 것 자체는 매력적임. 하지만 기간 내에는 조금 어려울 수 있음.
  • 수정 후의 feature-list 는 현실적인지?
    • 기능 시원하게 날린 것은 잘 했다고 생각함.
    • MVP 를 4주차로 잡아서 조금 빠듯할 수는 있음.
    • 기능을 구현할 때 협업 방식은 수직과 수평이 있는데 장단이 있으니 잘 선택해서~
      • 수직은 domain, server, data, viewmodel, ui 작업 단위로 쪼갤 수 있는데 이를 어떻게 분배하냐가 수직의 관점 (하나의 기능에 여러 명이 붙어서)
      • 수평은 하나의 기능은 한명이 맡는 것
2023-11-15

기술적 고민과 해결

  • Navigation 사용시, 뒤로가기를 어떻게 처리하는게 좋을까?

    • navigateUp() vs popBackStack()

    • 해결

      • Navigation 적용과 고민 링크에서 확인 가능
  • flow 로 ui event 관리 + navigation 사용

    • navigationUp 으로 뒤로가기를 처리했을 때 처음에는 한번, 두번째에는 두번, 세번째에는 세번 클릭해야 뒤로가기가 실행되는 문제

    • 해결

      • sharedFlow 옵션
        • replay : 새로운 수신자(subscriber)가 등록될 때 이전 이벤트를 재생하는지 여부. 즉 최신의 이벤트만 처리하고 싶으면 값을 0으로 주어야 함.
        • extraBufferCapacity : buffer 개수 정하는 옵션. flow의 emit이 빠르고 collect가 느릴 때 지정된 갯수만큼 buffer에 저장되며 지정된 갯수가 넘어가면 onBufferOverflow 정책에 따라 동작.
        • onBufferOverflow : buffer 가 다 찼을 경우 정책.
        • ex) replay 를 1로 설정하고 back 버튼을 누르니까 back & (이전 이벤트) goToEdit 이 함께 눌러지면서 back 이 동작이 실행 안됨. replay = 0 으로 설정하니 back 만 잡힘.
  • 현업 개발자들은 Merge Conflict 관리를 어떻게 하는지 궁금. github 에서 충돌 병합을 하진 않을거 같은데..

    • 멘토링 시간에 조언을 들음.
2023-11-16

기술적 고민과 해결

  • Duplicate class android.support … 관련 에러 발생

  • Failed resolution of: Lcom/google/android/gms/location/LocationRequest 에러 발생

    • naverMap 현위치 트래킹을 위해, "com.google.android.gms:play-services-location:16.0.0" 를 썼었는데, 버전을 21.0.1 로 변경 후 해결
  • AutoCompleteTextView 에 처음부터 값을 설정하니 해당 지역만 drop-down 에 표시됨

    • ex. 용산구를 설정하고 drop-down 하니 용산구만 표시됨
  • 활동지역 설정 Spinner 로 변경 후 해결

2023-11-20

안건

  • Navigation action 처리 방식 통일 논의
  • Api, Repository 파일 분리 단위 논의
  • Repository 에러 헨들링 방식 논의

논의 내용

  • naming

    • → response data class : 기능 + Response

    • → api 관련 메소드 : method 빼고 동사 + 명사 or 명사 + 명사 ex) loginNaver

    • api - repository - repositoryImpl - viewModel 전부 다 같은 함수명

  • Api, Repository 파일 분리 단위 논의

    • 화면으로만 쓰일 것은 화면으로만 API
      • Intro 는 하나로 관리
    • 중복으로 쓰일 것들은 기능 API
      • validation (email, nickname)
      • refreshToken 발급
  • 함수 네이밍은 동사 + 명사 / 명사 + 명사 / 동사 + 명사 + 명사 의 형식을 유지

멘토링

  • 캐시 한번 찾아보기
    • 메모리에 저장하거나 로컬에 저장하거나
  • api 호출을 최적화 하는 방안을 생각해보기 (근거를 만들어서 결론지어보기)
  • 클러스터링
    • 고민이 필요할 수도
    • 많은 부분에 마커가 찍혀있다면 하나로 처리해주는 것 생각해보기
    • 삽질기록 경험으로 남기면 됨
  • 패키지 컨벤션 찾아보기
  • 위치 권한과 관련해서는 시각화 자료 만들면 좋을 듯
  • network error 는 error 대로, 자식 viewmodel 에서 error 는 error 대로 나면서 나뉠 수 있음
    • 중복코드 해결
    • 있는것 자체는 괜찮음
2023-11-22

논의 내용

  • Api 응답 처리 로직 고민

    • BaseResponse generic 타입 data class 로 구현

    • ApiState → BaseState 로 변경하고

    • runNNApi → runRemote / runLocal 로 BaseState 반환하도록 수정

  • 토큰 관련

    • accesstoken 을 datastore 에서 비우는 경우 → 로그아웃, 회원탈퇴, refreshtoken 만료

    • 네이버 로그인 토큰을 헤더에 넣을 때는 직접 넣어주기

    • interceptor 로 구현하는건 access token 헤더에 넣는 경우에만 사용하기

2023-11-23

기술적 고민

  • Home Filter RecyclerView 클릭 이벤트 이슈

    • item 을 databinding 으로 주입시켜서, text 를 set 하면 잔상이 남음
class HomeFilterViewHolder(
    private val binding: ItemHomeFilterBinding
): RecyclerView.ViewHolder(binding.root){

    fun bind(item: UiFilterData){
        binding.item = item
    }
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="item"
            type="com.avengers.nibobnebob.presentation.ui.main.home.model.UiFilterData" />

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="12dp">

        <TextView
            android:id="@+id/tv_filter"
            style="@style/TextMediumBold"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/rect_primary3fill_nostroke_30radius"
            android:onClick="@{() -> item.onItemClicked.invoke(item.name)}"
            android:paddingHorizontal="12dp"
            android:paddingVertical="4dp"
            android:text="@{item.name}" 
            android:textColor="@color/white"
            app:filterBackground="@{item.isSelected}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
  • ViewHolder 내부에서 처리하게 되면, 잔상이 남지 않음
class HomeFilterViewHolder(
    private val binding: ItemHomeFilterBinding
): RecyclerView.ViewHolder(binding.root){

    fun bind(item: UiFilterData){
        binding.item = item
				binding.tvFilter.text = item.name
    }
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="item"
            type="com.avengers.nibobnebob.presentation.ui.main.home.model.UiFilterData" />

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="12dp">

        <TextView
            android:id="@+id/tv_filter"
            style="@style/TextMediumBold"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="@drawable/rect_primary3fill_nostroke_30radius"
            android:onClick="@{() -> item.onItemClicked.invoke(item.name)}"
            android:paddingHorizontal="12dp"
            android:paddingVertical="4dp"
            android:textColor="@color/white"
            app:filterBackground="@{item.isSelected}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

💡 어떤 차이로 발생하는지 아직 파악 하지 못함.. 잔상을 없애기 위해, ViewHolder 내부 코드로 commit 예정
  • Home Filter 클릭시, 깜빡임 현상

    • 클릭 이벤트를 HomeViewModel 에서 함수로 정의해, 함수 레퍼런스로 Item에 전달하고 있는중
    • HomeFilterAdapter 에서 DiffUtil로 아이템 내용 바뀌었을때 감지하도록 설정 하였으나, 클릭후 backGround 바뀔때 사알짝 깜빡임 현상 발생
2023-11-25

기술적 고민과 해결

  • 로그아웃 / 회원탈퇴 후 기존 activity 모두 종료하고 IntroActivity 나타내기
    • 기존 코드

      (*activity* as MainActivity).finish()
      val intent = Intent(context, IntroActivity::class.java)
                              startActivity(intent)
    • 리뷰 참고하여 Intent Flag 설정

      • FLAG_ACTIVITY_NEW_TASK : 기존 activity 스택이 아닌 새로운 스택에 activity 가 추가됨.
      • FLAG_ACTIVITY_CLEAR_TASK : FLAG_ACTIVITY_NEW_TASK 와 함께 사용해야 함. 다른 activity 모두 종료시킴.
      val intent = Intent(context, IntroActivity::class.java)
      intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
      startActivity(intent)
2023-11-28

페어프로그래밍 안건

  • 뒤로가기 두번 눌러서 앱 종료 → o
  • bottomsheet 내리는 시점
  • 제일 처음 지도가 표시되는 위치 지금 설정 되어있는건지? → 찾아보기 (시청역으로 되어있음)
  • 검색 marker 도 marker 리스트에 추가해야하는가? → 검색 bottom sheet 올라오고 난 후에 그게 내려가고 이후 동작을 정해야할듯
  • 마이페이지 수정, 맛집 추가 등 post 보내고 난 후에 유저에게 어떻게 메세지 보여줄 건지 정하기
  • 통신 에러 시 어떻게 메세지 제공할 것인지
  • GlobalRepository / Global 네이밍
  • global 패키지 main 하위에 두기
  • 마커 이미지 바꾸기

기술적 고민

  • Adapter 에 Item 안에 ClickListener 를 주입하는데, 어떻게 주입하는게 바람직할까

    • 팔로우 버튼을 클릭했을때의 동작을 onBtnClickListener로 넣어주려고 한다
    • 팔로잉 상태라면, 팔로우 취소 API 요청을 해야하고, 논팔로잉 상태라면 팔로우 API 호출을 해야한다
    • 이럴떄 다음과같은 고민이 생김
data class UiFollowData(
    val nickName: String = "",
    val region: String = "",
    val isFollowing: Boolean = true,
    val onBtnClickListener: (String, String) -> Unit,
    val onRootClickListener: (String) -> Unit
)
  • 함수 네이밍을, Adapter 입장에서 함수의 동작을 알고있다는 가정을 해야하는가?

  • item 의 상태값에 따라, 다른 동작을하는 두 함수를 호출해야 될때, 한개의 함수에 두개의 인자를 받을것인가? 아니면 두개의 함수를 받을 것인가?

2023-12-01

마스터 클래스 리뷰

  • Interceptor 부분에서 책임 분리에 대해서 신경 써주기

    • Bearer에서 listener를 해주는건 어떤지?
  • App부분에서 Hilt를 제대로 쓴건가? 라는 생각이 바로 들것 같다는 의견이심

companion object{
        lateinit var instance : App
        val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = APP_NAME)
        fun getContext(): Context = instance.applicationContext
    }
  • 다 이런식으로 동일하게 repository에서 진행하고 있는데 줄이기
Flow<BaseState<BaseResponse<List<FollowListResponse>>>>
data class BaseStateResponse<T>(val baseState: BaseState, val baseResponse: BaseResponse<T>)

typealias FollowListFlow<T> = Flow<BaseStateResponse<List<T>>>

FollowListFlow<FollowListResponse>
Clone this wiki locally