Eşit derecede optimal olmayan tasarımlarla sonsuz bir şekilde tekrarlamayı nasıl önlersiniz?


10

Muhtemelen birçokları gibi, genellikle kendimi tasarım problemleri ile baş ağrısına koşarken buluyorum, örneğin, sezgisel olarak problemlere uygun görünen ve istenen faydaları olan bazı tasarım desenleri / yaklaşımları var. Çoğunlukla patern / yaklaşımın, bir çeşit çalışma olmadan uygulanmasını zorlaştıran ve sonrasında paternin / yaklaşımın faydasını reddeden bazı uyarılar vardır. Pek çok model / yaklaşımla yinelemeyi çok kolay bir şekilde bitirebilirim çünkü tahmin edilebileceği gibi neredeyse hepsinin, kolay bir çözümün olmadığı gerçek dünya durumlarında çok önemli uyarılar var.


Misal:

Size son zamanlarda karşılaştığım gerçek bir örneğe dayanarak varsayımsal bir örnek vereceğim. Diyelim ki kompozisyonu kalıtım üzerinde kullanmak istiyorum çünkü kalıtım hiyerarşileri geçmişte kodun ölçeklenebilirliğini engellemişti. Ben kodu refactor olabilir ama sonra önlemek için girişimlere rağmen, üst sınıf / baseclass sadece alt sınıf işlevselliği çağırmak için gereken bazı bağlamlar olduğunu bulabilirsiniz.

Bir sonraki en iyi yaklaşım, yarı sınıfın davranışları devredebilmesi veya alt sınıfın üst sınıf olaylarını gözlemleyebilmesi için yarım delege / gözlemci örüntüsü ve yarım kompozisyon örüntüsü uygulamak gibi görünmektedir. Daha sonra sınıf daha az ölçeklenebilir ve sürdürülebilirdir, çünkü nasıl genişletilmesi gerektiği belirsizdir, ayrıca mevcut dinleyicileri / delegeleri genişletmek de zordur. Ayrıca bilgi iyi gizlenmez, çünkü bir kişi üst sınıfı nasıl genişleteceğinizi görmek için uygulamayı bilmeye ihtiyaç duyar (yorumları çok yoğun kullanmadığınız sürece).

Bundan sonra, sadece gözlemcileri veya delegeleri tamamen ağır yaklaşımları karıştırmakla birlikte gelen dezavantajlardan kurtulmak için kullanmayı tercih edebilirim. Ancak bu kendi sorunları ile birlikte gelir. Örneğin, pratikte her davranış için gözlemcilere / delegelere ihtiyaç duyana kadar artan sayıda davranış için gözlemcilere veya delegelere ihtiyacım olduğunu fark edebilirim. Bir seçenek, tüm davranışlar için sadece büyük bir dinleyici / delege sahip olmak olabilir, ancak uygulama sınıfı çok sayıda boş yöntem vb.

Sonra başka bir yaklaşım deneyebilirim ama bununla ilgili çok fazla sorun var. Sonra bir sonraki ve bir sonraki vb.


Bu yinelemeli süreç, her yaklaşımın diğerlerinden daha fazla problemi olduğu zaman çok zorlaşır ve bir tür tasarım karar felçine yol açar . Hangi tasarım modeli veya yaklaşımı kullanılırsa kullanılsın, kodun eşit derecede sorunlu olacağını kabul etmek de zordur. Bu duruma düşersem, sorunun kendisinin yeniden düşünülmesi gerektiği anlamına mı gelir? Diğerleri bu durumla karşılaştıklarında ne yaparlar?

Düzenleme: Sorunu temizlemek istediğim bir dizi yorum var gibi görünüyor:

  • OOP'yi tamamen sorudan çıkardım çünkü aslında OOP'ye özgü olmadığı ortaya çıktı, ayrıca OOP hakkında geçerken yaptığım bazı yorumları yanlış yorumlamak çok kolay.
  • Bazıları yinelemeli bir yaklaşım benimsemeli ve farklı kalıplar denemem gerektiğini ya da çalışmayı bıraktığında bir deseni atmam gerektiğini iddia etti. İlk etapta bahsetmek istediğim süreç bu. Bunun örnekten açık olduğunu düşündüm ama daha açık hale getirebilirdim, bu yüzden bunu yapmak için soruyu düzenledim.

