- 발행일
handleAjaxError를 다시 고민했다 — 커밋 두 개 451줄, 들여쓰기를 빼면 120줄
handleAjaxError를 다시 고민했다
이 글은 2026년 9월에 당시 커밋 이력을 다시 보며 정리한 것입니다. 날짜는 작업한 날 기준입니다.
8월이 되면서 트리 화면이 셋이었습니다. 메타데이터 클래스, 분류체계, OID. 7월 17일에 세 파일이 metaClassTree.js·conceptClassTree.js·oidClassTree.js로 이름을 맞추고 공통 함수를 commonClassTreeUtils.js로 뽑기 시작한 상태였어요.
그 공통 파일에 handleAjaxError가 있었습니다.
function handleAjaxError(request, status, err, customMessage = "") {
const prefix = customMessage ? customMessage + "\n" : "";
alert(
prefix +
"code:" +
request.status +
"\n" +
"error:" +
err +
"\n" +
"message:" +
request.responseText
);
}
네 번째 인자로 customMessage를 받게 만들어 뒀는데, 세 트리 파일이 전부 error: handleAjaxError로 함수를 그대로 넘기고 있었습니다. 그러니 alert에는 상태 코드와 서버 응답만 뜨고, 어느 요청이 실패한 건지는 안 나왔어요. 조회가 실패한 건지 저장이 실패한 건지 사용자도 저도 모르는 alert이었습니다.
16:25 — if 한 겹을 풀었다
먼저 든 커밋(8118f846)의 제목은 "first-fail 법칙으로 유도 하기"입니다. 148줄 추가, 145줄 삭제. 그런데 공백을 무시하고 보면 5줄 추가, 2줄 삭제예요.
+ // 관리자 버튼 표시/숨김 처리
+ if (!checkAccessLevel()) {
+ $("#addClassBtn, #editClassBtn, #deleteClassBtn").hide();
+ }
+
// 관리자 페이지에서만 버튼 이벤트 추가
- if (checkAccessLevel()) {
- $("#addClassBtn").on("click", function (e) {
+ $("#addClassBtn").on("click", function (e) {
관리자 버튼 네 개의 클릭 핸들러가 if (checkAccessLevel()) { ... } 한 덩어리 안에 들어 있었습니다. 그 겹을 풀어서, 권한이 없으면 버튼을 숨기고 끝내고, 핸들러는 조건 없이 붙였어요. 실패 조건을 먼저 처리하고 본문을 평평하게 두는, 프런트에서 늘 하던 정리입니다. 145줄이 움직인 건 그 안의 코드가 전부 한 단 왼쪽으로 온 것뿐이에요.
같은 시각에 분류체계 트리는 다른 방식이었습니다. 6월 25일부터 핸들러 안에서 if (!checkAccessLevel()) return;으로 빠져나가고 있었어요. 메타데이터 트리는 숨기고 무조건 바인딩, 분류체계 트리는 바인딩하고 안에서 return. 세 파일이 같은 일을 두 방식으로 하게 된 날이기도 합니다.
17:51 — alert에 문맥 한 줄을 붙였다
한 시간 반 뒤 커밋(4a7e249a)이 제목의 그 커밋입니다. 5개 파일에 451줄 추가, 384줄 삭제. 공백을 무시하면 115줄 추가, 48줄 삭제입니다. 나머지는 commonClassTreeUtils.js의 들여쓰기를 2칸에서 4칸으로 바꾸고 구획 주석을 넣은 거예요.
// =============================================================================
// HTTP 요청 관리
// =============================================================================
실제로 바뀐 건 세 가지입니다. 첫째, 세 트리 파일의 error: handleAjaxError 여섯 곳이 전부 문맥을 넘기는 꼴이 됐습니다.
- error: handleAjaxError,
+ error: function (request, status, err) {
+ handleAjaxError(request, status, err, "메타 클래스 기본 속성 조회 중 오류가 발생했습니다.");
+ },
customMessage 인자는 7월 17일부터 있었는데 아무도 안 넘기고 있던 걸 이날 채운 겁니다. "다시 고민했다"는 제목치고는 함수 본문은 그대로이고 부르는 쪽만 바꿨어요.
둘째, 메타데이터 트리의 버튼 바인딩에 .off("click")을 앞세웠습니다.
- $("#addClassBtn").on("click", function (e) {
+ $("#addNodeBtn")
+ .off("click")
+ .on("click", function (e) {
분류체계 트리는 여덟 곳, OID 트리는 여섯 곳에 이미 이렇게 돼 있었고 메타데이터 트리만 0이었습니다. 초기화가 두 번 돌면 핸들러가 두 번 붙는 종류의 문제인데, 실제로 두 번 붙는 걸 봤는지 다른 파일과 맞추느라 넣었는지는 커밋에 없습니다.
셋째, 버튼 id를 #addClassBtn에서 #addNodeBtn으로 바꿨습니다. 분류체계와 OID 트리가 이미 NodeBtn이었고 메타데이터 트리만 ClassBtn이었어요. 템플릿의 버튼 셋도 같이 바꿨습니다. 공통화하려면 id부터 같아야 하니까요.
무엇이 바뀐 것처럼 보이고, 무엇이 바뀌었나
| 겉보기 | 실제 |
|---|---|
| 두 커밋 599줄 추가, 529줄 삭제 | 공백 빼면 120줄 추가, 50줄 삭제 |
handleAjaxError를 다시 고민 | 함수 본문 무변경. 호출부 여섯 곳에 메시지 한 줄씩 |
| first-fail 법칙 | if 한 겹을 풀어 145줄이 한 단 왼쪽으로 |
| 공통 유틸 404줄 변경 | 들여쓰기 2칸에서 4칸, 구획 주석 셋. 로직 무변경 |
이 표를 그때 그렸으면 커밋을 둘로 나눴을 겁니다. 들여쓰기 커밋 하나, 로직 커밋 하나로요. 그때는 파일을 열어 보이는 대로 정리하고 한 번에 올렸습니다.
검증
- 손으로 확인했습니다. 관리자·비관리자로 들어가 버튼이 보이고 안 보이는 것까지는 봤을 텐데, 실패 alert를 무엇으로 만들어 봤는지는 기록이 없습니다.
- 공백 무시 줄 수(5/2, 115/48)와
.off("click")개수(메타데이터 0에서 6, 분류체계 8, OID 6에서 7)는 이 글을 쓰면서git show -w와 grep으로 셌습니다. 그날 센 숫자가 아닙니다. - 핸들러가 실제로 두 번 붙던 증상은 재현하지 않았습니다.
남은 것 · 한계
handleAjaxError는 여전히alert입니다. 상태 코드와responseText를 그대로 띄우는 구조라, 서버가 HTML 오류 페이지를 돌려주면 alert에 HTML이 통째로 뜹니다. 문맥 한 줄을 앞에 붙였을 뿐 그 구조는 그대로예요.- 공통 유틸 안의
defaultHandlers는 여전히error: handleAjaxError입니다. 세 트리 파일의 호출부만 고치고 공통 파일 안의 두 곳은 빈손으로 남겼습니다. - 접근 판단이 세 파일 두 방식이 됐습니다. 숨기고 무조건 바인딩하는 쪽은 비관리자 페이지에도 핸들러가 붙어 있어요. 버튼이 안 보이니 누를 수는 없지만, 콘솔에서
.click()을 부르면 돕니다. 서버가StaffOnlyMixin으로 막고 있어서 화면 문제로 끝나지만 깔끔한 상태는 아니었습니다. 다음날 "코드 공통화" 커밋이 이어졌고, 옵션과 핸들러까지 한 곳으로 모은 건 2026년 5월입니다. .hide()로 숨긴 버튼은 왜 못 쓰는지 말하지 않습니다. 1년 뒤 잠긴 버튼에 사유를 붙이는 글에서 이 문제를 다뤘는데, 이날은 숨기면 끝이라고 봤습니다.- 들여쓰기와 로직을 한 커밋에 섞었습니다. 리뷰하는 사람은
git show -w를 알아야 이 커밋을 읽을 수 있어요.
관련 글: 분류체계와 메타클래스 트리 공통 로직을 헬퍼 4종으로 추출한 회고 · disabled를 쓰면 "왜 안 되는지"를 말할 수 없다 · jsTree 기본 사용법 · 처음 만든 트리를 열흘 만에 통째로 다시 짰다 · 파일 33개를 한 커밋에 넣었다