Skip to main content

Laravel Pennant란

Laravel Pennant는 단순하고 가벼운 기능 플래그(Feature Flag) 패키지입니다. 기능 플래그를 사용하면 새로운 기능을 단계적으로 롤아웃하거나, A/B 테스트를 실시하거나, 트렁크 기반 개발을 보완할 수 있습니다.

기능 플래그란

기능 플래그를 사용하면 코드의 배포와 릴리스를 분리할 수 있습니다. 코드는 프로덕션 환경에 배포해두면서, 기능의 ON/OFF를 설정으로 제어할 수 있습니다.

설치

1

패키지 설치

Composer를 사용해 Pennant를 설치합니다.
2

설정 파일과 마이그레이션 공개

vendor:publish Artisan 명령으로 파일을 공개합니다.
이를 통해 config/pennant.phpdatabase/migrations에 마이그레이션 파일이 생성됩니다.
3

마이그레이션 실행

Pennant가 기능 플래그 값을 저장하는 features 테이블을 생성합니다.

설정

config/pennant.php에서 사용할 스토리지 드라이버를 설정할 수 있습니다. Pennant는 두 종류의 드라이버를 지원합니다.

기능 정의

클로저 기반 정의

기능은 Feature 파사드의 define 메서드로 정의합니다. 보통 서비스 프로바이더의 boot 메서드에서 정의합니다. 클로저에는 “스코프”(보통 인증된 사용자)가 전달됩니다.
이 기능의 로직은 다음과 같습니다.
  • 사내 팀 멤버는 반드시 ON
  • 트래픽이 많은 고객은 OFF
  • 그 외에는 1% 확률로 ON
기능이 처음 체크될 때 클로저의 결과가 스토리지 드라이버에 저장됩니다. 다음번부터는 저장된 값이 사용됩니다.
정의가 Lottery만 반환하는 경우 클로저를 생략할 수 있습니다.

클래스 기반 정의

Pennant는 클래스 기반의 기능 정의도 지원합니다. 클래스 기반인 경우 서비스 프로바이더에 대한 등록은 불필요합니다.
생성된 클래스는 app/Features 디렉터리에 배치됩니다. resolve 메서드를 구현하기만 하면 됩니다.

저장명 커스터마이즈

기본적으로 완전 수식 클래스명이 저장됩니다. Name 애트리뷰트로 이름을 커스터마이즈할 수 있습니다.

기능 체크 가로채기 (before 메서드)

클래스 기반 기능에는 before 메서드를 정의할 수 있습니다. 이 메서드는 스토리지에서 값을 가져오기 전에 인메모리에서 실행되며, null 이외의 값을 반환하면 그 값이 사용됩니다.
before 메서드는 버그 발생 시 기능을 긴급 비활성화하거나, 특정 일시에 롤아웃을 스케줄링할 때 유용합니다.

기능 확인

Feature::active() / Feature::inactive()

active 메서드로 기능이 활성화되어 있는지 확인할 수 있습니다. 기본적으로 현재 인증된 사용자에 대해 체크가 수행됩니다.
클래스 기반 기능인 경우 클래스명을 전달합니다.
그 밖에 편리한 메서드도 준비되어 있습니다.

조건부 실행 (when / unless)

when 메서드를 사용하면 기능이 활성화되어 있는 경우에만 클로저를 실행할 수 있습니다.
unlesswhen의 반대로, 기능이 비활성화되어 있는 경우에 첫 번째 클로저를 실행합니다.

HasFeatures 트레이트

HasFeatures 트레이트를 User 모델에 추가하면, 모델에서 직접 기능을 체크할 수 있습니다.

Blade 디렉티브

Blade 템플릿에서는 @feature 디렉티브를 사용할 수 있습니다.

미들웨어

EnsureFeaturesAreActive 미들웨어를 사용하면 라우트 접근에 기능이 필요함을 지정할 수 있습니다. 기능이 비활성화되어 있는 경우 400 Bad Request가 반환됩니다.
응답을 커스터마이즈하려면 whenInactive 메서드를 사용합니다.