3
"OO felsefesine abone olmayın". Bu bir araç, önemli bir yaşam kararı değil. Yardımcı olduğunda kullanın ve yardımcı olmadığında kullanmayın.
user253751

Belirli kalıplar açısından düşünmeye devam ederseniz, belki de C'de orta derecede karmaşık bir proje yazmayı deneyin, bu kalıplar olmadan ne kadar yapabileceğinizi deneyimlemek ilginç olacaktır.
user253751

2
Ah C'nin kalıpları var. Onlar sadece çok farklı kalıplardır. :)
candied_orange

Düzenlemedeki bu yanlış yorumların çoğunu temizledim
Jonathan

Bu sorunların bir kez ortaya çıkması normaldir. Bunların sık sık meydana gelmesi söz konusu olmamalıdır. Büyük olasılıkla, sorun için yanlış programlama paradigmasını kullanıyorsunuz veya tasarımlarınız yanlış yerlerde paradigmaların bir karışımı.
Dunk

Yanıtlar:


8

Böyle sert bir karara vardığımda kendime genellikle üç soru soruyorum:

  1. Mevcut tüm çözümlerin artıları ve eksileri nelerdir?

  2. Henüz düşünmediğim bir çözüm var mı?

  3. En önemlisi:
    Gereksinimlerim tam olarak nedir? Kağıt üzerindeki gereksinimler değil, gerçek temel gereksinimler?
    Sorunu basit bir şekilde yeniden biçimlendirebilir / gereksinimlerini değiştirebilir miyim, böylece basit, basit bir çözüme izin verebilir mi?
    Verilerimi farklı bir şekilde temsil edebilir miyim, böylece bu kadar basit ve basit bir çözüme izin verir mi?

    Bu algılanan sorunun temelleri ile ilgili sorulardır. Aslında yanlış problemi çözmeye çalışıyorsunuz. Sorununuz, genel durumdan çok daha basit bir çözüme izin veren özel gereksinimlere sahip olabilir. Sorununuzu formülasyonunuzu sorgulayın!

Devam etmeden önce her üç soruyu da sert düşünmenin çok önemli olduğunu düşünüyorum. Bir yürüyüşe çıkın, ofisinize ayak uydurun, bu soruların cevaplarını gerçekten kısmak için ne gerekiyorsa yapın. Ancak, bu soruları cevaplamak uygunsuz zaman almamalıdır. Uygun süreler 15 dakikadan bir haftaya kadar değişebilir, daha önce bulduğunuz çözümlerin kötülüğüne ve bütüne olan etkisine bağlıdır.

Bu yaklaşımın değeri, bazen şaşırtıcı derecede iyi çözümler bulabilmenizdir. Zarif çözümler. Bu üç soruyu cevaplamak için yatırım yaptığınız zamana değecek çözümler. Ve hemen bir sonraki yinelemeye girerseniz, bu çözümü bulamazsınız.

Tabii ki, bazen iyi bir çözüm yoktur. Bu durumda, birinci soruya verdiğiniz cevaplarla sıkışıp kalırsınız ve iyilik en azından kötüdür. Bu durumda, bu soruları yanıtlamak için zaman ayırmanın değeri, muhtemelen başarısız olması gereken tekrarlardan kaçınmanızdır. Sadece uygun bir süre içinde kodlamaya geri döndüğünüzden emin olun.


Bunu cevap olarak iyi işaretleyebilirim, bu benim için en mantıklı ve sorunun kendisinin yeniden değerlendirilmesi konusunda bir fikir birliği var gibi görünüyor.
Jonathan

Ayrıca, durumu değerlendirmek için bir çeşit gevşek prosedür var, bu yüzden adımları nasıl bozduğunuzu seviyorum.
Jonathan

