Yanıltıcı kod çoğaltma


56

Genel içgüdü, kodda gördüğünüz kod çoğaltmayı kaldırmaktır. Ancak, kendimi çoğaltmanın aldatıcı olduğu bir durumda buldum .

Durumu daha ayrıntılı olarak açıklamak için: Bir web uygulaması geliştiriyorum ve çoğu görünüm temelde aynı - kullanıcının kaydırıp seçebileceği öğelerin bir listesini, seçilen öğeleri içeren ikinci bir listeyi ve "Kaydet "Yeni listeyi kaydetmek için" düğmesine basın.

Bana problemin kolay olduğu görünüyordu. Ancak, her bir görüntünün kendi tuhaflıkları vardır - bazen bir şeyi yeniden hesaplamanız gerekir, bazen bazı ek verileri vb. Saklamanız gerekir. Bunlar, ana mantık koduna geri çağırma kancaları ekleyerek çözdüm.

Orada o kadar çok Temelde bütün işlevselliği için geri aramalar sağlamanız gerekir, çünkü daha az sürdürülebilir hale gelmektedir görünümler arasında dakikalık farklar ve ana mantık geri arama çağırmaları büyük dizisine benzemeye başlar. Sonunda hiçbir zaman veya kod kaydetmiyorum, çünkü her görüntünün kendi kodunun yürütülmesi - tümü geri aramalarda.

Sorunlar:

  • farklar öyle ki öyle ki kod bütün görünümlerde neredeyse tamamen aynı görünüyor.
  • o kadar çok fark var ki, ayrıntılara baktığınızda, kodlama biraz benzemiyor

Bu durumu nasıl ele almalıyım?
Çekirdek mantığın tamamen geri arama çağrılarından oluşması iyi bir çözüm mü?
Yoksa kodu kopyalayıp geri arama kodunun karmaşıklığını düşürmeyi tercih etmeli miyim?


38
Çoğunlukla çoğaltmanın başlamasına izin vermek yararlı olur. Birkaç örneğim olduğunda, neyin ortak neyin ortak olmadığını görmek ve ortak parçaları paylaşmanın bir yolunu bulmak çok daha kolay.
Winston Ewert,

7
Çok iyi bir soru - dikkate alınması gereken bir şey, yalnızca kodun fiziksel olarak çoğaltılması değil, anlamsal çoğaltmadır. Kodun bir parçasındaki bir değişiklik mutlaka aynı değişimin diğerleri arasında çoğaltılacağı anlamına gelirse, o zaman muhtemelen bu kısım yeniden düzenleme veya soyutlama için bir adaydır. Bazen kendinizi gerçekten tuzağa düşürdüğünüz noktaya göre normalleştirebilirsiniz, bu yüzden kopyalamayı semantik olarak farklı olarak değerlendirmenin pratik sonuçlarını da göz önünde bulundurabilirim.
Ant P

Unutmayın, yalnızca aynı şeyi yapan kodu yeniden kullanabilirsiniz. Uygulamanız farklı ekranlarda farklı şeyler yapıyorsa, farklı geri aramalar gerektirir. Hayır eğer, ve, veya bu konuda ama.
corsiKa

13
Bu konuda kişisel kurallarım: Kodda bir yerde değişiklik yaparsam, başka yerde de aynı değişikliği yapmazsam hata mı olur? Eğer öyleyse, bu kötü bir çoğaltmadır. Emin değilseniz, hangisi için daha okunaklı olana gidin. Örneğinizde davranıştaki farklılıklar kasıtlıdır ve böcek sayılmaz, bu nedenle bazı kopyalamalar iyidir.
Ixrec,

Açı Yönelimli Programlama hakkında okumak isteyebilirsiniz.
Ben Jackson

Yanıtlar:


53

Sonuçta, kopyalamayı ortadan kaldırmak için benzer bir kodu bir araya getirip getirmeyeceğinize dair bir yargılama yapmanız gerekir .

Her zaman ezbere uyulması gereken kurallar olarak “Kendini tekrar etme” gibi prensipler alma konusunda talihsiz bir eğilim var gibi görünüyor. Aslında, bunlar evrensel kurallar değil, iyi tasarım hakkında düşünmenize ve geliştirmenize yardımcı olması gereken kurallardır.

Hayattaki her şey gibi, faydaları maliyetlere karşı göz önünde bulundurmalısınız. Ne kadar çoğaltılmış kod kaldırılacak? Kod kaç kez tekrarlanıyor? Daha genel bir tasarım yazmak için ne kadar çaba sarf edilecektir? Gelecekte kodu ne kadar geliştirme ihtimaliniz var? Ve bunun gibi.

Özel kodunuzu bilmeden, bu açık değildir. Belki de, çoğaltmanın kaldırılması için daha zarif bir yol vardır (LindaJeanne tarafından önerildiği gibi). Veya, belki de soyutlamayı garanti etmek için yeterli gerçek tekrarı yoktur.

