رفتن به محتوای اصلی

SDK و هدف‌گیری Feature Flag

استفاده از identify، operatorهای شرط و APIهای React و Vanilla برای ارزیابی Feature Flag.

هدف‌گیری Feature Flag در آلفانا بر اساس ویژگی‌هایی انجام می‌شود که برای Visitor در اختیار SDK قرار گرفته‌اند. این ویژگی‌ها معمولاً از طریق identify() ثبت می‌شوند و هنگام ارزیابی Flag با Conditionهای تعریف‌شده در داشبورد مقایسه می‌شوند.

اگر یک Feature Flag بیش از یک Condition داشته باشد، تمام Conditionهای آن با منطق AND ترکیب می‌شوند. یعنی برای فعال شدن Flag، همه شرط‌های تعریف‌شده باید هم‌زمان برقرار باشند.

برای مثال، اگر Flag فقط برای کاربران Plan Pro در کشور ایران تعریف شده باشد، Visitor باید هر دو شرط را داشته باشد تا نتیجه ارزیابی true شود.

Operatorهای شرط#

Backend در نسخه فعلی از Operatorهای زیر برای ارزیابی Conditionها پشتیبانی می‌کند:

operatorمعنی
equalsبررسی برابری رشته‌ای بدون حساسیت به بزرگی یا کوچکی حروف
containsبررسی می‌کند مقدار Visitor شامل رشته موردنظر باشد
is_inبررسی می‌کند مقدار Visitor داخل فهرست comma-separated تعریف‌شده قرار داشته باشد

هر Condition یک property از Visitor را با مقدار تعریف‌شده برای Flag مقایسه می‌کند.

برای اینکه نتیجه Targeting قابل‌پیش‌بینی بماند، بهتر است propertyهایی که در Conditionها استفاده می‌شوند با Naming ثابت در کل محصول ارسال شوند.

ثبت ویژگی‌های Visitor#

ویژگی‌های موردنیاز برای Targeting را می‌توانید با identify() ثبت کنید:

typescript
tracker.identify({
  email: "user@example.com",
  plan: "pro",
  country: "IR",
});

identify() ویژگی‌های جدید Visitor را در اختیار Tracker قرار می‌دهد و می‌تواند باعث refresh شدن ارزیابی Feature Flagها شود.

در نسخه فعلی، identify() فقط مقدارهایی با ساختار زیر می‌پذیرد:

typescript
Record<string, string>;

بنابراین اگر مقدار موردنظر عددی یا boolean است، آن را قبل از ارسال به string تبدیل کنید.

برای مثال:

typescript
tracker.identify({
  age: String(user.age),
  isTrial: String(user.isTrial),
});

Operator equals#

equals برای زمانی مناسب است که مقدار property باید با مقدار Condition برابر باشد.

برای مثال، اگر Condition به این شکل تعریف شده باشد:

text
property: plan
operator: equals
value: pro

Visitor زیر شرط را پاس می‌کند:

typescript
tracker.identify({
  plan: "pro",
});

مقایسه equals نسبت به بزرگی و کوچکی حروف حساس نیست. بنابراین مقدارهای زیر از نظر این Operator برابر در نظر گرفته می‌شوند:

text
pro
Pro
PRO

با این حال، بهتر است در داده‌های واقعی همچنان یک Naming Convention ثابت داشته باشید تا همان propertyها در Segmentها، گزارش‌ها و سایر بخش‌های محصول نیز یکدست باقی بمانند.

Operator contains#

contains بررسی می‌کند آیا مقدار property شامل رشته تعریف‌شده در Condition هست یا نه.

برای مثال، اگر Condition برای email تعریف شده باشد:

text
property: email
operator: contains
value: @example.com

مقدار زیر می‌تواند شرط را برقرار کند:

text
user@example.com

این Operator برای شرایطی مناسب است که تطبیق کامل مقدار لازم نیست و فقط وجود بخشی از رشته اهمیت دارد.

Operator is_in#

is_in برای مقایسه یک property با چند مقدار مجاز استفاده می‌شود.

مقادیر Condition به‌صورت یک فهرست comma-separated تعریف می‌شوند.

برای مثال:

text
property: country
operator: is_in
value: IR,TR,AE

اگر مقدار country برای Visitor یکی از این موارد باشد، Condition برقرار می‌شود.

برای مثال:

typescript
tracker.identify({
  country: "IR",
});

این Operator زمانی مناسب است که یک Flag باید برای چند گروه مشخص با یک property مشترک فعال باشد.

ترکیب چند Condition#

اگر Flag بیش از یک Condition داشته باشد، همه آن‌ها باید برقرار باشند.

برای مثال:

text
plan equals pro
country is_in IR,AE
email contains @company.com

برای فعال شدن این Flag، Visitor باید:

  • Plan برابر pro داشته باشد
  • Country او IR یا AE باشد
  • Email او شامل @company.com باشد

اگر حتی یکی از این Conditionها برقرار نباشد، نتیجه Flag false خواهد بود.

این رفتار بر اساس منطق AND انجام می‌شود و در نسخه فعلی Conditionهای یک Flag با OR ترکیب نمی‌شوند.

ارزیابی Flag در Vanilla SDK#

