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

서명 열쇠는 저장소 밖에 둔다

앱을 스토어에 올리려면 서명을 해야 한다. 서명에 쓰는 열쇠 파일과 비밀번호가 저장소에 들어가면, 그 저장소를 가진 누구나 내 이름으로 앱을 만들어 낼 수 있다. 코드가 새는 것과는 무게가 다르다. 스토어에서 나로 인정되는 신분이기 때문이다.

그래서 비밀번호는 저장소에서 제외되는 별도 파일에 두고, 빌드 설정이 그 파일을 읽게 했다. 열쇠 파일 자체도 제외 목록에 넣었다.

여기에 한 가지를 더 챙겼다. 그 파일이 없는 상태에서도 개발용 빌드는 되게 한 것이다. 비밀번호 파일이 있을 때만 서명 설정을 채우고, 없으면 그냥 넘어간다. 이렇게 안 해 두면 저장소를 새로 받은 상태에서 아무것도 못 돌린다.

비밀을 코드에서 분리할 때는 분리로 끝내지 말고, 비밀이 없는 사람이 어디까지 할 수 있어야 하는지를 같이 정한다. 전부 막으면 안전하지만 아무도 못 쓴다.


나중에 통째로 바꿀 것은 값이 아니라 이름으로 가리킨다

앱에 두 번째 테마를 넣었다. 기본은 어두운 화면이고, 새로 넣은 것은 밝은 크림색이다.

처음 구조로는 안 됐다. 화면 곳곳에 색이 직접 적혀 있어서, 테마를 바꿔도 그 색들은 그대로였다. 두 벌을 만들려면 화면 파일을 두 벌 만들어야 할 판이었다.

색마다 이름을 붙이고 화면에서는 그 이름만 가리키게 바꿨다. 배경색, 글자색, 강조색 같은 이름이다. 그리고 테마가 그 이름에 각각 다른 값을 채운다. 화면 파일은 한 벌 그대로 두고 테마만 갈아끼우면 전체가 따라온다.

이건 색에만 해당하는 얘기가 아니다. 나중에 한꺼번에 바꾸게 될 것 같은 것은 값을 직접 쓰지 말고 이름을 하나 만들어 그 이름을 쓴다. 그 순간에는 한 단계 늘어나 번거롭지만, 바꿀 일이 생겼을 때 고칠 자리가 한 곳으로 모인다. 두 벌째를 만들 때 비용이 갈린다.

밝고 어두움이 뒤집히는 자리는 따로 둬야 한다

색 이름을 정리하고 나서도 안 보이는 자리가 있었다. 목록을 펼쳤을 때 뜨는 작은 창은 본 화면과 반대 색을 쓴다. 어두운 화면에서 그 창은 밝은 배경에 어두운 글씨다. 본 화면용 글자색을 그대로 쓰면 밝은 배경에 밝은 글씨가 되어 안 보인다.

상태 표시줄 아이콘도 같은 문제였다. 배경이 밝으면 아이콘이 어두워야 하고 어두우면 밝아야 한다.

그래서 색 이름 묶음에 뒤집히는 자리용 이름을 따로 뒀다. 테마를 만들 때 화면 전체가 하나의 색 체계로 간다고 가정하면, 이렇게 반전되는 구석에서 글씨가 사라진다. 그리고 이런 건 실제로 눈으로 보기 전에는 안 드러난다.


어떤 설정은 언제 적용하느냐가 값의 일부다

테마 전환은 화면을 그리기 전에 정해야 한다. 이미 그려진 화면에 새 테마를 걸면 아무 일도 안 일어난다.

그래서 사용자가 테마를 바꾸면 선택을 저장하고 화면을 통째로 다시 만들게 했다. 다시 만들어지는 과정의 맨 앞에서 저장된 선택을 읽어 테마를 정하고, 그다음에 화면을 그린다.

여기에 전제가 하나 붙는다. 화면을 다시 만들어도 템포와 재생 상태는 남아 있어야 한다. 그 값들이 화면에 딸려 있었다면 테마를 바꿀 때마다 초기화됐을 것이다.

설정을 넣을 때는 “이 설정이 언제 읽히는가”를 확인한다. 실행 중에 못 바꾸는 것이면 다시 만들어서 적용해야 하고, 그러려면 다시 만들어도 살아남아야 하는 값이 무엇인지 먼저 정해야 한다.


상태를 자원 교체로 표현하면 관리할 것이 곱으로 늘어난다

박 표시 점은 지금 울리는 박일 때 켜지고 아닐 때 꺼진다. 처음 떠올린 방법은 켜진 그림과 꺼진 그림을 각각 만들어 갈아끼우는 것이었다.

그림 하나만 두고 색만 바꾸는 쪽으로 갔다. 점 모양이 단색 실루엣이라 색 하나로 켜짐과 꺼짐이 다 표현된다. 그리고 그 색을 테마 이름에서 가져오니 테마를 바꿔도 알아서 맞는다.

차이는 나중에 벌어진다. 그림을 갈아끼우는 방식이었다면 모양을 하나 추가할 때마다 켜진 것과 꺼진 것을 두 벌 만들어야 하고, 테마가 둘이니 또 두 배가 된다. 색으로 표현하면 모양이 늘어도 그림은 하나씩만 늘고 상태와 테마는 색이 알아서 처리한다.

상태를 표현할 방법을 고를 때, 그 방법이 나중에 다른 축과 곱해지는지를 본다. 곱해지는 방식은 처음엔 쉬워 보여도 축이 하나 늘 때마다 관리 대상이 배로 뛴다.


요약

  • 서명 열쇠는 스토어에서 나를 증명하는 신분이라 저장소 밖에 둔다. 다만 비밀이 없는 사람도 개발 빌드는 되게 열어 둔다.
  • 나중에 통째로 바꿀 것은 값이 아니라 이름으로 가리킨다. 두 벌째를 만들 때 비용이 갈린다.
  • 테마에는 밝고 어두움이 뒤집히는 자리가 있다. 하나의 색 체계로 가정하면 그 구석에서 글씨가 사라지고, 눈으로 보기 전엔 안 드러난다.
  • 어떤 설정은 언제 읽히는지가 값의 일부다. 실행 중에 못 바꾸는 것은 다시 만들어 적용하고, 그러려면 살아남아야 할 값을 먼저 정한다.
  • 상태 표현 방식을 고를 때 그것이 다른 축과 곱해지는지 본다. 곱해지면 축이 늘 때마다 관리 대상이 배로 뛴다.

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