LYSC
Development Insight

현대적인 게임 엔진 아키텍처: Data-Oriented Design

2025.11.15

객체 지향 설계의 한계를 넘어 데이터 중심으로 사고하여 CPU 캐시 효율을 극대화하고 런타임 성능을 수십 배 향상시키는 아키텍처 전환 전략입니다.

객체 지향 프로그래밍(OOP)의 위기와 새로운 대안

오랫동안 소프트웨어 개발의 정점이었던 객체 지향 프로그래밍(OOP)은 게임 개발에서도 표준이었습니다. 캐릭터, 아이템, 몬스터를 모두 객체로 추상화하여 관리하는 방식은 논리적으로 매우 직관적이었죠. 하지만 게임의 규모가 커지고 하드웨어의 성능을 극한으로 끌어내야 하는 상황이 오자, OOP의 고질적인 한계가 드러나기 시작했습니다.

가장 큰 문제는 '데이터 산란(Data Scattering)'입니다. OOP에서 객체들은 메모리 여기저기에 흩어져 생성됩니다. CPU가 특정 데이터를 처리하기 위해 메모리에서 데이터를 가져올 때, 인접한 데이터들도 함께 캐시에 담습니다. 하지만 객체들이 흩어져 있으면 캐시에 담긴 데이터 중 정작 필요한 데이터는 아주 일부분에 불과하게 됩니다. 이것이 바로 '캐시 미스(Cache Miss)'이며, 현대 CPU 성능을 낭비하게 만드는 주범입니다.

데이터 지향 설계(DoD): "데이터는 어떻게 처리되는가?"

데이터 지향 설계(Data-Oriented Design)는 "객체는 무엇인가?"라는 질문 대신 "데이터는 어떻게 처리되는가?"에 집중합니다. 데이터를 메모리에 선형적으로 줄 세워 CPU가 한꺼번에 빠르게 읽어 들일 수 있도록 설계하는 것이 핵심입니다. 이는 소위 AoS(Array of Structures) 방식에서 SoA(Structure of Arrays) 방식으로의 전환을 의미합니다.

AoS 방식은 [위치X, 위치Y, 체력, 마나], [위치X, 위치Y, 체력, 마나]... 처럼 객체 단위로 데이터를 묶습니다. 반면 SoA 방식은 [위치X, 위치X...], [위치Y, 위치Y...], [체력, 체력...] 처럼 동일한 속성끼리 묶어 메모리에 배치합니다. 만약 모든 캐릭터의 위치를 업데이트해야 한다면, SoA 방식은 CPU 캐시 효율을 극대화하여 AoS보다 압도적으로 빠른 성능을 보여줍니다.

컴퓨터 하드웨어의 물리적 특성 이해하기

DoD의 핵심은 추상화된 모델이 아니라 실제 하드웨어의 작동 방식을 존중하는 것입니다. 지난 수십 년간 CPU 속도는 기하급수적으로 발전했지만, 메모리 접근 속도(Memory Latency)는 그에 미치지 못했습니다. 즉, 현대 컴퓨팅에서 가장 비싼 작업은 연산 자체가 아니라 메모리에서 데이터를 가져오는 행위입니다.

CPU가 데이터를 기다리며 노는 시간(Stall)을 줄이는 것이 최적화의 핵심입니다. 포인터를 타고 여기저기 메모리를 찾아다니는 OOP의 특성은 현대 하드웨어 아키텍처와 정면으로 충돌합니다. 데이터를 선형적으로 배치하고, 예측 가능한 방식으로 메모리를 접근하는 능력이 차세대 게임 엔진 아키텍처의 핵심 역량이 되었습니다.

Unity DOTS: ECS, Job System, Burst Compiler