Tasarıma yetersiz dikkat çekmek bir zorluktur, ancak aşırı tasarıma da dikkat edin.


"Talihsiz eğilimler" ve kör kurallara uyma hakkındaki yorumunuz yerinde olduğunu düşünüyorum.
Mael,

1
@Mael Diyorsun ki eğer ileride bu kodu korumak olmaz, doğru tasarım almak için iyi nedenlerimiz var ki? (alınma sadece bu konuda ne düşündüğünü bilmek istiyorum)
Benekli

2
@ Mael Elbette biz bunu sadece talihsiz bir cümleye çevirebiliriz! : D Bununla birlikte, kod yazarken diğerleri için olduğu kadar katı olmalıyız (yazdıktan 2 hafta sonra kendi kodumu okuduğumda kendimi başka biri olarak görüyorum).
Benekli

2
@ user61852 o zaman çok sevmediğim olacaktır Kodsuz Kodunu .
RubberDuck

1
@ user61852, haha - ama eğer neyi yok hepsi bağlıdır (bilgilere söz konusu verilmemiştir)? Çok az şey kesinlikten daha az faydalıdır.

43

DRY'nin bilgi ile ilgili olduğunu unutmayın . İki kod parçasının benzer, aynı veya tamamen farklı görünmesi farketmez , sisteminizle ilgili aynı bilgi parçasının her ikisinde de bulunabiliyorsa, bunun önemi nedir .

Bir bilgi parçası gerçek olabilir ("istenen değerden izin verilen maksimum sapma% 0,1'dir") veya işleminizin bir yönü olabilir ("bu sıra asla üçten fazla öğe içermez"). Temelde kaynak kodunuzda kodlanmış herhangi bir bilgi parçası.

Bu nedenle, kaldırılması gereken bir şey olup olmadığına karar verirken, bunun bilginin tekrarı olup olmadığını sorun. Değilse, muhtemelen rastlantısal bir çoğaltmadır ve onu ortak bir yere çıkarmak, daha sonra görünüşte çoğaltılmış parçanın farklı olduğu benzer bir bileşen oluşturmak istediğinizde sorunlara neden olur.


12
Bu! DRY'nin odağı çift ​​değişikliklerden kaçınmaktır .
Matthieu M.

Bu oldukça yardımcı olur.

1
DRY'nin odak noktası, aynı olması gereken ama yapmaması gereken iki kod parçası olmadığından emin olmaktı. Sorun iki katına çıkmıyor, çünkü kod değişikliklerinin iki kez yapılması gerekiyor; asıl sorun, kod değişikliğinin iki kez uygulanması gereken ancak yapılmadığı durum.
gnasher729

3
@ gnasher729 Evet, mesele bu. Eğer iki kod parçası bilginin kopyasına sahipse, birisinin değişmesi gerektiğinde, diğerinin de değişmesi gerekeceğini ve bunun da tarif ettiğiniz soruna yol açmasını beklersiniz. Eğer tesadüfi kopyaları varsa , birinin değişmesi gerektiğinde, diğerinin de aynı kalması gerekebilir. Bu durumda, ortak bir yöntem (ya da her neyse)
çıkardıysanız

1
Aynı zamanda temel çoğaltma ve kazayla çoğaltma , bkz . Ruby'de Yanlışlıkla Bir Doppelgänger ve Kodumu KURDURDUM ve Şimdi Çalışması Zor. Ne oldu? . Kaza sonucu oluşan kopyalar ayrıca bağlam sınırının her iki tarafında da ortaya çıkar . Özet: yalnızca bu bağımlılıkların eşzamanlı olarak değiştirilmeleri için müşterileri için anlamlı olduğunda kopyaları birleştirme .
Eric,

27

Strateji kalıbı kullanmayı düşündünüz mü ? Birkaç görünüm tarafından çağrılan ortak kodu ve yordamları içeren bir View sınıfınız olur. View sınıfının çocukları, bu örneklere özgü kodu içerir. Hepsi Görünüm için oluşturduğunuz ortak arayüzü kullanacak ve böylece farklar kapsüllenmiş ve tutarlı olacaktır.


5
Hayır, düşünmedim. Öneriniz için teşekkür ederim. Strateji kalıbı hakkındaki kısa bir okumadan, aradığım bir şeye benziyor. Kesinlikle daha fazla araştırma yapacağım.
Mael,

3
orada şablon yöntem model . Bunu da düşünebilirsiniz
Shakil

5

Değişim potansiyeli nedir? Örneğin, uygulamamızın her alan için 4 veya daha fazla kullanıcı türü potansiyeli olan 8 farklı iş alanı vardır. Görünümler, kullanıcı türüne ve bölgeye göre özelleştirilir.

