SLECS 로고를 WEAVERKIT으로 교체
목차
SVG 에셋 두 개짜리 커밋이다. 파일 개수만 보면 아주 작은 작업처럼 보이지만, 왜 이게 버그였는지, 그리고 왜 그 방식으로 고쳤는지 정리하고 넘어가는 게 맞을 것 같아서 썼다.
sl-apple-touch-icon.svg와 sl-og-image.svg — 이름에서 알 수 있듯 각각 iOS 홈 화면 아이콘용, OG(Open Graph) 이미지용 파일이다. 평소엔 크게 신경 안 쓰이는 에셋들이지만, 이 두 파일이 브랜드의 첫인상을 만드는 실제 접점이라는 건 분명하다.
OG 이미지는 SNS나 메신저에서 링크를 공유했을 때 미리보기로 뜨는 이미지다. 카카오톡 링크 공유, Slack 채널 링크 붙여넣기, 트위터 카드 — 다 여기서 끌어온다. 사용자 입장에서는 "링크 미리보기"지만, 서비스 입장에서는 사람들이 가장 처음 보는 시각적 인상이다. apple-touch-icon은 iPhone이나 iPad에서 웹사이트를 홈 화면에 추가했을 때 나타나는 아이콘이다. 네이티브 앱처럼 홈 화면에 배치되는 그 아이콘.
이번 건은 브랜드 전환 — SLECS 로고를 WEAVERKIT으로 교체 — 맥락에서 발생한 누락이었다. 코드 어딘가에 조건 분기가 있었고, 그 분기가 특정 케이스에서 예전 로고를 그대로 가리키고 있었다. 정상 경로에서는 새 로고가 잘 나왔기 때문에 처음에는 눈에 안 띄었다.
조건 분기 버그가 숨어있던 방식
브랜드 에셋을 코드에서 다루는 방식은 프로젝트마다 다르다. 단순히 하드코딩된 경로로 박혀 있으면 전수 교체가 쉽다. 검색해서 바꾸면 끝이다. 근데 조건에 따라 다른 에셋을 내려주는 구조라면 얘기가 달라진다.
흔히 이런 패턴이 생긴다:
function getLogoUrl(brand) {
if (brand === 'weaverkit') {
return '/assets/wk-logo.svg';
}
// fallback — 여기가 문제의 온상이 된다
return '/assets/sl-logo.svg';
}
브랜드가 하나뿐일 때는 이 패턴에 별 문제가 없다. 근데 브랜드 전환 작업을 할 때 분기 상단만 고치고 fallback을 그대로 두면, 새 케이스로 진입하지 못하는 엣지 케이스에서 예전 값이 살아남는다. 이번 버그가 딱 그 케이스였다.
sl-apple-touch-icon.svg와 sl-og-image.svg 두 파일이 수정 대상이었다는 건, 해당 에셋을 참조하는 코드 경로가 두 군데 이상이었거나, 한 분기 안에서 두 에셋을 함께 처리하고 있었다는 얘기다. 어느 쪽이든 분기 로직을 따라가야 재현이 됐다.
수정 전에 재현 시나리오를 먼저 정리한 게 이 과정에서 도움이 됐다. "어떤 경로로 접근하면 버그가 터지는지"를 글로 정리해두면, 코드를 고친 후에 동일 시나리오로 다시 돌려볼 수 있다. "고쳤으니 됐겠지"가 아니라 실제로 재현이 안 되는 걸 확인하는 것. 이게 최소한의 회귀 방지다. 수정 후에는 정상 경로도 같이 체크했다. 버그 있던 경로만 고치고 정상 경로가 망가진 경우도 종종 있어서, 항상 양쪽 다 돌려보는 습관을 들이고 있다.
수정 범위를 왜 딱 거기서 끊었나
버그를 파다 보면 주변 코드가 자연스럽게 눈에 밟힌다. 이 함수 네이밍이 애매하다, 이 로직 더 깔끔하게 짤 수 있다, 이 상수 enum으로 빼면 좋겠다. 손 가는 건 이해하는데, 버그 픽스 커밋에 리팩토링을 섞으면 리뷰 구조가 흐려진다.
| 접근 방식 | 장점 | 단점 |
|---|---|---|
| 버그 픽스 + 리팩토링 한 커밋 | 한 번에 정리됨 | 리뷰 범위 확대, 롤백 단위 커짐 |
| 버그 픽스만 먼저 커밋 | 인과 관계 명확, 리뷰 작음 | 리팩토링 별도 PR 필요 |
| 버그 픽스 후 같은 PR에 후속 커밋 | 커밋 단위 의도 분리 가능 | PR 자체는 커짐 |
이번엔 두 번째 — 버그 픽스만 먼저 — 를 택했다. 이유는 단순하다. 변경 의도를 git log만 봐도 파악할 수 있게 하고 싶었고, 혹시 이 픽스를 롤백해야 할 상황이 생기면 리팩토링 변경이 같이 묶여 롤백되는 걸 피하고 싶었다.
주변 코드에 유사한 패턴이 있는지도 같이 체크했다. 같은 실수가 다른 파일에도 숨어 있으면 이번에 안 잡으면 다음 번에 또 나온다. 없었으면 다행이고, 있었으면 이번 픽스 범위에 포함하거나 별도 이슈로 기록했을 것이다.
방어 코드 관점에서, fallback이 있는 분기라면 명시적으로 exhaustive하게 처리하는 게 낫다고 다시 한번 느꼈다.
function getLogoUrl(brand) {
switch (brand) {
case 'weaverkit':
return '/assets/wk-logo.svg';
default:
// 알 수 없는 brand가 들어오면 조용히 넘기지 않는다
console.warn(`Unknown brand value: ${brand}`);
return '/assets/wk-logo.svg';
}
}
"혹시 모르니 구 브랜드로 폴백"이 아니라, 알 수 없는 값이 들어왔을 때 로그라도 남기는 구조. 상황에 따라 에러로 튀어나오게 해도 된다. 조용히 구 값 내려주는 게 제일 나쁜 선택이다 — 나중에 왜 예전 로고가 뜨는지 한참 디버깅하게 된다. 이번 버그가 그 케이스였으니까 더 와닿았다.
SVG 에셋 교체가 실제로 반영됐는지 확인하기까지
SVG 파일 자체는 바꿨는데 실제로 반영이 됐는지 확인하는 게 생각보다 번거롭다.
OG 이미지는 SNS 플랫폼 쪽에서 캐싱을 적극적으로 한다. 파일을 교체했어도 카카오톡이나 Slack에서는 한동안 이전 이미지가 뜰 수 있다. 각 플랫폼마다 캐시 강제 갱신 도구가 있다 — Facebook Sharing Debugger, Twitter Card Validator 같은 것들. 실제 반영 여부를 확인하려면 이 도구로 캐시를 날리고 다시 크롤링하도록 해야 한다.
apple-touch-icon도 비슷하다. 이미 홈 화면에 저장해둔 아이콘은 다시 추가하지 않으면 안 바뀐다. 새로 추가하는 경우에만 새 아이콘이 적용되기 때문에, 테스트할 때는 기존 아이콘 삭제하고 다시 홈 화면에 추가하는 과정을 거쳐야 한다.
이번 수정도 파일 변경 후 이 부분까지 눈으로 확인했다. 자동화 테스트로는 커버하기 어려운 영역이라 결국 직접 보는 게 제일 확실하다. 비주얼 회귀 테스트가 있는 프로젝트라면 얘기가 다르겠지만, 없는 상황에서는 사람 눈에 의존할 수밖에 없다.
에셋 쪽 작업은 코드 변경보다 실제 결과를 눈으로 체크하는 데 더 시간이 걸리는 경우가 많다. 이번 커밋도 파일은 두 개였지만 검증 과정은 그보다 길었다. 브랜드 교체 작업 이후로는 에셋 경로를 한 번 grep으로 훑어보는 걸 습관으로 삼고 있다. 이번처럼 분기 안에 숨은 참조까지 다 잡으려면 grep만으로는 부족할 수 있어서, 실제로 렌더링되는 결과를 눈으로 보는 단계를 항상 남겨두는 게 낫다.
댓글 0
첫 댓글 달아줘.