3기 김태영
1시간 전•

11월 일 일지

11월 10일

오늘 공부에 투자한 순수한 시간: 4시간 30분

학습한 개념 : apps-in-toss-harness를 내 구독관리앱에 적용하기

<app-in-toss-harness 적용하기>

1. 적용할 apps-in-toss-harness 소개

-> 미니앱을 빌드할 때 스위치 하나를 켜면 디버그 번들이 나오고, 안 켜면 릴리즈 번들이 나오게 된다. 두 번들은 앱 기능이 동일하게 작동하게 된다. 디버그 번들에만 debugger-client라는 코드가 한 덩이 더 들어 있고, 그게 화면, 로그, 네트워크를 밖으로 내보내는 통로를 여는 코드인 것이다.

정리하자면 릴리즈 번들은 보여주기만 하는 앱이고, 디버그 번들은 통로가 하나 더 달린 앱이다.

문제는 미니앱이 토스 앱 안에서만 돌아간다는 데서 나온다. 나의 개발환경인 PC와 폰에서 작동한느 toss앱 안에서의 환경은 매우 다르기 때문에 동작을 확인하려면 콘솔에 올려야 한다. 이 말은 디버깅용으로 올린 번들과 출시용으로 올린 번들이 같은 목록에 나란히 쌓인다는 말과 같다. 그리고 콘솔은 폰에서 테스트한 배포를 그대로 검수로 제출한다.

이 말은 디버깅 흐름과 출시 흐름이 같은 통로를 사용한다는 것이다.

디버그 번들이 오류가 난 것이 아니다. 개발을 할 때는 반드시 필요한 올바른 산출물이고 위치한 자리가 틀린것이다. 따라서 이는 품질을 보는 검사로는 확인할 수도 없고 걸러질 수도 없다. 빌드도 되고 테스트도 통과하고 폰에서도 아주 잘 돌아가고 작동하 수 있기때문이다.

그런데 검수 제출을 지나면 되돌릴 수 없다. 이미 깔린 앱은 지울 수 없고, 검수를 취소하면 그 배포는 다시 요청할 수 없다고 한다.

하네스를 쓰는 아주 포괄적인 원리는 사람이 볼 수 없는 것을 사람에게 묻지 않는 것이다.

2. 내 프로젝트에 적용할 수 있는 구조적 이유와 근거

내 앱에서는 drift를 사용한다. 나의 구독관리 앱에서 drift가 하는 일은 내가 쓴 선언을 보고 앱이 실제로 쓸 코드를 대신 만들어주는 것이다. 그래서 파일이 둘로 갈린다. tables.dart는 54줄이고, drift가 만든 app_database.g.dart는 2616줄이다. 내가 고치는 건 54줄이고 앱이 실제로 쓰는 건 2616줄인 것이다. 내가 table.dart에서 새로운 부분을 추가하거나 수정하면 변환해야 하는 단계가 필요하게 되는데 이 변환 단계가 build_runner다.

여기에 한 겹이 더 있다. 데이터가 사는 곳은 내가 만든 앱을 사용하는 사용자 개인 기기 안에 있는subscription_manager.sqlite(내가 만든 데이터베이스 파일의 이름) 파일이다. 앱을 업데이트하면 코드는 전부 새것으로 교체되는데 이 파일은 "그대로" 남는다. 즉, 한마디로 코드와 데이터의 수명이 다르게 되는 것이고, 데이터가 바뀐 코드를 따라가지 못하는 것이다. 둘을 연결해서 이어주는 신호는 schemaVersion 숫자 하나뿐이고, 이 숫자를 올리지 않으면 drift는 바뀐 게 없다고 간주하고 DB를 이에 맞게 바꾸지 않는다.

이 문제의 구조가 앱인토스 문제의 구조와 동일하게 대응된다. 앱인토스에서도 내가 고치는 소스와 세상에 나가는 번들이 다른 물건이고, 그 사이에 빌드가 끼어 있었다. 내 앱은 변환이 두 번이라 한 겹 더 깊다.

핵심 대응은 이렇게 잡았다.

앱인토스 : 번들 ──보이지 않는 성질──> "디버그 코드가 들었나"

내 앱 : 앱 업데이트 ──보이지 않는 성질──> "기존 사용자 DB에서 열리나"

둘 다 "물건이 아니라 물건이 들고 있는 성질"이 문제다. 그리고 그 성질은 눈으로 볼 수 없다. 대응을 더 벌려보면 이렇다.

세상에 공개되는 것 : .ait 번들 -> 앱 업데이트(APK)

