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

착수 전에 기획만 정리한 날인데, 정한 것 셋이 전부 같은 모양이었다. “지금 하나뿐인 것”을 나중에 둘로 늘릴 자리를 어디에 비워 두느냐는 문제였다.


지금 하나여도 나중에 둘이 될 자리는 미리 갈라 둔다

이 도구는 악보 파일(MusicXML — 악보 프로그램끼리 음표·박자·가사를 주고받는 표준 형식)을 읽어 그린다. 언젠가 연주 파일(MIDI — 어느 건반을 언제 얼마나 눌렀는지만 적힌 연주 기록)도 받게 된다. 두 형식은 담고 있는 게 달라서, 그리는 쪽이 “이게 어느 형식인지”를 알기 시작하면 그 구분이 그리는 코드 전체로 번진다.

그래서 읽는 부분과 그리는 부분 사이에 칸막이(어댑터 — 형식마다 하나씩 두는 번역층)를 하나 뒀다. 읽는 쪽이 형식 차이를 다 흡수해서 같은 모양으로 넘기고, 그리는 쪽은 파일이 무엇이었는지 모른다.

값을 언제 치르느냐가 판단의 핵심이다.

  • 지금 두면 — 코드가 한 겹 늘고, 당장은 아무 이득이 없다. 입력이 하나뿐이니까.
  • 나중에 두면 — 이미 그려진 것 전부를 뜯어야 한다. 그때는 “이번 기능만 급하니 그냥 분기 하나 더” 쪽으로 기운다.

즉 이 칸막이는 두 번째 것이 들어올 때 이득이 나오는데, 그때 만들려면 이미 비싸다. 그래서 지금 뒀다.

반대로 아무 데나 칸막이를 두면 코드만 늘어난다. 판단 기준은 “두 번째가 올 거라는 근거가 있나”다. 여기서는 있었다 — 가진 악보 중 일부는 MIDI뿐이다.


시간을 누가 알려주는지는 상황마다 다르다

같은 장면을 화면에서 재생할 때와 영상으로 뽑을 때, “지금 몇 초인가”의 답이 달라야 한다.

  • 재생 중에는 소리가 기준이다. 소리와 그림이 어긋나면 소리 쪽이 맞다.
  • 뽑을 때는 프레임 번호가 기준이다. 이때는 소리가 없고, 실시간도 아니다.

여기서 배운 건 “시간”이 하나가 아니라는 것이다. 벽시계로 세면 두 상황 모두 틀린다 — 재생 중에는 소리와 조금씩 벌어지고, 뽑을 때는 컴퓨터가 느린 날 결과물의 박자가 달라진다.

그래서 그리는 쪽은 시간을 스스로 세지 않고 받아쓰기만 한다. 누가 주는지는 상황이 정한다.


특수한 경우를 일반한 경우의 부분집합으로 만든다

악보는 한 줄짜리(선율)일 수도, 두 줄짜리(피아노 왼손·오른손)일 수도 있다. 내가 다루는 건 대부분 두 줄이다.

한 줄을 전제로 세로 자리를 잡아 두면 두 줄을 붙일 때 음표 위치·볼 궤적·가사 줄을 전부 다시 잡는다. 반대로 처음부터 “줄이 여러 개”로 잡으면 한 줄짜리는 개수가 1인 경우로 저절로 처리된다.

특수를 일반의 부분집합으로 만드는 쪽이 언제나 싸다. 반대로 하면 나중에 일반을 만들 때 특수까지 다시 만든다.


요약

  • 두 번째가 올 근거가 있으면 칸막이는 지금 둔다. 나중에 두는 값이 훨씬 비싸다
  • 근거가 없으면 두지 않는다. 미리 두는 칸막이도 공짜가 아니다
  • “지금 몇 초인가”의 답은 상황마다 다르다. 만드는 쪽이 스스로 세지 않게 한다
  • 특수한 경우를 일반의 부분집합으로 만든다. 반대로 하면 두 번 만든다

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