이 글은 Today I Learn 시리즈의 88번째 기록입니다. (총 125개)

단계를 만드는 창이 쓰기 불편해서 갈아엎었고, 창 전체도 시안을 먼저 보고 고른 다음 다시 짰다. 화면을 그리는 일보다 무엇을 합치고 무엇을 접고 무엇을 눈에 보이게 둘 것인가가 계속 걸렸다. 다음에 화면을 다시 짤 때 꺼내 쓸 것만 남긴다.


선택지 일곱 개가 한 줄에 늘어서 있었다

단계 종류를 고르는 라디오 버튼(하나만 골라지는 동그란 선택지)이 클릭·이동·드래그·스크롤·키·텍스트·대기까지 일곱 개, 한 줄에 늘어서 있었다. 더 걸린 건 따로 있었다. 좌표를 찍어 둔 뒤에 동작을 바꾸면 그 좌표가 사라졌다.

그래서 마우스·키보드·대기 세 묶음(탭)으로 나누고, 좌표를 쓰는 동작끼리는 같은 입력칸을 함께 쓰게 합치라고 했다. 고르는 자리는 나누고 찍어 둔 값은 합친 셈이다.

합치고 나니 “지금 무슨 종류인가”를 어디에 둘지가 남았다. 그 값을 따로 기억해 두지 않고, 어느 탭이 열려 있고 그 안에서 무엇이 골라져 있는지를 합쳐 그때그때 계산하게 했다.

  • 같은 사실을 화면과 기억 두 군데에 두면 언젠가 어긋난다. 한쪽에서 끌어내면 어긋날 수가 없다.
  • 나누는 것과 합치는 것은 반대로 보이지만 목적이 같았다. 고르는 자리는 나눠야 찾기 쉽고, 찍어 둔 값은 합쳐야 잃지 않는다.

키 이름만 외워서 타이핑하는 자리가 남아 있었다

나머지는 전부 화면에서 고르거나 찍어서 넣는데, 키 입력 단계 하나만 키 이름을 외워 타이핑해야 했다. 실제로 키를 누르면 그대로 채워지게 할 수 있냐고 물었더니 된다고 해서 넣었다.

만들고 나니 “다 눌렀다”를 무엇으로 아는지가 문제였다. Ctrl이나 Shift 같은 조합키는 혼자서는 끝이 아니라서, 조합키가 아닌 키가 눌리는 순간을 끝으로 잡았다.

그래서 Ctrl+Alt+Shift처럼 조합키만으로 된 단축키는 이 방식으로 잡히지 않는다. 끝나는 순간이 아예 없기 때문이다. 우회를 만드는 대신 한계로 받아들이고 그런 건 직접 적게 뒀다.

  • 입력을 받는 기능에서는 “언제 끝났다고 볼 것인가”를 정하는 게 곧 설계다. 그 정의가 그대로 그 기능의 한계선이 된다.
  • 한계가 정의에서 나온 것이면 우회로 덮지 않는 편이 낫다. 덮으면 끝나는 조건이 두 개가 되고, 어느 쪽으로 도는지 쓰는 사람이 알 수 없어진다.

색 띠는 굳이 없어도 됐다

목록 줄마다 종류별 색 띠를 세우려 했는데, 쓰고 있는 표 위젯(줄마다 칸이 나뉜 목록 부품)은 줄 단위로 글자색·배경색을 바꾸는 데까지만 되고 줄 앞에 색 막대를 세우는 건 안 됐다. 하려면 줄마다 작은 그림을 만들어 붙여야 했다.

화면을 보니 색 띠가 없어도 구분이 됐다. 대기 줄은 흐리게, 꺼둔 줄은 더 흐리게, 실행 중인 줄만 강조색이면 충분했다. 그래서 색 띠는 안 하기로 했다.

  • 할 수 있는 선을 먼저 재고, 그 안에서 목적을 이룰 다른 길이 있는지 본다. 목적은 “종류가 구분된다”였지 “색 띠가 있다”가 아니었다.
  • 못 하는 걸 우회하느라 무게를 늘리는 것보다 요구를 줄이는 쪽이 나을 때가 있다.

