직접 만든 에러 클래스를 227줄 지운 날

26년 05월 28일

에러 클래스를 왜 지웠는가

이날은 “직접 만든 걸 프레임워크 내장으로 바꾸는” 날이었다.

227줄짜리 에러 클래스를 지우고 프레임워크가 제공하는 기능으로 교체했다.

린터 여러 개를 하나로 통합했다.

그리고 CI에서 또 한바탕했다.

내가 만드는 소설 생성 프로젝트에 에러 처리 클래스가 있었다.

에러를 분류하고 에러 코드를 LLM한테 돌려주는 기능이었다.

227줄짜리 커스텀 코드였다.

근데 조사해보니, 내가 쓰는 프레임워크가 이미 이 기능을 제공하고 있었다.

프레임워크에는 구조화된 출력이랑 응답 검증기가 있다.

구조화된 출력은 LLM 응답을 자동으로 JSON으로 파싱하고 스키마로 검증한다.

응답 검증기는 검증이 실패하면 에러 메시지를 LLM한테 돌려주고 재시도한다.

내가 직접 만든 에러 클래스가 하던 일이 이거였다.

에러를 분류해서 코드를 만들고 그 코드를 LLM한테 돌려주는. 근데 프레임워크가 이미 더 잘하고 있었다.

교체

그래서 에러 클래스를 지웠다.

파싱 에러는 구조화된 출력으로 대체했다.

검증 에러랑 데이터베이스 에러는 그냥 에러를 던지는 걸로 단순화했다.

워크플로우가 실패 상태를 처리한다.

227줄이 사라졌다.

지우니까 코드가 단순해졌다.

그리고 프레임워크가 검증한 방식이라 더 안정적이다.

내가 만든 건 내가 관리해야 하는데, 프레임워크 건은 프레임워크가 관리한다.

교훈: 직접 만들기 전에 프레임워크를 확인하라

이 교훈은 명확하다.

직접 만들기 전에, 프레임워크가 이미 제공하는지 확인해야 한다.

내가 만든 코드는 내가 유지보수해야 한다.

프레임워크 코드는 프레임워크가 유지보수한다.

“있는지 몰라서” 직접 만드는 경우가 많다.

근데 그 비용은 계속 쌓인다.

버그가 나면 내가 고쳐야 하고 프레임워크가 업그레이드되면 내 코드가 안 맞을 수 있다.

프레임워크 내장 기능을 쓰면 이런 부담이 없다.

린터를 하나로 통합하다

여러 프로젝트에서 ESLint랑 Prettier를 쓰고 있었다.

근데 의존성이 여섯 개나 됐다.

ESLint, Prettier, 플러그인, 설정, 파서까지. 설정 파일도 각자 있었다.

그래서 Biome라는 린터로 통합했다.

의존성 여섯 개가 하나로 줄었다.

Rust 기반이라 10배에서 30배 빠르다.

그리고 모노레포를 지원해서 루트 설정 하나로 하위 패키지들이 상속한다.

마이그레이션

마이그레이션은 깔끔했다.

설정 파일 여섯 개를 만들고 옛날 파일 다섯 개를 지웠다.

자동 수정으로 16개 파일의 포맷이 통일됐다.

따옴표 통일, 임포트 정렬, 포맷팅이 한 번에 정리됐다.

버전 차이에서 오는 함정도 있었다.

이전 버전 문법을 쓰면 무시된다.

자동 감지 기능을 믿고 설정을 단순화했다.

CI에서 또 삽질

회사 프로젝트에서 CI 테스트가 또 멈췄다.

555개 테스트가 전부 통과했는데, exit code 1이 나온다.

CI 로그에 4분 공백이 있다.

뭔가 멈춘 거다.

“이전에 커버리지 플래그가 원인이었지”라고 생각하고 수정했다.

근데 이게 진짜 원인이 아니었다.

비슷한 다른 PR은 같은 플래그를 쓰는데 통과했다.

진짜 원인은 의존성 범위였다.

이 PR은 변경된 파일이 더 많은 의존성을 끌어와서 실행되는 테스트 묶음이 더 많았다.

48개 묶음이 돌아간 반면, 통과하는 PR은 36개만 돌았다.

묶음이 많으니까 워커 프로세스가 깔끔하게 종료되지 않은 거다.

“당연한 원인”이 틀릴 때가 있다.

커버리지 플래그가 의심스러웠지만 진짜 원인은 의존성 범위였다.

가설을 세우되, 그 가설을 다른 데이터로 검증해야 한다.

일일 배포 범위

알림 설정 기능을 일일 배포했다.

공통 패키지를 건드렸더니 배포 범위 추론이 21개 앱을 잡았다.

공통 패키지 변경은 여러 앱에 영향을 주니까. 근데 실제로는 5개 앱만 배포하면 됐다.

티켓 범위랑 실제 영향을 비교해서 21개를 5개로 줄였다.

자동 추론은 보수적으로 잡으니까, 실제 범위랑 비교해서 줄이는 게 필요하다.

마무리

이날의 핵심은 “덜 만드는 게 더 낫다”는 거다.

에러 클래스 227줄을 지웠다.

프레임워크가 이미 제공하는 걸 직접 만들고 있었다.

지우니까 코드가 단순해지고 유지보수 부담도 줄었다.

린터를 하나로 통합했다.

여섯 개 의존성이 하나로 줄었다.

설정도 단순해졌다.

직접 만드는 건 비용이다.

이미 있는 걸 쓰는 게 더 낫다.

“있는지 확인하기 귀찮아서” 직접 만들면, 그 비용은 계속 쌓인다.

있는지 확인하는 시간이 직접 만들고 유지보수하는 시간보다 훨씬 적다.