Tek sorumluluk ilkesi - gereğinden fazla mı kullanıyorum?


13

Referans için - http://en.wikipedia.org/wiki/Single_responsibility_principle

Ben bir uygulama modülünde defter girişleri oluşturmaktan sorumlu olduğu bir test senaryosu var. Gerçekleştirilebilecek üç temel görev vardır -

  • Mevcut defter girişlerini tablo biçiminde görüntüleyin.
  • Oluştur düğmesini kullanarak yeni defter girişi oluşturun.
  • Tablodaki bir defter girişine tıklayın (ilk işaretçide belirtilir) ve ayrıntılarını bir sonraki sayfada görüntüleyin. Bu sayfada bir defter girişini geçersiz kılabilirsiniz.

(Her sayfada birkaç işlem / doğrulama daha vardır, ancak kısaca, bunu bunlarla sınırlayacağım)

Bu yüzden üç farklı sınıf oluşturmaya karar verdim -

  • LedgerLandingPage
  • CreateNewLedgerEntryPage
  • ViewLedgerEntryPage

Bu sınıflar, bu sayfalarda yapılabilecek hizmetleri sunar ve Selenyum testleri, bu iddiaları belirli bir iddiada bulunabileceğim bir duruma getirmek için bu sınıfları kullanır.

Ben meslektaşım ile gözden geçirirken o zaman whelmed ve herkes için tek bir sınıf yapmak istedi. Tasarımımın çok temiz olduğunu düşünmeme rağmen Tek Sorumluluk prensibini gereğinden fazla kullanıyorsam şüpheliyim


2
IMHO genel olarak sorunuzu iki şey bilmeden cevaplamaya çalışmanın bir anlamı yok: Bu sınıflar ne kadar büyük (yöntem sayısı ve LOC ile)? Öngörülebilir gelecekte ne kadar daha büyük / daha karmaşık büyümeleri bekleniyor?
Péter Török

2
Her biri 10 yöntem olan IMHO, kodu 30 yöntemle bir sınıfa koymamak için açık bir göstergedir.
Doc Brown

6
Bu sınır bölgesi: 100 LOC ve 10 yöntemden oluşan bir sınıf çok küçük değil ve 300 LOC'dan biri çok büyük değil . Ancak, tek bir sınıfta 30 yöntem bana çok fazla geliyor. Genel olarak, birçok küçük derse sahip olmanın tek bir fazla kilolu sınıftan daha az riskli olması nedeniyle @Doc ile hemfikirim. Özellikle derslerin doğal olarak zamanla kilo alma eğilimi olduğunu göz önünde bulundurarak ...
Péter Török

1
@ PéterTörök - Ben OP beklediğim gibi yinelenen işlevsellik yerine kodu yeniden sezgisel olarak kullanılabilir bir sınıfa yeniden düzenlenemez sürece katılıyorum.
SoylentGray

1
Belki de MVC uygulamak bunu temizleyecektir: üç görünüm, bir model (Defter) ve muhtemelen üç kontrolör.
kevin cline

Yanıtlar:


19

@YannisRizos buraya :

Bu içgüdüsel bir yaklaşımdır ve muhtemelen doğrudur, çünkü değiştirilmesi daha muhtemel olan defterleri yönetmenin iş mantığıdır. Böyle bir durumda, bir sınıfı üçten daha korumak çok daha kolay olurdu.

En azından şimdi, yaklaşık 30 yıllık programlama deneyiminden sonra katılmıyorum. Daha küçük sınıflar IMHO, bu gibi durumlarda düşünebildiğim hemen hemen her durumda korumak için daha iyidir . Bir sınıfa ne kadar çok işlev koyarsanız, o kadar az yapıya sahip olursunuz ve kodunuzun kalitesi düşer - her gün birazcık. Tarun'u doğru anladığımda, bu 3 operasyonun her biri

LedgerLandingPage

CreateNewLedgerEntryPage

ViewLedgerEntryPage

bir kullanım örneğidir, bu sınıfların her biri ilgili görevi gerçekleştirmek için birden fazla işlevden oluşur ve her biri ayrı ayrı geliştirilip test edilebilir. Bu nedenle, her biri için sınıflar oluşturmak, birbirine ait olan şeyleri bir araya getirir ve bir şeyin değişmesi durumunda kodun değiştirilecek kısmını tanımlamayı çok daha kolay hale getirir.

Bu 3 sınıf arasında ortak işlevsellikleriniz varsa, bunlar ortak bir temel sınıf, Ledgersınıfın kendisine aittir (CRUD işlemleri için en azından bir tane olduğunu varsayıyorum) veya ayrı bir yardımcı sınıf.

Daha küçük sınıflar oluşturmak için daha fazla tartışmaya ihtiyacınız varsa, Robert Martin'in "Temiz Kod" kitabına bakmanızı tavsiye ederim .


bu yüzden her şeyi tek bir sınıfa itmek yerine üç farklı sınıfla karşılaştım. Bunların hiçbirinde ortak bir işlevsellik olmadığından, ortak bir sınıfım yok. Bağlantı için teşekkürler.
Tarun

2
"Daha küçük sınıfları düşünebildiğim her durumda korumak daha iyidir." Temiz Kod'un bile bu kadar ileri gideceğini sanmıyorum. Bir MVC modelinde, örneğin sayfa başına bir denetleyici olması gerektiğini (veya koyduğunuzda kullanım senaryosunu) gerçekten iddia eder misiniz? Yeniden Düzenleme'de Fowler'in birlikte iki kod kokusu vardır: biri bir sınıfı değiştirmek için birçok nedene (SRP) ve diğeri de bir değişiklik için birçok sınıfı düzenlemeye atıfta bulunur.
pdr

@pdr, OP bu sınıflar arasında ortak bir işlevsellik olmadığını belirtir, bu yüzden (benim için) tek bir değişiklik yapmak için birden fazla dokunmaya ihtiyaç duyduğunuzda bir durumu hayal etmek zor.
Péter Török

@pdr: Bir değişiklik için düzenlemek için çok fazla sınıfınız varsa, bu genellikle ortak işlevselliği ayrı bir yere yeniden düzenlemediğinizin bir işaretidir. Ancak yukarıdaki örnekte, bu muhtemelen sadece bir değil, dördüncü bir sınıfa yol açacaktır.
Doc Brown

2
@pdr: BTW, "Kodu Temizle" yi gerçekten okudunuz mu? Bob Martin, kodu daha küçük birimlere bölmede çok uzağa gidiyor .
Doc Brown

11

Tek Sorumluluk İlkesinin veya başka bir ilkenin kesin bir uygulaması yoktur. Neyin değişebileceğine bağlı olarak karar vermelisiniz.

@Karpie'nin daha önceki bir cevapta yazdığı gibi :

Sadece bir sınıfa ihtiyacınız vardır ve bu sınıfın tek sorumluluğu defterleri yönetmektir.

Bu içgüdüsel bir yaklaşımdır ve muhtemelen doğrudur, çünkü değiştirilmesi daha muhtemel olan defterleri yönetmenin iş mantığıdır. Böyle bir durumda, bir sınıfı üçten daha korumak çok daha kolay olurdu.

Ancak bu her vaka için incelenmeli ve kararlaştırılmalıdır. Küçük bir değişim olasılığı ile ilgili endişeleri gerçekten önemsememeli ve neyin değişme olasılığı daha fazla olduğu ilkesini uygulamaya konsantre olmalısınız. Defterleri yönetme mantığı çok katmanlı bir süreçse ve katmanlar bağımsız olarak değişmeye eğilimliyse veya prensipte ayrı olması gereken endişeler (mantık ve sunum) ise, ayrı sınıflar kullanmalısınız. Bu bir olasılık oyunu.

İlginç tasarım ilkeleri konusunda benzer bir soru, ilginç bulacağınızı düşünüyorum: Tasarım kalıpları: kalıpları kullanarak her şeyi ne zaman kullanmalı ve ne zaman bırakmalı


1
SRP, benim görüşüme göre, aslında bir tasarım modeli değil.
Doc Brown

@DocBrown Tabii ki bir tasarım deseni değil, ama soru hakkındaki tartışma son derece alakalı ... İyi yakala, yanıtı güncelledim
yannis

4

Bu sınıfları inceleyelim:

  • LedgerLandingPage: Bu sınıfın rolü defterlerin bir listesini göstermektir. Uygulama büyüdükçe, diğer veri kaynaklarından gelen verileri sıralamak, filtrelemek, vurgulamak ve şeffaf bir şekilde kaynaştırmak için yöntemler eklemek isteyeceksiniz.

  • ViewLedgerEntryPage: Bu sayfa defteri ayrıntılı olarak gösterir. Oldukça dümdüz görünüyor. Veriler doğrudan ileri olduğu sürece. Burada defteri geçersiz kılabilirsiniz. Bunu düzeltmek de isteyebilirsiniz. Veya yorum yapın veya bir dosya, makbuz veya harici rezervasyon numarası veya başka bir şey ekleyin. Düzenlemeye izin verdiğinizde, kesinlikle bir tarih göstermek istersiniz.

  • CreateLedgerEntryPage: Eğer ViewLedgerEntryPagetam düzenleme yeteneğine sahiptir, bu sınıfın sorumluluğu muhtemelen ya mantıklı olmayabilir olabilecek bir "boş girişi", düzenleyerek yerine getirilebilir.

Bu örnekler biraz uzak görünebilir, ancak mesele şu ki, bir UX'den burada özellikler konuşuyoruz. Tek bir özellik kesinlikle ayrı, tek bir sorumluluktur. Çünkü bu özelliğin gereksinimleri değişebilir ve iki farklı özelliğin gereksinimleri iki karşıt yöne dönüşebilir ve daha sonra SRP'ye en baştan takılı kalmanızı dilersiniz.
Ancak tersine, tek bir arabirime sahip olmak düşünebileceğiniz herhangi bir nedenden dolayı daha uygunsa, her zaman bir cepheyi üç sınıfa tokatlayabilirsiniz.


SRP'nin aşırı kullanımı gibi bir şey var : Bir dosyanın içeriğini okumak için bir düzine sınıfa ihtiyacınız varsa, bunu yaptığınızı varsaymak oldukça güvenlidir.

SRP'ye diğer taraftan bakarsanız, aslında, tek bir sorumluluğun tek bir sınıf tarafından ele alınması gerektiğini söyler. Ancak, sorumlulukların sadece soyutlama seviyelerinde bulunduğunu lütfen unutmayın. Bu nedenle, daha yüksek bir soyutlama seviyesinden bir sınıfın, işi en iyi bağımlılık tersine çevirme yoluyla elde edilen daha düşük seviyeli bileşene devrederek sorumluluğunu yerine getirmesi mükemmel bir mantıklıdır .


Sanırım bu sınıfların sorumluluğunu sizden daha iyi tarif edemezdim.
Tarun

2

Bu sınıfların değişmesi için sadece bir nedeni var mı?

Bunu bilmiyorsanız (henüz), o zaman spekülatif tasarıma / mühendislik tuzağına adım atmış olabilirsiniz (çok fazla sınıf, çok karmaşık tasarım desenleri uygulandı). YAGNI'dan memnun kalmadınız . Yazılım yaşam döngüsünün erken aşamalarında (bazı) gereksinimler açık olmayabilir. Böylece değişim yönü şu anda sizin için görülmüyor. Bunu fark ederseniz, bir veya en az sayıda sınıfta saklayın. Bununla birlikte, bu bir sorumluluk ile gelir: Gereksinimler ve değişiklik yönü daha açık olur olmaz, mevcut tasarımı yeniden düşünmeniz ve değişiklik nedenini karşılamak için bir yeniden düzenleme yapmanız gerekir.

Değişimin üç farklı nedeni olduğunu ve bu üç sınıfa eşlendiklerini zaten biliyorsanız, doğru dozda SRP uyguladınız. Yine bu bazı sorumluluklarla birlikte gelir: Yanlışsanız veya gelecekteki gereksinimler beklenmedik bir şekilde değişirse, mevcut tasarımı yeniden düşünmeniz ve değişiklik nedenini karşılamak için bir yeniden düzenleme yapmanız gerekir.

Bütün mesele:

  • Değişim için sürücülere bir göz atın.
  • Yeniden düzenlenebilir esnek bir tasarım seçin.
  • Kodu yeniden düzenlemeye hazır olun.

Bu zihniyete sahipseniz, kodu spekülatif tasarım / mühendislikten çok korkmadan şekillendireceksiniz.

Bununla birlikte, her zaman faktör süresi vardır: Birçok değişiklik için ihtiyacınız olan zamanınız olmayacaktır. Yeniden düzenleme, zaman ve çaba gerektirir. Tasarımı değiştirmek zorunda olduğumu bildiğim durumlarla sık sık karşılaştım, ancak zaman kısıtlamaları nedeniyle onu ertelemek zorunda kaldım. Bu olacak ve önlenemez. Mühendislik kodunda yeniden düzenleme yapmanın mühendislik kodundan daha kolay olduğunu buldum. YAGNI bana iyi bir rehberlik veriyor: Şüpheniz varsa, sınıfların miktarını ve tasarım modellerinin uygulamasını minimumda tutun.


1

SRP'yi bir sınıfı bölmenin bir nedeni olarak çağırmanın üç nedeni vardır:

  • böylece gereksinimlerdeki gelecekteki değişiklikler bazı sınıfları değiştirmeden bırakabilir
  • böylece bir hata daha çabuk izole edilebilir
  • sınıfı küçültmek

Bir sınıfı bölmeyi reddetmenin üç nedeni vardır:

  • böylece gelecekte yapılacak değişiklikler, birden çok sınıfta aynı değişikliği yapmanıza neden olmaz.
  • böylece hata bulma uzun dolaylı yolların izlenmesini içermez
  • ilgili bir sınıf tarafından ihtiyaç duyulduğunda herkese bilgi ya da yöntem ortaya koyan kapsülleme kırma tekniklerine (özellikler, arkadaşlar, ne olursa olsun) direnmek

Davanıza baktığımda ve değişiklikleri hayal ettiğimde, bazıları birden fazla sınıfta değişikliklere neden olacak (örneğin deftere bir alan ekleyin, üçünü de değiştirmeniz gerekecek), ancak birçoğu değişmeyecek - örneğin defterlerin listesine sıralama ekleme veya yeni bir defter girişi eklerken doğrulama kurallarını değiştirme. Meslektaşınızın tepkisi muhtemelen bir hatayı nerede arayacağını bilmek zor. Defter listesinde bir şeyler yanlış görünüyorsa, yanlış eklenmiş olması mı yoksa listede bir sorun var mı? Özet ve ayrıntılar arasında bir tutarsızlık varsa, bu yanlış mıdır?

Ayrıca meslektaşınız, her üç sınıfı da değiştirmek zorunda kalacağınız anlamına gelen gereksinimlerdeki değişikliklerin, sadece bir sınıfı değiştirmekten kaçacağınız değişikliklerden çok daha olası olduğunu düşünüyor olabilir. Bu gerçekten yararlı bir konuşma olabilir.


farklı bir bakış açısı görmek güzel
Tarun

0

Defter db bir tablo olsaydı, bu thress görev bir sınıfa (örneğin DAO) koymak öneririz. Defter daha mantık varsa ve db bir tablo değilse, ben bu görevleri yapmak için daha fazla sınıf oluşturmak gerektiğini öneririz (iki veya thress sınıfı olabilir) ve sadece müşteri için yapılacak bir cephe sınıfı sağlar.


defteri, kullanıcı arayüzünde bir özelliktir ve farklı sayfalardan yapılabilecek birçok ilgili işlem vardır.
Tarun

0

IMHO hiç ders kullanmamalısınız. Burada veri soyutlaması yok. Defterler somut bir veri türüdür. Bunları manipüle etme ve görüntüleme yöntemleri fonksiyonlar ve prosedürlerdir. Bir tarihin biçimlendirilmesi gibi paylaşılacak çok yaygın olarak kullanılan işlevler kesinlikle olacaktır. Görüntü ve seçim rutinlerindeki bir sınıfta herhangi bir verinin soyutlanması ve gizlenmesi için çok az yer vardır.

Defter düzenleme için bir sınıftaki durumu gizlemek için bazı durumlar vardır.

SRP'yi kötüye kullanıyor olsanız da etmeseniz de, daha temel bir şeyi kötüye kullanıyorsunuz: soyutlamayı aşırı kullanıyorsunuz. Bu, efsanevi OO fikrinin yarattığı tipik bir problemdir, aklı başında bir geliştirme paradigmasıdır.

Programlama% 90 somuttur: veri soyutlamasının kullanımı nadir ve dikkatli bir şekilde tasarlanmalıdır. Diğer yandan, işlevsel soyutlama daha yaygın olmalıdır, çünkü dil detayları ve algoritma seçiminin operasyonun anlamından ayrılması gerekir.


-1

Sadece bir sınıfa ihtiyacınız vardır ve bu sınıfın tek sorumluluğu defterleri yönetmektir .


2
Benim için bir '... yönetici' sınıfı genellikle onu daha fazla yıkmak için rahatsız edemeyeceğinizi gösterir. Sınıf yönetimi nedir? Sunum, kalıcılık?
sebastiangeiger

-1. 3 veya daha fazla kullanım durumunu 1 sınıfa koymak, SRP'nin kaçınmaya çalıştığı şeydir - ve iyi nedenlerle.
Doc Brown

@sebastiangeiger Peki OP'nin üç sınıfı ne yapıyor? Sunum mu, kalıcılık mı?
sevenseacat

@Karpie Dürüst olmak gerekirse sunumu umuyorum. Verilmiş, örnek gerçekten iyi değil, ama bir web sitesindeki '... Page' ın bir görünüme benzer bir şey yapmasını beklerim.
sebastiangeiger

2
Aslında, kullanıcıları mutlu etmek için tek sorumluluk ile tüm uygulama için sadece bir sınıfa ihtiyacınız var ;-)
Péter Török
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.