Erken Optimizasyon Lanetinden Nasıl Kaçınılır?
Yayınlanan: 2022-03-11Neredeyse garantiye değer, gerçekten. Acemilerden uzmanlara, mimariden ASM'ye ve makine performansından geliştirici performansına kadar her şeyi optimize edenlere kadar, sizin ve ekibinizin kendi hedeflerinizi kısa devre yapma ihtimali oldukça yüksektir.
Ne? Ben? benim takımım mı?
Bu seviye için oldukça ağır bir suçlama. Açıklamama izin ver.
Optimizasyon kutsal kâse değildir, ancak elde edilmesi de bir o kadar zor olabilir. Ekibinizin deneyimini kendi kendini sabote etmekten, uyum, tatmin, denge ve nihayetinde optimizasyona dönüştürmeye yardımcı olacak birkaç basit ipucunu (ve bir yığın tuzak) sizinle paylaşmak istiyorum.
Erken Optimizasyon Nedir?
Erken optimizasyon, performansı optimize etmeye çalışıyor:
- Bir algoritmayı ilk kodlarken
- Kıyaslamalar onaylamadan önce şunları yapmanız gerekir:
- Profil oluşturmadan önce, optimizasyonla uğraşmanın mantıklı olduğu nokta noktalarını belirleyin
- Projenizin şu anda belirttiğinden daha düşük bir seviyede
Şimdi, ben bir iyimserim, Optimus.
En azından bu yazıyı yazarken iyimser biri gibi davranacağım. Kendi adına, adının Optimus olduğunu farz edebilirsin, böylece bu sana daha doğrudan hitap edecek.
Teknolojide çalışan biri olarak, muhtemelen bazen bunun nasıl $year
olabileceğini merak ediyorsunuz ve yine de, tüm ilerlememize rağmen, $task
bu kadar can sıkıcı bir şekilde zaman alıcı olması bir şekilde kabul edilebilir bir standart. Zayıf olmak istiyorsun. Verimli. Mükemmel. Rockstar Programcıları gibi, bu iş ilanlarının yaygara kopardığı, ancak lider pirzolaları olan biri. Bu nedenle, ekibiniz kod yazdığında, onları ilk seferde doğru yapmaya teşvik edersiniz (burada “doğru” oldukça göreceli bir terim olsa bile). Bunun Clever Coder'ın yolu olduğunu biliyorlar ve ayrıca Daha Sonra Yeniden Düzenleme Yaparak Zaman Harcaması Gerekmeyenlerin yolu.
Hissediyorum. Mükemmeliyetçiliğin gücü bazen bende de güçlüdür. Ekibinizin şimdi biraz zaman harcamasını ve daha sonra çok zaman kazanmasını istiyorsunuz, çünkü herkes “Diğer İnsanların Yazdığı Boktan Kod (Hangi Cehenneme Ne Düşünüyorlardı?)” konusundaki payına düştü. Bu kısaca SCOPWWWTT, çünkü telaffuz edilemeyen kısaltmaları sevdiğinizi biliyorum.
Ayrıca ekibinizin kodunun kendileri veya satırdaki herhangi biri için böyle olmasını istemediğinizi de biliyorum.
Öyleyse ekibinizi doğru yöne yönlendirmek için neler yapılabileceğini görelim.
Ne Optimize Edilir: Bu Bir Sanat Olmak'a Hoş Geldiniz
Her şeyden önce, program optimizasyonunu düşündüğümüzde, genellikle performanstan bahsettiğimizi varsayarız. Bu bile göründüğünden daha belirsiz (hız? bellek kullanımı? vb.), o yüzden burada duralım.
Hadi daha da belirsiz hale getirelim! Sadece ilk başta.
Örümcek ağı beynim mümkün olduğu kadar düzen yaratmayı sever, bu yüzden söyleyeceğim şeyin iyi bir şey olduğunu düşünmem için her türlü iyimserliğim gerekecek.
Yapmayın diye giden basit bir (performans) optimizasyon kuralı var. Bunu katı bir şekilde takip etmek oldukça kolay geliyor ama herkes onunla aynı fikirde değil. Ayrıca buna tamamen katılmıyorum. Bazı insanlar kapıdan diğerlerinden daha iyi kod yazacaktır. Umarım, herhangi bir kişi için yepyeni bir projede yazacakları kodun kalitesi genellikle zamanla iyileşir. Ancak birçok programcı için durumun böyle olmayacağını biliyorum, çünkü ne kadar çok bilirlerse, zamanından önce optimize etmek için o kadar çok yol alacaklardır.
Pek çok programcı için… ne kadar çok bilirlerse, zamanından önce optimize etmek için o kadar çok yol cazip olacaktır.
Yani bu Yapma bunu kesin bir bilim olamaz, ancak yalnızca tipik teknisyenin bulmacayı çözmeye yönelik içsel dürtüsüne karşı koymak içindir. Her şeyden önce, birçok programcıyı zanaata çeken şey budur. anladım. Ama onlardan onu kurtarmalarını , ayartmaya direnmelerini isteyin. Şu anda bulmaca çözen bir çıkışa ihtiyaç duyuyorsanız, her zaman Pazar gazetesinin Sudoku'su ile uğraşabilir veya bir Mensa kitabı alabilir veya yapay bir problemle kod golfüne gidebilirsiniz. Ancak uygun zamana kadar deponun dışında bırakın. Neredeyse her zaman bu, ön optimizasyondan daha akıllıca bir yoldur.
Unutmayın, bu uygulama, insanların erken optimizasyonun tüm kötülüklerin kökü olup olmadığını sormalarına neden olacak kadar kötü bir üne sahiptir. (O kadar ileri gitmezdim ama bu düşünceye katılıyorum.)
Tasarımın her seviyesinde aklımıza gelebilecek en beyin ölümü gerçekleşen yolu seçmemiz gerektiğini söylemiyorum. Tabii ki değil. Ancak en zeki görüneni seçmek yerine, diğer değerleri göz önünde bulundurabiliriz:
- Yeni işe aldığınız kişiye açıklamanın en kolay yolu
- En deneyimli geliştiriciniz tarafından yapılan bir kod incelemesini geçme olasılığı en yüksek olan
- En sürdürülebilir
- En hızlı yazmak
- Test edilmesi en kolay
- en taşınabilir
- vb.
Ama işte burada sorun kendini zor gösteriyor. Bu sadece hız, kod boyutu, bellek ayak izi, esneklik veya geleceğe yönelik olma için optimizasyon yapmaktan kaçınmakla ilgili değildir. Bu, dengeyle ve yaptığınız şeyin aslında değerlerinizle ve hedeflerinizle uyumlu olup olmadığıyla ilgilidir. Tamamen bağlamsaldır ve bazen nesnel olarak ölçmek imkansızdır.
Bu neden iyi bir şey? Çünkü hayat böyledir. Dağınık. Programlamaya yönelik beyinlerimiz bazen kaosta düzen yaratmayı o kadar çok ister ki sonunda ironik bir şekilde kaosu çoğaltırız. Birini seni sevmeye zorlamanın paradoksu gibi. Bunu başardığınızı düşünüyorsanız, o artık aşk değildir; bu arada, rehin almakla suçlanıyorsun, muhtemelen her zamankinden daha fazla sevgiye ihtiyacın var ve bu metafor seçebileceğim en garip metaforlardan biri olmalı.
Her neyse, eğer bir şey için mükemmel sistemi bulduğunuzu düşünüyorsanız, pekala… devam eden yanılsamanın tadını çıkarın, sanırım. Sorun değil, başarısızlıklar öğrenmek için harika fırsatlardır.
UX'i Aklınızda Tutun
Kullanıcı deneyiminin bu potansiyel öncelikler arasında nasıl yer aldığını keşfedelim. Sonuçta, bir şeyin iyi performans göstermesini istemek bile, bir düzeyde UX ile ilgilidir.
Bir kullanıcı arayüzü üzerinde çalışıyorsanız, kodun kullandığı çerçeve veya dil ne olursa olsun, belirli bir miktarda ortak kalıp ve tekrar olacaktır. Bunu azaltmaya çalışmak, programcı zamanı ve kod netliği açısından kesinlikle değerli olabilir. Öncelikleri dengeleme sanatına yardımcı olmak için birkaç hikaye paylaşmak istiyorum.
Bir işte çalıştığım şirket, üzerinde düşünülmüş bir teknoloji yığınına dayanan kapalı kaynaklı bir kurumsal sistem kullandı. Aslında, bize satan satıcının, geliştiricileri için çok acı verici olduğu için yığının görüşlerine uymayan UI özelleştirmeleri yapmayı reddettiği konusunda çok fazla fikir vardı. Yığınlarını hiç kullanmadım, bu yüzden onları bunun için kınamıyorum, ancak gerçek şu ki, bu "programcı için iyi, kullanıcı için kötü" takası, belirli bağlamlarda iş arkadaşlarım için o kadar hantaldı ki bitirdim sistemin kullanıcı arayüzünün bu bölümünü yeniden uygulayan bir üçüncü taraf eklentisi yazmaya kadar. (Büyük bir üretkenlik artırıcıydı. İş arkadaşlarım onu sevdi! On yıldan fazla bir süre sonra, hala oradaki herkesi zamandan ve hayal kırıklığından kurtarıyor.)
Fikir edinmenin başlı başına bir sorun olduğunu söylemiyorum; sadece bu kadarı bizim durumumuzda bir sorun haline geldi. Bir karşı örnek olarak, Ruby on Rails'in en büyük avantajlarından biri, kişinin çok fazla seçeneğe sahip olmaktan kolayca baş dönmesine neden olduğu bir ön uç ekosisteminde tam olarak kanaatkar olmasıdır. (Kendi fikrimi bulana kadar bana fikirleri olan bir şey verin!)
Buna karşılık, projenizde UX'i Her Şeyin Kralı olarak taçlandırmak isteyebilirsiniz. Değerli bir hedef, ama ikinci hikayemi anlatayım.
Yukarıdaki projenin başarısından birkaç yıl sonra, iş arkadaşlarımdan biri bana geldi ve bazen ortaya çıkan belirli bir karmaşık gerçek hayat senaryosunu otomatikleştirerek UX'i optimize etmemi istedi, böylece tek bir tıklamayla çözülebildi. Senaryonun çok sayıda ve garip uç durumları nedeniyle yanlış pozitif veya negatif olmayacak bir algoritma tasarlamanın mümkün olup olmadığını analiz etmeye başladım. İş arkadaşımla bu konuda ne kadar çok konuşursam, o kadar çok gereksinimlerin işe yaramayacağının farkına vardım. Senaryo sadece arada bir ortaya çıktı - diyelim ki ayda bir - ve şu anda bir kişinin çözmesi birkaç dakika sürdü. Herhangi bir hata olmadan başarılı bir şekilde otomatikleştirebilsek bile , gerekli geliştirme ve bakım süresinin iş arkadaşlarım tarafından kazanılan zaman açısından ödenmesi yüzyıllar alacaktır. İçimdeki insanları memnun eden kişi “hayır” derken zor anlar yaşadı ama konuşmayı kısa kesmek zorunda kaldım.
Bu nedenle, bilgisayarın kullanıcıya yardımcı olmak için elinden geleni yapmasına izin verin, ancak yalnızca makul bir ölçüde. Yine de bunun ne ölçüde olduğunu nereden biliyorsun?
Almayı sevdiğim bir yaklaşım, geliştiricilerinizin kodlarını profilleri gibi UX'in profilini çıkarmaktır. Kullanıcılarınızın aynı şeyi tekrar tekrar tıklayarak veya yazarak en çok nerede vakit geçirdiklerini öğrenin ve bu etkileşimleri optimize edip edemeyeceğinizi görün. Kodunuz, büyük olasılıkla ne girecekleri konusunda bazı eğitimli tahminler yapabilir ve bunu girişsiz bir varsayılan yapabilir mi? Belirli yasaklanmış bağlamların (tıklamasız EULA onayı?) dışında, bu, kullanıcılarınızın üretkenliği ve mutluluğu üzerinde gerçekten bir fark yaratabilir. Yapabiliyorsanız, koridorda kullanılabilirlik testi yapın. Bazen, bilgisayarların neyin kolay olduğunu ve neyin olmadığını açıklamakta zorlanabilirsiniz… ancak genel olarak, bu değerin kullanıcılarınız için oldukça önemli olması muhtemeldir.
Erken Optimizasyondan Kaçınmak: Ne Zaman ve Nasıl Optimize Edilir
Diğer bağlamları incelememize rağmen, şimdi bu makalenin geri kalanı için ham makine performansının bazı yönlerini optimize ettiğimizi açıkça varsayalım. Benim önerdiğim yaklaşım, esneklik gibi diğer hedefler için de geçerlidir, ancak her hedefin kendine özgü sonuçları olacaktır; Ana nokta, herhangi bir şey için erken optimizasyonun muhtemelen başarısız olacağıdır.

