Bob Amca'nın temiz mimarisi - Her katman için bir varlık / model sınıfı?


44

ARKA FON :

Bob Amca'nın temiz mimarisini android uygulamamda kullanmaya çalışıyorum. Doğru yolu göstermeye çalışan birçok açık kaynaklı proje okudum ve RxAndroid'e dayalı ilginç bir uygulama buldum.

Farkettim:

Her katmanda (sunum, etki alanı ve veri), aynı varlık için bir model sınıfı var (UML konuşuyor). Artı, veriler sınırları geçerken (katmandan diğerine) nesnenin dönüşümüyle ilgilenen eşleyici sınıfları vardır.

SORU:

Tüm CRUD işlemlerine ihtiyaç duyulursa hepsinin aynı özelliklerle sonuçlanacağını bildiğimde her katmanda model sınıflarına sahip olmak gerekli midir? Veya, temiz mimariyi kullanırken bir kural mı yoksa en iyi uygulama mı?

Yanıtlar:


52

Kanımca, kesinlikle demek istediğim bu değil. Ve bu bir DRY ihlalidir.

Buradaki fikir, ortadaki varlık / etki alanı nesnesinin, etki alanını olabildiğince iyi ve uygun şekilde temsil edecek şekilde modellenmesidir. Her şeyin merkezindedir ve her şey ona bağlı olabilir çünkü alan çoğu zaman değişmez.

Dışarıdaki veritabanınız bu nesneleri doğrudan saklayabiliyorsa, katmanları ayırmak için onları başka bir formata eşlemek yalnızca anlamsız değil, modelin kopyalarını oluşturmak ve amaç değildir.

Öncelikle, temiz mimari farklı tipik bir çevre / senaryo düşünülerek yapıldı. Kendi özel nesne türlerine ihtiyaç duyan dev dış katmanlara sahip iş sunucusu uygulamaları. Örneğin, SQLRownesneleri üreten ve SQLTransactionsöğeleri güncellemenin karşılığında ihtiyaç duyan veritabanları . Bunları merkezde kullanacak olsaydınız, bağımlılık yönünü ihlal edersiniz, çünkü çekirdeğiniz veritabanına bağlı olacaktır.

Var olmayan objeleri yükleyen ve saklayan hafif ORM'ler. Kendi iç SQLRowbölgeniz ile etki alanınız arasındaki eşlemeyi yaparlar . @EntitiyEtki alanı nesnesine ORM'nin bir açıklamasını eklemeniz gerekse bile , bunun dış katmandan "söz edilmediğini" iddia ediyorum. Ek açıklamalar yalnızca meta veriler olduğundan, özellikle onları aramayan hiçbir kod bunları görmez. Daha da önemlisi, bunları kaldırırsanız ya da farklı bir veritabanının notuyla değiştirirseniz hiçbir şeyin değişmesi gerekmez.

Bunun aksine, etki alanınızı değiştirirseniz ve tüm bu haritalayıcıları yaparsanız, çok fazla değişiklik yapmanız gerekir.


Değişiklik: Yukarıda biraz fazla basitleştirilmiş ve hatta yanlış olabilir. Çünkü temiz mimaride katman başına bir temsil yaratmanızı isteyen bir bölüm var. Ancak bu uygulama bağlamında görülmelidir.

Yani burada aşağıdakiler https://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html

Önemli olan izole edilmiş, basit, veri yapılarının sınırlardan geçmesidir. Varlıkları veya Veritabanı satırlarını aldatmak ve geçmek istemeyiz . Veri yapılarının, Bağımlılık Kuralını ihlal eden herhangi bir bağımlılığa sahip olmasını istemiyoruz.

Varlıkları merkezden dış katmanlara geçirmek, bağımlılık kuralını ihlal etmiyor, ancak yine de bahsediliyor. Ancak bunun öngörülen uygulama bağlamında bir nedeni vardır. Etraftaki varlıkları geçmek, uygulama mantığını dışarıya doğru hareket ettirir. Dış katmanların, iç nesnelerin nasıl yorumlanacağını bilmeleri gerekecek, "kullanım durumu" katmanı gibi iç katmanların yapması gerekenleri etkin bir şekilde yapmaları gerekecek.

