TGViewer
C# Geeks (.NET) C# Geeks (.NET) @csharpgeeks · 549 subscribers
Post #813 309
📌 برای Order فقط یک Status داشته باشیم یا بریم سراغ State Machine؟ 🤔
فرض کن داریم یک فروشگاه اینترنتی میسازیم و Orderمون چندتا وضعیت داره:
Pending
Paid
Processing
Shipped
Delivered
Cancelled

خب معلومه دیگه 😎
یک enum می‌سازیم:
public enum OrderStatus
{
Pending,
Paid,
Processing,
Shipped,
Delivered,
Cancelled
}

بعد داخل Order:
public OrderStatus Status { get; private set; }

هرجا هم خواستیم وضعیت رو عوض کنیم:
order.Status = OrderStatus.Paid;

تموم شد رفت. 😎
هم ساده‌ست، هم خواناست، هم Database هم فقط یک ستون Status داره.
ولی یه لحظه صبر کن...
واقعاً هر Statusای می‌تونه به هر Status دیگه‌ای تبدیل بشه؟ 🤨
مثلاً:
Pending → Paid
Paid → Processing
Processing → Shipped
Shipped → Delivered

این‌ها منطقی به نظر میرسن.
ولی این چی؟
Delivered → Pending

یا:
Shipped → Paid

یا حتی:
Cancelled → Shipped

احتمالاً نه!
پس مشکل از خود Status نیست.
مشکل اینجاست که اگر فقط یک enum داشته باشیم، این enum به‌تنهایی هیچ چیزی درباره‌ی قوانین انتقال بین وضعیت‌ها نمیگه.
یعنی این کد:
order.Status = OrderStatus.Delivered;

از نظر #C کاملاً معتبره.
ولی از نظر Business ممکنه کاملاً غیرمعتبر باشه.
اینجاست که معمولاً یکی میگه:
«پس قبلش if می‌ذاریم.»

مثلاً:
if (order.Status != OrderStatus.Shipped)
throw new InvalidOperationException();

order.Status = OrderStatus.Delivered;

خب...
بعد یک ماه میشه:
if (status == OrderStatus.Pending)
{
...
}
else if (status == OrderStatus.Paid)
{
...
}
else if (status == OrderStatus.Processing)
{
...
}

بعد یک Requirement جدید میاد:
اگر Payment Failed شد، Order دوباره Payment بشه.

بعد یکی دیگه:
اگر Customer درخواست Cancellation داد، فقط قبل از Shipment اجازه بده.

بعد:
ءAdmin بتونه یک Order رو از حالت Processing به Cancelled ببره، ولی Customer نتونه.
و ناگهان...💀 Business Ruleهای مربوط به Lifecycle سفارش پخش شدن توی:
Controller
Service
Handler
Domain
Background Job
...

و هرکس هم یک قانون متفاوت نوشته.
اینجا دقیقاً جاییه که State Machine می‌تونه ارزش پیدا کنه.
ءState Machine اساساً میگه:
«ءOrder فقط یک Status نداره؛ یک Lifecycle داره و فقط بعضی Transitionها مجاز هستند.»
حالا به‌جای اینکه هرجای سیستم بنویسیم:
order.Status = OrderStatus.Shipped;

میگیم:
order.Ship();

و خود Domain تصمیم می‌گیره آیا این Transition مجازه یا نه.
مثلاً:
public void Ship()
{
if (Status != OrderStatus.Processing)
throw new InvalidOperationException(
"Only processing orders can be shipped.");

Status = OrderStatus.Shipped;
}

حالا اگر کسی بگه:
order.Ship();

و Order هنوز Pending باشه، خود Domain جلوش رو می‌گیره.
این خیلی بهتر از اینه که امیدوار باشیم همه‌ی Callerها قبلش if درست نوشته باشن. 😏
اماااا...
اینجا هم نباید سریع نتیجه بگیریم:
«پس State Machine همیشه بهتره!»

نه.
اگر سیستم ما یک Order خیلی ساده داره:
Pending → Completed

واقعاً لازم نیست برای دو وضعیت یک State Machine عظیم درست کنیم.
پس State Machine قرار نیست صرفاً چون اسمش خفن‌تره وارد پروژه بشه.
مسئله اینه که:
آیا Lifecycle موجودیت، خودش دارای پیچیدگی Business است؟
اینجا State Machine می‌تونه خیلی خواناتر و قابل‌کنترل‌تر باشه.
حتی می‌تونی Ruleهایی مثل این داشته باشی:
Customer فقط تا قبل از

Shipped
می‌تونه Cancellation درخواست کنه.

یا:

ءRefund فقط وقتی مجازه که Payment موفق بوده باشه.

یا:
ءShipment فقط بعد از Payment موفق ایجاد بشه.

این‌ها دیگه صرفاً Status نیستن.
این‌ها Business Rules مربوط به Transitionها هستن.
بعضیا فکر می‌کنن وقتی State Machine داریم، دیگه Status لازم نیست.
نه! State Machine و Status لزوماً رقیب هم نیستن.
More from @csharpgeeks
  1. Sep 22, 2026یه مدتی قراره از دنیای NET. فاصله بگیرم، چون وقتشه برم سربازی. راستش نمیدونم این مدت رو چج…
  2. Sep 20, 2026🔥 حالا مشکل اصلی: Alert Storm فرض کن Database از دسترس خارج شده. ۱۰۰ Pod داری. هر Pod می‌…
  3. Sep 20, 2026🚨 طراحی سیستم Monitoring و Alerting در یک سیستم بزرگ فرض کن ساعت ۳ صبح است. سیستم شما با…
  4. Sep 19, 2026#Engineering_Leadership تصمیم نگرفتن هم یک تصمیم است یه چیز عجیب توی تیم‌های مهندسی: گاهی…
  5. Sep 19, 2026☑ چک‌لیست آماده‌سازی تیم، فرایندها و زیرساخت برای توسعه با AI توجه: هیچ چک‌لیستی جهان‌شمول…
  6. Sep 19, 2026📌پایان یک انتظار طولانی: اعتبارسنجی ناهمگام (Async Validation) در NET 11.
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →