회귀(Regression)

박지예·2026년 8월 15일

공부2026

목록 보기
16/20

이전에 정상 동작하던 기능이 코드 변경 이후에 깨지는 현상이다.

새 기능 추가,버그 수정, 리팩토링, 라이브러리 업데이트 등 "좋은 의도의 변경"이 원인이라는 점이 핵심이다.

좋은 변경을 하였지만 발생한 나쁜 버그..

즉, 회귀는 새 기능의 변경이 아니라, 이미 검증된 영역이 뒤로 후퇴한 것이다.

왜 생기나

  • 숨은 결합 : 싱글톤, static 필드, scriptableobject 공유 인스턴스처럼 호출 관계에 들어나지 않는 의존성, A를 고쳤는데 B가 깨지는 전형적인 경로

  • 불안전한 이해 상태의 수정 : 증상만 눌러놓으면 원인이 다른 경로로 다시 표출된다.

  • 환경 변동 : Unity에디터 버전 업, SDK/플러그인 갱신, Android OS 업데이트 등

  • 머지 사고 : 잘못된 병합으로 이전 수정이 되돌아가는 경우

회귀의 종류

  • 기능 회귀 : 특정 조건에서 이벤트 트리거 실패

  • 성능 회귀 : 프레임 당 GC Alloc 증가, SetPass Call 증가, 로딩&빌드 시간 증가

  • 시각적 회귀 : URP 설정 & 쉐이더 변경으로 특정 기기에서 색 알파 깨짐 등

  • 데이터 호환성 회귀 : 세이브 스키마 변경 후 구 버전 유지 데이터 로드 실패

회귀 테스트

이러한 회귀를 잡는 테스트를 "회귀 테스트" 라고 한다.

회귀를 잡기 위해선 기존 기능을 언제든지 재실행 가능한 환경이 구축되어 있어야 한다.

  1. 버그를 재현하는 테스트를 먼저 작성한다. 실패를 확인한 뒤 고친다. 이 테스트 자체가 회귀를 1차로 방어하는 방어선이 된다.

  2. 순수 로직을 EditMode 테스트로 분리한다.
    재화 계산, 스탯 성장 공식, 확률 테이블 처럼 Monobehaviour에 묶이지 않은 부분이 회귀 비용 대비 효과가 좋다. 여기서 로직이 컴포넌트에 붙어 있으면 테스트가 불가능 하므로, 테스트 용이성이 곧 설계 기준으로 작용한다.

  3. PlayMode 테스트는 통합 시나리오에서만 최소한으로 쓴다. 느리고 깨지기 쉬워서 과하게 두면 유지보수에 어렵다.

  4. 성능을 수치로 고정한다. Unity Performance Testing Package나 Profiler Marker 로 GC Alloc 프레임 타임에 예산선을 걸고 CI 에서 초과시 실패시킨다.

배포 단계의 방어선

테스트로도 못 잡는 회귀가 많기 때문에 배포 자체를 방어선으로 써야 한다.

  1. CI 자동 빌드 : 커밋마다 실제 빌드가 통과하는지 확인. 에디터에서만 되는 코드가 의외로 많다.

  2. 단계적 출시 : Google Play 단계적 배포나 Apple Phased Release로 단계적으로 열어서 크래시율&ANR(안드로이드에서 앱이 응답하지 않는 상태)&핵심 지표를 관찰한다.

3.원격 설정 kill 스위치 : 신규 기능을 서버 플래그로 끌 수 있게 해두면 회귀 대응이 재배포가 아니라 설정 변경이 된다.


회귀 대응의 본질은 "버그를 다 잡는 것"이 아니라 같은 버그가 2번 나오지 않게 만드는 것이다. 고칠때 마다 그 수정을 고정하는 테스트를 남기면 그 테스트 스위트(묶어놓은 집합) 가 프로젝트의 회귀 이력 그 자체가 된다.

profile
게임 클라이언트 개발자

0개의 댓글