پرش به مطلب اصلی

اولویت بارگذاری و ساختار لایه‌ای

در پروژه‌های بزرگ، ماژول‌ها به صورت تصادفی یا بدون نظم نباید بارگذاری شوند.
برای جلوگیری از تداخل، وابستگی‌های پیچیده و کدهای تکراری، بهتر است از یک ساختار لایه‌ای (Layered Module Loading) استفاده کنیم.


Base Modules (ماژول‌های پایه)

  • ماژول‌هایی که شامل کد مشترک و ابزارهای عمومی هستند.
  • این ماژول‌ها به سایر ماژول‌ها وابسته نیستند، ولی تقریباً همه‌ی ماژول‌ها به آن‌ها نیاز دارند.
  • مثال‌ها:
    • Core → توابع کمکی، Middlewareهای عمومی، Exception Handling
    • User → مدل کاربر، احراز هویت پایه (Authentication)
    • Notification → سیستم اعلان‌ها
    • FileManager → مدیریت آپلود و ذخیره‌سازی فایل‌ها
نکته

اگر چندین ماژول نیازمند یک قابلیت مشترک باشند (مثلاً آپلود فایل یا مدیریت کاربر)، آن قابلیت باید در یک Base Module جداگانه قرار گیرد و ماژول‌های دیگر از آن استفاده کنند.
این کار جلوی تکرار (Duplication) و وابستگی‌های حلقه‌ای (Circular Dependency) را می‌گیرد.


Feature Modules (ماژول‌های قابلیت‌ها)

  • ماژول‌هایی که یک Business Feature خاص را پیاده‌سازی می‌کنند.
  • معمولاً وابسته به یک یا چند Base Module هستند.
  • مثال‌ها:
    • Bank → مدیریت حساب‌ها و تراکنش‌ها
    • Payment → مدیریت درگاه‌های پرداخت
    • Order → مدیریت سفارش‌ها

Integration Modules (ماژول‌های یکپارچه‌سازی)

  • ماژول‌هایی که ارتباط بین سیستم شما و سرویس‌های خارجی یا بین Feature Moduleها را مدیریت می‌کنند.
  • مثال‌ها:
    • BankGateway → ارتباط با API بانکی
    • PaymentBridge → ارتباط بین Payment و Bank

این ماژول‌ها معمولاً در لایه آخر بارگذاری می‌شوند.


پیشنهاد ساختار اولویت (Priority)

به جای یک مقدار عددی ساده (۰،۱،۲)، می‌توانید لایه‌ها را به صورت زیر در نظر بگیرید:

PriorityLayerتوضیحات
0Base Modulesهمیشه اول بارگذاری می‌شوند (Core, User, Shared)
1Feature Modulesقابلیت‌های اصلی کسب‌وکار (Bank, Order, Payment)
2Integrationارتباطات خارجی و ماژول‌های وابسته به Feature ها

نمونه پیکربندی ماژول‌ها

ماژول بانک
{
"name": "Bank",
"alias": "bank",
"priority": 1,
"providers": [
"Modules\\Bank\\Providers\\BankServiceProvider",
"Modules\\Bank\\Providers\\RouteServiceProvider"
]
}
ماژول پایه
{
"name": "Core",
"alias": "core",
"priority": 0,
"providers": [
"Modules\\Core\\Providers\\CoreServiceProvider"
]
}

مثال عملی: Base Module برای مدیریت فایل

فرض کنید چندین ماژول نیازمند آپلود فایل باشند:

  • ماژول User → آپلود عکس پروفایل
  • ماژول Bank → آپلود مدارک هویتی
  • ماژول Product → آپلود تصویر محصول

به جای تکرار منطق آپلود در هر ماژول، یک Base Module به نام FileManager ایجاد می‌کنیم:

Modules/
└── FileManager/
├── app/Services/FileUploader.php
├── database/migrations/create_files_table.php
├── routes/api.php
└── resources/views/uploader.blade.php

سپس سایر ماژول‌ها تنها از سرویس FileUploader استفاده می‌کنند:

use Modules\FileManager\Services\FileUploader;

class BankController extends Controller
{
public function uploadDocument(Request $request, FileUploader $uploader)
{
$file = $uploader->upload($request->file('document'), 'bank-docs');
return response()->json(['path' => $file->path]);
}
}

نکات مهم برای ماژول‌های قابل انتقال

اگر احتمال دارد یک ماژول به پروژه دیگری منتقل شود، رعایت موارد زیر ضروری است:

استقلال کامل از پروژه اصلی

  • ماژول نباید به کدهای app/ یا مسیرهای اصلی پروژه وابسته باشد.
  • تمام Route ها و Config ها و Controller ها و غیره باید داخل خود ماژول باشند.

Resources ایزوله

  • Viewها، Translationها و غیره داخل پوشه مختص به خود در ماژول نگهداری شوند.
  • برای View و Lang از namespace ماژول استفاده کنید view('bank::index') یا ('bank::validation.name')__.

وابستگی‌ها مدیریت شده

  • اگر ماژول به پکیج یا سرویس خارجی نیاز دارد، آن را در composer.json ماژول تعریف کنید.
  • این کار هنگام انتقال ماژول، نصب خودکار وابستگی‌ها را تضمین می‌کند.

نکات حرفه‌ای

  • تکرار ممنوع: اگر بخشی از کد (مثل FileUploader) در چند ماژول تکرار شده، باید آن را به یک Base Module منتقل کنید.
  • استقلال ماژول‌ها: Feature Module ها نباید وابسته به یکدیگر باشند، فقط به Base Module ها.
  • Shared Base Module: اگر چندین قابلیت عمومی (Helper، Traits، DTOها) در پروژه دارید، آن‌ها را در یک ماژول مثل Shared یا Core قرار دهید.

چرا این ساختار حرفه‌ای‌تر است؟

  • توسعه تیمی ساده‌تر می‌شود (هر تیم روی یک لایه کار می‌کند).
  • Dependency ها کنترل‌شده هستند و هیچ حلقه‌ای ایجاد نمی‌شود.
  • اگر در آینده ماژول جدید اضافه کنید، کافیست Priority و Layer را مشخص کنید.