اگر فکر کردی معماری پیازی فقط یه اصطلاح باکلاسه که توی لینکدین باهاش پز بدن، سخت در اشتباهی. معماری پیازی یعنی وقتی کارفرما بعد از ۶ ماه میاد و میگه «میخوام دیتابیس رو از PostgreSQL ببرم روی MongoDB» یا «میخوام کل سیستم ارسال پیامک رو عوض کنم»، لرزه به تنت نیفته. در FastAPI، به دلیل سادگی بیش از حد، خیلی راحت ممکنه توی تله‌ ی «نوشتن همه چیز در مسیر ها (Routes)» بیفتی. اما معمار واقعی، کدش رو طوری لایه‌بندی میکنه که هسته‌ ی بیزنس، اصلاً نفهمه از کدوم فریمورک یا دیتابیسی داره استفاده میکنه.

هسته (Domain)

 هسته (Domain): جایی که هیچ غریبه‌ای حق ورود نداره

توی معماری پیازی، قلب تپنده پروژه Domain یا همون Models و Schemas هستن. اینجا قانون اول اینه: هیچ وابستگی (Dependency) به بیرون نباید وجود داشته باشه. یعنی چی؟ یعنی توی لایه‌ی مدل‌های اصلی، نباید اثری از SQLAlchemy یا Pydantic (اگر برای دیتابیس باشن) یا پکیج‌های FastAPI ببینی. اینجا فقط منطق خالص بیزنس شماست.

نکته طلایی: اگر توی لایه‌ی Domain مجبوری پکیجی رو Import کنی که مربوط به دیتابیسه، بدون که داری راه رو اشتباه میری. هسته‌ی پیاز باید کاملاً مستقل باشه.

لایه‌ی سرویس (Service Layer)

لایه‌ی سرویس (Service Layer): مغز متفکر

اینجا جاییه که یوزکیس‌ها (Use Cases) تعریف می‌شن. مثلاً «ثبت‌نام کاربر» یک یوزکیس هست. لایه‌ی سرویس وظیفه داره به لایه‌ی دیتابیس بگه «این دیتا رو ذخیره کن» و به لایه‌ی ایمیل بگه «خوش‌آمدگویی بفرست». اما نکته اینجاست: سرویس نباید بدونه دیتابیس چیه! اون فقط با یک Interface (رابط) حرف می‌زنه.

آداپتورها (Adapters)

آداپتورها (Adapters): دروازه‌های ورود و خروج

لایه‌ی بیرونی پیاز، آداپتورها هستن. FastAPI خودش فقط یک آداپتوره! بله، درست شنیدی. FastAPI فقط ابزاریه که درخواست HTTP رو میگیره و به لایه‌ های داخلی میسپره.

  • Infrastructure Adapter: کدهای مربوط به SQLAlchemy یا ارتباط با Redis.

Entrypoint Adapter: همین مسیر های (Routes) خودمون در FastAPI.

جادوی Dependency Injection در FastAPI

چطور میشه لایه‌ی سرویس به دیتابیس بگه «ذخیره کن» بدون اینکه بدونه دیتابیس چیه؟ با استفاده از Repository Pattern. توی FastAPI ما از سیستم Depends استفاده میکنیم تا پیاده‌ سازی‌ های واقعی رو به لایه‌های داخلی تزریق کنیم.

# تعریف یک واسط (Interface) فرضی
class UserRepository(ABC):
    @abstractmethod
    def add(self, user: User): ...

# لایه سرویس فقط با واسط کار می‌کنه
class UserService:
    def __init__(self, repo: UserRepository):
        self.repo = repo

    def register(self, user_data):
        # منطق بیزنس...
        return self.repo.add(user_data)

اینجوری موقع تست نوشتن، میتونی به جای دیتابیس واقعی، یک Mock Repository به سرویس بدی و بدون نیاز به دیتابیس، کل منطق بیزنس رو تست کنی.

چرا این معماری نجات‌بخش است؟

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

  • در کد کثیف: باید کل فایل‌های routes.py رو بگردی و هر جا کد پیامک زدی رو عوض کنی.

در معماری پیازی: فقط یک SmsAdapter جدید مینویسی و توی تنظیمات اصلی، پیاده‌سازی جدید رو جایگزین قبلی میکنی. کل پروژه بدون تغییر به کارش ادامه میده. به این میگن قدرت!

نتیجه‌گیری

معماری پیازی در FastAPI شاید در ابتدا باعث بشه تعداد فایل‌های پروژه ‌ات زیاد بشه و حس کنی داری «بیش ‌مهندسی» (Over-engineering) میکنی، اما یادت باشه:

  1. کدها تست‌پذیر میشن: چون لایه‌ها از هم جدان.

  2. تغییرات ترسناک نیستن: چون وابستگی ‌ها مدیریت شدن.

  3. تیم بزرگ راحت‌ تر کار میکنه: هر کسی میدونه جاش کجای این پیازه!

برنامه‌نویسی که از معماری فرار می‌کنه، مثل بنایی میمونه که بدون نقشه ساختمون میسازه؛ شاید اولش سریع پیش بره، اما طبقه سوم که برسه، کل سازه روی سرش خراب میشه.