보이지 않는 성질 : 디버그 코드 여부 -> 기존 DB에서 열리는지

개발자가 보는 쪽 : 디버그 번들 -> 새로 만든 DB(내 폰)

사용자가 보는 쪽 : 출시된 그것 -> 기존 DB(남의 폰)

이 대응 관계가 어떻게 성립하는지를 세 가지로 확인할 수 있다.

  1. 내가 고치는 것과 나가는 것이 다른 물건인가?

  2. 어긋나도 겉으로 드러나지 않는가?

  3. 되돌릴 수 없는가.?

세 개 다 성립한다. 두 번째는 완전히 똑같다. analyze, test, run이 전부 통과하게 된다. 셋 다 지금 코드가 어떤가를 보는 도구라서, 이 코드가 옛 DB를 만나면 어떻게 되는지는 아무도 안 본다. 세 번째는 앱인토스보다 무겁다. 되돌릴 수 없는 게 코드가 아니라 사용자 데이터이고, 서버를 사용하지 않기 떄문에 데이터를 백업해둘 수도 없다.

그래서 같은 구조의 문제라고 보고 하네스를 적용할 수 있다고 정리했다.

실제로 내 앱에서 생길 수 있는 문제를 그려보면, 구독에 메모 칼럼을 추가하면서 schemaVersion을 안 올리고 마이그레이션도 안 쓴 경우다. 내 폰에서는 DB가 새로 만들어지니 멀쩡하게 돌아간다. 그런데 이미 쓰던 사람 DB에는 메모 칼럼이 없다. 앱을 켜는 순간 터진다. 리뷰에 안 켜진다는 말이 올라와도 내 폰에서는 재현이 안 되고 서버가 없으니 로그도 없다.

원인을 끝까지 내려보면 둘 다 내가 소유하지 않은 것에서 나온다.

하네스

미니앱은 토스 앱 안의 한 화면이다

↓ 배포 채널을 소유하지 않는다

폰에서 열려면 콘솔을 거쳐야 한다

↓

디버깅 흐름과 출시 흐름이 같은 통로를 쓴다

↓

섞일 수 있다

내 앱

데이터가 서버가 아니라 사용자 기기에 있다

↓ 데이터는 코드와 함께 배포되지 않는다

코드는 교체되는데 DB 파일은 남는다

↓

새 코드가 옛 데이터를 만나는 상황이 생긴다

↓

깨질 수 있다

3. 어떻게 적용할 수 있을까?

전체 큰 범위에서 나의 구독관리 앱에 하네스가 어떻게 적용되는지에 대해 한 문장으로 정리를 해보면

"스키마를 바꿀 때 build_runner, schemaVersion, 마이그레이션 세 개가 한 세트인데 하나라도 빠지면 아무 에러 없이 기존 사용자 DB만 깨지게 되고, 작업을 시작하기 전에 기계가 생성 코드에 손댄 흔적이 있는지 먼저 확인하고, 작업이 끝난 뒤에 세 개가 갖춰졌는지 확인하고, 갖춰지지 않거나 확인이 되지 않으면 릴리즈 빌드 앞에서 멈춘다. 갖춰졌으면 마이그레이션 내용을 보여주고 사람이 승인하고, 마지막에 앱을 지우지 않고 업데이트만 해서 실행해 보는 것이다."로 정리할 수 있다.

이렇게 적용할 수 있는 이유는 2번에서 잡은 동일성이다. 사람이 볼 수 없는 성질이 결과물에 붙어 있고, 확인 장치가 그걸 못 보고, 지나가면 되돌릴 수 없다.

앱인토스가 이 세 조건에서 쓴 방법이 기계가 결과물을 열어 정해진 것을 세고 문 앞에서 멈추는 것이었으니, 조건이 같으면 방법도 그대로 들어온다.

조금 더 디테일하게 내려가보면 전에 설명했던 2-2의 세 층에 그대로 놓인다.

위임 층은 에이전트에게 tables.dart를 맡긴 것 자체다. 앱인토스의 oauth 한 줄에 해당한다. 막는 장치가 아니라 위험이 생기는 자리이고, 권한을 되돌리는 게 답은 아니다.

멈춤 규약은 되돌릴 수 없다는 성질에 대응한다. 코드 수정이나 build_runner 재실행은 되돌릴 수 있으니 그냥 진행하고, schemaVersion을 올리고 마이그레이션을 쓰는 건 되돌리기 어려우니 내용을 보여주고 승인을 받는 것이다. 어느 테이블, 어느 칼럼, 기존 행의 값이 어떻게 되는지를 보여준 뒤 받은 답만 승인으로 보는 로직인 것이다. 그리고 반드시 릴리스 빌드와 스토어 업로드는 사람이 한다. 앱인토스에서 릴리스 노트 전문을 보여주던 자리에 마이그레이션 전문이 들어간 것이다.

