개발 slecs

관리자 페이지 콘솔 에러와 디자인 오류 수정

목차

관리자 페이지 콘솔 에러를 그냥 두면 안 되는 이유가 있다. 에러 자체가 사용자 화면을 직접 막는 게 아닐 수 있는데, 쌓이다 보면 진짜 중요한 에러를 알아채지 못하게 된다. 노이즈 안에 시그널이 묻히는 것. 이번 수정 범위는 뷰/스타일 파일 2개, 내부 클래스 1개였음. 숫자만 보면 작은데, 세 계층이 모두 엮여 있어서 한 곳만 고치면 다른 곳이 맞지 않는 구조였다.

관리자 페이지는 내부 사용자만 쓰기 때문에 우선순위가 뒤로 밀리기 쉽다. 근데 이게 생각보다 위험함. 관리자 도구가 부정확하거나 오작동하면 운영 판단을 잘못 내리게 되고, 그 영향은 서비스 전체로 퍼진다. 특히 집계 숫자를 다루는 화면이라면 더 그렇다.

문제 원인

기존 로직에서 엣지 케이스가 처리되지 않아 특정 상황에서 잘못된 결과를 반환하거나 오류가 발생하고 있었음. 콘솔 에러와 디자인 일탈이 동시에 나타난 건 우연이 아니었다. 같은 엣지 케이스가 두 개의 다른 증상으로 터진 것.

엣지 케이스가 처음부터 처리되지 않은 이유는 단순하다. 개발할 때 정상 플로우로만 테스트했기 때문. 데이터가 없는 경우, 예상치 못한 상태값, 빈 배열 같은 케이스를 별도로 확인하지 않으면 코드에 구멍이 생긴다. 그리고 그 구멍은 특정 조건에서만 재현되기 때문에 발견이 늦다.

사내 서비스를 만들다 보면 기능 하나가 단순히 화면에 버튼 하나 추가하는 것으로 끝나지 않는다는 걸 계속 체감함. SQL 집계, 상태 머신, 예외 처리, 화면 렌더링, 권한 체크가 모두 엮여 있어서 어느 하나만 빠뜨려도 숫자가 맞지 않거나 특정 사용자에게 이상한 화면이 나타난다. 특히 금융/결제 도메인에서 숫자 하나가 틀리면 신뢰가 무너질 수 있어서 꼼꼼함이 기본값이어야 한다. "대충 맞는 것 같다"로 넘기면 반드시 다시 돌아옴.

수정 내용

수정은 세 군데였다. 내부 클래스 로직 수정, 화면 렌더링 수정, 프론트 스크립트 수정.

증상만 픽스하는 게 아니라 왜 발생했는지 원인을 먼저 파악하고 수정했음. 비슷한 패턴이 다른 곳에도 있는지 확인했고, 위험한 케이스는 함께 수정했다. 이게 번거로워 보여도 같은 버그로 다시 오는 시간이 훨씬 비싸다.

내부 클래스에서 엣지 케이스를 방어하는 패턴은 대략 이렇다.

# 기존 - 특정 상태값이 없으면 KeyError 발생
def get_summary(self, status):
    return SUMMARY_MAP[status]

# 수정 - 없는 상태값에 기본값 처리
def get_summary(self, status):
    return SUMMARY_MAP.get(status, DEFAULT_SUMMARY)

"없을 수 있다"는 가정을 코드 안에 명시적으로 넣는 게 핵심이다. 조용히 None이나 undefined를 돌려보내면 뷰까지 전파되어 렌더링이 깨짐. 에러가 발생 지점에서 바로 터지면 디버깅이 쉬운데, 조용히 전파되면 증상이 전혀 다른 곳에서 나타나서 원인 찾기가 어려워진다.

프론트 쪽 콘솔 에러도 비슷한 패턴이었다. 서버에서 내려온 데이터 구조를 그대로 믿고 접근하다가, 특정 케이스에서 필드가 없으면 undefined를 읽으려다 에러가 발생하는 구조.

// 위험 - data.detail이 없으면 TypeError
const label = data.detail.label;

// 안전 - optional chaining + nullish coalescing
const label = data.detail?.label ?? '-';

스타일 일탈은 대부분 렌더링 버그에서 파생된다. 정상 케이스로만 테스트하면 특정 상태값이 들어왔을 때 레이아웃이 무너지는 걸 발견하지 못함. 조건부 클래스 처리에서 "값이 없을 때"를 빠뜨리면 그 케이스에서 레이아웃이 틀어진다. CSS만의 문제가 아니라 뷰 레이어로 내려오는 데이터가 예상 형태가 아닌 게 근본 원인인 경우가 많다.

버그 수정 프로세스

이번 수정에서 적용한 체크리스트를 정리해둔다.

항목 목적
같은 로직이 다른 경로에도 있는지 확인 중복 코드에 잠복한 같은 버그 선제 처리
수정이 기존 정상 케이스를 망가뜨리지 않는지 회귀 방지
해당 화면/API에서 실제 동작 확인 코드 리뷰만으론 부족
관련 숫자를 다른 화면과 cross-check 집계 로직 버그는 여기서 잡힘

수정 후 버그를 직접 재현해서 정상 동작을 확인했음. 숫자 정합성도 관련 화면과 비교했다. 집계/통계 화면에서는 수치 cross-check가 특히 중요하다. 렌더링이 정상으로 보여도 내부 계산 로직이 엣지 케이스에서 다른 값을 내보내는 경우가 있어서, 숫자 자체를 다른 화면이나 직접 쿼리 결과와 비교하는 게 필요하다.

변경 전 현재 동작을 스크린샷이나 수치로 메모해두는 습관을 유지하고 있음. 수정 후 같은 케이스로 다시 확인하고, 관련 화면이 있으면 숫자 cross-check까지 한다. 커밋 메시지는 "무엇을"보다 "왜"를 담으려고 노력한다. fix: admin console error보다 fix: handle missing status in summary to prevent KeyError가 나중에 git blame 볼 때 훨씬 유용함. 커밋이 이유를 설명하면 반년 뒤 본인이 봐도 당시 의도를 파악할 수 있다.

작은 커밋을 자주 하는 것도 같은 이유에서다. 문제가 생겼을 때 어느 변경에서 깨졌는지 찾기 훨씬 쉽다. 이번에도 내부 클래스, 렌더링, 프론트 스크립트를 하나로 묶지 않고 논리적으로 독립된 단위로 나눠서 커밋했음. 세 파일이 서로 연관되어 있어도 변경 이유가 다르면 커밋을 나누는 게 맞다. git bisectgit revert가 필요할 때 단위가 작을수록 리스크 범위가 좁다.

엣지 케이스를 꼼꼼히 따지는 게 귀찮아 보여도, 결국 같은 버그로 다시 오는 시간이 훨씬 크다. 관리자 페이지 콘솔이 조용해야 진짜 에러가 터졌을 때 바로 알아챌 수 있다.

댓글 0

첫 댓글 달아줘.