오픈데이 Openday TIL 3
서버를 두지 않기로 한 채로 구글 계정 연결을 붙였고, 기록이 두 기기에 생기면서 합치는 규칙을 새로 정해야 했다. 이어서 못 한 일을 다음 근무일로 넘기는 길을 냈다.
구글 로그인에 서버가 필요하다고 알고 있었는데 흐름이 둘이었다
구글 로그인을 붙이려면 서버가 필요하다고 알고 있었다. 그런데 틀렸다 — 흐름이 두 가지고, 그중 하나는 비밀키를 안 쓴다.
앱이 자기가 만든 데이터를 읽고 쓰는 정도면 브라우저가 직접 받는 쪽으로 충분했다. 서버 없이 갈 수 있느냐 없느냐가 이 앱의 뼈대를 정하는 문제였는데, 「원래 필요하다」는 한 줄에 막혀 있었다.
- 제약이라고 알고 있는 것 중 상당수는 어떤 조건에서만 참이다. 그 조건을 안 보면 안 되는 걸로 남는다
- 뼈대를 정하는 제약일수록 한 번 더 캔다. 거기서 갈리면 나머지 전부가 갈린다
같은 자리에서 하나 더 정했다. 권한은 필요한 것 하나만 고른다. 이 앱은 자기가 만든 파일만 볼 수 있고 이용자의 다른 파일은 목록조차 못 본다.
- 좁게 잡으면 동의 화면 문구가 순해져서 연결하는 사람의 부담이 준다
- 사고가 나도 잃을 게 없다. 권한 범위가 곧 사고 크기의 상한이다
틀린 판단은 지우지 말고 왜 틀렸는지를 남긴다
문서의 그 틀린 줄을 조용히 고칠 수도 있었다. 취소선을 긋고 무엇이 틀렸는지, 대신 어떤 제약이 따라왔는지를 같이 적었다.
틀린 판단은 그 자체로 정보다. 왜 그렇게 생각했는지가 남아 있어야 다음에 같은 갈림길에서 알아본다. 깨끗하게 고친 문서는 읽기 좋지만 아무것도 안 가르쳐 준다.
이용자 드라이브에 맡기면서 복구 기능을 안 갖기로 했다
기록을 이용자 본인 드라이브에 두기로 하면서 한 가지가 확정됐다. 이용자가 자기 손으로 그 파일을 지우면 되살릴 수 없다.
되살려 주려면 우리도 사본을 가져야 하는데, 그 순간 「우리 쪽으로는 아무것도 오지 않습니다」가 거짓이 되고 개인정보 부담이 서버를 두는 것과 같아진다. 둘 다는 안 된다.
여기서 말을 정확히 골라야 한다. 이건 잃은 게 아니라 안 갖기로 한 것이다.
- 드라이브를 붙이기 전에도 복구는 안 됐다. 기록이 브라우저 안에만 있어서 브라우저 데이터를 지우면 그대로 끝이었다
- 붙이고 나서는 오히려 나아졌다. 기기가 죽어도 본인 드라이브에 남는다
- 「우리가 사본을 들고 복구해 준다」는 애초에 가진 적이 없다. 후보에서 뺀 것이지 놓친 게 아니다
이 구별이 중요한 건 나중에 이 판단을 다시 잴 때다. 「잃었다」로 적어 두면 손해를 실제보다 크게 세게 되고, 그러면 「그러니까 서버를 두자」로 기울기 쉽다. 실제로는 아무것도 안 나빠졌고 좋아지는 길 하나를 안 가기로 한 것뿐이다.
대신 안 갖기로 한 만큼 다른 데서 갚았다. 지워지는 일 자체가 잘 안 일어나게 겹을 뒀다.
- 앱 데이터 공간에 두어 이용자의 드라이브 화면에 안 보인다
- 덮어쓰기는 합치기가 막는다
- 파일로 내보내기가 최후 보루다
되돌릴 수단을 안 갖기로 했으면 되돌릴 일을 줄이는 것으로 대신한다. 트레이드오프에서 안 고른 쪽을 그냥 두지 않고, 안 고른 만큼 다른 데서 갚는 것까지가 그 결정이다.
두 기기 기록을 합칠 때 「나중 것이 이긴다」를 어느 단위에 걸까
두 기기가 같은 기록을 만진다. 제일 쉬운 방법은 「나중에 올린 파일이 이긴다」인데, 이러면 회사에서 찍어 올려 둔 하루가 집에서 뭘 고치는 순간 통째로 사라진다. 덮어쓴 쪽은 자기가 뭘 지웠는지도 모른다.
같은 규칙을 파일이 아니라 더 작은 단위에 걸면 문제가 사라진다. 그 단위를 정하는 게 열쇠다.
- 하루 기록의 열쇠는 가게와 날짜를 합친 것
- 업무·가게의 열쇠는 각자의 id
열쇠가 다르면 둘 다 살아남고, 같은 열쇠를 양쪽에서 고쳤을 때만 나중 것이 이긴다. 실제로는 회사에서 회사 가게를, 집에서 개인 가게를 만지므로 부딪히는 일 자체가 드물다.
- 「나중 것이 이긴다」가 나쁜 게 아니라, 그걸 너무 큰 덩어리에 걸면 나빠진다
- 규칙을 고민하기 전에 그 규칙이 걸릴 단위를 먼저 정한다
저장할 때마다 시각을 찍으면 안 건드린 쪽이 이긴다
무엇이 나중인지 판단하려면 고친 시각이 있어야 한다. 여기서 밟기 쉬운 게, 저장할 때 전부 새로 찍는 것이다. 그러면 아무것도 안 건드린 쪽이 「방금 고친 것」이 되어 이겨 버린다.
합친 결과를 저장할 때도 마찬가지다. 그때 시각을 새로 찍으면 방금 진 쪽이 다시 최신이 되고, 다음번 합치기에서 승부가 뒤집힌다.
- 시각은 바뀐 것에만 찍는다. 손대지 않은 것에 찍는 순간 그게 주장이 된다
- 「최근에 저장됨」과 「최근에 바뀜」은 다른 말이다. 이 둘을 같게 두면 승부가 조용히 뒤집힌다
지운 업무가 합칠 때 되살아난다
한쪽에서 지운 것이 다른 쪽에 그대로 남아 있으면, 합칠 때 남아 있는 쪽이 살아서 되살아난다. 지움을 「배열에서 빠진 상태」로 표현하면 합집합 병합에서 아무 힘이 없기 때문이다.
이날은 그걸 알면서도 안 만들었다. 되살아나는 건 한 번도 안 쓴 것뿐이니 피해가 작다고 봤다.
- 판단의 근거가 「피해가 작다」일 때는 그 크기를 실제로 재 봐야 한다. 이건 나중에 뒤집혔다
- 있음과 없음이 대칭이 아닌 자리가 있다. 있는 것은 자기를 주장하고 없는 것은 못 한다
올리기는 내려받기 → 합치기 → 올리기다
순서가 전부다. 그냥 올리면 저쪽이 올려 둔 것이 지워진다. 「저장한다」가 실제로는 세 걸음이라는 걸 이름이 감춘다.
언제 도는지도 정했다. 손이 멈춘 뒤 3초, 다만 셔터를 내릴 때는 기다리지 않고 바로. 전부 미루거나 전부 즉시가 아니라 무엇이 중요한지로 갈랐다.
덮어쓰는 버튼을 확인 창으로 감싸는 대신 없앴다
연결 직후에 쓰라고 「드라이브에 올리기」와 「드라이브에서 가져오기」를 나란히 뒀는데, 올리기가 합치지 않고 덮어쓰는 동작이었다. 다른 기기에서 올려 둔 것이 그 순간 사라진다. 우리가 막으려던 바로 그 사고를 버튼 하나가 일으키는 꼴이었다.
확인 창을 붙이는 길도 있었다. 두 버튼을 걷어내고 「지금 맞추기」 하나로 합쳤다.
- 확인 창은 사고를 막는 게 아니라 사고 직전에 한 번 더 묻는다. 사람은 익숙해지면 읽지 않고 누른다
- 안전한 동작 하나만 남기면 물어볼 것도 없다. 고를 수 없는 것이 제일 안전하다
- 한쪽 방향만 필요한 일은 따로 두되(파일 내보내기·되살리기) 그건 사고 나도 남의 기록을 안 지운다
넘긴 날이 공휴일이면 그 일이 눈에서 사라진다
못 한 일을 다음 근무일로 넘기게 만들고 나서 따져 봤다. 수요일에 목요일로 넘겼는데 목요일이 공휴일이면?
목요일에 아무도 앱을 안 여니 그 기록은 그대로 남고, 금요일 보드는 금요일 기록만 보므로 그 업무가 안 뜬다. 데이터는 남아 있는데 눈에는 안 보인다 — 실질적으로 사라진 것이다.
풀 길이 둘이었다.
- 공휴일 달력을 들여와서 애초에 금요일로 넘긴다
- 못 맞혀도 살아남게 만든다 — 「넘어왔는데 하지도, 다시 넘기지도 않은 것」을 다음에 여는 날이 데려온다
뒤쪽으로 갔다. 앞쪽은 목요일만 푼다. 갑자기 아파서 쉰 날, 출장 간 날, 그냥 안 연 날은 여전히 못 잡는다.
- 바깥 사정을 데이터로 들여오는 방식은 들여온 만큼만 맞는다. 안 들여온 사정은 그대로 구멍이다
- 「못 맞히면 어떻게 되나」를 견디게 만들어 두면 맞히는 일 자체가 덜 급해진다. 실제로 보류해 둔 공휴일 처리가 이걸 넣고 나서 급하지 않아졌다
- 정확도를 올리는 것과 틀렸을 때를 버티는 것 중, 대개 뒤쪽이 싸고 오래간다
데려온 뒤 자국을 안 남기면 매번 다시 데려온다
여기에 함정이 있었다. 금요일에 데려오기만 하면 목요일 기록은 여전히 「넘어왔는데 안 한 것」인 채로 남는다. 다음 주 월요일에 또 훑으면 그게 또 걸린다. 이미 처리했는데도.
데려온 뒤 멈춰 있던 그 날에 매듭을 짓게 했다.
- 찾는 쪽만 만들고 「찾았다는 사실을 적는다」를 빼먹으면 같은 것을 영원히 다시 찾는다
- 무언가를 훑어서 처리하는 구조를 만들 때는 처리했다는 자국을 어디에 남길지가 같은 크기의 문제다
다른 기기에서 넘긴 일은 한 박자 늦게 따라온다
앱을 열면 두 가지가 일어난다. 멈춰 있는 이월이 있는지 훑는 것과, 드라이브에서 내려받아 합치는 것. 훑기가 먼저 돈다.
회사에서 넘기고 집에서 여는 경우를 따라가면 이렇게 된다.
집에서 앱을 연다
1. 이월 훑기 ← 이 시점의 로컬에는 회사에서 넘긴 기록이 아직 없다
2. 드라이브와 합치기 ← 여기서 들어온다. 그런데 훑기는 이미 끝났다
집에서 앱을 다시 연다
1. 이월 훑기 ← 이제 로컬에 있으니 잡아서 오늘로 데려온다
그러니까 그 일은 앱을 한 번 더 열어야 보드에 올라온다. 순서를 뒤집어 고칠 수도 있었는데 안 했다.
- 다음에 열면 반드시 잡히므로 사라지지는 않는다. 늦는 것과 사라지는 것은 무게가 다르다
- 결함을 고칠지 말지는 「불편한가」가 아니라 「무엇을 잃는가」로 잰다. 늦는 것은 기다리면 되고 사라지는 것은 안 돌아온다
- 대신 남겨 두기로 한 한계는 반드시 적는다. 안 적으면 다음에 보는 사람이 버그로 알고 순서를 뒤집다가 다른 걸 깨뜨린다
매월 5일 업무가 24일 기록실에 미완료로 떴다
그날 할 일이 아닌데도 그렇게 세고 있었다.
원인은 세는 기준이었다. 기록실이 「그날 기록에 남아 있는 자리」를 그대로 미완료로 세고 있었다. 그런데 그 자리는 배치와 상관없이 생긴다 — 업무를 만든 순간, 일정을 바꾼 순간에 빈 자리가 하나 놓인다.
미완료는 두 번째 질문에 속한다. 그래서 세는 기준을 기록에 남은 자리가 아니라 「그날 배치」 — 그 날짜에 일정 규칙을 돌려 나온 목록 — 으로 바꿨다. 매월 5일 업무는 24일에 그 목록에 안 들어가므로 셀 것 자체가 없어진다.
- 세는 코드를 볼 때 「무엇을 세나」보다 「그 수가 어느 질문의 답인가」를 먼저 본다
- 두 질문의 답이 대개 같으면 틀린 걸 오래 모른다. 이건 몇 달이 지나 어긋난 날이 오고서야 보였다
도장 없는 빈 자리까지 붙잡고 있었다
빈 자리가 계속 따라다닌 데는 이유가 있었다. 「배치에서 빠졌지만 기록이 남은 업무는 버리지 않고 붙인다」는 규칙이 있었다.
의도는 좋았다. 창고에서 업무를 지워도 어제 찍은 도장은 남아야 한다. 그런데 도장이 하나도 없는 자리까지 같이 붙잡고 있었다.
- 「혹시 모르니 남겨두자」는 남길 값어치가 있는 것과 없는 것을 가르고 나서 해야 한다
- 여기서 경계는 명확했다. 도장이나 메모가 있으면 그날의 진짜 기록이고, 아무것도 없으면 그냥 빈칸이다. 경계를 안 그으면 남길 값어치가 없는 것까지 쌓인다
달력에 기본 날짜를 채워 뒀더니 그 날짜만 안 골라졌다
넘기기 버튼을 누르면 달력이 다음 근무일에 미리 맞춰진 채로 열리게 했다. 친절해 보였다.
그 친절이 정확히 그 날짜를 고르는 길을 막았다. 이미 그 값이 골라져 있으니 같은 날을 다시 눌러도 값이 안 바뀌고, 값이 안 바뀌면 브라우저는 「바뀌었다」 신호를 안 준다. 하필 기본값과 같은 날 — 대개 고르고 싶은 바로 그 날 — 만 조용히 안 먹었다.
- 「값이 바뀌었다」와 「사용자가 골랐다」는 다른 사건이다. 이 둘을 같게 여기면 이미 그 값인 경우에만 안 먹는 자리가 생긴다
- 미리 채워 주는 편의는 「그 값을 고르는 일」과 부딪힐 수 있다. 둘 중에는 누른 대로 되는 쪽이 먼저다
오류도 경고도 없이 그냥 안 되는 버그를 좁히는 법
오류가 나면 최소한 어디를 볼지는 알려준다. 이건 오류도 경고도 없었고 그냥 아무 일도 안 일어났다.
단서는 「다른 날짜는 되는데 내일 날짜만 안 된다」였다. 되는 경우와 안 되는 경우의 차이가 원인을 가리킨다. 안 되는 것만 붙들고 보면 그 차이가 안 보인다.
근무 요일을 관리·창고·기록실 중 어디에 둘까
근무 요일을 어디서 정하게 할지 골라야 했다. 기준이 둘이었다.
첫째, 이 값이 하나뿐인가 저마다 다른가. 근무 요일은 가게마다 다르다. 회사는 월~금이지만 개인 가게는 매일일 수 있다. 앱 전체 설정 화면에 두면 가게별로 못 정한다 — 이 한 줄로 후보 하나가 떨어졌다.
둘째, 그 방이 무엇을 하는 곳인가. 창고는 「이 가게가 무슨 일을 언제 하는가」를 정하는 방이고 기록실은 지나간 것을 보는 방이다. 근무 요일은 첫 번째 질문에 속한다.
- 자리가 남았다는 건 넣을 이유가 아니다. 넣을 때마다 그 방이 무엇을 하는 곳인지가 흐려진다
- 요일별 업무를 만드는 자리 바로 위에 근무일이 있으면, 근무일이 아닌 요일에 업무를 배치해 둔 것이 눈에 보인다. 자리를 잘 고르면 설명이 필요 없어진다
처음 여는 사람에게 남의 업무 목록이 보였다
처음 열었을 때 보이는 기본 업무가 특정한 한 사람의 상황에 맞춘 예시였다. 남이 열면 자기 일이 아니라서 지우는 것부터 해야 한다. 첫 화면이 할 일을 주는 게 아니라 숙제를 주는 셈이다.
기본 업무를 사용법 안내로 바꿨다. 눌러 보면 익혀지고, 자기 업무를 만들기 시작하면 자연스럽게 밀려난다.
- 지워야 할 것을 주는 대신 해 볼 것을 준다
- 기본값이 남의 상황이면 첫인상이 「정리부터 하세요」가 된다
사용법 안내 다섯 개의 순서를 정한 기준
안내 업무 중 「오른쪽 클릭으로 되돌리기(완료도, 건수도)」를 세 번째에 뒀다. 완료 도장과 건수 도장을 다 본 뒤라야 그 괄호 안이 무슨 말인지 안다. 두 번째에 뒀으면 건수 도장은 아직 본 적이 없는 것이 된다.
무엇을 알려 줄지 다 정하고 나면 끝난 것 같은데, 그 목록을 어떤 순서로 세우느냐가 남아 있다.
만드는 동안에는 안 되는 길이 안 보인다
이월을 만들 때 머릿속 그림은 하나였다. 수요일에 넘기면 목요일에 뜬다. 그 길은 잘 됐다.
「목요일이 공휴일이면?」은 만들고 나서 따로 시간을 내어 따져 봤을 때 나왔다. 만드는 동안에는 안 보인다.
- 잘 되는 길을 좇는 것과 안 되는 길을 찾는 것은 다른 일이다. 그래서 다른 시간에 해야 한다
- 만든 직후는 제일 안 보이는 때다. 그때의 「다 된 것 같다」를 믿으면 안 된다
같은 결로 하나 더. 기능을 만들 때는 「무엇을 할 수 있게 할까」만 보게 되는데, 「무엇은 하지 않아도 되나」를 같이 정해야 목록이 짧아진다. 넘기기 대상에서 상시 업무를 뺀 게 그 예다 — 매일 뜨는 일을 「내일로 넘긴다」는 말이 성립하지 않고, 목록에 매일 끼면 정작 골라야 할 것이 안 보인다.
그밖에 정한 것들
- 자동으로 할지 고르게 할지는 한쪽을 끌 수 있게 두고, 기본은 물어보는 쪽으로 했다. 물어보는 것이 안 물어보는 것보다 되돌리기 쉽다
- 라이브 브랜치를 나눴다. 배포가 한 단계 는 게 아니라 배포하지 않을 자유가 생긴 것이다
- 데이터 모양을 바꿀 때 옛 것을 살릴지 버릴지는 코드를 보고 정하는 게 아니라 그게 이미 남의 기기에 나갔는지를 보고 정한다
- 누를 수 있다는 걸 알려 주는 건 기능이 아니라 생김새다. 글자 링크는 「덜 중요한 것」이라는 뜻으로 읽히므로, 있어야 할 것에 쓰면 없는 것이 된다
- 켜짐을 색으로만 구분하면 옆에 비교 대상이 없을 때 안 읽힌다. 형태를 하나 더 얹으면 하나만 있어도 읽힌다