Peki, performans açısından, gerçekte izlenecek hangi optimizasyon yöntemleri var? Hadi kazalım.
Bu Bir Taban Girişimi Değil, Üçlü-Eh
TL; DR: Yukarıdan aşağıya doğru çalışın. Projede daha yüksek seviyeli optimizasyonlar yapılabilir ve daha düşük seviyeli optimizasyonlar daha sonraya bırakılmalıdır. “Erken optimizasyon” ifadesinin anlamının çoğunu elde etmek için ihtiyacınız olan tek şey bu; işleri bu düzenin dışında yapmak, ekibinizin zamanını boşa harcama ve karşı etkili olma olasılığı yüksektir. Sonuçta, tüm projeyi en başından makine koduna yazmıyorsunuz, değil mi? Dolayısıyla, AAA modus operandi'miz şu sırayla optimize etmektir:
- Mimari
- algoritmalar
- toplantı
Genel kanı, algoritmaların ve veri yapılarının, en azından performans söz konusu olduğunda, genellikle optimize edilecek en etkili yerler olduğu yönündedir. Yine de, mimarinin bazen hangi algoritmaların ve veri yapılarının kullanılabileceğini belirlediğini unutmayın.
Bir keresinde, her bir finansal işlem için bir SQL veritabanını defalarca sorgulayarak ve ardından müşteri tarafında çok basit bir hesaplama yaparak finansal rapor yapan bir yazılım keşfettim. Nispeten küçük miktardaki finansal verileri bile, yepyeni masaüstleri ve oldukça güçlü bir sunucu ile rapor oluşturma süresinin zaten birkaç dakikaya kadar çıktığı anlamına gelmeden önce, yazılımı kullanan küçük işletmelerin yalnızca birkaç ayını aldı. oldukça sık kullanmaları gereken bir şeydi. Sonunda, toplama mantığını içeren basit bir SQL ifadesi yazdım - tüm yinelemelerden ve ağ gidiş dönüşlerinden kaçınmak için işi sunucuya taşıyarak mimarilerini engelleyen - ve hatta birkaç yıllık veriyi daha sonra, sürümüm şu sonucu oluşturabilir: aynı eski donanımda sadece milisaniyeler içinde aynı rapor.
Bazen bir projenin mimarisi üzerinde etkiniz olmaz çünkü bir mimari değişikliğin uygulanabilir olması için projede çok geç kalınmıştır. Bazen geliştiricileriniz, yukarıdaki örnekte yaptığım gibi onun etrafından dolaşabilirler. Ancak bir projenin başlangıcındaysanız ve mimarisinde söz sahibiyseniz, şimdi bunu optimize etmenin tam zamanı.
Mimari
Bir projede, mimari, sonradan değiştirilecek en pahalı kısımdır, bu yüzden burası, başlangıçta optimize etmenin mantıklı olabileceği bir yerdir. Örneğin, uygulamanız verileri devekuşları aracılığıyla iletecekse, kötü bir darboğazı daha da kötüleştirmemek için uygulamayı düşük frekanslı, yüksek yük kapasiteli paketlere göre yapılandırmak isteyeceksiniz. Bu durumda, kullanıcılarınızı eğlendirmek için tam bir Tetris uygulamasına sahip olsanız iyi olur, çünkü bir yükleme döndürücü bunu kesmeyecektir. (Şaka bir yana: Yıllar önce ilk Linux dağıtımım Corel Linux 2.0'ı kuruyordum ve uzun süredir devam eden kurulum sürecinin tam da bunu içermesinden çok memnundum. Windows 95 yükleyicisinin reklam ekranlarını o kadar çok gördüm ki onları ezberlemiştim. o zamanlar temiz bir nefesti.)
Mimari değişikliğin pahalı olmasına bir örnek olarak, yukarıda bahsedilen SQL raporunun ilk etapta bu kadar ölçeklenemez olmasının nedeni, geçmişinden açıktır. Uygulama, MS-DOS'taki köklerinden ve başlangıçta çok kullanıcılı bile olmayan, evde yetiştirilen, özel bir veritabanından zamanla gelişti. Satıcı nihayet SQL'e geçiş yaptığında, şema ve raporlama kodu bire bir taşınmış gibi görünüyor. Bu, onlara, belirli bir rapor için SQL'in avantajlarından gerçekten yararlanarak mimari geçişi tamamlamaya başladıklarında, güncellemeleri boyunca serpmek için yıllarca süren etkileyici %1.000'den fazla performans iyileştirmesi bıraktı. O zamanki işverenim gibi kilitli müşterilerle ve ilk geçiş sırasında açıkça kodlama verimliliğine öncelik vermeye çalışan müşterilerle çalışmak için iyi. Ancak bazı durumlarda müşterilerin ihtiyaçlarını karşılamak, bir çekicin vidayı çevirmesi kadar etkili olabilir.
Mimarlık, kısmen, projenizin ne dereceye kadar ve hangi yollarla ölçeklenebilmesi gerektiğini tahmin etmekle ilgilidir. Mimarlık çok üst düzey olduğu için, odağımızı belirli teknolojilere ve alanlara daraltmadan “yapılması ve yapılmaması gerekenler” ile somutlaşmak zor.
Ben öyle demezdim ama başka herkes yapar
Neyse ki, İnternet, şimdiye kadar hayal edilen her tür mimari hakkında toplanmış bilgelikle doludur. Mimarinizi optimize etmenin zamanının geldiğini bildiğinizde, tuzakları araştırmak, parlak vizyonunuzu tanımlayan moda kelimeyi bulmaya hemen hemen kaynar. Muhtemelen biri sizinle aynı çizgide düşünmüş, denemiş, başarısız olmuş, yinelemiş ve bir blogda veya kitapta yayınlamıştır.
Buzzword tanımlamasını sadece arayarak başarmak zor olabilir, çünkü sizin FLDSMDFR dediğiniz şey için, SCOPWWWTT terimini başka biri zaten icat etti ve çözdüğünüz aynı sorunu tanımlıyorlar, ancak sizin kullandığınızdan tamamen farklı bir kelime kullanıyorlar. Geliştirici toplulukları kurtarmaya! StackExchange veya HashNode'a olabildiğince ayrıntılı bir açıklama ve mimarinizin olmadığı tüm moda sözcükleri ekleyin, böylece yeterli ön araştırma yaptığınızı bilirler. Birisi sizi aydınlatmaktan memnun olacaktır.
Bu arada, bazı genel tavsiyeler düşünmek için iyi bir besin olabilir.
Algoritmalar ve Montaj
Elverişli bir mimari göz önüne alındığında, ekibinizdeki kodlayıcıların zamanları için en fazla T-bling'i alacağı yer burasıdır. Erken optimizasyondan temel olarak kaçınma burada da geçerlidir, ancak programcılarınız bu düzeydeki bazı özellikleri göz önünde bulundurursa iyi olur. Uygulama ayrıntıları söz konusu olduğunda düşünülecek o kadar çok şey var ki, kod optimizasyonu hakkında ön saflara ve kıdemli kodlayıcılara yönelik ayrı bir makale yazdım.
Ancak siz ve ekibiniz performans açısından optimize edilmemiş bir şey uyguladığınızda, bunu gerçekten Yapma'da mı bırakıyorsunuz? Hiç optimize etmiyor musun?
Haklısın. Bir sonraki kural, yalnızca uzmanlar için, Henüz yapmayın .
Kıyaslama Zamanı!
Kodunuz çalışıyor. Belki de o kadar yavaştır ki, optimize etmeniz gerektiğini zaten biliyorsunuzdur , çünkü bu sık çalışacak bir koddur. Belki emin değilsiniz veya bir O(n) algoritmanız var ve muhtemelen iyi olduğunu düşünüyorsunuz. Durum ne olursa olsun, eğer bu algoritma optimize edilmeye değerse, bu noktada benim tavsiyem aynı: Basit bir kıyaslama yapın.
Niye ya? O(n³) algoritmamın her şeyden daha kötü olamayacağı açık değil mi? Şey, iki nedenden dolayı:
- Şu anda karşılanıp karşılanmadıklarından bağımsız olarak, performans hedeflerinizin nesnel bir ölçüsü olarak kıyaslamayı test takımınıza ekleyebilirsiniz.
- Uzmanlar bile istemeden işleri yavaşlatabilir. Açık göründüğünde bile. Gerçekten bariz.
Bu ikinci noktada bana inanmıyor musun?
1.400 Dolarlık Donanımdan 7.000 Dolarlık Donanımdan Daha İyi Sonuçlar Nasıl Alınır
StackOverflow'un ünlü isimlerinden Jeff Atwood, bir keresinde, programcının değerli zamanını optimizasyona harcamaktansa, yalnızca daha iyi donanım satın almanın bazen (genellikle, onun görüşüne göre) daha uygun maliyetli olabileceğine dikkat çekmişti. Tamam, projenizin bu senaryoya uyacağına dair makul derecede objektif bir sonuca ulaştığınızı varsayalım. Ayrıca, optimize etmeye çalıştığınız şeyin derleme zamanı olduğunu varsayalım, çünkü bu üzerinde çalıştığınız ağır bir Swift projesi ve bu oldukça büyük bir geliştirici darboğazı haline geldi. Donanım alışveriş zamanı!
Ne satın almalısınız? Açıkçası yen için yen, daha pahalı donanımlar daha ucuz donanımlardan daha iyi performans gösterme eğilimindedir. Açıkçası, 7.000 dolarlık bir Mac Pro, yazılımınızı bazı orta sınıf Mac Mini'lerden daha hızlı derler, değil mi?
Yanlış!
Bazen daha fazla çekirdeğin daha verimli derleme anlamına geldiği ortaya çıktı… ve bu özel durumda LinkedIn, yığınları için tam tersinin doğru olduğunu zor yoldan öğrendi.
Ancak yönetimin bir hata daha yaptığını gördüm: Öncesini ve sonrasını kıyaslamadılar bile ve bir donanım yükseltmesinin yazılımlarını daha hızlı "hissettirmediğini" gördüler. Ama kesin olarak bilmenin bir yolu yoktu; ve ayrıca, darboğazın nerede olduğu konusunda hala hiçbir fikirleri yoktu, bu yüzden soruna ayırmaya istekli oldukları zaman ve parayı tükettikleri için performans konusunda mutsuz kaldılar.
Tamam, Zaten Kıyasladım. Aslında Henüz Optimize Edebilir miyim?
Evet, yapmanız gerektiğine karar verdiğinizi varsayarsak. Ama belki bu karar diğer algoritmaların çoğu/tümü uygulanana kadar bekleyecek, böylece hareketli parçaların nasıl birbirine uyduğunu ve hangilerinin en önemli olduğunu profilleme yoluyla görebilirsiniz. Bu, küçük bir uygulama için uygulama düzeyinde olabilir veya yalnızca bir alt sistem için geçerli olabilir. Her iki durumda da, belirli bir algoritmanın genel uygulama için önemli görünebileceğini unutmayın, ancak uzmanlar bile - özellikle uzmanlar - bunu yanlış teşhis etmeye eğilimlidir.
Rahatsız Etmeden Önce Düşünün
"Sizi bilmem millet ama..."
Düşünce için son bir gıda olarak, yanlış optimizasyon fikrini çok daha geniş bir bakış açısına nasıl uygulayabileceğinizi düşünün: projeniz veya şirketinizin kendisi, hatta ekonominin bir sektörü.
Biliyorum, teknolojinin günü kurtaracağını ve bunu gerçekleştiren kahramanlar olabileceğimizi düşünmek cezbedici.
Ayrıca biz yapmazsak başkası yapacak.
Ama unutmayın ki, en iyi niyetlere rağmen güç yozlaşır. Burada herhangi bir makaleye bağlantı vermeyeceğim, ancak herhangi birinde gezinmediyseniz, ekonomiyi bozmanın daha geniş etkisi ve bunun bazen kime hizmet ettiği hakkında biraz araştırma yapmaya değer. Optimizasyon yoluyla dünyayı kurtarmaya çalışmanın bazı yan etkilerine şaşırabilirsiniz.
dipnot
Bir şey fark ettin mi Optimus? Sana Optimus dediğim tek zaman başlangıçta ve şimdi sonundaydı. Makale boyunca adın Optimus değildi. Dürüst olacağım, unutmuşum. Bütün yazıyı sana Optimus demeden yazdım. Sonunda geri dönüp adını yazıya serpmem gerektiğini fark ettiğimde içimden bir ses, yapma dedi.