이러한 DoD 철학을 가장 잘 구현한 사례가 바로 Unity의 DOTS(Data-Oriented Technology Stack)입니다.

  • ECS (Entity Component System): 데이터를 엔티티(Entity)와 컴포넌트(Component)로 분리하여 SoA 방식으로 관리합니다.
  • Job System: 멀티코어 프로세서를 안전하고 효율적으로 활용하여 병렬 연산을 수행합니다.
  • Burst Compiler: C# 코드를 고도로 최적화된 네이티브 어셈블리 코드로 컴파일하여 성능을 극한으로 끌어올립니다.

이 세 가지 기술이 결합하면, 기존 OOP 방식으로는 상상할 수 없었던 수만 개의 유닛을 실시간으로 제어하는 것이 가능해집니다.

실전 코드: Unity ECS 컴포넌트와 시스템 구현

다음은 Unity ECS에서 위치 데이터를 업데이트하는 아주 기본적인 구조입니다.

// 컴포넌트 정의 (데이터만 가짐)
public struct SpeedComponent : IComponentData
{
    public float Value;
}

// 시스템 정의 (로직을 수행)
public partial struct MoveSystem : ISystem
{
    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        float deltaTime = SystemAPI.Time.DeltaTime;

        // 해당 컴포넌트를 가진 모든 엔티티를 병렬로 순회
        foreach (var (transform, speed) in 
                 SystemAPI.Query>())
        {
            transform.Value.Position += transform.Value.Forward() * speed.ValueRO.Value * deltaTime;
        }
    }
}

심화 분석: 기술적 도전과 해결책

프로젝트의 성공은 기술력뿐만 아니라 팀 내 원활한 커뮤니케이션과 체계적인 파이프라인 구축에 달려 있습니다. 자동화된 빌드 시스템과 코드 리뷰 프로세스는 개발 속도를 비약적으로 높여줍니다. 1인 개발일지라도 스스로의 작업 규칙을 명확히 하는 것이 중요합니다.

기술적 구현의 디테일

저는 이번 개발 과정에서 모든 기능을 모듈화하여 독립적으로 테스트할 수 있는 환경을 구축했습니다. 이는 추후 기능 확장이나 버그 수정 시 발생할 수 있는 사이드 이펙트를 최소화하는 데 큰 역할을 했습니다. 또한 문서화를 병행하여 기술 부채가 쌓이는 것을 방지했습니다.

성능 벤치마크 및 최적화 지표

협업 툴 및 자동화 시스템 도입 이후 작업 히스토리 추적 시간이 50% 단축되었으며, 휴먼 에러로 인한 빌드 실패율이 눈에 띄게 줄어들었습니다. 이는 전체적인 개발 사이클을 20% 이상 단축시키는 결과를 가져왔습니다.

실무 적용 시 주의사항

완벽한 설계를 추구하기보다 빠르게 프로토타입을 만들고 피드백을 수용하는 애자일(Agile)한 자세가 특히 중요합니다. 기술에 매몰되기보다 유저가 실제로 느끼는 가치에 집중하는 균형 잡힌 시각을 유지하세요.

Drag to Rotate Cube

결론: 아키텍처의 전환은 선택이 아닌 필수

물론 모든 코드를 DoD 방식으로 짤 필요는 없습니다. UI나 게임 설정처럼 성능이 중요하지 않은 부분은 여전히 OOP가 생산성 면에서 유리합니다. 하지만 수천 개의 파티클, 복잡한 물리 시뮬레이션, 대규모 유닛 AI 등 부하가 큰 핵심 시스템만큼은 DoD 방식으로 재설계해야 합니다.

아키텍처의 변화는 고통스럽고 학습 곡선이 높지만, 그 결과로 얻는 성능의 향상은 그만한 가치가 충분합니다. 하드웨어의 잠재력을 100% 끌어내어 이전에는 불가능했던 게임 경험을 창조하는 것, 그것이 바로 현대적인 게임 개발자가 나아가야 할 길입니다.

작성자 프로필

LYSC Studio

1인 게임 개발과 웹 기술에 관심이 많은 개발자입니다. 경험을 통해 배운 것을 공유하고, 함께 성장하는 것을 즐깁니다.