5 puan yazan GN⁺ 2025-06-18 | 1 yorum | WhatsApp'ta paylaş
  • Karmaşıklık, yazılım geliştirmedeki en tehlikeli unsurdur
  • Gerçek verimlilik, "80/20 çözümü" gibi karmaşıklıktan kaçınan pragmatik yaklaşımlardan doğar
  • Test ve refactoring konusunda dengeli ve esnek bir tutum sürdürmek önemlidir
  • Araç kullanımını ve okunması ile bakımı kolay kod yazma alışkanlığını vurgular
  • Aşırı soyutlamaya ve trendlere karşı dikkatli olunmasını, sadeliği hedefleyen bir yaklaşım benimsenmesini önerir

Giriş

  • Bu yazı, uzun yıllar yazılım geliştirirken deneyimden öğrenilenleri derleyen bir Grug Brain geliştiricisinin düşünce notlarıdır
  • Grug Brain geliştiricisi kendini çok zeki biri olarak görmese de, uzun yıllar programlama yaparak çok şey öğrenmiştir
  • Başkalarının hatalardan ders çıkarmasını umarak, farkındalıklarını kolay ve komik bir dille paylaşır
  • Karmaşıklık, geliştirme hayatının en büyük düşmanıdır
  • Karmaşıklık, kod tabanına gizlice sızar ve başta anlaşılması kolay olan kodu zamanla değiştirilemez hale getirir

Karmaşıklık şeytanıyla başa çıkmak

  • Karmaşıklık, görünmez bir ruh gibi sessizce yayılır ve proje yöneticileri ile Grug olmayan geliştiriciler bunu çoğu zaman fark etmez
  • Karmaşıklığı engellemenin en iyi yolu "hayır" diyebilmektir
    • "Bu özelliği yapmayacağım"
    • "Bu soyutlamayı eklemeyeceğim"
    • Elbette kariyer açısından yüksek sesle "evet" demek daha kazançlı olabilir, ama Grug Brain geliştiricisi kendine karşı dürüst olmayı önemser
  • Koşullara göre uzlaşmak (“ok”) da gerekir; bu gibi durumlarda sorunu 80/20 çözümüyle (Pareto ilkesi) basitçe çözmeyi tercih eder
  • Proje yöneticisine her ayrıntıyı söylemeden, işi gerçekte 80/20 yaklaşımıyla halletmek de akıllıca bir stratejidir

Kod yapısı ve soyutlama

  • Kodun uygun birimlere ayrılacağı yerler zamanla doğal olarak ortaya çıkar; bu yüzden erken soyutlamadan kaçınmak daha iyidir
  • İyi bir ayrım noktasında, sistemin geri kalanıyla arayüzün dar olması idealdir
  • Erken soyutlama girişimleri kolayca başarısız olur; deneyimli geliştiriciler, kodun şekli biraz oturduktan sonra yavaş yavaş yapılandırmayı dener
  • Daha az deneyimli ya da “big brain” geliştiriciler, projenin başında aşırı soyutlamaya gider ve geride bakım yükü bırakır

Test stratejisi

  • Testler konusunda takıntı ile denge arasında doğru noktayı bulmak önemlidir
  • Prototiplemeden sonra, kod biraz daha oturduğunda test yazmayı tercih eder
  • Unit testler başlangıçta yararlıdır, ancak pratikte en büyük faydayı orta seviye testler (integration testler) sağlar
  • End-to-end testler de gereklidir, ama fazla olduklarında bakımı imkansız hale gelebilir; bu yüzden yalnızca gerçekten gerekli yollar için az sayıda tutulmalıdır
  • Bir bug raporu geldiğinde, bug'ı düzeltmeden önce mutlaka yeniden üretim testi ekler

Süreç, agile ve refactoring

  • Agile, Grug geliştiricisine göre kötü değildir; en kötüsü de değildir, ancak "agile şamanlarından" aşırı beklentiye girmek risklidir
  • Prototipleme, araçlar ve iyi takım arkadaşları gerçekte daha önemli başarı faktörleridir
  • Refactoring de iyi bir alışkanlıktır, ama büyük ve zorlayıcı refactoring girişimleri risklidir
  • Karmaşık soyutlamaları zorla devreye sokmak, tersine projenin başarısız olmasına yol açabilir

Bakım, mükemmeliyetçilik ve alçakgönüllülük

  • Mevcut sistemi sebepsiz yere söküp yeniden yapmak risklidir; “neden var olduğu bilinmeyen bir yapıyı” düşünmeden kaldırmak iyi bir alışkanlık değildir
  • Kusursuz kod hayali kuran idealizm, pratikte çoğu zaman sorun üretir
  • Deneyim arttıkça, “çalışan koda saygı duymak” gerektiği daha iyi anlaşılır

Araçlar ve üretkenlik

  • İyi geliştirme araçları (IDE code completion, debugger vb.) üretkenliği ciddi biçimde artırır; bu araçları derinlemesine öğrenmek önemlidir
  • Tip sistemlerinin asıl değerinin “otomatik tamamlama” ve hata önleme olduğu vurgulanır; aşırı soyutlama ve generics ise tersine riskli olabilir

Kod stili ve tekrar

  • Daha okunabilir ve debug etmesi daha kolay kod için, koşulları birden çok satıra bölmek gibi stiller önerilir
  • DRY(Don’t Repeat Yourself) ilkesine saygı duyulur, ancak tekrar eden kodu zorla ortadan kaldırmaktansa dengenin daha önemli olduğu vurgulanır
  • Basit tekrarın, karmaşık bir DRY uygulamasından daha iyi olduğu pek çok durum vardır

Yazılım tasarım ilkeleri

  • SoC(Separation of Concerns) ilkesindense davranış yerelliğini tercih eder; "ilgili davranışı yapan kodun o nesnenin içinde olması bakım işini kolaylaştırır" görüşünü savunur
  • Callback/closure, tip sistemleri, generics, soyutlama gibi araçların yalnızca az ve yerinde kullanılmasını öğütler
  • Closure'ların aşırı kullanımı JavaScript'te "callback hell" yaratabilir

Logging, operasyon

  • Logging çok önemlidir; ana dallanmaların her birinde log bırakılmalı ve cloud ortamlarında request ID gibi bilgilerle izlenebilirlik sağlanmalıdır
  • Dinamik log seviyeleri ve kullanıcı bazlı loglar kullanılabiliyorsa, üretimdeki sorunların takibinde büyük fayda sağlar