하드 차단 부분이 선별한 본체다. 사람이 볼 수 없는 것이라 기계가 본다. 생성 코드에 손댔는지, tables.dart가 생성 코드보다 나중에 수정됐는지, schemaVersion이 올랐는데 마이그레이션이 없는지, 마이그레이션은 있는데 숫자가 그대로인지를 보는것이다.

여기에 앱인토스에는 없는 한 겹을 더 붙였다. 앱인토스에서 진짜 위험한 문은 사람이 누르는 버튼이라 그 앞에 벽을 세울 수 있었다. 내 구독관리 앱에서 진짜 위험한 문은 사용자 폰에서 앱이 켜질 때 저절로 열리는 자동문이다. 그 앞에 설 수가 없으니 문이 열리는 상황을 내가 미리 만들어 보는 수밖에 없다. 그래서 마지막에 앱을 지우지 않고 업데이트만 해서 켜보는 단계가 들어가야 하는 것이다.

4. 하네스를 적용함으로 해결하는 것은?

-> 여기서 먼저 "해결"의 의미부터 잡고 가면, drift의 성질이 바뀌는 건 아니다. 선언과 생성 코드는 계속 갈려 있고 DB 파일은 계속 사용자 기기에 남는다. 바뀌는 건 아무 신호 없이 지나가던 길에 신호가 생긴다는 것이다. 신호가 생기면 고치는 건 어렵지 않다. 어려웠던 건 모른다는 것이었다.

신호가 네 군데에서 난다. 작업을 시작하기 전에 생성 코드에 손댄 흔적이 있으면 멈춘다. 지금 상태를 믿을 수 없다는 뜻이다. 작업하는 동안에는 CLAUDE.md가 매 대화 올라와 있어서 세 개를 함께 하라고 붙잡는다. 이건 틀렸다고 알려주는 게 아니라 애초에 빠뜨리지 않게 하는 쪽이다. 작업이 끝난 뒤에는 기계가 네 가지를 센다. analyze, test, run이 원리적으로 볼 수 없는 것을 여기서 본다. 릴리즈 빌드 전에는 앱을 지우지 않고 업데이트만 해서 켜본다. 기계는 있는지만 보고 맞는지는 못 보니까 이 단계가 필요하다.

빠진 것 중에 진짜 중요한 건 하나다. 생성 코드 수정이나 build_runner 누락이나 숫자 안 올린 것은 다시 돌리면 된다. 마이그레이션 누락만 이미 깨진 사용자 데이터를 복구할 수 없다. 서버 백업이 없으니 그렇다.

없었을 때와 있을 때를 나란히 두면 차이가 분명하다. 없을 때는 작업하고 analyze, test, run이 다 통과하고 출시하고 기존 사용자가 깨지고 원인을 모른다. 그 사이에 아무 신호가 없다. 있을 때는 작업 전, 작업 중, 작업 후, 릴리즈 전 네 지점에서 걸린다. 각자 보는 게 달라서 하나가 놓친 걸 다음이 잡는다.

해결되는 건 빠뜨린 줄 모르는 상태다. 기존 행의 메모를 빈 값으로 둘지 null로 둘지 같은 판단은 그대로 내 몫으로 남는다. 그런데 원래 막혔던 지점이 그게 아니었다. 마이그레이션이 필요하다는 걸 몰랐던 것이 문제였다.

그리고 지금은 아직 출시 전이라 창이 한 번도 열리지 않았다. 사고를 막는 게 아니라 사고가 생길 수 있는 구조를 미리 닫는 쪽이다. 지금은 schemaVersion을 올려보고 마이그레이션을 연습해도 아무 일이 없다. 출시 뒤에는 매번 실전이다.

키워드

ㄴ꼬리질문1 app-in-toss 미니맵을 만드려고 하는게 아니라

이 하네스는 toss 개발자들의 경험과 노하우를 통해 만들어진거잖아 이 하네스를 꼭 app -in-toss 미니앱을 만드는데 사용하는 것이 아닌 나의 내가 앱을 만때도 사용할 수 있을 것 같아

그래서 현재 내가 만들고 있는 구독관리앱에 해당 하네스를 적용할 수 있다면 어떤 부분을 적용할 수 있는지 설명해줘

ㄴ꼬리질문2 오케이 일단 app-in-toss-harness를 현재 내 구독관리 앱에 어떻게 적용할 건지에 대해 알아봤다면

이제 이를 통해 내 구독관리 앱에 적용하면 크게 도움이 되고, 좋은 하네스를 선별해서 리스트업 해주고, 왜 이 부분을 선택하고 선벼랳서 리스트업을 해줬는지에 대한 부분을 나한테 설명해줘

ㄴ꼬리질문3 선별3에 대해서 drift의 작동방식을 연관지어서 drift의 어떤 특수한 작동방식 때문에 하네스를 적용하고, 또 어떤 부분에서 어떻게 적용하는지에 대해 어려운 단어 없이 직관적으로 쉽게 설명해줘

ㄴ꼬리질문4 선별3에서 app-in-toss 하네스를 적용하면 어떻게 해당 문제가 해결이 되는지에 대해서 자세하면서 쉽게 설명해줘

ㄴ꼬리질문5 오케이 이제 내가 선별3에 대해 질문한것들을 정리해보자

내 앱에 하네스를 적용하기 위해서 우선 기존의 선별3에 해당하는 하네스의 원본을 보고

내 구독관리앱에 왜 적용할 수 있는지에 대한 연결점을 찾아서 합당한 논리적인 근거를 정리해주고

근거를 정리했으면 근거에 맞게 내 구독관리앱의 drift의 특징을 통해 기존의 하네스 원본이랑 연결지어서 핵심 구조와 논리는 동일하게 하네스가 어떻게 적용이 되는지를 2-2내용을 적용한다는 내용 또한 엮어서 정리해줘

그 다음으로 하네스를 적용하면 어떤 부분을 해결할 수 있는지를 정리해주면 되

전체적인 흐름이 중요해 우선 내 앱에 해당 하네스를 왜 적용하는지에 대한 근거는 해당 하네스의 원본 내용과 내 구독관리앱의 어떤 연결성 (공통점과 같은 기타 등등의 관계성)을 이끌어내서 적용할 수 있다는 근거를 찾고

근거를 찾았으면 해당 근거에 맞게 어느 부분에 어떻게 하네스를 적용할 수 있는지 설명하는데 이 해당 하네스를 적용할 수 있는 필연성?과 같은 관계로 인해서 사용을 하는데 이 필연성이 나는 drift의 작동 방식과 app-in-toss-harness와의 공통된 뼈대나 구조가 있을 것 같다고 생각해 어떻게 적용되는지에 대한 이해 또한 app-in-toss-harness가 적용되는 방식이랑 일맥상통한 구조가 있을 것 같아 이 부분을 찾아서 끌어내주고 정리해주면 되

그 다음 어디에 어떻게 적용하는지를 알았을 테니 이를 통해 어떤 결과값 또는 문제를 해결할 수 있는지를 정리해주면 되고 흐름을 절대 간과하거나 놓치면 안돼

ㄴ꼬리질문6 우선 각 단계별로 이해를 해보자

우선 선별3에 적용할 app-in-toss-harness를 제대로 이해를 해야 할 것 같아

4단계 중에서 선별3을 에 적용할 원본 하네스를 내가 이해할 수 있도록 쉽고 직관적으로 그리고 어려운 단어 쓰지 않고 쉽게 설명해줘

1단계에서 너가 언급한 나의 구독관리앱 경우와 기존의 경우의 공통된 부분에 대한 하네스를 중점적으로 설명해줘

"예를 들어서 이 하네스는 이러이러한 구조(공통 구조 A,B,C 이렇게 세 부분)로 인해 발생할 문제를 [원본]의 부분에서 이러이러한 부분을 통해 에이전트가 일을 되돌릴 수 없는 부분까지 하지 않도록 막을 수 있게 되는 것이에요"

이런 식으로 정리를 할 수 있도록 체계적으로 설명해줘 내가 원본을 알려고 하는 이유도 [원본] 이 부분 즉, 설명을 위해 알려고 하는거야

ㄴ꼬리질문7 2-2 부분의 하네스를 적용하는거 아니야? 이렇게 보니까 좀 혼란스러워

2-2의 3개의 층을 기준으로 원본을 통해 설명할수 있도록 정리해줘

ㄴ꼬리질문8 1단계 부분에서의 핵심인 원본을 통해 막으려는 대상의 성격과 특징을 전문적이고, 어려운 용어 쓰지 않고, 대상의 성격과 특징을 파악하는데 중요한 핵심 로직과 컨셉을 쉽게 해당 분야의 전문가가 해당 분야의 지식이 전혀 없는 사람에게 쉽게 설명해서 이해할 수 있도록 설명하는 것 처럼

설명해줘

