"깊이"가 다른 게임개발자 허민영

유저에서 게임까지, 철학에서 코딩까지, 본질을 보는 게임개발

소프트웨어 공학/아키텍처 및 구조론

제3정규화(3NF)의 원칙과 필드 선언의 정제

허민영 2025. 4. 8. 19:47

데이터베이스 설계에서의 **제3정규화(Third Normal Form, 3NF)**는, 제2정규화를 만족하는 상태에서 비-키 속성이 기본 키에 이행적으로 종속되는 관계를 제거하는 정규화 단계이다. 즉, 모든 비-키 속성은 직접적으로 기본 키에만 종속되어야 하며, 다른 비-키 속성을 통해 간접적으로 결정되는 경우는 허용되지 않는다.

예를 들어 다음과 같은 테이블을 살펴보자.


ItemID ItemName CategoryID CategoryName
101 Iron Sword 1 Weapon

위 테이블에서 기본 키는 ItemID이다. 이때 CategoryName은 CategoryID에 의해 결정되므로, ItemID → CategoryID → CategoryName이라는 이행적 종속이 존재한다. 이처럼 비-키 속성이 또 다른 비-키 속성에 의존할 경우, 데이터의 일관성과 유지보수성이 저해되며, 제3정규화를 위반하게 된다. 이를 해결하기 위해선 Category 정보를 별도의 테이블로 분리하고 Item은 참조만 하도록 구조화해야 한다.


제3정규화와 필드 선언의 연결점

이러한 정규화 원칙은 객체지향 프로그래밍, 특히 데이터 중심의 설계 구조에서도 유사한 문제로 나타난다. 대표적으로 Unity 개발에서 자주 활용되는 ScriptableObject 기반 필드 선언에서, 한 데이터 오브젝트에 직접적인 속성뿐 아니라 문맥적, 파생적 정보까지 함께 선언하는 실수가 발생하곤 한다.

즉, 어떤 데이터가 객체의 본질적인 속성이 아니라 다른 필드를 통해 결정되거나 유도되는 값임에도, 필드로 선언되어 버리는 경우가 많다. 이는 곧 이행적 종속을 객체 내부에 포함시키는 결과로 이어지며, 데이터 구조가 정제되지 못하고, 변경 시 불필요한 수정 범위를 발생시키게 된다.


예시: ScriptableObject 필드 설계의 문제점

[CreateAssetMenu(menuName = "Game/Skill")]
public class SkillData : ScriptableObject
{
    public string skillName;
    public int basePower;
    public float cooldown;

    public string characterClassName;
    public int requiredLevel;
}

이 예시에서 characterClassName과 requiredLevel은 SkillData가 직접 소유할 필요가 없는 정보다. 스킬이 어떤 클래스에서 어떤 조건으로 사용 가능한지는 **문맥(Context)**의 문제이지, 스킬 자체의 정체성에 속한 정보는 아니다. 하지만 이처럼 포함해버릴 경우, 클래스 조건이 변경되거나 클래스 자체가 재설계될 때, 관련된 모든 SkillData 에셋이 영향을 받게 된다.


리팩토링: 문맥 정보의 외부 위임

제3정규화의 원칙에 따라 이행적 종속 관계를 제거하고, 문맥적 정보는 별도의 매핑 구조로 분리한다.

[CreateAssetMenu(menuName = "Game/Skill")]
public class SkillData : ScriptableObject
{
    public string skillName;
    public int basePower;
    public float cooldown;
}

[CreateAssetMenu(menuName = "Game/ClassSkillMapping")]
public class ClassSkillRule : ScriptableObject
{
    public CharacterClassData characterClass;
    public SkillData skill;
    public int requiredLevel;
}

 

이 구조에서는 SkillData가 자신의 본질적인 속성만 보유하며, 사용 조건은 ClassSkillRule이라는 별도의 객체를 통해 관리된다. 이로써 데이터의 응집도가 높아지고, 책임이 분리되며, 구조적 확장성도 향상된다. 예를 들어 클래스 조건이 바뀌더라도, ClassSkillRule만 수정하면 되고, 스킬 데이터 자체는 변경되지 않는다.


결론

제3정규화는 이행적 종속을 제거하여 데이터의 의미적 명확성과 구조적 응집력을 확보하는 설계 원칙이다. 이 원칙은 필드 선언과 객체 설계에서도 동일하게 적용될 수 있다. 불필요하게 포함된 파생 정보는 정제하여 제거하고, 문맥적 책임은 외부 객체나 관계 데이터로 분리함으로써, 보다 깔끔하고 유연한 시스템 구조를 구성할 수 있다. 특히 ScriptableObject를 기반으로 하는 Unity 환경에서는 이러한 정제된 선언 습관이 데이터 에셋의 안정성과 관리 효율성에 큰 영향을 미친다.