Laravel 13에서는 이제 대부분의 모델을 복잡하게 만들던 $table, $fillable, $casts 속성을 네이티브 PHP 어트리뷰트(attributes)로 대체할 수 있습니다. 이 변화는 모델 설정부터 이벤트 리스너, 메일러블(mailables)에 이르기까지 12개 이상의 프레임워크 기능에 적용되며, 기존 코드를 깨뜨리지 않고 작동합니다.

Laravel이 네이티브 어트리뷰트를 추가한 이유

Laravel은 오랫동안 모델 클래스 상단에 위치하는 컬럼 이름이나 숨겨진 필드들의 배열인 "매직 스트링(magic strings)"에 의존해 왔습니다. 이러한 배열은 IDE가 기반 스키마에 대한 힌트를 얻을 수 없게 만들어, 컬럼 이름을 리팩터링할 때 이를 인지하지 못하고 지나칠 수 있습니다. 설정을 실제 타입이 지정된 코드로 이동함으로써, Laravel은 개발자가 클래스 본문을 비즈니스 로직에 집중할 수 있게 하는 동시에 에디터가 자동 완성, 타입 체크, 이름 변경 리팩터링 도구를 제공할 수 있도록 합니다.

프레임워크는 PHP의 reflection API를 통해 어트리뷰트를 읽고 그 결과를 캐싱하므로, 런타임 오버헤드는 사실상 제로입니다. 기존의 속성 기반 모델은 현재와 동일하게 계속 작동하므로, 새로운 구문을 점진적으로 도입할 수 있습니다.

얻을 수 있는 이점

  • 타입이 지정된 설정 – 어트리뷰트는 타입이 지정된 인수를 허용하여 매직 스트링을 제거합니다. 컬럼 이름을 변경하면 IDE가 업데이트가 필요한 모든 위치를 알려줍니다.
  • 더 깔끔한 클래스 본문 – 모든 설정이 클래스 이름 위에 위치하며, 클래스 본문에는 관계(relationships), 스코프(scopes), 메서드만 포함됩니다.
  • 더 나은 IDE 경험 – 문자열 배열로는 불가능한 어트리뷰트 인수에 대한 자동 완성 및 정적 분석이 가능해집니다.
  • 중단 없는 변경 – Laravel은 기존 속성과 새로운 어트리뷰트를 모두 읽을 수 있으므로, 혼합된 코드베이스에서도 문제없이 실행됩니다.

단계별 마이그레이션 가이드

  1. 마이그레이션할 모델 식별
    모델 파일을 엽니다. 파일의 처음 12줄 정도가 $table, $fillable, $hidden 또는 casts() 메서드로 채워져 있다면 마이그레이션 대상입니다.

  2. 어트리뷰트 클래스 추가
    파일 상단에 교체할 속성에 해당하는 어트리뷰트 클래스를 임포트합니다(예: Table, Fillable, Casts). Laravel은 이러한 어트리뷰트를 기본적으로 제공합니다.

  3. 속성 선언을 어트리뷰트로 교체

    // Before
    protected $table = 'site_deployments';
    protected $fillable = ['site_id', 'server_id', 'status'];
    protected function casts(): array
    {
        return ['is_rollback' => 'boolean'];
    }
    
    // After
    #[Table('site_deployments')]
    #[Fillable(['site_id', 'server_id', 'status'])]
    #[Casts(['is_rollback' => 'boolean'])]
    class Deployment extends Model
    {
        // business logic only
    }
    

    어트리뷰트 구문은 클래스 선언 바로 위에 위치합니다. 어트리뷰트가 정상적으로 작동하는 것을 확인한 후 기존 속성이나 메서드를 제거합니다.

  4. 테스트 스위트 실행
    대량 할당(mass-assignment), 직렬화(serialization) 및 모든 커스텀 캐스팅이 이전과 동일하게 작동하는지 확인합니다. Laravel의 어트리뷰트 처리는 캐싱되므로, 테스트 실패 시 대개 어트리뷰트 인수의 오타가 원인입니다.

  5. 소규모 단위로 커밋 및 배포
    마이그레이션된 모델을 기능 브랜치(feature branch)에 푸시하고, CI 파이프라인을 통과하면 머지한 뒤 서버 일부에 먼저 배포합니다. 기존 속성 구문이 여전히 지원되므로, 잘못된 참조가 있더라도 런타임 에러를 발생시키지 않습니다.

  6. 네임스페이스별로 반복
    전체 코드베이스를 한꺼번에 다시 작성하는 대신, 논리적인 모델 그룹(예: 모든 결제 관련 엔티티)을 먼저 어트리뷰트로 옮긴 후 다음 그룹으로 넘어갑니다. 이는 회귀 오류(regression)의 영향 범위를 제한합니다.

도구 및 안전장치

  • Rector – 반복적인 속성 구문을 어트리뷰트로 변환할 수 있는 자동화된 리팩터링 도구입니다. 코드베이스의 복사본에서 실행하여 차이점(diff)을 검토한 후, 올바르게 보이는 변경 사항만 적용하세요.
  • 자동화된 테스트 – Laravel의 내장 테스트 유틸리티는 대량 할당 및 JSON 출력의 불일치를 잡아냅니다. 각 마이그레이션 단계마다 테스트를 통과(green) 상태로 유지하세요.
  • 피처 플래그(Feature flags) – 빠른 롤백이 필요한 경우, 새로운 어트리뷰트 사용을 기존 설정과 새 설정 사이를 전환할 수 있는 플래그로 감싸세요.

마이그레이션을 건너뛰어도 되는 경우

프로젝트가 작고 안정적이며 거의 수정되지 않는다면, 모델을 깔끔하게 만드는 이점이 변환에 드는 노력보다 크지 않을 수 있습니다. 어트리뷰트 구문은 선택 사항입니다. 기존의 클래식한 속성 방식을 계속 사용할 수 있습니다. 반대로, 활발하게 개발 중인 애플리케이션, 특히 모델이 크거나 스키마 변경이 빈번한 경우에는 어트리뷰트를 조기에 도입하는 것이 향후 마찰을 줄여줍니다.

다음에 주목할 사항

Laravel 13의 어트리뷰트 지원은 모델을 넘어 이벤트 리스너, 알림(notifications), 메일러블(mailables), 브로드캐스트 이벤트로 확장됩니다. 커뮤니티에서 이러한 영역에 구문을 채택함에 따라 유사한 리팩터링 패턴이 나타날 것입니다. 향후 마이너 릴리스에서 추가될 새로운 어트리뷰트 클래스에 대해 공식 업그레이드 가이드를 계속 주시하세요.

핵심 요약: Laravel 13은 더 가볍고 IDE 친화적인 모델로 나아가는 비용 부담 없는 경로를 제공합니다. 한 번에 하나의 네임스페이스씩 변환하며 Rector와 테스트 스위트를 활용한다면, 설정 데이터가 쏟아져 나오는 파일이 아닌 마치 비즈니스 명세서처럼 읽히는 클래스를 완성할 수 있습니다.