Senior
Çekirdek'te periferik bileşen bağımlılıklarının kullanım sorununu nasıl çözersiniz?
sobes.tech yapay zeka
AI'dan gelen yanıt
Çekirdek (alan mantığı) içinde çevresel bileşenlerin (adaptörler, arayüzler) bağımlılıklarının kullanılması sorununu çözmek, örneğin, Temiz Mimari veya DDD gibi mimarilerde, Bağımlılıkların Tersine Çevrilmesi İlkesi (Dependency Inversion Principle - DIP) kullanılarak yapılabilir.
DIP'nin özü:
- Üst seviye modüller alt seviye modüllere bağlı olmamalıdır. Her ikisi de soyutlamalara bağlı olmalıdır.
- Soyutlamalar detaylara bağlı olmamalıdır. Detaylar soyutlamalara bağlı olmalıdır.
Pratik uygulama:
- Çekirdek arayüzleri bildirir: Çekirdek, çevresel bileşenlerin ihtiyaç duyduğu fonksiyonları tanımlayan soyutlamaları (arayüzler veya soyut sınıflar) belirler.
- Çevresel bileşenler arayüzleri uygular: Dış modüller (veritabanları için adaptörler, HTTP istemcileri, dosya sistemleri vb.) bu arayüzleri uygular.
- Bağımlılık Enjeksiyonu (Dependency Injection - DI): Çevresel bileşenler, genellikle uygulamanın daha yüksek seviyelerinde (örneğin, bileşen kökünde veya DI konteyneri kullanılarak) dışarıdan çekirdeğe enjekte edilir. Çekirdek sadece soyutlamalarla çalışır.
Node.js'te DIP kullanımına örnek:
Varsayalım ki, veriye erişmesi gereken bir çekirdeğimiz var.
// src/domain/interfaces/UserRepository.ts
// Çekirdek arayüzü bildirir
export interface UserRepository {
getUserById(id: string): Promise<User | null>;
}
// src/domain/entities/User.ts
// Çekirdek varlığı
export class User {
constructor(public id: string, public name: string) {}
}
// src/domain/usecases/GetUserUseCase.ts
// Çekirdek kullanımı, UserRepository soyutlamasına bağlıdır
import { UserRepository } from '../interfaces/UserRepository';
import { User } from '../entities/User';
export class GetUserUseCase {
constructor(private userRepository: UserRepository) {}
async execute(id: string): Promise<User | null> {
return this.userRepository.getUserById(id);
}
}
// src/infrastructure/database/MongoDbUserRepository.ts
// Çevresel bileşen, çekirdek arayüzünü uygular
import { UserRepository } from '../../domain/interfaces/UserRepository';
import { User } from '../../domain/entities/User';
export class MongoDbUserRepository implements UserRepository {
// MongoDB ile etkileşim mantığı burada olacak
async getUserById(id: string): Promise<User | null> {
console.log(`Fetching user with id ${id} from MongoDB...`);
// Veri alma simülasyonu
if (id === '123') {
return new User('123', 'John Doe');
}
return null;
}
}
// src/app/CompositionRoot.ts
// Bileşen kökü bağımlılıkları toplar
import { GetUserUseCase } from '../domain/usecases/GetUserUseCase';
import { MongoDbUserRepository } from '../infrastructure/database/MongoDbUserRepository';
// Bağımlılık enjeksiyonu: Çekirdek, MongoDbUserRepository uygulamasını arayüz aracılığıyla alır
const userRepository = new MongoDbUserRepository();
const getUserUseCase = new GetUserUseCase(userRepository);
// Artık kullanım örneğini kullanabiliriz
async function run() {
const user = await getUserUseCase.execute('123');
if (user) {
console.log(`Found user: ${user.name}`);
} else {
console.log('User not found');
}
}
run();
Bu yaklaşımın avantajları:
- Çekirdek bağımsızlığı: Çekirdek, çevresel bileşenlerin belirli uygulamalarını bilmez.
- Test edilebilirlik: Çekirdek, arayüzlerin mock uygulamalarıyla kolayca test edilebilir.
- Esneklik: Bir uygulamayı (örneğin, veritabanını) başka bir uygulama ile kolayca değiştirebilirsiniz, çekirdek kodunu değiştirmeden.
- Bakım: Kodun bakımı ve değiştirilmesi kolaylaşır.