GPT-5와 기술 부채에 대한 경험과 생각

1. 이전 AI 활용 방식과 변화

  • 과거에는 AI를 작은 단위 작업에 활용
    → 내가 직접 설계한 틀을 AI에게 검토시킨 뒤, 피드백을 반영해 점진적으로 구현
  • GPT-5 업데이트 후 코딩 능력 강화가 두드러짐
    → 이번에는 3개 이상의 클래스를 한 번에 생성·수정하도록 요청

2. 이번 사례

  • TurnLevel에서 전투를 위해 CombatManager 구현
  • GPT-5 제안 구조 중, Character와 전투 상태 관련 로직을 COEGameInstance에 병합
  • CharacterCombatManager 연결을 위해 TurnCombatBridgeComponent를 상속한 블루프린트를 할당
  • 결과: 오타·실수 외에는 첫 컴파일에서 성공
    → 기존 방식 대비 작업 시간 6시간 → 3시간 단축

3. 느낀 점

  • AI가 대부분의 코드를 작성해도 사람이 전체 구조와 로직을 이해·검토해야 함
  • 구현된 함수와 변수를 확인하는 과정 때문에 시간 단축 효과는 제한적
  • 이후 기능 추가·유지보수 시 기술 부채 가능성
    • AI가 기존 코드 일부만 수정하지 않고 전체를 재작성하는 경우가 잦아 위험
    • 불필요한 흐름 변경 및 예기치 못한 문제 발생 위험
    • 문제가 생겨도 AI는 책임지지 않음

4. 결론

  • AI에게 모든 것을 맡기는 것은 위험 → 최종 검토와 책임은 반드시 사람의 몫
  • AI를 그대로 쓰면 개발자의 실력이 정체될 수 있음
    • AI를 활용하는 능력도 개발자의 필요 능력으로 자리잡고 있기 때문에 개발자 본인의 개발 능력에 AI 활용능력도 습득이 필요
  • 기업 입장에서는
    • 잘하는 중·고급 개발자가 주니어 업무를 AI로 보조
    • 단순 작업은 비전문 인력 + AI 조합이 더 효율적일 수 있음

' > 공부' 카테고리의 다른 글

Claude 사용기  (3) 2025.08.22
Unreala CollisionChannel Issue 정리  (1) 2025.08.05

DECLARE_MULTICAST_DELEGATE관련 이슈

  • 최초에는 FOnTurnEnemyDead OnDead를 UPROPERTY를 통해 BlueprintAssignable 속성을 부여했으나DECLARE_MULTICAST_DELEGATE는 정적(C++) 타입이어서 등록되지 않음 이를 해결하기위해서는 동적(DYNAMIC) 델리케이트를 사용하거나 C++전용으로 UPROPERTY를 제거해야함 결국 아래와 같이 수정
// 완전 C++ 전용으로, UPROPERTY 제거
DECLARE_MULTICAST_DELEGATE(FOnTurnEnemyDead);
FOnTurnEnemyDead OnDead;
  • 오류 해결 이후에도 브로드캐스트 호출 시그니처 관련 이슈로 델리게이트 선언과 Broadcast 호출의 매개변수가 일치하지 않아 아래와 같이 수정
//수정 전
OnDead.Broadcast(DamageCauser);

//수정 후
OnDead.Broadcast();
  • 리스너(바인딩) 방식에서도 AddDynamic이 아닌 AddUObject로 수정
//수정 전
Enemy->OnDead.AddDynamic(this, &ATurnGameMode::OnEnemyDied);

//수정 후
Enemy->OnDead.AddUObject(this, &ATurnGameMode::OnEnemyDied);
  • 만일 델리게이트에서 파라미터로 AActor* 같은 인자를 넘기고 싶다면 아래와 같이 사용해야함
// 헤더
DECLARE_MULTICAST_DELEGATE_OneParam(FOnTurnEnemyDead, AActor*);
FOnTurnEnemyDead OnDead;

// CPP
OnDead.Broadcast(DamageCauser);

// 바인딩
Enemy->OnDead.AddUObject(this, &ATurnGameMode::OnEnemyDiedWithParam);
void OnEnemyDiedWithParam(AActor* Causer) { … }
  • 블루프린트 바인딩이 필요할때는 DYNAMIC 버전 필요
// 헤더
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnTurnEnemyDead, AActor*, DamageCauser);

UPROPERTY(BlueprintAssignable, Category="Combat")
FOnTurnEnemyDead OnDead;
  • 순수 C++전용 타입이라면 델리게이트선언에서 DYNAMIC 제거
  • Broadcast호출과 시그니처(매개변수 개수)는 일치해야함
    ex) DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnTurnEnemyDead, AActor*, DamageCauser);
  • 리스너등록(바인딩)은 순수 C++타입은 AddUObject 사용 블루프린트 바인딩 시 AddDynamic 사용
  • 필요시 파라미터 버전은 OneParam등 사용
//순수 C++ 델리게이트 (파라미터 없음)

//헤더
DECLARE_MULTICAST_DELEGATE(FOnTurnEnemyDead);

FOnTurnEnemyDead OnDead;

//Broadcast
OnDead.Broadcast();

//바인딩
Enemy->OnDead.AddUObject(this, &ATurnGameMode::OnEnemyDied);

void ATurnGameMode::OnEnemyDied()
{
    // 파라미터 없는 콜백
}

//순수 C++ 델리게이트 (파라미터 1개)

//헤더
DECLARE_MULTICAST_DELEGATE_OneParam(FOnTurnEnemyDead, AActor*);

FOnTurnEnemyDead OnDead;

//Broadcast
OnDead.Broadcast(DamageCauser);

//바인딩
Enemy->OnDead.AddUObject(this, &ATurnGameMode::OnEnemyDiedWithParam);

// 콜백
void ATurnGameMode::OnEnemyDiedWithParam(AActor* Causer)
{
    // Causer 처리
}

//동적(Dynamic) 델리게이트 (블루프린트 바인딩, 파라미터 없음)

//헤더
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnTurnEnemyDead);

UPROPERTY(BlueprintAssignable, Category="Combat")
FOnTurnEnemyDead OnDead;

//Broadcast
OnDead.Broadcast();

//바인딩
Enemy->OnDead.AddDynamic(this, &ATurnGameMode::OnEnemyDied);

// 콜백
UFUNCTION()  // 반드시 UFUNCTION() 필요
void OnEnemyDied();

void ATurnGameMode::OnEnemyDied()
{
    // 파라미터 없는 블루프린트 바인딩 콜백
}

//동적(Dynamic) 델리게이트 (블루프린트 바인딩, 파라미터 1개)

//헤더
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnTurnEnemyDead, AActor*, DamageCauser);

UPROPERTY(BlueprintAssignable, Category="Combat")
FOnTurnEnemyDead OnDead;

//Broadcast
OnDead.Broadcast(DamageCauser);

//바인딩
Enemy->OnDead.AddDynamic(this, &ATurnGameMode::OnEnemyDiedWithParam);

// 콜백
UFUNCTION()  // 반드시 UFUNCTION() 필요
void OnEnemyDiedWithParam(AActor* Causer);

void ATurnGameMode::OnEnemyDiedWithParam(AActor* Causer)
{
    // 파라미터로 전달된 Causer 처리
}

용도 선언 매크로 바인딩 Broadcast
순수 C++, 파라미터 없음 DECLARE_MULTICAST_DELEGATE AddUObject Broadcast()
순수 C++, 파라미터 있음 DECLARE_MULTICAST_DELEGATE_OneParam AddUObject Broadcast(param)
블루프린트, 파라미터 없음 DECLARE_DYNAMIC_MULTICAST_DELEGATE AddDynamic Broadcast()
블루프린트, 파라미터 있음 DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam AddDynamic Broadcast(param)

이슈 해결 후 추가로 찾아본 언리얼 엔진에서의 델리게이트 이론정리

  1. 델리게이트란?

    • 함수 포인터의 안전한 버전 == 함수를 저장해두었다가 나중에 호출할 수 있는 객체
  2. 왜 사용하는지?

    • 의존성 제거: Player가 UI 나 Sound 클래스를 몰라도 됨

    • 독립적 개발: 각 시스템을 따로 개발 가능

    • 테스트 용이: Player만 단독으로 테스트 가능

      // 직접 호출 방식 
      class APlayer : public APqwn 
      { 
      private: 
      AUIManager* UIManager; //직접 참조 필요 
      ASoundManager* SoundManager; //직접 참조 필요 
      AGameMode* GameMode; // 직접 참조 필요 
      public: 
      void TakeDamage(float Damage) 
      { 
          CurrentHealth -= Damage; 
          // 모든 시스템을 직접 호출 
          if (UIManager) UIManager->UpdateHealthBar(CurrentHealth); 
          if (SoundManager) SoundManager->PlayDamageSound(); 
          if (GameMode) GameMode->CheckGameOver(); 
      
           //새로운 시스템 추가시 이어서 수정 
      } 
      }; 
      // 델리게이트 방식 
      class APlayer : public APawn 
      { 
      public: 
      DECLARE_MULTICAST_DELEGATE_OneParam(FOnHealthChaged, float); 
      FOnHealthChange OnHealthChanged; 
      void TakeDamage(float Damge) 
      { 
          CurrentHealth -= Damage; 
      
          // 누가 듣고 있는지 몰라도 됨 
          OnHealthChanaged.Broadcast(CurrentHealth); 
      } 
      };
  3. 확장성

    • 이벤트 기반 아키텍처
      • Observer 패턴: 하나의 이벤트에 여러 관찰자
      • 발행 구독 모델: 이벤트 발생자와 처리자 분리
      • 비동기 처리: 이벤트 발생과 처리의 분리
    • 유지보수성
      • 단일 수정: 이벤트 로직만바꾸면 모든 곳에 적용
      • 버그 격리: 한 시스템 오류가 다른 시스템에는 영향 X
      • 코드 재사용: 같은 이벤트를 여러 곳에서 활용
    //새로운 시스템 추가가 쉬움 
    class AParticleManager : public AActor 
    { 
        void BeginPlay() override 
        { 
            //기존 Player 클래스 수정 없이 새 기능 추가 
            Player->OnHealthChanged.AddUObject(this,&AParticleManager::PlayBloodEffect); 
        } 
    };

' > 포트폴리오' 카테고리의 다른 글

포트폴리오 log #5  (2) 2025.07.31
포트폴리오 log #4  (4) 2025.07.17
포트폴리오 log #3  (0) 2025.07.16
포트폴리오 log #2  (0) 2025.07.15
포트폴리오 log #1  (0) 2025.07.11

+ Recent posts