입사 초에는 프리팹이 그저 미리 만들어 둔 화면 조각이라고 생각했다. 비슷한 목록이 필요하면 기존 프리팹을 복사하고 텍스트와 버튼만 바꾸면 빠르게 끝났다. 그런데 그렇게 만든 화면이 늘어나자 한 군데의 여백을 바꾸려고 여러 프리팹을 돌아다녀야 했다. 어떤 건 공통 스크립트를 쓰고 어떤 건 복사된 스크립트를 써서 수정 범위도 바로 보이지 않았다.
처음에는 파일 이름을 예쁘게 정리하는 작업으로 시작했다. 막상 연결 관계를 따라가다 보니 문제는 폴더보다 책임에 있었다. 화면 모양, 데이터 가공, 클릭 처리까지 하나의 컴포넌트가 전부 맡고 있었다.
외형과 동작의 구분
두 화면이 비슷해 보인다고 무조건 같은 프리팹으로 합칠 수는 없었다. 반대로 데이터만 다르고 배치와 동작이 같다면 복사본을 유지할 이유도 적었다. 그래서 먼저 바뀌는 부분을 적었다.
공통: 아이콘, 이름, 값, 선택 표시
다름: 값 포맷, 클릭 후 이동할 화면, 빈 상태 문구
공통인 모양은 하나의 아이템 프리팹에 두고, 달라지는 값은 바인딩할 때 넘겼다. 클릭 결과처럼 화면마다 의미가 다른 행동은 외부에서 주입하도록 했다.
데이터를 과도하게 아는 컴포넌트
기존 코드 중에는 아이템 하나가 전체 계좌 목록을 찾아 자기 값을 꺼내는 경우도 있었다. 당장은 편하지만 데이터 구조가 바뀌면 작은 UI까지 함께 수정해야 했다. 아이템은 이미 정리된 표시 값만 받게 바꿨다.
public void Bind(string name, string value, Action onClick)
{
nameText.text = name;
valueText.text = value;
button.onClick.RemoveAllListeners();
button.onClick.AddListener(() => onClick?.Invoke());
}
이렇게 해두니 아이템은 이름과 값을 어떻게 구했는지 몰라도 됐다. 값의 자릿수나 통화 포맷은 상위 화면에서 정리할 수 있었다.
공통화 경계
정리를 시작하면 모든 차이를 옵션으로 만들고 싶은 욕심이 생겼다. isA, isB, showExtra 같은 플래그가 계속 붙으면 하나로 합친 코드가 오히려 읽기 어려웠다. 공통 프리팹 안에서 조건문이 빠르게 늘어나는 부분은 별도 컴포넌트로 남겼다.
재사용은 파일 수를 줄이는 일이 아니라 변경 이유를 모으는 일에 가까웠다. 같은 이유로 함께 바뀌는 부분까지만 묶어야 했다.
프리팹 정리 기준
예전에는 중복 코드가 보이면 바로 합치는 게 리팩터링이라고 생각했다. 이번에는 무엇이 같아 보이는지보다 무엇 때문에 바뀌는지를 먼저 봤다. 화면 모양이 바뀔 때 함께 수정돼야 하는 것과, 업무 규칙이 달라서 따로 움직여야 하는 것을 구분했다.
프리팹 몇 개를 정리한 작은 작업이었지만 이후 코드를 볼 때 “이 컴포넌트가 여기까지 알아야 하나?”를 자주 묻게 됐다. 책임이라는 말이 책 속 개념이 아니라 다음 수정 범위를 결정하는 현실적인 기준으로 느껴지기 시작했다.
유사 문제 대응 기준
이 문제를 고친 뒤 관련 공식 자료를 찾아 읽으면서, 당시 코드에서 우연히 맞았던 부분과 규칙으로 남겨야 할 부분을 나눠 봤다.
Unity 실행 순서 문서는 Awake, OnEnable, Start, Update 같은 엔진 이벤트가 어느 구간에서 호출되는지 설명한다. 하지만 로딩·성공·빈 결과·실패 같은 업무 상태의 순서까지 대신 정해 주지는 않는다. 두 종류의 순서를 섞어 생각하면 콜백이 한 프레임 늦게 왔다는 이유만으로 이전 화면 상태가 다시 살아날 수 있다.
그래서 수명주기 메서드는 상태 전이를 직접 흩어 놓는 장소보다, 한 곳에 모인 전이 함수를 호출하는 경계로 쓰는 편이 추적하기 쉬웠다.
다음에 프리팹 정리와 코드 책임 같은 문제를 보면 아래 순서부터 확인하려고 한다.
- OnDisable·OnDestroy 중 실제 정리 시점
- 구독 해제와 취소 토큰의 소유자
- 닫힌 뒤 도착한 콜백 처리
- 다시 열었을 때 중복 등록 여부
새 응답을 적용하기 전에 요청 식별자와 현재 선택 조건이 여전히 같은지 확인해야 오래된 응답을 버릴 수 있다.
공식 참고 자료
- Unity 2021.3 이벤트 함수 실행 순서 — MonoBehaviour 이벤트와 프레임 단계의 실행 순서
- ECMA-334 C# 언어 사양 6판 — decimal·enum·예외를 포함한 C# 언어 규칙