Optimize edilmiş kodu okunabilir kodla değiştirmek uygun mudur?


78

Bazen, varolan bazı kodları genişletmeniz / iyileştirmeniz gereken bir duruma girersiniz. Eski kodun çok zayıf olduğunu görüyorsunuz, ancak genişletilmesi de zor ve okumak zaman alıyor.

Modern kodla değiştirmek iyi bir fikir mi?

Bir süre önce yalın yaklaşımı sevdim, ama şimdi bana daha yüksek soyutlamalar, daha iyi arayüzler ve daha okunaklı, genişletilebilir kodlar lehine birçok optimizasyondan ödün vermenin daha iyi olduğu görülüyor.

Derleyiciler de daha iyi hale geliyor gibi gözüküyor, bu yüzden sessizlik s'ye struct abc = {}dönüştürülüyor memset, shared_ptrs ham gösterici twiddling ile aynı kodu üretiyor, şablonlar süper iyi çalışıyor çünkü süper yalın kod üretiyorlar, vb.

Ama yine de, bazen yığın tabanlı diziler görüyorsunuz ve eski C bazı karanlık mantıklarla çalışıyor ve genellikle kritik yolda değiller.

Her iki şekilde de küçük bir parçaya dokunmanız gerekirse, bu kodu değiştirmek iyi bir fikir midir?


20
Okunabilirlik ve optimizasyonlar çoğu zaman karşı değildir.
deadalnix

23
Okunabilirlik bazı yorumlarla gelişebilir mi?
YetAnotherUser

17
OOP-ification'ın 'modern kod' olarak kabul edilmesi endişeleniyor
James

7
Slackware felsefesi gibi: eğer kırılmazsa düzeltmeyin, daha azında bunu yapmak için çok, çok iyi bir nedeniniz var
osdamv

5
En iyi duruma getirilmiş kod ile, gerçek en iyileştirilmiş kod mu , yoksa sözde en iyileştirilmiş kod mu demek istiyorsunuz ?
dan04

Yanıtlar:


115

Nerede?

  • Google ölçeğinde bir web sitesinin giriş sayfasında kabul edilemez. İşleri olabildiğince çabuk tut.

  • Yılda bir kez bir kişi tarafından kullanılan bir uygulamanın bir bölümünde, kod okunabilirliği elde etmek için performanstan ödün vermek tamamen kabul edilebilir.

Genel olarak, üzerinde çalıştığınız kodun parçası için işlevsel olmayan gereksinimler nelerdir? Bir eylem 900 msn altında gerçekleştirilmelidir. Belirli bir bağlamda (makine, yük vb.) zamanın% 80'i ve gerçekte 200 msn altında performans gösterir. Zamanın% 100'ü, performansı çok az etkilese bile kodu daha okunabilir kılar. Öte yandan, aynı eylem on saniyenin altında hiçbir zaman gerçekleşmediyse, performansta neyin yanlış olduğunu görmeyi denemelisiniz (veya ilk etapta gereklilik).

Ayrıca, okunabilirlik gelişimi performansı nasıl düşürür? Genellikle, geliştiriciler davranışı erken optimizasyona yakın bir şekilde uyarlarlar: okunabilirliği arttırmaktan korkarlar, performansı büyük ölçüde tahrip edeceğine inanırken, daha okunaklı kod aynı işlemi yapmak için birkaç mikrosaniyeyi harcayacaktır .


47
1! Sayıların yoksa, bazı numaralar al. Numaraları almak için zamanınız yoksa, değiştirmek için zamanınız yok.
Takroy

49
Genellikle, geliştiriciler, örneğin, "C" nin "C ++" dan daha hızlı olduğunu varsayarak ve sayıları desteklemeyen şeylerin daha hızlı olduğunu düşünerek C ++ özelliklerinden kaçınarak efsane ve yanlış anlamaya dayalı olarak "optimize ediyorlar". Bana takipçilerden gotodaha hızlı olduğunu düşünen bir C geliştiricisini hatırlatıyor . İronik olarak, optimizer döngüler için daha iyisini yaptı, bu yüzden kodu daha yavaş ve okumasını zorlaştırdı.
Steven Burnap

6
Başka bir cevap eklemek yerine, bu cevabı + 1'ledim. Kod parçalarını anlamak önemliyse, onları iyi yorumlayın. Bir C / C ++ / Assembly ortamında 10 yıl boyunca eski kodlarla onlarca katılımcıyla çalıştım. Kod işe yararsa, onu rahat bırakın ve işe geri dönün.
Chris K,

Bu yüzden sadece okunabilir kod yazmaya meyilliyim. Birkaç sıcak noktayı keserek performansa ulaşılabilir.
Luca

36

Genellikle hayır .

Kodun değiştirilmesi, sistemin herhangi bir yerinde öngörülemeyen çalma sorunlarına neden olabilir (katı ünite ve duman testleriniz yoksa, bazen bir projede daha sonradan fark edilmeyebilir). Genelde "kırılmazsa düzeltmeyin" zihniyetine uğrarım.

Bu kuralın istisnası, bu koda değen yeni bir özellik uyguluyorsanızdır. Bu noktada, mantıklı gelmiyorsa ve yeniden düzenlemenin gerçekten yapılması gerekiyorsa, yeniden yapılandırma süresi (ve knock-on sorunları ile başa çıkmak için yeterli test ve tampon) tüm tahminlerde hesaba katıldığı sürece devam edin.

Tabii ki, profil, profil, profil , özellikle kritik bir yol alanıysa.


2
Evet, ancak optimizasyonun gerekli olduğunu varsayıyorsunuz. Öyle olup olmadığını her zaman bilmiyoruz ve muhtemelen bunu önce belirlemek istiyoruz.
haylem

2
@haylem: Hayır, kodun olduğu gibi çalıştığını varsayıyorum . Ayrıca, kodun yeniden yapılandırılmasının, sistemin herhangi bir yerinde bozulma sorunlarına yol açacağını (dışsal bağımlılıkları olmayan önemsiz bir kod ögesiyle uğraşmadığınız sürece) olacağını varsayıyorum.
Demian Brecht

Bu cevabın bazı gerçekleri var ve ironik bir şekilde bunun nedeni, takılma sorunlarının geliştiriciler tarafından nadiren belgelenmesi, anlaşılması, iletilmesi ve hatta dikkat edilmesidir. Geliştiriciler geçmişte olan sorunları daha iyi anlıyorlarsa, neyin ölçüleceğini bilecekler ve kod değişikliklerinde daha emin olacaklar.
rwong

29

Kısaca: Bağlıdır

  • Refactored / geliştirilmiş sürümünüze gerçekten ihtiyacınız olacak mı veya kullanacak mısınız?

    • Hemen veya uzun vadeli bir somut kazanç var mı?
    • Bu kazanç yalnızca sürdürülebilirlik için mi yoksa gerçekten mimari mi?
  • Gerçekten optimize edilmesi gerekiyor mu?

    • Neden?
    • Hangi hedef kazancı hedeflemeniz gerekiyor?

Detaylarda

Temizlenmiş, parlak şeylere ihtiyacın olacak mı?

Burada temkinli olması gereken şeyler var ve gerçek olan, ölçülebilir kazanç ile kişisel tercihiniz ve olması gereken kodlara dokunmamanın olası kötü alışkanlığı arasındaki sınırı belirlemelisiniz.

Daha spesifik olarak, bunu bilmek:

Over-Engineering diye bir şey var.

Bu bir anti-patern ve yerleşik sorunlara sahip:

  • o daha genişletilebilir olabilir , ama kolay olmayabilir , uzatmak
  • o anlamak kolay olmayabilir ,
  • son, ama kesinlikle en az burada değil: tüm kodu yavaşlatabilir.

Bazıları KISS ilkesinden referans olarak da bahsedebilir , ancak burada karşı sezgiseldir: en iyi yol basit yol mu yoksa temiz tasarım yol mu? Aşağıdaki geri kalanında açıklandığı gibi cevap mutlaka mutlak değildir.

İhtiyacın olmayacak

YAGNI prensibi diğer sorunu tamamen dik değil, ama kendinize soru sormak için yardımcı olur: Eğer ihtiyacımız olacak?

Daha karmaşık mimari, sizin için daha sürdürülebilir olma görünümü vermenin yanı sıra gerçekten de bir fayda sağlıyor mu?

Kırılmadıysa, Onarma

Bunu büyük bir postere yazın ve ekranınızın yanına veya iş yerindeki mutfak alanına veya toplantı salonuna asın. Elbette, kendini tekrarlamaya değecek birçok başka mantra var, ancak “bakım çalışması” yapmaya çalıştığınızda ve “iyileştirme” dürtüsünü hissettiğinizde bu özellikle önemlidir.

Anlaşmayı denemek için okuduğumuz gibi, kodu "geliştirmek" istemek, hatta bilinçsizce bile dokunmak doğaldır. İyi bir şey, bu bizim fikrimiz olduğu ve iç dünyaları daha derinlemesine anlamaya çalıştığımız anlamına geldiği için, aynı zamanda beceri seviyemize, bilgimize bağlı (neyin daha iyi olduğuna veya neyin daha iyi olduğuna nasıl karar veriyorsunuz? ...) ve yazılımı bildiğimizi düşündüğümüz her türlü varsayımı ...:

  • aslında,
  • aslında yapması gereken
  • sonunda yapmanız gerekecek
  • ve ne kadar iyi yapar.

Gerçekten optimize edilmesi gerekiyor mu?

Bütün bunlar, neden her şeyden önce "optimize edildi" dedi? Erken optimizasyonun tüm kötülüklerin kökü olduğunu söylerler ve belgelenmemiş ve görünüşte optimize edilmiş bir kod görürseniz, genellikle bunun muhtemelen Optimizasyon Kurallarına uymadığını ve muhtemelen optimizasyon çabalarına ihtiyaç duymadığını ve bunun sadece her zamanki geliştiricinin korsanı devreye giriyor. Yine, belki de şu an seninki konuşuyor.

Varsa hangi sınırlar içinde kabul edilebilir hale gelir? Buna bir ihtiyaç varsa, bu sınır vardır ve işleri iyileştirmek için yer ya da bırakmaya karar vermeniz için zorlu bir yol sunar.

Ayrıca görünmez özelliklere dikkat edin. Muhtemelen, bu kodun "genişletilebilir" sürümünüz, çalışma zamanında da daha fazla bellek tüketir ve çalıştırılabilir için daha büyük bir statik bellek alanı sağlar. Parlak OO özellikleri bunun gibi sezgisel olmayan maliyetlerle gelir ve programınız ve üzerinde çalışması gereken çevre için önemli olabilir.

Ölç, Ölç, Ölç

Google şimdi millet gibi, her şey verilerle ilgili! Verileri ile yedekleyebilirsiniz, o zaman gerekli.

Gelişiminde harcanan her 1 $ için takip edecek bu o kadar eski masalı var en azından test $ 1 ve en az destek $ 1 (ama gerçekten, çok daha fazla var).

Değişim bir çok şeyi etkiler:

  • yeni bir yapı oluşturmanız gerekebilir;
  • yeni birim testleri yazmalısınız (kesinlikle yok ise ve daha fazla genişletilebilir mimariniz muhtemelen hata için daha fazla yüzeye sahip olduğunuzdan daha fazla alana yer açacaktır);
  • yeni performans testleri yazmalısınız (bunun gelecekte sabit kalmasını sağlamak ve tıkanıklıkların nerede olduğunu görmek için) ve bunların yapılması zor ;
  • belgelendirmeniz gerekir (ve daha fazla genişletilebilir, ayrıntılar için daha fazla alan demektir);
  • Siz (veya bir başkasının) QA'da kapsamlı şekilde yeniden test etmeniz gerekecek;
  • kod hiç bir zaman hatasız değildir ve onu desteklemeniz gerekir.

Bu nedenle , burada ölçmeniz gereken yalnızca donanım kaynakları tüketimi (yürütme hızı veya bellek alanı) değil, aynı zamanda ekip kaynakları tüketimidir. Her ikisinin de bir hedef amaç tanımlaması, ölçülmesi, hesaba katılması ve kalkınmaya dayalı olarak uyarlanması öngörülmelidir.

Ve sizin yöneticiniz, bu mevcut gelişim planına uymak anlamına gelir, bu yüzden bunun hakkında iletişim kurun ve öfkeli kovboy / denizaltı / kara ops kodlamasına girmeyin.


Genel olarak...

Evet ama...

Beni yanlış anlama, genel olarak önerdiğin şeyi yapmanın lehine olurum ve bunu sıklıkla savunurum. Ancak uzun vadeli maliyetlerin farkında olmanız gerekir.

Mükemmel bir dünyada doğru çözüm:

  • bilgisayar donanımı zaman içinde iyileşir
  • derleyiciler ve çalışma zamanı platformları zaman içinde daha iyi hale gelir,
  • mükemmel, temiz, bakımı kolay ve okunabilir kodlar elde edersiniz.

Uygulamada:

  • daha kötü hale getirebilirsin

    Buna bakmak için daha fazla göz küresi gerekir ve ne kadar karmaşıklaşırsanız, ihtiyaç duyduğunuz gözbebekleri o kadar fazla olur.

  • geleceği tahmin edemezsin

    İhtiyacınız olursa kesin olarak bilemezsiniz ve ihtiyaç duyacağınız "uzantılar" eski formda uygulamak için daha kolay ve daha hızlı olurdu ve kendilerinin süper optimize edilmeleri gerekse bile .

  • yönetimin bakış açısından, doğrudan kazanç elde etmek için büyük bir maliyeti temsil eder.

Sürecin Bir Parçası Yap

Burada bunun oldukça küçük bir değişiklik olduğunu ve aklınızda bazı özel sorunların olduğunu belirtiyorsunuz. Bu durumda genellikle sorun yok derdim, ama çoğumuz aynı zamanda küçük programların kişisel hikayeleri var, neredeyse cerrahi grev düzenlemeleri, sonunda bakım kabusu ve neredeyse kaçırılan ya da patlamış son teslim tarihleri, çünkü Joe Programmer görmedi Kodun arkasındaki nedenlerden ve olmamalıdır bir şeye dokundu.

Bu tür kararları ele almak için bir süreciniz varsa, bunlardan kişisel kenarı atarsınız:

  • Bir şeyleri doğru test ederseniz, eğer kırılırsa daha hızlı anlarsınız,
  • Onları ölçerseniz, iyileşip iyileşmediklerini bileceksiniz,
  • Eğer gözden geçirirseniz, insanları atıp atmadığını bileceksiniz.

Test Kapsamı, Profil Oluşturma ve Veri Toplama Zor

Ancak, elbette, test kodunuz ve metrikleriniz, gerçek kodunuz için kaçınmaya çalıştığınız sorunlardan muzdarip olabilir: doğru şeyleri test ediyor musunuz ve gelecek için doğru şey mi? bir şeyler?

Yine de, genel olarak, ne kadar çok test ederseniz (belirli bir sınıra kadar) ve ölçün, o kadar çok veri toplar ve güvende olursunuz. Kötü benzetme zamanı: araba sürmek gibi düşünün (ya da genel olarak hayat): araba sizi kırarsa ya da birileri bugün kendi arabalarıyla arabaya binerek kendilerini öldürmeye karar verirse, dünyanın en iyi sürücüsü olabilirsiniz. yetenekler yeterli olmayabilir. Hem sizi vurabilecek çevresel şeyler hem de insan hataları önemli.

Kod İncelemeleri Geliştirme Ekibinin Koridor Testleri

Ve bence son kısım anahtardır: kod incelemeleri yapın. Yalnız yaparsan, iyileştirmelerinin değerini bilemezsin. Kod incelemeleri bizim "koridor testi" dir: hem hataları saptamak hem de aşırı mühendislik ve diğer anti-kalıpları tespit etmek ve kodun ekibinizin yeteneklerine uygun olmasını sağlamak için Raymond'un Linus Yasası versiyonunu takip edin . Eğer başka hiç kimsenin anlayamadığı ve bakımını yapamayacağınız "en iyi" kodlara sahip olmanın hiçbir anlamı yoktur ve bu hem şifreli optimizasyonlar hem de 6 katlı derin mimari tasarımlar için geçerlidir.

Kelimeleri kapatırken, unutmayın:

Herkes hata ayıklamanın ilk başta bir program yazmaktan iki kat daha zor olduğunu bilir. Peki, yazarken olabildiğince zekisin, nasıl hata ayıklayacaksın? - Brian Kernighan


"Bozulmadıysa, Onarmayın" refactoring'e karşı çıkıyor. Bir şeyin işe yarayıp yaramadığı ise değiştirilmesinin önemi yok.
Miyamoto Akira,

@MiyamotoAkira: Bu iki hızlı bir şey. Kırık ama oluyor değilse kabul edilebilir ve destek görme olasılığının düşük, olabilir yalnız Yerine üzerine potansiyel yeni böcek veya harcama geliştirme zamanı tanıtan bırakmak kabul edilebilir. Her şey, refactoring'in hem kısa hem de uzun vadeli faydalarını değerlendirmekle ilgilidir. Kesin bir cevap yok, değerlendirme gerektiriyor.
haylem

kabul. Sanırım cümleyi (ve arkasındaki felsefeyi) beğenmedim çünkü refactoring'i varsayılan seçenek olarak görüyorum ve yalnızca çok uzun sürecek ya da çok zor olacak gibi görünüyorsa, o zaman karar vermeyecek / karar verilmelidir. onunla git. Dikkat edin, insanlar tarafından bir şeyleri değiştirmedim, çalışmama rağmen, bunları sürdürmek veya uzatmak zorunda kalmaz en yanlış çözüm oldular.
Miyamoto Akira

@MiyamotoAkira: Kısa cümleler ve görüş bildirimleri çok fazla ifade edemez. Sanırım senin yüzünde olmaları ve bir yandan geliştirilmeleri gerekiyor sanırım. Sık sık büyük bir güvenlik ağı olmasa da ya da çok fazla sebep olmasa bile, kodları olabildiğince sık inceleme ve dokunma faktörü olarak kendim hissediyorum. Eğer kirliyse, temizlersiniz. Fakat benzer şekilde birkaç kez de yandım. Ve hala yanacak. 3. derece olanlar olmadığı sürece, o kadar umursamıyorum, şimdiye kadar uzun vadeli kazançlar için her zaman kısa vadeli yanıklar oldu.
haylem

8

Genel olarak, önce okunabilirliğe ve daha sonra performansa odaklanmalısınız. Çoğu zaman, bu performans optimizasyonları zaten ihmal edilebilir, ancak bakım maliyeti çok büyük olabilir.

Kuşkusuz, tüm "küçük" şeylerin, açıkça belirttiğiniz gibi değiştirilmeleri gerekir, çünkü belirttiğiniz gibi, çoğu zaten derleyici tarafından en iyi duruma getirilir.

Daha büyük optimizasyonlara gelince, optimizasyonların makul performansa ulaşma konusunda gerçekten kritik olma şansı olabilir (şaşırtıcı bir şekilde bu olmasa da). Değişikliklerinizi yapar ve ardından değişikliklerden önce ve sonra kodu profillerim. Yeni kodun önemli performans sorunları varsa, her zaman en iyi duruma getirilmiş sürüme geri dönebilirsiniz;

Her seferinde kodun yalnızca bir bölümünü değiştirin ve her yeniden yapılandırma turundan sonra performansı nasıl etkilediğini görün.


8

Kodun neden optimize edildiğine ve onu değiştirmenin etkisinin ne olduğuna ve kodun genel performans üzerindeki etkisinin ne olacağına bağlıdır. Test değişikliklerini yüklemek için iyi bir yol olup olmadığına da bağlı olmalıdır.

Bu değişikliği yapmadan önce ve sonra ve tercihen üretimde görülene benzer bir yük altında profillemeden yapmamalısınız. Bu, bir geliştirici makinede küçük bir veri alt kümesi kullanmamak veya yalnızca bir kullanıcı sistemi kullanırken test etmek anlamına gelir.

Optimizasyon yakın zamanda yapıldıysa, geliştiriciyle konuşabilir ve sorunun tam olarak ne olduğunu ve uygulamanın optimizasyondan önce ne kadar yavaş olduğunu öğrenebilirsiniz. Bu size optimizasyonun yapılmasının değmeyeceği ve optimizasyonun hangi şartlar için gerekli olduğu hakkında bir çok şey söyleyebilir (örneğin, bütün bir yılı kapsayan bir rapor, değişikliklerinizi test ediyorsanız Eylül veya Ekim aylarına kadar yavaş olmayabilir) Şubat ayında, yavaşlık henüz belirgin olmayabilir ve test geçersiz olabilir).

Optimizasyon oldukça eskiyse, daha yeni yöntemler daha hızlı ve daha okunaklı bile olabilir.

Sonuçta bu patronun için bir sorudur. İyileştirilmiş bir şeyi yeniden düzenlemek ve değişikliğin nihai sonucu etkilememesini sağlamak ve eskiyle kıyaslandığında iyi ya da en azından kabul edilebilir bir şekilde performans göstermesini sağlamak zaman alıcıdır. Birkaç dakikalık kodlama süresinden tasarruf etmek için yüksek riskli bir iş yerine zamanınızı başka alanlarda harcamanızı isteyebilir. Veya kodun anlaşılmasının zor olduğu ve sık müdahaleye ihtiyaç duyduğu ve daha iyi yöntemlerin mevcut olduğu konusunda hemfikir olabilir.


6

eğer profilleme optimizasyonu (kritik bir bölümde değildir) gereksiz olduğunu göstermektedir hatta (kötü prematüre optimizasyonu sonucu olarak) daha kötü bir çalışma zamanını alır, sonra emin korumak daha kolaydır okunabilir kod ile değiştirin

ayrıca kodun uygun testlerle aynı şekilde davrandığından emin olun


5

Bunu iş perspektifinden düşünün. Değişimin maliyeti nedir? Değişikliği yapmak için ne kadar zamana ihtiyacınız var ve kodu genişletmeyi veya sürdürmeyi daha kolay hale getirerek uzun vadede ne kadar tasarruf edeceksiniz? Şimdi o zaman bir fiyat etiketi ekleyin ve performansı düşürerek kaybedilen parayla karşılaştırın. Belki de kayıp performansı telafi etmek için bir sunucu eklemeniz veya yükseltmeniz gerekir. Belki ürün artık gereklilikleri karşılamamaktadır ve artık satılamaz. Belki kayıp yoktur. Belki değişim sağlamlığı arttırır ve başka yerlerde zaman kazandırır. Şimdi kararını ver.

Yan bir notta, bazı durumlarda bir parçanın her iki versiyonunu da tutmak mümkün olabilir. Rasgele girdi değerleri üreten bir test yazabilir ve sonuçları diğer versiyonla doğrulayabilirsiniz. Tamamen anlaşılır ve açık bir şekilde doğru olan çözümün sonucunu kontrol etmek için "akıllı" çözümü kullanın ve böylece yeni çözümün eskisine eşdeğer olduğuna dair bir güvence (ancak kanıt yok) elde edin. Veya diğer tarafa gidin ve zor kodun sonucunu ayrıntılı kodla kontrol edin ve böylelikle hack'in arkasındaki amacı net bir şekilde belgeleyin.


4

Temel olarak, yeniden yapılanmanın değerli bir girişim olup olmadığını soruyorsunuz . Bunun cevabı kesinlikle evet.

Fakat...

... dikkatlice yapmalısın. Yeniden canlandırdığınız herhangi bir kod için sağlam birim, entegrasyon, fonksiyonel ve performans testlerine ihtiyacınız var. Gerekli tüm işlevleri gerçekten test ettiklerinden emin olmanız gerekir. Onları kolayca ve tekrar tekrar çalıştırma yeteneğine ihtiyacınız var. Bunu yaptıktan sonra, bileşenleri eşdeğer işlevselliği içeren yeni bileşenlerle değiştirebilmelisiniz.

Martin Fowler bu konuda kitabı yazdı .


3

Çalışmayı, üretim kodunu iyi bir sebep olmadan değiştirmemelisiniz. "Yeniden düzenleme", işinizi yeniden düzenleme olmadan yapamadığınız sürece, yeterince iyi bir neden değildir . Yaptığınız şey, zor kodun içindeki hataları düzeltmek olsa bile, bunu anlamak ve mümkün olan en küçük değişikliği yapmak için zaman ayırmalısınız. Eğer kodun anlaşılması o kadar zorsa, onu tamamen anlayamazsınız ve yaptığınız herhangi bir değişikliğin tahmin edilemeyecek yan etkileri vardır - böcekler, başka bir deyişle. Değişim ne kadar büyük olursa, sorun yaratma olasılığınız o kadar yüksek olur.

Bunun bir istisnası olacaktı: anlaşılmaz kodun eksiksiz bir birim test seti olsaydı, yeniden değerlendirebilirsiniz. Ünite testleri ile birlikte anlaşılmaz bir kod görmedim ya da hiç duymadığım için, önce ünite testlerini yazıyorsunuz, bu ünite testlerinin gerçekte kodun ne yapması gerektiğini temsil etmesi gerektiği ve bu kodun değişmesi gereken kodun yapılması gerektiğini onaylayan kişilerin anlaşmasını alıyorsunuz. . Bunu bir ya da iki kez yaptım; boyundaki bir ağrı ve çok pahalı, ama sonuçta iyi sonuçlar veriyor.


3

Anlaşılması zor bir şekilde basit bir şey yapan kısa bir kod parçasıysa, "hızlı anlayışı" genişletilmiş bir yorumda ve / veya kullanılmamış bir alternatif uygulamada değiştiririm.

#ifdef READABLE_ALT_IMPLEMENTATION

   double x=0;
   for(double n: summands)
     x += n;
   return x;

#else

   auto subsum = [&](int lb, int rb){
          double x=0;
          while(lb<rb)
            x += summands[lb++];
          return x;
        };
   double x_fin=0;
   for(double nsm: par_eval( subsum
                           , partitions(n_threads, 0, summands.size()) ) )
     x_fin += nsm;
   return x_fin;

#endif

3

Cevap, genel kayıp olmadan, evet. Okunması zor bir kod olduğunda daima modern kod ekleyin ve çoğu durumda hatalı kodu silin. Aşağıdaki işlemi kullanıyorum:

  1. Performans testi ve destekleyici profil bilgisine bakın. Performans testi yoksa, kanıt olmadan neyin iddia edilebileceği kanıt olmadan yok sayılabilir. Modern kodunuzun daha hızlı olduğunu ve eski kodu kaldırın. Eğer biri tartışırsa (kendin bile) onlardan hangisinin daha hızlı olduğunu ispatlamak için profil kodunu yazmalarını isteyin.
  2. Profil kodu varsa, yine de modern kodu yazın. Buna benzer bir isim verin <function>_clean(). Ardından, kodunuzu kötü koda karşı "yarışın". Kodunuz daha iyiyse, eski kodu kaldırın.
  3. Eski kod daha hızlıysa, modern kodunuzu yine de orada bırakın. Diğer kodun yapması gerekenler için iyi bir dokümantasyon görevi görür ve "yarış" kodu orada olduğundan, iki yol arasındaki performans özelliklerini ve farklarını belgelemek için çalıştırmaya devam edebilirsiniz. Kod davranışındaki farklılıklar için birim testi de yapabilirsiniz. Önemli olarak, modern kod bir gün "optimize edilmiş" kodu garantileyecektir. Ardından hatalı kodu kaldırabilirsiniz.

QED.


3

Ölmeden önce dünyaya (Yazılım hakkında) bir şey öğretebilirsem, "X'e karşı Performans" ın Yanlış Bir İkilem olduğunu öğretirdim.

Yeniden kaplama, genellikle okunabilirlik ve güvenilirlik için bir nimet olarak bilinir, ancak en iyi şekilde optimizasyonu da destekleyebilir. Bir dizi yeniden düzenleme işlemi olarak performans iyileştirmesini gerçekleştirdiğinizde, uygulamanın daha hızlı ilerlemesini sağlayarak Kampanya Kuralını da onurlandırabilirsiniz. Aslında, en azından benim görüşüme göre, bunu yapmanın üstüne etik olarak bağlı.

Mesela, bu sorunun yazarı çılgınca bir kod parçasıyla karşılaştı. Bu kişi benim kodumu okuyor olsaydı, çılgın bölümün 3-4 satır uzunluğunda olduğunu bulurlardı. Tek başına bir yöntemdedir ve yöntem adı ve açıklaması, yöntemin ne yaptığını gösterir. Yöntem, çılgınca kodun şüpheli görünmesine rağmen doğru cevabı nasıl aldığını açıklayan 2-6 satırlık satır içi yorum içerecektir.

Bu şekilde bölümlere ayrılmış olarak, bu yöntemin uygulamalarını istediğiniz gibi değiştirmekte özgürsünüz. Nitekim, muhtemelen başlamak için çılgın versiyonu bu şekilde yazdım. Denemek veya en azından alternatifleri sormak için bekliyoruz. Naif uygulamanın farkedilir derecede daha kötü olduğunu fark edeceksiniz (genellikle sadece 2-10x iyileştirme için zahmete giriyorum), fakat derleyiciler ve kütüphaneler her zaman değişiyor ve bugün ne zaman müsait olmadığını öğrenebilecekleri kim biliyor fonksiyon yazıldı mı?


Çoğu durumda verimliliğin önemli bir anahtarı, bir kodun verimli bir şekilde yapılabilecek şekillerde mümkün olduğu kadar çok işi yapmasıdır. Beni .NET ile rahatsız eden şeylerden biri, örneğin bir koleksiyonun bir bölümünü diğerine kopyalamak için etkili mekanizmaların bulunmamasıdır. Koleksiyonların çoğu dizilerde ardışık öğe gruplarını (tümü olmasa da) saklar; bu nedenle, örneğin son 5.000 öğeyi 50.000 öğe listesinden kopyalamak, birkaç toplu kopyalama işleminde (yalnızca bir tane değilse) artı birkaç diğerinde ayrıştırılmalıdır. adımlar en fazla bir kaç kez yapılır.
supercat

Ne yazık ki, bu tür işlemlerin verimli bir şekilde gerçekleştirilmesi mümkün olduğunda bile, genellikle "hacimli" ilmeklerin 5.000 ite (ve bazı durumlarda 45.000!) Çalıştırılması gerekli olacaktır. Bir işlem toplu dizi kopyaları gibi şeylere azaltılabiliyorsa, bunlar büyük kazanç sağlayacak şekilde aşırı derecelere optimize edilebilir. Her döngü yinelemesinin bir düzine adım atması gerekiyorsa, bunlardan herhangi birini özellikle iyi bir şekilde optimize etmek zordur.
supercat,

2

Muhtemelen dokunmak iyi bir fikir değildir - kod performans nedenleriyle bu şekilde yazılsaydı, değiştirmenin daha önce çözülmüş olan performans sorunlarını geri getirebileceği anlamına gelir.

Eğer varsa do daha okunabilir ve uzanacak şekilde şeyleri değiştirmeye karar: Eğer altında bir değişiklik, kriter eski kod yapmadan önce ağır yük. Daha da iyisi, bu garip görünen kodun düzeltmesi gereken performans sorununu tanımlayan eski bir belge veya sorunlu bilet bulabilirseniz. Sonra değişikliklerinizi yaptıktan sonra, performans testlerini tekrar çalıştırın. Çok farklı değilse veya hala kabul edilebilir parametreler dahilindeyse, muhtemelen sorun yok.

Bazen, bir sistemin diğer bölümleri değiştiğinde, bu performans optimizasyonlu kodun artık böyle ağır optimizasyonlara ihtiyaç duymadığı, ancak kesin bir test yapılmadan kesin olarak bunu bilmenin bir yolu olmadığı ortaya çıkabilir.


1
Şimdi birlikte çalıştığım adamlardan biri , eğer sık ​​sık kullanıyorsa, kullanıcıların ayda bir kez vurduğu alanlarda işleri optimize etmeyi seviyor . Zaman alıyor ve nadiren başka sorunlara neden oluyor çünkü kodlama ve taahhüt etmeyi seviyor ve KG veya diğer aşağı akış fonksiyonunun gerçekten test etmesine izin veriyor. : / Adil olmak gerekirse, genellikle hızlı, hızlı ve doğru, ama bu kuruş ante "optimizasyonları" sadece ekibin geri kalanı için işleri zorlaştırıyor ve kalıcı ölümleri İyi Bir Şey olacaktı.
DaveE

@DaveE: Bu optimizasyonlar gerçek performans sorunları nedeniyle mi uygulanıyor? Yoksa bu geliştirici bunu yapabildiği için mi yapıyor? Ne olursa sanırım biliyorum optimizasyon bir etkisi gidiş değildir, güvenle daha okunabilir kod ile değiştirebilirsiniz, ama ben sadece bunu sistem üzerinde bir uzman olan birini emanet ederim.
SinirliFormsDesigner ile

Yapıldı çünkü yapabilir. Genelde bazı döngüleri kurtarıyor, ancak program elemanı ile kullanıcı etkileşimi birkaç saniye sürdüğünde (15 ila 300-s), “verimlilik” peşinde koşarken saniyenin onda birini tıraş etmek saçma. Özellikle de onu takip eden insanlar ne yaptığını anlamak için gerçek zaman almak zorunda kaldıklarında. Bu, aslında 16 yıl önce inşa edilmiş bir PowerBuilder uygulamasıdır, bu yüzden zihniyetin belki de anlaşılabilir olduğu şeylerin ortaya çıkması göz önüne alındığında, ama zihniyetini mevcut gerçeklikle güncellemeyi reddediyor.
DaveE

@DaveE: Sanırım birlikte çalıştığınız adama sizden daha çok katılıyorum. Herhangi bir nedenden ötürü yavaş olan şeyleri tamir etmeme izin verilmiyorsa deliririm. Bir dizgiyi bir araya getirmek için sürekli olarak + operatörünü kullanan bir C ++ satırı görürsem ya da sadece bir bayrak ayarlamayı unuttuğu için döngüde her seferinde açıp / dev / urandomu okuyan ve okuyan bir kod varsa onu düzeltirim. Bu konuda fanatik olarak, başkalarının her seferinde bir mikrosaniye kaydırmasına izin verdiğinde hızlanmayı başardım.
Zan Lynx,

1
Tamam, aynı fikirde olmayacağız. Gerçekten geliştiren ve diğer geliştiriciler için kafa kafaya çizilen bir şekilde kod bırakan bir işlev için çalışma süresinde kesirli saniye tasarrufu sağlayacak bir şeyi bir saat harcamak doğru değildir. Bunlar, uygulamanın yüksek stresli kısımlarında art arda yürütülen işlevlerse, ince ve zeki. Ama tarif ettiğim durum bu değil. Bu gerçekten dehşet verici bir kod, "UserX'in haftada bir kez fraksiyonel olarak daha hızlı bir şekilde yaptığı şeyi yaptım" demekten başka bir sebep olmadan sonlandırmadır. Bu arada, yapması gereken işleri ödüyoruz.
DaveE

2

Buradaki sorun "optimize edilmiş" ifadesini okunabilir ve genişletilebilir olmaktan farklı kılıyor; kullanıcıların optimize edilmiş kod olarak gördüklerini ve derleyicinin optimize edilmiş olarak gördüklerini iki farklı şey olarak görüyoruz. Değiştirmek istediğiniz kod hiçbir şekilde tıkanıklık olmayabilir ve bu nedenle kod "zayıf" olsa bile "optimize edilmesi" gerekmez. Veya kod yeterince eskiyse, derleyicinin daha eski basit bir yapı yapısını eski koddan eşit veya daha verimli şekilde kullanmasını sağlayan yerleşiklerde optimizasyonlar olabilir.

Ve "yalın" okunamayan kod her zaman optimize edilmez.

Zekice / yalın kodun iyi bir kod olduğu fikrindeydim, ama bazen kod oluşturmada yardım etmek yerine dilin gizlenmiş kurallarından faydalandığımda, herhangi bir gömülü işden daha fazla ısırılmaya çalıştım. zeki olun, çünkü derleyici akıllı kodunuzu gömülü donanım tarafından tamamen kullanılamayan bir şey haline getirir.


2

Optimize edilmiş kodu hiçbir zaman Okunabilir kodla değiştirmeyeceğim, çünkü performanstan ödün veremem ve her bir bölümde uygun yorumlamayı kullanmayı tercih edeceğim, böylece her iki sorunu da çözecek olan bu Optimize edilmiş bölümde uygulanan mantığı herkes anlayabilir.

Bu nedenle, Kod Optimize Edilecek + Doğru Yorumlama onu Okunabilir hale getirecektir.

NOT: Bir Optimize Edilmiş Kodu, uygun yorumların yardımıyla okunabilir hale getirebilirsiniz, ancak Okunabilir Kodları En İyileştirilmiş Kod haline getiremezsiniz.


Bu yaklaşımdan bıkacağım çünkü tek yapmanız gereken yorumun senkronize edilmesini sağlamak için kodu düzenleyen bir kişi. Birden bire sonraki incelemeler, Y'yi yaparken X gerçekleştirdiğini düşünerek uzaklaşacaktır.
John D

2

Basit kod ve optimize kod arasındaki farkı görmek için bir örnek: https://stackoverflow.com/a/11227902/1396264

cevabın sonuna doğru o sadece değiştirir:

if (data[c] >= 128)
    sum += data[c];

ile:

int t = (data[c] - 128) >> 31;
sum += ~t & data[c];

Adil olmak gerekirse, if ifadesinin ne değiştirildiği hakkında hiçbir fikrim yok, ancak cevaplayan aynı bit sonuçlarına göre bazı bit işlemlerini söylediği için (sadece bunun için onun sözünü alacağım) .

Bu işlem, orijinal zamanın dörtte birinden daha kısa sürede gerçekleştirilir (11.54sn - 2.5sn)


1

Buradaki asıl soru şudur: optimizasyon gerekli midir?

Öyleyse, daha yavaş, daha okunaklı kodla değiştiremezsiniz. Daha okunaklı hale getirmek için yorum vb. Eklemeniz gerekir.

Kodun optimize edilmesi gerekmiyorsa, o zaman (okunabilirliği etkileyen noktaya kadar) olmamalı ve onu daha okunaklı hale getirmek için yeniden faktörlendirebilirsiniz.

Bununla birlikte - bir şeyleri değiştirmeden önce tam olarak ne yaptığınızı ve nasıl baştan sona test edeceğinizi bildiğinizden emin olun. Bu, en yoğun kullanımı vb. İçerir. Bir dizi test durumu oluşturmak ve bunları daha önce ve sonra çalıştırmak zorunda kalmazsanız, yeniden düzenleme yapmak için zamanınız olmaz.


1

İşleri böyle yaparım: İlk önce okunabilir kodda çalışmasını sağlarım, sonra onu optimize ederim. Orijinal kaynağı saklıyorum ve optimizasyon adımlarını belgeliyorum.

Sonra bir özellik eklemem gerektiğinde okunabilir koduma geri dönerim, özelliği ekler ve belgeledim optimizasyon adımlarını uygularım. Belgelendirdiğiniz için, kodunuzu yeni özellikle yeniden düzenlemek gerçekten hızlı ve kolaydır.


0

IMHO okunabilirliği, optimize edilmiş koddan daha önemlidir, çünkü çoğu durumda mikro-optimizasyon buna değmez.

Anlamsız mikro optimizasyonlar hakkında makale :

Çoğumuz olarak, baskıyı yankı ile değiştirmek, ++ $ i $ i ++ ile ya da tekli tırnaklarla çift tırnak gibi anlamsız mikro optimizasyonlarla ilgili blog yazılarını okumaktan yoruldum. Neden? Çünkü zamanın% 99,999999'u alakasız.

"print", "echo" dan bir tane daha opcode kullanır çünkü gerçekte bir şey döndürür. Echo'nun baskıdan daha hızlı olduğu sonucuna varabiliriz. Fakat bir opcode hiçbir şeye mal olmaz, gerçekten hiçbir şeye mal olmaz.

Yeni bir WordPress kurulumunda denedim. Komut dizisi bilgisayarımda "Bus Error" ile bitmeden önce duruyor, ancak opcod sayısı zaten 2.3 milyondan fazlaydı. Yeterince söylendi.


0

Optimizasyon görecelidir. Örneğin:

Bir sürü BOOL üyesi olan bir sınıfı düşünün:

// no nitpicking over BOOL vs bool allowed
class Pear {
 ...
 BOOL m_peeled;
 BOOL m_sliced;
 BOOL m_pitted;
 BOOL m_rotten;
 ...
};

BOOL alanlarını bit alanlarına dönüştürmek isteyebilirsiniz:

class Pear {
 ...
 BOOL m_peeled:1;
 BOOL m_sliced:1;
 BOOL m_pitted:1;
 BOOL m_rotten:1;
 ...
};

Bir BOOL, INT olarak tanımlandığından (Windows platformlarında işaretli bir 32 bit tam sayıdır), bu onaltı baytı alır ve bunları bir araya getirir. Bu% 93 tasarruf! Bundan kim şikayet edebilir?

Bu varsayım:

Bir BOOL, INT olarak tanımlandığından (Windows platformlarında işaretli bir 32 bit tam sayıdır), bu onaltı baytı alır ve bunları bir araya getirir. Bu% 93 tasarruf! Bundan kim şikayet edebilir?

yol açar:

Bir BOOL'u tek bitlik bir alana dönüştürmek, üç baytlık veriyi kaydetti ancak üyeye sabit olmayan bir değer atandığında size sekiz baytlık bir kod maliyeti verdi. Benzer şekilde, değeri çıkarmak daha pahalı hale gelir.

Ne olmak için kullanılan

 push [ebx+01Ch]      ; m_sliced
 call _Something@4    ; Something(m_sliced);

olur

 mov  ecx, [ebx+01Ch] ; load bitfield value
 shl  ecx, 30         ; put bit at top
 sar  ecx, 31         ; move down and sign extend
 push ecx
 call _Something@4    ; Something(m_sliced);

Bitfield sürümü dokuz bayt daha büyük.

Hadi oturup biraz aritmetik yapalım. Bu bit alanlı alanların her birine kodunuzda altı kez, yazışma için üç kez ve okuma için üç kez erişildiğini varsayalım. Kod büyümesindeki maliyet yaklaşık 100 bayttır. Tam olarak 102 bayt olmayacaktır, çünkü optimizer bazı işlemler için halihazırda kayıtlı olan değerlerden faydalanabilir ve ek talimatlar azaltılmış kayıt esnekliği açısından gizli maliyetlere sahip olabilir. Asıl fark daha fazla olabilir, daha az olabilir, ancak bir zarf arkası hesaplaması için bunu 100 olarak adlandıralım. Bu arada, bellek tasarrufu sınıf başına 15 bayttır. Bu nedenle, başlangıç ​​noktası yedi. Programınız bu sınıfın yediden az örneğini oluşturursa, kod maliyeti veri tasarruflarını aşıyor: Bellek optimizasyonunuz bir bellek optimizasyonuydu.

Referanslar

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.