SVG 사각형 하나 잡으려고 네 번 고친 날

26년 05월 27일

SVG에 사각형이 깜빡인다

이날은 SVG 사각형 하나 때문에 하루 종일 싸운 날이었다.

알림 설정 기능도 마무리하고 CI 문제도 여러 개 잡았다.

근데 기억에 남는 건 SVG 버그뿐이다.

같은 버그를 네 번 고쳤다.

고칠 때마다 원인이 더 깊은 곳에 있었다.

증상은 단순했다.

페이지를 열 때 SVG 아이콘 자리에 잠깐 사각형이 깜빡였다.

금방 사라지니까 대부분은 안 보이지만 분명히 있었다.

첫 번째 시도: CSS 로딩 타이밍

첫 번째 원인은 CSS 로딩 타이밀이었다.

이 프로젝트는 모듈 연합으로 앱들을 느리게 로드한다.

커리큘럼 앱만 Tailwind를 쓰는데 Tailwind의 기본 스타일이 전역에 주입된다.

이 기본 스타일에는 SVG에 대한 설정이 있다.

CSS 로딩 타이밍 차이 때문에 사이드바의 특정 스타일이 적용되기 전까지 Tailwind 기본값이 잠깐 적용된다.

그 사이에 사각형이 보이는 거다.

해결은 SVG에 명시적으로 스타일을 넣는 거였다.

Tailwind 기본값보다 항상 우선하게 만들었다.

두 번째 시도: transition all

고쳤다고 생각했는데 또 깜빡였다.

디버깅 도구를 열어보니 transition이 의심스러웠다.

전역 SCSS에 SVG에 transition all이 걸려 있었다.

transition all은 편리하다.

근데 “모든 속성”에 트랜지션을 건다.

SVG의 display랑 box-sizing이 바뀔 때도 트랜지션이 걸린다.

그래서 속성이 바뀌는 0.2초 동안 사각형이 보이는 거다.

해결은 transition을 fill로만 제한하는 거였다.

transition all 대신 transition fill. 색상만 트랜지션되게, 크기는 바로 바뀌게.

세 번째 시도: 공유 SCSS

또 깜빡였다.

이번엔 다른 원인이었다.

공유 전역 SCSS 파일에 SVG transition all이 또 있었다.

근데 이 파일은 여러 앱이 공유해서 수정하면 안 됐다.

그래서 컴포넌트에서 같은 선택자에 important를 걸어서 덮어썼다.

공유 파일은 못 건드리니까 컴포넌트에서 강제로 우선하게 만든 거다.

important를 쓰는 건 별로 안 좋지만 공유 파일을 못 건드리면 어쩔 수 없다.

네 번째: 원복하고 검증

이전 수정이 다른 브랜치에 남아 있었다.

원복 커밋을 찾아서 되돌리고 깃 diff로 공유 파일이 원본이랑 같은지 확인했다.

그리고 사이드바만 수정한 상태로 배포했다.

네 번 고치고 나서야 사각형이 안 깜빡였다.

같은 버그를 네 번 고친 교훈

이 버그는 원인이 한 번에 안 나왔다.

고칠 때마다 더 깊은 곳에 원인이 있었다.

첫 번째는 CSS 타이밍. 두 번째는 transition all.

세 번째는 공유 SCSS. 네 번째는 브랜치 간 충돌.

전부 다른 원인인데 증상은 같았다.

“고쳤다”고 생각했는데 또 나타나면 더 깊은 곳을 봐야 한다.

표면적인 원인을 고치고 “됐다”고 넘어가면 같은 증상이 다른 원인으로 다시 나타난다.

원인을 하나씩 벗겨내면서 결국 바닥까지 가야 한다.

그리고 transition all은 정말 조심해야 한다.

편리하지만 의도하지 않은 속성까지 트랜지션시킨다.

SVG에서 display가 바뀌는 걸 트랜지션시킬 이유가 없다.

transition은 필요한 속성만 지정하는 게 안전하다.

복잡도 36을 4개 헬퍼로 쪼개다

SVG 버그 외에 코드 복잡도 문제도 잡았다.

CI 품질 게이트가 함수 복잡도를 검사하는데 한 함수의 복잡도가 36이었다.

임계값은 25다.

게이트에 막혔다.

이 함수는 폼 제출을 처리하는 거였다.

너무 많은 일을 하고 있었다.

그래서 헬퍼 함수 4개로 쪼갰다.

규칙 만들기, 알림 규칙 만들기, 학습 한계 정규화, 접근 제한 해결. 각각 하나의 일만 하는 작은 함수로 분리했다.

중첩된 삼항 연산자도 early return으로 바꿨다.

그러니까 복잡도가 25 아래로 떨어졌고 함수도 137줄에서 80줄로 줄었다.

복잡도가 높은 함수는 여러 가지 일을 하고 있다는 신호다.

쪼개면 각 함수가 하나의 일만 하게 된다.

그러면 복잡도도 내려가고 이해하기도 쉬워진다.

마무리

이날의 핵심은 SVG 버그였다.

사각형 하나를 잡으려고 네 번 고쳤다.

고칠 때마다 원인이 바뀌었다.

이런 디버깅은 인내심이 필요하다.

“고쳤다”고 생각했는데 또 나타나면 짜증난다.

근데 거기서 멈추지 말고 더 깊이 파고들어야 한다.

증상은 같은데 원인이 다를 수 있다.

원인을 하나씩 벗겨내면서 결국 바닥까지 가야 한다.

transition all의 위험성도 다시 배웠다.

편리한 도구는 편리한 만큼 위험하다.

“모든 속성”에 적용되는 건 의도하지 않은 결과를 만든다.

필요한 것만 지정하는 게 항상 더 안전하다.