유니티 [FormerlySerializedAs] 완벽 가이드: 리팩토링 시 인스펙터 데이터 유실 막는 법

안녕하세요, 유니티 개발자 여러분! 혹시 이런 경험 없으신가요? 스크립트에서 변수 이름의 오타를 발견하고 기분 좋게 수정했는데, 유니티 에디터로 돌아가 보니 인스펙터(Inspector)에 정성껏 설정해 둔 값들이 전부 초기화되어버린 허무한 경험 말입니다. 프리팹 수십 개에 연결된 값이었다면 아찔하기까지 하죠.
이런 대참사를 막아주는 마법 같은 어트리뷰트가 바로 [FormerlySerializedAs]입니다. 오늘은 이 강력하면서도 간단한 기능에 대해, 왜 필요한지부터 언제 어떻게 사용해야 하는지까지 완벽하게 파헤쳐 보겠습니다.
1. 문제의 시작: 왜 데이터는 사라지는가? - 유니티의 직렬화(Serialization)
이 문제를 이해하려면 먼저 유니티의 '직렬화(Serialization)'라는 개념을 알아야 합니다. 어렵게 들리지만 간단합니다. 유니티는 우리가 스크립트에 public으로 선언하거나 [SerializeField] 어트리뷰트를 붙인 변수의 값을 저장(직렬화)해서 씬(Scene) 파일이나 프리팹(Prefab) 에셋에 기록합니다.
중요한 점은, 유니티가 이 값을 저장할 때 '변수의 이름'을 기준(Key)으로 삼는다는 것입니다. 마치 각 데이터에 변수 이름이라는 이름표를 붙여두는 것과 같습니다.
예를 들어, public int playerScore; 라는 변수에 100을 할당했다면, 유니티는 어딘가에 "playerScore": 100 과 같은 형태로 정보를 저장합니다.
그런데 우리가 스크립트에서 이 변수 이름을 playerCurrentScore로 바꾸면 어떻게 될까요? 유니티는 이제 playerCurrentScore라는 새로운 이름표를 가진 변수를 찾지만, 저장된 데이터에는 playerScore라는 낡은 이름표만 있을 뿐입니다. 결국 유니티는 "이 데이터는 누구 것인지 모르겠다"고 판단하여 playerCurrentScore를 기본값인 0으로 초기화해버립니다. 이것이 바로 인스펙터 연결이 끊어지고 데이터가 유실되는 현상의 원인입니다.

2. 마법의 주문, [FormerlySerializedAs]의 등장
[FormerlySerializedAs]는 이런 상황을 위해 존재합니다. 이 어트리뷰트는 유니티에게 "지금 이 변수의 이름은 바뀌었지만, 예전엔 저 이름이었으니 그 데이터를 그대로 물려받게 해줘" 라고 알려주는 '개명 신청서' 같은 역할을 합니다.
사용법은 매우 간단합니다. 새로 바꾼 변수 선언부 바로 위에 대괄호 []와 함께 예전 변수 이름을 문자열로 적어주기만 하면 됩니다.
기본 문법:
[FormerlySerializedAs("옛날_변수_이름")]
public 변수타입 새로운_변수_이름;
실제 예시:
// (수정 전) public int playerScore;
// (수정 후)
[FormerlySerializedAs("playerScore")]
public int playerCurrentScore;
이렇게 하면, 유니티는 씬을 로드할 때 playerCurrentScore에 해당하는 값을 찾지 못하면, FormerlySerializedAs 어트리뷰트를 확인합니다. 그리고 "아, 옛날 이름이 playerScore였구나!" 하고 깨달은 뒤, 저장되어 있던 playerScore의 값 100을 playerCurrentScore에 안전하게 할당해 줍니다. 데이터 유실 없이 완벽하게 이름 변경이 완료되는 것입니다.
3. 이럴 때 꼭 사용하세요! 실전 활용법
그렇다면 이 어트리뷰트는 정확히 어떤 상황에서 사용해야 할까요? 대표적인 세 가지 사례를 알아보겠습니다.
① 변수 이름의 오타를 수정할 때 가장 흔하고 중요한 사용 사례입니다. 급하게 코드를 작성하다 보면 playerHelth나 maxEnegy 같은 오타는 비일비재합니다. 나중에 이 오타를 발견하고 playerHealth, maxEnergy로 수정할 때, 이 어트리뷰트가 없다면 해당 변수를 사용하는 모든 컴포넌트의 데이터가 초기화될 것입니다.
// 실수로 만든 오타가 있는 변수
// (전) public float playerHelth;
// 오타를 수정하며 어트리뷰트 추가
// (후)
[FormerlySerializedAs("playerHelth")]
public float playerHealth;
② 코드 가독성을 위해 리팩토링할 때 프로젝트 초반에 간단하게 temp나 value라고 지었던 변수들이 나중에는 어떤 용도인지 파악하기 어려워질 수 있습니다. 코드의 명확성과 유지보수성을 높이기 위해 변수 이름을 더 구체적으로 변경하는 리팩토링 과정에서 필수적입니다.
// 역할이 불분명한 변수 이름
// (전) public GameObject obj;
// 더 명확한 이름으로 리팩토링
// (후)
[FormerlySerializedAs("obj")]
public GameObject bulletPrefab;
③ 팀의 코딩 규칙(Convention)이 변경되었을 때 팀 프로젝트에서는 일관된 코딩 스타일을 유지하는 것이 중요합니다. 만약 변수명 앞에 언더스코어(_)를 붙이던 규칙에서 카멜 케이스(camelCase)로 규칙을 변경하기로 했다면, 기존 코드들을 수정할 때 이 어트리뷰트를 사용하여 안전하게 데이터를 마이그레이션할 수 있습니다.
// 언더스코어 규칙을 따르던 변수
// (전) public int _item_count;
// 새로운 카멜 케이스 규칙으로 변경
// (후)
[FormerlySerializedAs("_item_count")]
public int itemCount;
4. 마무리하며: 안전한 리팩토링의 첫걸음
[FormerlySerializedAs]는 사소해 보일 수 있지만, 프로젝트의 안정성을 크게 높여주는 중요한 기능입니다. 특히 규모가 큰 프로젝트나 여러 명의 팀원이 협업하는 환경에서는 데이터 유실로 인한 버그와 시간 낭비를 막아주는 생명줄과도 같습니다.
이제부터 유니티 인스펙터에 값이 할당된 변수의 이름을 바꿀 때는, [FormerlySerializedAs]를 추가하는 것을 습관화하여 예기치 못한 데이터 유실의 공포에서 벗어나 보세요. 여러분의 코드는 더 깔끔해지고, 프로젝트는 더욱 안정적으로 발전할 것입니다.

'Unity' 카테고리의 다른 글
| Unity 이벤트 값 전달이 안될 때? 99%는 이 문제입니다 (동적 vs 정적) (0) | 2025.08.21 |
|---|---|
| Unity Input Field 이벤트 완벽 정복: On Value Changed, On End Edit, On Select, On Deselect 비교 분석 및 활용법 (1) | 2025.08.21 |
| Unity Rider 프로젝트, .gitignore 교체 후 Git 캐시를 비워야 할까요? 완벽한 버전 관리를 위한 안내서 (0) | 2025.08.19 |
| 유니티 URP에서 마젠타 오류 해결하기: Render Pipeline Converter 완벽 가이드 (0) | 2025.08.12 |
| 유니티(Unity) 안드로이드 빌드 오류: Gradle Manifest 충돌 해결 가이드 (2) | 2025.08.11 |