ㄴ꼬리질문9 이 하네스가 정확히 어떤 부분을 위한 하네스인지도 쉽게 설명을 해줘

디버그 번들~~이 ~~랑 달라서 이를 만약 사람이 모르고 출시를 해버리면 ~한 문제가 발생하게 이 문제는 되돌릴수가 없다. 에이전트는 작업의 상한선을 두지 않고 끝까지 해버릴 수 있기 때문에 해당 하네스는 이를 ~~한 방법의 원릴르 통해 이를 해결한다.

이런식으로 내가 정확히 아직 잘 파악이 되지 않아서 완벽하게는 몰라 그러니까 너는 내가 1단계 부분을 이해하고 잘 설명할 수 있도록 답변해줘

ㄴ꼬리질문10 디버그 번들과 릴리스 번들이 서로 다르지만 작동은 똑같기 때문에 잘못하면 되돌릴 수 없는 결과(스키마 변경을 통한 마이그레이션 준비를 하지 않았는데 이를 실행시켜 버림)가 생겨날 수 있는데 이를 방어하기 위한 하네스 인거지?

ㄴ꼬리질문11 그럼 확인장치가 하나도 못 걸러내는거면 어떻게 정상적으로 제대로 출시를 할 수 있는거고

해당 문제가 왜 일어나는지 설명해줘

ㄴ꼬리질문12 오케이 이제 2단계에 대해서 내가 1단계에 대해 질문한 부분을 보면 내가 답변의 방향성과 수준과 컨셉을 어떤식으로 해줘야 하는지 알 수 있을거야 이 흐름과 수준 그대로 2단계에 대해서 자세하게 그리고 쉽고 직관적으로 설명해줘

ㄴ꼬리질문13 오케이 이제 3단계도 마찬가지로 흐름 잃지 않고, 1단계 2단계 답변이랑 동일한 컨셉과 수준 그리고 흐름과 답변 형식로직으로 설명을 해주면 되

어떻게 설명을 해주면 되냐면

"스키마를 바꿀 때 build_runner·schemaVersion·마이그레이션 세 개가 한 세트인데, 하나라도 빠지면 아무 에러 없이 기존 사용자의 DB만 깨져, 그래서 기계가 세 개가 갖춰졌는지 세고, 안 갖춰졌거나 확인이 안 되면 스토어 업로드 앞에서 멈춰요. 갖춰졌으면 마이그레이션 내용을 보여주고 사람이 승인하고, 마지막에 앱을 지우지 않고 업데이트만 해서 실행시켜 보는 것"

내 앱에서 어떻게 하네스를 적용하는지 큰 틀에서 보면 이렇게 정리할 수 있잖아?

내가 큰 틀에서 하네스가어떻게 적용되는지에 대해 정리한 문장에 틀린 부분이 있다면 이 부분을 먼저 수정하고

이 근본 핵심 원리를 포함한 하네스 적용 방향성에 대한 문장을 전체 숲으로 보고

여기서 세부적으로 어떻게 적용이 되는지를 2단계에서의 핵심인 동일한 구조에 하네스를 어떻게 적용하는지에 대한 디테일을 조금 더 추가해서 설명해주면 되

너무 깊게 들어갈 필요 없어

AI 대화 내역 링크:

클로드: https://claude.ai/share/ec12c656-f300-4c70-8d59-492a9f2973e4

오늘 잘한 점: 하네스의 원본 -> 이 하네스를 내 프로젝트에 적용할 수 있는 근거 -> 하하네스를 내 프로젝트에 어떻게 적용할 수 있는가? -> 하네스를 적용함으로써 어떤 부분의 문제를 해결할 수 있는가? 로 흐름으로 세분화해서 생각한 것이 잘한 것 같다.

오늘 부족했던 점: 이 부분 말고 많은 부분에서도 하네스를 적용할 수 있는데, 이 부분이 제일 중요하다고 판단했고 근거도 명확하고 생각해서 이 부분을 중점적으로 깊이 들어갔는데 이 떄문에 다른 부분들을 다루지 못한점이 아쉬운 것 같다.

오늘 총평: 하네스를 구축하고 이를 이해하는 것이 개인적으로 쉽지는 않은 것 같다. 그래도 이해를 하려고 계속해서 노력하고, 질문 어떤식으로 해야 내가 이해를 더 빨리 그리고 잘 할 수 있을지에 대한 생각을 계속해서 하게 되는 것 같고 이는 배우려고 한느 내용이 어려울 수록 더 많이 고려하고 생각하게 되는 것 같다.

0
0

여기에 파일을 드롭하세요