BuildingHub TIL 2
관리자 화면을 다듬은 날의 판단들이다. 셋으로 묶인다. 나중에 답할 수 있게 남기는 문제, 통과 신호를 어디까지 믿는가, 그리고 완성도가 갈리는 자리.
나중에 답할 수 있게 남기기
의무가 없는 것과 안 남겨도 되는 것은 다르다
시드 이미지는 전부 저작권이 완전히 풀린 것만 골랐다. 그런 사진은 출처를 화면에 적을 의무가 없다. 그래서 라이선스만 확인하고 파일만 챙겼다.
그런데 “이 이미지 어디서 가져왔냐”는 질문에 저장소만 봐서는 답할 수 없는 상태가 됐다.
의무와 추적은 다른 이야기다. 의무는 “화면에 적어야 하는가”이고, 추적은 “물어보면 댈 수 있는가”다. 앞엣것이 없다고 뒤엣것까지 필요 없다고 넘긴 게 잘못된 추론이었다. 저작권 문제를 피하는 게 전제인 프로젝트에서 출처를 못 대면, 공들여 피한 것 자체가 증명이 안 된다. 남에게 보여줄 물건이면 더 그렇다.
이번엔 임시 폴더에 원본이 남아 있어서 21장을 전부 되찾았다. 그런데 그 폴더가 지워졌으면 복구가 불가능했다. 사후에 복구된 건 운이고, 규칙으로 삼을 건 하나뿐이다. 나중에 누가 물어볼 수 있는 정보는 받는 자리에서 함께 적는다.
되찾은 김에 장치를 하나 걸었다. 데모 데이터를 처음 상태로 되돌리는 시드 스크립트(npm run db:seed)가 있는데, 출처가 빈 이미지가 하나라도 있으면 거기서 멈추고 실행이 안 된다. 기록을 사람 습관에 맡기지 않고 절차가 강제하게 만든 것이다. 앞 글의 “규율로 막을 것과 구조로 막을 것”과 같은 판단이다.
자동 검사는 스스로 흔적을 남긴다
관리자의 문의 화면에 같은 이름의 문의가 열세 건 쌓여 있었다. 검사 스크립트가 문의 넣기를 실제로 해 보고 지우지 않은 것들이다.
시드 스크립트는 “이 표들을 비운다”는 DELETE 목록을 들고 도는데, 그 목록에 문의 표(inquiries)만 빠져 있었다. 검사를 돌릴 때마다 한 건씩 늘어난 게 그대로 남았다.
검사는 데이터를 읽기만 하지 않는다. 실제로 예약을 만들고 문의를 넣는다. 그러니 검사를 늘리는 결정에는 “그 검사가 남긴 것을 누가 치우는가”가 딸려 온다.
그리고 손으로 관리하는 목록은 언젠가 샌다. 표가 하나 늘 때 비우는 목록도 같이 늘려야 한다는 규칙은, 지켜지는 동안만 유효하고 안 지켜졌을 때 알려 주지 않는다. 그래서 실제 표 목록과 비우는 목록을 대조해 빠진 게 있으면 스크립트가 멈추게 했다. 사람 기억에 기대는 목록은 대조할 상대를 옆에 둔다.
빈 화면은 기능이 없는 것으로 읽힌다
문의 데이터를 지우고 나니 문의 관리 화면이 텅 비었다. 그런데 빈 화면은 “아직 문의가 없구나”로 안 읽히고 “이 기능은 안 만들었구나”로 읽힌다.
제안용 물건에서 이건 실제 손해다. 만든 걸 못 보여주는 것과 안 만든 것이 화면에서 구별되지 않는다. 답변 전후를 섞은 문의 다섯 건을 기본 데이터로 넣었다.
기준으로 남기면, 보여줄 목적이 있는 화면은 비어 있으면 안 된다. 빈 상태는 실제 운영에서나 정상이지 데모에서는 결함이다.
통과 신호를 어디까지 믿나
“확인할 게 없었다”가 “확인했고 맞았다”로 읽힌다
예약 목록에서 “취소” 상태만 걸러 내는 기능이 있다. 그게 잘 도는지 보려고 “걸러진 목록의 모든 줄이 취소 상태인가”를 묻는 검사를 넣었고, 늘 통과했다. 그런데 걸러진 목록이 0건이었다.
빈 목록에서 “모든 줄이 그렇다”는 자동으로 참이 된다. 어길 줄이 하나도 없기 때문이다. 그러니 이 검사는 필터가 잘 돈다는 걸 한 번도 확인한 적이 없으면서 계속 통과 신호를 보내고 있었다.
앞 글에서 「“문제 없었습니다”만 오는 보고는 아직 아무 말도 안 한 보고다」라고 적었는데, 같은 함정이 검사 코드 안쪽에도 있었다. 요약 줄을 밖에서 확인하는 것만으로는 부족하고, 검사 하나하나가 몇 건을 보고 그렇게 말하는지를 함께 찍게 만들어야 한다.
이 결은 코드 밖에서도 통한다. “문제 없었습니다”라는 보고는 문제를 찾아봤다는 뜻일 수도, 찾을 것이 없었다는 뜻일 수도 있다. 둘은 같은 문장으로 온다.
검사는 숫자가 아니라 의도를 재야 오래 산다
목록 접기가 실제로 공간을 아끼는지 보려고 “접힌 줄이 64px 미만”이라는 검사를 넣었다. 썸네일을 넣자 딱 64px이 되어 검사가 실패했다. 기능은 의도대로 동작하고 있었다.
재려던 건 “접기가 공간을 아끼는가”인데 특정 숫자로 바꿔 적었다. 숫자는 여백을 조금만 손봐도 흔들린다. “접은 것이 펼친 것보다 확실히 짧은가”로 바꾸니 디자인을 손봐도 안 깨진다.
여기서 진짜 위험은 검사가 깨지는 것 자체가 아니다. 멀쩡한 변경 때마다 우는 검사는 사람이 결국 끄거나 무시한다. 그러면 진짜로 깨졌을 때도 안 본다. 검사가 얼마나 오래 쓸모 있느냐는 얼마나 정확한가보다 헛되이 우는 일이 얼마나 드문가로 정해진다.
돌리는 시점에 따라 결과가 달라지면 검사가 아니다
브라우저 검사가 실패했는데 앱은 멀쩡했다. 회의실은 평일만 운영해서 토요일에는 모든 시간대가 비활성이었다.
앞서 “두 번 돌리면 실패하는 검사”를 고쳤는데 이건 다른 축이다. 그때는 이전 실행이 남긴 상태가 문제였고, 이번엔 실행 시점이 문제다. 검사가 기대야 할 것은 “지금이 언제인가”가 아니라 “무엇을 확인하려는가”다.
완성도가 갈리는 자리
기본 팝업은 제품처럼 보이지 않는다
예약 반려 사유를 브라우저 기본 입력창으로 받고 있었다. 주소창 아래 붙어 나오는 회색 상자다.
이게 두 가지를 망친다. 하나는 인상이다. 기본 대화상자는 제품 화면이 아니라 스크립트가 끼어든 것처럼 보인다. 제안용 물건에서 “덜 만든 티”는 기능 목록이 아니라 이런 데서 난다. 다른 하나는 기능이다. 한 줄만 받으니 반려 사유를 제대로 적을 수가 없다.
인상 때문에 고치자니 사치 같고 기능 때문에 고치자니 사소해 보이는데, 둘이 같은 원인에서 나온다. 급하게 붙인 임시 조치는 보기에도 임시고 쓰기에도 임시다. 이런 항목은 둘 중 하나만 놓고 보면 늘 우선순위에서 밀린다.
흔한 이름은 언젠가 부딪힌다
접힌 줄의 썸네일 자리가 38px이어야 하는데 98px이었다. 사진이 없는 자리에 empty라는 이름을 붙였는데, 사이트 전역에 “등록된 항목이 없습니다” 안내문용으로 쓰는 empty가 이미 있었다. 그쪽에 걸린 위아래 여백 96px이 이 작은 칸에 그대로 먹었다.
이름 짓기 규칙은 취향 문제로 보이지만 실제로는 사고 예방이다. 그리고 이런 충돌은 에러를 안 낸다. 화면에서는 “좀 크네” 정도로 보여서, 재 보기 전까지는 그냥 넘어간다. 앞 글의 홈 카드가 세로로 쌓인 일과 같은 종류다.
좁은 화면에서 열 많은 표는 줄이지 말고 밀어서 본다
관리자 표를 휴대폰 폭으로 보니 “회의실”이 세 글자로 쪼개져 세로로 접혔다. 공개 사이트 표는 멀쩡했는데, 그쪽은 열이 적어서다.
좁은 화면 대응을 “다 보이게 줄이는 것”으로 잡으면 열이 많은 표에서 무너진다. 최소 폭을 지키고 가로로 밀어 보게 하는 편이 낫다. 반응형은 모든 걸 한 화면에 넣는 게 아니라, 무엇을 포기할지 정하는 일이다.
요약
- 의무는 “적어야 하는가”이고 추적은 “물어보면 댈 수 있는가”다. 앞이 없다고 뒤까지 필요 없는 게 아니다
- 나중에 누가 물어볼 수 있는 정보는 받는 자리에서 적는다. 사후 복구가 됐다면 그건 운이다
- 기록을 사람 습관에 맡기지 말고 절차가 강제하게 만든다
- 검사는 데이터를 만든다. 검사를 늘리는 결정에는 그 흔적을 누가 치우는가가 딸려 온다
- 사람 기억에 기대는 목록은 대조할 원본을 옆에 둔다
- 보여줄 목적이 있는 화면은 비어 있으면 안 된다. 빈 상태는 운영에서나 정상이고 데모에서는 결함이다
- “문제 없었습니다”는 찾아봤다는 뜻일 수도, 찾을 것이 없었다는 뜻일 수도 있다. 둘은 같은 문장으로 온다
- 검사가 오래 쓸모 있으려면 정확한 것보다 헛되이 우는 일이 드물어야 한다. 멀쩡한 변경마다 우는 검사는 결국 무시된다
- 돌리는 시점에 따라 결과가 달라지면 검사가 아니다
- 급하게 붙인 임시 조치는 보기에도 임시고 쓰기에도 임시다. 인상과 기능 중 하나만 놓고 보면 늘 우선순위에서 밀린다
- 이름 충돌은 에러를 안 내고 “좀 이상하네” 정도로 보인다. 재야 잡힌다
- 반응형은 모든 걸 한 화면에 넣는 게 아니라 무엇을 포기할지 정하는 일이다