بعد از ثبت ویژگی‌های Visitor می‌توانید Flagها را refresh کنید و وضعیت یک Flag مشخص را بخوانید:

typescript
tracker.identify({
  email: "user@example.com",
  plan: "pro",
  country: "IR",
});

await tracker.fetchFlags();

if (tracker.isFeatureEnabled("new-checkout")) {
  showNewCheckout();
}

در این مثال:

  1. ویژگی‌های Visitor با identify() ثبت می‌شوند.
  2. fetchFlags() ارزیابی جدید Flagها را از Backend دریافت می‌کند.
  3. isFeatureEnabled() وضعیت فعلی Flag موردنظر را از snapshot Tracker می‌خواند.

در بسیاری از سناریوها، identify() خودش باعث refresh شدن Flagها می‌شود. بنابراین لازم نیست بعد از هر بار identify() حتماً fetchFlags() را جداگانه اجرا کنید، مگر اینکه بخواهید زمان refresh را به‌صورت مستقیم کنترل کنید.

خواندن همه Flagها#

برای دریافت snapshot فعلی همه Feature Flagها می‌توانید از getFlags() استفاده کنید:

typescript
const flags = tracker.getFlags();

این متد آخرین وضعیت موجود در Tracker را برمی‌گرداند و درخواست شبکه جدیدی ایجاد نمی‌کند.

اگر فقط وضعیت یک Flag مشخص مهم است، استفاده از isFeatureEnabled() خواناتر است:

typescript
const enabled = tracker.isFeatureEnabled("new-checkout");

دنبال کردن تغییر Flagها#

اگر بخشی از برنامه باید هنگام تغییر نتیجه Feature Flag واکنش نشان دهد، می‌توانید از onFlagsChange() استفاده کنید.

برای مثال:

typescript
const unsubscribe = tracker.onFlagsChange((flags) => {
  console.log(flags);
});

این callback زمانی اجرا می‌شود که snapshot Feature Flagها تغییر کند.

در پایان lifecycle مربوط به subscription، اگر API برگشتی امکان unsubscribe داشته باشد، آن را مطابق قرارداد همان نسخه اجرا کنید تا listener اضافی باقی نماند.

استفاده در React#

در React معمولاً نیازی نیست مستقیماً با getFlags() یا onFlagsChange() کار کنید. Hookهای React snapshot و rerender مرتبط با تغییر Feature Flagها را مدیریت می‌کنند.

برای بررسی یک Flag مشخص:

tsx
import { useFeatureFlag, useFeatureFlags } from "alphana-sdk/react";

function Checkout() {
  const enabled = useFeatureFlag("new-checkout");

  const allFlags = useFeatureFlags();

  return enabled ? <NewCheckout /> : <CurrentCheckout />;
}

useFeatureFlag(key) مقدار boolean مربوط به Flag مشخص‌شده را برمی‌گرداند.

useFeatureFlags() نیز map فعلی تمام Feature Flagهای ارزیابی‌شده را در اختیار Component قرار می‌دهد.

وقتی Flagها refresh شوند، Hookهای مرتبط می‌توانند Component را با snapshot جدید دوباره Render کنند.

Targeting بعد از Login#

یکی از زمان‌های مهم برای اجرای identify() بعد از Login است.

پیش از شناسایی کاربر، Tracker ممکن است فقط اطلاعات عمومی Visitor را در اختیار داشته باشد. بعد از Login می‌توانید propertyهایی مثل Plan، Role یا Country را ثبت کنید تا Targeting با context دقیق‌تری انجام شود.

برای مثال:

typescript
tracker.identify({
  plan: user.plan,
  role: user.role,
  country: user.country,
});

اگر Feature Flag بر اساس یکی از این propertyها Condition داشته باشد، ارزیابی بعدی می‌تواند نتیجه متفاوتی نسبت به قبل از Login داشته باشد.

Naming ویژگی‌ها#

Propertyهایی که برای Feature Flag Targeting استفاده می‌کنید بهتر است در کل محصول ساختار ثابتی داشته باشند.

برای مثال، برای Plan یکی از این الگوها را انتخاب کنید:

text
free
pro
enterprise

و همان الگو را همیشه حفظ کنید.

ارسال مقدارهای متفاوت مثل:

text
pro
Pro Plan
professional

برای یک مفهوم یکسان می‌تواند Targeting و تحلیل Audience را پیچیده‌تر کند.

همین اصل برای نام propertyها نیز برقرار است. اگر در Condition از country استفاده می‌کنید، در بخش دیگری همان داده را با نامی مثل user_country ارسال نکنید مگر اینکه عمداً دو مفهوم متفاوت باشند.

Feature Flag جایگزین Authorization نیست#

Feature Flag می‌تواند مشخص کند چه تجربه‌ای به یک کاربر نمایش داده شود، اما نباید به‌عنوان مکانیزم امنیتی یا Authorization استفاده شود.

برای مثال، اگر یک قابلیت فقط برای کاربران Enterprise مجاز است، مخفی کردن UI با Feature Flag کافی نیست.

Backend همچنان باید دسترسی واقعی به عملیات حساس را بر اساس Authentication و Authorization خودش بررسی کند.

Feature Flag بیشتر برای کنترل rollout، تجربه محصول، Targeting و Kill Switch مناسب است.