Geliştiriciler Etki Alanı Odaklı Tasarım (DDD), CQRS ve Event Sourcing ile ilk kez temasa geçtiklerinde zaten yanlarında zihinsel modeller getiriyorlar. Yıllarca nesneler ve tablolarla çalışmak, veriler hakkındaki düşünme biçimlerini şekillendirdi.
Duyurudan sonra devamını okuyun
Golo Roden, native web GmbH'nin kurucusu ve CTO'sudur. Etkinlik ve hizmet odaklı dağıtılmış mimarilere odaklanarak web ve bulut uygulamaları ile API'lerin tasarımı ve geliştirilmesiyle ilgilenmektedir. Yol gösterici ilkesi, yazılım geliştirmenin kendi başına bir amaç olmadığı, her zaman temeldeki profesyonelliği takip etmesi gerektiğidir.
Ve böylece “toplama” kelimesini duyduklarında akıllarında hemen tanıdık bir görüntü oluşur: Toplama bir nesne gibi olmalıdır ve nesneler tablolara eşlenir. Bu sezgi doğru görünüyor. Ama öyle değil ve ekstra adımlarla şüpheli bir şekilde CRUD'a benzeyen bir sisteme yol açıyor.
Bu modeli sayısız kez gördüm. Ekipler olay odaklı sistem adını verdikleri bir sistem oluşturur ve sonunda bir birey elde ederler. booksher tu alanını içeren tablo Book-Toplam var. Esasen, aktarım mekanizması olarak yalnızca olayları içeren ilişkisel bir veritabanını yeniden yarattılar. DDD, CQRS ve Event Sourcing'in güçlü yanları, yani bu kavramların vaat ettiği esneklik henüz kullanılmamıştır.
Toplu yanlış anlama
Sorun, geliştiricilerin genel olarak bir bütün olarak düşündüğü şeydir: tek bir şeyle ilgili tüm veriler için bir kapsayıcı. Kendilerini tanıtıyorlar Book-Önce toplayın ve mülkleri listelemeye başlayın:
BookAggregate {
id: string
title: string
author: string
isbn: string
currentBorrower: string | null
dueDate: Date | null
location: string
condition: string
purchasePrice: number
acquisitionDate: Date
lastInspectionDate: Date
popularityScore: number
}
Bir nesneye benziyor. Bütün alanları var. Temiz bir şekilde bir veritabanı tablosuna eşlenebilir. Hata tam olarak burada yatıyor: Toplama bir veri kabı olarak muamele etmek.
Duyurudan sonra devamını okuyun
Bu şekilde düşündüğünüzde, toplamınız bir kitap hakkında bilmek isteyebileceğiniz her şeyin şişirilmiş bir temsili haline gelir. Okuma şeklinizin yapısını yansıtır çünkü bunların temelde farklı amaçlara hizmet eden temelde farklı kavramlar olduğunu henüz fark etmemişsinizdir.
Aslında bir toplam nedir
DDD'ye göre toplam, karar vermenin tutarlılık sınırıdır. Hepsi bu. Amacı, komutları işlerken iş kurallarına uyulmasını sağlamaktır. Bir komutun geçerli olup olmadığına karar vermek için yalnızca gerekli bilgilere ihtiyacı vardır.
Bunu düşün BorrowBook-Emretmek. Bir kitabın ödünç alınıp alınamayacağına karar vermek için bilmeniz gereken tek şey şudur: Kitap şu anda mevcut mu? Başlığa, yazara, ISBN'ye, satın alma fiyatına, konuma veya son inceleme tarihine ihtiyacınız yoktur. Bu bilgilerin hiçbiri, bu özel komutun başarılı olup olmayacağına karar vermenize yardımcı olmayacaktır. Bu, yalnızca kararla ilgili durumu içerdiğinden toplamın çok küçük olabileceği anlamına gelir.
Kütüphane örneğimiz için, uygun şekilde tasarlanmış bir tane olabilir. Book-Bu nedenle toplam şuna benzer:
BookAggregate {
isAvailable: boolean
currentBorrower: string | null
}
Karar vermeniz yeterli:
- Bu kitap ödünç alınabilir mi? (
isAvailable === true) - Bu kişi iade edebilir mi? (
currentBorrower === personId)
Kitapla ilgili diğer her şey, her bilgi başka bir yere aittir: topluluğa değil, okuma kalıplarına.
Okuma modelinin yanlış anlaşılması
Geliştiriciler bir toplamanın belirli alanlara sahip olduğunu kabul eder etmez bir sonraki hata şu şekilde olur: “Toplamda bu alanlar varsa, okuma modeli tablomda da bu alanlar bulunmalıdır.”
Sonuç tahmin edilebilir. Bir tane yaratırsın books-Sütunlu tablo id, title, author, isbn, borrower, dueDate, location, condition, purchasePrice ve aklınıza gelebilecek diğer alanlar. Bu yekpare yapıda sorgular karmaşık birleşimler haline gelir. Performans zarar görüyor. Esneklik kaybolur.
Bu, olay kaynağına uygulanan CRUD düşüncesidir. Olaylar vardır ama bunlar yalnızca bir ulaşım katmanıdır. Sistem, tıpkı geleneksel ilişkisel veritabanı gibi, verilerin tek bir kanonik temsili etrafında dönüyor.
Gerçekte okuma modelleri nelerdir?
Okuma modelleri, belirli sorgular için optimize edilmiş projeksiyonlardır. Veri yapılarına değil, kullanım senaryolarına ihtiyacınız var. Temel içgörü şu: Okuma kalıpları toplamlardan değil olaylardan kaynaklanır:
- Toplamınız ne olacağına karar verir.
- Olaylar yaşananları kaydeder.
- Belirli soruları etkili bir şekilde yanıtlamak için bu etkinliklerden okuma kalıpları oluşturulur.
Okuma modellerinin agregaların yapısını yansıtması gerektiğini belirten hiçbir gereklilik, hiçbir kural, hiçbir mimari prensip yoktur.
Gerçekte bunun tersi doğrudur. Bir etkinlik akışından birçok farklı okuma modeli oluşturabilirsiniz. Bu, tablolarda düşünürken kaybolan CQRS'nin gücüdür.
Kütüphane örneği: bir yazma modeli, birçok okuma modeli
Bunu özellikle kütüphanemizle yapalım. Bir tane var Book– Kararları yöneten toplu:
BookAggregate {
isAvailable: boolean
currentBorrower: string | null
}
Olaylar sistem üzerinden akar: BookAcquired, BookBorrowed, BookReturned, BookRemoved ve benzeri. Bu olaylar yaşananlara ilişkin zengin bilgiler içermektedir.
Şimdi insanların yanıtlanmasını istediği farklı soruları ele alalım:
- Katalog aramasında mevcut kitaplar başlıkları, yazarları ve ISBN kodlarıyla birlikte gösterilmelidir. Geçmişi veya fiziksel konumu ödünç almakla ilgilenmiyor.
- Üyenin kontrol panelinde (“Kitaplarım” sayfası) üyenin hangi kitapları teslim aldığı, bunların teslim tarihi ve herhangi birinin süresinin dolup dolmadığı gösterilmelidir. ISBN'ye veya fiziksel konuma gerek yok.
- Kütüphaneciler için istatistiksel kontrol panelinin hangi kitapların en popüler olduğunu, ortalama ödünç alma sürelerini ve zaman içindeki eğilimleri bilmesi gerekir. Mevcut kullanılabilirlik gerektirmez.
- Gecikme raporu, borçlunun adını, iletişim bilgilerini, kitap başlığını ve geciktiği gün sayısını gerektirir. Satın alma fiyatları veya durum değerlendirmeleri gerektirmez.
- Envanter yönetimi sistemi fiziksel konumları, durum derecelendirmelerini ve son denetim tarihlerini gerektirir. Borçlunun bilgisine gerek yoktur.
Bunların her biri, aynı olaylardan oluşturulan ve kendi özel kullanım durumu için optimize edilmiş ayrı bir okuma modelidir.
Büyük bir masa yerine birçok küçük okuma modeli
Bu okuma kalıpları şöyle görünebilir:
Katalog okuma modelini arayın:
{
bookId: string
title: string
author: string
isbn: string
isAvailable: boolean
}
Borçlu kontrol paneli okuma şablonu:
{
memberId: string
books: [
{
bookId: string
title: string
dueDate: Date
daysOverdue: number
}
]
}
Kütüphane istatistikleri okuma şablonu:
{
bookId: string
title: string
totalBorrows: number
averageDuration: number
popularityRank: number
}
Süresi dolmuş kitap okuma düzeni:
{
bookId: string
title: string
borrowerId: string
borrowerName: string
contactEmail: string
daysOverdue: number
}
Stoktaki yatak modeli:
{
bookId: string
location: string
condition: string
lastInspectionDate: Date
}
Herhangi bir okuma modeli
- yalnızca kullanım durumu için gerekli alanlara sahiptir,
- gerektiğinde başka bir veritabanında saklanabilir (işlemler için PostgreSQL, arama için Elasticsearch, hızlı aramalar için Redis),
- herhangi bir zamanda olaylardan yeniden oluşturulabilir ve
- diğer okuma modellerinden bağımsız olarak gelişir.
Çarpımsal etki
Burası olay kaynağının gerçek gücünü gösterdiği yerdir. Birçok özel okuma modeli bir olaylar akışından türetilir. Her biri küçük, odaklanmış ve hızlıdır. Yeni bir okuma modeli eklemek, mevcut yazma modelinin veya okuma modellerinin değiştirilmesini gerektirmez. Aynı olaylardan başka bir projeksiyon oluşturmanız yeterlidir.
Yeni bir ilişkiye mi ihtiyacınız var? Yeni bir okuma modeli oluşturun. Yavaş bir sorguyu optimize etmeniz mi gerekiyor? Bu özel okuma modelini başka hiçbir şeye dokunmadan yeniden yapılandırın. Yeni bir kullanım senaryosunu desteklemeniz mi gerekiyor? Başka bir projeksiyon ekleyin.
Bu esneklik CQRS'nin vaadidir. Ancak bu yalnızca okuma kalıplarını toplamlarınızın bir yansıması olarak görmeyi bıraktığınızda gerçekleşir.
Bu neden önemlidir?
Pratik avantajlar dikkat çekicidir:
- Her okuma modeli küçük ve uzmanlaşmış olduğundan performans artar. Sorgular artık tam olarak ihtiyaç duydukları verilere ulaşmıyor. Dizinler belirli erişim kalıpları için optimize edilebilir.
- Yazma desenini veya diğer okuma desenlerini etkilemeden okuma desenlerini ekleyebileceğiniz, değiştirebileceğiniz veya kaldırabileceğiniz için esneklik artar. Takımlar okuma modellerine bağımsız olarak sahip olabilirler.
- Açıklık, her okuma modelinin açık bir amacı olması gerçeğinden gelir. Hangi verinin hangi kullanım durumu için olduğu konusunda belirsizlik yoktur. Her okuma modelinin yapısı cevapladığı soruları yansıtır.
- Bağımsızlık, farklı ekiplerin, kalıp değişikliklerini koordine etmek zorunda kalmadan, farklı okuma kalıpları üzerinde çalışabilmesinden kaynaklanmaktadır. Olaylar sözleşmedir, veritabanı tabloları değil.
Tabloyu unut
Olay kaynağı bulmanın en zor kısmı, CRUD sistemlerinde size iyi hizmet eden zihinsel modellerin öğrenilmemesidir. Nesneler ve tablolar yararlı kavramlardır ancak toplamaları anlamak ve kalıpları okumak için doğru mercek değildirler.
“Toplamda hangi alanlar var?” diye sormayı bırakın. Kendinize şu soruyu sormaya başlayın: “Bu kararı vermek için neyi bilmem gerekiyor?”
“Bu toplam için hangi tabloya ihtiyacım var?” diye sormayı bırakın. “Kullanıcılarımın hangi soruları yanıtlaması gerekiyor?” diye sormaya başlayın.
Toplam, kararınızın basitleştirilmiş ve odaklanmış sınırıdır. Olaylar, olup bitenlere dair tarihsel kaydınızdır. Okuma modelleri, belirli sorgular için optimize edilmiş görünümlerdir.
Bunlar üç farklı kavramdır. Aynı yapıya sahip olmaları gerekmez. Aslında muhtemelen yapmamaları gerekir.
(Ben)

Bir yanıt yazın