Yeniden düzenleme ve Açık / Kapalı prensibi


12

Son zamanlarda temiz kod geliştirme hakkında bir web sitesi okuyor (İngilizce olmadığı için buraya bir bağlantı koymayın).

Bu site tarafından ilan edilen ilkelerden biri Açık Kapalı Prensiptir : her yazılım bileşeni genişletme için açık ve modifikasyon için kapalı olmalıdır. Örneğin, biz uygulanacak ve bir sınıf test ettik, biz sadece hataları düzeltmek için veya yeni işlevler eklemek için (örneğin yeni yöntemleri değiştirmelisiniz yok mevcut olanları etkilemek). Mevcut işlevsellik ve uygulama değiştirilmemelidir.

Normalde bu ilkeyi bir arabirim Ive karşılık gelen bir uygulama sınıfı tanımlayarak uygularım A. Sınıf Akararlı hale geldiğinde (uygulandığında ve test edildiğinde ) normalde çok fazla değiştirmiyorum (muhtemelen, hiç de değil), yani

  1. Kodda büyük değişiklikler gerektiren yeni gereksinimler (örn. Performans veya tamamen yeni bir uygulama) gelirse, yeni bir uygulama yazarım Bve olgun olmadığı Asürece kullanmaya devam ederim B. Ne zaman Bolgun olduğunu gerekli olduğunu tüm nasıl değiştirmektir Iörneği.
  2. Yeni gereksinimler de arabirimde bir değişiklik önerirse, yeni bir arabirim I've yeni bir uygulama tanımlarım A'. Yani I, Adonmuş ve kalan uygulama uzun olduğu kadar üretim sistemi için I've A'bunların yerine istikrarlı yeterli değildir.

Dolayısıyla, bu gözlem ışığında, web sayfasının karmaşık yeniden düzenleme işlemlerinin kullanılmasını önerdiğine biraz şaşırdım, çünkü kod doğrudan son haliyle yazmak mümkün değil. ”

Açık / Kapalı İlkesini uygulamak ile karmaşık yeniden düzenlemelerin en iyi uygulama olarak kullanılmasını önermek arasında bir çelişki / çatışma yok mu? Ya da buradaki fikir, bir sınıfın gelişimi sırasında karmaşık yeniden düzenlemeleri kullanabileceğidir A, ancak bu sınıf başarıyla test edildiğinde dondurulmalı mıdır?

Yanıtlar:


9

Açık-Kapalı prensibini bir tasarım hedefi olarak düşünüyorum . Sonunda onu ihlal etmek zorunda kalırsanız, bu ilk tasarımınızın başarısız olduğu anlamına gelir, bu kesinlikle mümkündür ve hatta muhtemeldir.

Yeniden düzenleme, işlevselliği değiştirmeden tasarımı değiştirdiğiniz anlamına gelir. Muhtemelen tasarımınızı değiştiriyorsunuz çünkü onunla ilgili bir sorun var. Belki de sorun, mevcut kodda değişiklik yaparken açık-kapalı prensibini takip etmenin zor olmasıdır ve bunu düzeltmeye çalışıyorsunuzdur.

Bir sonraki özelliğinizi , OCP'yi ihlal etmeden uygulamadan mümkün kılmak için yeniden düzenleme yapıyor olabilirsiniz .


Kesinlikle bir tasarım hedefi olarak herhangi bir ilke olarak düşünmemelisiniz . Bunlar araçlar - yazılımı içeride güzel ve teorik olarak doğru yapmıyorsunuz, müşteriniz için değer üretmeye çalışıyorsunuz. Bu bir rehber , başka bir şey değil.
T. Sar

@ T.Sar İlke, bir kılavuzdur, uğraştığınız bir şeydir, sürdürülebilirlik ve ölçeklenebilirliğe yöneliktir. Bu benim için bir tasarım hedefi gibi görünüyor. Bir prensibi bir tasarım desenini veya çerçeveyi bir araç olarak görme biçimimde bir araç olarak göremiyorum.
Tulains Córdova

