3 puan yazan GN⁺ 2024-09-12 | 1 yorum | WhatsApp'ta paylaş
  • Yorumlar, tanımlayıcılardan daha ifade gücü yüksek insan dili kullanabildiği için kodda yer almayan seçenekleri ve vazgeçilen alternatifleri bırakmaya uygundur
  • “comment the why, not the what”, bilgiyi mümkün olduğunca tanımlayıcılara koymaya yönelik bir yaklaşım olsa da son dönemde gerekçeyi bile uzun fonksiyon adlarına veya test adlarına taşıma eğilimi var
  • Logic for Programmersın epub derlemesinde, 16 matematik sembolünü her dize için sırayla değiştiren yavaş bir uygulama kullanıldı; ancak şu anda yalnızca 25 matematik dizesi olduğu için yeterince hızlı
  • Bu tür yorumlar, ileride matematik dizeleri yüzlerceye çıkıp derleme darboğazı oluştuğunda nerelerin düzeltilmesi gerektiğini gösterir ve yavaş kodun bilinçli bir ödünleşim olduğunu kayda geçirir
  • Fonksiyon adları veya testler, kodun fiilen yaptığı işe bağlandığı için seçilmemiş alternatifleri ve yapılmayan işleri içeren negatif bilgiyi kendi kendini belgeleyen şekilde aktarmak zordur

Yorumların koda göre daha kolay taşıyabildiği bilgiler

  • Kod, yapılandırılmış bir makine dilidir; yorumlar ise ifade gücü yüksek insan diliyle yazılır
  • “comment the why, not the what”, mümkün olduğunca fazla bilgiyi tanımlayıcılara koymak anlamında yorumlanabilir
  • Tanımlayıcılar, kodun içine dahil edilmiş sınırlı bir insan diline daha yakındır; tüm “what” bilgisini taşıyamazlar, ancak çoğu durumda önemli bir kısmını taşıyabilirler
  • Son dönemde “why” bilgisinin de yorum yerine uzun fonksiyon adlarına veya test case adlarına konabileceği görüşü yaygınlaşıyor
  • Kendi kendini belgeleyen kod tabanları genelde tanımlayıcı ekleme yoluyla belgelendirmeyi artırır
    • İstisna olarak, yorumların loglamaya dönüştürülerek kodun daha fazla kendi kendini belgelediği bir örnek de vardır

“Why Not” yorumlarının ele aldığı şey

  • Kodla ifade edilmesi zor olan bilgi negatif bilgidir
  • Negatif bilgi, sistemde neyin bulunmadığına ve belirli bir alternatifin neden seçilmediğine dikkat çeker
  • “why not”, kodun ne yaptığını açıklamaktan ziyade kodun seçmediği seçenekleri ve bunların nedenlerini kayda geçirir

epub matematik sembolü değiştirme örneği

  • Logic for Programmersın epub derlemesinde, teknik nedenlerle \forall gibi matematik gösterimleri gibi sembollere dönüştürülmüyordu
  • Bunu çözmek için matematik dizelerindeki token’ları karşılık gelen Unicode sembolleriyle doğrudan değiştiren bir script yazıldı
  • En kolay uygulama, gerekli 16 matematik sembolünün her biri için string = string.replace(old, new) çağırmaktı
  • Bu yöntem her dizeyi 16 kez dolaştığı için verimsizdir; ancak 16 değiştirmenin tümünü tek geçişte yapmak daha karmaşıktır
  • Bırakılan yorumun özü şuydu
    • Her dize 16 kez dolaşılır
    • Kitapta şu anda yalnızca 25 matematik dizesi var ve çoğu 5 karakterden kısa
    • Bu yüzden hâlâ yeterince hızlı
  • Bu yorum yalnızca “neden yavaş kod kullanılıyor” sorusunu değil, “neden hızlı kod kullanılmıyor” sorusunu da açıklar

Gelecekteki okurlar için bir işaret levhası

  • Yavaş kod şu anda sorun çıkarmasa da ileride sorun olabilir
  • Logic for Programmersın gelecekteki bir sürümünde matematik dizeleri yüzlerceye çıkarsa ilgili derleme adımı tüm derlemenin darboğazı haline gelebilir
  • Şimdi bir işaret bırakılırsa, ileride hangi bölümün düzeltilmesi gerektiği hemen anlaşılabilir
  • Kod sorunsuz çalışmaya devam etse bile yorum, yazarın ödünleşimin farkında olduğu gerçeğini korur
  • 2 yıl sonra epub_math_fixer.py yeniden açıldığında, yavaş kodun acemilikten mi, zaman yetersizliğinden mi yoksa hatadan mı kaynaklandığını yeniden araştırma ihtiyacı azalır
  • Negatif yorum, yavaş uygulamanın bilindiği, alternatiflerin değerlendirildiği ve optimize etmeme kararı verildiği bilgisini bırakır

Fonksiyon adları ve testlerle değiştirmenin zor olma nedeni

  • RunFewerTimesSlowerAndSimplerAlgorithmAfterConsideringTradeOffs gibi bir fonksiyon adı fazla uzundur ve gerçek ödünleşimi yeterince açıklayamaz
  • Daha sonra kod optimize edilirse bu adın birçok yerde değiştirilmesi gerekebilir
  • Daha büyük sorun, böyle bir adın fonksiyonun gerçekte ne yaptığını anlatamaması ve kendi kendini belgelemeyi aksine zayıflatmasıdır
  • Fonksiyon adları ve değişken adları gibi tanımlayıcılar yalnızca bir cümlelik bilgi taşıyabilir
  • Tek bir tanımlayıcıya hem “fonksiyonun yaptığı işi” hem de “fonksiyonun kabul ettiği ödünleşimi” aynı anda koymak zordur

Testlerle de bırakılması zor negatif bilgi

  • Kitaptaki matematik bloklarını grep edip sayı 80’i aşarsa başarısız olan bir test yazılabilir
  • Ancak böyle bir test EpubMathFixerın kendisini doğrudan test etmez
  • Fonksiyonun içinde bu testin bağlanabileceği bir nokta yoktur
  • Kendi kendini belgeleme, yazılmış koda ilişerek kodun yaptığı işi açıklar
  • Negatif bilgi ise kodun yapmadığı işleri ele aldığı için kendi kendini belgeleme yöntemiyle temelden uyuşmaz

Daha geniş soru

  • “why not” yorumları, karşıolgusalın (counterfactual) bir örneği olarak görülebilir
  • İnsan iletişiminin soyut unsurlarının genel olarak kendi kendini belgeleyip belgeleyemeyeceği sorusu ortada kalır
  • Benzetme, belirsizlik ve etik iddialar gibi bilgilerin de kendi kendini belgeleyip belgeleyemeyeceği hâlâ soru işaretidir