어제 고른 값 때문에 오늘 엉뚱한 데서 시작한다

재생을 처음부터 할지 선택한 단계부터 할지 고를 수 있어야 한다고 했다. 고른 값은 다음에도 그대로 쓰이게 기억시켰는데, 기억만 하고 보여 주지 않으면 어제 고른 값 때문에 오늘 엉뚱한 데서 시작한다. 마우스를 실제로 움직이는 도구에서 그건 사고다. 그래서 기억한 값을 버튼 글자에 그대로 띄웠다.

  • 편의를 위해 기억하는 값은 눈에 보여야 안전하다. 안 보이는 기억은 편의가 아니라 함정이다.
  • 반대로 잠가야 하는 것도 있었다. 재생이 도는 동안에는 편집 버튼과 설정 입력을 한꺼번에 잠갔다. 도는 도중에 값이 바뀌면 화면이 말하는 것과 실제로 도는 것이 어긋난다.

녹화는 받아 적는 일이 아니라 판정하는 일이었다

녹화를 붙이고 보니 조작을 그대로 옮겨 적는 일이 아니었다. 누르고 뗀 자리가 얼마 이상 벌어지면 클릭이 아니라 끌기로, 짧은 간격의 연속 클릭은 더블클릭 하나로, 일정 시간 이상 비면 대기 단계로 바꾼다. 어디까지가 클릭이고 어디부터가 끌기인지는 결국 사람이 정해 준 숫자다.

그 숫자는 전부 임의로 정한 값이라 언제든 어긋난다.

  • 판정 기준이 임의값이면 완벽하게 맞추려 들 게 아니라, 틀렸을 때 사람이 고칠 수 있게 두는 편이 낫다. 녹화 결과를 목록에서 그대로 고칠 수 있게 해 두니 판정이 조금 틀려도 문제가 되지 않았다.

Series: Today I Learn