인메모리 캐시

Pennant는 1리퀘스트 내에서 기능의 결과를 인메모리에 캐시합니다. 같은 기능 플래그를 여러 번 체크해도 추가 DB 쿼리는 발생하지 않습니다. 캐시를 수동으로 클리어하려면 flushCache 메서드를 사용합니다.

스코프

스코프 지정

기본적으로 인증된 사용자가 스코프가 되지만, for 메서드로 임의의 스코프를 지정할 수 있습니다.
팀별로 기능을 관리하는 예입니다.

기본 스코프 커스터마이즈

Feature::resolveScopeUsing으로 기본 스코프를 커스터마이즈할 수 있습니다.
설정 후에는 for를 생략하면 기본 스코프가 사용됩니다.

Nullable Scope

스코프가 null인 경우(미인증 라우트, Artisan 명령 등), 기능 정의가 null에 대응하지 않으면 자동으로 false가 반환됩니다. null을 다루는 경우 nullable 타입으로 정의해 주세요.

리치 기능 값

기능은 boolean 이외의 값도 반환할 수 있습니다. 예를 들어 A/B 테스트에서 버튼의 색상을 제어하는 경우입니다.
값을 가져오려면 value 메서드를 사용합니다.
Blade에서는 값을 사용한 조건 분기도 가능합니다.
리치 값을 사용하는 경우, false 이외의 모든 값이 활성으로 간주됩니다.
when 메서드에 리치 값이 전달되는 경우, 첫 번째 클로저에 값이 전달됩니다.

여러 기능 가져오기

values 메서드로 여러 기능의 값을 한 번에 가져올 수 있습니다.
all 메서드로 정의된 모든 기능의 값을 가져올 수 있습니다.
클래스 기반 기능을 all의 결과에 포함시키려면 서비스 프로바이더에서 discover를 호출합니다.
이를 통해 app/Features 디렉터리의 모든 기능 클래스가 등록됩니다.

Eager Loading

루프 안에서 기능 체크를 수행하는 경우 성능 문제가 발생할 수 있습니다. load 메서드를 사용해 미리 값을 가져와 두면 해결할 수 있습니다.
미취득 값만 가져오려면 loadMissing을 사용합니다.

값 업데이트

수동 업데이트

activate / deactivate 메서드로 기능의 ON/OFF를 전환할 수 있습니다.
저장된 값을 잊게 하려면 forget 메서드를 사용합니다. 다음 체크 시에 정의로부터 재평가됩니다.

일괄 업데이트

activateForEveryone / deactivateForEveryone으로 스토리지 내 모든 스코프에 일괄 적용할 수 있습니다.

기능 퍼지

기능을 애플리케이션에서 삭제한 경우나 정의를 변경한 경우, 스토리지에서 값을 삭제(퍼지)할 수 있습니다.
Artisan 명령으로도 퍼지할 수 있습니다. 배포 파이프라인에 통합하면 편리합니다.

테스트

기능 재정의

테스트에서는 Feature::define으로 기능을 재정의함으로써 반환 값을 제어할 수 있습니다.
tab=Pest
tab=PHPUnit
클래스 기반 기능도 마찬가지로 다룰 수 있습니다.
tab=Pest
tab=PHPUnit

테스트용 스토어 설정

테스트 중에 사용할 스토어를 phpunit.xml의 환경 변수로 지정할 수 있습니다.

커스텀 드라이버

기존 드라이버가 요건에 맞지 않는 경우, 커스텀 드라이버를 작성할 수 있습니다. Laravel\Pennant\Contracts\Driver 인터페이스를 구현합니다.
서비스 프로바이더의 boot 메서드에서 extend를 호출해 등록합니다.
등록 후에는 config/pennant.php에서 드라이버를 지정할 수 있습니다.

정리

다음 단계

디버그와 에러 핸들링

애플리케이션의 예외 처리와 리포트의 구조를 배웁니다.

Laravel Pulse

애플리케이션의 성능 모니터링 대시보드를 도입합니다.
마지막 수정일 2026년 7월 13일