Bunun yanı sıra, aynı zamanda katmanları da ayrıştırır, böylece çekirdekteki değişiklikler mutlaka dış katmanlarda değişiklik gerektirmez (bkz. SteveCallender'ın yorumu). Bu bağlamda, nesnelerin, özellikle kullanıldıkları amacı nasıl temsil etmesi gerektiğini görmek kolaydır. Ayrıca bu katmanların birbirleriyle, özellikle bu iletişim amacıyla yapılmış nesneler hakkında konuşmaları gerekir. Bu, her katmanda 1, katlar arasında taşıma için 1 olmak üzere 3 gösterim olduğu anlamına gelebilir.

Ve yukarıda belirtilen https://blog.8thlight.com/uncle-bob/2011/11/22/Clean-Architecture.html var :

Diğer insanlar benim tavsiyemin net sonucunun çok sayıda kopya kod olacağından ve verilerin bir veri yapısından diğerine sistemin katmanları boyunca çok sayıda nefretle kopyalanmasından korkuyorlardı. Kesinlikle bunu da istemiyorum; ve önerdiğim hiçbir şey kaçınılmaz olarak veri yapılarının tekrarlanmasına ve alan kopyalamanın yanlış olmasına yol açmayacaktır.

IMO, düz 1: 1 nesnelerin kopyalanmasının mimaride bir koku olduğunu ima ediyor, çünkü aslında uygun katmanları ve / veya soyutlamaları kullanmıyorsunuz.

Daha sonra tüm "kopyalamayı" nasıl hayal ettiğini açıklar.

İkisi arasında basit veri yapıları ileterek kullanıcı arabirimini iş kurallarından ayırırsınız. Denetçilerinizin iş kuralları hakkında hiçbir şey bilmesine izin vermeyin. Bunun yerine, denetleyiciler HttpRequest nesnesini basit bir vanilya veri yapısına paketten çıkarır ve ardından bu veri yapısını, iş nesnelerini çağırarak kullanım durumunu uygulayan bir etkileşimli nesneye geçirir. Etkileyici daha sonra yanıt verilerini başka bir vanilya veri yapısına toplar ve tekrar UI'ye iletir. Görünümler işletme nesnelerini bilmez. Sadece o veri yapısına bakarlar ve cevabı sunarlar.

Bu uygulamada, temsiller arasında büyük bir fark vardır. Akan veriler sadece varlıklar değildir. Bu da farklı sınıfları garanti ve talep eder.

Ancak, Photoişletmenin yaklaşık 0 iş kuralına sahip olduğu ve bunlarla ilgilenen "kullanım senaryosunun" neredeyse bulunmadığı ve aslında önbelleğe alma ve indirme konusunda daha endişeli olduğu bir fotoğraf görüntüleyici gibi basit bir Android uygulamasına uygulanır (bu işlem IMO olmalıdır. Daha açık bir şekilde ifade edilirse), bir fotoğrafın ayrı gösterimlerini yapma noktası ortadan kalkmaya başlar. Gerçek ticari-mantık-çekirdek katmanı eksikken fotoğrafın kendisinin veri aktarımı nesnesi olduğu hissine kapılıyorum.

İkisi arasında basit veri yapılarını ileterek kullanıcı arabirimini iş kurallarından ayırmak ile " ve " bir fotoğrafın yolunu 3 kez yeniden adlandırmak istediğinizde "arasında bir fark vardır .

Bunun yanı sıra, bu demo uygulamaların temiz mimariyi temsil etmekte başarısız olduğunu gördüğüm nokta, katmanları ayırma uğruna katmanları ayırmaya büyük önem vermeleri, ancak uygulamanın ne yaptığını etkili bir şekilde gizlemeleri. Yani söylenenlerin aksine olduğu https://blog.8thlight.com/uncle-bob/2011/09/30/Screaming-Architecture.html - yani o

Bir yazılım uygulamasının mimarisi, uygulamanın kullanım durumları hakkında çığlık atar

Temiz mimaride katmanları ayırma vurgusu görmüyorum. Bağımlılık yönü ile ilgilidir ve uygulamanın çekirdeğini temsil etmeye odaklanır - varlıklar ve kullanım durumları - dış mekana bağımlı olmadan ideal java'da. Bu çekirdeğe olan bağımlılıklar hakkında çok fazla bir şey değil.

Bu nedenle, başvurunuz aslında iş kurallarını temsil eden ve davaları kullanan bir çekirdeğe sahipse ve / veya farklı kişiler farklı katmanlar üzerinde çalışıyorsa, lütfen onları istediğiniz şekilde ayırın. Öte yandan, sadece basit bir uygulama yazıyorsanız, kendiniz abartmayın. Akıcı sınırları olan 2 katman, fazlasıyla olabilir. Katmanlar daha sonra da eklenebilir.


1
@RamiJemli İdeal olarak, varlıklar tüm uygulamalarda aynıdır. "Kurum çapında iş kuralları" ile "uygulama iş kuralları" (bazen işle uygulama mantığı) arasındaki fark budur. Çekirdek, varlıklarınızın her yerde kullanabileceğiniz kadar genel olan çok soyut bir temsilidir. Biri müşteri desteği için, biri para çekme makinelerinde çalışan, biri müşterinin kendisi için web kullanıcı arayüzü gibi birçok uygulamaya sahip bir banka düşünün. Hepsi aynı şeyi kullanabilir BankAccountancak uygulamaya özel kurallarla o hesapla neler yapabilirsiniz.

4
Temiz mimarideki önemli bir nokta, farklı katmanların varlığı temsil etmesi arasında dönüştürmek (veya harita dediğiniz gibi) için arayüz adaptör katmanını kullanarak, söz konusu varlığa olan bağımlılığı azaltmanızdır. Usecase veya Entity katmanlarında bir değişiklik olması durumunda (umarım pek olası değildir, ancak şartlar bu katmanları değiştirdikçe) değişimin etkisi adaptör katmanında bulunur. Tüm varlığın aynı temsilini mimariniz boyunca kullanmayı seçtiyseniz, bu değişikliğin etkisi çok daha büyük olacaktır.
SteveCallender

1
@RamiJemli hayatı kolaylaştıran çerçeveler kullanmak iyidir, asıl nokta, mimariniz onlara güvendiğinde dikkatli olmanız ve onları her şeyin merkezine koymaya başlamanızdır. İşte RxJava blog.8thlight.com/uncle-bob/2015/08/06/let-the-magic-die.html hakkında bir makale bile - kullanmamanız gerektiği yazıyor . Daha çok gibi: Bunu gördüm, bir yıl içinde farklı olacak ve başvurunuz hala buralarda durumdayken. Düz eski SOLID prensiplerini uygularken, detaylandırın ve eski java'daki en önemli şeyleri yapın.
zapl

1
@zapl Bir web servis katmanı hakkında aynı şekilde hissediyor musunuz? Başka bir deyişle, @SerializedNameGson ek açıklamalarını etki alanı modeline ekler misiniz ? Veya web yanıtını etki alanı modeliyle eşlemekten sorumlu yeni bir nesne mi oluşturursunuz?
tir38

2
@ tir38 Ayrılmanın kendisi fayda sağlamaz, bununla birlikte gelecekteki değişikliklerin maliyetidir. => Uygulamaya göre değişir. 1) farklı temsiller arasında dönüşüm ekleyen aşamayı yaratmanız ve sürdürmeniz zaman alır. Örneğin, etki alanına bir alan eklemek ve başka bir yere eklemeyi unutmak duyulmamış değil. Basit bir yaklaşımla olamaz. 2) İhtiyacınız olursa daha sonra daha karmaşık bir kuruma geçmenin maliyeti. Katman eklemek kolay değildir, bu nedenle büyük uygulamalarda hemen gerekmeyen daha fazla katmanı haklı çıkarmak daha kolaydır
zapl