1 C++ 자료형(Data Type) 2 MD5 vs pHash 3 C++에서 함수의 선언과 정의 4 Tkinter padx, pady 5 메모리와 포인터 변수 6 Call by Value, Call by Reference, Call by Pointer 비교 7 const 8 Gemfile — Jekyll 프로젝트의 의존성 파일 9 kramdown-parser-gfm — Jekyll의 GFM 파서 10 파서(Parser) 11 AHU vs OHU 12 I might try it vs I'll try it 뉘앙스 차이 13 SESSION_EXPIRE_AT_BROWSER_CLOSE=True 14 configuration key 15 Git stash vs discard 16 subprocess.Popen으로 Windows 탐색기에 명령어를 전달 17 Post 잔디 분석하기 18 Google Sheets Sync 최적화 19 DSL (Domain Specific Language)과 GPL (General Purpose Language) 20 마크다운 표 그리는 방법 21 쿼리 파라미터(Query Parameter). 기존 QR코드 재활용 22 Django 보안 취약점 점검 및 수정 23 OOP Object-Oriented Programming 객체 지향 프로그래밍 24 Fernet 대칭 암호화 25 Jekyll 코드블록 안의 Liquid 태그 26 insertOnConflictUpdate vs DoUpdate(target) 27 세션 필터 28 아코디언(Accordiaon) UI를 펼친상태로 만들기 29 input의 step 30 Word Cloud 31 Google Sheets를 데이터 버스로(with AppSheet) 32 Django 모델 텍스트 필드 자동 수집 패턴 33 localStorage로 섹션 토글 상태 유지 34 순차 ID 생성(`select_for_update()` + `max()` 조합) 35 역참조 검색과 distinct() 36 xlsx 다운로드와 로딩 오버레이 충돌 37 Android 파일 공유 MIME 타입 38 AssetManifest — Flutter 빌드 타임 asset 목록 런타임 조회 39 UTF-8 BOM과 PowerShell 파일 쓰기 40 소리꽃 KeyBloom TIL 1 41 소리꽃 KeyBloom TIL 2 42 소리꽃 KeyBloom TIL 3 43 메트로놈 Simple Metronome TIL 1 44 소리꽃 KeyBloom TIL 4 45 메트로놈 Simple Metronome TIL 2 46 소리꽃 KeyBloom TIL 5 47 메트로놈 Simple Metronome TIL 3 48 정적 블로그 SEO 정비와 Pagefind 검색 도입 49 메트로놈 Simple Metronome TIL 4 50 안드로이드 AudioTrack 연속 재생, 실측 피커 정렬, 카메라 토치 플래시 51 메트로놈 Simple Metronome TIL 5 52 모래게임 Sandrop TIL 1 53 메트로놈 Simple Metronome TIL 6 54 모래게임 Sandrop TIL 2 55 모래게임 Sandrop TIL 3 56 메트로놈 Simple Metronome TIL 7 57 모래게임 Sandrop TIL 4 58 모래게임 Sandrop TIL 5 59 모래게임 Sandrop TIL 6 60 소리꽃 KeyBloom TIL 6 61 모래게임 Sandrop TIL 7 62 모래게임 Sandrop TIL 8 63 소리꽃 KeyBloom TIL 7 64 모래게임 Sandrop TIL 9 65 소리꽃 KeyBloom TIL 8 66 모래게임 Sandrop TIL 10 67 소리꽃 KeyBloom TIL 9 68 소리꽃 KeyBloom TIL 10 69 소리꽃 KeyBloom TIL 11 70 소리꽃 KeyBloom TIL 12 71 소리꽃 KeyBloom TIL 13 72 온실 GreenHouse TIL 1 73 소리꽃 KeyBloom TIL 14 74 온실 GreenHouse TIL 2 75 소리꽃 KeyBloom TIL 15 76 소리꽃 KeyBloom TIL 16 77 소리꽃 KeyBloom TIL 17 78 소리꽃 KeyBloom TIL 18 79 소리꽃 KeyBloom TIL 19 80 소리꽃 KeyBloom TIL 20 81 로그스톤 상표 셀프 출원 TIL 1 82 소리꽃 KeyBloom TIL 21 83 소리꽃 KeyBloom TIL 22 84 소리꽃 KeyBloom TIL 23 85 소리꽃 KeyBloom TIL 24 86 MiniMacro TIL 1 87 Astro가 무엇인지, 왜 옮기는지 88 MiniMacro TIL 2 읽는 중 89 메트로놈 Simple Metronome TIL 8 90 메트로놈 Simple Metronome TIL 9 91 블로그 Astro 이관 TIL 92 오픈데이 Openday TIL 1 93 오픈데이 Openday TIL 2 94 Unreal Engine MCP TIL 1 95 콘티온 Conti On TIL 11 96 오픈데이 Openday TIL 3 97 오픈데이 Openday TIL 4 98 오픈데이 Openday TIL 5 99 ScorePlayer TIL 1 100 BuildingHub TIL 1 101 ScorePlayer TIL 2 102 BuildingHub TIL 2 103 ScorePlayer TIL 3 104 Unreal Engine MCP TIL 2 105 궁 미로 PalaceMaze TIL 1 106 메트로놈 Simple Metronome TIL 10 107 메트로놈 Simple Metronome TIL 11 108 오픈데이 Openday TIL 6 109 BuildingHub TIL 3 110 Obsidian vault에서 코드만 빼기 — directory junction 111 ScorePlayer TIL 4 112 오픈데이 Openday TIL 7 113 URL은 바뀔 수 있는 것에 묶지 않는다 114 도구는 기능이 아니라 내 일에 맞는지로 고른다 115 돌이키기 힘든 변경은 작게 먼저 확인한다 116 궁 미로 PalaceMaze TIL 3 117 궁 미로 PalaceMaze TIL 2 118 소리꽃 KeyBloom TIL 29 119 오픈데이 Openday TIL 8 120 BuildingHub TIL 4 121 ScorePlayer TIL 5 122 BuildingHub TIL 5 123 MiniMacro TIL 3 124 소리꽃 KeyBloom TIL 30 125 궁 미로 PalaceMaze TIL 4