2 Ocak 2021 Cumartesi

Calibre Ebook okuyucu ile İngilizce yazılmış bir kitabı anlık çeviri yaparak okumak

 Bu youtube videosunda Calibre Ebook okuyucu ile özellikle ağır İngilizce ile yazılmış bir kitabı anlık çeviri yaparak okumanın nasıl yapılabileciğini anlatmaya çalıştım.





Download Calibre 


Ayrıca bilgisayarınza text to speech uygulaması indirip, çevirdiğiniz metni okutarak sesli bir kitaba sahip olabilirsiniz.










1 Ocak 2021 Cuma

3- Domain-Driven Design ve Hexagonal(Altıgen) Mimari - vaadin.com - Petter Holmström - Çevirsi

"Bu makale dizisinde, Domain Driven Desgin (etki alnına dayalı tasarım)'ın ne olduğunu ve projenize - veya bir kısmının - projelerinize nasıl uygulanacağını öğreneceksiniz." diyor Petter Holmström. Ben de elimden geldiğince bu yazı dizisini Türkçe'ye çevirmeye çalışacağım. Umarım İngilizce okumada zorluk çeken arkadaşlar için yararlı olur.


Yazı Dizisinin Orjinali

Örnek DDD projesi


Serinin diğer yazıları :

2 - Tactical Domain Driven Design (Taktiksel DDD)


Önceki iki makalede, stratejik ve taktiksel alan odaklı tasarım hakkında bilgi sahibi olduk. Şimdi bir domain modelini çalışan yazılıma nasıl dönüştüreceğinizi, daha spesifik olarak bunun altıgen mimariyi kullanarak nasıl yapılacağını öğrenmenin zamanı geldi.

Önceki iki makale, kod örnekleri Java ile yazılmış olsa da oldukça geneldi. Bu makaledeki pek çok teori diğer ortamlarda ve dillerde de uygulanabilir olsa da, bunu açıkça Java ve Vaadin ile yazdım.

Yine içerik, Eric Evans'ın Domain-Driven Design: Tackling Complexity in the Heart of Software and Implementing Domain-Driven Design by Vaughn Vernon kitaplarına dayanıyor ve ikisini de okumanızı şiddetle tavsiye ediyorum. Ancak önceki makalelerde de kendi düşüncelerimi, fikirlerimi ve deneyimlerimi sunmuş olsam da, bu daha da güçlü bir şekilde düşündüklerim ve inandıklarımla renkleniyor. Bununla birlikte, beni DDD ile başlatan şey Evans ve Vernon'un kitaplarıydı ve burada yazdıklarımın kitaplarda bulacaklarınızdan çok da uzak olmadığını düşünmek istiyorum.

Bu, bu makalenin ikinci versiyonu. İlkinde, port kavramını yanlış anlamıştım. Bu, minnettar olduğum bir okuyucu tarafından yapılan bir yorumda belirtildi. Şimdi bu hatayı düzelttim ve örnekleri ve diyagramları buna göre güncelledim. Bu mimari tarz ve DDD hakkındaki yorumlarım hakkındaki yorumlar her zaman memnuniyetle karşılanacaktır.


Neden Altıgen Deniyor?


Altıgen mimari adı, bu mimarinin genellikle tasvir edilme biçiminden gelir:




Bu makalenin ilerleyen bölümlerinde neden altıgenlerin kullanıldığına döneceğiz. Bu mimari aynı zamanda portlar ve adaptörler (arkasındaki ana fikri daha iyi açıklayan) ve onion(soğan) mimarisi (nasıl katmanlı olduğu için) adlarına da giriyor.

Aşağıda "soğana" daha yakından bakacağız. Çekirdekle başlayacağız - domain modeli - ve sonra kendimizi, her seferinde bir katman olarak, adaptörlere ve onlarla etkileşime giren sistemlere ve istemcilere ulaşana kadar çalışacağız.

Altıgen ve Geleneksel Katmanlar


Altıgen mimarinin derinliklerine indiğimizde, daha geleneksel katmanlı mimariye birkaç benzerliği olduğunu göreceksiniz. Aslında, altıgen mimariyi katmanlı mimarinin bir evrimi olarak düşünebilirsiniz. Bununla birlikte, özellikle bir sistemin dış dünya ile nasıl etkileşime girdiğine dair bazı farklılıklar vardır. Bu farklılıkları daha iyi anlamak için katmanlı mimarinin bir özetiyle başlayalım:




İlke, sistemin birbiri üzerine yığılmış katmanlardan oluşmasıdır. Daha yüksek bir katman, daha düşük bir katmanla etkileşime girebilir ancak tersi olamaz. Tipik olarak, domaine dayalı katmanlı bir mimaride, en üstte UI katmanına sahip olursunuz. Bu katman da, bir domain katmanında yaşayan domain modeliyle etkileşime giren bir application servis katmanıyla etkileşime girer. En altta, veritabanı gibi harici sistemlerle iletişim kuran bir altyapı katmanımız var.

Altıgen sistemde, uygulama katmanının ve domain katmanının hemen hemen aynı olduğunu göreceksiniz. Bununla birlikte, UI katmanı ve altyapı katmanı çok farklı bir şekilde ele alınır. Nasıl olduğunu öğrenmek için okumaya devam edin.

Etki Alanı Modeli (Domain Model)

Altıgen mimarinin tam merkezinde, önceki makalede ele aldığımız taktik DDD yapı taşlarını kullanarak uygulanan alan modeli yatıyor. Tüm iş kararlarının alındığı, iş mantığının yaşadığı yer burasıdır. Bu aynı zamanda yazılımın en az değişeceğini umduğumuz en kararlı parçasıdır (tabii işin kendisi değişmedikçe).

Alan modeli, bu dizinin önceki iki makalesinin konusu olmuştur, bu yüzden artık burada ele almayacağız. Bununla birlikte, domain modeli tek başına, onunla etkileşim kurmanın bir yolu yoksa herhangi bir değer sağlamaz. Bunu yapmak için, "soğan" da bir sonraki katmana geçmemiz gerekiyor.

Uygulama Hizmetleri(Application Services)


Bir application servis, müşterilerin alan modeliyle etkileşime gireceği bir cephe görevi görür. Applicaiton servisleri aşağıdaki özelliklere sahiptir:

Durum bilgisi turmazlar (stateless)

Sistem güvenliğini uygularlar

Veritabanı işlemlerini kontrol ederler

İş operasyonlarını düzenlerler ancak herhangi bir iş kararı almazlar (yani herhangi bir iş mantığı içermezler)

Bunun ne anlama geldiğine daha yakından bakalım.

Altıgen ve Entity-Kontrol-Sınırı(Hexagonal vs. Entity-Control-Boundary)

Entity-Kontrol-Sınır modelini daha önce duyduysanız, altıgen mimariyi tanıdık bulacaksınız. Aggregate'lerinizi entity'ler(entities), domain servisleri , factory'leri ve repository'leri controller'lar(controllers) olarak ve applicaiton servislerini sınırlar(boundries) olarak düşünebilirsiniz.

Durum Bilgisizlik (Statelessness)


Bir application servis, istemcilerle etkileşime girerek değiştirilebilecek herhangi bir iç durumu korumaz. Bir işlemi gerçekleştirmek için gereken tüm bilgiler, applicaiton servis yönteminin girdi parametreleri olarak mevcut olmalıdır. Bu, sistemi daha basit, hata ayıklamayı ve ölçeklendirmeyi kolaylaştıracaktır.

Kendinizi tek bir iş süreci bağlamında birden çok application servis çağrısı yapmanız gereken bir durumda bulursanız, iş sürecini kendi sınıfında modelleyebilir ve uygulamanın servis metoduna bir girdi parametresi olarak bir örneğini iletebilirsini. Metod daha sonra sihrini yerine getirir ve diğer application servis yöntemlerine girdi olarak kullanılabilen iş süreci nesnesinin güncellenmiş bir örneğini döndürür:

Girdi Argümanı Olarak İş Süreci.

public class MyBusinessProcess {
    // Current process state
}

public interface MyApplicationService {

    MyBusinessProcess performSomeStuff(MyBusinessProcess input);

    MyBusinessProcess performSomeMoreStuff(MyBusinessProcess input);
}
 

Ayrıca, iş süreci nesnesini mutable hale getirebilir ve application servis yönteminin(applicaiton service) nesnenin durumunu doğrudan değiştirmesine izin verebilirsiniz. Kişisel olarak bu yaklaşımı tercih etmiyorum çünkü istenmeyen yan etkilere yol açabileceğine inanıyorum, özellikle transaction rollback yapıldığında. Bu, application servisinin istemci tarafından nasıl çağrıldığına bağlıdır ve bu konuya daha sonra bağlantı noktaları(ports) ve bağdaştırıcılar(adaptors) hakkındaki bölümde bahsedilecektir.

Daha karmaşık ve uzun süreli iş süreçlerinin nasıl uygulanacağına dair ipuçları için Vernon'un kitabını okumanızı tavsiye ederim.

Güvenlik yaptırımı(Security Enforcement)


Application servis, mevcut kullanıcının söz konusu işlemi gerçekleştirmesine izin verilmesini sağlar. Teknik olarak, bunu her bir application servis yönteminin üst kısmında manuel olarak yapabilir veya AOP gibi daha karmaşık bir şey kullanabilirsiniz. Domain modeli içinde değil, applicaiton servis katmanında olduğu sürece güvenliğin nasıl uygulandığı önemli değildir. 

Şimdi, bu neden önemli?

Bir uygulamada güvenlik hakkında konuştuğumuzda, yetkili erişime izin vermektense yetkisiz erişimi önlemeye daha fazla vurgu yapma eğilimindeyiz. Bu nedenle, sisteme eklediğimiz herhangi bir güvenlik kontrolü, esasen kullanımını zorlaştıracaktır. Bu güvenlik kontrollerini domain modeline eklersek kendimizi güvenlik kontrolleri eklendiğinde aklımıza gelmediği için önemli bir işlemi yapamayacağımız bir durumda bulabiliriz. Tüm güvenlik kontrollerini domain modelinin dışında tutarak, domain modeli ile istediğimiz şekilde etkileşim kurabildiğimiz için daha esnek bir sistem elde ediyoruz. Tüm istemcilerin zaten bir application servisinden geçmesi gerektiğinden sistem yine de güvenli olacaktır. Yeni bir application servisi oluşturmak, domain modelini değiştirmekten çok daha kolaydır.

Kod Örnekleri


Aşağıda, bir application servisinde güvenlik uygulamasının nasıl görünebileceğine dair iki Java örneği verilmiştir. Kod test edilmemiştir ve gerçek Java kodundan daha çok sözde kod olarak ele alınmalıdır.

Bildirime Dayalı(Declarative) Güvenlik Uygulaması


@Service
class MyApplicationService {

    @Secured("ROLE_BUSINESS_PROCESSOR") // 
    public MyBusinessProcess performSomeStuff(MyBusinessProcess input) {
        var customer = customerRepository.findById(input.getCustomerId()) // 
            .orElseThrow( () -> new CustomerNotFoundException(input.getCustomerId()));
        var someResult = myDomainService.performABusinessOperation(customer); // 
        customer = customerRepository.save(customer);
        return input.updateMyBusinessProcessWithResult(someResult); // 
    }
}

  1. Anatasyon, framework'e yalnızca ROLE_BUSINESS_PROCESSOR rolüne sahip kimliği doğrulanmış kullanıcıların yöntemi çağırmasına izin vermesi talimatını verir.
  2. Application servis(applicaiton service), domain modelindeki bir repodan bir domain model arar.
  3. Application servis, aggregate'i domain modelindeki bir domain servisine(domain service) geçirerek sonucu (ne olursa olsun) depolar.
  4. Application servisi, iş süreci nesnesini güncellemek için domain servisinin sonucunu kullanır ve aynı uzun süreli işleme katılan diğer  applicaiton servis yöntemlerine aktarılabilmesi için onu döndürür.

Manuel Güvenlik Uygulaması


@Service
class MyApplicationService {

    public MyBusinessProcess performSomeStuff(MyBusinessProcess input) {
        // We assume SecurityContext is a thread-local class that contains information
        // about the current user.
        if (!SecurityContext.isLoggedOn()) { // 
            throw new AuthenticationException("No user logged on");
        }
        if (!SecurityContext.holdsRole("ROLE_BUSINESS_PROCESSOR")) { // 
            throw new AccessDeniedException("Insufficient privileges");
        }

        var customer = customerRepository.findById(input.getCustomerId())
            .orElseThrow( () -> new CustomerNotFoundException(input.getCustomerId()));
        var someResult = myDomainService.performABusinessOperation(customer);
        customer = customerRepository.save(customer);
        return input.updateMyBusinessProcessWithResult(someResult);
    }
}

  1. Gerçek bir uygulamada, muhtemelen bir kullanıcı oturum açmamışsa istisnayı atan yardımcı yöntemler oluşturursunuz. Neyin kontrol edilmesi gerektiğini göstermek için bu örneğe yalnızca daha ayrıntılı bir versiyon ekledim.
  2. Önceki durumda olduğu gibi, yalnızca ROLE_BUSINESS_PROCESSOR rolüne sahip kullanıcıların yöntemi çağırmasına izin verilir.

Transaction yönetimi (Transaction Management)


Her  applicaiton servis yöntemi, temeldeki veri deposunun işlemleri kullanıp kullanmadığına bakılmaksızın, kendi başına tek bir işlem oluşturacak şekilde tasarlanmalıdır. Bir application servis yöntemi başarılı olursa, işlemi tersine çeviren başka bir application servisini açıkça çağırmak dışında bunu geri almanın bir yolu yoktur (böyle bir yöntem varsa bile).

Kendinizi aynı işlem içinde birden çok application servisi yöntemini çağırmak istediğiniz bir durumda bulursanız, application servisinizin ayrıntı düzeyinin doğru olup olmadığını kontrol etmelisiniz. Belki de application servisinizin yaptığı bazı şeyler aslında bunun yerine domain servislerde olmalıdır? Sisteminizi güçlü tutarlılık yerine nihai tutarlılığı kullanacak şekilde yeniden tasarlamayı da düşünmeniz gerekebilir (bununla ilgili daha fazla bilgi için lütfen taktik domaine dayalı tasarım hakkındaki önceki makaleye bakın).

Teknik olarak, işlemleri application servisi yöntemi içerisinde manuel olarak halledebilir veya Spring ve Java EE gibi frameworkler ve platformlar tarafından sunulan anatasyonları kullanabilirsiniz.

Kod Örnekleri:


İşte bir application servisindeki işlem yönetiminin nasıl görünebileceğine dair iki Java örneği. Kod test edilmemiştir ve gerçek Java kodundan daha çok sözde kod olarak ele alınmalıdır.

Bildirime Dayalı(Declarative) Transaction Yönetimi


@Service
class UserAdministrationService {

    @Transactional // 
    public void resetPassword(UserId userId) {
        var user = userRepository.findByUserId(userId); // 
        user.resetPassword(); // 
        userRepository.save(user);
    }
}

  1. Framework, tüm yöntemin tek bir işlem içinde çalıştığından emin olacaktır. Bir istisna atılırsa, işlem geri alınır. Aksi takdirde, yöntem geri döndüğünde kesinleşir.
  2. Application servisi, Kullanıcı aggregate kökünü bulmak için domain modelinde bir repository çağırır.
  3. Application servisi, Kullanıcı aggreagte kökünde bir iş yöntemini çağırır.


Manuel Transaction Management





@Service
class UserAdministrationService {

    @Transactional
    public void resetPassword(UserId userId) {
        var tx = transactionManager.begin(); // 
        try {
            var user = userRepository.findByUserId(userId);
            user.resetPassword();
            userRepository.save(user);
            tx.commit(); // 
        } catch (RuntimeException ex) {
            tx.rollback(); // 
            throw ex;
        }
    }
}
  1. Tranaction  yöneticisi application servisine enjekte edilmiştir, böylece servis yöntemi açıkça yeni bir işlem başlatabilir.
  2. Her şey çalışırsa, işlem parola sıfırlandıktan sonra gerçekleştirilir.
  3. Bir hata oluşursa, işlem geri alınır ve istisna yeniden oluşturulur.

Orkestrasyon

İyi bir application servisi tasarlamanın belki de en zor kısmı, düzenlemeyi doğru yapmaktır. Bunun nedeni, yalnızca düzenleme yaptığınızı düşünseniz bile application servisine kazara iş mantığı eklemediğinizden emin olmanız gerektiğidir. Peki bu bağlamda orkestrasyon ne anlama geliyor?

Düzenleme ile, doğru domain nesnelerini doğru sırada aramak ve çağırmak, doğru girdi parametrelerini geçirmek ve doğru çıktıyı döndürmek demek istiyorum. En basit haliyle, bir application servisi bir kümeyi bir kimliğe göre arayabilir, bu kümede bir yöntemi çağırabilir, kaydedebilir ve geri dönebilir. Bununla birlikte, daha karmaşık durumlarda, yöntemin birden çok kümeye bakması, domain servisleriyle etkileşime girmesi, girdi doğrulaması yapması vb. Gerekebilir. Kendinizi uzun application servisi yöntemleri yazarken bulursanız, kendinize aşağıdaki soruları sormalısınız:

Yöntem bir iş kararı mı veriyor yoksa domain modelinden karar vermesini mi istiyor?

Kodun bir kısmı domain olay dinleyicilerine (domain event listeners) taşınmalı mı?

Bununla birlikte, bir application servisi yönteminde biten bir iş mantığına sahip olmak dünyanın sonu değil. Alan modeline hala oldukça yakındır ve iyi bir şekilde kapsüllenmiştir ve daha sonra alan modelini yeniden düzenlemek oldukça kolay olacaktır. Sizin için hemen anlaşılmamışsa, bir şeyin alan modeline mi yoksa application servistine mi girmesi gerektiğini düşünerek çok fazla değerli zaman kaybetmeyin.

Kod Örnekleri


İşte tipik bir orkestrasyonun nasıl görünebileceğine dair bir Java örneği. Kod test edilmemiştir ve gerçek Java kodundan daha çok sözde kod olarak ele alınmalıdır.

Birden Çok domain Nesnesini İçeren Düzenleme


@Service
class CustomerRegistrationService {

    @Transactional // 
    @PermitAll // 
    public Customer registerNewCustomer(CustomerRegistrationRequest request) {
        var violations = validator.validate(request); // 
        if (violations.size() > 0) {
            throw new InvalidCustomerRegistrationRequest(violations);
        }
        customerDuplicateLocator.checkForDuplicates(request); // 
        var customer = customerFactory.createNewCustomer(request); // 
        return customerRepository.save(customer); // 
    }
}

  1. Application servisti yöntemi bir transaction içinde çalışır.
  2. Application servisi yöntemine herhangi bir kullanıcı tarafından erişilebilir.
  3. Gelen kayıt talebinin gerekli tüm bilgileri içerip içermediğini kontrol etmek için bir JSR-303 doğrulayıcı çağırıyoruz. İstek geçersizse, kullanıcıya geri bildirilecek bir istisna atarız.
  4. Veritabanında aynı bilgilere sahip bir müşteri olup olmadığını kontrol edecek bir domain servisini çağırıyoruz. Durum böyleyse, domain servisi kullanıcıya geri yayılacak bir istisna (burada gösterilmemiştir) atar.
  5. Kayıt talebi nesnesinden gelen bilgilerle yeni bir Müşteri agrregate'i oluşturacak bir domain factory'si çağırıyoruz.
  6. Müşteriyi kaydetmek için bir domain repository'si çağırırız ve yeni oluşturulan ve kaydedilen müşteri aggregate root döndürürüz.

Domain Olay Dinleyicileri (Domain Event Listeners)

Taktiksel domaine dayalı tasarımla ilgili bir önceki makalede, domain olayları ve domain olay dinleyicileri hakkında konuştuk. Bununla birlikte, domain olay dinleyicilerinin genel sistem mimarisine nerede uyduğundan bahsetmedik. Önceki makaleden hatırlıyoruz ki, bir domain olay dinleyicisi, olayı ilk etapta yayınlayan yöntemin sonucunu etkilememelidir. Pratikte bu, bir domain olay dinleyicisinin kendi işlemi içinde çalışması gerektiği anlamına gelir.

Bu nedenle, domain olay dinleyicilerini bir istemci tarafından değil, bir domain olayı tarafından başlatılan özel bir applicaiton servis türü olarak görüyorum. Başka bir deyişle: domain olay dinleyicileri, domain modelinin içine değil applicaiton servis katmanına aittir. Bu aynı zamanda bir domain olay dinleyicisinin herhangi bir iş mantığı içermemesi gereken bir düzenleyici olduğu anlamına gelir. Belirli bir domain olayı yayınlandığında ne olması gerektiğine bağlı olarak, birden fazla ileriye giden yol varsa onunla ne yapılacağına karar veren ayrı bir domain servisi oluşturmanız gerekebilir.

Şöyle ki, önceki makaledeki agregalarla ilgili bölümde, bazen aynı işlem içinde birden fazla agregayı değiştirmenin, toplam tasarım yönergelerine aykırı olsa da, haklı görülebileceğinden bahsetmiştim. Ayrıca bunun tercihen domain olayları aracılığıyla yapılması gerektiğinden de bahsetmiştim. Bu gibi durumlarda, domain olay dinleyicileri mevcut işleme katılmak zorunda kalacak ve bu nedenle etkinliği yayınlayan yöntemin sonucunu etkileyerek hem domain olayları hem de applicaiton servisleri için tasarım yönergelerini bozabilirler. Bunu bilerek yaptığınız ve gelecekte karşılaşabileceğiniz sonuçların farkında olduğunuz sürece bu dünyanın sonu değildir. Bazen sadece pragmatik olmanız gerekir.

Giriş ve çıkış (Input and Output)


Applicaiton servislerini tasarlarken önemli bir karar, hangi verilerin (metod parametreleri) tüketileceğine ve hangi verilerin döndürüleceğine karar vermektir. Üç seçeneğiniz var:

  1. Entityleri ve değer nesnelerini doğrudan domain modelinden kullanın.
  2. Ayrı Veri Aktarım Nesneleri (DTO'lar) kullanın.
  3. Yukarıdaki ikisinin birleşimi olan domain payload Nesnelerini (DPO'lar) kullanın.

Her alternatifin kendi artıları ve eksileri vardır, bu nedenle her birine daha yakından bakalım.

Varlıklar ve Agregalar (Entities and Aggregates)


İlk alternatifte, applicaiton servisleri tüm agregaları (veya bunların parçalarını) döndürür. Client onlarla istediğini yapabilir ve değişiklikleri kaydetme zamanı geldiğinde, agregalar(veya bunların parçaları) parametre olarak applicaiton servislere geri gönderilir.

Bu alternatif, domain modeli anemik olduğunda (yani yalnızca veri içerdiğinde ve iş mantığı olmadığında) ve agregalar küçük ve kararlı olduğunda (yakın gelecekte pek değişmesi muhtemel olmadığı gibi) en iyi şekilde çalışır.

Ayrıca, istemcinin sisteme REST veya SOAP üzerinden erişmesi durumunda da çalışır ve agregalar kolayca JSON veya XML ve geri serileştirilebilir. Bu durumda, istemciler aslında agregalarınıza doğrudan değil, tamamen farklı bir dilde uygulanabilecek bir JSON veya toplamın XML temsiliyle etkileşimde bulunacaktır. Clientin bakış açısından, agregalar sadece DTO'lardır.

Bu alternatifin avantajları şunlardır:
  • Zaten sahip olduğunuz sınıfları kullanabilirsiniz
  • Domian nesneleri ve DTO'lar arasında dönüştürme yapmaya gerek yoktur.
Dezavantajlar:
  • Domain modelini doğrudan istemcilerle eşleştirir. Domain modeli değişirse, clientleriniz de değiştirmeniz gerekir.
  • Kullanıcı girişini nasıl doğrulayacağınıza dair kısıtlamalar getirir (bununla ilgili daha sonra daha fazla bahsedeceğiz).
  • Agregalarınız, clientin agregayı tutarsız bir duruma getiremeyeceği veya izin verilmeyen bir işlemi gerçekleştiremeyeceği şekilde tasarlamalısınız.
  • Bir toplu (JPA) içindeki entitylerin geç yüklenmesiyle ilgili sorunlarla karşılaşabilirsiniz.
Şahsen ben bu yaklaşımdan elimden geldiğince kaçınmaya çalışıyorum.

Veri Aktarım Nesneleri (Data Transfer Objects)

İkinci alternatifte, applicaiton servisleri veri aktarım nesnelerini tüketir ve döndürür. DTO'lar, domain modelindeki entitylere karşılık gelebilir, ancak daha sık olarak belirli bir applicaiton servisti veya hatta belirli bir applicaiton servisi yöntemi (istek ve yanıt nesneleri gibi) için tasarlanmıştır. applicaiton servisi daha sonra verileri DTO'lar ve domain nesneleri arasında ileri geri taşımaktan sorumludur.

Bu alternatif, domain modeli iş mantığı açısından çok zengin olduğunda, agregalar karmaşık olduğunda veya istemci API'sini olabildiğince istikrarlı tutarken domain modelinin çok değişmesi beklendiğinde en iyi şekilde çalışır.

Bu alternatifin avantajları şunlardır:

  • İstemciler, domain modelinden ayrıştırılarak istemcileri değiştirmek zorunda kalmadan onu geliştirmeyi kolaylaştırır.
  • Yalnızca gerçekte ihtiyaç duyulan veriler istemciler ve uygulama hizmetleri arasında aktarılır, bu da performansı artırır (özellikle istemci ve uygulama hizmeti dağıtılmış bir ortamda bir ağ üzerinden iletişim kuruyorsa).
  • Domain modeline erişimi kontrol etmek, özellikle yalnızca belirli kullanıcıların belirli agrega yöntemlerini başlatmasına veya belirli toplu öznitelik değerlerini görüntülemesine izin veriliyorsa daha kolay hale gelir.
  • Yalnızca applicaiton servisleri, aktif işlemlerin içindeki agregalarla etkileşime girecektir. Bu, bir agrega (JPA) içindeki entitylerin  lazy yüklemesini kullanabileceğiniz anlamına gelir.
  • DTO'lar arayüzlerse ve sınıflar değilse, daha da fazla esneklik elde edersiniz.

Dezavantajlar:
  • Bakım için yeni bir DTO sınıfı seti alırsınız.
  • Verileri DTO'lar ve agregalar arasında ileri geri taşımanız gerekir. DTO'lar ve entitiyler yapı olarak neredeyse benzer ise, bu özellikle sıkıcı olabilir. Bir takımda çalışıyorsanız, DTO'lar ve agregaların neden ayrılması gerektiğine dair iyi bir açıklamaya ihtiyacınız vardır.
Şahsen, çoğu durumda işe başladığım yaklaşım budur. Bazen, bakacağımız bir sonraki alternatif olan DTO'larımı DPO'lara dönüştürmek oluyor.

Domain Yük Nesneleri(Domain Payload Objects)

Üçüncü alternatifte, applicaiton servisleri domain yük nesnelerini tüketir ve döndürür. Domain yük nesnesi, domain modelinin farkında olan ve domain nesnelerini içerebilen bir veri aktarım nesnesidir. Bu, esasen ilk iki alternatifin bir kombinasyonudur.

Bu alternatif, domain modelinin anemik olduğu, agregaların  küçük ve kararlı olduğu ve birden çok farklı agregayı içeren bir işlem uygulamak istediğiniz durumlarda en iyi sonucu verir. Kişisel olarak, DPO'ları girdi nesnelerinden çok çıktı nesneleri olarak kullandığımı söyleyebilirim. Bununla birlikte, DPO'larda domain nesnelerinin kullanımını, yalnızca mümkünse nesnelere değer vermek için sınırlandırmaya çalışıyorum.

Bu alternatifin avantajları şunlardır:

  • Her şey için DTO sınıfları oluşturmanıza gerek yoktur. Bir domain nesnesini doğrudan istemciye iletmek yeterince iyidir, bunu yaparsınız. Özel bir DTO'ya ihtiyacınız olduğunda, bir tane oluşturursunuz. İkisine de ihtiyacınız olduğunda ikisini de kullanırsınız.

Dezavantajlar:

  • İlk alternatifle aynı. Dezavantajlar, yalnızca DPO'ların içine immutable değer nesnelerini dahil ederek hafifletilebilir.

Kod Örnekleri

Sırasıyla DTO'ları ve DPO'ları kullanmanın iki Java örneği. DTO örneği, varlığı doğrudan döndürmektense bir DTO kullanmanın daha mantıklı olduğu bir kullanım durumunu gösterir: Entity özelliklerinin yalnızca bir kısmına ihtiyaç vardır ve entityde var olmayan bilgileri eklememiz gerekir. DPO örneği, DPO kullanmanın mantıklı olduğu bir kullanım durumunu gösterir: Bir şekilde birbiriyle ilişkili birçok farklı agregayı eklememiz gerekir.

Kod test edilmemiştir ve gerçek Java kodundan daha çok sözde kod olarak ele alınmalıdır.

Veri Aktarım Nesnesi Örneği

public class CustomerListEntryDTO {  
    private CustomerId id;
    private String name;
    private LocalDate lastInvoiceDate;

     Getters and setters omitted
}
@Service
public class CustomerListingService {

    @Transactional
    public List  getCustomerList() {
        var customers = customerRepository.findAll();  
        var dtos = new ArrayList();
        for (var customer : customers) {
            var lastInvoiceDate = invoiceService.findLastInvoiceDate(customer.getId()); 
            dto = new CustomerListEntryDTO();
            dto.setId(customer.getId());
            dto.setName(customer.getName());
            dto.setLastInvoiceDate(lastInvoiceDate);
            dtos.add(dto);
        }
        return dto;
    }
}
  • Veri Aktarım Nesnesi, herhangi bir iş mantığı içermeyen bir veri yapısıdır. Bu özel DTO, yalnızca müşteri adını ve son fatura tarihini göstermesi gereken bir kullanıcı arabirimi liste görünümünde kullanılmak üzere tasarlanmıştır.
  • Veritabanından tüm müşteri kümelerini arıyoruz. Gerçek dünyadaki bir uygulamada, bu yalnızca müşterilerin bir alt kümesini döndüren sayfalandırılmış bir sorgu olacaktır.
  • Son fatura tarihi müşteri varlığında saklanmaz, bu nedenle bizim için aramak için bir domain servisini çağırmamız gerekir.
  • DTO örneğini oluşturuyoruz ve onu verilerle dolduruyoruz.
Domain Yük Nesnesi Örneği


public class CustomerInvoiceMonthlySummaryDPO { // 
    private Customer customer;
    private YearMonth month;
    private Collection invoices;

    // Getters and setters omitted
}

@Service
public class CustomerInvoiceSummaryService {

    public CustomerInvoiceMontlySummaryDPO getMonthlySummary(CustomerId customerId, YearMonth month) {
        var customer = customerRepository.findById(customerId); // 
        var invoices = invoiceRepository.findByYearMonth(customerId, month); // 
        var dpo = new CustomerInvoiceMonthlySummaryDPO(); // 
        dpo.setCustomer(customer);
        dpo.setMonth(month);
        dpo.setInvoices(invoices);
        return dpo;
    }
}
  1. Domain Yük Nesnesi, hem domain nesnelerini (bu durumda entityler) hem de ek bilgileri (bu durumda yıl ve ay) içeren herhangi bir iş mantığı olmayan bir veri yapısıdır.
  2. Müşterinin agrega kökünü repodan alıyoruz.
  3. Müşterinin belirtilen yıl ve aya ait faturalarını alıyoruz.
  4. DPO örneğini oluşturup verilerle dolduruyoruz.

Giriş Doğrulama (Input Validation)

Daha önce bahsettiğimiz gibi, bir agrega her zaman tutarlı bir durumda olmalıdır. Bu, diğer şeylerin yanı sıra, bir agreganın durumunu değiştirmek için kullanılan tüm girdileri uygun şekilde doğrulamamız gerektiği anlamına gelir. Bunu nasıl ve nerede yapıyoruz?

Bir kullanıcı deneyimi perspektifinden, kullanıcı arayüzü, verilerin geçersiz olması durumunda kullanıcının bir işlemi bile gerçekleştirememesi için doğrulama içermelidir. Ancak, altıgen bir sistemde sadece kullanıcı arabirimi doğrulamasına güvenmek yeterince iyi değildir. Bunun nedeni, kullanıcı arayüzünün sisteme potansiyel olarak birçok giriş noktasından biri olmasıdır. Bir REST uç noktası, domain modeline herhangi bir çöpün geçmesine izin veriyorsa, kullanıcı arabiriminin verileri doğru şekilde doğrulamasına yardımcı olmaz.

Girdi doğrulama hakkında düşünürken aslında iki farklı doğrulama türü vardır: format doğrulama ve içerik doğrulama. Formatı doğrularken, belirli türlerdeki belirli değerlerin belirli kurallara uygun olup olmadığını kontrol ederiz. Örneğin. bir sosyal güvenlik numarasının belirli bir modelde olması beklenmektedir. İçeriği doğruladığımızda, zaten iyi biçimlendirilmiş bir veri parçasına sahibiz ve bu verilerin mantıklı olup olmadığını kontrol etmekle ilgileniyoruz. Örneğin. İyi biçimlendirilmiş bir sosyal güvenlik numarasının gerçekte gerçek bir kişiye karşılık gelip gelmediğini kontrol etmek isteyebiliriz. Bu doğrulamaları farklı şekillerde uygulayabilirsiniz, bu sebeblerden dolayı daha yakından bakalım.

Biçim Doğrulaması (Format Validation)

Domain modelinizde ilkel türlerin (dizeler veya tamsayılar gibi) etrafına sarılmış çok sayıda değer nesnesi kullanıyorsanız (bunu kişisel olarak yapma eğilimindeyim), o zaman biçim doğrulamasını doğrudan değer nesnesi oluşturucunuza oluşturmak mantıklıdır. . Başka bir deyişle, örneğin oluşturulması mümkün olmamalıdır. iyi biçimlendirilmiş bir bağımsız değişkeni iletmeden bir EmailAddress veya SocialSecurityNumber örneği. Bu, geçerli verileri girmenin bilinen birden çok yolu varsa (örneğin, bir telefon numarası girerken bazı kişiler sayıyı gruplara ayırmak için boşluklar veya kısa çizgiler kullanabilirken diğerleri oluşturucu içinde bazı ayrıştırma ve temizleme işlemleri yapabileceğiniz gibi ek bir avantaja sahiptir hiçbir boşluk kullanmayın).

Şimdi, değer nesneleri geçerli olduğunda, onları kullanan entityleri nasıl doğrularız? Java geliştiricileri için kullanılabilen iki seçenek vardır.

İlk seçenek, doğrulamayı kurucularınıza, fabrikalarınıza ve ayarlayıcı yöntemlerinize eklemektir. Buradaki fikir, bir kümeyi tutarsız bir duruma getirmenin bile mümkün olmaması gerektiğidir: tüm gerekli alanlar kurucuda doldurulmalıdır, gerekli alanların ayarlayıcıları boş parametreleri kabul etmeyecektir, diğer ayarlayıcılar yanlış bir değeri kabul etmeyecektir. format veya uzunluk, vb. İş mantığı açısından çok zengin olan alan modelleriyle çalışırken kişisel olarak bu yaklaşımı kullanma eğilimindeyim. Domain modelini çok sağlam kılar, ancak aynı zamanda pratik olarak sizi istemciler ve applicaiton servisleri arasında DTO'ları kullanmaya zorlar çünkü bir UI'ye düzgün bir şekilde bağlanmak hemen hemen imkansızdır.

İkinci seçenek, Java Bean Doğrulamasını (JSR-303) kullanmaktır. Tüm alanlara ek açıklamalar yerleştirin ve applicaiton servisinizin, onunla başka bir şey yapmadan önce agregayı Doğrulayıcı aracılığıyla çalıştırdığından emin olun. Ben kişisel olarak bu yaklaşımı anemik alan modelleriyle çalışırken kullanma eğilimindeyim. Agreganın kendisi kimsenin onu tutarsız bir duruma sokmasını engellemese de, bir depodan alınmış veya doğrulamadan geçmiş tüm agregaların tutarlı olduğunu güvenle varsayabilirsiniz.

Domain modelinizdeki ilk seçeneği ve gelen DTO'larınız veya DPO'larınız için Java Bean Doğrulamasını kullanarak her iki seçeneği de birleştirebilirsiniz.

İçerik Doğrulama (Content Validation)

İçerik doğrulamasının en basit durumu, aynı agregada iki veya daha fazla birbirine bağlı özniteliğin geçerli olduğundan emin olmaktır (örneğin, bir attribute ayarlanmışsa, diğeri boş olmalıdır ve bunun tersi de geçerlidir). Bunu doğrudan entity sınıfının kendisine uygulayabilir veya sınıf düzeyinde bir Java Bean Doğrulama kısıtlaması kullanabilirsiniz. Bu tür içerik doğrulaması, aynı mekanizmaları kullandığı için format doğrulaması yapılırken ücretsiz olarak gelecektir.

Daha karmaşık bir içerik doğrulama durumu, bir yerde bir arama listesinde belirli bir değerin var olduğunu (veya olmadığını) kontrol etmek olabilir. Bu büyük ölçüde applicaiton  servsinin sorumluluğundadır. Herhangi bir iş veya kalıcılık işleminin devam etmesine izin vermeden önce, application servisi aramayı gerçekleştirmeli ve gerekirse bir istisna atmalıdır. Bu, entityler taşınabilir domain nesneleri olduğundan, arama için gereken nesneler tipik olarak statik olduğundan entitylerinize yerleştirmek isteyeceğiniz bir şey değildir (hareketli ve statik nesneler hakkında daha fazla bilgi için taktik DDD hakkındaki önceki makaleye bakın).

İçerik doğrulamasının en karmaşık durumu, tüm bir agregayı bir dizi iş kuralına göre doğrulamak olacaktır. Bu durumda sorumluluk, domain modeli ve application servisi arasında bölünür. Doğrulamanın kendisinin gerçekleştirilmesinden bir domain servisi sorumlu olabilir, ancak domain servisini başlatmaktan application servisi sorumlu olacaktır.


Kod Örnekleri
Burada, doğrulama işleminin üç farklı yoluna bakacağız. İlk durumda, bir değer nesnesinin (bir telefon numarası) yapıcısının içinde biçim doğrulaması gerçekleştirmeye bakacağız. İkinci durumda, yerleşik doğrulama olan bir varlığa bakacağız, böylece nesneyi ilk etapta tutarsız bir duruma sokmak mümkün olmaz. Üçüncü ve son durumda, aynı varlığa bakacağız ancak JSR-303 doğrulaması kullanılarak uygulanacağız. Bu, nesneyi tutarsız bir duruma getirmeyi mümkün kılar, ancak bu şekilde veritabanına kaydetmemeyi mümkün kılar.

Biçim Doğrulamalı Değer Nesnesi


public class PhoneNumber implements ValueObject {
    private final String phoneNumber;

    public PhoneNumber(String phoneNumber) {
        Objects.requireNonNull(phoneNumber, "phoneNumber must not be null"); // 
        var sb = new StringBuilder();
        char ch;
        for (int i = 0; i lt phoneNumber.length(); ++i) {
            ch = phoneNumber.charAt(i);
            if (Character.isDigit(ch)) { // 
                sb.append(ch);
            } else if (!Character.isWhitespace(ch) && ch != '(' && ch != ')' && ch != '-' && ch != '.') { // 
                throw new IllegalArgument(phoneNumber + " is not valid");
            }
        }
        if (sb.length() == 0) { // 
            throw new IllegalArgumentException("phoneNumber must not be empty");
        }
        this.phoneNumber = sb.toString();
    }

    @Override
    public String toString() {
        return phoneNumber;
    }

    // Equals and hashCode omitted
}
İlk olarak, giriş değerinin boş olmadığını kontrol ederiz.

Gerçekte sakladığımız son telefon numarasına yalnızca rakamları dahil ediyoruz. Uluslararası telefon numaraları için, ilk karakter olarak bir '+' işaretini de desteklemeliyiz, ancak bunu okuyucuya bir alıştırma olarak bırakacağız.

İnsanların telefon numaralarında sıklıkla kullandıkları beyaz boşluklara ve belirli özel karakterlere izin veririz, ancak yok sayarız.

Son olarak tüm temizlik bittiğinde telefon numarasının boş olmadığını kontrol ediyoruz.

Yerleşik Doğrulamalı Entity


public class Customer implements Entity {

    // Fields omitted

    public Customer(CustomerNo customerNo, String name, PostalAddress address) {
        setCustomerNo(customerNo); // 
        setName(name);
        setPostalAddress(address);
    }

    public setCustomerNo(CustomerNo customerNo) {
        this.customerNo = Objects.requireNonNull(customerNo, "customerNo must not be null");
    }

    public setName(String name) {
        Objects.requireNonNull(nanme, "name must not be null");
        if (name.length() lt 1 || name.length > 50) { // 
            throw new IllegalArgumentException("Name must be between 1 and 50 characters");
        }
        this.name = name;
    }

    public setAddress(PostalAddress address) {
        this.address = Objects.requireNonNull(address, "address must not be null");
    }
}
  1. Setter yöntemlerinde uygulanan doğrulamayı gerçekleştirmek için kurucudan setterları çağırırız. Bir alt sınıfın bunlardan herhangi birini geçersiz kılmaya karar vermesi durumunda, bir kurucudan geçersiz kılınabilen yöntemleri çağırmanın küçük bir riski vardır. Bu durumda, setter yöntemlerini final olarak işaretlemek daha iyi olacaktır, ancak bazı kalıcılık çerçevelerinin bununla ilgili bir sorunu olabilir. Sadece ne yaptığınızı bilmeniz lazım.
  2. Burada bir stringin uzunluğunu kontrol ediyoruz. Her müşterinin bir adı olması gerektiğinden, alt sınır bir iş gereksinimidir. Bu durumda veritabanı, yalnızca 50 karakterlik stringleri depolamasına izin veren bir şemaya sahip olduğundan, üst düzey bir veritabanı gereksinimidir. Doğrulamayı buraya zaten ekleyerek, veritabanına çok uzun stringler eklemeye çalıştığınızda daha sonraki bir aşamada can sıkıcı SQL hatalarını önleyebilirsiniz.

JSR-303 Doğrulamalı Entity

public class Customer implements Entity {

    @NotNull (1)
    private CustomerNo customerNo;

    @NotBlank (2)
    @Size(max = 50) (3) 
    private String name;

    @NotNull
    private PostalAddress address;

    // Setters omitted
}
  1. Bu anatasyon, entity kaydedildiğinde müşteri numarasının null olmamasını sağlar.
  2. Bu anatasyon, entity kaydedildiğinde adın boş veya null olmamasını sağlar.
  3. Bu anatasyon, entity kaydedildiğinde adın 50 karakterden uzun olmamasını sağlar.

Boyut Önemli mi?

Portlara ve adaptörlere geçmeden önce kısaca bahsetmek istediğim bir şey daha var. Tüm facede'lerde olduğu gibi, çok fazla şey bilen ve çok şey yapan büyük tanrı sınıflarına dönüşen application servsilerin her zaman mevcut bir riski vardır. Bu tür sınıfları okumak ve sürdürmek genellikle çok büyük oldukları için zordur.

Peki application servsilerini nasıl küçük tutarsınız? İlk adım, elbette çok büyük büyüyen bir servisi daha küçük servislere bölmek. Ancak bunda da bir risk var. Durumların, geliştiricilerin aralarındaki farkın ne olduğunu veya hangi servise hangi yöntemin girmesi gerektiğini bilmediği kadar benzer iki servis olduğunu gördüm. Sonuç, servis yöntemlerinin iki ayrı servis sınıfına dağılmış olması ve hatta bazen iki kez (her servisde bir kez), ancak farklı geliştiriciler tarafından uygulanmasıydı.

application servsilerini tasarlarken, onları olabildiğince tutarlı hale getirmeye çalışıyorum. CRUD uygulamalarında bu, agrega başına bir application servsi anlamına gelebilir. Daha fazla domaine dayalı uygulamalarda bu, iş süreci başına bir application servisi veya hatta belirli kullanım durumları veya kullanıcı arabirimi görünümleri için ayrı servisler anlamına gelebilir.

Adlandırma, application servsleri tasarlarken çok iyi bir kılavuzdur. Application servslerinizi, ilgilendikleri agregaların aksine yaptıklarına göre adlandırmaya çalışın. Örneğin. EmployeeCrudService veya EmploymentContractTerminationUsecase, EmployeeService'ten çok daha iyi isimlerdir ve bu da herhangi bir anlama gelebilir. Ayrıca adlandırma kurallarınızı düşünmek için biraz zaman ayırın: tüm servislerinizi gerçekten Service son ekiyle sonlandırmanız gerekiyor mu? Bazı durumlarda Usecase veya Orchestrator gibi son ekleri kullanmak veya hatta soneki tamamen dışarıda bırakmak daha mantıklı olur mu?

Son olarak, komut tabanlı uygulama servislerinden bahsetmek istiyorum. Bu durumda, her application servis modelini, karşılık gelen bir komut işleyiciye sahip bir komut nesnesi olarak modellersiniz. Bu, her application servisinin tam olarak bir komutu işleyen tam olarak bir yöntem içerdiği anlamına gelir. Özel komutlar veya komut işleyicileri oluşturmak için polimorfizmi kullanabilirsiniz. Bu yaklaşım, çok sayıda küçük sınıfla sonuçlanır ve özellikle kullanıcı arabirimleri doğası gereği komut güdümlü olan veya istemcilerin bir ileti kuyruğu (MQ) veya kurumsal hizmet veriyolu gibi bir tür ileti mekanizması aracılığıyla uygulama hizmetleriyle etkileşime girdiği uygulamalarda yararlıdır. ESB).

Kod Örnekleri

Size Tanrı sınıfının neye benzediğine dair bir örnek vermeyeceğim çünkü bu çok fazla yer kaplar. Ayrıca, bir süredir bu meslekte olan çoğu geliştiricinin bu tür sınıflardan adil bir pay aldığını düşünüyorum. Bunun yerine, komut tabanlı bir uygulama hizmetinin nasıl görünebileceğine dair bir örneğe bakacağız. Kod test edilmemiştir ve gerçek Java kodundan daha çok sözde kod olarak ele alınmalıdır.

Komut Tabanlı Uygulama Hizmetleri



public interface Command { // 
}

public interface CommandHandler, R/> { // 

    R handleCommand(C command);
}

public class CommandGateway { // 

    // Fields omitted

    public , R/> R handleCommand(C command) {
        var handler = commandHandlers.findHandlerFor(command)
            .orElseThrow(() -> new IllegalStateException("No command handler found"));
        return handler.handleCommand(command);
    }
}

public class CreateCustomerCommand implements Command { // 
    private final String name;
    private final PostalAddress address;
    private final PhoneNumber phone;
    private final EmailAddress email;

    // Constructor and getters omitted
}

public class CreateCustomerCommandHandler implements CommandHandler { // 

    @Override
    @Transactional
    public Customer handleCommand(CreateCustomerCommand command) {
        var customer = new Customer();
        customer.setName(command.getName());
        customer.setAddress(command.getAddress());
        customer.setPhone(command.getPhone());
        customer.setEmail(command.getEmail());
        return customerRepository.save(customer);
    }
}
  1. Komut arayüzü, komutun sonucunu (çıktısını) da gösteren bir işaret arayüzüdür. Komutun çıkışı yoksa, sonuç Void olabilir.
  2. CommandHandler arabirimi, belirli bir komutu nasıl işleyeceğini (gerçekleştireceğini) ve sonucu nasıl döndüreceğini bilen bir sınıf tarafından uygulanır.
  3. İstemciler, tek tek komut işleyicileri aramak zorunda kalmamak için bir CommandGateway ile etkileşime girer. Ağ geçidi, mevcut tüm komut işleyicileri ve herhangi bir komuta göre doğru olanı nasıl bulacağını bilir. İşleyicileri aramak için kullanılan kod, işleyicileri kaydetmeye yönelik temel mekanizmaya bağlı olduğundan, örnekte dahil edilmemiştir.
  4. Her komut, Komut arayüzünü uygular ve komutu gerçekleştirmek için gerekli tüm bilgileri içerir. Komutlarımı yerleşik doğrulama ile değişmez hale getirmeyi seviyorum, ancak bunları değiştirilebilir ve JSR-303 doğrulamasını da kullanabilirsiniz. Hatta komutlarınızı arayüz olarak bırakabilir ve maksimum esneklik için istemcilerin kendilerinin uygulamasına izin verebilirsiniz.
  5. Her komutun, komutu gerçekleştiren ve sonucu döndüren kendi işleyicisi vardır.

Bağlantı Noktaları ve Adaptörler (Ports And Adaptors)

Şimdiye kadar domaini ve onu çevreleyen ve onunla etkileşime giren application servisleri tartıştık. Ancak, istemcilerin onları çağırmasının bir yolu yoksa ve portların ve adaptörlerin resme girmediği bu yerde, bu application servisleri tamamen yararsızdır.

Port Nedir?

Port, belirli bir amaç veya protokol için tasarlanmış, sistem ile dış dünya arasındaki bir arayüzdür. Portları yalnızca dış istemcilerin sisteme erişmesine izin vermek için değil, aynı zamanda sistemin harici sistemlere erişmesine izin vermek için de kullanılır.

Artık portlar ağ portları olarak ve protokolleri HTTP gibi ağ protokolleri olarak düşünmeye başlamak kolaydır. Bu hatayı ben kendim yaptım ve hatta Vernon bunu kitabındaki en az bir örnekte yapıyor. Ancak, Vernon'un bahsettiği Alistair Cockburn'ün yazdığı makaleye daha yakından bakarsanız, durumun böyle olmadığını göreceksiniz. Aslında bundan çok daha ilginç.

Port, uygulamayla belirli bir etkileşim türü (dolayısıyla "protokol" kelimesi) için tasarlanmış, teknolojiden bağımsız bir uygulama programlama arabirimidir (API). Bu protokolü nasıl tanımlayacağınız tamamen size bağlıdır ve bu yaklaşımı heyecan verici kılan da budur. İşte sahip olabileceğiniz farklı portlara birkaç örnek:

  • Bir veritabanına erişmek için uygulamanız tarafından kullanılan bir port
  • Uygulamanız tarafından e-posta veya kısa mesaj gibi mesajlar göndermek için kullanılan bir port
  • İnsan kullanıcılar tarafından uygulamanıza erişmek için kullanılan bir port
  • Uygulamanıza erişmek için diğer sistemler tarafından kullanılan bir port
  • Uygulamanıza erişmek için belirli bir kullanıcı grubu tarafından kullanılan bir port
  • Belirli bir kullanım durumunu ortaya çıkaran bir port
  • İstemcileri sorgulamak için tasarlanmış bir port
  • Müşterilere abone olmak için tasarlanmış bir port
  • Senkronize iletişim için tasarlanmış bir port
  • Eşzamansız iletişim için tasarlanmış bir port
  • Belirli bir cihaz türü için tasarlanmış bir port
Bu liste hiçbir şekilde kapsamlı değildir ve eminim daha birçok örneği kendiniz de bulabilirsiniz. Bu türleri de birleştirebilirsiniz. Örneğin, yöneticilerin senkronize olmayan iletişim kullanan bir istemci kullanarak kullanıcıları yönetmesine olanak tanıyan bir porta sahip olabilirsiniz. Diğer bağlantı noktalarını veya domain modelini etkilemeden sisteme istediğiniz veya ihtiyaç duyduğunuz kadar port ekleyebilirsiniz.

Altıgen mimari şemasına tekrar bakalım:



İç altıgenin her bir tarafı bir portu temsil eder. Bu mimarinin genellikle bu şekilde tasvir edilmesinin nedeni budur: Farklı portlar için kullanabileceğiniz kutudan çıkar çıkmaz altı tarafa ve ihtiyacınız olduğu kadar çok sayıda adaptör çekmeniz için bolca alana sahip olursunuz. Ama adaptör nedir?

Adaptör nedir?

Bağlantı noktalarının (portların) teknolojiden bağımsız olduğundan bahsetmiştim. Yine de, bazı teknolojiler aracılığıyla sistemle etkileşime girersiniz - bir web tarayıcısı, bir mobil cihaz, özel bir donanım cihazı, bir masaüstü istemcisi vb. Adaptörlerin devreye girdiği yer burasıdır.

Bir adaptör, belirli bir teknolojiyi kullanarak belirli bir port üzerinden etkileşime izin verir. Örneğin:

Bir REST adaptörü, REST istemcilerinin bazı portlar aracılığıyla sistemle etkileşime girmesine izin verir

Bir RabbitMQ adpter, RabbitMQ istemcilerinin bazı portlar üzerinden sistemle etkileşime girmesine izin verir.

Bir SQL adaptörü, sistemin bazı portlar üzerinden bir veritabanı ile etkileşime girmesine izin verir

Bir Vaadin adaptörü, insan kullanıcıların bazı portlar aracılığıyla sistemle etkileşime girmesine olanak tanır

Tek bir port için birden çok adaptöre veya birden çok port  için tek bir adaptöre sahip olabilirsiniz. Diğer adaptörleri, portları veya domain modelini etkilemeden sisteme istediğiniz veya ihtiyaç duyduğunuz kadar adaptör ekleyebilirsiniz.

Koddaki Portlar ve Adaptörler


Şimdiye kadar, kavramsal düzeyde bir portun ve adaptörün ne olduğu hakkında bir fikriniz olmalı. Peki bu kavramları koda nasıl dönüştürürsünüz? Bir bakalım!

Portlar çoğu durumda kendilerini kodunuzda arayüzler olarak somutlaştırır. Dış sistemin uygulamanıza erişmesine izin veren portlar için bu arabirimler, application servisi arabirimlerinizdir:



Arayüzünüzün uygulanması, application servis katmanınızın içinde bulunur ve adaptörler, servisi yalnızca arayüzü aracılığıyla kullanır. Bu, adaptörün applicaiton katmanınızı kullanan başka bir istemci olduğu klasik katmanlı mimariye çok uygundur. Temel fark, port kavramının daha iyi uygulama arabirimleri tasarlamanıza yardımcı olmasıdır, çünkü arabirimlerinizin istemcilerinin ne olacağını gerçekten düşünmeniz gerekir ve farklı istemcilerin tek boyutta uyum sağlamak yerine farklı arabirimlere ihtiyaç duyabileceğini kabul etmeniz gerekir. 

Uygulamanızın bir adaptör aracılığıyla harici bir sisteme erişmesine izin veren bir porta baktığımızda işler daha ilginç hale geliyor:



Bu durumda, arayüzü uygulayan adaptördür. Application servisi daha sonra bu arabirim aracılığıyla adaptörle etkileşime girer. Arabirimin kendisi uygulama hizmet katmanınızda (factory arabirimi gibi) veya domain modelinizde (repository arabirimi gibi) bulunur. Arayüz bir üst katmanda ("uygulama katmanı" veya "domain katmanı") bildirileceği, ancak daha düşük bir katmanda ("altyapı katmanı") uygulanacağı için bu yaklaşıma geleneksel katmanlı mimaride izin verilmezdi.

Lütfen bu iki yaklaşımda da bağımlılık oklarının arayüzü işaret ettiğine dikkat edin. Uygulama her zaman adaptörden ayrılmış olarak kalır ve adaptör her zaman uygulamanın gerçekleştirilmesinden ayrı kalır.

Bunu daha da somut hale getirmek için bazı kod örneklerine bakalım.

Örnek 1: REST API

İlk örnekte Java uygulamamız için bir REST API oluşturacağız:




Port, REST aracılığıyla açığa çıkmaya uygun bazı application servisidir. REST controller'ı adaptör görevi görür. Doğal olarak, POJO'lar (Düz Eski Java Nesneleri) ve XML / JSON arasında hem sunucu uygulaması hem de eşleştirme sağlayan Spring veya JAX-RS gibi bir frameork kullanıyoruz. Sadece aşağıdakileri yapacak olan REST controller'ını uygulamalıyız:

  1. Input olarak ham XML / JSON veya serileştirilmemiş POJO'ları alın,
  2. Application servislerini çağırın,
  3. Frameork tarafından serileştirilecek ham XML / JSON veya POJO olarak bir yanıt oluşturun ve
  4. Response'u client'e iletin.
İstemciler, bir tarayıcıda çalışan istemci tarafı web uygulamaları veya kendi sunucularında çalışan diğer sistemler olup olmadıklarına bakılmaksızın, bu belirli altıgen sistemin bir parçası değildir. Sistem ayrıca, port ve adaptörlerin desteklediği protokole ve teknolojiye uydukları sürece istemcilerin kim olduğuna da aldırmak zorunda değildir.

Örnek 2: Sunucu Tarafı Vaadin Kullanıcı Arayüzü

İkinci örnekte, farklı bir adaptör türüne, yani sunucu tarafı Vaadin UI'ye bakacağız:


Port, bir web kullanıcı arayüzü aracılığıyla gösterilmeye uygun bazı application servisidir. Adaptör, gelen kullanıcı eylemlerini applicaiton servisi yöntemi çağrılarına ve çıktıyı tarayıcıda işlenebilen HTML'ye çeviren Vaadin UI'dir. Kullanıcı arayüzünü yalnızca başka bir adaptör olarak düşünmek, iş mantığını kullanıcı arayüzünün dışında tutmanın mükemmel bir yoludur.

Örnek 3: İlişkisel Veritabanı ile İletişim Kurma

Üçüncü örnekte, işleri tersine çevireceğiz ve sistemimizin harici bir sisteme, daha özel olarak ilişkisel bir veritabanını çağırmasını sağlayan bir adaptöre bakacağız:


Bu sefer, Spring Data kullandığımız için, port, domain modelinden bir repository arayüzüdür (Spring Data kullanmadıysak, port muhtemelen repository uygulamalarına, transaction yönetimine erişim sağlayan bir tür veritabanı ağ geçidi arayüzü olacaktır. ve bunun gibi).

Adaptör Spring Data JPA'dır, bu yüzden gerçekten kendimiz yazmamız gerekmez, sadece doğru şekilde kurmamız gerekir. Uygulama başladığında ara yüzü proxy kullanarak otomatik olarak uygulayacaktır. Spring konteyneri, proxy'yi onu kullanan applicaiton servisine inject etmeyle ilgilenir.

Örnek 4: REST Üzerinden Harici Bir Sistemle İletişim Kurma

Dördüncü ve son örnekte, sistemimizin REST üzerinden harici bir sisteme istek yapmasını sağlayan bir adaptöre bakacağız:


Application servisinin harici sisteme ulaşma ihtiyacı olduğu için bunun için kullanmak istediği bir arayüz ilan etmiştir. Bunu bir anti-corruption katmanının ilk bölümü olarak düşünebilirsiniz (ne olduğu konusunda tazelemeye ihtiyacınız varsa geri dönün ve stratejik DDD hakkındaki makaleyi okuyun).

Adaptör daha sonra bu arabirimi uygulayarak anti-corruption katmanının ikinci bölümünü oluşturur. Önceki örnekte olduğu gibi, bağdaştırıcı, Spring gibi bir tür bağımlılık enjeksiyonu kullanılarak uygulama hizmetine enjekte edilir. Daha sonra, harici sisteme çağrı yapmak için bazı dahili HTTP istemcilerini kullanır ve alınan yanıtları, entegrasyon arabiriminin belirlediği şekilde domain nesnelerine çevirir.

Çoklu Sınırlı Bağlamlar(Multiple Bounded Contexts)

Şimdiye kadar sadece tek bir sınırlı bağlama uygulandığında altıgen mimarinin nasıl göründüğüne baktık. Ancak birbirleriyle iletişim kurmanız gereken birden fazla sınırlı bağlamınız olduğunda ne olur?

Bağlamlar ayrı sistemlerde çalışıyorsa ve bir ağ üzerinden iletişim kuruyorsa, bunun gibi bir şey yapabilirsiniz: Yukarı akış sistemi için bir REST sunucu adaptörü ve aşağı akış sistemi için bir REST istemci adaptörü oluşturun:


Farklı bağlamlar arasındaki eşleştirme, aşağı akış sisteminin adaptöründe gerçekleşecektir.

Bağlamlar tek bir monolitik sistem içinde modüller olarak çalışıyorsa, yine de benzer bir mimari kullanabilirsiniz, ancak yalnızca tek bir adaptöre ihtiyacınız vardır:





Her iki bağlam da aynı sanal makinenin içinde çalıştığından, her iki bağlamla doğrudan etkileşime giren yalnızca bir adaptöre ihtiyacımız var. Adaptör, aşağı akış bağlamının bağlantı noktası arabirimini uygular ve yukarı akış bağlamının bağlantı noktasını çağırır. Herhangi bir bağlam eşlemesi adaptörün içinde gerçekleşir.

Sonraki: Domaine Dayalı Tasarım ve Spring Boot

Bu dizinin bir sonraki ve son makalesinde, domaine dayalı tasarımı ve altıgen mimariyi kullanarak uygulamalar oluşturmak için Spring Boot'u nasıl kullanacağımızı öğreneceğiz.

Çeviri için izin veren  Petter Holmström'e teşekkürler.



Bonus :

Barış Velioğlu
Domain Driven Design Kimdir?

24 Aralık 2020 Perşembe

Dünyanın en büyük ücretsiz öğrenme platformu Khan Academy

 "Dünyanın en büyük ücretsiz öğrenme platformuna hoş geldiniz!

Khan Academy eğitimde fırsat eşitliğini güçlendirmek için herkese, her yerde, dünya standartlarında ve ücretsiz bir öğrenim imkanı sağlamayı amaçlayan ve kar amacı gütmeyen uluslararası bir eğitim kuruluşudur. Tek bir şeyi bilmelisin: Her Şeyi Öğrenebilirsin! Şu anda Khan Academy Türkçe'nin resmi YouTube kanalındasınız, binlerce ders videosundan oluşan kütüphanemizi gezmek için web sitemizi ziyaret edebilirsiniz: www.khanacademy.org.tr #KhanAcademyTürkçe #DünyaOkulu #HerŞeyiÖğrenebilirsin #EğitimdeFırsatEşitliği #KhanAcademyTR * * * Khan Academy, bir STFA Vakfı olana Bilimsel ve Teknik Yayınları Çeviri Vakfı çatısı altında yüzlerce gönüllünün katkılarıyla Türkçeleştirilmektedir. Daha çok eğitim içeriğinin dilimize çevrilmesine ya da Khan Academy'nin ücretsiz bir kaynak olarak daha çok insana ulaşmasına destek olmak isterseniz, gönüllü olmak için bize ulaşın: info@khanacademy.org.tr"

20 Ağustos 2020 Perşembe

Yazılım mühendisleri için davranışsal görüşme soruları (Behavioral Interviews: for Software Engineers)

 Merhaba bu yazımda sizlere, teknik mülakattan önce işveren için adayı tanıma konusunda yol gösterici olan, davranışsal interview sorularına biraz kendi mesleki hayatımdan ve bazen kurgusal olarak örnekler vermeye çalışacağım.

Davranışsal görüşmede nasıl başarılı olunur?

1) Hazırlıksız gelme

Size hangi davranışsal mülakat sorularının sorulacağını önceden bilemezsiniz. Bununla birlikte, her zaman yaptığınız gibi yine de bir röportaj için hazırlanmanız gerekir. Aksi takdirde, mülakatı yapan kişide en iyi izlenimi bırakmadan kendi sözlerinizle ya da aklınıza gelen ilk şeyi söyleyerek mırıldanırsınız.
Şirketi araştırmaya ek olarak, büyük mesleki başarılarınızı ve zorluklarınızı hatırlamak için zaman ayırın. Hatta bunları bir yere yazabilirsiniz, böylece işe alma müdürü size başarılı ekip çalışması örneklerini sorarsa, zaten bir cevabınız oluşmuş olur.

2) STAR yaklaşımını kullanın


Kariyer danışmanları, STAR yaklaşımının davranışsal mülakat sorularına yanıt vermenin etkili bir yolu olduğunu belirtmektedir. Bilgilendirici ve kapsamlı bir cevap vermek için izlemeniz gereken belli bir yapıyı ifade eder.
- S (Situation) - durum - içinde çalışmanız gereken bağlamı ana hatlarıyla belirtin;
- T (Task) - görev - tamamlamanız gereken görevi, çözmeniz gereken sorunu veya belirlenen hedefi tanımlayın;
- A (Action) - eylem - yukarıda belirtilen görevi tamamlamak için gerçekleştirdiğiniz belirli eylemleri anlatın;
- R (Result) - sonuç - eylemlerinizle hangi sonucu başardığınızı açıklayın.
STAR tekniği neden işe yarıyor? Sadece konunun etrafında dolaşmadan odaklanmış bir cevap vermenize yardımcı olmakla kalmaz, aynı zamanda hedefe ulaşmak için hangi becerileri uyguladığınızı göstermenize de olanak tanır.

3) Rakamları ve gerçek olayları kullanın

STAR yaklaşımına göre hikayeyi anlatırken, onu kesin rakamlar ve belirli sonuçlarla enjekte edin. Ayrıca ünlü müşterinin veya sektörde etkili bir kişi olan patronun adını da bırakabilirsiniz. "Tanıttığım yeni yönetim tekniği ile zamandan tasarruf ettik" demek yerine, "Ekip görevleri% 10 daha hızlı tamamlamaya başladı" deyin. Gerçekler, sonuçlara odaklanmanızı ve güvenilir bir şekilde inşa ettiğinizi gösterir.

4) Kültürel uyumunuzu gösterin

Görüşme için hazırlanırken, web sitesini, sosyal medya sayfalarını ve orada çalışan kişilerin hikayelerini kullanarak şirketin kurumsal kültürünü araştırın. İşe alan kişinin sorularını yanıtlarken, mükemmel bir kültürel uyum olarak karşımıza çıkmak için farklı açılardan yararlanın. Örneğin, şirket bireyselliği ve rekabeti teşvik ediyorsa, stresi kendi katkınıza ve çabalarınıza koyun. Şirket ekip çalışmasına değer veriyorsa, içinde çalıştığınız ekibin başarısını gösteren hikayeleri anlatın.

5) Vücut diliniz üzerinde çalışın

Daha önce beden dilinin ve sözlü olmayan sinyallerin önemini duyduğunuzu biliyoruz. Ancak, tekrar edilmeye değer. Mesele şu ki, omuzlarınız devrilmiş ve bacak bacak üstüne atılmış olarak otururken kendinizi harika bir müzakereci ve en iyi performans gösteren biri olarak tanımlarsanız, görüşmeci tutarsız bir izlenim edinir. Bu yüzden mülakat anlaşması için ipuçları bile çok önemlidir.
Ünlü bir yaşam koçu Antony Robbins, daha güvenli görünmek ve hissetmek için "güçlü poz verme" yi öneriyor. Ofise girmeden önce, 2 dakika Süpermen gibi ellerinizi kalçalar üzerinde tutun. Bu pozu almak testosteron seviyenizi% 20 artırır ve stresi azaltır.

6) Negatif olmaktan kaçının

Görüşmenin yalnızca başarılarınızı kapsaması pek olası değildir. Görüşmeci, çatışmaları, zor durumlardaki çözümünüz ve başarısızlıkları nasıl ele aldığınızı görmek isteyecektir (bu arada, konuyla ilgili bazı uzman tavsiyelerini burada bulabilirsiniz: http://resumeperk.com/blog/conflicts-at-work-most-common-types),  Dolayısıyla, muhtemelen müşteriden bir şikayet aldığınızda, projeyi zamanında teslim edemediğinizde veya iş için maliyetli olduğu ortaya çıkan bir hata yaptığınızda durum size sorulacaktır. "Asla hata yapmam" gibi bir şeye yanıt vermekten kaçının. Bu durumda hata yaptığınızı veya yanlış davrandığınızı kabul etmelisiniz, ancak durumdan öğrendiğiniz derslere odaklanmalısınız. Örneğin bilgi eksikliğinden dolayı bir hata yaptıysanız ileride bu tür hatalardan kaçınmak için kurumsal eğitim aldığınızı belirtebilirsiniz.

7) Önemsenecek noktalarınızı öğrenin ve bunları gösterin

Uzmanlar, ödevinizi yaparken sizi benzer niteliklere sahip adaylardan ayıran üç ana özelliği yazmanızı tavsiye ediyor. Örneğin, başkalarının tavsiye almak için başvuracağı bir kişi olmanız ya da  pazarlama girişimleri sunan gerçekten yetenekli bir iletişimci olabilmeniz gibi. 
Doğru soru ortaya çıktığında bu yetkinliklerden bahsedin. Davranışsal soruların doğru ya da yanlış cevapları olmadığından, düşüncelerinizi bir araya getirmek için birkaç saniyenizi ayırmanız sorun değildir (nefes alabilir veya biraz su yudumlayabilirsiniz).


Davranışsal sorular ve cevaplar ingilizce olacak, ayrıca Türkçe açıklama ve çeviriler eklenecektir.

01. Tell me about one of the most technically challenging projects you have done.

(Bitirmiş olduğunuz, teknik olarak en zorlu projelerden birini anlatın.)

Answer: Most of the projects that I involved in were technically challenging. But if I had to choose one I can say Digital Agency Project in Anadolu Sigorta was the most challenging. When we started this project, the technologies we use were just becoming popular in 2017 (Jhipster, Spring Boot, Angular 4, Elasticearch, Yarn, Liquebase, Mapstruct) and we didn't have too much knowledge about these technologies and we had to integrate them with Anadolu Sigorta SOA services. The project domain was also complex. By the time my colleagues left the project to involve other projects and I had to finish the project alone while helping the project analaysing team also.

02. Tell me about one of your failed projects. What did you learn? What could you do differently?

(Bana başarısız projelerinizden birini anlatın. Ne öğrendin? Neyi farklı yapabilirdin?)

Answer: I can give an example a big task of a project I fail. In Garanti Investment web project financial dictionary implementation was a important part of the project. I was not well skilled at javascript as much as backend technologies. And I was not aware of clean code too much. I successfully finish dictionary implemantation but i took too long time and it  hadn't been implemented by clean code princibles and effective way. Our team leader decide to implement from the scratch by himself.

After that task I realized of importance of clean code and writing effective javascript code.

03. Tell me about the project that you are most proud of. What was the most significant accomplishment of your entire career?

(Bana en çok gurur duyduğun projeden bahset. Tüm kariyerinizin en önemli başarısı neydi?)

Answer: If had to choose one I can say my most proud the project was emlakjet.com rebuild project. We analysed the legacy project, understood the domain, migrate the database from MySQL to postgresql, implement the project with the modern framework, and completed the project successfully on deadline.

04. Tell me about a time that you found a creative solution to a problem.

(Bana bir soruna yaratıcı bir çözüm bulduğunuz zamanı anlatın.)
Answer: In my last project RiskMobile we had performance and memory issues. We had some solutions for these :
Increased free heap memory space by up to %50 calculating report String size before transforming base64 StringBuilder
Increased report photo upload speed by up to %80 using the parallel upload
An increased report read time up to %80 by lazy loading

05. Tell me about a time when you had a conflict with your teammate or manager: how did you resolve it, and what did you learn?

(Takım arkadaşın veya yöneticinle bir çatışma yaşadığın bir zamandan bahset: Bunu nasıl çözdün ve ne öğrendin?)

Answer: Usually, conflicts happen between analysts and developers. In such cases, I have a private conversation with the analyst to try to understand him/her and tell him/her about my task-related dilemmas. I try to find a solution together without personalizing the issue.

06. Tell me about a time that you were behind on a project and you knew that you could not meet the deadline. Tell me about a time when you changed priorities to meet a deadline.

(Bana bir projede geride kaldığınız ve son teslim tarihine yetişemeyeceğinizi bildiğiniz bir zamandan bahsedin. Son teslim tarihine uymak için önceliklerinizi değiştirdiğiniz bir zamandan bahsedin.)

Answer: In a new version of the Alcatel OSOS project, we had defects to solve and new features to add. Towards the end date, we were far behind these goals. We have postponed less critical new features to the next version and put it first to solve problems that matter to the customer. After solving the problems, we applied the most valuable new features and successfully released the version.

07. Tell me about a time that you had to implement a workaround (vs. a solution) for a critical issue to meet a deadline and as a result, you introduced technical debt. What did you do with the technical debt after the deadline?

(Son teslim tarihini karşılamak için kritik bir sorun için bir geçici çözüm (çözüm yerine) uygulamak zorunda olduğunuz ve bunun sonucunda teknik borç getirdiğiniz bir zamandan bahsedin. Son teslim tarihinden sonra teknik borcunuzla ne yaptınız?)

Answer:

08. Why do you want to leave your current job? Could you mention some general issues in your current job? Have you taken any action to mitigate/resolve those issues? 

(Mevcut işinizden neden ayrılmak istiyorsunuz? Şu anki işinizle ilgili bazı genel sorunlardan bahsedebilir misiniz? Bu sorunları hafifletmek / çözmek için herhangi bir önlem aldınız mı?)

Answer:

09. Why do you want to join us? What do you know about our company?

(Neden bize katılmak istiyorsun? Şirketimiz hakkında ne biliyorsun?)

Answer:

10. If you have worked in many companies for short periods of time (< 2yrs), why do you switch your jobs so frequently?

(Kısa süreler için (<2 yıl) birçok şirkette çalıştıysanız, neden işlerinizi bu kadar sık değiştiriyorsunuz?)

Answer:

11. What is your weakness?

(Zayıf yönün nedir?)

Answer: When I involve or start a project a new project, because of my passion I am trying to have critical role at the begining even I don't have enough domain and structure knowladge of the project. This may cause deviation of the project plan.

Well, If I must say one more, I am not expert at project helper software like Microsoft Office. I should attach importance to learining tools that help agile process and project management.

12. What is your strength?

(Güçlü yönün nedir?)

Answer: I believe that my greatest strength is the ability to solve problems quickly and efficiently. I can see any given situation from multiple perspectives, which makes me uniquely qualified to complete my work even under challenging conditions. That problem solving allows me to be a better communicator. I am just as comfortable speaking to senior executives as I am junior team members. I think my ability to see all sides of an issue will make me a great asset to the team.

13. What is your current salary, or what is your salary expectation?

(Mevcut maaşınız veya maaş beklentiniz nedir?)

Answer:

14. What does your typical day look like at your current job?

(Mevcut işinizde tipik bir gününüzü nasıl geçirirsiniz?)

Answer:

15. Describe one of the biggest mistakes you have made in your job, and what did you learn?

(İşinizde yaptığınız en büyük hatalardan birini anlatın ve bu hatadan ne öğrendinizi söyleyin?)

Answer:

16. Describe a situation in which you were faced with a major obstacle in order to complete a project. How did you deal with it? What steps did you take?

(Bir projeyi tamamlamak için büyük bir engelle karşı karşıya kaldığınız bir durumu anlatın. Bununla nasıl başa çıktın? Hangi adımları attın?)

Answer:

17. How do you solve ambiguous problems?

(Belirsiz sorunları nasıl çözersiniz?)

Answer:

18. How do you see yourself in five (or ten) years? What skills do you want to learn?

(Kendinizi beş (veya on) yılda nasıl görüyorsunuz? Hangi becerileri öğrenmek istiyorsun?)

Answer: In several years, I see myself involved in architecting complex Java applications. Beyond that is too far away to think of right now.

19. Tell me about a time that you supervised/trained other engineers.

(Bana diğer mühendisleri denetlediğiniz / eğittiğiniz bir zamandan bahsedin.)

Answer:

20. Tell me about a time that you changed or improved the culture of your company or team.

(Şirketinizin veya ekibinizin kültürünü değiştirdiğiniz veya geliştirdiğiniz bir zamandan bahsedin.)

Answer:

21. Tell me about a time that you took the initiative.

(Bana inisiyatif aldığınız bir zamandan bahsedin.)

Answer:

22. Do you read any related blogs?

(İlgili herhangi bir blog okuyor musunuz?)

Answer:

23. Describe a time when you made a suggestion to improve something within the project that you were working on.

(Üzerinde çalıştığınız proje içinde bir şeyi iyileştirmek için bir öneride bulunduğunuz bir zamanı anlatın.)

Answer:

24. Give me an example of a time when you noticed a small problem before it turned into a major one. Did you take the initiative to correct it? What kind of preventive measures did you undertake?

(Küçük bir problemi büyük bir problem haline gelmeden önce fark ettiğiniz bir zamana örnek verin. Düzeltmek için inisiyatif aldınız mı? Ne tür önleyici tedbirler aldınız?)

Answer:

25. How will you adjust yourself in a fast-paced environment?

(Hızlı tempolu bir ortamda kendinizi nasıl ayarlarsınız?)

Answer:

26. What is your learning process like? How do you learn new skills?

(Öğrenme süreciniz nasıl? Yeni becerileri nasıl öğrenirsiniz?)

Answer:

27. What don’t you like in a job?

(Bir işte neyi sevmezsin?)

Answer:

28. When do you consider a project to be successful?

(Bir projenin ne zaman başarılı olduğunu düşünürsünüz?)

Answer:

29.Tell me about a time when you had to present a complex programming problem to a person that didn’t understand technical jargon. How did you ensure that the other person understood you?

(Bana teknik jargonu anlamayan bir kişiye karmaşık bir programlama problemi sunmanız gereken bir zamandan bahsedin. Diğer kişinin sizi anladığından nasıl emin oldunuz?)

Answer:

30.Tell me about a time you had to work on several projects at once. How did you handle that?

(Aynı anda birkaç proje üzerinde çalışmanız gereken bir zamandan bahsedin. Bunu nasıl hallettiniz?)

Answer:


31.Describe a situation in which you have experienced a significant project change that you weren’t expecting. What was it? How did that impact you, and how did you adapt to this change? How did you remain productive through the project?

( Beklemediğiniz önemli bir proje değişikliği yaşadığınız bir durumu açıklayın. Bu neydi? Bu sizi nasıl etkiledi ve bu değişime nasıl uyum sağladınız? Proje boyunca nasıl üretken kaldınız?)

Answer:


32.Tell me about a time when you had to work with a difficult person to accomplish a goal. What was the biggest challenge? How did you handle it?

(Bir hedefe ulaşmak için zor bir insanla çalışmanız gereken bir zamandan bahsedin. En büyük zorluk neydi? Bunu nasıl hallettin?)

Answer:


Kaynaklar : CRACKING THE BEHAVIORAL INTERVIEWS FOR SOFTWARE ENGINEERS, FIRST EDITION ,  https://devskiller.com/45-behavioral-questions-to-use-during-non-technical-interview-with-developers/ ,  https://resumeperk.com/blog/behavioral-interview-questions---and-how-to-answer-them 


15 Ağustos 2020 Cumartesi

1- Strategic Domain-Driven Design - vaadin.com - Petter Holmström - Çevirsi

"Bu makale dizisinde, Domain Driven Desgin (domaine dayalı tasarım)'ın ne olduğunu ve projenize - veya bir kısmının - projelerinize nasıl uygulanacağını öğreneceksiniz." diyor Petter Holmström. Ben de elimden geldiğince bu yazı dizisini Türkçe'ye çevirmeye çalışacağım. Umarım İngilizce okumada zorluk çeken arkadaşlar için yararlı olur.


Yazı Dizisinin Orjinali

Örnek DDD projesi


Serinin diğer yazıları :


3 - Domain-Driven Design and the Hexagonal Architecture (DDD ve Altıgen Mimari)


1 - Strategic Domain-Driven Design

(Stratejik DDD)

Domaine Dayalı Tasarım (DDD) Eric Evans'ın konuyla ilgili kitabını 2003'te yayınladığından beri var. Birkaç yıl önce veri tutarlılığı sorunları olan bir projeye katıldığımda DDD ile haşır neşir oldum. Veritabanında tekrarlanan veriler ortaya çıktı, bazı bilgiler hiç kaydedilmedi ve her yerde ve her zaman iyimser kilitleme hatalarıyla karşılaşabileceğimi gördüm. Taktiksel DDD tasarımın yapı taşlarını kullanarak bunu çözmeyi başardık.

O zamandan beri Domaine Dayalı Tasarım (DDD)  hakkında daha fazla şey öğrendim ve bunu projelerimde uygun olan yerlerde kullanmaya çalıştım. Bununla birlikte, diğer geliştiricilerle konuştuğum geçtiğimiz yıllarda, birçoğu domaine dayalı tasarım terimini duydu, ancak bunun ne anlama geldiğini bilmiyorlar. Bu makale dizisinde, gördüğüm ve anladığım şekliyle Domaine Dayalı Tasarım (DDD) a kısa bir giriş yapacağım. İçerik büyük ölçüde Eric Evans'ın Domain-Driven Design: Tackling Complexity in the Heart of Software ve Implementing Domain-Driven Design kitaplarına dayanıyor. Ancak her şeyi kendi sözlerimle açıklamaya ve kendi düşüncelerimi, görüşlerimi ve deneyimlerimi de aşılamaya çalıştım.

Makale dizimi okuyarak Domaine Dayalı Tasarım (DDD)  konusunda uzman olmayacaksınız, ancak umarım bu konu hakkında daha fazlasını başka yerlerde okumanız için size ilham verir. Ayrıca Evans ve Vernon'un kitaplarını okumanızı şiddetle tavsiye ediyorum.

Şimdi ilk konuya, yani stratejik Domaine Dayalı Tasarım (DDD) 'a başlayalım.

Domain(Etki Alanı) nedir?

MacBook'umdaki Sözlük uygulamasında domain'in kelime ararsam aşağıdaki tanımı alırım:

[A] n belirli bir hükümdar veya hükümetin sahip olduğu veya kontrol ettiği bölge bölgesi…

  • belirli bir faaliyet veya bilgi alanı ...
- Apple Sözlüğü

Domaine Dayalı Tasarım (DDD) söz konusu olduğunda, bizim ilgilendiğimiz tanımın ikinci kısmıdır. Bu durumda, faaliyet bir organizasyonun yaptığı şeydir ve bilgi, organizasyonun nasıl yaptığıdır. Alan konseptine organizasyonun faaliyetlerini yürüttüğü ortamı da ekleyeceğiz.

Subdomains (Alt alanlar)

Alan kavramı çok geniş ve soyuttur. Daha somut ve elle tutulur hale getirmek için, onu alt alan adı verilen daha küçük parçalara ayırmak mantıklıdır. Bu alt domainleri bulmak her zaman kolay bir şey değildir ve eğer yanlış yaparsanız, bulmacanızdaki parçalar birden bire birbirine tam oturmadığında yolun yarısında sorun yaşayabilirsiniz.

Alt domainleri aramaya başlamadan önce, alt domain kategorileri hakkında düşünmelisiniz. Tüm alt alanlar üç kategoriye ayrılabilir:
  1. Çekirdek alanlar (Core Domains)
  2. Destekleyen alt alanlar (Supporting Subdomains)
  3. Genel alt alanlar (Generic Subdomains)
Bu kategoriler yalnızca alt alan adlarınızı bulmanıza yardımcı olmakla kalmaz, aynı zamanda geliştirme çabalarınızı önceliklendirmenize de yardımcı olur.

Bir organizasyona özel ve diğer organizsasyonlardan farklı kılan şey çekirdek alan adıdır. (core domain) Bir organizsayon, core domnainde olağanüstü derecede iyi olmadan başarılı olamaz (hatta var olamaz). Core domain çok önemli olduğu için, en yüksek önceliği, en büyük çabayı ve en iyi geliştiricileri alması gerekir. Daha küçük alanlar için yalnızca tek bir core domain tanımlayabilirsiniz, daha büyük alanların birden fazla alanı olabilir. Core domain'in özelliklerini sıfırdan oluşturmaya hazırlıklı olmalısınız.

Destekleyen bir alt alan  (Supporting Subdomains), kuruluşun başarılı olması için gerekli olan, ancak core domain kategorisine girmeyen bir alt alan adıdır. Genel değildir çünkü söz konusu organizasyon için hala bir miktar uzmanlaşma gerektirir. Mevcut bir çözümle başlayabilir ve onu ince ayarlayabilir veya özel ihtiyaçlarınıza göre genişletebilirsiniz.

Genel bir alt alan adı  (Generic Subdomains), kuruluşa özel herhangi bir şey içermeyen ancak yine de genel çözümün çalışması için gerekli olan bir alt alan adıdır. Genel alt alan adlarınız için hazır yazılımları kullanmaya çalışarak zamandan ve işten tasarruf edebilirsiniz. Tipik bir örnek, kullanıcı kimliği yönetimi olabilir.

Organizsayonun ne yaptığına bağlı olarak aynı alt alan adının farklı kategorilere girebileceğini belirtmek gerekir. Kimlik yönetimi konusunda uzmanlaşmış bir şirket için kimlik yönetimi core bir alandır. Bununla birlikte, müşteri ilişkileri yönetimi konusunda uzmanlaşmış bir şirket için kimlik yönetimi, generic bir alt alan adıdır.

Son olarak, tüm alt alan adlarının, hangi kategoriye girdiklerine bakılmaksızın genel çözüm için önemli olduğuna dikkat çekmek önemlidir. Bununla birlikte, farklı miktarlarda çaba gerektirirler ve aynı zamanda farklı kalite ve eksiksizlik gereksinimlerine sahip olabilirler.

Misal

Küçük klinikler için bir EMR (Elektronik Tıbbi Kayıtlar) sistemi oluşturduğumuzu varsayalım. Aşağıdaki alt alanları belirledik:

  1. Hasta tıbbi kayıtlarını yönetmek için Hasta Kayıtları(Patient Records) (kişisel bilgiler, tıbbi geçmiş, vb.).
  2. Laboratuvar testleri sipariş etmek ve test sonuçlarını yönetmek için laboratuar(Lab).
  3. Randevuları planlamak için planlama(Scheduling ).
  4. Hasta kayıtlarına (farklı belgeler, röntgen resimleri, taranmış kağıt belgeler gibi) eklenmiş dosyaları depolamak ve yönetmek için Dosya Arşivi (File Archive).
  5. Doğru kişilerin doğru bilgilere erişimini sağlamak için Kimlik Yönetimi (Identity Management).

Şimdi, bu alt alanları nasıl sınıflandırabiliriz? En bariz olanlar, açıkça genel alt alanlar olan dosya arşivi ve kimlik yönetimidir. Peki ya diğerleri? Bu, bu özel EMR sistemini piyasadaki diğerleri arasında öne çıkaran şeyin ne olduğuna bağlıdır.


Bir EMR sistemi kurduğumuz için, hasta kayıtlarının temel bir alan olduğunu varsaymak oldukça güvenlidir. Akıllı ve yenilikçi zamanlama yoluyla tüm kliniklerin daha verimli çalışmasını sağlayan bir sistem oluşturarak pazarı ele alacaksak, o zaman planlama da muhtemelen core bir alandır. Aksi takdirde, supporting bir alt domaindir, belki mevcut bazı planlama motorunun üzerine inşa edilmiştir. Aynı mantık laboratuar alt alanına da uygulanabilir: iş vakamızın önemli bir parçası hasta kayıtları ve laboratuvar arasında kusursuz bir entegrasyon ise, o zaman laboratuvar büyük olasılıkla core bir alandır. Aksi takdirde, supporting bir alt alan adıdır.


Sorunlardan Çözümlere

Bazen "problem domain" olarak adlandırılan domaini bulursunuz. Bu, domainin yazılımın çözeceği sorunları tanımlaması gerçeğinden kaynaklanmaktadır (sonuçta, yazılımın ilk etapta yapılmasının bir nedeni vardır). Vaughn Vernon, bir alanı bir problem alanına ve bir çözüm alanına ayırır. Sorun alanı, çözmeye çalıştığımız iş sorunlarına odaklanır. Alt alanlar bu alana aittir.

Çözüm uzayı (solution space), problem uzayındaki (problem space) problemlerin nasıl çözüleceğine odaklanır. Çözüm uzayı daha somut, daha teknik ve daha fazla ayrıntı içerir. Peki sorunlarımızı çözüme nasıl dönüştüreceğiz?

The Ubiquitous Language (Ortak bir dil).

Bir alan adı için yazılım oluşturabilmek için, alanı tanımlamanın bir yoluna ihtiyacınız vardır. İlişkisel bir veri modeline veya benzer bir şeye sahip olmak yeterli değildir. Sadece şeyleri ve onların ilişkilerini değil, aynı zamanda olaylar, süreçler, iş değişmezleri, şeylerin zaman içinde nasıl değiştiği gibi dinamikleri de tanımlayabilmelisiniz. Domain hakkında hem geliştiricilerinizle hem de domain uzmanlarıyla tartışabilmeniz ve mantık yürütebilmeniz gerekir. İhtiyacınız olan şey, ortak bir dildir.

Ortak dil, hem alan uzmanları hem de geliştiriciler tarafından alanı açıklamak ve tartışmak için sürekli olarak kullanılan bir dildir. Kodun kendisinden ayrı olarak, bu dil, Domaine Dayalı Tasarım (DDD)  sürecinin en önemli çıktısıdır. Dilin büyük bir kısmı, alan uzmanları tarafından halihazırda kullanılmakta olan alan terminolojisidir, ancak alan uzmanlarıyla işbirliği içinde yeni kavramlar ve süreçler icat etmeniz de gerekebilir. Bu nedenle, alan uzmanlarının aktif katılımı, Domaine Dayalı Tasarım (DDD)'ın  başarılı olması için kesinlikle gereklidir. Müşteri alanınızı öğretmek ve ortak  bir dil oluşturmanıza yardımcı olmak için zaman ve çaba harcamakla ilgilenmiyorsa, müşteriyi fikrini değiştirmeye ikna etmeye çalışmalı veya başka bir tasarım yöntemi seçmelisiniz.

Ortak dili çeşitli şekillerde belgeleyebilirsiniz. İyi bir başlangıç noktası, bir terimler sözlüğü oluşturmaktır. İş süreçleri, örn. swimline diyagramları ve akış şemaları. UML, farklı şeyler farklı süreçler boyunca ilerlerken durumun nasıl değiştiğini açıklamak için nesneler ve durum diyagramları arasındaki ilişkiyi tanımlamak için kullanılabilir. Alt alan adları da ortak dilin bir parçasıdır ve hatta farklı alt alanlar için dilin farklı "lehçelerini" tanımlamanız gerekebilir. Ortak dilin bu düzenlemesi alan modelidir ve sonunda çalışma koduna dönüştürülecektir. Başka bir deyişle, alan modeli bir veri modeli veya bir UML sınıf diyagramı ile aynı değildir.

Ortak dilin güzel bir özelliği vardır ve bu size doğru yolda olup olmadığınızı söylemesi. Bir iş kavramını veya sürecini dili kullanarak kolayca açıklayabiliyorsanız, doğru yoldasınız demektir. Öte yandan, kendinizi bir şeyi açıklamakta zorlanırken bulursanız, büyük olasılıkla dilden ve dolayısıyla alan modelinizden bir şeyler kaçırıyorsunuzdur. Bu olduğunda, bir alan uzmanı tutmalı ve eksik parçaları aramalısınız. Hatta mevcut modelinizi tamamen tersine çeviren ve daha önce sahip olduğunuzdan çok daha üstün bir domain modeliyle sonuçlanan bir geliştirmeyle karşılaşabilirsiniz.

Introducing Bounded Contexts(Sınırlı Bağlamlara Giriş)


Kusursuz bir dünyada, yeknesak bir dil ve tek bir alanla ilgili her şeyi açıklayacak bir model olurdu. Ne yazık ki, çok küçük ve basit alanlar dışında durum böyle değil. İş süreçleri birbiri içine geçebilir ve hatta çakışabilir. Aynı kelime farklı anlamlara gelebilir veya farklı kelimeler farklı bağlamlarda aynı anlama gelebilir. Nasıl gördüğünüze bağlı olarak, sorun alanında bir sorunu çözmenin birden fazla yolu olabilir (ve genellikle vardır).

Büyük Birleşik Modeli(Big Unified Model) bulmaya çalışmak yerine, gerçekleri kabul etmeyi seçeriz ve bunun yerine sınırlı bağlamlar(bounded context) denen bir şey sunarız. Sınırlı bağlam, yeknesak dilin belirli bir alt kümesinin veya diyalektinin her zaman tutarlı olduğu alanın ayrı bir parçasıdır. Başka bir deyişle, bölme ve yönetme uyguluyor ve domain modelini açıkça tanımlanmış sınırları olan daha küçük, az çok bağımsız modellere ayırıyoruz. Her sınırlı bağlamın kendi adı vardır ve bu ad yeknesak dilin bir parçasıdır.

Sınırlı bağlamlar ve alt alanlar arasında mutlaka bire bir eşleştirme olması gerekmez. Sınırlı bir bağlam çözüm uzayına ve bir alt domain sorun uzayına ait olduğundan, sınırlı bağlamı birçok olası çözüm arasında alternatif bir çözüm olarak düşünmelisiniz. Dolayısıyla, tek bir alt alan, birden çok sınırlı bağlam içerebilir. Kendinizi tek bir sınırlı bağlamın birden çok alt alanı kapsadığı bir durumda da bulabilirsiniz. Buna karşı bir kural yoktur, ancak bu, alt alanlarınızı veya bağlam sınırlarınızı yeniden düşünmeniz gerekebileceğinin bir göstergesidir.

Kişisel olarak, sınırlı bağlamları ayrı sistemler olarak düşünmeyi seviyorum (örneğin, Java dünyasında ayrı çalıştırılabilir JAR'lar veya konuşlandırılabilir WAR'lar). Bunun mükemmel bir gerçek dünya örneği, her mikroservisin kendi sınırlı bağlamı olarak kabul edilebileceği mikroservislerdir. Ancak bu, tüm sınırlı bağlamlarınızı mikroservisler olarak uygulamanız gerektiği anlamına gelmez. Sınırlı bir bağlam, tek bir monolitik sistem içinde ayrı bir alt sistem de olabilir.

Misal

Önceki örnekteki EMR sistemini ve daha spesifik olarak hasta kayıtlarının temel alanını tekrar gözden geçirelim. Orada ne tür sınırlı bağlamlar bulabiliriz? Şimdi sağlık hizmetleri yazılımı konusunda uzman değilim, bu yüzden sadece birkaçını uyduracağım, ama umarım, temel fikri anlarsınız.

