Bilinmeyen şekilde kopyalayan kodu nasıl önlerim?


33

Oldukça büyük bir kod tabanı üzerinde çalışıyorum. Yüzlerce sınıf, tonlarca farklı dosya, çok fazla işlevsellik, yeni bir kopyayı çekmek için 15 dakikadan fazla zaman alıyor.

Bu kadar büyük bir kod tabanıyla ilgili büyük bir sorun, oldukça az sayıda yardımcı program yöntemine sahip olması ve aynı şeyi yapan gibi ya da bu yardımcı program yöntemlerini kullanamadığı zaman kullanamayan bir koda sahip olmasıdır. Ayrıca fayda yöntemleri sadece bir sınıfta değildir (çünkü büyük bir karışıklık olacaktır).

Kod üssünde yeniyim, ancak yıllardır üzerinde çalışan ekip lideri aynı sorunu yaşıyor gibi görünüyor. Bir çok kod ve iş çoğaltmasına yol açar ve bu nedenle, bir şey bozulduğunda, genellikle aynı kodun 4 kopyasında kırılır

Bu modeli nasıl frenleyebiliriz? Çoğu büyük projede olduğu gibi, tüm kodlar belgelenmemiş (bazıları olsa da) ve tüm kodlar ... tamam değil, temiz. Ancak, temel olarak, bu açıdan kaliteyi arttırmak için çalışabilirsek, gelecekte daha az kod çoğaltmaya sahip olmamız ve faydalı fonksiyonlar gibi şeylerin keşfedilmesi daha kolay olacaksa gerçekten iyi olurdu.

Ayrıca, yardımcı fonksiyonlar genellikle bazı statik yardımcı sınıflarında, tek bir nesne üzerinde çalışan bazı statik olmayan yardımcı sınıflarında veya genellikle üzerinde yardımcı oldukları sınıfta statik bir yöntemdir.

Eklenti yöntemleri olarak yardımcı işlevler ekleme konusunda bir denemem vardı (sınıfın herhangi bir iç kısmına ihtiyacım yoktu ve kesinlikle yalnızca çok özel senaryolarda gerekliydi). Bu, birincil sınıfı ve benzerlerini karıştırmayı önleme etkisine sahipti, ama siz bunu bilmiyorsanız, artık gerçekten keşfedilemez.


Yanıtlar:


30

Basit cevap, kod çoğaltmayı gerçekten önleyemediğinizdir. Bununla birlikte, iki adımda aşağıya inen zor ve sürekli tekrarlayan artımlı bir işlemle "düzeltebilirsiniz":

Adım 1. Eski kod üzerinde testler yazmaya başlayın (tercihen bir test çerçevesi kullanarak)

Adım 2. Testlerden öğrendiklerinizi kullanarak kopyalanan kodu yeniden yazın / yeniden sınıflandırın

Yinelenen kodu algılamak için statik analiz araçlarını kullanabilirsiniz ve C # için bunu sizin için yapabilecek çok sayıda araç vardır:

Bunun gibi araçlar, kodda benzer şeyleri yapan noktaları bulmanıza yardımcı olacaktır. Gerçekten yaptıklarını belirlemek için testler yazmaya devam edin; yinelenen kodu kullanmak daha basit hale getirmek için aynı testleri kullanın. Bu "yeniden düzenleme" birden çok yolla yapılabilir ve doğru olanı belirlemek için bu listeyi kullanabilirsiniz:

Ayrıca Michael C. Tüyler, Eski Kod ile Etkili Çalışma bu konu hakkında bir kitap da var . Kodu daha iyi hale getirmek için kullanabileceğiniz farklı stratejiler derinlemesine gider. Yukarıdaki iki adım işleminden uzakta olmayan bir "eski kod değiştirme algoritması" vardır:

  1. Değişim noktalarını tanımla
  2. Test noktalarını bul
  3. Bağımlılıkları kır
  4. Testleri yaz
  5. Değişiklik ve refactor yapmak

Kahverengi alan geliştirme, yani değişmesi gereken eski kodla ilgileniyorsanız, kitap iyi bir okumadır.

