فیچر فلگهای کلاسمحور با Laravel Pennant
خلاصهٔ کاملتر
به گفتهٔ تیم koomai، اونها از فیچر فلگها استفاده میکنن تا دیپلوی رو از ریلیز جدا کنن: کد به main مرج میشه و رو پروداکشن میره، ولی پشت یه فلگ خاموش میمونه تا وقتی خودشون تصمیم بگیرن روشنش کنن. معمولاً اول برای ادمینها، بعد کاربرهای بتا، بعد همه فعالش میکنن و اگه چیزی خراب شد، فقط فلگ رو خاموش میکنن؛ بدون هاتفیکس و بدون ریدیپلوی.
تو این روش هر فیچر یه کلاس تو app/Features/ هست که با پسوند Feature نامگذاری میشه و دو متد داره. متد before() کلید خاموشیه: Pennant قبل از اینکه سراغ استوریج بره، اونرو رو هر چک تو حافظه اجرا میکنه. اگه false برگردونه، فیچر برای همه خاموشه و اگه null برگردونه، نوبت به resolve() میرسه. resolve() تصمیم میگیره وقتی فیچر روشنه کی بهش دسترسی داره؛ اینجا فقط اعضای پرمیوم.
نکتهٔ اصلی اینجاست که مقدار resolve() ذخیره میشه. اولین بار که یه کاربر چک میشه، Pennant جواب resolve() رو تو جدول features مینویسه و از اون به بعد همون مقدار کششده رو میخونه. برای همین با عوضکردن resolve() نمیشه فیچر رو خاموش کرد، چون جوابهای قبلی تو دیتابیس موندن.
راهحل همون before() هست که رو هر ریکوئست تو حافظه اجرا میشه و هیچوقت ذخیره نمیشه. اونها این متد رو به یه مقدار کانفیگ وصل میکنن که خودش از یه متغیر محیطی خونده میشه:
public function before(User $scope): ?bool
{
if (! Config::get('features.create-events.enabled')) {
return false;
}
return null;
}پس با enabled=false، متد before() مقدار false برمیگردونه، resolve() اصلاً اجرا نمیشه و فیچر آنی برای همه خاموشه؛ بدون تغییر دیتابیس و بدون دیپلوی. کافیه env رو تو کانفیگ سرور برگردونی تا هر کاربر دقیقاً همونجایی که resolve() رهاش کرده برگرده، چون مقادیر ذخیرهشده دستنخورده میمونن.
یه قانون مهم هم هست: before() باید فقط false یا null برگردونه. اگه true برگردونه، کلاً resolve() رو دور میزنه و فیچر رو به همه میده که معمولاً یه footgun ـه؛ هرچند نویسنده میگه یه حالت خاص هست که همین کار درسته. اونها همیشه بهجای رشتهٔ اسم، مستقیم به کلاس فیچر (با ::class) ارجاع میدن تا تایپو و فلگ قدیمی موقع کامپایل لو بره نه اینکه بیصدا false خونده بشه. برای فرانتاند React هم فلگهای مشترک رو تو یه enum به اسم SharedFeatureFlag تعریف میکنن تا یه منبع حقیقت واحد و تایپسیف داشته باشن.
نکات کلیدی:
- هر فیچر یه کلاس تو app/Features/ با دو متد before() و resolve() هست
- before() کلید خاموشی درونحافظهایه؛ resolve() گروه هدف رو تعیین میکنه و کش میشه
- چون resolve() تو جدول features ذخیره میشه، خاموشکردن فیچر از راه before() و یه فلگ env انجام میشه
- before() فقط باید false یا null برگردونه؛ true کل منطق دسترسی رو دور میزنه
- ارجاع به فیچر با ::class و اشتراک فلگ با فرانتاند از راه یه enum تایپسیف




