전체 검색

글, 태그와 카테고리를 검색하고 바로 이동해요

"저장하기"를 버리고 "커밋"으로 돌아왔습니다

쉬운 말이 이 앱의 정체성이었어요. 저장하기, 실험 공간, 보관함. 13일 만에 그걸 다 걷어내고 커밋·브랜치·스태시로 돌아왔습니다. 포기가 아니라 순서를 바꾼 이야기예요.

2026. 07. 29. 09:51:177분 읽기프로젝트/Git GUI
조회 22
가게 간판을 쉬운 말에서 전문 용어로 갈아 끼우는 사람, 내린 간판은 벽에 기대둔 일러스트

이 앱의 커밋 버튼에는 "저장하기"라고 적혀 있었어요. 브랜치 탭은 "실험 공간", 스태시는 "보관함"이었고요.

그게 이 앱의 정체성이었습니다. 첫 편에서 제가 그렇게 선언했잖아요 — 개발자 모드와 쉬운 모드를 한 앱에 담겠다고.

그리고 오늘, 그 단어들을 전부 걷어냈습니다.

그 사이에 있었던 일

첫 두 편과 이 글 사이에 13일이 지났고, 커밋이 500개 넘게 쌓였어요. 앱은 그동안 꽤 자랐습니다. 충돌을 카드로 바꿨고, 터미널과 워크트리도 들어왔죠.

충돌이 나면 겹치는 부분을 카드로 하나씩 고르게 됐고, 히스토리는 로컬·원격·태그를 한 화면에 그리는 전체 그래프가 됐고, 하단에는 진짜 터미널이 붙었고, 워크트리가 1급 시민이 됐고, 설치 가능한 앱 파일까지 나왔어요.

쓸 만해진 거예요. 그래서 문제가 보이기 시작했습니다.

쉬운 말이 왜 안 쉬웠나

처음 설계할 때 저는 "커밋"이 어려운 단어라고 생각했어요. 지금도 그 판단은 틀리지 않았다고 봅니다. 문제는 다른 데 있었어요.

원래 라벨바꾼 말실제로 벌어진 일
커밋저장하기문서 저장(Ctrl+S)과 헷갈림 — "저장했는데 왜 안 올라가요?"
브랜치실험 공간실험이 아닌 정식 작업도 여기서 하는데 이름이 가벼움
스태시보관함보관은 영구적인 느낌인데 실제로는 임시
푸시백업백업은 복사인데 푸시는 공유 — 뜻이 다름
받아오기병합이 같이 일어난다는 게 안 드러남

오른쪽 열을 보면 공통점이 있어요. 쉬운 단어가 이미 다른 뜻을 갖고 있었던 겁니다. 빈 그릇에 이름을 붙인 게 아니라, 남의 그릇에 이름을 덮어쓴 거예요.

낯선 단어는 배우면 되는데, 잘못 아는 단어는 고쳐야 해요. 그리고 고치는 게 훨씬 어렵습니다.

내가 만든 화면을 내가 못 읽었어요

제가 이 앱의 첫 번째 사용자거든요. 매일 씁니다.

그런데 "보관함"을 누를 때마다 머릿속에서 한 번 번역을 했어요. 아, 스태시. 브랜치를 만들 때도 "실험 공간 만들기"를 보면서 브랜치를 생각했고요.

쉬운 말이 쉽지 않았던 겁니다. 적어도 저한테는요. 그리고 지금 이 앱을 쓰는 사람은 저 하나예요.

(비개발자를 위한 앱을 만들면서, 정작 매일 쓰는 유일한 사용자는 개발자였던 거죠.)

게다가 화면에는 한글 라벨 옆에 영문 개념 배지가 따라 붙어 있었어요. 병합 옆에 merge, 푸시 옆에 push 하는 식으로요. 쉬운 말로 적어놓고 옆에 원어를 붙이고 있었으니, 두 번 말하고 있었던 셈입니다.

그래서 세어 봤습니다

걷어내기 전에 규모부터 쟀어요.

쉬운 말화면에 쓰인 곳
실험 공간59곳
보관함37곳
백업22곳
받아오기17곳
합치기16곳
지금 여기14곳

세어 본 결과가 이랬어요.

