Layered Architecture: Query → Service → API
Bugün öğrendiğimiz kavramları (transaction, isolation, locking vb.) sistem içinde nerede ve nasıl uygulayacağımızı inceleyeceğiz.
Bu noktada devreye Layered Architecture girer.
Modern yazılım mimarisinde:
Query → Service → API hattı, Separation of Concerns (Sorumlulukların Ayrılması) prensibine dayanır.
Amaç şudur:
- Veritabanı işlemlerini
- Business logic’i
- HTTP katmanını
birbirinden tamamen izole etmek.
1. API Katmanı (Controller)
API katmanı sistemin dış dünyaya açılan kapısıdır. Sadece HTTP protokolü ile ilgilenir.
Görevleri:
- Request’i karşılamak
- Gelen veriyi doğrulamak
- Service katmanını çağırmak
- Response dönmek
// controllers/CartController.js
static async addToCart(req, res, next) => {
try {
const { productId, quantity } = req.body;
const userId = req.user.id;
const result = await CartService.addItem({
userId,
productId,
quantity
});
return res.status(200).json(result);
} catch (error) {
next(error);
}
};
⚠ Controller içinde:
- SQL yazılmaz
- Transaction başlatılmaz
- Business kuralı yazılmaz
2. Service Katmanı (Business Logic)
Service katmanı sistemin beyin kısmıdır.
Burada:
- İş kuralları uygulanır
- Kontroller yapılır
- Transaction boundary belirlenir
- Data katmanı çağrılır
// services/CartService.js
static async addItem({ userId, productId, quantity }) {
return await sequelize.transaction(async (t) => {
const product = await ProductData.getById(productId, {
transaction: t
});
if (product.stock < quantity) {
throw new Error("Yetersiz stok");
}
await CartData.upsertItem(
{ userId, productId, quantity },
{ transaction: t }
);
return { message: "Ürün sepete eklendi" };
});
}
Transaction boundary burada başlar ve burada biter.
Service katmanı:
- Veri nasıl alınır değil,
- İş mantığı nasıl çalışır sorusuyla ilgilenir.
3. Data Katmanı (Repository)
Repository katmanında yalnızca veri işlemleri yapılır.
- Veriyi getir
- Veriyi kaydet
- Veriyi güncelle
Hepsi bu.
// data/ProductData.js
export const getById = async (id, { transaction }) => {
return await Product.findOne({
where: { id },
transaction,
lock: transaction.LOCK.UPDATE
});
};
Burada business logic yoktur. Sadece veritabanı erişimi vardır.
Workflow (Adım Adım)
- Client →
POST /cart/add - Route → Controller’a yönlendirir
- Controller → Service’i çağırır
- Service → Transaction başlatır
- Data → DB’den veriyi çeker (gerekirse locking yapar)
- Service → Kontrolleri yapar ve kaydeder
- Controller → Response döner
Neden DB İşlemlerini Controller’da Yapmayız?
Eğer Controller içinde:
- Veri doğrulama
- Stok kontrolü
- SQL sorgusu
- Transaction yönetimi
- Mail gönderme
gibi işlemleri yazarsan:
- Dosya devasa büyür
- Test edilemez hâle gelir
- Hata ayıklamak zorlaşır
- Kod tekrarları oluşur
Layered mimari sayesinde:
- Kod daha okunabilir olur
- Test etmek kolaylaşır
- Business logic tekrar kullanılabilir
- Sistem büyüdüğünde çökmek yerine ölçeklenir
Mimari Özet
Controller (HTTP)
↓
Service (Business Logic + Transaction)
↓
Repository (DB Access)
Her katman yalnızca kendi sorumluluğundan sorumludur.