DDD #2 – Anlamın Sınırları
Problem Space, Subdomain ve Bounded Context ile stratejik tasarıma derin dalış.
DDD yazı serisinin ikinci yazısından merhaba.
Bir önceki yazıda DDD’ye güçlü bir giriş yaptık. Nedir, neden kıymetlidir; bunu anlamaya çalıştık. Bize eşlik edecek olan Ubiquitous Language’i keşfettik. Anemic design’i tanıdık ve neden ondan kaçınmamız gerektiğini konuştuk.
Eğer bir önceki yazıyı okumadıysan, lütfen önce onu oku. Sonra buraya geri dön.
Umarım DDD’nin zihninde yeterince demlenmesine izin vermişsindir. Vermediysen de bundan sonrası için buna özellikle dikkat et. DDD oldukça “soft” bir konu. Üzerinde düşünmeye, zihninde tutmaya izin verdiğinde çok daha kolay kavranıyor.
Hala tam anlamamış gibi hissediyor olabilirsin.
Merak etme, bu oldukça normal.
Bu yazıda Bounded Context’i keşfedeceğiz ve DDD’nin stratejik tasarım araçlarına giriş yapacağız.
Üzerinde çalıştığımız bir ürün için aşağıdaki soruların cevaplarını bulmayı öğreneceğiz:
Neden stratejik tasarım bu kadar önemli?
Problem space ve Solution space nedir?
Domain nedir, sınırları nelerdir?
Subdomain nedir?
Bounded Context nedir?
Şimdi hazırsan başlayalım ☕️
1. Strategic Design, Tactical Design & DDD-Lite
Domain’i tasarlamaya başlamadan önce, neyi tasarlayacağımızı netleştirmemiz gerekir. En az bunun kadar önemli olan bir diğer konu da, neyi bilinçli olarak tasarlamayacağımızdır. Başlangıçta vereceğimiz kararların ne kadar kritik olduğundan bir önceki yazıda bahsetmiştik. İşte şimdi tam olarak o noktadayız.
Derinlere inmeden önce, kuş bakışı bir perspektife ihtiyacımız var. Bu yüzden işe Strategic Design ve Tactical Design’ı tanıyarak başlayalım.
1.1. Stratejik Tasarım (Strategic Design):
Büyük resmin döndüğü yer burasıdır.
Stratejik tasarım; business stratejiye, şirketin değer önerisine, para kazandığı alanlara ve organizasyonel yapıya odaklanır. Asıl mesele, “Neyi, neden inşa ediyoruz?” sorusuna cevap bulmaktır.
Bu aşamada Domain, Subdomain, Bounded Context ve Context Map gibi araçlar kullanılarak bir tasarım ortaya çıkar. Bunların her birini ilerleyen bölümlerde detaylıca ele alacağız. Şimdilik bilmen gereken şey şu: Bu kavramların tamamı stratejik tasarıma hizmet eder.
Burada code düşünülmez. Odak tamamen business’ın detaylı bir röntgenini çekmektir.
Stratejik tasarımın ana amacı; business’ı en ince ayrıntısına kadar inceleyerek mantıksal sınırları olan parçalara ayırmak, Core Domain’i belirlemek ve buna bağlı olarak ekipler arasındaki sınırları netleştirmektir. Evet, DDD organizasyonel yapıyı da etkiler. Hatta daha doğru bir ifadeyle, ekiplerin en verimli şekilde çalışabilmesi için organizasyona güçlü bir yön duygusu kazandırır.
Stratejik tasarım hatalı yapıldığında ise ortaya şu tip sistemler çıkar: Teknik olarak başarılı ama işte karşılığı olmayan ya da birbirleriyle sürekli çatışan, silo halinde çalışan sistemler.
1.2. Taktiksel Tasarım (Tactical Design)
Başlığı Türkçe yazmamın sebebi, bu kavramı en azından bir kez duymuş olmanı sağlamak. Günün birinde bir yerde karşına çıktığında, beynin bu bağlantıyı kurabilmeli. Ama gerçekçi olalım: Bunu %99,9 ihtimalle Tactical Design olarak duyacaksın. Zihnine de diline de bu haliyle yerleştirmen çok daha sağlıklı.
Tactical Design, teknik analizin detaylarına ve kodun implementasyonuna odaklanır. Strategic Design ile belirlenen sınırlar içerisinde, domain’lerin nasıl modelleneceği asıl meseledir.
Bu aşamada kullandığımız araçları kabaca şöyle sıralayabiliriz: Entities, Value Objects, Aggregates, Domain Services ve Events.
Amaç; belirlenmiş bir Bounded Context içinde, dilsel bağlamı da koruyarak iş kurallarını anlaşılır ve eksiksiz bir şekilde koda dökmektir. Yani mesele parıltılı, karmaşık teknik implementasyonlar değildir. Mesele; basit, net, ne eksik ne fazla bir modelleme yapabilmektir.
İyi modellenmiş bir domain, bazen bir sanat eseri gibi hissettirir. Bazen de iyi bestelenmiş bir müzik gibi. Notaların bir aradalığındaki o uyumu fark edersin.
Tactical Design, Strategic Design’ın çizdiği sınırlar (Bounded Context) içerisinde anlam kazanır.
1.3 DDD Lite
DDD’nin bir lite versiyonu olduğunu düşündüysen, doğru yerdesin.
Strategic Design ve Tactical Design’dan bahsettik. DDD Lite, DDD’nin stratejik kısmını büyük ölçüde es geçip yalnızca Tactical Design tarafına odaklanılan halidir. Yani işi daha çok kod seviyesindeki araçlara indirger.
Başka bir deyişle: DDD Lite, “DDD yapıyorum” denildiğinde yalnızca implementasyon tarafının kastedildiği yaklaşımdır.
Eğer DDD uyguladığını söylerken odağın sadece aşağıdakilerse, büyük ihtimalle DDD Lite uyguluyorsundur:
Entities: Bir kimliği olan ve zaman içinde değişen nesneler
Value Objects: Tamamen stateless olan ve yalnızca taşıdığı değerlerle tanımlanan nesneler (Para birimi, adres, tarih gibi)
Aggregates: Birbirine bağlı nesneler grubu ve bu grubun yönetiminden sorumlu bir Aggregate Root
Domain Services: Tek başına bir Entity, Aggregate ya da Value Object içine sığmayan iş kuralları ve davranışlar
Peki DDD Lite tam olarak neyi dışarıda bırakır? Biraz yakından bakalım.
Ubiquitous Language (Ortak Dil): Yazılımcılar ve iş birimleri arasında ortak bir dil inşa etme çabası ya çok sınırlıdır ya da hiç yoktur.
Bounded Context’ler: Sistemi anlamlı bağlamsal sınırlara ayırmak yerine, çoğu zaman sadece kod içindeki klasörleme yapısına odaklanılır. Sonuçta bağlamdan bağımsız, teknik bir proje yapısı ortaya çıkar.
Context Mapping: Farklı servislerin ya da bağlamların domain ile nasıl ilişki kurduğu düşünülmez. Çoğu zaman bu ilişkiler ne tasarlanır ne de görselleştirilir.
Yani işin mutfağı, felsefesi ve incelikli kısmı bilinçli olarak dışarıda bırakılır.
Özetle DDD Lite,
“Ben DDD’nin teknik nimetlerinden faydalanayım ama işin felsefesiyle uğraşamam” diyenlerin tercih ettiği yaklaşımdır. Ve senin de şu anda düşündüğün gibi, “DDD uyguluyoruz” diyen şirketlerin büyük bir kısmı, en iyi ihtimalle DDD Lite uyguluyordur.
DDD Lite hem bir tercihtir hem de bir eleştiridir.
Küçük ve orta ölçekli sistemlerde hayat kurtarıcı olabilir. Ancak büyük ölçekli, karmaşık iş kurallarının olduğu sistemlerde işleri daha da karmaşıklaştırır. Ve çoğu zaman kaçınılmaz olarak Big Ball of Mud’a dönüşür.
2. Domain, Problem & Solution Spaces
2.1. Domain Kavramı
Öncelikle Domain Driven Design derken kastettiğimiz Domain’in ne olduğunu netleştirmemiz gerekiyor.
Domain, bir organizasyonun varlık nedeni, tüm çabalarının toplamı ve sahip olduğu bilginin bütünüdür. Yani Domain derken, bir şirketin tek bir departmanındaki bilgiden değil; organizasyonun tamamından bahsediyoruz. Faaliyet gösterdiği tüm iş alanlarını, süreçleri ve bu süreçler boyunca biriken bilgiyi kapsar.
Örneğin bir banka için bu Domain bankacılıktır.
Bir havayolu şirketi için ise havacılıktır.
2.2 Problem Space
Problem Space, Domain’in hangi kısmına odaklandığını gösterir. Bu aşamada henüz “Nasıl çözeceğiz?” sorusunun cevabı yoktur. Asıl mesele, hangi problemin çözülmesinin stratejik olarak önemli olduğudur.
Problem Space, Domain’in tamamını değil; çözülmesi gereken belirli bir iş problemini temsil eder. Bu noktada elimizdeki en önemli kavramlardan biri Subdomain’lerdir. Burada kritik olan şudur: Subdomain çözüme değil, Problem Space’e aittir. Yani hala iş tarafındayız, henüz çözüm konuşmuyoruz.
Problem Space; Core Domain ve onu destekleyen Subdomain’lerin bir bileşimidir.
2.2.1 Core Domain
Core Domain, asıl rekabet avantajı yaratan Domain parçasıdır.
Örneğin Domain bir lojistik şirketiyse, Core Domain çoğu zaman rota optimizasyonu ya da warehouse optimizasyonu gibi alanlardır. Yani şirket için çözülmesi zor olan, gerçekten fark yaratan problem Core Domain’i temsil eder. Şirket bu problemi çözdüğü için para kazanır; rakiplerinden daha iyi çözdüğü için öne çıkar.
Bu yüzden Core Domain, Domain içindeki en kıymetli parçadır. Doğru yatırımlar burada yapılmalıdır. Şirket içindeki en iyi yazılımcılar bu alana kanalize edilmeli, bu bilgi bilinçli şekilde korunmalıdır.
Core Domain’in bazı ayırt edici özellikleri vardır:
Her Domain için özelleşmiştir
Dışarıdan kolayca satın alınamaz
Yanlış tasarlanırsa doğrudan mali zarara neden olabilir
Korunması gereken bilgidir; şirket dışına sızması engellenmelidir
2.2.2 Subdomain
Subdomain, Domain’in mantıksal olarak ayrılmış parçalarıdır. Her biri farklı bir iş problem alanını temsil eder. Core Domain de bir Subdomain’dir. Yani Subdomain’lerin bazıları stratejik olarak çok kritikken, bazıları destekleyicidir; bazıları ise Domain’den bağımsız sayılabilecek kadar geneldir ve neredeyse her şirkette benzer şekilde bulunur.
Bir Domain’i Subdomain’lerine ayırarak okumak oldukça kıymetlidir. Çünkü bu sayede:
Hangi Subdomain’in kritik, hangisinin daha az kıymetli olduğunu görebiliriz
Domain’i kuş bakışı daha net okuyabiliriz
Eforu ve odağı Subdomain’lere göre paylaştırarak daha verimli çalışabiliriz
Subdomain’leri üç ana kategoride inceleyebiliriz.
Core Subdomain
Rekabetin olduğu, şirketi rakiplerinden ayıran Subdomain’dir.
Burada geliştirilen kurallar ve özellikler, doğrudan şirketin kârlılığını etkiler. Bir önceki başlıkta detaylandırdığımız alan tam olarak burasıdır.
Supporting Subdomain
Supporting Subdomain, Core Subdomain’i destekleyen yan Domain’lerdir. Core Subdomain’in tek başına yapmaması gereken ama çalışabilmesi için gerekli olan alanları temsil eder.
Bu Subdomain’ler:
Domain bilgisi barındırır; yani hâlâ şirkete özeldir
Business açısından kritiktir
Ancak rekabet avantajı yaratmaz
Supporting Subdomain’ler genellikle Core Domain’i sade tutar ve kritik olmayan operasyonel yükü onun üzerinden alır.
Generic Subdomain
Generic Subdomain, neredeyse tüm şirketlerde bulunan ve büyük ölçüde aynı olan Subdomain’lerdir. Özel bir domain bilgisi barındırmaz; en fazla şirket özelinde küçük uyarlamalar içerir.
Bu Subdomain’ler:
Neredeyse tamamen standarttır
Dışarıdan satın alınabilir
Çoğu zaman kendin yazmak anlamlı değildir
Notification, Identity Management ve Logging gibi alanlar buna iyi örneklerdir.
Unutmamak gerekir ki Subdomain’ler Problem Space’e aittir. Yani hala iş tarafındayız. Henüz yazılım modeli ya da teknik çözüm konuşmuyoruz.
2.3 Solution Space
Evet, artık Solution Space’e geçiyoruz.
Problem Space’te tanımlanan ihtiyaçların yazılım olarak nasıl karşılanacağı, Solution Space’in cevap aradığı sorudur. Bu noktada işin içine teknik kararlar, modeller ve sınırlar girer.
Problem space işin doğası ile ilgilidir, solution space ise bunun yazılım karşılığıdır.
2.3.1 Bounded Context
Bounded Context, bir domain modelinin yaşadığı sınırdır. Bu sınırlar içinde konuşulan dil ise Ubiquitous Language’dir.
Bir Domain içindeki bir kavramın ne anlama geldiğini, ancak hangi Bounded Context içinde konuşulduğunu bilerek anlayabiliriz. Çünkü tek bir Domain içinde birden fazla Bounded Context vardır ve her Context kendi ortak diline sahiptir.
Bu da şunu gösterir: Bounded Context aynı zamanda dilsel bir sınırdır.
Eğer bir kavramın birden fazla anlama geldiğini düşünüyorsan, büyük ihtimalle Context fazla büyümüştür ve aslında birden fazla Bounded Context’in içindesindir.
Bounded Context Dilsel Bir Sınırdır
Dil, tahmin edebileceğin üzere DDD’nin en kritik konularından biridir. Bu yüzden “dilsel sınır” derken neyi kastettiğimizi biraz daha netleştirelim.
Bir Bounded Context içinde:
Kavramlar ve terimler nettir, anlamları sabittir
Domain modeli, dili bire bir yansıtır
İki ayrı Context’te aynı kavramın farklı anlamlara gelmesi, farklı özellikler ve davranışlar barındırması son derece yaygındır.
Örneğin bir bankacılık Domain’inde Account kavramını ele alalım.
Bir Checking Account Context içinde Account; para yatırma, para çekme, bakiye takibi ve günlük işlem limitleri gibi davranışlara sahiptir. Bu bağlamda Account, müşterinin günlük finansal işlemlerini temsil eder ve ağırlıklı olarak transaction odaklıdır.
Aynı Domain içinde yer alan bir Savings Account Context’te ise Account bambaşka bir anlama sahiptir. Burada Account; faiz hesaplama, vadeye bağlı kurallar ve birikim davranışlarıyla tanımlanır. Günlük işlem hareketliliği ikinci plandadır; esas odak uzun vadeli değer saklamadır.
Her iki Context’te de nesnenin adı Account olabilir. İsimler üzerinden yapay bir ayrım yaratmaya gerek yoktur. Anlam farkı zaten Bounded Context tarafından belirlenir.
Sık yapılan hatalardan biri, aynı Domain’de ama farklı Bounded Context’lerde yer alan bu Account nesnelerini tek bir yapı altında birleştirmeye çalışmaktır. Bu yaklaşım modeli gereksiz yere karmaşıklaştırır ve her iki Context’in dilini de bulanıklaştırır. Doğru yaklaşım, her bir Account’un kendi Bounded Context’i içinde, kendi Ubiquitous Language’ı ile yaşamasına izin vermektir.
Modelden Daha Fazlası
DDD denildiğinde çoğu yazılımcının aklına sadece Domain katmanı gelir. Ancak Bounded Context’i gerçekten kavradığında, bunun yalnızca Domain katmanından ibaret olmadığını fark edersin.
Bounded Context bir sınır çizer. Bu sınır sadece backend developer için değil; takım içindeki tasarımcı, frontend developer ve hatta ürün tarafı için de geçerlidir.
Bounded Context, yalnızca domain modelini değil, modelin çalışmasını sağlayan tüm unsurları kapsar:
Persistence şeması (dolayısıyla database modeli)
Application servisleri
UI katmanı
API endpoint’leri
Bu şu anlama gelir: Domain modelde kullandığın isimlendirmeyi database şemasında da görürsün. Application servisleri ilgili Bounded Context’e hizmet eder ve aynı dili konuşur. UI ya da diğer servisler için açılan endpoint’ler de yine bu Context’i yansıtır.
Tasarım ve Frontend’de Dilsel Sınırlar
UI konusu biraz kafa karıştırıcı olabilir; o yüzden biraz açmak istiyorum.
Bir UI tasarlandığında, tasarımda kullanılan dil çoğu zaman koddaki dilden oldukça farklı olur. Bu genellikle iki sebepten kaynaklanır:
Ya tasarımcı domain expert’lerden kopuk bir süreç yürütmüştür ya da backend developer Ubiquitous Language’i yeterince dikkate almamıştır.
Frontend tarafında bu kopukluk daha da belirginleşebilir. Genel olarak frontend kodunun domain diliyle okunabilir olması çok da önemsenmez. Sanki böyle bir gereklilik yokmuş gibi davranılır.
Burada şunu netleştireyim:
İş kurallarını UI’da yazmaktan bahsetmiyorum. DDD, Smart UI Anti-Pattern’ı zaten reddeder.
Demek istediğim şey şu:
Data mapping aşamasında kullanılan dil, aynı Bounded Context içinde backend ile aynı dili konuşmalıdır.
Frontend Domain Logic taşımıyor diye Bounded Context içerisinde generic bir dil kullanamayız. Aynı şekilde tasarımda sırf “daha havalı” görünsün diye ortak dilin dışına çıkmak da doğru değildir.
Bounded Context’in Boyutu
Bounded Context’in boyutuna dair kesin bir ölçü yoktur. Burada sayı aramak yerine şu soruyu sormak gerekir:
Ubiquitous Language eksiksiz ve net bir şekilde ifade edilebiliyor mu, yoksa dil bulanıklaşıyor mu?
Bir Bounded Context ne gereğinden fazla kavram içermelidir ne de eksik kalmalıdır. İlgili Subdomain’e ait olmayan bir kavram Context’in içine alınmamalıdır. Ama domain kurallarını doğru şekilde ifade edebilmek için gerekli olan hiçbir kavram da dışarıda bırakılmamalıdır.
Bu, incelikli bir muhakeme gerektiren bir dengedir. Uygulamaya geçtiğinde ne demek istediğimi çok daha net hissedeceksin.
Tek Context, Tek Dil, Tek Takım
Bir Bounded Context, tek bir Ubiquitous Language’ı temsil eder. Bu dili korumanın ve domain’i sağlıklı şekilde çalıştırmanın en iyi yolu, tek bir ekibin bu Context’e odaklanmasıdır.
Yazının başında DDD’nin organizasyon yapısını bile etkilediğinden bahsetmiştim. İşte tam olarak bundan söz ediyorum.
Scale-up aşamasındaki startup’ların en zorlandığı konulardan biri, organizasyonu doğru şekilde büyütebilmektir. Domain —yani şirketin iş stratejisi— büyürken, organizasyonun da Domain ile paralel hizalanması gerekir. Doğru iş bölümünü yapmak ve buna uygun ekip yapılanmasını kurmak kritik hale gelir.
Küçükken her şey daha kolaydır. Evet, şirkete para giriyordur; ama büyümeye devam edebilmek için bu problemin çözülmesi gerekir.
İşte DDD’nin Subdomain kavramı ve onunla birlikte gelen doğru Bounded Context yapılanması, şirkete yalnızca bir yazılım mimarisi değil; çalışan bir organizasyon yapısı da sunar.
2.4 Subdomain vs Bounded Context
DDD’nin en kafa karıştırıcı noktasını sona bıraktım.
Bounded Context’i okurken zihninin bir köşesinde sürekli Subdomain ile Bounded Context arasındaki ilişki dolaştıysa, yalnız değilsin. “Aynı şey gibi ama tam da değil” diye düşündün muhtemelen. Şimdi bunu netleştirelim.
İsimleri benzer, birlikte anılırlar ama farklı problemleri çözerler ve farklı düzlemlerde dururlar.
Subdomain, Problem Space’e ait bir kavramdır.
Bounded Context ise Solution Space’e.
Bu ayrımı yapmadan yapılan her modelleme, er ya da geç dilsel olarak bulanıklaşır.
Subdomain Problemi Tanımlar
Subdomain her zaman problemle ilgilenir ve problemi tanımlar. Domain’in business açısından en anlamlı parçalarını temsil eder. Bu noktada henüz ortada yazılım yoktur, kod yoktur.
Subdomain dediğinde, aklına kesinlikle teknik ya da çözüme dair bir şey gelmemelidir. Eğer bu aşamada çözüm uzayında düşünmeye başlarsan, doğru soruları soramazsın.
Subdomain şu sorularla ilgilenir:
Bu iş alanında hangi Subdomain’ler var?
Hangisi Core, hangisi Supporting, hangisi Generic?
Organizasyon için nerede rekabet avantajı var? (Core Domain’i belirlemek için)
Yani Subdomain, neyle uğraştığımızı anlatır.
Ama tek başına bir yazılım çözümü değildir.
Bounded Context Çözümü Somutlaştırır
Bounded Context, Subdomain’de tanımlanan problemin yazılımda nasıl ele alındığını gösterir.
Bu yüzden Bounded Context’i, Subdomain’in yazılım karşılığı olarak düşünebilirsin. Ama bu ilişki bire bir olmak zorunda değildir.
Ve geldik bir diğer kritik noktaya.
İdeal Olan: Bire Bir Hizalanma
İdeal senaryoda, bir Subdomain’e karşılık tek bir Bounded Context gelir.
Sıfırdan geliştirilen, yani greenfield projelerde bu oldukça mümkündür ve çok değerlidir. Bu durumda business dili ile yazılım dili neredeyse tamamen örtüşür.
Ama legacy sistemler gerçeği varken, bunun her zaman mümkün olmadığını hepimiz biliyoruz. Bu tür durumlarda şunlarla karşılaşabiliriz:
Bir Subdomain, birden fazla Bounded Context’e yayılabilir
Bir Bounded Context, birden fazla Subdomain’den kavramlar içerebilir
Bu durumlar çoğu zaman kötü tasarlanmış sistemlerin bir sonucudur. Ancak bu gerçeği yok sayamayız.
Stratejik Tasarım Olmadan DDD Olmaz
DDD’ye hızlı bir giriş yaptıktan sonra, bu yazı ile biraz daha derine daldık. Bir önceki yazıda kafan karıştıysa, bu yazıdan sonra iyice darmadağın olmuş olabilir. Doğru yoldayız demektir 🙂
DDD’nin Strategic Design kısmını kavramak kritik. Bu yazıda ele aldığımız kavramları atlayarak uygulanan DDD, teknik olarak iyi görünebilir ama ya çalışmaz ya da en iyi ihtimalle Big Ball of Mud olmaktan öteye gidemez.
Ubiquitous Language konuşmaya devam ettik ve bundan sonraki yazılarda da etmeye devam edeceğiz. Çünkü bu yazıdan da anlayacağın üzere, karmaşık iş süreçlerinin içinde bize yolumuzu gösteren pusula Ubiquitous Language.
Problem Space ve Solution Space kavramları hayatına ilk defa girmiş olabilir. Senden ricam, bunlar üzerine biraz daha kafa yorman. Solution Space’de çalışmaya alışmış olabilirsin; ama Problem Space’de kalıp, çözümü hiç düşünmeden probleme odaklanabilirsen çok daha doğru bir modelleme yapabilirsin. Kodu düşünmeden problemi konuşmak yazılımcılar için zor, biliyorum.
Subdomain ve Bounded Context, DDD’de en çok karıştırılan kavramlar. Subdomain tiplerini ne kadar iyi kavrarsak, o kadar doğru Bounded Context’ler belirleriz. Tahmin edersin ki doğru belirlenen sınırlar, beraberinde doğru implementasyonu getirir.
DDD yazı serisinin bu ikinci yazısıyla birlikte, yanlış modellemenin maliyetinin ne kadar yüksek olduğunu daha net görmeye başladık. Ne kadar iyi Strategic Design, o kadar iyi Tactical Design demek. Aksi halde DDD’nin bir Lite versiyonundan öteye geçemiyoruz.
Seriyi takipte kal. Bir sonraki yazıda bir Problem Space’in içinde vakit geçirip, Context Map ile domain modelleyeceğiz.
Kaynaklar
Implementing Domain-Driven Design (https://learning.oreilly.com/library/view/implementing-domain-driven-design/9780133039900/)
Domain-Driven Design: Tackling Complexity in the Heart of Software (https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215)
Buraya kadar benimle kalıp okuduğun için teşekkürler!
Eğer ilham verici ya da düşündürücü bulduysan, aşağıdaki ❤️ ikonuna tıklayabilir, ilgisini çekeceğini düşündüğün biriyle paylaşabilir ve gelecek sayılardan haberdar olmak için abone olabilirsin.
👋 Bağlantıda kalalım! Beni LinkedIn’de bulabilirsin.


'DDD lite' kavramını hiç duymamıştım ama daha önce çok kez gördüğümü farkettim. Çok bilgilendirici bir yazı olmuş, devamını bekliyoruz ☕