NestJS Circular Dependency Nedir? Projelerde Bağımlılık Yönetimi Nasıl Gerçekleştirilmeli?
Büyük ve karmaşık projelerde bağımlılık yönetimi zorlaşmaktadır. Bağımlılıkların tasarımı proje başında yapılmadığında ortaya sonradan toparlanması güç sorunlar çıkabiliyor. Bu yazımızda bir NodeJS framework’ü olan NestJS üzerinden bağımlılık yönetimini ve çıkan sorunları nasıl çözebileceğimize göz atacağız.
NestJS bizlere Dependency Injection (DI) desteği ile büyük bir kolaylık sağlayabilmektedir. Peki nedir bu Dependency Injection (DI) diye soracak olursak detaylarına bakabiliriz. NestJS de DI mekanizması, Providers ve Injectables konsepti üzerine kuruludur. Reflect Metadata gibi TypeScript özelliklerinden ve NestJS’in kendi altyapısından yararlanır. Temel dekoratörler:
@Injectable() Dekoratörü:
- Bir sınıfı Dependency Injection (DI) için kullanılabilir hale getirir.
- NestJS, bu dekoratör ile sınıfın bağımlılıklarını tanır ve gerektiğinde enjekte eder.
import { Injectable } from '@nestjs/common';
@Injectable()
export class CozumParkService {
getMessage() {
return 'CozumPark';
}
}
Bağımlılığın dahil Edilmesi:
Bir servis farklı bir servise dahil edilirken, dahil edilecek servise constructor injection yöntemiyle eklenir. İki farklı servisimizin olduğunu varsayıyoruz. CozumParkUserService ve CozumParkPostService
Burada CozumParkUserService servisimiz, kullanıcıların gönderilerini çekmek için Post servisine ihtiyaç duyuyor ve çağırıyor.
import { Injectable } from '@nestjs/common';
import { CozumParkPostService } from './postService';
@Injectable()
export class CozumParkUserService {
constructor(private readonly postService: CozumParkPostService) {}
execute() {
return this.postService.getPosts();
}
}
PostService servisini dahil ettiğimiz için User sınıfının modül dosyasına dahil etmemiz gerekiyor.
import { Module } from '@nestjs/common';
import { CozumParkUserService } from './CozumParkUserService';
import { CozumParkPostService } from './another-service';
@Module({
providers: [CozumParkUserService, CozumParkPostService],
})
export class AppModule {}
Bu şekilde servisleri birbirlerine dahil ederek bağımlılık yaratabiliyoruz.
DI’nin Sağladığı Avantajlar
Kodun Tekrar Kullanılabilirliği: Bağımlılıkların yeniden kullanılması kolaylaşır.
Bağımlılık Yönetimi: Bağımlılıkları manuel olarak oluşturmak yerine, NestJS sizin yerinize bunları otomatik olarak çözer.
Test Edilebilirlik: Mock veya farklı implementasyonlar kullanarak birim testler yazmayı kolaylaştırır.
Circular Dependency Nedir? Nasıl Ortaya Çıkar?
Peki nedir bu Circular Dependency? Circular Dependency (Dairesel Bağımlılık), bir uygulama içinde iki veya daha fazla modülün ya da sınıfın birbirine doğrudan ya da dolaylı olarak bağımlı olduğu bir durumdur. Yani, A modülü B modülüne, B modülü de tekrar A modülüne bağımlıdır. Bu döngü, sistemde çeşitli sorunlara neden olabilir. Bunu sizlere bir görsel ile göstermek daha uygun olabilir.
Burada A modulünün B modülüne ihtiyacı olduğunu ve onun bir servisini kendisine dahil ettiğini görüyoruz. Aynı şekilde B modülü de A modülünün bir servisini kendisine dahil ediyor. Bu durumda iki modül birbirine ihtiyaç duyduğu için döngüsel bir bağımlılık ortaya çıkmış oluyor.
Mümkün olduğu sürece bu kullanımdan kaçınmalıyız fakat projemizin büyüdüğü durumlarda bunu yapmaya ihtiyacımız olabiliyor. Sık sık kullanımdan kaçınılarak zorunlu haller dışında bu şekilde kullanılmamalıdır. Kullanıldığı taktirde problem yaşanmaması için NestJS’in sunmuş olduğu forward referencing tekniğini kullanabiliriz. ModuleRef sınıfını kullanarak bağımlılık sorununu ortadan kaldıracağız.
Yukarıda yazmış olduğumuz bu kod üzerinden devam edebiliriz. Post servisimizi dahil ettik. Bunu direkt olarak dahil etmek yerine şu şekilde dahil edeceğiz:
@Inject(forwardRef(() => CozumParkPostService))
private postService: CozumParkPostService,
import { Injectable } from '@nestjs/common';
import { CozumParkPostService } from './postService';
@Injectable()
export class CozumParkUserService {
constructor(
@Inject(forwardRef(() => CozumParkPostService))
private postService: CozumParkPostService,
) {}
execute() {
return this.postService.getPosts();
}
}
Aynı işlemi diğer servisimize uyguluyoruz. Daha sonra modul üzerinden de farklı bir şekilde import etmemiz gerekiyor. forwardRef kullanarak gerekli modulü dahil ediyoruz.
@Module({
imports: [forwardRef(() => CozumParkPostModule)],
})
export class CozumParkUserModule {}
Bu kullanım ile bağımlılık döngüsünün önüne geçilebilir. Ayrıca her yerde kullanılması gereken bir servisiniz var ise bunu @Global() dekoratörü ile destekleyebilir ve her yerde kullanılmasını sağlayabilirsiniz. @Global() kullanılan modüllerin servislerini sadece ilgili servise direkt olarak dahil edip kullanabilirsiniz ek olarak module dahil etmenize gerek kalmaz.
Daha fazlası için https://docs.nestjs.com/modules
Eline sağlık.
Sağolun, teşekkür ederim. 😊