یک تیم فرانت‌اند یک لایه شبیه‌سازی API (mocking) با امنیت تایپی (type-safe) را پیاده‌سازی کرده است که فقط در محیط توسعه (development) فعال است. با استفاده از Axios interceptors و قابلیت tree-shaking در Vite، باندل نسخه تولید (production) بدون تغییر باقی می‌ماند. مهندسان در حالی که منتظر آماده شدن اندپوینت‌های بک‌اند هستند، داده‌ها را با الگوهای معمول خود دریافت می‌کنند و سپس تنها با تغییر یک پرچم محیطی (environment flag)، به API واقعی متصل می‌شوند.

چرا تیم به روش بهتری برای mock کردن نیاز داشت

توسعه‌دهندگان فرانت‌اند زمانی که یک مسیر (route) در بک‌اند هنوز تکمیل نشده است، با بن‌بست مواجه می‌شوند. راه حل سریع — یعنی هاردکد کردن یک پاسخ در داخل کامپوننت یا پراکنده کردن بلوک‌های if (process.env.NODE_ENV === 'development') در سراسر UI — باعث پیشروی اپلیکیشن می‌شود اما بدهی فنی (technical debt) به جا می‌گذارد. آن اشیاء mock به بخشی از منطق کامپوننت تبدیل می‌شوند، خطر ارسال داده‌های جعلی به نسخه تولید را افزایش می‌دهند و خواندن و تست کردن کد را دشوارتر می‌کنند.

تیم می‌خواست تمام mockها را از درخت کامپوننت (component tree) خارج کند، قراردادی بین فرانت‌اند و بک‌اند برقرار کند و تضمین کند که هیچ مورد اضافه‌ای در ساخت نسخه تولید (production build) قرار نمی‌گیرد.

فرآیند سه مرحله‌ای که تیم دنبال می‌کند

  1. جلسه قرارداد (Contract meeting) – مهندسان فرانت‌اند و بک‌اند دور هم جمع می‌شوند و هر درخواست، URL، متد و Payload مورد انتظار آن را لیست می‌کنند.
  2. قرارداد تایپ‌شده (Typed contract) – آن‌ها لیست را به یک اینترفیس TypeScript تبدیل می‌کنند که به تنها منبع حقیقت (single source of truth) برای ساختار درخواست‌ها و پاسخ‌ها تبدیل می‌شود.
  3. سیم‌کشی اینترسپتور (Interceptor wiring) – یک Axios interceptor هر درخواست خروجی را بررسی می‌کند. اگر URL با یک mock ثبت‌شده مطابقت داشته باشد، اینترسپتور داده‌های mock را برمی‌گرداند؛ در غیر این صورت، درخواست به سمت سرور واقعی ارسال می‌شود.

از آنجایی که اینترسپتور تنها جایی است که منطق mock در آن قرار دارد، کد کامپوننت‌ها بدون تغییر باقی می‌ماند. توسعه‌دهندگان همچنان از هوک‌های معمول دریافت داده خود — مانند useQuery — بدون اضافه کردن هیچ منطق شرطی استفاده می‌کنند.

چگونه از سنگین شدن نسخه تولید جلوگیری می‌شود

تیم سه لایه حفاظتی ایجاد کرده است که به Rollup (باندلری که توسط Vite استفاده می‌شود) اجازه می‌دهد هنگام ساخت نسخه تولید، کدهای mock را به طور کامل حذف کند:

  • مقدار import.meta.env.DEV در ساخت نسخه تولید برابر با false می‌شود، بنابراین کل ماژول اینترسپتور در طول فرآیند tree-shaking حذف می‌گردد.
  • متغیر MODE هنگام اجرای تست‌های واحد (unit tests) روی مقداری غیر از test تنظیم می‌شود تا کدهای مخصوص تست از بقیه جدا بمانند.
  • یک پرچم سفارشی به نام VITE_ENABLE_MSW به صورت پیش‌فرض روی false است و برای فعال‌سازی mock باید صراحتاً روشن شود.

وقتی هر سه شرط false باشند، رجیستریِ mock هرگز وارد باندل نهایی نمی‌شود.

سازماندهی فایل‌های mock

مخزن (repo) از یک ساختار ویژگی‌محور (feature-centric) پیروی می‌کند:

  • interfaces/ – شامل تعاریف TypeScript است که از جلسه قرارداد تولید شده‌اند.
  • scenarios.ts – شامل نمونه‌های عینی از پاسخ‌های موفق و موارد خطا برای هر اندپوینت است.
  • devHandlers.ts – به عنوان رجیستری مرکزی عمل می‌کند که URLها را به داده‌های سناریو نگاشت کرده و اینترسپتور را به Axios متصل می‌کند.

یک اسکریپت ساختاردهنده (scaffolding script) کوچک می‌تواند این فایل‌ها را به طور خودکار تولید کند: کافی است یک URL و اینترفیس مطابقت آن را به آن بدهید تا فایل‌های stub را ایجاد و mock را ثبت کند. این اسکریپت خارج از مسیر کدهای تولید قرار دارد، بنابراین بر اندازه باندل تأثیری نمی‌گذارد.

دستاوردهای تیم

  • صفر کردن mockها در داخل کامپوننت‌ها – تمام داده‌های جعلی در یک لایه اختصاصی قرار دارند و کد UI را تمیز نگه می‌دارند.
  • امنیت تایپی سرتاسری (End-to-end type safety) – داده‌های mock با همان اینترفیس‌های TypeScript که برای پاسخ‌های واقعی استفاده می‌شوند مطابقت دارند، بنابراین عدم تطابق‌ها در زمان کامپایل شناسایی می‌شوند.
  • عدم افزایش حجم در نسخه تولید – قابلیت tree-shaking، اینترسپتور و داده‌های mock را به طور کامل حذف می‌کند و اندازه باندل را بدون تغییر باقی می‌گذارد.
  • سناریوهای مشترک برای توسعه و تست – همان تعاریف mock هم برای توسعه محلی و هم برای تست‌های خودکار استفاده می‌شوند که باعث کاهش تکرار می‌شود.

سبک‌سنگین کردن‌ها و محدودیت‌ها

این رویکرد جایگزین یک بک‌اند واقعی نیست. اگر قراردادِ mock با API واقعی متفاوت شود، توسعه‌دهندگان تنها پس از تغییر پرچم محیطی متوجه این عدم تطابق خواهند شد.

آنچه باید در آینده زیر نظر گرفت

  • یکپارچه‌سازی ابزارها (Tooling integration)
  • پذیرش گسترده‌تر (Broader adoption)
  • نظارت بر عملکرد (Performance monitoring)

نتیجه‌گیری روشن است: انتقال منطق mock به یک لایه تایپ‌شده و کنترل‌شده توسط محیط (environment-gated)، به تیم‌های فرانت‌اند اجازه می‌دهد کامپوننت‌ها را دست‌نخورده نگه دارند، امنیت تایپی را حفظ کنند و نسخه‌های تولید را بدون بار اضافیِ داده‌های mock عرضه کنند. حفظ یک قرارداد مشترک، بهای داشتن یک گردش کار توسعه روان‌تر و یک کدبیس تمیزتر است.