대상개수바꾸면 생기는 일
화면에 박힌 한글 라벨약 124개전부 손으로 찾아야 함
E2E 테스트의 문구 단언154회무더기로 깨짐
그중 "저장" 계열108회한 단어가 테스트 절반을 붙잡고 있었음
영문 개념 배지라벨마다같은 뜻을 두 번 말하는 중

세 번째 줄을 보고 잠깐 멍했어요. 단어 하나가 테스트 108개를 인질로 잡고 있었던 거예요. 그리고 그건 제가 그렇게 짰기 때문이고요.

테스트가 화면 문구를 직접 단언하면 이렇게 됩니다. 문구는 제품에서 제일 자주 바뀌는 것 중 하나인데, 그걸 테스트가 붙들고 있으니까요.

화면에 박힌 한글 문자열이 대략 124개. 그리고 진짜 문제는 여기였어요 — E2E 테스트가 이 문구들을 154번 단언하고 있었습니다. "저장" 계열만 108번이요.

즉 단어를 바꾸면 테스트가 무더기로 깨져요. 한 번이면 참겠는데, 문제는 이게 마지막 변경이 아니라는 거였습니다.

하드코딩으로 갈아치우지 않은 이유

쉬운 말을 버리는 게 아니라 미루는 것이었거든요. 언젠가 쉬운 모드를 다시 켤 거예요. 그때 또 124곳을 뒤지고 테스트 154개를 고칠 순 없죠.

그래서 단어를 코드에 박는 대신, 용어 사전 파일을 하나 만들었습니다. 화면에 보이는 라벨은 전부 그 사전을 참조해요.

테스트도 같은 사전을 가져다 씁니다. "저장하기라는 글자를 찾아라"가 아니라 "사전의 커밋 항목에 해당하는 글자를 찾아라"로요. 그러면 다음에 어휘가 바뀌어도 테스트는 한 줄도 안 고쳐도 됩니다.

쉬운 모드는 이제 같은 모양의 표 하나를 더 만들고 토글을 다는 일이에요. 되돌릴 길을 먼저 깐 거죠.

(문장 전체는 사전에 안 넣었어요. 안내문까지 키로 만들면 그건 다국어 시스템을 만드는 일이 되거든요. 그건 지금 필요 없는 규모예요.)

사전은 이렇게 생겼어요. 별거 없습니다.

// 용어 사전 — 화면과 테스트가 같은 걸 봅니다
export const TERMS = {
  commit:   { label: "커밋",   origin: "commit" },
  branch:   { label: "브랜치", origin: "branch" },
  stash:    { label: "스태시", origin: "stash" },
  merge:    { label: "병합",   origin: "merge" },
  push:     { label: "푸시",   origin: "push" },
} as const;

export type TermKey = keyof typeof TERMS;
// 화면
<Button>{TERMS.commit.label}</Button>

// 테스트 — 문구가 아니라 개념을 찾습니다
await page.getByRole("button", { name: TERMS.commit.label }).click();

// 어휘가 바뀌어도 이 줄은 안 고칩니다
방식어휘를 바꿀 때쉬운 모드를 켤 때
문구를 코드에 직접124곳 + 테스트 154곳같은 작업을 또
사전 참조사전 한 파일표 하나 더 만들고 토글

이게 "쉬운 말을 버린 게 아니라 미뤘다"의 실체예요. 되돌릴 길을 먼저 깔아 둔 겁니다. 되돌리는 비용이 낮으면 결정을 빨리 내릴 수 있고요.

사전에 넣은 것들

저장하기는 커밋으로. 실험 공간은 브랜치, 보관함은 스태시, 합치기는 병합, 백업은 푸시, 받아오기는 가져오기로 갔어요.

"지금 여기"는 현재 위치(HEAD)가 됐고, "겹침"은 충돌이 됐습니다. "없어진 폴더"는 정리 대상으로, "연결 없음"은 업스트림 없음으로요.

그리고 영문 배지는 화면에서 뺐어요. 대신 툴팁으로 내렸습니다. 병합 버튼에 마우스를 올리면 "병합 (merge)"이 뜨는 식으로요.

원어가 필요한 사람은 있어요. 다만 그게 화면에서 제일 눈에 띄는 요소일 필요는 없었던 거죠.

그리고 사전에 안 넣은 것도 정해 뒀어요. 여기서 선을 안 그으면 다국어 시스템을 만들게 되거든요.

