장치 제어 앱의 presets 표에 우리가 내장한 프리셋과 사용자가 만든 프리셋이 같이 들어 있었고 이름 앞의 접두어로 구분하고 있었다. 사용자가 이름을 바꿀 수 있다는 것이 이 구분의 전제를 무너뜨렸다.
Table of contents
Open Table of contents
배경 — 이름 규칙이 가르던 소유
BLE 장치에 보낼 설정 묶음을 프리셋이라 부르고 sqflite 로 만든 로컬 표 하나에 둔다. 우리가 넣은 것에는 sys_ 접두어를 붙이고 조회할 때 LIKE 'sys_%' 로 갈랐다. 접두어가 있으면 내장 프리셋이고 없으면 사용자 프리셋이라는 규칙이었다.
이 규칙은 이름이 안 바뀐다는 전제 위에 서 있었다. 그런데 이름은 사용자가 편집 화면에서 언제든 바꿀 수 있는 값이었다.
막힌 지점 — 이름을 바꾸면 구분이 깨진다
사용자가 sys_ 로 시작하는 이름을 지으면 그 프리셋이 내장 것으로 잡힌다. 반대로 내장 프리셋의 이름을 사용자가 바꾸면 사용자 것으로 잡힌다.
두 방향 모두 조용히 어긋나고 어디서도 오류가 나지 않는다. 구분의 근거가 사용자가 바꿀 수 있는 값이면 그 구분은 언젠가 깨진다.
조치 — 값으로 옮긴 뒤의 조건
owner 컬럼을 두고 기존 이름 규칙으로 한 번 채운 뒤부터는 그 값으로 갈랐다. 마이그레이션은 onUpgrade 에서 ALTER TABLE presets ADD COLUMN owner TEXT NOT NULL DEFAULT 'user' 로 넣고 sys_ 행만 system 으로 고쳤다. SQLite 공식 문서는 ADD COLUMN 에 NOT NULL 을 붙이면 NULL 이 아닌 기본값이 있어야 한다고 적는다.
이름을 바꿔도 구분이 유지되므로 이름 규칙 자체를 없앨 수 있었다. 소유에 따라 수정 권한과 삭제 가능 여부와 앱 갱신 시 덮기와 내보내기 대상이 갈린다. 전에는 이름 비교가 코드 여기저기에 흩어져 있었는데 값 하나로 판단하니 조건이 한 자리에 모였다.
원인 — 덮는 범위와 이름 삭제의 위험
내장 프리셋은 앱 판을 올릴 때 지우고 다시 넣는데 전에는 그 삭제를 이름으로 했다. 사용자가 sys_ 로 시작하는 이름을 지었으면 갱신 때 같이 지워진다.
실제로 시험 단계에서 사용자 프리셋 몇 개가 그렇게 사라진 적이 있었다. DELETE FROM presets WHERE owner = 'system' 으로 지우게 바꾸니 남의 것이 딸려 갈 자리가 없어졌다.
해 본 것 — 둘로 안 나뉘는 중간 성격
우리가 준 기본 프리셋을 사용자가 고쳐 쓰는 것이 있었는데 덮으면 고친 내용이 사라진다. 그래서 system 과 user 사이에 user_modified 를 하나 더 두는 쪽을 골랐다. 이유는 고친 순간 소유가 바뀐다는 사실을 값에 그대로 담을 수 있어서다.
사용자가 고치는 순간 유형이 바뀌고 그 뒤로는 덮지 않는다. 대신 새 판의 기본 프리셋을 그 사용자가 자동으로는 못 받는 것을 감수했다. 갱신할 때 건너뛴 것을 목록으로 알려서 새 판을 원하면 개별로 처리하게 했고 같은 문제가 있던 알림 규칙에도 같은 값을 넣었다.
정리
- 이름 규칙으로 소유를 가르면 이름을 바꿀 때 깨진다
- 사용자가 바꿀 수 있는 값을 구분 근거로 삼지 않는다
- 두 방향 모두 오류 없이 조용히 어긋난다
- 값으로 가르면 이름을 자유롭게 쓸 수 있다
- 소유에 따라 무엇이 다른지 표로 적으면 조건이 한 자리에 모인다
- 이름으로 지우면 같은 이름의 남의 것이 지워진다
- 둘로 안 나뉘는 중간 성격은 고친 순간 유형이 바뀌게 한다
- 덮기 전에 건너뛴 것을 알린다