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

만든 것을 실제 주소에 올려 사람 손에 쥐여 준 하루였다. 만드는 것과 내보내는 것은 배우는 게 달랐다.


배포 방식은 프로젝트를 만들 때만 고를 수 있었다

호스팅에 올리는 방법이 둘이었다. 내 컴퓨터에서 결과물을 밀어 넣는 방식과, 저장소를 연결해 두고 호스팅이 알아서 빌드하는 방식이다. 먼저 밀어 넣는 쪽으로 붙였다가 연결 방식으로 옮기려 했는데, 그게 프로젝트를 만들 때만 고를 수 있는 항목이었다. 옮기려면 프로젝트를 지우고 다시 만들어야 하고 주소도 놓았다 다시 잡아야 한다.

설정 화면 어딘가에서 언제든 바꿀 수 있을 것 같은 항목이, 실은 만들 때 한 번만 정해지는 항목이었다.

  • 새 도구를 쓸 때 「무엇이 좋은가」보다 먼저 물을 것은 「이건 나중에 바꿀 수 있나」다
  • 못 바꾸는 항목은 그 자리에서 시간을 더 써도 된다. 바꿀 수 있는 항목은 일단 아무거나 고르고 지나가도 된다
  • 이 구분을 안 해 두면 시간을 정확히 반대로 쓰게 된다 — 바꿀 수 있는 것에 오래 고민하고, 못 바꾸는 것을 빨리 지나친다

검색에서 감추려고 크롤러를 막으면 역효과가 난다

아직 남에게 보일 상태가 아니라 검색 결과에 안 뜨게 하려 했다. 흔히 쓰는 방법은 크롤러에게 「들어오지 마라」고 적는 것인데, 이게 역효과다.

못 들어오게 하면 페이지 안에 적어 둔 「목록에 넣지 마세요」를 읽을 방법이 없다. 그래서 다른 데 링크가 걸려 있으면 내용 없이 주소만 검색 결과에 남는 일이 생긴다.

들어와서 읽게 두되 색인만 막는 쪽이 맞았다.

  • 차단과 지시는 다른 일이다. 지시를 전하려면 상대가 들어올 수는 있어야 한다
  • 「제일 세게 막는 방법」이 「원하는 결과를 내는 방법」과 다를 때가 있다. 세기를 고르지 말고 원하는 결과를 먼저 적는다

높이 계산이 두 번 안 나았는데 식은 처음부터 맞았다

고친 자리는 계산식이었는데 원인은 기준점이었다. 비율로 높이를 정하려면 부모가 자기 높이를 알고 있어야 하는데, 중간에 「내용만큼」인 요소가 하나 있으면 그 아래 비율은 기준을 잃고 통째로 무시된다.

  • 값이 이상하면 식을 먼저 의심하게 되는데, 식은 대개 맞다. 그 식이 무엇을 기준으로 도는지가 더 자주 틀린다
  • 「무시됐다」는 「틀리게 계산됐다」와 다른 증상이다. 계산이 아예 안 도는 경우를 따로 의심해야 한다

같은 날 비슷한 걸 하나 더 밟았다. 화면 폭을 뜻하는 값이 스크롤바 두께를 포함하고 있어서, 그걸로 여백을 계산하면 스크롤바가 생기는 순간 어긋난다. 이것도 식이 아니라 그 값이 무엇을 재는지의 문제였다.


화면 크기 구간마다 값을 적다가 계산식 하나로 바꿨다

처음엔 화면 크기 구간마다 값을 따로 적었다. 1400px 이하면 얼마, 1200px 이하면 얼마 하는 식이다. 구간이 늘수록 어디를 고칠지 헷갈리고, 구간 사이에서는 어차피 어정쩡하다.

말로 옮기면 「화면을 채우되 양옆에 96px을 남기고, 아주 넓은 화면에서는 1200px에서 멈춘다」다. 그게 한 줄이 됐다.

--shop-w: min(1200px, calc(100vw - 96px));

calc(100vw - 96px)가 화면을 따라가는 부분이고 min(1200px, ...)이 상한이다. 구간 사다리가 하려던 일이 사실 이 두 마디였다 — 따라가되 어디서 멈춘다.

  • 구간을 나눌 이유는 값이 뚝 달라져야 할 때뿐이다. 그냥 따라오면 되는 값이면 식으로 적는다
  • 사다리를 적기 전에 「이 값이 화면 크기를 따라가나」를 먼저 묻는다. 따라간다면 칸을 나눌 게 아니라 따라가는 식을 적어야 한다
  • 사다리는 늘어날 때 아프다. 처음 두세 칸은 멀쩡해 보여서 늘리게 되고, 다섯 칸쯤에서 손을 못 댄다