1 yorum

 
GN⁺ 2024-09-12
Hacker News görüşleri
  • Birkaç yıl önce Twitter’da gördüğümü sandığım bir şakayı hatırlıyorum: “Junior mühendis, kodun ne yaptığını açıklayan yorumlar yazar; orta seviye mühendis, kodun neden bunu yaptığını açıklayan yorumlar yazar; senior mühendis ise kodun neden başka bir şekilde yazılmadığını açıklayan yorumlar yazar” gibi bir şeydi.

    • Gerçekten doğru. Kodun kendisinden 5 kat uzun bir yorum eklemek zorunda kaldığım da oldu; bunun nedeni, kodu ya da domain’i veya geniş dinamik kapsamlarla uğraşırken dikkat edilmesi gerekenleri bilmeyen birinin iyi niyetle refactor etmesini engellemekti.
      Buna karşılık, fonksiyon ve değişken adlarıyla anlam netleşebiliyorsa, epey büyük fonksiyonları bile yorumsuz yazdığım oldu.
    • Üçünü de yapıyorum. Özet yorumlar inanılmaz faydalı ve ampirik araştırmalarla da doğrulanmış durumda; ama birçok kişi Clean Code tarzı düşünceye o kadar derinden kapılmış ki kurtarmak zor görünüyor.
    • Junior programcılar genelde ya hiçbir şeyi dokümante etmez ya da her şeyi dokümante eder. Deneyim kazandıkça yalnızca sıra dışı olanı dokümante etmenin yeterli olduğunu öğrenirsin; daha da deneyim kazandıkça sıra dışı şeyler giderek azalır, yorumlar da azalır.
      Bu yüzden daha az yorum olan taraf kazanır; ama yorumsuz bir kod tabanı gördüğünde bunun güzelce cilalanmış bir başyapıt mı yoksa acemilerin yaptığı kırılgan bir kod mu olduğunu ayırt etmek için bizzat incelemek gerekir.
    • Bariz şekilde aptalca görünen bir davranışı neden yeniden üretmeye devam etmek gerektiğini açıklayan yorumlar da vardır. Çünkü başka bir şey o aptalca davranışa bağımlıdır.
    • C-seviyesi bir mühendis olsaydınız, “Bu kodu refactor etmeye X saat harcandı. Öncekilerin yolundan gitmeye karar verdiyseniz bu sayacı artırın” gibi bir yorum bırakırdınız.
      Tam bir yama gibi görünse de bazen gerçekten elde edilebilecek en iyi şey odur.
  • Bir yıl sonra koda tekrar baktığımda bana faydalı olacak gibi görünen her şeyi yorum olarak bırakırım. Genelde bunlar neden ve neden olmaz olur; kod karmaşıksa akışı daha iyi görmek için kısa bir “ne” de yazarım.
    Faydasız olan zorunlu yorumlardır. Public API’ler yeterince dokümante edilmelidir; ama bazı organizasyonlar private fonksiyonlara kadar her fonksiyon için yorum zorunlu tutar ve amaç o kadar barizdir ki fonksiyon adını tekrar etmekten ibaret hale gelir. Bu yalnızca zaman kaybı değil, aynı zamanda insanları yorumlara karşı duyarsızlaştırıp onları görmezden gelme alışkanlığı kazandırır.
    Araçların eklediği israf yorumları da sevmem. Her döngüye //for ya da //try koymak özellikle kötü.

    • Tuhaf biçimde birçok sözdizimi vurgulama renk paleti yorumları soluklaştırıp kontrastı düşürüyor. Muhtemelen zorunlu ya da üretilmiş yorumlarda bilgi miktarı az olduğu içindir.
      Zorunlu ve üretilmiş yorumları kaldırıp, koyu temalarda yorumları göze çarpacak şekilde parlak neon renge çevirmek daha iyi olur. Bir yorum varsa, bu önemli olduğu anlamına gelmelidir.
    • Eskiden “tüm yorumlar code smell’dir” görüşündeydim ve hâlâ büyük ölçüde öyle düşünüyorum; ama yüzlerce kişinin aktif olarak geliştirdiği ve bakımını yaptığı çok büyük bir kod tabanında çalışınca tavrım biraz yumuşadı.
      Sıkışık takvimli bir iş ortamında eski ve büyük sistemleri sürdürürken garip şeyler yapmak zorunda kalınabilir; o zaman da nedenini açıklamak gerekir.
      Yorumlara karşı olmanın büyük nedeni, yorumların da kodun parçası haline gelip bakım gerektirmesidir. Ama çoğu kişi yorumları yalnızca takıldığında okur; editörler de yorumları griye boyayıp psikolojik olarak görünmez kılar. Bu yüzden yorumlar kolayca eskir.
      “Gelecekteki ben” için bağlamın, çok sayıda geliştiricinin dokunduğu paylaşımlı kod tabanlarında da faydalı olup olmadığını; yoksa az sayıda kişinin koda dokunduğu durumlarda iyi çalışan bir yöntem mi olduğunu merak ediyorum.
    • Tamamen katılıyorum. Yorum çok fazla olunca bir class ya da fonksiyonun içinde ne olduğunu görmek zorlaşıyor. Normalde tek ekrana sığacak bir class ya da fonksiyon, yorumlar yüzünden tek ekranı aşıyorsa bir okunabilirlik maliyeti doğuyor.
    • Dün kişisel projemde “Bu gerçekten faydalı mı?” yorumunun bulunduğu bir satır gördüm ve kolayca kaldırılabilecek gibi duruyordu. Yeni ve temiz bir class kullanmayı denedim ama belirli bir eski yöntemin gerçekten gerekli olduğu ortaya çıktı.
      Bu yüzden mevcut yoruma “=> yes!” ekledim ve geçmişteki kendimin bu soruyu dokümante etmiş olmasına minnettar oldum. İşte ise özellikle bug fix’lerinde, açık olmayan bir değişikliğin üstüne ticket numarası ile birlikte sık sık bir iki satır yorum bırakırım.
  • Kodda bıraktığım yorumlar arasında en sevdiğim format şu şablon: “DEAR MAINTAINER: Bu kod [neden] yüzünden böyle. Bunu ‘düzeltmeye’ çalışmanın korkunç bir hata olduğunu fark ederseniz, sonraki kişi için uyarı olarak total_hours_wasted_here = n sayacını artırın.”
    Orijinal yazarı ben değilim ama bir iki kez minnetle kullandım; yalnızca sayacı artıran tek satırlık commit’ler görmek eğlenceliydi.

    • Keşke birkaç yıl önce bu olsaydı. Gereksinimleri karşılamak için recursive kullanımı epey serbest olması gereken SQL üretme kodu yazmıştım; karşılıklı recursive çağrılar çok olduğu için kod dağınıktı ama gerekli bir kötüydü.
      Daha senior bir mühendis kod tabanını devralıp her şeyi döngü tabanlı yaklaşımla “düzeltti” ve e-postayla recursion’ın neden kötü olduğu konusunda bana ders vermeye çalıştı; ama onun kodu gerçek gereksinimlerin hepsini karşılamıyordu ve sonunda benim recursion ile yaptığım şeyleri fiilen yeniden kurdu.
      Daha sonra bazı sözleri için özür diledi; ama en üste böyle bir yorum koymuş olsaydım tüm bu işten kaçınılabilirdi.
  • Başlığın muğlak olduğuna katılıyorum; zaten yazıyı bu yüzden okudum. Kişisel olarak genelinde daha az yorum kullanmayı tercih ederim, ama yazıdaki açıklayıcı yorumlar kesinlikle değerli. Neden öyle yapıldığını, neden başka bir yol seçilmediğini açıklamak gerektiğini iyi hatırlatıyor.
    Bu özellikle 5, 10, 15 yıl sonra bile bakımını yapmanız gereken kendi kodunuz için geçerli. Geçenlerde bir çalışma arkadaşımın yeni kodunu incelerken “Neden böyle yapmış?” diye düşündüm; 10 satır yukarıda, 8 yıl önce benim aynı şeyi yapmamın nedeni duruyordu. O çalışma arkadaşım bakımın temel kuralına, yani mevcut kod gibi görünmesini sağlamaya uymuştu.

    • Eski kod tabanlarının bakımında mevcut kod gibi görünmesini sağlamak çok hafife alınıyor. Sizden sonra gelecek insanların ruh sağlığı için lütfen mevcut kod gibi görünmesini sağlayın.
  • Bu, daha geniş ölçekte izlenen bir ilkenin yalnızca özel bir hâli: kodu okurken şaşırtıcı olan şeylere yorum eklemek
    Kod yazarken zihninde sürekli “Bu kodu daha sonra anlayabilecek miyim?” diye sorup her seferinde içgüdüsel olarak “evet” diyen biri kibirlidir ve sık sık yanılır. Yanıt “emin değilim” ise sonraki soru doğal olarak “neden?” olur; bunun yanıtı da yoruma yazılması gereken şeydir
    Bazen yanıt “okuyan kişi neden başka bir şekilde yazılmadığını merak edebilir” olur; bu yazının ele aldığı özel durum budur. Ama bazen de “nasıl çalıştığı ya da neden doğru olduğu açık değil” olur; o zaman başka tür bir yorum gerekir

    • Kodu önce bir şekilde yazmayı deneyip çalışmadığını gördüyseniz ve ikinci bir yaklaşıma ihtiyaç duyduysanız, bu oraya yorum gerektiğine dair güçlü bir işarettir. Yazarken şaşırdıysanız, 1 yıl sonra o şaşkınlığı unutup kodu okurken yeniden şaşırma olasılığınız yüksektir
    • Benzer bir ilke olarak “Bu beklediğim gibi çalışmazsa nereye bakmalıyım?” ölçüt alınır. Yanıt belgelerde yoksa ya da wiki → paket/modül → dosya → sınıf → fonksiyon/metot yolunda 10 satırdan daha uzaktaysa satır içi yorum ekler ya da belgeleri güncellerim
      Bu genellikle dizeleri kesip biçerken veya ara adım olarak alışılmadık veri yapılarını keşfederken olur
  • Tanımlayıcılarla çok uzağa gidilebilir, ama sonuna kadar gidilemez. Kişisel olarak herkese açık metotlar veya değişkenler, alanlar, parametreler için jsdoc/xmldoc gibi dokümantasyon yorumları istemeyi seviyorum
    Metot adını iyi koymak da önemlidir, ama ne yaptığını kısaca yazmayı denemek daha netleştirir ve özellikle bariz kusurları ortaya çıkarır. İlk cümleyi yazdığınız anda çoğu zaman daha iyi bir ad akla gelir; açıklamaya “ve” girmeye başlıyorsa bu, metodun fazla iş yaptığı ve daha mantıklı biçimde bölünebileceği anlamına gelir
    Özellikler, belge gerektirmeyecek kadar açık sanılabilir; ama /** The API key */ string ApiKey; gibi bir şeyde eksik olan çok fazla şey vardır. Bu anahtarın nereden geldiğini, yalnızca dahili kullanım için mi yoksa harici sistemlerle alınıp veriliyor mu olduğunu, zorunlu olup olmadığını, null ya da boş değer alıp alamayacağını, maksimum uzunluğu olup olmadığını, geçersiz bir değer olursa ne olacağını, okunacak başka kod ya da belge bulunup bulunmadığını bilemeyiz
    Asıl yazarın 1-2 dakikada yazabileceği bilgiler bunlar; ama yeni gelen biri bunu değiştirmek, kullanmak ya da yıllar sonra bir hatayı düzeltmek için görevlendirildiğinde anlaması saatler sürebilir

  • Kod incelemesinde aşırı didikleyen bir reviewer’ın ne diyeceğini tahmin edebildiğimde “Y nedeniyle X yapmadım” gibi yorumları sıkça yazarım. Amaç, yorucu gidip gelmeli tartışmaları azaltmaktır

    • Deneyime göre gidip gelme miktarı aynı kalıyor, sadece birkaç kez “yorumda yazdığı gibi” yazabiliyorsunuz
    • Böyle içerikleri PR’a önceden ekliyorum, ama kodun içinde bırakmaya gerçekten değip değmediğinden pek emin değilim
  • “Her dizeyi 16 kez dolaşıyor, ama kitaptaki formül dizeleri şimdiye kadar yalnızca 25 tane ve çoğu 5 karakterden kısa olduğu için yeterince hızlı” türü yorumların başka bir çeşidi de var
    Girdi, özgün tasarım kısıtlarının çok üzerine çıktığında tetiklenen debug log eklemek. Gelecekteki geliştiriciye neredeyse aynı mesajı verir, ama daha erken fark edilmesini sağlayarak teşhis ve debug süresini daha da azaltır

    • Çoğu durumda iyi bir fikir. Şimdilik çalışan ama çok yavaş bir döngü kullandığınız zamanlar olur; bir zamanlayıcı koyup “X saniyeden uzun sürerse uyarı log’u yaz” denebilir
      İdeal bir logging ve gözlemlenebilirlik sistemi, uygulamanın tüm bileşenlerinin süresini ölçer ve sık sık debug bilgisi bırakırdı; ama böyle kusursuz bir sistemi pratikte kim kullanıyor ki? Daha sonra performansı bozulabilecek ya da optimize etmeye zaman bulunamamış yerlere özellikle log eklemek daha önemlidir
      Geriye dönüp bakınca bariz bir fikir, ama şimdiye kadar daha sonra yeniden bakılması gereken yerlere yorum bırakıp işler kötüleştiğinde o yorumu hatırlamayı ummak şeklindeydi
    • bazel gibi iyi niyetli araçlar, hata olmayan çıktıları çoğu zaman gizlenmesi gereken gürültü olarak görür. Bu tür mesajları en yakın çöp kutusuna gönderiverdikleri için bazı alanlarda log, kısıtları aktarmanın çok güvensiz bir aracı hâline gelir
  • Kim ne derse desin, kodun her yerine bol bol yorum ve dokümantasyon yorumu yazarım. Ama tersinden yaklaşırım: önce uygulamanın adım listesini kabaca yorum olarak yazar, sonra geliştirdikçe büyük adımları küçük adımlara böler; ilk yorumları bazen siler, bazen bırakır ve neredeyse tamamlanmış bir algoritmaya dönüşene kadar yorumları ayrıntılandırırım
    Genelde dıştan içe doğru kod yazdığım için, yorumları bölerken kodu da beraber yazarım. Bazen de kodu topluca yazıp sonra, çoğu kişinin üşeneceği ölçüde yorum eklerim. Her fonksiyona ve değişkene açıklama koyarım; deg_to_rad fonksiyonuna bile """Converts degrees to radians.""" eklerim. Depolama alanı ucuz ne de olsa
    Çoğu kişinin bundan hoşlanmadığını biliyorum ama sorun değil. Görmek istemiyorsanız bir script ile kaldırabilir ya da kod incelemesinde silebilirsiniz. Yine de yorumsuz başkasının kodunu okumaktansa kendi eski kodumu okumak çok daha keyifli. Python’da Flask API gibi basit boilerplate kodlar genelde kendi kendini belgeler; ama bazen tam da bu boilerplate çok değiştiği için önemli yorumlar taşır. Sektörde algoritma tarafı ise çoğunlukla baştan yazılır
    Yorumları ve dokümantasyon yorumlarını sevmeye devam edeceğim

    • Benzerini yapıyorum ama çoğunlukla yalnızca en üst düzey bileşenlerde. Çünkü yorumların en faydalı olduğu yerler buralar
      Zihnimde genel kavramsallaştırmayı yapmayı seviyorum ve başlangıçta çeşitli tasarım seçeneklerini gerçekten yazarak denemeyi yavaş buluyorum. Bu yüzden bir tasarım seçimi netleştiğinde mutlaka belgelendirilmesi gerekiyor. Çünkü başkalarının henüz zihnimin içine erişimi yok
      Ayrıntıların, başkaları da kavramsallaştırmayı tamamladığında daha netleşmesini beklerim. Ancak herhangi bir nedenle o kavramsallaştırma gerçekleşmezse okunması daha zorlaşabileceğinden, en azından temel okunabilirliği korumak için ayrıca düzeltirim
    • Yorumlar iyi bakım gördüğünde harikadır. Ama okuyanlara kıyasla yorumları yöneten çok sayıda kişinin olduğu açık kaynak gibi durumlar dışında, sonunda herkes unutur ya da üşenir ve bakımını yapmaz
      Yorumları güncellemek de çoğu zaman kodu düzeltmek kadar iş olur. Bu yüzden pratikte yorumlar genellikle yalana dönüşmeyi bekleyen şeylerdir. Sonunda yorumla kod birbirinden sapar; bu da yorumsuz koddan bile daha kötü olabilir
      Bunun yerine niyeti gösteren otomatik testler daha iyidir. Testler genel olarak yalan söyleyemez; aksi halde zaten birleştirilmemiş olurdu. Kodun nasıl kullanılmasının amaçlandığını gösteren iyi bir test kümesi varsa, hem açıklayıcıdır hem de neredeyse doğru olduğu garanti edildiği için görmek isterim
    • “Hoşunuza gitmiyorsa kendi sürümünüzde bir script ile silin ya da kod incelemesinde kaldırın” kısmına kadar iyiydi; ama buradan sonrası bir ekip arkadaşı açısından büyük bir tehlike işareti gibi görünüyor
    • Ben de benzerim. Yaklaşık yarısında önce yapmak istediğim şeyi açıklayan yorumları yazar, sonra beklendiği gibi gitmeyen noktaları ve gerçekten çalışır hale getirmek için yapmam gerekenleri eklerim
      5 hafta sonra tekrar bakmam gerektiğinde inanılmaz yardımcı oluyor
    • Her durumda dokümantasyon yorumu gerektiğini düşünmüyorum; her fonksiyonun her parametresini ve dönüş değerini belgelendirmek gerektiğini de sanmıyorum. Ama karmaşık API’lerde kesinlikle faydalı
  • “Yorumlar gelecekteki kendime gönderilmiş bir özürdür” anlayışını izliyorum
    Kod tuhaf ya da yavaşsa veya birine açıklarken “biraz derme çatma” diyeceğim bir yerse genelde yorum bırakırım. Özellikle daha önce değiştirmeyi denediysem, çalışmayan durumları ya da yaptığım düzeltmeyi vb. belgelendiririm
    Bu ölçütle yaklaşırsanız gereksiz yorumlar doğal olarak ortadan kalkar ve genellikle gerçekten gerektiğinde nedenini belgelendirirsiniz. Kendi kod tabanınızda bir ay kadar deneyin; ne demek istediğimi anlarsınız