Bu durumda

OP'nin durumunda, test edilemeyen kodun, çeşitli biçimlerde bulunan "faydalı yöntemler ve püf noktaları" için bir bal kabından kaynaklandığını hayal edebiliyorum:

  • statik yöntemler
  • statik kaynak kullanımı
  • singleton sınıfları
  • sihirli değerler

Bunlarla ilgili yanlış bir şey olmadığını unutmayın, ancak diğer yandan bakımı ve değişimi genellikle zordur. .NET'teki uzantılar yöntemleri statik yöntemlerdir, ancak test edilmesi nispeten kolaydır.

Yeniden yapılanmalara başlamadan önce, ekibinizle bunun hakkında konuşun. Herhangi bir şeye devam etmeden önce sizinle aynı sayfada tutulmaları gerekir. Bunun nedeni, eğer bir şeyi yeniden gözden geçiriyorsanız, şansın yüksek olması birleşme çatışmalarına neden oluyor olmanızdır. Bir şeyi elden geçirmeden önce araştırın, ekibinize bu kod noktaları üzerinde çalışıp bitinceye kadar dikkatli çalışmasını söyleyin.

OP kodda yeni olduğu için herhangi bir şey yapmadan önce yapmanız gereken başka şeyler var:

  • Kod tabanından öğrenmek için zaman ayırın, yani "her şeyi" kırın, "her şeyi" test edin, geri alın.
  • Ekipten birinden, taahhütte bulunmadan önce kodunuzu incelemesini isteyin. ;-)

İyi şanslar!


Aslında oldukça fazla birim ve entegrasyon testimiz var. % 100 kapsam dahilinde olmamakla birlikte, yaptığımız bazı işler kod tabanımızda köklü değişiklikler olmadan birim testi yapmak neredeyse imkansız. Çoğaltmayı bulmak için statik analiz kullanmayı hiç düşünmedim. Bunu bir daha denemem gerekecek.
Earlz

@Earlz: Statik kod analizi harika! ;-) Ayrıca, değişikliği ne zaman yapmanız gerektiğine bağlı olarak, değişiklikleri kolaylaştırmak için çözümler düşünün (bunun için desen kataloğuna
refraktöre bakın

+1 Birisinin bu cevabı "fazladan yardım" olarak ödüllendirmek için bu Q'ya bir ödül getirip getirmediğini anlarım. Desenler için Refactor Kataloğu altındır, GuidanceExplorer.codeplex.com biçiminde bunun gibi şeyler harika programlama yardımcılarıdır.
Jeremy Thompson,

2

Sorunu başka bir açıdan da görmeyi deneyebiliriz. Sorunun kod çoğaltması olduğunu düşünmek yerine, sorunun tekrar kullanım politikalarının olmamasından kaynaklanıp kaynaklanmadığını düşünebiliriz.

Kısa süre önce Yeniden Kullanılabilir Bileşenlere Sahip Yazılım Mühendisliği kitabını okudum ve kodun yeniden kullanılabilirliğini nasıl örgüt düzeyinde geliştireceğiyle ilgili çok ilginç fikirler var.

Bu kitabın yazarı, Johannes Sametinger, bazılarını biraz teknik olarak yeniden kodlamanın önündeki bazı engelleri açıklar. Örneğin:

Kavramsal ve Teknik

  • Yeniden kullanılabilir yazılımı bulmakta zorluk : Yazılım bulunamadığı sürece tekrar kullanılamaz. Bir depo, bileşenler hakkında yeterli bilgiye sahip olmadığında veya bileşenler zayıf bir şekilde sınıflandırıldığında yeniden kullanım olasılığı düşüktür.
  • Bulunan yazılımın tekrar kullanılmazlığı : mevcut yazılıma kolay erişim, yazılımın tekrar kullanımını mutlaka arttırmaz. İstemeden, yazılım nadiren yazılır, bu sayede diğerleri onu kullanabilir. Başkasının yazılımını değiştirmek ve uyarlamak, gerekli işlevselliği sıfırdan programlamaktan daha pahalı hale gelebilir.
  • Yeniden kullanım için uygun olmayan eski bileşenler : Yeniden kullanım için tasarlanmadıklarında ve geliştirmediklerinde bileşenlerin yeniden kullanımı zor veya imkansızdır. Mevcut bileşenleri çeşitli eski yazılım sistemlerinden toplamak ve bunları yeni gelişmeler için tekrar kullanmaya çalışmak, sistematik yeniden kullanım için yeterli değildir. Yeniden mühendislik, yeniden kullanılabilir bileşenlerin çıkarılmasında yardımcı olabilir, ancak çaba önemli olabilir.
  • Nesneye yönelik teknoloji : Nesneye yönelik teknolojinin yazılımın yeniden kullanımı üzerinde olumlu bir etkisi olduğuna inanılıyor. Ne yazık ki ve yanlış olarak, çoğu kişi de yeniden kullanımın bu teknolojiye bağlı olduğuna veya nesne yönelimli teknolojiyi kullanmanın yazılımın yeniden kullanımı için yeterli olduğuna inanıyor.
  • Değişiklik : bileşenler her zaman tam olarak istediğimiz gibi olmayacak. Eğer değişiklik gerekliyse, bileşen üzerindeki etkilerini ve önceki doğrulama sonuçlarını belirleyebilmeliyiz.
  • Çöplerin yeniden kullanımı : Yeniden kullanılabilir bileşenleri belirli kalite seviyelerinde sertifikalandırmak olası hataları en aza indirmeye yardımcı olur. Düşük kalite kontrolleri yeniden kullanımın önündeki en büyük engellerden biridir. Gerekli işlevlerin bir bileşen tarafından sağlanan işlevlerle eşleşip eşleşmediğini yargılamaya ihtiyacımız var.

Diğer temel teknik zorluklar arasında

  • Yeniden kullanılabilir bir bileşenin neyi oluşturduğunu kabul etmek.
  • Bir bileşenin ne yaptığını ve nasıl kullanılacağını anlamak.
  • Yeniden kullanılabilir bileşenlerin tasarımın geri kalanıyla nasıl ilişkilendirileceğini anlamak.
  • Yeniden kullanılabilir bileşenleri tasarlamak, böylece kontrollü bir şekilde uyarlamaları ve değiştirmeleri kolaydır.
  • Bir depo düzenlemek, böylece programcılar ihtiyaç duyduklarını bulabilir ve kullanabilir.

Yazara göre, bir kuruluşun vadesine bağlı olarak farklı seviyelerde yeniden kullanımlık ortaya çıkar.

  • Uygulama grupları arasında geçici yeniden kullanım : yeniden kullanım için kesin bir taahhüt yoksa, yeniden kullanım en iyi şekilde gayrı resmi ve tehlikeli bir şekilde olabilir. Yeniden kullanımın çoğu, eğer varsa, projeler içinde gerçekleşir. Bu aynı zamanda kod temizlemeye yol açar ve kod çoğaltmayla sonuçlanır.
  • Uygulama grupları arasında depo temelli yeniden kullanım : bir bileşen deposunun kullanılması ve çeşitli uygulama grupları tarafından erişilebilir olması durumunda durum biraz iyileşir. Ancak, bileşenleri depoya koymak için açık bir mekanizma yoktur ve depodaki bileşenlerin kalitesinden kimse sorumlu değildir. Bu, birçok soruna ve yazılımın yeniden kullanılmasına engel olabilir.
  • Bir bileşen grubu ile merkezi yeniden kullanım: Bu senaryoda, bir bileşen grubu depodan açıkça sorumludur. Grup, hangi bileşenlerin depoda depolanacağını belirler ve bu bileşenlerin kalitesinin ve gerekli belgelerin bulunup bulunmadığından emin olur ve belirli bir yeniden kullanım senaryosunda uygun bileşenlerin alınmasına yardımcı olur. Başvuru grupları, her bir başvuru grubuna bir çeşit taşeron olarak davranan bileşen grubundan ayrılmaktadır. Bileşen grubunun amacı, fazlalığı en aza indirmektir. Bazı modellerde, bu grubun üyeleri belirli projeler üzerinde de çalışabilir. Proje başlangıcı sırasında bilgileri yeniden kullanımı teşvik etmek için değerlidir ve belirli bir projeye dahil olmaları sayesinde depoya dahil olmaları için olası adayları belirleyebilirler.
  • Etki Alanı Tabanlı Yeniden Kullanım : Bileşen gruplarının uzmanlığı, etki alanı tabanlı yeniden kullanıma açıktır. Her etki alanı grubu, etki alanındaki bileşenlerden, örneğin ağ bileşenleri, kullanıcı arabirimi bileşenleri, veritabanı bileşenleri sorumludur.

Bu nedenle, belki de, diğer cevaplarda verilen tüm önerilerin yanı sıra, bir yeniden kullanılabilirlik programı tasarlamaya çalışabilir, yönetimi dahil edebilir, etki alanı analizi yaparak yeniden kullanılabilir bileşenlerin tanımlanmasından sorumlu bir bileşen grubu oluşturabilir ve diğer geliştiricilerin kolayca kullanabileceği yeniden kullanılabilir bileşenlerin bir havuzunu tanımlayabilirsiniz. kendi sorunlarına çözüm önerileri sormak ve aramak.


1

2 olası çözüm vardır:

Önleme - Olabildiğince iyi belgelere sahip olmaya çalışın. Her işlevin düzgün bir şekilde belgelenmesini ve tüm belgelerde kolayca arama yapmasını sağlayın. Ayrıca, kod yazarken, kodun nereye gideceği belli olur; bu nedenle nereye bakılacağı açıktır. Sınırlı miktarda "yardımcı" kod bunun en önemli noktalarından biridir. Ne zaman "yardımcı sınıf yapalım" diye duyduğumda saçlarım yükseliyor ve kanım donuyor, çünkü bariz bir problem. Her zaman bir özellik zaten mevcutsa, kod tabanını tanımalarını istemek için her zaman hızlı ve kolay bir yol kullanın.

Çözüm - Önleme başarısız olursa, sorunlu kod parçasını hızlı ve verimli bir şekilde çözebilmelisiniz. Geliştirme işleminiz yinelenen kodu hızlıca düzeltmeyi sağlamalıdır. Birim testi bunun için mükemmeldir, çünkü kodu kırma korkusu olmadan verimli bir şekilde değiştirebilirsiniz. Bu nedenle, benzer 2 kod parçası bulursanız, bunları bir işleve veya sınıfa soyutlamak biraz yeniden düzenleme ile kolay olmalıdır.

Şahsen ben önlemenin mümkün olduğunu sanmıyorum. Ne kadar çok denersen, zaten mevcut olan özellikleri bulmak o kadar problemlidir.


0

Bu tür sorunların genel bir çözümü olduğunu sanmıyorum. Geliştiriciler mevcut kodu aramaya istekliyse, yinelenen kod oluşturulmaz. Ayrıca geliştiriciler isterlerse sorunları yerinde çözebilirlerdi.

Dil C / C ++ ise, birleştirme, bağlantı esnekliği nedeniyle birleştirme daha kolay olacaktır (biri externönceden bilgi olmadan herhangi bir işlevi çağırabilir ). Java veya .NET için yardımcı sınıflar ve / veya yardımcı program bileşenleri geliştirmeniz gerekebilir.

Çoğunlukla çoğaltmayı, yalnızca büyük hatalar çoğaltılmış parçalardan kaynaklanıyorsa varolan kodu kaldırmaya başlar.


0

Bu, çok fazla akran baskısı altında katkıda bulunan birçok programcı tarafından yönetilen daha büyük bir projenin tipik bir sorunudur. Bir sınıfın kopyasını çıkarmak ve o sınıfa uyarlamak çok caziptir. Bununla birlikte, kaynak sınıfta bir sorun bulunduğunda, sık sık unutulan decunentlerinde de çözülmesi gerekir.

Bunun için bir çözüm var ve Java 6'da tanıtılan Generics olarak adlandırılıyor. Şablon olarak adlandırılan C ++ 'ın karşılığı. Tam sınıfın Genel Sınıf içinde henüz bilinmediği kod. Lütfen Java Generics'i kontrol edin ve tonlarca ve tonlarca belge bulacaksınız.

Belli bir hata nedeniyle düzeltmeniz gereken ilkini yeniden yazarak, birçok yerde kopyalanmış / yapıştırılmış görünen kodu yeniden yazmak iyi bir yaklaşımdır. Generics kullanmak için tekrar yazınız ve ayrıca çok sıkı test kodları yazınız.

Generic sınıfının her yönteminin çağrıldığından emin olun. Ayrıca, kod kapsamı araçlarını da tanıtabilirsiniz: genel kod, tam kod kapsamı olmalıdır, çünkü çeşitli yerlerde kullanılacaktır.

Ayrıca, test kodunu, yani Genel kod parçası ile birlikte kullanılacak olan birinci sınıf için JUnit veya benzeri kullanarak yazınız.

Önceki kodun tümü çalıştığında ve tamamen test edildiğinde, ikinci kodu (çoğu zaman) kopyalanan sürümü için Genel kodu kullanmaya başlayın. Belirlediğiniz sınıfa özgü bazı kod satırları olduğunu göreceksiniz. Bu kodlanmış satırları, Generic base sınıfını kullanan türetilmiş sınıf tarafından uygulanması gereken soyut korumalı bir yöntemle çağırabilirsiniz.

Evet, sıkıcı bir iştir, ancak ilerledikçe, benzer sınıfları söküp yerine çok temiz, iyi yazılmış ve bakımı daha kolay bir şeyle değiştirirsiniz.

Sonunda, genel sınıfta sonunda neredeyse hemen hemen aynı olan ancak bir süre boyunca çeşitli programcılar tarafından kopyalanıp yapıştırılan 6 veya 7 diğer hemen hemen aynı sınıf gibi şeylerin yerini aldı.

Ve evet, kodun otomatik olarak test edilmesinden yanayım. Başlangıçta daha pahalıya mal olacak ama kesinlikle size muazzam bir zaman kazandıracak. Ve Genel kod için genel olarak en az% 80 ve% 100 kod kapsamı sağlamaya çalışın.

Umarım bu yardımcı olur ve iyi şanslar.


0

Aslında burada en az popüler olan görüşü yankılayacağım ve Gangnuskod çoğaltmanın her zaman zararlı olmadığını ve bazen daha az kötülük olabileceğini öne süreceğim.

Söyleyin, bana kullanma seçeneğini verirseniz:

A) Nokta test ürünleri ve lp'ler ve kelepçeler gibi vektörel matematik için birkaç düzine basit matematiksel kod satırını kopyalayan , iyi test edilmiş , kararlı (değişmeyen) ve minik bir resim kitaplığı bir saniye.

B) Yukarıda belirtilen birkaç düzine kod satırından kaçınmak için epik bir matematik kütüphanesine bağlı olan kararsız (hızla değişen) bir resim kütüphanesi, matematik kütüphanesi kararsız ve sürekli olarak yeni güncellemeler ve değişiklikler alıyor ve dolayısıyla resim kütüphanesi de düpedüz değişmediyse yeniden yapılmalıdır. Herşeyi temizlemek 15 dakika sürer.

... o zaman açıkça, çoğu kişinin A'nın ve aslında tam olarak küçük kod çoğaltılması nedeniyle tercih edilmesinin akıllıca olması gerekir. Yapmam gereken anahtar vurgu, iyi test edilmiş kısımdır. Açıkçası, ilk etapta bile çalışmayan, kodlanan koddan daha kötü bir şey yoktur, bu noktada kopyalanan hatalar vardır.

Ancak düşünülmesi gereken bir birleşme ve kararlılık var, ve burada mütevazı bir çoğaltma da var ve bu da paketin kararlılığını (değişmeyen doğası) artıran bir ayrıştırma mekanizması olarak hizmet edebilir.

Bu yüzden benim önerim aslında teste ve gerçekten istikrarlı bir şey (geleceğin değişmesi için birkaç neden buluyormuş gibi) ve eğer varsa, dışarıdaki kaynaklara bağımlılığı güvenilir olan bir şeyle gelmeye çalışmaya odaklanacak. çok istikrarlı, kod üssünüzdeki tüm çoğaltma biçimlerini damgalamaya çalışmak yerine. Büyük bir ekip ortamında, ikincisi, kod tabanınızdaki bağdaştırıcıyı ve dengesiz kod miktarını artırabileceğinden bahsetmek yerine, pratik bir amaç olma eğilimindedir.


-2

Unutmayın ki kod çoğaltma her zaman zararlı değildir. Hayal edin: şimdi projenizin tamamen farklı modüllerinde çözülmesi gereken bir göreviniz var. Hemen şimdi aynı görev.

Bunun üç nedeni olabilir:

  1. Bu görevin etrafındaki bazı temalar her iki modül için aynıdır. Bu durumda kod çoğaltması kötüdür ve tasfiye edilmesi gerekir. Bu temayı desteklemek için bir sınıf veya modül oluşturmak ve yöntemlerini her iki modülde de kullanmak akıllıca olacaktır.

  2. Görev, projeniz açısından teorik. Örneğin, fizik veya matematik vs.'den geliyor. Görev projenizde bağımsız olarak var. Bu durumda, kod çoğaltması kötüdür ve de tasfiye edilmesi gerekir. Böyle fonksiyonlar için özel bir sınıf oluşturabilirim. Ve böyle bir işlevi, ihtiyaç duyduğunuz herhangi bir modülde kullanın.

  3. Ancak diğer durumlarda görevlerin tesadüfü geçici bir tesadüftür ve başka bir şey değildir. Yeniden yapılanma ve hatta hata ayıklama nedeniyle bu görevlerin proje değişiklikleri sırasında aynı kalacağına inanmak tehlikeli olabilir. Bu durumda , farklı yerlerde iki aynı fonksiyon / kod parçası oluşturmak daha iyi olacaktır . Ve bunlardan birinde gelecekteki değişiklikler diğerine dokunmayacak.

Ve bu 3. dava çok sık olur. Eğer "bilmeden" çoğaltırsanız, çoğunlukla bunun nedeni budur - gerçek bir çoğaltma değildir!

Bu yüzden, gerçekten gerekli olduğunda temiz tutmaya çalışın ve gerekmediği takdirde çoğaltılmasından korkmayın.


2
code duplication is not always harmfulkötü bir tavsiye.
Tulains Córdova,

1
Otoritesine boyun eğmeli miyim? Sebeplerimi buraya koydum. Yanılıyorsam, nerede olduğunu göster. Şimdi daha ziyade tartışmaya devam etme yeteneğiniz zayıf gibi görünüyor.
Gangnus,

3
Kod çoğaltması, yazılım geliştirmedeki temel sorunlardan biridir ve pek çok bilgisayar uzmanı ve teorisyen, yazılım geliştirmedeki sürdürülebilirlik sorunlarının ana kaynağı olarak kod çoğaltılmasını önlemek için paradigmalar ve metodolojiler geliştirmiştir. "Kötü kod yazmanın her zaman kötü olmadığını" söylemek gibi bir şey, bu şekilde her şey sözde haklı olabilir. Belki de haklısınız, ancak kod çoğaltmasından kaçınmak, tam tersini teşvik etmek için yaşamak için çok iyi bir ilkedir.
Tulains Córdova

Ben var burada argümanlar koydu. Yapmadın Yetkililere yapılan atıflar, 16. yüzyıldan beri işe yaramayacak. Onları doğru anladığınızı ve benim için otoriteler olduklarını garanti edemezsiniz.
Gangnus

Haklısın, kod çoğaltma , yazılım geliştirmedeki temel sorunlardan biri değildir ve bundan kaçınmak için hiçbir paradigma ve metodoloji geliştirilmemiştir.
Tulains Córdova
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.