이번 주 hyper는 브라우저 밖으로 나왔다.
지난 몇 주 hyper 대시보드는 그냥 브라우저 탭이었다. 편하긴 한데, 탭은 어쩐지 임시라는 느낌을 지울 수가 없다. 켜야 보이고, 닫으면 사라지고. 그래서 로컬 대시보드를 통째로 감싸는 네이티브 macOS 앱을 tauri v2로 만들었다. 트레이에 아이콘이 상주하고(둥근 사각형에 상태 점 하나 깜빡이는), 로그인하면 자동으로 뜨고, 대시보드에서 설치 파일을 바로 받게 했다. 사실 안쪽은 여전히 같은 웹이고 껍데기 하나 씌운 게 전부다. 근데 트레이에 늘 떠 있으니까 이 도구를 대하는 내 태도가 좀 달라지는 것 같다. 웹을 네이티브로 감싼 건 기능적으론 아무것도 아닌데, 상주한다는 것 하나가 생각보다 크다. 이게 그냥 기분 문제인지는 아직 모르겠다 (지난주에 이름 바꾸고 개운했던 거랑 비슷한 결인가 싶기도 하고).
겸사겸사 봇이 광고 수익을 긁어오는 스킬도 하나 붙였다. admob은 앱별로, adsense는 사이트별로 얼마 벌었는지 한군데서 보여주게. 요즘 자잘한 앱이 늘다 보니(주차 앱들에, 곧 나올 사진 앱까지) 이것들이 실제로 돈이 되긴 하는지 궁금했다. 물론 액수는 민망한 수준이다. 근데 숫자를 눈앞에 두는 거랑 안 두는 건 다르니까. 왜 이걸 지금 굳이 보고 싶어졌는지는 나도 잘 모르겠다.
모바일 쪽은 불을 껐다. 봇 응답이 스트리밍으로 흘러들어올 때 SwiftUI가 뷰 전체를 몇십 번씩 다시 그리면서 버벅였다. 글자 한 조각 들어올 때마다 화면을 통째로 재렌더하고 있었으니 당연히 느렸다. 그걸 잡고, 무한 반복하던 pulse 애니메이션도 symbolEffect로 갈아끼웠다. 새 기능은 아닌데, 안 하면 계속 거슬리는 종류의 일이다. 지난주에 abyss로 남겨뒀던 죽은 코드도 이번에 다 쓸어냈다 (이름 바꾸고 나면 이런 뒷정리가 한참 따라온다).
지난주에 며칠 됐다고 거칠다던 그 사진 앱(denvik, 표시 이름 Loupe)을 이번 주엔 App Store에 올리기로 마음먹었다. 그래서 절반은 이름과 서류 일이었다. 스토어 이름을 'Loupe - AI Photo Search'로 확정하고, 부제·키워드 짜고, Team ID 박고, 암호화 수출 선언에 개인정보방침 초안까지. 화면에 남아 있던 Denvik 흔적도 Loupe로 다 통일했다. 사실 만드는 것보다 이 서류 채우는 게 더 진을 빼는 것 같다.
나머지 절반은 온통 성능이었다. 일단 os_signpost로 인터랙션 지연을 계측하는 것부터 깔고, 그 위에서 눈에 밟히는 버벅임을 하나하나 잡았다. 색인 중 UI가 최대 1초씩 얼어붙던 hang, 상세뷰 들어갈 때 검은 갭, ESC 누르면 EXIF 읽느라 1초 멈추던 것, 그리드 스크롤 프리페치, 상세 지도를 탭할 때만 로드하게 지연 마운트... 검색 자체도 레코드 재정규화를 걷어내서 약 2.8배 빨라졌다. 검색 모델은 MobileCLIP S0에서 S2로 올렸고, 흔들리거나 포커스 나간 사진을 라플라시안 선명도로 찾는 것도 붙였다.
작은 사진 앱 하나에 이렇게까지 성능을 파는 게 맞나 싶은데, 손이 자꾸 간다. 아무도 눈치 못 챌 1초짜리 버벅임인데, 그게 있으면 내가 못 견디는 것 같다. 이게 사용자를 위한 건지 그냥 내 강박인지는 잘 모르겠다. 다만 온디바이스로 자연어 검색이 딱딱 걸릴 때의 손맛은 매끄러워야 완성되는 거라, 결국 다 필요한 일이라고 스스로를 설득하는 중이다 (설득이 되나).
곁다리로 주차 앱도 하나 갈라냈다. 예전에 만든 airport-parking을 포크해서 제주 전용으로 축소한 jeju-parking. AdMob SDK 들어내고, 거짓 만차가 뜨던 버그 잡고, Firebase랑 패키지 새로 붙였다. 템플릿 하나 잘 만들어두면 지역만 갈아끼워 새 앱을 뽑아낼 수 있는지 확인하는 실험에 가깝다. 이게 의미가 있나 싶다가도, 만드는 비용이 거의 안 드니까 일단 던져본다. heg-core엔 이번 주에도 조용히 지식이 쌓였다. 봇들이 알게 된 걸 한군데 모으는 그 저장소인데, 외부 서비스 계정 레지스트리 같은 것도 노트로 정리해 넣었다. 눈에 띄는 변화는 없지만 이런 게 나중에 어디서 힘을 쓸 거라고 믿는 수밖에.
한 줄로 하면, hyper는 껍데기를 얻었고 Loupe는 스토어 문 앞까지 갔다. 다음 주엔 Loupe를 진짜 심사에 넣을 수 있을지 모르겠다. 서류가 제일 무섭다.
26.07.19 — 코드보다 개인정보방침 쓰는 게 더 오래 걸린 주.