@ TulainsCórdova Sürdürülebilirlik, Performans, Doğruluk, Ölçeklenebilirlik - bunlar hedeflerdir. Açık-Kapalı prensibi onlara yönelik bir araçtır - çoğundan sadece biri. Bir şey uygulanabilir değilse veya projenin gerçek hedeflerinden uzaklaşırsa, açık-kapalı prensibine doğru bir şey yapmanız gerekmez. Sen yok satmak , bir müşteriye "Açık-Kapalılığı". Sadece bir kılavuz olarak , işinizi daha okunaklı ve net bir şekilde yapmanın bir yolunu bulursanız atılabilecek bir başparmak kuralından daha iyi değildir. Her şeyden önce yönergeler araçlardır.
T. Sar

@ T.Sar Bir müşteriye satamayacağınız çok şey var ... Öte yandan, size katılıyorum ki, projenin amaçlarından uzaklaşacak şeyler yapmamanız gerekiyor.
Tulains Córdova

9

Açık-Kapalı prensibi, yazılımınızın ne kadar iyi tasarlandığının bir göstergesidir ; tam anlamıyla takip edilecek bir ilke değil. Ayrıca, mevcut arayüzleri yanlışlıkla değiştirmemize yardımcı olan bir prensiptir (çağırdığınız sınıflar ve yöntemler ve nasıl çalışmasını beklediğiniz).

Amaç kaliteli yazılım yazmaktır. Bu niteliklerden biri genişletilebilirliktir. Bu, mümkün olduğunca az mevcut sınıfla sınırlı olma eğiliminde olan bu değişikliklerle kod eklemek, kaldırmak ve değiştirmek kolay olduğu anlamına gelir. Yeni kod eklemek mevcut kodu değiştirmekten daha az risklidir , bu nedenle Açık-Kapalı yapmak iyi bir şeydir. Ama tam olarak hangi koddan bahsediyoruz? Bir sınıfa mevcut yöntemleri değiştirmek yerine yeni yöntemler ekleyebileceğiniz zaman OC'yi ihlal etme suçu çok daha azdır.

OC fraktaldır . Tasarımınızın tüm derinliklerinde elmalar. Herkes bunun sadece sınıf düzeyinde uygulandığını varsayar. Ancak yöntem düzeyinde veya montaj seviyesinde eşit olarak uygulanabilir.

Uygun seviyede OC'nin çok sık ihlali, belki de yeniden düzenleme zamanı olduğunu göstermektedir . "Uygun seviye", genel tasarımınızla ilgili her şeye sahip bir yargılama çağrısıdır.

Açık-Kapalı'yı takip etmek kelimenin tam anlamıyla sınıfların patlayacağı anlamına gelir. Gereksiz yere (büyük "I") arayüzler oluşturacaksınız. Sınıflara yayılmış işlevsellik parçalarına sahip olacaksınız ve daha sonra hepsini birbirine bağlamak için çok daha fazla kod yazmanız gerekiyor. Bir noktada, orijinal sınıfı değiştirmenin daha iyi olacağı konusunda şaşıracaksınız.


2
"Bir sınıfa mevcut yöntemleri değiştirmek zorunda kalmak yerine yeni yöntemler ekleyebildiğinizde OC'yi ihlal etme suçu çok daha azdır.": Anladığım kadarıyla, yeni yöntemler eklemek OC ilkesini (uzantıya açık) ihlal etmiyor . Sorun, iyi tanımlanmış bir arabirim uygulayan ve bu nedenle zaten iyi tanımlanmış semantiğe sahip (değiştirme için kapalı) mevcut yöntemleri değiştirmektir. Prensip olarak, yeniden düzenleme semantiği değiştirmez, bu yüzden görebildiğim tek risk zaten kararlı ve iyi test edilmiş kodda hatalar getirmektir.
Giorgio

1
İşte uzantıya açık olan CodeReview yanıtı . Bu sınıf tasarımı genişletilebilir. Buna karşılık, bir yöntem eklemek sınıfı değiştirmektir.
radarbob

Yeni yöntemler eklemek OCP'yi değil, LSP'yi ihlal eder.
Tulains Córdova

1
Yeni yöntemler eklemek LSP'yi ihlal etmez . Bir yöntem eklerseniz, yeni bir arayüz eklediniz @ TulainsCórdova
RubberDuck

6

Açık-Kapalı prensibi, TDD daha yaygın olmadan önce ortaya çıkan bir prensip gibi görünmektedir. Fikir, kodu yeniden düzenlemek için riskli olduğu için bir şeyi kırabilirsiniz, böylece mevcut kodu olduğu gibi bırakmak ve sadece eklemek daha güvenlidir. Testlerin yokluğunda bu mantıklı. Bu yaklaşımın dezavantajı kod atrofisidir. Bir sınıfı yeniden düzenlemek yerine her genişlettiğinizde ekstra bir katman elde edersiniz. Sadece kodu üste vidalıyorsunuz. Ne zaman daha fazla kod eklerseniz, tekrarlama şansınız da artar. Hayal etmek; benim kod temeli kullanmak istediğiniz bir hizmet var, ben ne istediğimi yok bu yüzden onu genişletmek ve yeni işlevselliği dahil etmek için yeni bir sınıf oluşturmak bulmak. Başka bir geliştirici daha sonra gelir ve aynı hizmeti kullanmak ister. Ne yazık ki, yapmıyorlar t Genişletilmiş sürümümün mevcut olduğunu fark etmem. Orijinal uygulamaya karşı kodlama yapıyorlar, ancak kodladığım özelliklerden birine de ihtiyaçları var. Sürümümü kullanmak yerine artık uygulamayı genişletiyor ve yeni özelliği ekliyorlar. Şimdi 3 sınıfımız var, orijinal olanı ve bazı yinelenen işlevlere sahip iki yeni sürümü var. Açık / kapalı prensibini izleyin ve bu çoğaltma, gereksiz bir şekilde karmaşık bir kod tabanına yol açan projenin yaşam süresi boyunca birikmeye devam edecektir.

İyi test edilmiş bir sistemde, bu kod atrofisine maruz kalmanıza gerek yoktur, kodunuzu sürekli olarak yeni kodu takmak yerine tasarımınızın yeni gereksinimleri özümsemesine izin vererek güvenle yeniden düzenleyebilirsiniz. Bu gelişme tarzına acil tasarım denir ve yavaş yavaş toplanmaktan ziyade tüm yaşamları boyunca iyi durumda kalabilen kod tabanlarına yol açar.


1
Açık-kapalı prensibin ya da TDD'nin savunucusu değilim (onları icat etmediğim için). Beni şaşırtan şey, birisinin aynı zamanda açık ve kapalı prensibi VE yeniden düzenleme ve TDD kullanımını önermesiydi. Bu benim için çelişkili görünüyordu ve bu yüzden tüm bu yönergeleri nasıl tutarlı bir sürece dönüştürmeyi anlamaya çalışıyordum.
Giorgio

"Fikir kodu yeniden düzenlemek için riskli olması çünkü bir şey kırmak olabilir, bu yüzden mevcut kodu olduğu gibi bırakmak ve sadece eklemek daha güvenli.": Aslında ben bu şekilde görmüyorum. Fikir, yerine koyabileceğiniz veya genişletebileceğiniz küçük, bağımsız birimlere sahip olmaktır (böylece yazılımın gelişmesine izin verir), ancak her birime iyice test edildikten sonra dokunmamanız gerekir.
Giorgio

Sınıfın yalnızca kod tabanınızda kullanılmayacağını düşünmelisiniz. Yazdığınız kütüphane başka bir projede kullanılabilir. Bu yüzden OCP önemlidir. Ayrıca, genişleyen bir sınıfı ihtiyaç duyduğu işlevsellikle bilmeyen yeni bir programcı, bir tasarım problemi değil, bir iletişim / dokümantasyon problemidir.
Tulains Córdova

@ TulainsCórdova uygulama kodunda bu ilgili değil. Kütüphane kodu için, anlamsal sürüm oluşturmanın, kırılma değişikliklerini iletmek için daha uygun olduğunu iddia ediyorum.
opsb

1
@ TulainsCórdova kütüphane kodu API kararlılığı çok daha önemlidir çünkü istemci kodunu test etmek mümkün değildir. Uygulama kodu ile test kapsamınız herhangi bir kırılma anında size bildirilecektir. Başka bir deyişle, uygulama kodu risksiz bir şekilde değişiklik yapabilirken kütüphane kodu, sabit bir API koruyarak ve semantik versiyonlama kullanarak kırılma sinyalleri vererek riski yönetmelidir
opsb

6

Layman'ın sözleriyle:

A. O / C ilkesi, uzmanlığın , özel ihtiyaçları karşılamak için bir sınıfı değiştirerek değil, genişletilerek yapılması gerektiği anlamına gelir .

B. Eksik (uzmanlaşmamış) işlevsellik eklemek, tasarımın tamamlanmadığı ve sözleşmeyi ihlal etmeden açık bir şekilde temel sınıfa eklemeniz gerektiği anlamına gelir. Bunun prensibi ihlal etmediğini düşünüyorum.

C. Yeniden düzenleme ilkeyi ihlal etmez.

Bir tasarım , üretimde bir süre sonra olgunlaştığında :

  • Bunu yapmak için çok az neden olmalı (B noktası), zamanla sıfıra eğilimli.
  • (C noktası) daha seyrek olmasına rağmen her zaman mümkün olacaktır.
  • Tüm yeni işlevselliklerin uzmanlaşma olduğu varsayılır, yani sınıflar genişletilmelidir (devralınmalıdır) (A noktası).

Açık / kapalı prensibi çok yanlış anlaşılmıştır. A ve B puanlarınız tam olarak doğru.
gnasher729

1

Bana göre, Açık-Kapalı Prensibi zor ve hızlı bir kural değil, bir rehberdir.

İlkenin açık kısmı ile ilgili olarak, Java'daki son sınıflar ve özel olarak bildirilen tüm kurucularla C ++ sınıfları açık-kapalı ilkesinin açık kısmını ihlal eder. Son sınıflar için iyi katı kullanım durumları vardır (not: katı, katı değil). Genişletilebilirlik için tasarım önemlidir. Bununla birlikte, bu büyük bir öngörü ve çaba gerektirir ve her zaman YAGNI'yi (buna ihtiyacınız olmayacak) ihlal etme ve spekülatif genelliğin kod kokusunu enjekte etme çizgisini süpürüyorsunuz. Önemli yazılım bileşenleri uzantıya açık mı olmalı? Evet. Herşey? Hayır. Bu kendi başına spekülatif genelliktir.

Kapalı kısım ile ilgili olarak, bazı ürünlerin sürüm 2.0'dan 2.1 ila 2.2 ila 2.3'e giderken, davranışı değiştirmemek iyi bir fikirdir. Kullanıcılar her küçük sürüm kendi kod etiketini bozduğunda hoşlanmıyor. Bununla birlikte, yol boyunca, sürüm 2.0'daki ilk uygulamanın temelde kırıldığını veya ilk tasarımı sınırlayan dış kısıtlamaların artık geçerli olmadığını bulur. Sırıtıyor ve taşıyor ve 3.0 sürümünde bu tasarımı koruyor musunuz, yoksa 3.0'ı geriye dönük olarak uyumlu kılıyor musunuz? Geriye dönük uyumluluk büyük bir kısıtlama olabilir. Başlıca serbest bırakma sınırları, geriye dönük uyumluluğu bozmanın kabul edilebilir olduğu yerlerdir. Bunu yapmanın kullanıcılarınızı rahatsız edebileceğine dikkat etmeniz gerekir. Geçmişle olan bu kopuşun neden gerekli olduğu için iyi bir durum olmalı.


0

Yeniden düzenleme, tanım gereği, davranış değiştirmeden kod yapısını değiştirmektedir. Refactor olduğunuzda yeni özellikler eklemezsiniz.

Açılış Prensibi için örnek olarak yaptıklarınız Kulağa hoş geliyor. Bu ilke, mevcut kodun yeni özelliklerle genişletilmesiyle ilgilidir.

