ویرگول
ورودثبت نام
میر مجتبی هاشمی جنتی
میر مجتبی هاشمی جنتیدانش آموخته مهندسی نرم افزار | فعال در صنعت | با اندکی تجربه
میر مجتبی هاشمی جنتی
میر مجتبی هاشمی جنتی
خواندن ۴ دقیقه·۴ روز پیش

Idempotency در مهندسی نرم افزار

Idempotency؛ مفهومی ساده با اثرات حیاتی در طراحی سیستم‌ها

سلام دوستان؛ مستقیم میرم سر اصل مطلب. اگر بخوام صادقانه بگم، idempotency جزو اون مفاهیمیه که خیلی‌ها فکر می‌کنن می‌دوننش، ولی وقتی پای پیاده‌سازی واقعی وسط میاد، تازه عمق ماجرا مشخص می‌شه. مخصوصاً وقتی سیستم بزرگ می‌شه، توزیع‌شده می‌شه، یا با پول و داده‌ی حساس سروکار داره. idempotency دقیقاً همون چیزیه که جلوی خیلی از فاجعه‌های نرم‌افزاری رو قبل از اتفاق گرفتن می‌گیره.

به زبان ساده، idempotency یعنی اجرای چندباره‌ی یک عملیات، سیستم رو به وضعیت جدیدی نبره و نتیجه نهایی همون نتیجه‌ی اجرای یک‌باره باشه. نکته‌ی مهم اینجاست که این «نتیجه» فقط مقدار خروجی نیست؛ شامل side effectها هم می‌شه. یعنی نه داده‌ی تکراری ساخته بشه، نه پول دوبار کم بشه، نه state سیستم از کنترل خارج بشه.


ریشه‌ی idempotency؛ از ریاضیات تا مهندسی نرم‌افزار

مفهوم idempotency در اصل از ریاضیات میاد. تابعی idempotent محسوب می‌شه که اگر چند بار روی یک ورودی اعمال بشه، خروجی تغییر نکنه. علوم کامپیوتر این مفهوم رو گرفت و به یکی از پایه‌های تفکر در طراحی سیستم‌های قابل‌اعتماد تبدیلش کرد.

در مهندسی نرم‌افزار، idempotency بیشتر از اینکه یک تعریف تئوریک باشه، یک استراتژی برای بقا در دنیای غیرقابل‌اعتماد شبکه‌هاست. چون در عمل، هیچ تضمینی وجود نداره که یک درخواست فقط یک بار ارسال یا فقط یک بار پردازش بشه.


idempotency در HTTP و APIها؛ قرارداد نانوشته اما حیاتی

در دنیای وب، idempotency به‌صورت رسمی در استانداردهای HTTP تعریف شده. طبق RFC 7231، بعضی متدهای HTTP ذاتاً idempotent در نظر گرفته می‌شن. این یعنی کلاینت حق داره اون‌ها رو چند بار صدا بزنه، بدون اینکه نگران تغییر ناخواسته‌ی وضعیت سرور باشه.

اما این فقط یک «انتظار» از سمت پروتکله، نه یک تضمین خودکار. اگر backend درست طراحی نشده باشه، حتی PUT هم می‌تونه غیر-idempotent بشه. اینجاست که مسئولیت کامل می‌افته روی دوش طراح سیستم.


جدول idempotency در متدهای HTTP

جدول idempotency در متد های HTTP
جدول idempotency در متد های HTTP


مثال واقعی ۱: پرداخت آنلاین؛ جایی که idempotency نجات‌دهنده است

فرض کن کاربر روی دکمه‌ی «پرداخت» کلیک می‌کنه. درخواست به سرور می‌رسه، پول کم می‌شه، ولی پاسخ به‌خاطر timeout به کاربر نمی‌رسه. کاربر دوباره روی دکمه کلیک می‌کنه. اگر سیستم idempotent نباشه، پول دوباره کم می‌شه. همین یک سناریو به‌تنهایی کافیه تا بفهمیم idempotency شوخی‌بردار نیست.