Eşzamanlılık, optimizasyon

  • Eşzamanlılıkta, mümkün olduğunca yalnızca basit modellere (durumsuz web istekleri, ayrılmış worker queue'lar vb.) güvenir
  • Optimizasyonun ancak gerçek performans profiling verileri elde edildikten sonra yapılmasını önerir
  • Network I/O gibi gizli maliyetlere dikkat etmek gerekir; yalnızca CPU karmaşıklığına bakmak risklidir

API tasarımı

  • İyi bir API kullanımı kolay olmalıdır; aşırı karmaşık tasarımlar veya soyutlamalar geliştirici deneyimine zarar verir
  • "Kullanım senaryosuna uygun basit API" ile "karmaşık senaryoları da kurmaya imkan veren katmanlı API" yapısını önerir

Parser geliştirme

  • Recursive descent parser'lar akademide hak ettiği değeri görmese de, gerçek üretim kodu için en uygun ve anlaşılması en kolay yöntemdir
  • Parser geliştirme deneyimlerinin çoğunda, araçlarla üretilen parser'ların çıktısı fazla karmaşık olmuş ve problem çözmeyi kolaylaştırmak yerine zorlaştırmıştır
  • Önerilen kitap olarak "Crafting Interpreters"ı en üst sıraya koyar; kitap çok sayıda pratik tavsiye içerir

Frontend ve trendler

  • Modern frontend (React, SPA, GraphQL vb.) çoğu zaman gereksiz yere yeni karmaşıklık şeytanları çağırır
  • Grug, karmaşıklığı azaltmak için htmx ve hyperscript gibi daha basit araçları tercih eder
  • Frontend tarafında sürekli yeni denemeler yapılsa da, bunların çoğunun mevcut fikirlerin tekrarından ibaret olabileceğine dikkat çekmek gerekir

Psikolojik etkenler, impostor syndrome

  • Geliştiricilerin çoğu sık sık “ne yaptığını bilmiyorum” duygusuna kapılır; FOLD(Fear Of Looking Dumb) etkisinden özgürleşmek gerekir
  • Kıdemli bir geliştirici açıkça “bu bana da zor geliyor, fazla karmaşık” dediğinde, junior geliştiriciler de üzerlerindeki baskıyı bırakabilir
  • Impostor syndrome yaygın bir duygudur; insanın öğrenerek ve ilerleyerek gelişebileceği hatırlatılır

Sonuç

  • Programlamada karmaşıklığa karşı her zaman tetikte olmak gerekir; sadeliği korumak başarılı geliştirmenin anahtarıdır
  • Deneyim, araçların etkili kullanımı, alçakgönüllülük ve gerçekten çalışan koda saygı, uzun vadede daha verimli ve daha değerli bir geliştirme anlayışına götürür
  • "Karmaşıklık çok, çok kötüdür" — bu cümle her zaman akılda tutulmalıdır

1 yorum

 
GN⁺ 2025-06-18
Hacker News görüşleri
  • Ben iyi bir debugger’ın değerini parayla bile ölçülemeyecek kadar yüksek görüyorum, hatta pratikte daha da etkileyici buluyorum. İster küçük bir startup olsun ister ünlü bir big tech ekibi, çoğu zaman ekipte debugger kullanan tek kişi ben oluyordum. Hâlâ birçok insanın print satırlarıyla debug yaptığı gerçeğini gördüm. İş akışımı ekip arkadaşlarıma anlatmaya çalışsam da pek tepki almıyorum. Bir sistemi anlamaya başlamak için en iyi çıkış noktasının debugger olduğu fikrine katılıyorum. Test sırasında ilginç bir kod satırında durup stack’e bakmak, kodu kafada takip etmeye çalışmaktan çok daha kolay. Debugger kullanmayı öğrenirseniz gerçekten küçük bir süper güç kazanmış olursunuz. Mümkünse mutlaka bir kez denemenizi tavsiye ederim
    • Ben gerçekten düzgün bir debugger kullanmak istiyorum ama sadece büyük şirketlerde çalışmış biri olarak bu pratikte mümkün olmadı. Mikroservis mesh mimarisinde lokalde bir şey çalıştırmak mümkün olmuyor ve test ortamında da çoğu zaman step debugger bağlanamayacak şekilde ayarlanıyor. Bu yüzden print ile debug etmek tek mümkün seçenek oluyor. Hatta log sisteminde bile sorun çıkarsa ya da program log basamadan çöküyorsa, print bile kullanılamayan bir duruma düşüyorsunuz
    • Bu konuda yıllar önce iyi bir tartışma vardı. Brian Kernighan ve Rob Pike’ın bir sözü var; ikisi de genç geliştiriciler sayılmaz. "Biz debugger’ı stack trace ya da birkaç değişken değerine bakmanın ötesinde bir amaçla kullanmıyoruz. Karmaşık veri yapıları ve kontrol akışı yüzünden ayrıntılara saplanmak çok kolay. Programı zihinde daha çok düşünmek, aralara print çıktıları ve self-checking code eklemek daha üretken. print eklemek, debugger ile adım adım içeri girmekten çok daha hızlı. Ayrıca print kodu programda kalır, debugging session ise kaybolur." Ben de bu görüşe katılıyorum. Geliştirmenin büyük kısmında print-hipotez-çalıştır döngüsü çok daha hızlı sorun çözümü sağlıyor. Kodu kafamda “çalıştırmıyorum”; onun yerine kod akışı hakkında zaten bir çalışma modelim var ve print yanlış bir çıktı gösterdiğinde çoğu zaman durumun ne olduğunu hızla sezebiliyorum. İlgili bağlantı: The unreasonable effectiveness of print debugging
    • Linux tarafında printf ile debug etmenin hep yaygın olmasının nedeni, GUI tabanlı debugger’ların güvenilmez olduğu ortamlardı. Linux GUI’si çoğu zaman kararsız olduğu için güven vermiyordu. Benim de debugger’ı gerçekten kullanmaya başlamam şu dönemlere denk geldi: (1) Windows’ta GUI iyi çalışırken CLI’nin sık sık bozulduğu zamanlar ve (2) print ile debug kodunun yanlışlıkla sürüme girip sorun çıkardığını birkaç kez yaşadıktan sonra. Sonrasında CLI debugger’larla çeşitli maceralarım oldu ve Junit+debugger (Eclipse gibi IDE tabanlı) ile deneysel kodu anında yazıp test olarak bırakabildiğiniz sürecin Python REPL kadar kullanışlı olduğunu hissettim. Tabii debugger’ı ortama uygun şekilde kurmak için başta bir yatırım gerekiyor
    • Kendi kodumda debugger kullanmak kolay ve bunu gerçekten seviyorum. Ama debugger benim yazdığım koddan çıkıp kütüphane ya da framework içlerine derinlemesine indiğinde ben de hemen kayboluyorum ve hoşlanmamaya başlıyorum. Böyle framework/kütüphaneler on binlerce saat emekle üretildiği için benim seviyemde kavrayış sınırımı hızla aşıyor
  • Profesörüm (Carson), eğer bunu görüyorsanız size içten bir teşekkür iletmek istiyorum. Üniversitedeyken neden HTMX öğrendiğimizi, neden buna bu kadar tutkuyla yaklaştığınızı anlayamamıştım; ama birkaç yıl sonra gerçekten fark ettim. HTML over the wire gerçekten her şeymiş. Staff Ruby on Rails Engineer olarak çalışırken Hotwire içinde de hocamın çalışmalarına defalarca rastladım ve bazen GitHub ya da Hacker News’te aktif olduğunuzu görünce gerçekten şaşırıyorum. Siz her zaman programlama topluluğunun bir ışığı gibisiniz. Derin saygı ve teşekkürlerimi sunuyorum
    • Burada duygulanan tek kişi ben değilim, gerçekten etkileyici
    • HTMX sadece bir meme değil miydi? Poe’s Law yüzünden ciddi olup olmadığını anlayamıyorum
  • Bu yazıda gerçekten çok iyi söz var ama ben en çok mikroservis kısmını sevdim: "grug, büyük beynin sistemi düzgün parçalara ayırmakta zorlanırken neden bir de ağ çağrılarını eklediğini anlamıyor"
    • Bazı insanlar sistemi parçalara ayırmanın tek yolunun onu API yapmak olduğunu sanıyor. API olarak açığa çıkarılmıyorsa, onu sadece anlaşılamayan ve yeniden kullanılamayan opak kod olarak görüyorlar
    • Çeşitli nedenlerle mikroservislerin pratik olduğu durumlar olduğu için kullanılıyor olması biraz üzücü
    • Çok basit bir web uygulamasında sadece beş form olsa bile, iki kişilik küçük bir geliştirme ekibinin bunu “mikroservis” yapısı diye gereksiz yere karmaşıklaştırdığını sürekli görüyorum: paylaşılan veritabanı, API yönetimi, kuyruk üzerinden batch işleri, e-posta bildirimleri, kendi observability platformunu eklemek vb. Sonunda da sıradan formları bile SPA yapıyorlar çünkü sözde “daha kolay”. Artık “mimari” ve “pattern” denen şeylerin, işe yaramaz geliştiricilere meşguliyet üretmek için var olduğunu anlıyorum. Bunlar olmasa ellerinde “Bana bir parça sandviç verin, JavaScript kullanayım” pankartıyla sokakta olacak tipler
    • Benim bir komplo teorim var: mikroservis pattern’inin bu kadar yayılmasının nedeni cloud vendor’ların bunu itmesi. - K8S gibi orchestrator’lar olmadan çalışamaz hale getiriyorsun, böylece yönetilen cloud satmak kolaylaşıyor - Daha fazla ağ trafiği/CPU kullanımıyla daha çok ücret çıkar - Büyük ölçekli state paylaşımı zorlaştığı için yönetilen veritabanı/olay kuyruğu gerekiyor - Lokalde çalıştırmak zorlaşıyor, dolayısıyla geliştirme ortamı da cloud maliyetine dönüşüyor - Cloud’a özgü yaklaşımlara bağımlı kalıp çıkmak zorlaşıyor. Eskiden cloud’un BT maliyetlerini azaltacağını reklam ediyorlardı; tamamen komik. Bunun bir yanılsama olduğu 2000’lerden beri belliydi ve sonuçta her şey sadece daha pahalı hale geldi
  • "Karmaşıklık mı yoksa yüz yüze bir tiranozor mu; grug karmaşıklık yerine tiranozoru seçer: en azından tiranozor görünür" cümlesi o kadar etkileyiciydi ki haftada bir kez aklıma geliyor
    • Alıntı: "Düşerken bile Leyster küreği bırakmamıştı. Panik içinde bunu fark etmemişti. Bu yüzden umutsuzca küreği kaldırıp yavru tiranozorun bacağına savurdu...". Tiranozorla verilen o aşırı hayatta kalma mücadelesini çok canlı anlatan bir sahne. Sonunda ekip arkadaşı Tamara’nın cesurca mızrağı tiranozorun tam yüzünün ortasına saplayıp krizi aşması unutulmazdı. Savaş, gerilim ve ardından gelen sessizlik sahnesi çok etkileyici
    • Belli ki grug hiç “görünmez” bir tiranozorla dövüşmek zorunda kalmamış. Ben şu anda görünmez bir tiranozorla bire bir mücadele ediyorum ve gerçekten çok zor
  • Bu makaledeki asıl hayranlık uyandıran nokta, yazarın “daha karmaşık şeyi” yapabilecek olsa bile deneyimle o yolu seçmemesi. Elbette soyutlamanın ya da karmaşıklığın gerekli olduğu zaman ve yerler var ama grug felsefesi bunların kendi başına özsel bir değer taşımadığını söylüyor. Bence bu çok isabetli. Yapay zekanın da tutarlı ve veriye dayalı kodda daha etkili olduğunu hissediyorum
    • Karmaşıklık ve soyutlama, ancak kodu öncekinden daha anlaşılır yaptığında kullanılmalı. “Anlamak için ayrıca özel bir ders gerekmiyorsa” öncülünü akılda tutmak gerek. (Duruma göre değişir)
    • "Her şey olabildiğince basit yapılmalı, ama gereğinden fazla basit değil"
  • Bunun 2022 tarihli bir yazı olduğuna inanmak zor. Sanki bunu 10 yıl önce okuyup çoktan bir “klasik” olarak zihnime yerleştirmişim gibi geliyor
  • Bu deneme, yazılım yapmak üzerine en sevdiğim yazı. Üslubu da çekici (bazılarına itici gelebilir), ama özü her zaman geçerli
  • "Üzücü ama gerçek: 'evet' demeyi öğren, işler ters gidince suçu başka bir grug’a atmayı öğren, en iyi kariyer stratejisi" şeklindeki kod parçası tam anlamıyla gerçek hayat. Ben de başta şirkette bunun sadece teknik ekibin iletişim sorunu olduğunu sanıyordum ama zamanla (grug gibi) gerçekten öyle olduğunu öğrendim
  • Şimdiye kadar gördüğüm visitor pattern açıklamaları arasında bu makaledeki en iyisiydi
    • Ben tipik bir OO kod tabanında çalışmadığım için visitor pattern’in ne olduğunu tam bilmiyordum; ama interpreter/VM yapımıyla ilgili "Crafting Interpreters" kitabını önermek isterim. Orada visitor pattern’in pratikte nasıl kullanıldığı gösteriliyor. Okurken karmaşıklığın nedenini anlamaya çalıştım ama sonunda onu tagged union ile değiştirdim. Belki OO tarafında zayıfımdır ama grug yazısının temel noktası da bu: gereksiz yere karmaşıklık ve dolaylılık seçmek zorunda değilsin; daha sezgisel yollar olabiliyor
    • İsimlendirme konusunda hassasım ve visitor pattern adı bana fazla belirsiz geliyor. Gerçekte hiç Visitor adlı bir şey yazmadım. Mesela sözdizim ağacı (AST) çalışıyorsanız, Visitor yerine AstWalker, AstItem::dispatch(AstWalker), AstWalker::process(AstItem) gibi daha somut adlandırmalar çok daha anlamlı. visitor denince “ziyaret eder” demek fazla soyut ve anlamsız kalıyor. Duruma göre değişir tabii; ayrıca yoruma bunun “visitor pattern” olduğunu yazarsanız tanınmasında sorun olmaz. Geçmişte iki nesne ağacını eşleyip verileri karşılaştırma/aktarma işi yapmıştım; orada AbstractImporter adını kullanmıştım. Daha somuttu, süreç ve rol daha açıktı. Klasik visitor pattern’den farklıydı
    • Az önce baktım, buna “Bad” diyenler de olmuş. haha
  • İlgili yazıları da paylaşıyorum. Başka görüşü ya da ek yazısı olan var mı?<br/><i>The Grug Brained Developer (2022)</i> - https://news.ycombinator.com/item?id=38076886 - Ekim 2023 (192 yorum)<br/><i>The Grug Brained Developer</i> - https://news.ycombinator.com/item?id=31840331 - Haziran 2022 (374 yorum)