OP, kod çözümünün mekaniğinde sıkışıp kaldığınızı görüyorum, bu yüzden evet "yanıtı da işaretleyebilirsiniz". Yazdığımız en iyi kod, gereksinimlerin, türetilmiş gereksinimlerin, sınıf diyagramlarının, sınıf etkileşimlerinin vb. 'tasarımda çok fazla zaman harcıyoruz', "acele edin ve kodlama alın!", "bu çok fazla sınıf!", vb. Bir kez başladık, kodlama bir zevkti - eğlenceden daha fazlası. Nesnel olarak tüm proje için en iyi kod buydu.
radarbob

13

Öncelikle ilk şeyler - kalıplar, OO tasarımı değil, tasarımın tamamı değil, yararlı soyutlamalar.

İkincisi - modern OO her şeyin bir nesne olmadığını bilecek kadar zekidir. Bazen düz eski işlevler, hatta bazı zorunlu stil komut dosyaları kullanmak, bazı sorunlar için daha iyi bir çözüm getirecektir.

Şimdi şeylerin etine:

Bu, her yaklaşımın diğerlerinden daha fazla problemi olduğu zaman çok zorlaşır.

Neden? Bir dizi benzer seçeneğiniz olduğunda, kararınız daha kolay olmalı! "Yanlış" seçeneğini seçerek fazla kaybetmezsiniz. Ve gerçekten, kod sabit değil. Bir şey deneyin, iyi olup olmadığına bakın. Tekrar ediyorum .

Hangi tasarım deseni veya yaklaşımı kullanılırsa kullanılsın, kodun çok sorunlu olacağını kabul etmek de zordur.

Sert fındık. Zor problemler - gerçek matematiksel zor problemler sadece zor. Muhtemelen zor. Onlar için tam anlamıyla iyi bir çözüm yok. Ve ortaya çıkıyor, kolay problemler gerçekten değerli değil.

Ancak dikkatli olun. Çoğu zaman insanların iyi seçeneklerden dolayı hayal kırıklığına uğradıklarını gördüm, çünkü soruna belirli bir şekilde bakmaya sıkıştılar veya sorumluluklarını eldeki soruna doğal olmayan bir şekilde kestiler. "İyi bir seçenek yok" yaklaşımınızda temelde yanlış olan bir şey olabilir.

Bu "motivasyon kaybı" ile sonuçlanır çünkü "temiz" kod bazen bir seçenek olmaktan çıkar.

Mükemmel, iyinin düşmanıdır. Çalışmak için bir şeyler alın, sonra yeniden düzenleyin.

Bu sorunu en aza indirmeye yardımcı olabilecek tasarım yaklaşımları var mı? Böyle bir durumda ne yapılması gerektiğine dair kabul edilmiş bir uygulama var mı?

Bahsettiğim gibi, yinelemeli gelişim genellikle bu sorunu en aza indirir. Bir şey işe yaradığında, sorunu çözmek için sizi daha iyi bir konuma getiren soruna daha aşina olursunuz. Sen gelmez bazı soyut tasarım, bakmak fiili koduna sahip ve değerlendirmek görünmek hakkı.


Sadece düzenlemedeki bazı yanlış yorumları temizlediğimi söylemeliyim diye düşündüm. Genellikle "işe koyul" ve refactor yaklaşımını yaparım. Ancak, çoğu zaman bu benim deneyimimde çok fazla teknik borca ​​yol açar. Örneğin, sadece bir şeyi çalışır hale getirirsem, ancak kendim veya diğerleri bunun üzerine inşa edilirse, bu şeylerin bazıları kaçınılmaz bağımlılıklara sahip olabilir ve bu da bir ton yeniden düzenleme gerektirebilir. Elbette bunu her zaman önceden bilemezsiniz. Ancak, yaklaşımın kusurlu olduğunu zaten biliyorsanız, kodun üzerine inşa edilmeden önce işe koyulmalı ve tekrarlanır bir şekilde yeniden gözden geçirilmelidir mi?
Jonathan

@Jonathan - tüm tasarımlar bir dizi ticarettir. Evet, tasarım kusurluysa ve onu iyileştirmek için net bir yolunuz varsa hemen tekrar etmelisiniz. Net bir gelişme yoksa, lanet olası.
Telastyn