راه‌حل رایج اینه که برای هر درخواست پرداخت، یک idempotency key یکتا تعریف بشه. سرور اگر دوباره همون key رو ببینه، نتیجه‌ی قبلی رو برمی‌گردونه، نه اینکه عملیات رو تکرار کنه.


مثال واقعی ۲: ثبت سفارش در فروشگاه اینترنتی

در ثبت سفارش، معمولاً POST استفاده می‌شه. اما اگر درخواست دوبار ارسال بشه، دو سفارش ساخته می‌شه. اینجاست که یا باید:

  • شناسه‌ی سفارش از سمت کلاینت بیاد

  • یا server-side تشخیص بده که این درخواست قبلاً پردازش شده

در غیر این صورت، دیتابیس پر از سفارش‌های تکراری می‌شه و کسی هم نمی‌فهمه مشکل از کجاست.


مثال واقعی ۳: مصرف پیام در سیستم‌های صف و event-driven

در Kafka یا RabbitMQ، دریافت دوباره‌ی پیام یک اتفاق کاملاً طبیعیه. مصرف‌کننده ممکنه crash کنه، یا commit offset انجام نشه. اگر پردازش پیام idempotent نباشه، نتیجه می‌تونه ثبت چندباره‌ی یک عملیات باشه.

به همین دلیله که در سیستم‌های event-driven، idempotent consumer یک اصل طراحی محسوب می‌شه، نه یک بهینه‌سازی. (معمار ها میدونن چی دارم میگم!)


idempotency و دیتابیس؛ فراتر از transaction

خیلی‌ها فکر می‌کنن transaction داشتن یعنی idempotency. ولی این اشتباهه. transaction فقط atomic بودن رو تضمین می‌کنه، نه idempotent بودن رو. یک INSERT داخل transaction اگر دوبار اجرا بشه، دوبار داده می‌سازه.

برای رسیدن به idempotency در دیتابیس، معمولاً از این ابزارها استفاده می‌شه:

  • unique constraint

  • primary key معنادار

  • upsert

  • check روی state قبلی


اشتباهات رایج در درک و پیاده‌سازی idempotency

یکی از رایج‌ترین اشتباهات اینه که idempotency فقط در سطح API دیده می‌شه. در حالی که اگر منطق بیزینس یا دیتابیس idempotent نباشه، API هم عملاً idempotent نخواهد بود.

اشتباه رایج دیگه اینه که idempotency با retry اشتباه گرفته می‌شه. retry یک مکانیزمه، idempotency یک خاصیته. retry بدون idempotency فقط احتمال خرابکاری رو بیشتر می‌کنه.

و شاید خطرناک‌ترین اشتباه اینه که idempotency رو فقط برای «سیستم‌های بزرگ» ضروری بدونیم. واقعیت اینه که حتی یک سرویس کوچیک هم اگر قراره رشد کنه، باید از همون اول با این طرز فکر ساخته بشه.


جمع‌بندی؛ چرا idempotency نشانه‌ی بلوغ معماری است؟

idempotency یعنی پذیرش این واقعیت که دنیای واقعی پر از خطاست. یعنی طراحی سیستم به‌گونه‌ای که از تکرار نترسه. سیستمی که idempotent طراحی شده، نه‌تنها پایدارتره، بلکه قابل‌اعتمادتر، قابل‌دیباگ‌تر و در نهایت حرفه‌ای‌تره.

اگر بخوای یک خط قرمز بین سیستم آماتور و سیستم بالغ بکشی، idempotency یکی از واضح‌ترین اون‌هاست.

در مقاله بعدی بیشتر در مورد پیاده سازی این موضوع صحبت خواهیم کرد ...

تفکر طراحیسمت کلاینتعلوم کامپیوترمهندسی نرم‌افزار
۳
۰
میر مجتبی هاشمی جنتی
میر مجتبی هاشمی جنتی
دانش آموخته مهندسی نرم افزار | فعال در صنعت | با اندکی تجربه
شاید از این پست‌ها خوشتان بیاید