7

Aslında doğru anlamışsın. DRY ihlal edilmez çünkü SRP'yi kabul ediyorsunuz.

Örneğin: bir business-Method createX (String name) kullanıyorsanız, DAO-Layer'da business-Method içinde çağrılan bir Method createX (String name) olabilir. Aynı imza sahip olabilirler ve belki sadece bir delegasyon vardır ancak farklı amaçları vardır. UseCase'de ayrıca bir createX (String name) olabilir. O zaman bile gereksiz değil. Bununla demek istediğim şudur: Aynı imzalar aynı anlambilim anlamına gelmez. Anlambilimin temizlenmesi için başka isimler seçin. Kendisini isimlendirmek SRP'yi hiç etkilemez.

UseCase uygulamaya özel mantıktan sorumludur, iş nesnesi uygulamadan bağımsız mantıktan ve DAO depolamaktan sorumludur.

Farklı anlambilimden ötürü tüm katmanlar kendi temsil ve iletişim modellerine sahip olabilir. Genellikle "varlıklar" ı "iş nesneleri" olarak görür ve genellikle bunları ayırma gerekliliğini görmezsiniz. Ancak “büyük” projelerde katmanları düzgün bir şekilde ayırmak için çaba gösterilmelidir. Proje büyüdükçe, farklı katmanlar ve sınıflarda temsil edilen farklı semantiklere ihtiyacınız olma ihtimali artar.