"Sorumluluklarını eldeki problem için doğal olmayan bir şekilde kestiler. İyi bir seçenek, yaklaşımınızda temelde yanlış olan bir şey olduğu kokusu olamaz." Bunun üzerine bahse girerim. Bazı geliştiriciler OP'nin tanımladığı sorunlarla hiç karşılaşmazlar ve diğerleri bunu oldukça sık yapar. Genellikle, orijinal geliştirici tarafından poz verildiğinde çözümü görmek kolay değildir, çünkü tasarımı zaten sorunu çerçevelediği şekilde önyargılar. Bazen oldukça açık bir çözüm bulmanın tek yolu, tasarım gereksinimlerine kadar baştan başlamaktır.
Smaç

8

Açıkladığınız durum aşağıdan yukarıya bir yaklaşıma benziyor. Bir yaprak alırsınız, düzeltmeye çalışırsınız ve kendisinin de başka bir dala bağlı olan bir dalı olduğunu öğrenirsiniz.

Bir lastikle başlayan bir araba inşa etmeye çalışmak gibi.

İhtiyacınız olan şey geri adım atmak ve daha büyük resme bakmak. Bu yaprak genel tasarımda nasıl oturuyor? Bu hala güncel ve doğru mu?

Sıfırdan tasarlayıp uygularsanız modül nasıl görünürdü? Şu anki uygulamanız bu "ideal" den ne kadar uzakta.

Böylece neye doğru çalışacağınıza dair daha büyük bir resminiz olur. (Veya çok fazla iş olduğuna karar verirseniz, sorunların ne olduğu).


4

Örneğin, tipik olarak daha büyük eski kod parçalarında ve "çok büyük" yeniden düzenleme yapmaya çalıştığınızda ortaya çıkan bir durumu açıklar.

Bu durum için size verebileceğim en iyi tavsiye:

  • tek bir büyük patlamada ana hedefinize ulaşmaya çalışmayın ,

  • kodunuzu daha küçük adımlarla nasıl geliştireceğinizi öğrenin!

Tabii ki, bu yapılmaktan daha kolay, peki bunu gerçekte nasıl başarabilirim? Uygulamaya ve deneyime ihtiyacınız var, bu duruma büyük ölçüde bağlı ve her davaya uyan "bunu yap ya da bunu yap" diyen zor ve hızlı bir kural yok. Ama varsayımsal örneğinizi kullanayım. "miras üzerinden kompozisyon" bir ya hep ya hiç tasarım hedefi değil, birkaç küçük adımda başarmak için mükemmel bir adaydır.

Diyelim ki, "miras üzerinden kompozisyon" davanın doğru aracı. Bunun mantıklı bir hedef olduğuna dair bazı göstergeler olmalı, aksi takdirde bunu seçmezdiniz. Öyleyse, üst sınıfta alt sınıflardan sadece "çağrılan" bir çok işlevsellik olduğunu varsayalım, bu nedenle bu işlevsellik bu üst sınıfta kalmamak için bir adaydır.

Üst sınıfı alt sınıflardan hemen kaldıramayacağınızı fark ederseniz, ilk önce üst sınıfı yukarıda belirtilen işlevselliği kapsayan daha küçük bileşenlere yeniden düzenleyerek başlayabilirsiniz. En düşük asılı meyvelerle başlayın, önce bazı basit bileşenleri çıkarın, bu da üst sınıfınızı daha az karmaşık hale getirecektir. Üst sınıf ne kadar küçük olursa, ek yeniden düzenleme işlemleri de o kadar kolay olur. Bu bileşenleri alt sınıfların yanı sıra üst sınıftan da kullanın.

Eğer şanslıysanız, üst sınıftaki kalan kod bu süreç boyunca o kadar basit olacaktır ki üst sınıfı başka herhangi bir sorun yaşamadan alt sınıflardan kaldırabilirsiniz. Veya, üst sınıfı korumanın artık bir sorun olmadığını fark edeceksiniz, çünkü kodu yeterince miras almadan yeniden kullanmak istediğiniz bileşenlere zaten çıkardınız.

Nereden başlayacağınızdan emin değilseniz, bir yeniden düzenlemenin basit olup olmayacağını bilmiyorsanız, bazen en iyi yaklaşım sıfırdan yeniden düzenleme yapmaktır .