식이 낼 수 있는 값의 범위를 안 따지면 극단에서 터진다

가게를 화면 가운데 세우려고 남는 자리를 반으로 나눠 여백으로 줬다.

padding-left: calc((100% - var(--shop-w)) / 2);

모바일에서 가게 폭을 화면 폭과 같게 하자 이 값이 0이나 음수가 됐다. 음수 여백은 요소를 바깥으로 밀어내 배치를 망가뜨린다. 바닥을 정해 두는 것으로 막았다.

padding-left: max(0px, calc((100% - var(--shop-w)) / 2));
  • 계산으로 나오는 값에는 바닥이나 천장을 정해 둔다. 식은 중간값에서만 확인하게 되는데 터지는 건 늘 극단이다
  • 앞의 min과 여기의 max가 하는 일이 같다. 식이 갈 수 있는 범위를 손으로 잘라 두는 것이다

광고가 들어올 자리를 미리 잡아 둔다

광고는 스크립트가 나중에 채운다. 자리를 안 잡아 두면 광고가 들어오는 순간 화면이 그만큼 아래로 밀리고, 누르려던 버튼이 손가락 밑에서 이동한다.

그래서 스크립트를 붙이기 전에 규격 크기만 먼저 잡아 뒀다.

  • 늦게 오는 것이 있으면 그 자리를 미리 비워 둔다. 광고든 이미지든 불러오는 목록이든 같다
  • 반대로 자리를 잡아 뒀는데 안 채워지면 빈 칸이 남는다. 그래서 자리는 잡되 안 보이게 두고, 채워진 뒤에 드러나게 한다

개발하며 새로고침한 것이 광고 노출로 집계되면 사고다

이날 제일 중요했던 판단이다. 광고를 붙이면 화면을 고치며 수십 번 새로고침하는 동안 그 노출이 전부 집계된다. 사람이 보지도 않은 광고가 노출로 잡히면 무효 트래픽이고, 광고 계정이 위험해진다.

배포본에서만 진짜 광고를 부르고 개발 중에는 빈 상자만 두게 갈랐다.

  • 개발은 실제와 같은 조건에서 하는 게 좋지만, 바깥에 흔적이 남는 것만은 예외다. 집계·과금·알림·메일처럼 밖으로 나가는 것은 개발에서 끊는다
  • 「나중에 지우자」로 남긴 디버그용은 반드시 잊는다. 처음부터 배포본에 안 실리게 묶는 쪽이 싸다

광고 배너 하나에 개인정보처리방침이 따라왔다

이 앱은 계정도 없고 기록도 브라우저에만 있어서 수집하는 게 하나도 없었다. 그런데 광고 배너 하나를 붙이는 순간 개인정보처리방침이 필요해졌다. 광고가 광고 식별자를 쓰기 때문이다.

  • 순서가 거꾸로 되면 안 되는 종류의 일이다. 문서가 먼저 올라가 있어야 기능을 내보낸다
  • 기능을 정할 때 「이걸 붙이면 코드 말고 무엇이 따라오나」를 같이 묻는다. 방침·약관·심사·비용이 그 자리에 있다

아직 방침 주소가 없는 동안에는 링크를 살려 두지 않고 「준비 중」 안내로 바꿔 뒀다. 없는 페이지로 보내는 것보다 아직 없다고 말하는 쪽이 정직하다.


스크롤바를 화면마다 다르게 하다가 통일했다

스크롤바를 기록실만 감췄다가, 오늘 화면도 감췄다가, 결국 넷 다 보이게 하고 모양을 통일했다. 각 단계마다 그럴듯한 이유가 있었는데 모아 놓고 보니 일관성이 없었다.

  • 화면마다 다르게 할 거면 그 이유를 한 문장으로 적을 수 있어야 한다. 못 적겠으면 그때그때 기분이었던 것이다
  • 백로그도 같다. 할 일만 적어 두면 나중에 「이걸 왜 하기로 했더라」가 되고, 그러면 그날 기분으로 순서를 다시 정한다. 이유를 같이 적어 두면 우선순위가 저절로 서고 「이 이유가 아직 유효한가」로 판단할 수 있다

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