[Android] Preferences Data store 공식문서의 No type safety

김방토·2025년 2월 26일
0

Android

목록 보기
3/10

발단

현재 프로젝트에서 자주 써야하지만 잦은 변경이 되지 않는 값을 preferences datastore를 사용해서 저장해서 사용하고 있다.

공식문서를 차근차근 따라해가며 도입을 완료했고, 전체적으로는 이 부분을 다른 조원이 맡아서 했기 때문에 생각없이 꺼내서 쓰다가 구현하기로 한 두개의 앱 중 나머지 한개 부분을 서로 해보지 않은 부분을 해보자고 얘기한 후 이 부분을 내가 손보게 되었다.

전개

구현이 거의 완료 된 앱(이하 관리자 앱)에서 쓰고있는 코드는 suspend로 읽기와 쓰기를 처리하고 있다.
공식문서에서는 쓰기 작업을 suspend로, 읽기 작업을 flow로 처리하고 있다.

관리자 앱의 다른 읽기/쓰기 작업들(네트워크 작업)에서는 datasource 레이어에서 suspend로 되어있는 것들을 repository 레이어에서 초기화, 준비, 성공, 실패로 나뉜 커스텀 sealed class로 감싸 UI단에서 일관적인 화면 처리를 가능하도록 flow로 처리했다.
(아마 await처럼 처리하기 위해 suspend 형태로 놔둔듯 하다. 실제 API를 호출하기 위해 필요한 값들-userId나 teamId같은-을 Datastore에서 처리했기 때문에 맨 처음 호출이 선행되고 난 다음 그 뒤가 진행되어야 했음)

그렇게 정의된 Datastore에서 조원은 viewModel을 통해 이 값들을 사용했고, 나는 컴포저블에서 바로 Datastore를 호출해 사용했다.

그래서 차라리 새로 구현하기 시작한 앱(이하 스탭 앱)에서는 사용방법을 합의해서 통일하면 조금 더 깔끔한 코드가 되지 않을까 하는 생각에 다시 공식문서부터 찬찬히 살펴보기로!

위기

안드로이드의 Data Store 공식문서

preferences datastore의 정의, 읽고 쓰는 방법 등은 공식문서에 친절하게...나와...있지만...

안드로이드 Datastore 공식 문서의 읽기 부분

데이터를 flow로 노출할 수 있다는거 오키오키. 알겠어요
그런데 저 주석의 No type safety가 미친듯이 신경쓰였다.
나는 주언어를 자바스크립트 -> 타입스크립트 -> 코틀린으로 옮겨오면서 이미 수많은 타입 예외를 낸 전적이 있기때문에 특히 더 예민하다...
그런데 아무리 찾아봐도! 저 문서에! 타입 안정성에 대한 얘기가 없어!
안드로이드의 공식문서는 꽤나 친절한 편이라고 생각하는데, 가끔 이렇게 예상치 못한 곳에서 뒤통수를 칠 때가 있다.
내가 적응해야 한다. 상대는 구글이다...

타입 안정성 오키. 없을 수 있다고 생각해요.
근데... 너네 이미 값 저장할때 타입 명시하라고 하잖아...?🥲

우리는 string으로 값을 저장하고 있어 stringPreferencesKey를 사용하고 있는데, 공식문서에는 intPreferencesKey를 사용하고 있다.
이미 키를 지정할때부터 밸류 타입을 요구해놓고 도대체 왜 노 타입 세이프티를 주장하는지 눈물나도록 답답해서 찾아보았다...
구글링 하면 자꾸 preferences는 type safety 지원 안 하니까 proto 쓰라고 해서 더 오기가 생김... 쓰는건 제가 결정할게요 왜 그런지부터 알고싶다고요...

절정

일단 flow로 값을 읽어오는 친구를 만들어 확인해보면, Flow<String?>을 반환한다. nullable을 반환한다는 것 자체는 딱히 type safety의 문제가 아니라고 생각한다. 데이터스토어에 정의만 해놓고 저장은 안 하고 가져오려고 하면 null을 가져올수도 있으니까?(그야 저장된게 없으니까..)
내가 생각한 no type safety란 Int키에 String을 저장할수 있다던가 하는것이다.

그래서 챗GPT와 심도깊은(?) 대화를 나누어 보았다.

결말

지정한 key와 다른 타입을 저장하는것이 가능?

✨불가능!

궁금하면 해보는게 제일 좋다고 생각하는 저라는 인간은 일단 냅다 String에 Int를 저장해봅니다...
애초에 IDE에서 빨간줄 띄워줍니다!
아니 그럼 도대체 왜!!!! 애초에 저장이 안되는데 왜 no type safety야!!!!!!!!!!!!!(오열

그럼 도대체 왜?

intPreferencesKey("example_counter")로 만든 키에는 Int 값만 저장할 수 있기 때문에 String을 저장하려 하면 컴파일 오류가 발생합니다.
그러나, 이전 저장 데이터가 Int라는 보장이 없기 때문에 런타임 오류는 발생할 수 있습니다.
예를 들어, JSON 기반 SharedPreferences → DataStore 마이그레이션 과정에서 데이터 타입이 꼬일 가능성이 있습니다.

아 그러니까, DataStore의 근본부터 알았어야 했다...
지금의 DataStore의 바탕이 되는 SharedPreferences는 여러가지 불편한 점이 있었기 때문에 Preferences와 Proto Datastore를 만들었고, 현재 안드로이드 공식문서에도 마이그레이션해서 사용하기를 권장하고 있는데 SharedPreferences에서는 값을 저장할때 특정 타입을 강제하지 않았다는 것이다...
putInt()나 putString()같은 메서드를 이용해 저장하기는 했으나, 내부적으로는 사실상 모든 데이터를 같은 곳에 저장했다는 말씀...!

예를 들면 putInt("teamId", 1234)라고 하고 난 뒤에
putString("teamId", "myTeamName") 하고 같은 키에 다른 타입의 밸류를 넣는것이 가능했다는것!

그런 SharedPreferences를 Preferences Datastore로 마이그레이션 하면, 내부적으로 어떤 값이 저장되어있는지 확신할수가 없는 상태이기 때문에 no type safety라고 하는것이었어요...!

그러면 사실 저희 프로젝트는 SharedPreferences를 사용하지 않았고, 당연히 마이그레이션 작업도 한 적이 없기 때문에 별 문제는 되지 않는 상황입니다.

하지만 나중에 제가 마이그레이션을 할 수도 있고... 뭐든 알아둬서 나쁠게 없습니다.
그렇게 생각하며 눈물을 닦고 저는 마저 일 하러 가도록 하겠습니다...

profile
🍅 준비된 안드로이드 개발자 📱

0개의 댓글