Tabii ki, gerçek durumunuz daha karmaşık olabilir. Öyleyse öğrenin, deneyim toplayın ve sabırlı olun, bunu doğru yapmak yıllar alır. Burada önerebileceğim iki kitap var, belki onları faydalı buluyorsun:

  • Üstlenmeden Fowler tarafından: tam bir katalog anlatmaktadır çok küçük refactorings.

  • Feathers'ın eski koduyla etkili bir şekilde çalışmak : kötü tasarlanmış kodun büyük parçalarıyla nasıl başa çıkılacağı ve daha küçük adımlarla daha test edilebilir hale getirilmesi için mükemmel tavsiyeler verir


1
Bu da çok faydalı. Küçük adım adım veya çizik yeniden düzenleme güzel bir fikirdir, çünkü daha sonra çok fazla engellemeden diğer çalışmalarla birlikte aşamalı olarak tamamlanabilecek bir şey haline gelir. Keşke birden fazla yanıtı onaylayabilseydim!
Jonathan

1

Bazen en iyi iki tasarım prensibi KISS * ve YAGNI ** 'dir. Bilinen her tasarım desenini "Merhaba dünya!"

 * Keep It Simple, Stupid
 ** You Ain't Gonna Need It

Soru güncellemesinden sonra düzenleyin (ve Pieter B'nin söylediklerini bir ölçüde yansıtın):

Bazen erken bir mimari karar alırsınız, bu da onu uygulamaya çalıştığınızda her türlü çirkinliğe yol açan belirli bir tasarıma götürür. Ne yazık ki, bu noktada, "uygun" çözüm geri çekilip bu pozisyona nasıl geldiğiniz üzerinde çalışmaktır. Cevabı henüz göremiyorsanız, görene kadar geri adım atmaya devam edin.

Ancak bunu yapmak için yapılan iş orantısızsa, soruna en az çirkin geçici çözümü bulmak pragmatik bir karar alır.


Düzenlemede bunlardan bazılarını temizledim, ancak genel olarak, mevcut basit bir çözümün bulunmadığı sorunlara başvuruyorum.
Jonathan

Ah güzel evet geri adım atma ve sorunu yeniden değerlendirme konusunda bir fikir birliği var gibi görünüyor. Bu iyi bir fikir.
Jonathan

1

Bu durumdayken yaptığım ilk şey durmak. Başka bir soruna geçiyorum ve bir süre bunun üzerinde çalışıyorum. Belki bir saat, belki bir gün, belki daha fazla. Bu her zaman bir seçenek değildir, ancak bilinçli beynim daha üretken bir şey yaparken bilinçaltım şeyler üzerinde çalışacaktır. Sonunda, taze gözlerle geri dönüp tekrar deniyorum.

Yaptığım başka bir şey benden daha akıllı birine sormak. Bu, Stack Exchange'de soru sorma, konuyla ilgili web'de bir makale okuma veya bu alanda daha fazla deneyime sahip bir meslektaşınıza soru sorma şeklinde olabilir. Çoğu zaman doğru yaklaşım olduğunu düşündüğüm yöntem yapmaya çalıştığım şey için tamamen yanlış çıkıyor. Sorunun bazı yönlerini yanlış tanımladım ve aslında düşündüğüm kalıba uymuyor. Bu olduğunda, bir başkasının "Bilirsiniz, bu daha çok benziyor ..." demesini sağlamak büyük bir yardımcı olabilir.

Yukarıdakiler, itiraf yoluyla tasarım veya hata ayıklama ile ilgilidir. Bir meslektaşınıza gidip "Size yaşadığım sorunu anlatacağım ve sonra size sahip olduğum çözümleri anlatacağım. Her yaklaşımdaki sorunları işaret edip diğer yaklaşımları önereceğim. ." Genellikle diğer kişi konuşmadan önce, açıkladığım gibi, diğerlerine eşit görünen bir yolun aslında düşündüğümden çok daha iyi veya daha kötü olduğunu fark etmeye başladım. Ortaya çıkan konuşma ya bu algıyı güçlendirebilir ya da düşünmediğim yeni şeylere işaret edebilir.

Yani TL; DR: Bir ara verin, zorlamayın, yardım isteyin.

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.