Sistem, hem doktor randevuları hem de fizyoterapi için hizmetleri destekler. Ek olarak, yeni hastalar için mülakat yapılan, fotoğraflarının çekildiği ve bir ilk değerlendirmenin verildiği ayrı bir alıştırma süreci vardır. Bu, core domainde aşağıdaki sınırlı bağlamlara yol açar:


  1. Hastanın kişisel bilgilerini yönetmek için kişisel bilgiler (Personal Information) (isim, adres, mali bilgiler, tıbbi geçmişi, vb.).
  2. Sisteme yeni hastaları tanıtmak için ilk katılım (Onboarding).
  3. Doktorların hastayı muayene ederken ve tedavi ederken kullandıkları Tıbbi Muayeneler (Medical Exams).
  4. Fizyoterapistlerin hastayı muayene ederken ve tedavi ederken kullandıkları fizyoterapi(Physiotherapy).
Çok basit bir sistemde, muhtemelen her şeyi tek bir bağlama sıkıştırırsınız, ancak bu EMR daha gelişmiştir ve sağlanan her hizmet türü için aerodinamik ve optimize edilmiş özellikler sağlar. Ancak, yine de aynı core alt domainindeyiz.

Bağlamlar Arasındaki İlişkiler


Önemsiz olmayan bir sistemde, çok az (varsa) sınırlı bağlam tamamen bağımsızdır. Çoğu bağlamın diğer bağlamlarla bir tür ilişkisi olacaktır. Bu ilişkilerin belirlenmesi sadece teknik olarak (sistemler teknik olarak nasıl iletişim kuracaklar) değil, aynı zamanda nasıl geliştirildikleri (sistemleri geliştiren ekipler birbirleriyle nasıl iletişim kuracaklar) açısından da önemlidir.

Sınırlı bağlamlar arasındaki ilişkileri belirlemenin en basit yolu, bağlamları yukarı akış bağlamları (upstream contexts) ve aşağı akış bağlamları(downstream contexts) olarak sınıflandırmaktır. Bağlamları bir nehrin yanındaki şehirler olarak düşünün. Akış yukarısındaki şehirlerden akan malzemeler aşağıdaki şehirlere ulaşan nehre bir şeyler döküyor. Malzemelerin bir kısmı aşağı havza şehirleri için çok önemlidir ve bu nedenle nehirden geri alırlar. Diğer şeyler zararlıdır ve aşağı havzadaki şehirlere doğrudan zarar verebilir ("pislik yokuş aşağı yuvarlanır").

Yukarı veya aşağı havza olmanın avantajları ve dezavantajları vardır. Bir yukarı akış bağlamı, herhangi bir yönde gelişmesini bir şekilde özgür kılan başka herhangi bir bağlama bağlı değildir. Bununla birlikte, herhangi bir değişikliğin sonuçları aşağı havza bağlamlarında şiddetli olabilir ve bu da, yukarı akış bağlamında kısıtlamalar getirebilir. Aşağı akış bağlamı, yukarı akış bağlamına bağımlılığıyla sınırlıdır, ancak aşağı akış bağlamının geliştiricilerine bir şekilde yukarı akış bağlamının geliştiricilerine göre daha özgür eller veren diğer bağlamları daha aşağı yönde kırma konusunda endişelenmesine gerek yoktur.

Okların aşağı akış bağlamlarından yukarı akış bağlamlarına işaret ettiği bir bağımlılık diyagramı kullanarak veya U ve D rollerini kullanarak ilişkileri grafiksel olarak tanımlayabilirsiniz.



Son olarak, nerede durduğunuza bağlı olarak bir bağlamın aynı anda hem yukarı akış bağlamı hem de aşağı akış bağlamı olabileceğini unutmayın.

Context Maps and Integration Patterns(Bağlam Haritaları ve Entegrasyon Modelleri)


Bağlamlarımızın ne olduğunu ve nasıl ilişkili olduklarını öğrendikten sonra, bunları nasıl bütünleştireceğimize karar vermeliyiz. Bu birkaç önemli soruyu içerir:

  1. Bağlam sınırları nerede?
  2. Bağlamlar teknik olarak nasıl iletişim kuracak?
  3. Bağlamların domain modelleri arasında nasıl harita oluşturacağız (yani yeknesak bir dilden diğerine nasıl çeviri yapıyoruz)?
  4. Yukarı yönde meydana gelen istenmeyen veya sorunlu değişikliklere karşı nasıl korunacağız?
  5. Aşağı akış bağlamlarında sorun yaratmaktan nasıl kaçınacağız?
Bu soruların cevapları bir bağlam haritası (context map) halinde derlenecektir. Bağlam haritası şu şekilde grafiksel olarak belgelenebilir:


Bağlam eşlemesini oluşturmayı kolaylaştırmak için, çoğu kullanım durumu için çalışan bir dizi hazır tümleştirme modeli(integration patterns) vardır. Hangi entegrasyon modelini seçtiğinize bağlı olarak, onu gerçekten kullanışlı hale getirmek için bağlam haritasına ek bilgiler eklemeniz gerekebilir.


Partnership(Ortaklık)


Her iki bağlamdaki ekipler işbirliği yapar. Arayüzler - ne olursa olsunlar - her iki bağlamın geliştirme ihtiyaçlarını karşılayacak şekilde gelişir. Birbirine bağlı özellikler, her iki takıma da mümkün olduğunca az zarar verecek şekilde uygun şekilde planlanır ve programlanır.

Shared Kernel (Paylaşılan Çekirdek)


Her iki bağlam da çekirdek olan ortak bir kod tabanını paylaşır. Çekirdek, herhangi bir ekip tarafından değiştirilebilir, ancak önce diğer ekibe danışılmadan yapılamaz. İstenmeyen yan etkilerin ortaya çıkmadığından emin olmak için, sürekli entegrasyon (otomatik test ile) gereklidir. İşleri olabildiğince basit tutmak için, paylaşılan çekirdek mümkün olduğu kadar küçük tutulmalıdır. Paylaşılan çekirdekte çok sayıda model kodu varsa, bu bağlamların aslında tek bir büyük bağlamda birleştirilmesi gerektiğinin bir işareti olabilir.

Customer-Supplier (Müşteri - Satıcı)

Bağlamlar, yukarı akış-aşağı akış ilişkisi içindedir ve bu ilişki, yukarı akış ekibi tedarikçi ve aşağı akış ekibi müşteri olacak şekilde biçimlendirilir. Bu nedenle, her iki takım da kendi sistemleri üzerinde az çok bağımsız olarak çalışabilse de, yukarı akış ekibinin (tedarikçi) aşağı akış ekibinin (müşteri) ihtiyaçlarını hesaba katması gerekir.

Conformist (Uyumlu Kimse)

Bağlamlar yukarı akış-aşağı akış ilişkisi içindedir. Bununla birlikte, yukarı akış ekibinin, aşağı akış ekibinin ihtiyaçlarını karşılamak için hiçbir motivasyonu yoktur (örneğin, daha büyük bir tedarikçiden bir hizmet olarak sipariş edilebilir). Alt ekip, her ne olursa olsun, üst ekip modeline uymaya karar verir.

Anticorruption Layer (Adaptosyon Katmanı)


Bağlamlar yukarı akış-aşağı akış ilişkisi içindedir ve yukarı akış ekibi, aşağı akış ekibinin ihtiyaçlarını umursamaz. Ancak, yukarı akış modeline uymak yerine, aşağı akış ekibi, aşağı akış bağlamını yukarı akış bağlamındaki değişikliklerden koruyan bir soyutlama katmanı oluşturmaya karar verir. Bu adaptasyon katmanı, aşağı akış ekibinin ihtiyaçlarına en çok uyan bir domain modeliyle çalışmasına olanak tanır ve yine de yukarı akış bağlamıyla bütünleşir. Yukarı akış bağlamı değiştiğinde, adaptasyon katmanının da değişmesi gerekir, ancak aşağı akış bağlamının geri kalanı değişmeden kalabilir. Bu stratejiyi, yukarı akış arayüzündeki değişiklikleri tespit etmek için otomatik testlerin kullanıldığı sürekli entegrasyonla birleştirmek iyi bir fikir olabilir.

Open Host Service


Bir sisteme erişim, açıkça tanımlanmış bir protokol kullanılarak, açıkça tanımlanmış hizmetler tarafından sağlanır. Protokol, ihtiyaç duyan herkesin sisteme entegre olabilmesi için açıktır. Web hizmetleri ve mikroservisler, bu entegrasyon modelinin güzel bir örneğidir. Bu örüntü, bağlamlar ve onları geliştiren takımlar arasındaki ilişkiyi önemsemediği için diğerlerinden farklıdır. open host service modelini diğer modellerden herhangi biriyle birleştirebilirsiniz.


Bu kalıbı kullanırken dikkat edilmesi gereken nokta, protokolü basit ve kararlı tutmaktır. Sistem istemcilerinin çoğu bu protokolden ihtiyaç duyduklarını alabilmelidir. Kalan özel durumlar için özel entegrasyon noktaları oluşturun.

Published Language (Yayın Dili)


Bu, şahsen açıklamakta en zorlandığım entegrasyon modeli. Benim baktığım şekilde, yayınlanan dil, open host servisine en yakın olanıdır ve genellikle bu entegrasyon modeliyle birlikte kullanılır. Sistemin girişi ve çıkışı için belgelenmiş bir dil (örneğin XML tabanlı) kullanılır. Yayınlanan dile uyduğunuz sürece belirli bir kitaplığı veya bir şartnamenin belirli bir uygulamasını kullanmaya gerek yoktur. Yayınlanmış dillerin gerçek dünya örnekleri, matematiksel formülleri temsil eden MathML ve coğrafi bilgi sistemlerinde coğrafi özellikleri temsil eden GML'dir.

Lütfen web hizmetlerini yayınlanan bir dille birlikte kullanmanız gerekmediğini unutmayın. Ayrıca bir dosyanın bir dizine bırakıldığı ve çıktıyı başka bir dosyada depolayan bir toplu iş tarafından işlendiği bir kuruluma sahip olabilirsiniz.

Separate Ways (Ayrı Roller)


Bu entegrasyon modeli, herhangi bir entegrasyon gerçekleştirmemesi açısından özeldir. Yine de, alet çantasında tutulması gereken önemli bir kalıptır ve çok fazla para ve zaman tasarrufu sağlayabilir. İki bağlam arasındaki entegrasyonun yararı artık çabaya değmediğinde, bağlamları birbirinden ayırmak ve bağımsız olarak evrimleşmelerine izin vermek daha iyidir. Bunun nedeni, sistemlerin artık birbirleriyle ilişkili olmadıkları bir noktaya evrilmiş olmaları olabilir. Aşağı akış bağlamının fiilen kullandığı yukarı akış bağlamı tarafından sağlanan (birkaç) hizmet, aşağı akış bağlamında yeniden uygulanır.

Stratejik Domaine Dayalı Tasarım Neden Önemlidir?


Stratejik domaine dayalı tasarımın aslında daha büyük projeler için tasarlandığına inanıyorum, ancak projede DDD'nin başka herhangi bir parçasını kullanmasanız bile, bundan daha küçük projelerde de yararlanabileceğinizi düşünüyorum.

Şahsen benim için stratejik domaine dayalı tasarımın başlıca çıkarımları şunlardır:

  1. Sınırlar getirir. Kapsam sünmesi (Scope creep), tüm hobi projelerimde değişmeyen bir faktördür. Sonunda, üzerinde çalışmak eğlenceden daha kapsamlı hale gelir veya tek başına bitirmek tamamen gerçekçi olmaz. Müşteri projeleri üzerinde çalışırken, bir şeyleri aşırı düşünerek veya aşırı mühendislik yaparak teknik kapsamın sünmesine neden olmamak için çok çalışmam gerekir. Sınırlar - nerede olurlarsa olsunlar - projeyi daha küçük parçalara bölmeme ve doğru zamanda doğru olanlara odaklanmama yardımcı oluyor.
  2. Her durumda çalışan bir süper model bulmamı gerektirmiyor. Stratejik DDD gerçek dünyada, genellikle az çok açıkça tanımlanmış bağlamlarda birçok küçük modelin olduğunu kabul eder. Bu modelleri kırmak yerine kucaklar.
  3. Sisteminizin getireceği değeri ve en büyük değeri elde etmek için çabalarınızın çoğunu nereye koymanız gerektiğini düşünmenize yardımcı olur. Doğru bir şekilde tanımlamanın ve ardından core domaine odaklanmanın büyük bir fark yaratacağı projelerden kişisel deneyime sahibim. Ne yazık ki, stratejik DDD'yi henüz duymamıştım ve hem zaman hem de para israf ettim.

Ayrıca, bu yaklaşımla riskleri tanımlayacak kadar iyi olduğumu da biliyorum: alt alanlar ve sınırlı bağlamlar bulmak adına alt alanlar ve sınırlı bağlamlar bulmak. Sevdiğim yeni bir şey öğrendiğimde, onu gerçek dünyada denemeyi çok isterim. Bu bazen orada olmayan şeyleri aramaya gittiğim anlamına gelebilir. Buradaki önerim, her zaman bir core domain ve bir sınırlı bağlam (bounded context) ile başlamaktır. Domain modellemesini dikkatlice yapıyorum, ek alt domainleri ve sınırlı bağlamlar varsa, sonunda kendilerini ortaya cıkaracaklardır.

Çeviri için izin veren  Petter Holmström'e teşekkürler.


Bonus :

Barış Velioğlu
Domain Driven Design Kimdir?