Başlangıçta, bu, burada ve orada, farklı şeylerin gösterilmesi gerekip gerekmediğini belirlemek için birkaç kontrolle aynı görüşü kullanarak yapıldı. Zamanla, iş alanlarından bazıları önemli ölçüde farklı şeyler yapmaya karar verdi. Sonunda, iş alanı başına bir işlevsellik parçası başına temel olarak bir görünüme (ASP.NET MVC durumunda kısmi görünümler) geçtik. Tüm iş alanları aynı işlevselliğe sahip değildir, ancak biri diğerinin sahip olduğu işlevselliği isterse, o alan kendi görüşünü alır. Kodun anlaşılması ve test edilebilirlik için çok daha az hantaldır. Örneğin, bir alan için değişiklik yapmak, başka bir alan için istenmeyen bir değişikliğe neden olmaz.

@ Dan1111'de bahsedildiği gibi, bu bir karar çağrısına inebilir. Zamanla, çalışıp çalışmadığını bulabilirsiniz.


2

Bir sorun, sadece işlevselliğin tek bir seviyesine bir arayüz (dil özelliği değil, teorik arayüz) sağlamanız olabilir:

A(a,b,c) //a,b,c are your callbacks or other dependencies

Ne kadar kontrol gerektiğine bağlı olarak çoklu seviyeler yerine:

//high level
A(a,b,c)
//lower
A myA(a,b)
B(myA,c)
//even lower
A myA(a)
B myB(myA,b)
C myC(myB,c)
//all the way down to you just having to write the code yourself

Anladığım kadarıyla, uygulama ayrıntılarını (orada olan diğer şeyleri) gizleyerek, yalnızca yüksek seviye arayüzünü (A) ortaya çıkarırsınız.

Uygulama ayrıntılarını gizlemenin avantajları vardır ve yalnızca bir dezavantaj buldunuz - doğrudan düşük seviye arayüzleri kullanırken mümkün olan her bir şey için açıkça özellikler eklemiyorsanız kontrol sınırlıdır.

Demek iki seçeneğin var. Ya sadece düşük seviye arayüzü kullanın, düşük seviye arayüzü kullanın, çünkü yüksek seviye arayüz hem yüksek hem de düşük seviye arayüzleri korumak veya göstermek için çok fazla çaba harcadı. Mantıklı olan tek seçenek, gereksiz kodlardan kaçınmak istediğinizi varsayarak hem yüksek hem de düşük seviyeli arayüzler (ve bunların arasındaki her şeyi) sunmaktır.

Daha sonra, eşyalarınızdan bir tanesini yazarken, şu ana kadar yazmış olduğunuz mevcut tüm işlevselliğe bakarsınız (hangilerinin yeniden kullanılacağına karar vermenize kadar sayısız olasılık) ve bunları bir araya getirirsiniz.

Çok az kontrole ihtiyaç duyduğunuz tek bir nesne kullanın.

Bazı tuhaflıkların olması gerektiğinde en düşük seviye işlevselliği kullanın.

Aynı zamanda çok siyah-beyaz değil. Belki de büyük üst sınıf sınıfınız tüm olası kullanım durumlarını makul şekilde karşılayabilir. Belki de kullanım durumları o kadar değişkendir ki, en düşük seviyeli ilkel işlevsellik yeterli değildir. Dengeyi bulmak size kalmış.


1

Zaten başka faydalı cevaplar var. Benimkini ekleyeceğim.

Çoğaltma kötü çünkü

  1. kod kümeler
  2. Kodun bizim yorumumuzu sıkıştırıyor ama en önemlisi
  3. Çünkü burada bir şeyi değiştirirseniz ve oradaki bir şeyi de değiştirmek zorunda kalırsanız, unutabilir / hatalar / .... ve asla unutmak zordur.

Yani mesele şu ki: bunun uğruna çoğaltmayı ortadan kaldırmıyorsunuz ya da birisi önemli olduğunu söyledi. Bunu yapıyorsun çünkü hataları / problemleri azaltmak istiyorsun. Sizin durumunuzda, görünümdeki bir şeyi değiştirirseniz, muhtemelen diğer tüm görünümlerde aynı çizgiyi değiştirmenize gerek kalmayacak . Bu nedenle gerçek çoğaltmaya değil , belirgin çoğaltmaya sahipsiniz .

Başka bir önemli nokta, Joel'in dediği gibi, şu anda yalnızca bir prensip temelinde çalışan bir şeyi asla sıfırdan yazmak değildir (zaten onu duymuş olabilirsiniz ...). Bu nedenle, görüşleriniz çalışıyorsa, adım adım iyileştirmeye devam edin ve "herhangi bir yazılım şirketinin yapabileceği en kötü tek stratejik hata" nın peşine düşmeyin.

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.