معماری تمیز در فلاتر: ساختار پوشه‌ها و لایه‌بندی برای پروژه‌های بزرگ

وقتی اپ بزرگ می‌شود، بدون ساختار مشخص کد به هم می‌ریزد. این مقاله ساختار feature-first، لایه‌های UI، state، repository و data source و اصول تست‌پذیری را به زبان ساده توضیح می‌دهد.

۳ دقیقه مطالعه۲ بازدید
معماری تمیز در فلاتر: ساختار پوشه‌ها و لایه‌بندی برای پروژه‌های بزرگ

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

#ساختار پوشه: ویژگی‌محور (feature-first)

به‌جای دسته‌بندی بر اساس نوع فایل (همه‌ی ویجت‌ها یک‌جا، همه‌ی مدل‌ها یک‌جا)، بر اساس قابلیت دسته‌بندی کنید:

lib/
  core/            # shared: network, theme, utils
  features/
    auth/
      data/        # api + repository implementation
      domain/      # models + repository interface
      presentation/# screens, widgets, controllers
    courses/
      data/
      domain/
      presentation/
  main.dart

مزیتش این است که برای کار روی یک قابلیت فقط در یک پوشه می‌گردید و حذف یا جابه‌جایی یک قابلیت آسان می‌شود.

#چهار لایه با مسئولیت مشخص

  • UI (ویجت‌ها): فقط نمایش می‌دهد و رویداد کاربر را به کنترلر می‌دهد. منطق کسب‌وکار ندارد.
  • State / Controller: وضعیت صفحه را نگه می‌دارد و از repository داده می‌گیرد (Riverpod، Bloc یا ChangeNotifier).
  • Repository: تنها دروازه‌ی داده برای بقیه‌ی اپ است. نمی‌داند داده از شبکه می‌آید یا از دیتابیس محلی.
  • Data source: کار واقعی با API یا ذخیره‌ساز محلی.

#Repository با واسط (interface)

abstract class CourseRepository {
  Future<List<Course>> fetchCourses();
}

class ApiCourseRepository implements CourseRepository {
  ApiCourseRepository(this._api);
  final CourseApi _api;

  @override
  Future<List<Course>> fetchCourses() => _api.getCourses();
}

چرا واسط؟ چون در تست، یک FakeCourseRepository می‌گذارید و بدون اینترنت رفتار صفحه را تست می‌کنید.

#تزریق وابستگی (DI)

کلاس‌ها نباید وابستگی‌هایشان را خودشان بسازند؛ از بیرون بگیرند. با سازنده یا با Riverpod:

final courseRepositoryProvider = Provider<CourseRepository>(
  (ref) => ApiCourseRepository(ref.watch(courseApiProvider)),
);

#مدل‌های تغییرناپذیر

مدل‌ها را final و const تعریف کنید و برای تغییر، نسخه‌ی جدید بسازید (copyWith). این کار باگ‌های ناشی از تغییر پنهان داده را از بین می‌برد.

#قواعدی که ساختار را سالم نگه می‌دارد

  • ویجت‌ها هیچ‌وقت مستقیم HTTP صدا نمی‌زنند.
  • لایه‌ی پایین‌تر هرگز لایه‌ی بالاتر را import نمی‌کند (domain از presentation خبر ندارد).
  • هر فایل یک دلیل برای تغییر داشته باشد.

#زیاده‌روی نکنید

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

اگر یک چیز یاد بگیرید: UI را از منطق و داده جدا کنید. بقیه‌ی چیزها همین‌جا شروع می‌شود.

فلاتر را حرفه‌ای و پروژه‌محور یاد بگیر

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

مشاهده‌ی دوره‌ی VIP