سازماندهی قابلیت ها و ماژول های انگولار — به زبان ساده

۲۵۵ بازدید
آخرین به‌روزرسانی: ۱۱ شهریور ۱۴۰۲
زمان مطالعه: ۶ دقیقه
سازماندهی قابلیت ها و ماژول های انگولار — به زبان ساده

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

همچنین باید از ماژول‌های core و shared استفاده کنیم چون راهنمای سبک انگولار این موارد را مستقیماً توصیه کرده‌اند.

سازمان‌دهی قابلیت‌ها

یکی از بزرگ‌ترین عواملی که روی یک معماری منسجم انگولار تأثیر می‌گذارد، شیوه سازمان‌دهی قابلیت‌های اپلیکیشن است. برخی اپلیکیشن‌ها ممکن است قابلیت‌های بسیار مختلفی داشته باشند. در این حالت باید نه تنها در مورد شیوه سازمان‌دهی قابلیت‌ها بلکه در مورد شیوه سازمان‌دهی کامپوننت‌های فرزند درون آن‌ها، ماژول‌ها و موارد دیگر هم تأمل کنیم.

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

سازماندهی قابلیت ها و ماژول های انگولار

در راهنمای استایل انگولار، با گزاره زیر روبرو می‌شویم.

اپلیکیشن را به ترتیبی سازمان‌دهی کنید که بتوانید کد را سریع پیدا کنید، کد را در یک نگاه شناسایی کنید و ساختارها را تا حد امکان مسطح غیر تودرتو) حفظ کنید. تا حد امکان از اصل DRY پیروی کنید. (https://angular.io/guide/styleguide)

در ادامه موارد طرح شده در این راهنما را یک به یک توضیح می‌دهیم:

  • سریع یافتن کد – ما باید بتوانیم وارد ادیتور کد شویم و کدی که به دنبالش هستیم را به سرعت پیدا کنیم و برای ای کار نیازمند صرف زمان و تلاش زیاد نباشیم. به طور خاص برای افت یک کد نباید در پو‌شه‌های مختلف به دنبالش بگردیم
  • شناسایی کد در یک نگاه – این مورد به شیوه نام‌گذاری فایل‌ها مربوط است. کامپوننت‌ها باید کلمه component را در نام خود داشته باشد، سرویس‌ها باید کلمه service را در نام خود داشته باشند، گاردهای مسیر در اغلب موارد کلمه guard را دارند و مواردی از این دست. به این ترتیب شناسایی کدی که بررسی می‌کنیم در نگاه نخست کار واقعاً آسانی خواهد بود.
  • مسطح نگه‌داشتن ساختار – از ایجاد سلسله مراتب پوشه‌های تودرتو با عمق زیاد اجتناب کنید.
  • اصل DRY را رعایت کنید – اصل DRY اختصاری برای عبارت «خود را تکرار نکنید» (Do not repeat yourself) است. انگولار فریمورکی است که به ما کمک می‌کند این اصل را از طریق مواردی مانند سرویس‌ها رعایت کنیم. امکان استفاده مجدد از سرویس‌ها به روش‌های مختلفی وجود دارد. همچنین می‌توانیم از کامپوننت‌ها و دایرکتیوها نیز استفاده مجدد بکنیم. اگر معمار هستید و اپلیکیشن خود را به طور مناسبی طراحی کرده‌اید، آن نقشه اولیه را در دست دارید در این صورت پیاده‌سازی اصل DRY تا زمانی که طرح‌ریزی درستی داشته باشید، کار دشواری نخواهد بود.

دو روش برای سازمان‌دهی کد وجود دارد:

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

روش سازمان‌دهی کد به روش متعارف توصیه نمی‌شود. به بیان دیگر نباید پوشه‌ای به نام components داشته باشید که همه کامپوننت‌هایتان را در آن قرار دهید و در پوشه components نیز همه سرویس‌ها را انباشته کنید.

با این که این کار از نظر عملیاتی خللی وارد نمی‌کند، اما موجب صرف وقت زیاد برای یافتن موارد مختلف می‌شود.

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

جمع‌بندی در این مورد آن است که باید از یک رویکرد «مبتنی بر قابلیت» برای سازمان‌دهی کد خود استفاده کنید.

از Angular CLI برای تولید پوشه/کامپوننتت اولیه قابلیت استفاده کنید. به این ترتیب می‌توانید به صورت خودکار این روش را مورد استفاده قرار دهید. برای قابلیت‌های سطح فوقانی می‌توانید به صورت پیش‌فرض از CLI استفاده کنید تا سرعت کارها افزایش یابد.

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

به این ترتیب می‌توانید برای «بارگذاری کند» (lazy loading) برنامه‌ریزی کنید تا قابلیت مورد نظر خودکفا باشد و بتوان آن را برای نمونه در صورت نیاز در ماژول ریشه برخی قابلیت‌های دیگر ایمپورت کرد. این کار همچنین موجب سهولت نگه‌داری قابلیت می‌شود چون همه چیز خودکفا و مستقل است و می‌توانیم از همه قابلیت‌های جالب انگولار بهره بگیریم.

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

در مجموع پیشنهاد می‌کنیم توصیه‌های ارائه شده از سوی راهنمای سبک کدنویسی انگولار را به طور کامل رعایت کنید.

ماژول‌های قابلیت

اگر راهنمای استایل انگولار را بررسی کنید، اطلاعات زیادی در مورد «ماژول‌های قابلیت» (Feature Modules) خواهید دید.

فرض کنید یک قابلیت به نام «کارگزارها» (Brokers) و قابلیت دیگری به نام «صندوق‌ها» (Funds) داریم. روش مناسب برای سازمان‌دهی آن‌ها چیست؟

سازماندهی قابلیت ها و ماژول های انگولار

قبل از هر چیز باید از دستور ng generate component (‌به اختصار ng g c) استفاده کنیم و نام قابلیت را Brokers بگذاریم که می‌تواند یک زیرپوشه به نام Brokers در سطح فوقانی پروژه اضافه کند. اما بعد چه می‌توان کرد؟

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

بنابراین باید برای هر قابلیت دست کم یک ماژول داشته باشیم، اما در اغلب موارد بهتر است دو ماژول داشته باشیم، ‌زیرا یک قابلیت غالباً مسیریابی نیز دارد و از این رو بهتر است مسیرهای قابلیت درون یک ماژول در خود قابلیت تعریف شوند.

بنابراین در این مورد فایل brokers-routing.module.ts را ایجاد می‌کنیم و سپس آن را در ماژول این قابلیت که brokers.module.ts نام دارد، ایمپورت می‌کنیم.

در صورتی که قابیلت مورد نظر دارای قابلیت‌های فرعی دیگری نیز باشد، ممکن است ماژول‌های دیگری هم داشته باشید، زیرا در عمل می‌خواهید آن‌ها خودکفا باشند.

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

اکنون نوبت به ایجاد قابلیت Funds می‌رسد. و در این مورد نیز می‌توانیم از همان روش قبلی استفاده کنیم، یعنی یک ماژول برای مسیرهای قابلیت Funds به نام funds-routing.module.ts ایجاد کنیم و سپسان را در ماژول قابلیت به نام funds.module.ts ایمپورت کنیم.

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

به این ترتیب، اگر شما رهبر یک تیم برنامه‌نویسی باشید و بخواهید ماژول Brokers را در ماژول rooe ایمپورت کنید، دیگر لازم نیست در مورد جزییات آن چیزی بدانید. علاوه بر این، لازم نیست در مورد هیچ مسیر یا زیرماژول فرزند که ممکن است در ماژول Borkers باشد، اطلاعاتی داشته باشیم. به سادگی آن را ایمپورت می‌کنیم و کار تمام است.

به طور مشابه می‌توانیم قابلیت Funds را نیز تقسیم کنیم و آن را به یک تیم متفاوت یا یک عضو دیگر تیم بدهیم و از آنجا که قابلیت خودکفایی است می‌تواند به طور مستقل از دیگر قابلیت‌ها و ماژول‌ها به‌روزرسانی شود.

این روش ایجاد یک الگوی «مسئولیت منفرد» (single responsibility) در اپلیکیشن است که روش مناسبی محسوب می‌شود و برای ساخت ماژول‌های قابلیت‌های خودکفا توصیه می‌شود.

کدنویسی

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

  • فایل brokers-routing.module.ts
1import { NgModule } from '@angular/core';
2import { Routes, RouterModule } from '@angular/router';
3
4import { BrokersComponent } from './brokers.component';
5
6const routes: Routes = [
7  { path: '', component: BrokersComponent }
8]
9
10@NgModule({
11  imports: [ RouterModule.forChild(routes) ],
12  exports: [ RouterModule ]
13})
14export class BrokersRoutingModule { 
15  static components = [ BrokersComponent ];
16}
  • فایل brokers.module.ts
1import { NgModule } from '@angular/core';
2
3import { BrokersRoutingModule } from './brokers-routing.module';
4
5@NgModule({
6  imports: [ BrokersRoutingModule ],
7  declarations: [ BrokersRoutingModule.components ]
8})
9export class BrokersModule { }
  • فایل app-routing.module.ts
1import { NgModule } from '@angular/core';
2import { Routes, RouterModule } from '@angular/router';
3
4import { PreloadModulesStrategy } from './core/strategies/preload-modules.strategy';
5
6
7const routes: Routes = [
8  { path: 'brokers', loadChildren: () => import('./brokers/brokers.module').then(m => m.BrokersModule) }
9];
10
11@NgModule({
12  imports: [ RouterModule.forRoot(routes, { preloadingStrategy: PreloadModulesStrategy }) ],
13  exports: [ RouterModule ],
14  providers: [ PreloadModulesStrategy ]
15})
16export class AppRoutingModule { }

این الگو برای همه قابلیت‌های دیگر نیز تکرار می‌شود.

آیا الزامی به رعایت این روش وجود دارد؟ پاسخ این سؤال منفی است. این صرفاً یک توصیه است و بدیهی است که ممکن است در برخی موارد نیز مناسب نباشد. همچنان که یک مدل و اندازه کفش برای همه افراد مناسب نیست، یک رویکرد معماری اپلیکیشن نیز برای همه کاربردها مناسب نخواهد بود.

اگر این مطلب برای شما مفید بوده است، ‌آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۱ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
swlh
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *