Kod Optimizasyonu: Optimize Etmenin En İyi Yolu
Yayınlanan: 2022-03-11Performans optimizasyonu, kodunuz için en büyük tehditlerden biridir.
Düşünüyor olabilirsiniz, o insanlardan biri değil . Anladım. Her türlü optimizasyon, etimolojisine bakılırsa, açıkça iyi bir şey olmalıdır, bu yüzden doğal olarak, bunda iyi olmak istersiniz.
Sadece kendinizi daha iyi bir geliştirici olarak diğerlerinden ayırmak için değil. Sadece The Daily WTF'de “Dan” olmaktan kaçınmak için değil, aynı zamanda kod optimizasyonunun Yapılacak Doğru Şey olduğuna inandığınız için. İşinle gurur duyuyorsun.
Bilgisayar donanımı hızlanmaya devam ediyor ve yazılım yapmak daha kolay, ancak Yapabilmek İstediğiniz Basit şey ne olursa olsun , Lanet olsun her zaman bir öncekinden daha uzun sürer. Bu fenomene (tesadüfen Wirth Yasası olarak bilinir) başınızı sallarsınız ve bu eğilimi kırmaya karar verirsiniz.
Bu çok asilce ama dur.
Sadece dur!
Programlamada ne kadar deneyimli olursanız olun, kendi hedeflerinizi engelleme tehlikesiyle karşı karşıyasınız.
Nasıl yani? Geri çekilelim.
Her şeyden önce , kod optimizasyonu nedir?
Çoğu zaman, onu tanımladığımızda, kodun daha iyi performans göstermesini istediğimizi varsayıyoruz. Kod optimizasyonunun, bir programın mümkün olan en az bellek veya disk alanını kullanması, CPU süresini veya ağ bant genişliğini en aza indirmesi veya ek çekirdeklerden en iyi şekilde yararlanması için kod yazma veya yeniden yazma olduğunu söylüyoruz.
Pratikte bazen başka bir tanıma geçiyoruz: Daha az kod yazmak.
Ancak, bu amaçla yazdığınız önleyici olarak kötü kodun, birinin tarafında bir diken haline gelmesi daha olasıdır. Kimin? Kodunuzu anlaması gereken bir sonraki şanssız kişi, hatta kendiniz bile olabilir. Ve sizin gibi akıllı ve yetenekli biri, kendi kendini sabote etmekten kaçınabilir: Amaçlarınızı asil tutun, ancak tartışmasız sezgisel görünseler de araçlarınızı yeniden değerlendirin.
Yani kod optimizasyonu biraz belirsiz bir terimdir. Bu, kodu optimize etmenin diğer yollarından bazılarını düşünmeden önce, aşağıda anlatacağız.
Jackson'ın ünlü kod optimizasyon kurallarını birlikte keşfederken, bilgelerin tavsiyelerini dinleyerek başlayalım:
- yapma.
- (Yalnızca uzmanlar için!) Henüz yapmayın.
1. Yapmayın: Mükemmeliyetçiliği Yönlendirmek
Uzun zaman önce, SQL'in harika, pastanı ye ve onu da ye dünyasında ayaklarımı ıslattığım bir zamandan oldukça utanç verici derecede uç bir örnekle başlayacağım. Sorun şu ki, daha sonra pastanın üzerine bastım ve ıslak olduğu ve ayak gibi kokmaya başladığı için daha fazla yemek istemedim.
SQL'in harika, pastanı ye ve onu da ye dünyasında ayaklarımı ıslatıyordum. Sorun şu ki, daha sonra pastanın üzerine bastım…
Beklemek. Az önce yaptığım ve açıkladığım bir metaforun bu araba kazasından çıkmama izin verin.
Bir gün çalıştığım küçük işletme için tamamen entegre bir yönetim sistemi olacağını umduğum bir intranet uygulaması için Ar-Ge yapıyordum. Onlar için her şeyi takip edecek ve o zamanki mevcut sistemlerinden farklı olarak, verilerini asla kaybetmeyecekti, çünkü diğer geliştiricilerin kullandığı lapa lapa evde yetiştirilen düz dosya şeyi değil, bir RDBMS tarafından desteklenecekti. Her şeyi mümkün olduğunca akıllı tasarlamak istedim çünkü boş bir sayfam vardı. Bu sistemle ilgili fikirler kafamda havai fişekler gibi patlıyordu ve bir CRM, muhasebe modülleri, envanter, satın alma, CMS ve proje yönetimi için tablo—kontaklar ve bunların pek çok bağlamsal varyasyonunu tasarlamaya başladım, ki bunu yakında test edeceğim.
Her şeyin durma noktasına gelmesi, geliştirme ve performans açısından, çünkü… tahmin ettiniz, optimizasyon.
Nesnelerin (tablo satırları olarak temsil edilir) gerçek dünyada birbirleriyle birçok farklı ilişkisi olabileceğini ve bu ilişkileri izlemekten fayda sağlayabileceğimizi gördüm: Daha fazla bilgi tutabilir ve sonunda iş analizini her yerde otomatikleştirebilirdik. Bunu bir mühendislik problemi olarak görerek, sistemin esnekliğinin optimizasyonu gibi görünen bir şey yaptım.
Bu noktada yüzünüze dikkat etmeniz önemli çünkü avucunuz ağrırsa sorumlu tutulamam. Hazır? İki tablo oluşturdum: relationship
ve bir tanesinde yabancı anahtar referansı vardı, relationship_type
. relationship
, tüm veritabanındaki herhangi bir iki satıra atıfta bulunabilir ve aralarındaki ilişkinin doğasını açıklayabilir.
Ah, dostum. Bu esnekliği o kadar çok optimize etmiştim ki.
Aslında çok fazla. Şimdi yeni bir sorunum vardı: belirli bir relationship_type
türü, verilen her satır kombinasyonu arasında doğal olarak bir anlam ifade etmeyecekti. Bir person
bir company
ilişkisi olan bir employed by
olması mantıklı olsa da, bu asla iki document
arasındaki ilişkiye anlamsal olarak eşdeğer olamaz.
Tamam sorun değil. Bu ilişkinin hangi tablolara uygulanabileceğini belirterek relationship_type
tipine iki sütun ekleyeceğiz. (Bunu, bu iki sütunu ilişki_tipi.id 'ye atıfta bulunan yeni bir tabloya taşıyarak normalleştirmeyi düşündüğümü tahmin ederseniz, bonus puanlar, böylece anlamsal olarak birden fazla tablo çiftine uygulanabilecek relationship_type.id
tablo adları çoğaltılmaz. Ne de olsa, bir tablo adını değiştirmem gerekirse ve geçerli tüm satırlarda güncellemeyi unutursam, bu bir hata oluşturabilir! Geriye dönüp baktığımda, en azından böcekler kafatasımda yaşayan örümcekler için yiyecek sağlayabilirdi.)
Neyse ki, bu yolda çok fazla ilerlemeden önce bir ipucu fırtınasında bilincimi kaybettim. Uyandığımda, RDBMS'nin dahili yabancı anahtarla ilgili tablolarını aşağı yukarı yeniden uygulamayı başardığımı fark ettim. Normalde, "Ben çok metayım" diye küstahça ilan etmemle biten anlardan hoşlanırım ama bu, ne yazık ki, onlardan biri değildi. Ölçeklendirmeyi unutun — bu tasarımın korkunç şişkinliği, DB'si henüz herhangi bir test verisiyle neredeyse hiç doldurulmamış olan hala basit uygulamamın arka ucunu neredeyse kullanılamaz hale getirdi.
Bir saniyeliğine geri çekilelim ve burada geçerli olan birçok ölçümden ikisine bir göz atalım. Biri, belirttiğim hedefim olan esneklik. Bu durumda, doğada mimari olan optimizasyonum erken bile değildi:
(Son zamanlarda yayınlanan Prematüre Optimizasyonun Lanetinden Nasıl Kaçınılır başlıklı makalemde buna daha fazla değineceğiz.) Bununla birlikte, çözümüm çok esnek olduğu için olağanüstü bir şekilde başarısız oldu. Diğer ölçüt, ölçeklenebilirlik, henüz düşünmediğim bir ölçüydü, ancak en azından ikincil hasarla olağanüstü bir şekilde yok etmeyi başardı.
Bu doğru, "Ah."
Bu, optimizasyonun nasıl tamamen ters gidebileceğine dair bana güçlü bir ders oldu. Mükemmeliyetçiliğim tamamen çöktü: Zekiliğim, şimdiye kadar yaptığım nesnel olarak en akıllıca olmayan çözümlerden birini üretmeme yol açtı.
Kodunuzu Değil, Alışkanlıklarınızı Optimize Edin
Doğruluğunu kanıtlamak için çalışan bir prototipiniz ve test takımınız bile olmadan önce kendinizi yeniden düzenleme eğilimindeyken yakalarken, bu dürtüyü başka nereye yönlendirebileceğinizi düşünün. Sudoku ve Mensa harika ama belki de projenize doğrudan fayda sağlayacak bir şey daha iyi olabilir:
- Güvenlik
- Çalışma zamanı kararlılığı
- Netlik ve stil
- kodlama verimliliği
- Test etkinliği
- profil oluşturma
- Araç setiniz/DE
- KURU (Kendinizi Tekrar Etmeyin)
Ancak dikkatli olun: Bunlardan herhangi birini optimize etmek, diğerlerinin pahasına olacaktır. En azından, zaman pahasına gelir.
Kod oluşturmada ne kadar sanat olduğunu burada kolayca görebilirsiniz. Yukarıdakilerden herhangi biri için, size bunun ne kadar çok veya çok azının yanlış seçim olduğu konusunda hikayeler anlatabilirim. Burada düşünmeyi kimin yaptığı da bağlamın önemli bir parçasıdır.
Örneğin, DRY ile ilgili olarak: Sahip olduğum bir işte, en az %80 gereksiz ifadelerden oluşan bir kod tabanını devraldım, çünkü yazarı görünüşe göre bir işlevi nasıl ve ne zaman yazacağını bilmiyordu. Kodun diğer %20'si kafa karıştırıcı bir şekilde kendine benziyordu.
Ona birkaç özellik eklemekle görevlendirildim. Böyle bir özelliğin, uygulanacak tüm kod boyunca tekrarlanması gerekecek ve yeni özelliği kullanmak için gelecekteki herhangi bir kodun dikkatli bir şekilde kopyalanması gerekecekti.
Açıkçası, sadece kendi akıl sağlığım (yüksek değer) ve gelecekteki geliştiriciler için yeniden düzenlenmesi gerekiyordu. Ancak, kod tabanında yeni olduğum için, yeniden düzenlememin herhangi bir gerileme getirmediğinden emin olmak için önce testler yazdım. Aslında, tam da bunu yaptılar: Yol boyunca, senaryonun ürettiği tüm saçma sapan çıktılar arasında fark etmeyeceğim iki hata yakaladım.
Sonunda, oldukça iyi yaptığımı düşündüm. Yeniden düzenlemeden sonra, zor olarak kabul edilen bir özelliği birkaç basit kod satırıyla uygulayarak patronumu etkiledim; dahası, kod genel olarak daha performanslıydı. Ama çok geçmeden aynı patron bana çok yavaş davrandığımı ve projenin çoktan bitmiş olması gerektiğini söyledi. Tercüme: Kodlama verimliliği daha yüksek bir öncelikti.
Dikkat: Herhangi bir belirli [yön] heck'i optimize etmek, başkalarının pahasına olacaktır. En azından, zaman pahasına gelir.
Kod optimizasyonu o sırada patronum tarafından doğrudan takdir edilmemiş olsa bile, hala orada doğru kursu aldığımı düşünüyorum. Yeniden düzenleme ve testler olmadan, gerçekten düzeltmenin daha uzun süreceğini düşünüyorum - yani, kodlama hızına odaklanmak onu gerçekten engellerdi. (Hey, bu bizim temamız!)
Bunu küçük bir yan projemde yaptığım bazı çalışmalarla karşılaştırın. Projede, yeni bir şablon motoru deniyordum ve yeni şablon motorunu denemek projenin nihai hedefi olmasa da, baştan iyi alışkanlıklar edinmek istedim.
Eklediğim birkaç bloğun birbirine çok benzediğini ve ayrıca her bloğun aynı değişkene üç kez atıfta bulunması gerektiğini fark ettiğim anda kafamda DRY zili çaldı ve doğru olanı bulmak için yola koyuldum. bu şablon motoruyla yapmaya çalıştığım şeyi yapmanın yolu.
Birkaç saatlik sonuçsuz hata ayıklamadan sonra, bunun şu anda hayal ettiğim şekilde şablon motoruyla mümkün olmadığı ortaya çıktı. Sadece mükemmel bir DRY çözümü yoktu; hiç KURU çözüm yoktu!
Bu tek değerimi optimize etmeye çalışırken, kodlama verimliliğimi ve mutluluğumu tamamen raydan çıkardım, çünkü bu sapma projeme o gün sahip olabileceğim ilerlemeye mal oldu.
O zaman bile, tamamen yanılmış mıydım? Bazen, özellikle yeni bir teknoloji bağlamında, en iyi uygulamaları daha sonra değil, daha erken tanımak için biraz yatırım yapmaya değer. Yeniden yazılacak daha az kod ve geri alınacak kötü alışkanlıklar, değil mi?
Hayır, önceki anekdottaki tavrımın tam tersine, kodumdaki tekrarı azaltmanın bir yolunu aramanın bile akıllıca olmadığını düşünüyorum. Bunun nedeni, bağlamın her şeydir: Küçük bir oyun projesinde yeni bir teknoloji parçası keşfediyordum, uzun bir süre için yerleşmedim. Fazladan birkaç satır ve tekrardan kimseye zarar gelmezdi ama odak kaybı bana ve projeme zarar verdi.
Bekle, yani en iyi uygulamaları aramak kötü bir alışkanlık olabilir mi? Ara sıra. Ana hedefim yeni motoru öğrenmek veya genel olarak öğrenmek olsaydı, o zaman bu iyi harcanmış bir zaman olurdu: Kurcalamak, sınırları bulmak, ilgisiz özellikleri keşfetmek ve araştırma yoluyla elde etmek. Ama asıl amacımın bu olmadığını unutmuştum ve bana pahalıya mal oldu.
Dediğim gibi bu bir sanat. Ve bu sanatın gelişimi, " Yapma " hatırlatmasından yararlanır. En azından, çalışırken hangi değerlerin etkin olduğunu ve hangilerinin sizin bağlamınızda sizin için en önemli olduğunu düşünmenizi sağlar.
Peki ya o ikinci kural? Gerçekte ne zaman optimize edebiliriz?
2. Henüz Yapmayın: Biri Bunu Zaten Yaptı
Tamam, sizin tarafınızdan veya bir başkası tarafından, mimarinizin zaten ayarlandığını, veri akışlarının düşünüldüğünü ve belgelendiğini ve kodlamanın zamanı geldiğini görüyorsunuz.
Bir adım daha ileri gitmeyin : Henüz kodlamayın bile .
Bunun kendisi erken optimizasyon gibi kokabilir, ancak bu önemli bir istisnadır. Niye ya? Korkunç NIHS veya "Burada Bulunmadı" Sendromundan kaçınmak için - önceliklerinizin kod performansını ve geliştirme süresini en aza indirmeyi içerdiğini varsayarsak. Değilse, hedefleriniz tamamen öğrenme odaklıysa bir sonraki bölümü atlayabilirsiniz.
İnsanların sırf kibirden kare tekerleği yeniden icat etmeleri mümkün olsa da, sizin ve benim gibi dürüst, alçakgönüllü insanların bu hatayı yalnızca elimizdeki tüm seçenekleri bilmeyerek yapabileceğine inanıyorum. Yığınınızdaki her API ve aracın her seçeneğini bilmek ve bunlar büyüdükçe ve geliştikçe bunların üstünde tutmak kesinlikle çok fazla iş gerektirir.
Ancak, sizi uzman yapan ve tarih-saat hesaplayıcıları veya dize manipülatörlerine yönelik büyüleyici yaklaşımları tarafından geride bırakılan yıkım izi nedeniyle lanetlenen ve alay edilen CodeSOD'daki zilyonuncu kişi olmanızı engelleyen şey, bu zamanı bir araya getirmektir.
(Bu genel kalıba iyi bir kontrpuan eski Java Calendar
API'dir, ancak o zamandan beri düzeltildi.)
Standart Kitaplığınızı Kontrol Edin, Çerçevenizin Ekosistemini Kontrol Edin, Sorununuzu Zaten Çözen FOSS'u Kontrol Edin
Muhtemelen, uğraştığınız kavramların oldukça standart ve iyi bilinen adları vardır, bu nedenle hızlı bir internet araması size çok zaman kazandıracaktır.
Örnek olarak, yakın zamanda bir masa oyunu için yapay zeka stratejilerinin bazı analizlerini yapmaya hazırlanıyordum. Bir sabah, hatırladığım belirli bir kombinatorik kavramını kullanırsam, planladığım analizin daha verimli bir şekilde yapılabileceğini fark ederek uyandım. Şu anda bu kavramın algoritmasını kendim bulmakla ilgilenmediğimden, aranacak doğru adı bilerek zaten öndeydim. Ancak, yaklaşık 50 dakikalık bir araştırmadan ve bazı ön kodları denedikten sonra, bulduğum yarı bitmiş sözde kodu doğru bir uygulamaya dönüştürmeyi başaramadığımı gördüm. (Yazarın yanlış algoritma çıktısını varsaydığı, varsayımları eşleştirmek için algoritmayı yanlış uyguladığı, yorum yapanların buna işaret ettiği ve yıllar sonra hala düzeltilmediği bir blog yazısı olduğuna inanabiliyor musunuz?) O noktada, sabah çayım başladı ve [name of concept] [my programming language]
. 30 saniye sonra, GitHub'dan aldığım kanıtlanabilir şekilde doğru kodum vardı ve aslında yapmak istediğim şeye geçiyordum. Sadece spesifik olmak ve dili dahil etmek, onu kendim uygulamak zorunda kalacağımı varsaymak yerine, her şey demekti.
Veri Yapınızı Tasarlama ve Algoritmanızı Uygulama Zamanı
…yine, kod golf oynama. Gerçek dünya projelerinde doğruluk ve netliğe öncelik verin.
Tamam, baktınız ve probleminizi çözen alet zincirinize yerleşik veya web'de serbestçe lisanslanmış hiçbir şey yok. Sen kendin çıkarsın.
Sorun yok. Bu sırayla, tavsiye basittir:
- Acemi bir programcıya açıklaması basit olacak şekilde tasarlayın.
- Bu tasarımın ürettiği beklentilere uyan bir test yazın.
- Acemi bir programcının tasarımı ondan kolayca çıkarabilmesi için kodunuzu yazın.
Basit, ama belki de takip etmesi zor. İşte burada kodlama alışkanlıkları ve kod kokuları, sanat, zanaat ve zarafet devreye giriyor. Bu noktada yaptığınız işin bir mühendislik yönü olduğu açık, ancak yine de kod golfü oynamayın. Gerçek dünya projelerinde doğruluk ve netliğe öncelik verin.
Videoları beğendiyseniz, yukarıdaki adımları az çok izleyen biri karşınızda. Videodan hoşlanmayanlar için özetleyeceğim: Bu, bir Google iş görüşmesinde yapılan bir algoritma kodlama testidir. Görüşülen kişi önce algoritmayı iletişim kurması kolay bir şekilde tasarlar. Herhangi bir kod yazmadan önce, çalışan bir tasarımın beklediği çıktının örnekleri vardır. Sonra kod doğal olarak takip eder.
Testlere gelince, bazı çevrelerde test odaklı geliştirmenin çekişmeli olabileceğini biliyorum. Bence bunun nedeninin bir kısmı aşırıya kaçabilir, gelişim zamanından fedakarlık noktasına kadar dini olarak takip edilebilir. (Yine en baştan bir değişkeni bile çok fazla optimize etmeye çalışarak kendimizi ayağımıza çekiyoruz.) Kent Beck bile TDD'yi bu kadar uç noktalara götürmez ve aşırı programlamayı icat etmiş ve TDD'nin kitabını yazmıştır. Çıktınızın doğru olduğundan emin olmak için basit bir şeyle başlayın. Sonuçta, yine de kodlamadan sonra bunu manuel olarak yapacaksınız, değil mi? (Kodunuzu ilk yazdıktan sonra bile çalıştıramayacak kadar rock yıldızı bir programcıysanız özür dilerim. Bu durumda, belki kodunuzun gelecekteki koruyucularını bir testle bırakmayı düşünebilirsiniz, böylece onların almayacaklarını bilirsiniz. harika uygulamanızı bozun.) Dolayısıyla, yerinde bir testle manuel, görsel bir fark yapmak yerine, bilgisayarın bu işi sizin için yapmasına zaten izin veriyorsunuz.
Algoritmalarınızı ve veri yapılarınızı uygulamanın oldukça mekanik süreci sırasında, satır satır optimizasyon yapmaktan kaçının ve özel bir alt düzey dil extern kullanmayı düşünmeyin (C, C'de kodlıyorsanız Montaj 'Perl'de kodlama vb.) bu noktada. Nedeni basit: Algoritmanız tamamen değiştirilirse - ve bunun gerekli olup olmadığını sürecin ilerleyen zamanlarına kadar öğrenemezsiniz - o zaman düşük seviyeli optimizasyon çabalarınızın sonunda hiçbir etkisi olmaz.
Bir ECMAScript Örneği
Mükemmel topluluk kodu inceleme sitesi execism.io'da, yakın zamanda, tekilleştirme veya netlik için optimizasyon yapmayı açıkça öneren bir alıştırma buldum. Tekilleştirme için optimize ettim, sadece DRY'yi (yukarıda bahsettiğim gibi, aksi takdirde faydalı bir kodlama zihniyetini) çok ileri götürürseniz işlerin ne kadar saçma olabileceğini göstermek için. İşte kodum neye benziyordu:
const zeroPhrase = "No more"; const wallPhrase = " on the wall"; const standardizeNumber = number => { if (number === 0) { return zeroPhrase; } return '' + number; } const bottlePhrase = number => { const possibleS = (number === 1) ? '' : 's'; return standardizeNumber(number) + " bottle" + possibleS + " of beer"; } export default class Beer { static verse(number) { const nextNumber = (number === 0) ? 99 : (number - 1); const thisBottlePhrase = bottlePhrase(number); const nextBottlePhrase = bottlePhrase(nextNumber); let phrase = thisBottlePhrase + wallPhrase + ", " + thisBottlePhrase.toLowerCase() + ".\n"; if (number === 0) { phrase += "Go to the store and buy some more"; } else { const bottleReference = (number === 1) ? "it" : "one"; phrase += "Take " + bottleReference + " down and pass it around"; } return phrase + ", " + nextBottlePhrase.toLowerCase() + wallPhrase + ".\n"; } static sing(start = 99, end = 0) { return Array.from(Array(start - end + 1).keys()).map(offset => { return this.verse(start - offset); }).join('\n'); } }
Orada neredeyse hiç dize kopyası yok! Bu şekilde yazarak, bira şarkısı için (ancak yalnızca bira şarkısı için) bir metin sıkıştırma biçimini manuel olarak uyguladım. Tam olarak faydası neydi? Diyelim ki şişe yerine kutudan bira içmek hakkında şarkı söylemek istiyorsunuz. Bunu, tek bir bottle
örneğini can
.
Güzel!
…Sağ?
Hayır, çünkü o zaman tüm testler bozulur. Tamam, düzeltmesi kolay: sadece bir arama yapacağız ve birim test spesifikasyonundaki bottle
değiştireceğiz. Ve bunu yapmak, ilk etapta kodun kendisine yapmak kadar kolaydır ve istemeden bir şeyleri kırma riskini taşır.
Bu arada, değişkenlerim garip bir şekilde daha sonra adlandırılacak, bottlePhrase
gibi şeylerin şişelerle hiçbir ilgisi yok. Bundan kaçınmanın tek yolu, yapılacak değişikliğin türünü tam olarak öngörmek ve değişken isimlerimde bottle
yerine vessel
veya container
gibi daha genel bir terim kullanmaktır.
Bu şekilde geleceğe hazır olmanın bilgeliği oldukça tartışmalıdır. Herhangi bir şeyi değiştirmek isteme ihtimaliniz nedir? Ve eğer yaparsanız, değiştirdiğiniz şey bu kadar rahat işe yarayacak mı? bottlePhrase
örneğinde, ikiden fazla çoğul biçimi olan bir dilde yerelleştirme yapmak isterseniz ne olur? Bu doğru, yeniden düzenleme zamanı ve kod daha sonra daha da kötü görünebilir.
Ancak gereksinimleriniz değiştiğinde ve yalnızca onları tahmin etmeye çalışmıyorsanız, belki de yeniden düzenleme zamanı gelmiştir. Ya da belki yine de erteleyebilirsiniz: Gerçekçi olarak kaç gemi tipi veya yerelleştirme ekleyeceksiniz? Her neyse, veri tekilleştirmenizi netlikle dengelemeniz gerektiğinde, Katrina Owen'ın bu gösterisini izlemeye değer.
Kendi çirkin örneğime geri dönelim: Söylemeye gerek yok, tekilleştirmenin faydaları burada o kadar fazla fark edilmiyor bile. Bu arada maliyeti ne oldu?
İlk etapta yazmak daha uzun sürmesinin yanı sıra, okuma, hata ayıklama ve bakım artık biraz daha az önemsiz. Makul miktarda yinelemeye izin verilen okunabilirlik düzeyini hayal edin. Örneğin, dört ayet varyasyonunun her birinin hecelenmesi.
Ama Hala Optimize Etmedik!
Artık algoritmanız uygulandığına ve çıktısının doğru olduğunu kanıtladığınıza göre, tebrikler! Bir temeliniz var!
Son olarak, optimize etme zamanı geldi, değil mi? Hayır, yine de henüz yapma . Temel çizginizi alıp güzel bir kıyaslama yapmanın zamanı geldi. Bu konuda beklentileriniz için bir eşik belirleyin ve bunu test takımınıza yapıştırın. O zaman bir şey aniden bu kodu yavaşlatırsa - hala çalışıyor olsa bile - kapıdan çıkmadan önce bileceksiniz.
İlgili kullanıcı deneyiminin tamamını uygulayana kadar optimizasyona devam edin. O noktaya kadar, kodun ihtiyaç duyduğunuzdan tamamen farklı bir bölümünü hedefliyor olabilirsiniz.
Git uygulamanızı (veya bileşeninizi) tamamlayın, henüz yapmadıysanız, tüm algoritmik karşılaştırma temellerinizi giderken ayarlayın.
Bu yapıldıktan sonra, sisteminizin en yaygın gerçek dünya kullanım senaryolarını kapsayan uçtan uca testler oluşturmak ve kıyaslamak için harika bir zamandır.
Belki her şeyin yolunda olduğunu göreceksiniz.
Veya gerçek yaşam bağlamında bir şeyin çok yavaş olduğunu veya çok fazla bellek gerektirdiğini belirlediniz.
Tamam, Şimdi Optimize Edebilirsiniz
Bu konuda objektif olmanın tek yolu var. Alev grafiklerini ve diğer profil oluşturma araçlarını ortaya çıkarmanın zamanı geldi. Deneyimli mühendisler, acemilerden daha sık tahminde bulunabilir veya olmayabilir, ancak mesele bu değil: Kesin olarak bilmenin tek yolu profil çıkarmaktır. Performans için kodu optimize etme sürecinde her zaman yapılacak ilk şey budur.
Gerçekten en büyük etkiyi yaratacak şeyi elde etmek için belirli bir uçtan uca test sırasında profil oluşturabilirsiniz. (Ayrıca, dağıtımdan sonra, kullanım kalıplarını izlemek, gelecekte sisteminizin hangi yönlerinin ölçülmesiyle en alakalı olduğunu bilmek için harika bir yoldur.)
Profil oluşturucuyu tam derinliğine kadar kullanmaya çalışmadığınızı unutmayın; genel olarak, ifade düzeyinde profil oluşturmadan çok işlev düzeyinde profil oluşturma arıyorsunuz, çünkü bu noktada amacınız yalnızca hangi algoritmanın darboğaz olduğunu bulmaktır. .
Artık sisteminizin darboğazını belirlemek için profil oluşturmayı kullandığınıza göre, artık optimizasyonunuzun yapmaya değer olduğundan emin olarak gerçekten optimize etmeye çalışabilirsiniz. Ayrıca, yol boyunca yaptığınız temel karşılaştırma ölçütleri sayesinde girişiminizin ne kadar etkili (veya etkisiz) olduğunu da kanıtlayabilirsiniz.
Genel Teknikler
İlk olarak, mümkün olduğunca uzun süre yüksek seviyede kalmayı unutmayın:
Biliyor musun? Nihai evrensel optimizasyon hilesi, her durumda geçerlidir:
— Lars Doucet (@larsiusprime) 30 Mart 2017
- Daha az şey çizin
- Daha az şey güncelleyin
Tüm algoritma düzeyinde, bir teknik güç azaltmadır. Döngüleri formüllere indirgemek durumunda olsa da, yorum bırakmaya dikkat edin. Herkes her kombinatorik formülü bilmez veya hatırlamaz. Ayrıca, matematiği kullanırken dikkatli olun: Bazen, güç azaltma olabileceğini düşündüğünüz şey, sonunda değildir. Örneğin, x * (y + z)
'nin açık bir algoritmik anlamı olduğunu varsayalım. Beyniniz bir noktada, herhangi bir nedenle, benzer terimlerin grubunu otomatik olarak çözmek için eğitildiyse, bunu x * y + x * z
olarak yeniden yazmaya cazip gelebilirsiniz. Birincisi, bu, okuyucu ile orada olan açık algoritmik anlam arasına bir engel koyar. (Daha da kötüsü, gerekli olan ekstra çarpma işlemi nedeniyle artık daha az verimlidir. Döngü açma işlemi pantolonunu henüz yumuşatmış gibidir.) Her durumda, niyetiniz hakkında kısa bir not uzun bir yol kat edebilir ve hatta niyetinizi görmenize yardımcı olabilir. işlemeden önce kendi hatanız.
İster formül kullanıyor olun, ister döngü tabanlı bir algoritmayı başka bir döngü tabanlı algoritma ile değiştiriyor olun, farkı ölçmeye hazırsınız.
Ama belki sadece veri yapınızı değiştirerek daha iyi performans elde edebilirsiniz. Kullanmakta olduğunuz yapı ve alternatifler üzerinde yapmanız gereken çeşitli işlemler arasındaki performans farkı konusunda kendinizi eğitin. Belki bir karma sizin bağlamınızda çalışmak için biraz daha dağınık görünebilir, ancak bir dizi üzerinde üstün arama süresi buna değer mi? Bunlar, karar vermek size kalmış takas türleridir.
Bir kolaylık fonksiyonunu çağırdığınızda bunun sizin adınıza hangi algoritmaların yürütüldüğünü bilmekle ilgili olduğunu fark edebilirsiniz. Yani sonuçta, güç azaltma ile gerçekten aynı şey. Ve satıcınızın kitaplıklarının perde arkasında ne yaptığını bilmek, yalnızca performans için değil, aynı zamanda kasıtsız hatalardan kaçınmak için de çok önemlidir.
Mikro Optimizasyonlar
Tamam, sisteminizin işlevselliği tamamlandı, ancak UX açısından performansa biraz daha ince ayar yapılabilir. Elinizden gelenin en iyisini yaptığınızı varsayarsak, şimdiye kadar kaçındığımız optimizasyonları düşünmenin zamanı geldi. Düşünün, çünkü bu optimizasyon seviyesi hala netlik ve sürdürülebilirliğe karşı bir dengedir. Ancak zamanın geldiğine karar verdiniz, bu nedenle, artık tüm sistemin bağlamında, gerçekten önemli olduğu yerde olduğunuza göre, ifade düzeyinde profil oluşturmaya devam edin.
Tıpkı kullandığınız kütüphanelerde olduğu gibi, derleyiciniz veya yorumlayıcınız düzeyinde sizin yararınıza sayısız mühendislik saati yapılmıştır. (Sonuçta, derleyici optimizasyonu ve kod oluşturma, başlı başına devasa konulardır). Bu, işlemci düzeyinde bile geçerlidir. En düşük seviyelerde neler olduğunun farkında olmadan kodu optimize etmeye çalışmak, dört tekerlekten çekişe sahip olmanın aracınızın daha kolay durabileceğini ima etmeye benzer.
Bunun ötesinde iyi bir genel tavsiye vermek zor çünkü bu gerçekten teknoloji yığınınıza ve profil oluşturucunuzun neye işaret ettiğine bağlı. Ancak, ölçüm yaptığınız için, çözümler organik ve sezgisel olarak size problem bağlamından gelmiyorsa, yardım istemek için zaten mükemmel bir konumdasınız. (Uyku ve başka bir şey düşünmek için harcanan zaman da yardımcı olabilir.)
Bu noktada, bağlama ve ölçeklendirme gereksinimlerine bağlı olarak, Jeff Atwood muhtemelen geliştirici zamanından daha ucuz olabilecek donanım eklemeyi önerecektir.
Belki de o yoldan gitmiyorsun. Bu durumda, çeşitli kod optimizasyon teknikleri kategorilerini keşfetmeye yardımcı olabilir:
- Önbelleğe almak
- Bit hack'leri ve 64-bit ortamlara özgü olanlar
- Döngü optimizasyonu
- Bellek hiyerarşisi optimizasyonu
Daha spesifik olarak:
- C ve C++'da kod optimizasyon ipuçları
- Java'da kod optimizasyon ipuçları
- .NET'te CPU kullanımını optimize etme
- ASP.NET web grubu önbelleğe alma
- SQL veritabanı ayarlama veya özellikle Microsoft SQL Server ayarlama
- Scala'nın Oyununu Ölçeklendirme! çerçeve
- Gelişmiş WordPress performans optimizasyonu
- JavaScript prototipi ve kapsam zincirleriyle kod optimizasyonu
- React performansını optimize etme
- iOS animasyon verimliliği
- Android performans ipuçları
Her halükarda, senin için daha çok Yapmayacağım şeyler var:
Bir değişkeni birden çok farklı amaç için yeniden kullanmayın. Bakım açısından bu, yağsız bir araba çalıştırmak gibidir. Bu, yalnızca en aşırı gömülü durumlarda bir anlam ifade etti ve bu durumlarda bile artık mantıklı olmadığını savunuyorum. Bu organize etmek derleyicinin işidir. Kendiniz yapın, ardından bir kod satırını hareket ettirin ve bir hata ortaya çıkardınız. Hafızayı kurtarma yanılsaması sizin için buna değer mi?
Nedenini bilmeden makroları ve satır içi işlevleri kullanmayın. Evet, işlev çağrısı ek yükü bir maliyettir. Ancak bundan kaçınmak genellikle kodunuzu hata ayıklamayı zorlaştırır ve bazen gerçekten yavaşlatır. Arada bir iyi bir fikir olduğu için bu tekniği her yerde kullanmak altın bir çekiç örneğidir.
Döngüleri elle açmayın. Yine, bu döngü optimizasyonu biçimi, kodunuzun okunabilirliğinden ödün vererek değil, derleme gibi otomatik bir işlemle neredeyse her zaman daha iyi optimize edilmiş bir şeydir.
Son iki kod optimizasyon örneğindeki ironi, aslında performans karşıtı olabilmeleridir. Tabii ki, kıyaslama yaptığınız için, kendi kodunuz için bunu kanıtlayabilir veya çürütebilirsiniz. Ancak bir performans artışı görseniz bile, sanat tarafına dönün ve kazancın okunabilirlik ve sürdürülebilirlik kaybına değip değmediğini görün.
Sizin: Optimum Optimize Edilmiş Optimizasyon
Performans optimizasyonunu denemek faydalı olabilir. Bununla birlikte, çoğu zaman, çok erken yapılır, beraberinde bir dizi kötü yan etki taşır ve en ironik olarak, daha kötü performansa yol açar. Umarım optimizasyon sanatı ve bilimi ve en önemlisi uygun bağlamı için geniş bir takdirle uzaklaşmışsınızdır.
Bu, baştan mükemmel kod yazma fikrinden kurtulmamıza ve bunun yerine doğru kodu yazmamıza yardımcı olursa sevinirim. Yukarıdan aşağıya optimizasyon yapmayı, darboğazların nerede olduğunu kanıtlamayı ve bunları düzeltmeden önce ve sonra ölçmeyi unutmamalıyız. Optimizasyonu optimize etmek için en uygun, optimum strateji budur. İyi şanslar.