Aynı anlambilimin farklı yönlerini düşünebilirsiniz. Ekranda bir Kullanıcı Nesnesi gösterilmeli, bazı iç tutarlılık kuralları vardır ve bir yerde saklanmalıdır. Her özellik farklı bir sınıfta (SRP) temsil edilmelidir. Haritacılar oluşturmak eşeklerde acı olabilir, bu yüzden bu yönlerde çalıştığım birçok projede tek bir sınıfta eritilir. Bu açıkça bir SRP ihlalidir ancak kimse gerçekten umursamıyor.

Temiz mimari ve SOLID uygulamasını “sosyal olarak kabul edilebilir değil” olarak adlandırıyorum. İzin verilirse onunla çalışırdım. Şu anda bunu yapmama izin verilmiyor. SOLID'i ciddiye almayı düşünmek zorunda olduğumuz anı bekliyorum.


Veri katmanındaki hiçbir yöntemin, Etki Alanı katmanındaki herhangi bir yöntemle aynı imzasına sahip olmamasını düşünüyorum. Etki Alanı katmanında, signUp veya login gibi işle ilgili adlandırma kurallarını kullanırsınız ve Veri katmanında, kaydetme (DAO kalıbıysa) veya ekleme (bu kalıp, Koleksiyon'u metafor olarak kullandığından dolayı) kullanırsınız. Son olarak, varlıklardan (Veri) ve modelden (Etki Alanı) bahsetmiyorum, UserModel ve Eşleyici'nin (sunum katmanı) işe yaramazlığını vurguladım. Sunumun içindeki etki alanının Kullanıcı sınıfını arayabilirsiniz ve bu bağımlılık kuralını ihlal etmez.
Rami Jemli

Rami ile aynı fikirdeyim, haritacı gereksiz çünkü haritalamayı doğrudan interaktif uygulamada yapabilirsiniz.
Christopher Perry

5

Hayır, her katmanda model sınıfları oluşturmanıza gerek yoktur.

Entity ( DATA_LAYER) - Database nesnesinin tam veya kısmi bir temsilidir.DATA_LAYER

Mapper ( DOMAIN_LAYER) - aslında, Varlığı, üzerinde kullanılacak ModelClass öğesine dönüştüren bir sınıftır.DOMAIN_LAYER

Bir göz atın: https://github.com/lifedemons/photoviewer


1
Tabii ki, veri katmanındaki varlıklara karşı değilim, ancak örneğinizde sunum katmanındaki PhotoModel sınıfı, etki alanı katmanındaki Photo sınıfının aynı özelliklerine sahip. Teknik olarak aynı sınıf. bu gerekli mi

Bir şey senin haritacılar IMO, tersi mengene olmalıdır veri katmanında varlıkları bağlıdır sizin örnekte olduğu gibi diğer katmanlardan dayanmamalısınız alanı katmanı olarak sizin örnekte kapalı olduğunu düşünüyorum
navid_gh
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.