대상사전에 넣나이유
버튼·메뉴·탭 라벨넣음개념을 가리키는 짧은 말
상태 배지넣음같은 개념이 여러 화면에 반복됨
안내 문장안 넣음문장은 맥락마다 달라서 키로 만들면 어색해짐
에러 메시지안 넣음원인을 설명하는 글이라 개념 치환으로 안 됨

선을 이렇게 그은 이유는 간단해요. 지금 필요한 건 어휘 전환이지 국제화가 아니거든요. 필요해지면 그때 확장하면 되고, 지금 미리 만들면 쓰지도 않을 구조를 유지하게 됩니다.

배지를 툴팁으로 내린 것도 결정이었어요

영문 배지를 그냥 지울 수도 있었는데, 툴팁으로 옮겼습니다. 이유가 있어요.

처리원어가 필요한 사람필요 없는 사람
화면에 항상 표시편함시선이 두 번 감
완전히 제거검색할 단어를 모름깔끔함
툴팁으로올려 보면 나옴평소엔 안 보임

가운데가 진짜 문제예요. 이 앱을 쓰다 막히면 사람들은 검색을 하거든요. 그때 "병합"으로는 답이 잘 안 나오고 "git merge"로는 나옵니다. 원어를 지우면 밖으로 나가는 문을 닫는 셈이에요.

원어가 필요한 사람은 있어요. 다만 그게 화면에서 제일 눈에 띄는 요소일 필요는 없었던 거죠.


사전에도 규칙이 필요했습니다

단어를 한곳에 모으니 새로운 실수가 가능해졌어요. 두 개념에 같은 라벨을 붙이는 것 같은.

그래서 단위 테스트를 두 개 박았습니다. 사전의 모든 항목이 비어 있지 않을 것, 그리고 같은 라벨이 두 항목에 붙지 않을 것. 라벨이 겹치면 툴팁도 테스트 단언도 모호해지거든요.

사전에 없는 단어를 쓰려고 하면 타입 검사에서 막힙니다. 실행 전에요.

규칙을 어떻게 강제했는지도 적어 둘게요.

// 사전 자체를 검사합니다
test("모든 항목에 라벨이 있다", () => {
  for (const [key, term] of Object.entries(TERMS)) {
    expect(term.label.trim()).not.toBe("");
  }
});

test("같은 라벨이 두 항목에 붙지 않는다", () => {
  const labels = Object.values(TERMS).map(t => t.label);
  expect(new Set(labels).size).toBe(labels.length);
});

두 번째 검사가 실제로 필요했어요. 단어를 한곳에 모으니까 "이것도 비슷하니 같은 라벨 쓰지 뭐"가 가능해졌거든요. 라벨이 겹치면 툴팁도 테스트 단언도 모호해집니다.

그리고 사전에 없는 키를 쓰면 타입 검사에서 막혀요. 실행 전에요. 이 앱에서 반복되는 태도인데 — 규칙은 문서가 아니라 실패하는 검사로 존재합니다.

그래서 쉬운 모드는요?

안 버렸어요. 순서를 바꿨을 뿐입니다.

처음 계획은 쉬운 말로 시작해서 개발자용을 나중에 얹는 거였는데, 지금은 반대가 됐어요. 개발자 어휘가 기본이고, 쉬운 말이 나중에 얹히는 층입니다.

만드는 사람이 매일 쓰는 말이 기본이 되는 게 맞았어요. 쓰지도 않는 말로 만든 화면은, 아무리 다정해도 결국 아무도 안 읽습니다.

참고로 이 전환의 시작은 어휘가 아니었어요. "디자인이 AI가 만든 것처럼 보인다"는 지적 한 줄이었습니다. 그날 제 화면을 다시 본 이야기는 내가 만든 앱이 AI가 만든 것처럼 보였다에 따로 썼어요.

그리고 그렇게 어휘까지 정리하고 나니, 이 앱이 정말 도구가 됐어요. 5주간의 결산은 Git GUI 0.0.1 — 5주 만에 도구가 됐습니다에 있습니다.

시리즈 이어읽기

Git GUI, 도구가 되기까지

3 / 5

이야기 나누기

반응을 남기고 새 글 소식을 받아보세요.

댓글0
서로를 존중하는 대화를 남겨주세요.

첫 댓글을 남겨 대화를 시작해보세요.

새 글 구독
새 글이 공개되면 이메일로 알려드려요.