Ancak, bu yanıtı yanlış anlamayın. Sadece büyük veri parçaları için sadece özellikler yapmanız veya yeniden düzenleme yapmanız gerektiğini ima etmiyorum. Programlamanın en yaygın yolu, hemen biraz yeniden düzenleme yapmaktan biraz daha fazla özellik yapmaktır (herhangi bir davranışı değiştirmediğinizden emin olmak için elbette testlerle birlikte). Karmaşık yeniden düzenleme, "büyük" yeniden düzenleme anlamına gelmez, karmaşık ve iyi düşünülmüş yeniden düzenleme tekniklerinin uygulanması anlamına gelir.

SOLID ilkeleri hakkında. Yazılım geliştirme için gerçekten iyi yönergelerdir, ancak körü körüne izlenecek dini kurallar değildir. Bazen, birçok kez, ikinci ve üçüncü ve n. Bir özelliği ekledikten sonra, ilk tasarımınızın Open-Close'a saygı duysa bile, diğer ilkelere veya yazılım gereksinimlerine uymadığını fark edersiniz. Daha karmaşık değişikliklerin yapılması gerektiğinde bir tasarımın ve yazılımın gelişiminde noktalar vardır. Asıl mesele, bu sorunları en kısa zamanda bulmak ve gerçekleştirmek ve mümkün olduğunca yeniden düzenleme tekniklerini uygulamaktır.

Mükemmel tasarım diye bir şey yoktur. Mevcut tüm ilke veya kalıplara saygı duyan ve saygı duyacak böyle bir tasarım yoktur. Bu ütopyayı kodlar.

Umarım bu cevap ikileminizde size yardımcı olmuştur. Gerekirse açıklama istemekten çekinmeyin.


1
"Yani refactor zaman, yeni özellikler eklemek yok.": Ama ben test edilmiş bir yazılım parçası hataları tanıtmak olabilir.
Giorgio

"Bazen, birçok kez, ikinci ve üçüncü ve n'inci bir özellik ekledikten sonra, ilk tasarımınızın Open-Close'a saygı duysa bile, diğer ilkelere veya yazılım gereksinimlerine uymadığını fark edersiniz.": İşte o zaman yeni bir uygulama yazmaya başlayın Bve bu hazır olduğunda eski uygulamayı Ayeni uygulama ile değiştirin B(arayüzlerin bir kullanımıdır). A's kodu' s kodu için bir temel olarak hizmet verebilir Bve sonra Bgeliştirme sırasında kod üzerinde yeniden düzenleme kullanabilirsiniz , ancak zaten test Akod dondurulmuş kalması gerektiğini düşünüyorum .
Giorgio

@Giorgio Eğer planı ayrı zaman olabilir en neden testler (hatta daha iyi TDD do) yazmanızı böcekleri tanıtmak. Refactor için en güvenli yol, çalıştığını bildiğinizde kodu değiştirmektir. Bunu geçen bir dizi testle biliyorsunuz. Üretim kodunuzu değiştirdikten sonra, testlerin yine de geçmesi gerekir, bu yüzden bir hata yapmadığınızı bilirsiniz. Ve unutmayın, testler üretim kodu kadar önemlidir, bu yüzden üretim kurallarına aynı kuralı uygular ve onları temiz tutar ve periyodik ve sık sık yeniden düzenler.
Patkos Csaba

@Giorgio Kod bir evrim Bolarak kod üzerine kuruluysa , ne zaman piyasaya sürüldüğünde kaldırılmalı ve bir daha kullanılmamalıdır. Daha önce kullanan müşteriler , arayüzün değiştirilmemesi nedeniyle değişikliği bilmeden kullanacaklar (belki biraz burada AABAABI
Liskov

Evet, aklımda olan buydu: geçerli (iyi test edilmiş) bir yedek alana kadar çalışma kodunu atmayın.
Giorgio

-1

Anladığım kadarıyla - mevcut sınıfa yeni yöntemler eklerseniz OCP'yi kırmaz. ancak im bit Sınıfta yeni değişkenlerin eklenmesi ile karıştırılır. Ancak mevcut yöntemdeki mevcut yöntemi ve parametreleri değiştirirseniz, OCP'yi kesinlikle kesecektir, çünkü yöntemi [Gereksinim değiştiğinde] kasıtlı olarak değiştirirsek kod zaten test edilir ve geçirilirse sorun olacaktır.

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.