1 puan yazan GN⁺ 2023-10-05 | 1 yorum | WhatsApp'ta paylaş
  • 20 yılı aşkın süredir yazılım geliştirme deneyimime göre güçlü statik tipleme, REPL veya tek seferlik script’ler gibi istisnalar dışında neredeyse her zaman tercih etmeye değer
  • Tipler, çağıran ile çağrılan arasındaki sözleşmeyi kodda bırakarak yanlış parametreleri veya dönüş değerlerini derleme/tip denetimi aşamasında eler
  • HTML girdisinden gelen "20" string’inin sayı gibi kullanılıp "201" sonucunu üretmesi örneği, çalışma zamanından önce yakalanan hata ile müşteriye yansıyan hata arasındaki farkı gösterir
  • Svix; Redis anahtarlarını, cache değerlerini, PersonId·PetId gibi tanımlayıcıları ve API girdi doğrulamasını tip sistemine taşıyarak yazım hatalarını ve yanlış ID aktarımını azaltmaya çalışıyor
  • Tipleri atlamak ilk implementasyonu hızlandırabilir, ancak dokümantasyon, test ve debug maliyetini büyütür; tip çıkarımı ve IDE desteği kullanıldığında refaktör ve onboarding daha kolay hale gelir

Statik tiplerde neden ısrar ediyorum

  • Güçlü statik tipleme, iyi bir fikir olmanın ötesinde, çoğu yazılım için doğru varsayılana yakındır
  • Tipsiz dillerin veya varyantlarının da işe yaradığı yerler vardır
    • REPL kullanımı
    • Zaten neredeyse hiç tipin olmadığı ortamlardaki tek seferlik script’ler, örneğin shell
  • Bunun dışındaki çoğu durumda güçlü tipleri tercih ediyorum
  • Tip kullanmamak, kısa vadede geliştirme hızını artırabilir ama bana göre bu, “uçuruma doğru tam gaz gitmeye” daha yakındır
  • Seçenek sonunda ikiye iner
    • Daha fazla emek verip değişmez koşulları derleme veya tip denetimi aşamasında doğrulamak
    • Daha az emek verip bunları çalışma zamanında doğrulamak ya da hiç doğrulamamak
  • Çalışma zamanı hataları geliştirme sırasında her zaman yakalanmaz; yakalansa bile müşteriye görünür şekilde ortaya çıkabilir
  • Testler yardımcı olur, ancak olası tüm yanlış fonksiyon parametre tiplerini test etmek zordur; yanlış tipleri tiplerle engellemek daha kolaydır

Tipler, kod sözleşmeleri ve hata azaltımıyla doğrudan bağlantılıdır

  • Tipler, hem insanlar hem araçlar için faydalı kod açıklamalarıdır ve kod parçaları arasındaki sözleşmeyi daha sıkı hale getirir
  • Aynı doğum günü kutlama fonksiyonunda bile sözleşmenin açıklığı ciddi biçimde değişir
    • birthdayGreeting1(...params), parametre sayısını bile göstermediği için dokümantasyonu okumadan nasıl çalıştığını anlamak zordur
    • birthdayGreeting2(name, age), bir isim ve yaş olduğunu ima eder ama tip bilgisi yoktur
    • birthdayGreeting3(name: string, age: number): string, girdi ve dönüş tiplerini de sözleşmeye dahil eder
  • Fonksiyon age + 1 kullanacak şekilde değiştiğinde tipsiz sürüm string girdilerde sorun çıkarır
    • HTML input’tan gelen değerler her zaman string olabilir
    • birthdayGreeting2("John", "20"), "John will turn 201 next year!" döndürür
    • Tipli sürümde age sayısal olmak zorunda olduğu için yanlış çağrı derlemede başarısız olur
  • Çağıran ile çağrılan arasındaki sözleşme, kod tabanı büyüdükçe daha önemli hale gelir
    • Çağrılan taraf değiştiğinde bunun çağıranı nasıl etkilediği anlaşılabilir
    • Açık kaynak kütüphanelerde olduğu gibi çağıran ile çağrılanı farklı kişilerin yazdığı durumlarda bu özellikle önemlidir
  • Bu tür sözleşmeler olmadan, bir değişikliğin nereye kadar etki ettiğini anlamak zordur

Geliştirici deneyimi, refaktör ve onboarding açısından avantajlar

  • Tip bilgisi, IDE’lerin ve geliştirme araçlarının bunu kullanarak geliştirici deneyimini ciddi ölçüde iyileştirmesini sağlar
  • Kodu yazarken beklentiniz yanlış olduğunda bunu hemen görmek bilişsel yükü azaltır
  • Geliştiricinin mevcut bağlamdaki tüm değişken ve fonksiyon tiplerini akılda tutması gerekmez; derleyici uyumsuzlukları gösterir
  • Refaktör de kolaylaşır
    • Bir fonksiyon implementasyonunu değiştirirken başka yerlerdeki varsayımları bozup bozmadığınızı derleyici söyleyebilir
  • Yeni mühendislerin kod tabanına veya bir kütüphaneye uyum sağlaması da kolaylaşır
    • Tip tanımlarını takip ederek nerelerde kullanıldığını anlayabilirler
    • Değişiklik yaptıklarında derleme hatası oluşacağı için deneme yapmak kolaydır
  • Person tipi alan fonksiyon örneği bu farkı gösterir
    • birthdayGreeting3(person: Person), IDE ile Person kullanım noktalarını bulmayı kolaylaştırır
    • Tipsiz birthdayGreeting2(person) fonksiyonunun aslında Person beklediğini anlamak için tüm kod tabanını okumak gerekir
  • Dokümantasyon bazı boşlukları doldurabilir, ancak dokümanlar kolayca eskiyebilir; tipler ise kodun içinde yaşayan dokümantasyon olur
  • Tipler, faydalı değişken adlarının daha güçlü bir biçimine yakındır

Svix bilgiyi tip sistemine nasıl koyuyor

  • Svix, derleme zamanında yakalanabilecek hataları azaltmak ve geliştirici deneyimini iyileştirmek için mümkün olduğunca fazla bilgiyi tip sistemine koymaya çalışıyor
  • Redis doğası gereği string tabanlı bir protokoldür ve yerleşik tipleri yoktur; bu yüzden Redis katmanında tiplerin avantajı kaybolabilir
  • Basit bir cache örneğinde iki hata vardır
    • person-{id} yerine preson-{id} yazılması gibi anahtar adı yazım hatası
    • Kişi verisini Pet tipi olarak yüklemeye çalışma
  • Svix bu sorunlardan kaçınmak için iki şey uyguluyor
    • Anahtarların sıradan string değil, belirli bir tip olmasını şart koşuyor
    • Anahtar ile değeri zorunlu olarak eşleştiriyor
  • Örneğin PersonCacheKey::new(id) ile oluşturulan bir anahtar kullanıldığında, cache.get(PersonCacheKey::new(id)) sonucunu Pet olarak almaya çalışan kod derlemede başarısız olur
  • Basit String ID’ler de hataya açıktır
    • do_something(id: String), hangi ID’nin beklendiğini açıkça göstermez
    • Aslında pet.owner verilmesi gereken yere pet.id verme hatası yapılabilir
  • Svix her ID için ayrı bir tip tanımlar
    • PersonId(String)
    • PetId(String)
    • Pet içindeki owner, PersonId tipindedir
  • API’den gelen ID’nin geçerliliği de tip oluşturmayla ilişkilendirilir
    • Örneğin pet ID’si, pet_ önekinin ardından bir Ksuid gelen biçimdedir
    • PetId, doğrulama yapılmadan oluşturulamaz
    • Bu sayede veritabanında pet bulunamadığı için 404 Not Found döndürdüğünüzde, en azından ID biçiminin geçerli olduğundan emin olabilirsiniz
    • Geçersiz ID’ler zaten API handler’da 422 veya 400 olarak ele alınır

Karşı argümanlar ve araçların rolü

  • Tiplere yönelik başlıca itirazlar geliştirme hızı, öğrenme eğrisi ve tip karmaşıklığı, ayrıca emek ve boilerplate maliyetidir
  • Tipsiz prototipleme gerçekten daha hızlı olabilir
    • Derleyici şikâyet etmeden kodu yorum satırına alabilirsiniz
    • Doğru değerler netleşmeden alanlara yanlış değerler koyabilirsiniz
  • Ancak bu yaklaşımın, agresif ve gereksiz bir teknik borç olduğu; local’de, test suite’te ve production’da debug ederken bedelinin defalarca ödendiği düşünülüyor
  • Bir öğrenme eğrisi vardır, ancak çoğu insanın tip uzmanı olması gerekmez
    • Basit tip ifadeleriyle bile rahatça çalışılabilir
    • Tıkandığınızda yardım almak yeterlidir
  • Geliştiriciler zaten kodlama, React, Axum gibi framework’ler ve daha fazlasını öğrenmek zorundadır; bu yüzden tip öğrenme yükünün abartıldığı düşünülüyor
  • Tipleri öğrenmenin maliyeti bir kereliktir; buna karşılık belirli bir kod tabanına onboarding sırasında tiplerin sağladığı fayda daha büyüktür
  • Tip kullanılmadığında temel güvenilirliği sağlamak için ciddi miktarda dokümantasyon ve test gerekir
    • Dokümanlar ve testler eskiyebilir
    • Doğru tipleri eklemek daha az çaba olabilir
  • Tip çıkarımı olmayan dillerde tipleme can sıkıcı olabilir
    • Java örneğinde Person person1 = newPerson(); gibi tekrarlar oluşur
    • Yazıya daha sonra Java’da tip çıkarımı da olduğuna dair bir düzeltme eklenmiştir
  • Rust gibi tip çıkarımı olan dillerde let person1 = new_person(); gibi daha kısa bir yazım mümkündür
  • Tiplerin avantajından yararlanmak için dili anlayan modern code completion özelliklerine sahip bir kod editörü veya IDE gerekir
  • vim ve emacs, tab ve space gibi tercih tartışmalarının aksine, tiplerin maliyet/fayda oranı o kadar yüksektir ki kullanılmamasını anlamak zor bir tutum olarak görülür
  • Devam yazısı olarak using the type system effectively bulunuyor

1 yorum

 
GN⁺ 2023-10-05
Hacker News görüşleri
  • Bu tartışmada en sinir bozucu olan şey, her şeyin insanların nasıl hissettiği üzerinden konuşulması ve ampirik kanıtın eksik olması.
    Mevcut araştırmalar iki yaklaşım arasında anlamlı bir fark olmadığını gösteriyordu; yeni bir araştırma yoksa herkesin kendi tercih ettiği tarafın kesinlikle doğru olduğunu söylemek zor.
    Kişisel olarak tipli dilleri seviyorum, ama TypeScript gibi tip sistemleri yetersiz. Tipleri runtime'da gerçekten kullanamadığınız için runtime hataları kalıyor ve çok sayıda runtime mantığını tip sistemine kodlayamadığınızdan, imkânsız durumları hâlâ elle kontrol etmek zorunda kalıyorsunuz.
    Tip sistemi runtime hatalarını düşünme ihtiyacını neredeyse ortadan kaldırsa bu ezici bir avantaj olurdu; ama çoğu dil o seviyede değil, overhead ile bazı faydalar arasında belirsiz bir orta noktada kalıyor.
    Hata sayısı ya da hızda büyük fark olmamasının nedeni sanırım sonuçta birbirini dengelemesi. Tip güvenlik ağı yoksa daha fazla test yazıyorsunuz; tersine tip sistemine fazla güvenince de sonuçta benzer miktarda runtime hatası kalıyor. Bu konuda sağlam bir araştırma olmasını isterdim, ama zor bir mesele.

    • Çoğu kişi tiplerin birçok hatayı engellediği konusunda hemfikir olur gibi; bu thread'e de böyle bir araştırma konmuştu.
      Asıl mesele daha çok, tiplere yatırım yapmaya değmeyeceğine karar vermenin öznel nedenlerinin ne olduğu.
    • Sonunda bunu bir muhakeme meselesi olarak kabul etmek gerekecek gibi.
      Birkaç yıl önce geliştirici üretkenliği araştırmalarına bakmıştım; neredeyse hepsi berbat durumdaydı ya da ancak junior'lara düzgün uygulanabilecek şeylerdi. Örneğin acemiler statik hatalara hızlı geri bildirim almaktan büyük fayda görüyor.
      İyi bir deney tasarımını üniversite öğrencileri yerine uzmanlara uygulamak neredeyse imkânsız; bireysel farklar, geliştirme türü, yönetim biçimi gibi sayısız değişkeni ayrıştırmak gerektiğinden sinyali çıkarmak zor. Üzücü ama hayattaki birçok şeyi etkili biçimde ölçmek zor.
    • Ben de neredeyse aynı düşünüyorum.
      Yazı ve birçok yorum programcı konforundan, üretkenlikten, “doğruluktan” söz ediyor; ama mevcut araştırmalar statik tiplerin bunları iyileştirdiğine ya da kötüleştirdiğine dair anlamlı bir sonuç vermiyor. Fiilen öznel.
      Ancak statik tiplerin gerçekten sağladığı tek etki önemsiz biçimde kanıtlanabilir: Daha verimli kod yazmayı mümkün kılması. Tip disiplini tartışmalarının merkezinde bu olmalı; geri kalanı şu aşamada havada kalan şeylere yakın.
      Yazıda kullanılan TypeScript aslında güçlü tipli değil; statik tipli ama zayıf tipli. Tipler neredeyse yorum satırı gibi; performans ya da bellek yerleşimi garantisi de yok. Bu yüzden belgeleme dışında, statik tiplerin maliyetini öderken pratikte neredeyse hiç gerçek fayda elde edemiyorsunuz.
      Teknoloji topluluğunun gerçek kanıtları görmezden gelip kültürel ve kişisel tercihleri olgu gibi kabul etmesi şaşırtıcı.
    • Statik tipler, daha güvenilir yazılım için İsviçre peyniri dilimlerinden yalnızca biridir.
      Diğer teknikler gibi onun da delikleri var; bu yüzden azami güvenilirlik için birden fazla tekniği birleştirmek gerekir. Her şeyi yakalayamıyor diye statik tipleri bırakmak, hırsız camı kırabilir diye kapıyı kilitlememeye benzer. Güvenlik gerçekten önemliyse hem kapıyı kilitler hem de pencerelere demir parmaklık takarsınız; ikisinden yalnızca birini seçmezsiniz.
    • Programı, tipleri ifade eden bir dille yazınca “runtime hataları”nın sihirli biçimde ortadan kalkacağını düşünüyor gibisiniz.
      Bir dil genel programlar yazacak kadar güçlüyse, hata yapmaya da yetecek kadar güçlüdür.
      Statik tipler belirli türdeki hataları yakalamada etkili olabilir, ama hepsini değil. Bazen statik birim testleri ya da çalıştırılabilir dokümantasyon için alan odaklı bir dil gibi okunabilirliği artırırlar.
      Genel olarak dinamik diller daha çeviktir ve daha kolay, daha çok test yazmaya imkân verir. Statik tipli bir dil olsaydı yazmanız gerekmeyecek testler de vardır; dolayısıyla tipler hâlâ faydalıdır, ama yaygın inanıldığı kadar evrensel ölçüde güçlü değildir.
  • Statik tipleri sevmek gerektiğine dair toplumsal baskıdan bağımsız olarak, sonunda statik tiplerden uzaklaşmamın nedeni her zaman etrafında bir fildişi kule inşa edilmiş olmasıydı
    Her iki paradigmada da ayrı ayrı 10’ar yıl yazılım geliştirdim ve artık tip sistemi kullanmamayı tercih ediyorum
    Dinamik tipler, birim testlerin birleştirilebilir kodu zorunlu kılması gibi, basit kod yazmaya zorlayan bir güç gibi geliyor. Okuması ve anlaması kolay koddan söz ediyorum
    Yeni geliştiricilerin kod tabanına daha kolay yaklaşabildiği iddiasını da pek iyi bulmuyorum. Çünkü anlamadan yalnızca kırmızı işaretleri ortadan kaldırmaya yönelik bir tekrar döngüsünü teşvik etmesi kolay. Tip sistemi, her projede dilin üzerine bir de son derece alana özgü başka bir dil öğrenmeyi gerektiriyor ve çoğu zaman gerçek davranışı anlamayı engelliyor
    Metinde ortaya konan sorunlar, tipler kadar sağlam ama anlaşılması daha kolay biçimlerde çözülebilir. Tipleri basit kullanmak mümkün olabilir, ama benim deneyimime göre pratikte neredeyse hiç öyle olmadı. Otomatik tamamlamayı da sevmiyorum; böyle kabul edin
    Belki de “kod dokümanın ta kendisidir” diye bağıran yaşlı bir geliştiriciyimdir; ama bu düşünce, bugün sektörde bolca görülen “ChatGPT doğru dedi ve yüksek maaş alıyorum” geliştiricilerine duyulan derin hoşnutsuzluktan da çıkmış olabilir

    • Dinamik tipler çoğu geliştiriciye gerçekten basit kod yazdırıyorsa bu çok güçlü bir argüman olurdu
      Ama genel olarak karşı kanıtlar daha güçlü görünüyor. Gerçek dinamik kodu belgelendirmek için sonradan yazılan tipler, aynı işlevin baştan statik tiplerle uygulanmış hâlinden çoğu zaman çok daha karmaşık oluyor. TypeScript ekosistemindeki DefinitelyTyped bunun sayısız örneğini sunuyor
      Bu tiplerin “basit kullanıldığını” söylemek zor; ancak bu karmaşıklık tip sisteminin kendisinden ya da tip tanımlarının sunulma biçiminden değil, açıkladığı dinamik kodun karmaşıklığından kaynaklanıyor
      Baştan statik tiplerle yapılmış eşdeğer paketlerin arayüzleri genellikle daha basit oluyor. Çünkü tipler sonradan mevcut API’ye uydurulmaya çalışılmıyor, en başta tanımlanıyor
      Hatta arayüzü açıkça belirtmeden o arayüzün basit mi karmaşık mı olduğunu bile bilemeyeceğimizi düşünüyorum. “Kod dokümandır” idealine katılıyorum; ancak arayüzü açıkça belirten kod yoksa, o arayüz tanım gereği eksik dokümante edilmiştir
    • “Tip sistemi yeni geliştiricinin anlamasını engeller ve yalnızca kırmızı işaretleri yok etmeye iter” sözü ilk duyulduğunda bana tam tersi gibi geliyor
      Hatta böyle bir sahneyi yanımda görmek isterdim. Benim alanımda alana özgü mantık, dinamik tipli kod tabanlarında neredeyse anlaşılmazken, statik tipli kod geliştiriciye iş mantığını öğretir
      “Kod dokümandır” sözü de bana aksine kafa karıştırıcı geliyor. Kendi deneyimime göre kodun doküman olabilmesi için statik tipler gerekir. Yoksa bir nesnede hangi özelliklerin olduğunu, var olmadığını düşündüğünüz bir özelliğin neden kontrol edildiğini bilmenin yolu yoktur. Yorumlar var ama anlamlı yorum bırakan insanı neredeyse hiç görmedim
    • Bu mantığın neredeyse tamamı bana tersine çevrilmiş gibi geldiği için anlaması zor
      Benim deneyimim bunun tersi. Çok dinamik örüntülere düzgün tip eklemek zordur; iyi bir tip sistemi daha basit örüntüleri teşvik eder ve tipler de basitleşir
      Kırmızı işaretleri kaldırmak önemlidir. Kırmızı işaret bir sorun olduğu anlamına gelir ve hatayı başka yollarla bulmaktan çok daha kolaydır. O hatayı neden daha sonra keşfetmek isteyesiniz, anlamıyorum
      Otomatik tamamlamayı da sevmediğini söylemesi, beni statik tip karşıtlarına güvenmemek gerektiği tarafına itiyor. Bilgisayarın programlamaya yardım etmesini istemeyen bir programcı çok şüphelidir
    • Fildişi kulelerin ve toplumsal baskının belirli bir teknolojiyi benimsemekten soğutabileceği iyi bir nokta
      Ancak bu, teknolojik avantajları azaltmaz. Bir teknoloji harika olabilir, etrafındaki insanlar ise kendini beğenmiş olabilir
      Dinamik tiplerin basit kod yazdırdığı iddiası, “göz bandıyla araba kullanırsan yavaş sürersin, bu da iyidir” demek gibi geliyor. Amaç buysa satır uzunluğuna veya parametre sayısına sınır koyan bir linter kullanılır; kısıtı dolaylı biçimde yaratmaya gerek yok
      Tipler tek çözüm değil ama yatırıma göre getirisi çok yüksek olduğu için önce çıkarılacak araç olduğunu düşünüyorum. Yatırım neredeyse yok, kazanç büyük
      “Kod dokümandır” sözüne katılıyorum, ama tipler de kodun bir parçası. Bu yüzden bunu “kod dokümandır ve tipler kodun bir parçasıdır” diye ifade etmek isterim
    • Neredeyse aynı cevabı yazmak üzereydim
      Bulunduğumuz alan mühendislik; tek bir doğru yok ve her şey bir ödünleşim. Zaten bu yüzden işimiz hemen otomatikleşip ortadan kaybolmuyor
      Bu başlıkta başka mühendislerin görüşleri ya da deneyimleri yüzünden onları “küçümseyen” hava gerçekten rahatsız edici
  • Verilerin çoğunun ağ üzerinden JSON olarak gidip geldiği bir durumda güçlü statik tip uygulama mücadelesi genellikle tutarsız yürütülüyor
    Kullanılabilecek tüm araçlar kullanılmalı, ama çoğu “veri” sanıldığından çok daha gevşek. İnsanların telefon numarasını string olarak tutması tembellikten değil; bir zamanlar daha güçlü bir tipe dönüştürebileceklerini sanıp fazlasıyla canları yandığı için. İsim, adres ve posta kodu da aynı
    Bu değerler kullanıcıdan alınmak zorunda ve fiilen metni parse etmekten başka yol yok. Parse etmeden önceki ham metni saklamayacak bir sistem kurarsanız, bir gün neredeyse kesinlikle pişman olursunuz
    Özgün giriş metnini saklayıp bunu backend kullanıcılarına tipli bir veri kümesi olarak sunan bir katmanın en iyisi olduğunu düşünüyorum; ama herkesin kendi küçük alanında bunun yatırıma değip değmeyeceğini tartması gerekir
    Ağır değerlendirme yapılıyorsa SAT’a ya da başka bir sayısal modele dönüştüren bir katmana ihtiyaç duyulması çok muhtemel. O dünyada sayılar soyutlamadır. Başka türlü yapmaya çalışırsanız neredeyse kesinlikle acı çekersiniz. Problemi formülasyona, çözüm uzayını da domaine çeviren bir katman koymak iyidir; tipler burada yardımcı olabilir, ama pratikte ilgi gören “tipler” çoğu zaman bu tür tipler değildir

    • Yazının yazarıyım. Svix’te yaptığımız yöntemde tek bir paragrafta sadece kısaca değinip daha fazla açıklamam gereken bir şey vardı
      Serde ve Pydantic gibi kütüphaneler sayesinde deserialization aynı zamanda doğrulamadır yaklaşımını izliyoruz. JSON verisini kod içindeki struct’lara dönüştürmeden önce her şeyi doğruluyoruz
      Redis örneğine benziyor: Ağ üzerinden JSON alsak bile tamamen doğrulandıktan sonra koda ulaştığında bunun düzgün biçimlendirilmiş bir tip olduğundan emin olabiliriz. Bu yüzden kodda e-posta tipinin geçerli bir e-posta, ID tipinin de geçerli bir ID olduğunu varsayabiliyoruz
    • İsim ve adres, derinlemesine bakıldığında ikisi de string olsa bile yine de string değil, ayrı tipler olarak kullanılmalı
      İsim alanı ile adres alanını karıştırmak neredeyse her zaman hatadır ve tip sistemi bunu zorunlu kılabilir
    • Verilerin çoğu JSON olarak gidip geliyor diye gerçekten bu kadar kaotik mi oluyor? Belirli durumlarda Map de tamamen makul bir tiptir
  • Yazım hatası çalışma zamanı hatasına dönüşüyorsa bu “daha hızlı ilerlemek” değildir; bir fonksiyon imzasını değiştirdiğinizde kod tabanında grep yapıp tüm çağrı noktalarını bulmanız ve hepsini düzelttiğinize dua etmeniz gerekiyorsa bu da “daha üretken” olmak değildir.
    Tipler iyidir ama her şeyin fazlası sorun olur. Tüm iş mantığını tip sistemine kodlamayı hayat amacı edinirseniz, hiç tip olmamasından daha anlaşılmaz bir karmaşa ortaya çıkar. Hata mesajındaki tip adı tek satıra sığmıyorsa fazla ileri gitmişsiniz demektir.

    • Çılgın TypeScript tip tanımları gördüm.
      Adil olmak gerekirse eski saf JS koduyla uyum sağlamak içindi ve o zavallı değişkene her tür değer girebiliyordu.
      TypeScript’e sonsuza dek minnettarım ama gelecekte “tiplerin fazla ileri gittiği dönem” diye bir makaleye böyle kodlar girse şaşırmam.
    • Eskiden from pdb import set_trace: set_trace() ile etkileşimli düzenleme yapılabildiği için, derleyicidense çalışan programla etkileşime girmenin daha iyi olduğunu düşünürdüm.
      Ama program biraz karmaşıklaşınca durum değişiyor. Sistemler arasında kuyruklarla veri aktarmaya, asenkron/thread/multiprocessing kullanmaya, performans açısından kritik kısımlarda derlenmiş ikili kütüphaneler kullanmaya başlayınca, sonunda hepsini Erlang ile yazmış olmayı diliyorsunuz.
    • Fonksiyon imzası değişikliklerini gerçekten böyle yapan insanların nasıl çalıştığını çok merak ediyorum.
      %100 kod kapsamına sahip çok katı testler gibi genel bir metodolojileri mi var?
    • Statik tipler hakkında bu tür şikâyetleri her gördüğümde, tip tanımlarını ve mimariyi nasıl kurmuşlar da bu sorun oluyor diye merak ediyorum.
      Build ya da derleme zamanında çağrı noktalarını yakalayamıyorsa statik tip kullanmıyorsunuz demektir.
    • Bu iki şeyin tip tartışmasıyla nasıl bağlantılı olduğundan emin değilim.
      Yazım hataları, en güçlü statik tipli dillerde bile hatalı kod üretebilir. Yoksa kod yazmak tam olarak ne anlama gelir ki? Çalışma zamanı hatası mı daha kötü, yoksa hata vermeden yanlış sonuç üretmek mi?
      Bir Python projesini çalıştırmak C++ derlemekten daha hızlı olabilir ve dinamik tipli diller de fonksiyon çağrılarını bulmak için grepten daha iyi yollar sunabilir.
  • Tip kullanmamanın geliştirme hızını artırdığı iddiası da benim deneyimime uymuyor. Statik tipler günlük programlamayı hızlandırır.
    IDE’nin statik tipler sayesinde daha iyi hâle geldiğini ileride ele almıştı, ama bunu REPL’de de hissediyorum. Statik olarak yakalanan tip hataları, asıl kök nedene çok daha yakın anlamlı hata mesajları verir ve bunları çalışma zamanı hatalarından daha hızlı düzeltirsiniz.
    Tipler konusunda aşırı dikkatli düşünme yükünü de azaltır. Disiplini derleyici koruduğu için benim daha az kaygılanmam yeterli olur. Büyük bir hata sınıfının anında yakalanacağı güveniyle daha hızlı hareket edebilirim.
    Benim deneyimime göre statik tip sistemleri kullanımı kolaydır, geliştirmeyi hızlandırır ve güvenilirliği artırır. Şimdiye kadar gördüğüm maliyetleri yalnızca iki tane: öğrenmesi daha zor olabilir ve uygulaması daha zordur.

    • Tamamen katılıyorum. Bakım yapılabilirlik tartışması da bununla büyük ölçüde kapanıyor.
      6 ay sonra işe alınacak junior geliştirici, tipsiz koda uyum sağlamakta çok daha yavaş kalacaktır.
      Bazıları için ilk yazımın “daha hızlı” olabileceğini kabul ederim ama sonrasında o kodu okuyan her geliştirici yavaşlar.
    • Tam da bu dikkatli düşünmenin yazılımı daha temiz ve daha iyi hâle getirdiği de savunulabilir.
      Sırf derleyiciden geçen karmakarışık bir şey yerine, tam olarak neyi içeri alıp neyi dışarı verdiğinizi ve nedenini düşünmek iyi olabilir.
  • Bence yazar neredeyse her noktada yanılıyor. Ben de onlarca yıl böyle düşündüm ama son birkaç yılda fikrim tamamen değişti.
    Tipler bug’ları azaltır mı? Hayır. Çok az olabilir ama anlamlı değil. İlgili araştırmalara bakılabilir.
    Tipler daha iyi bir geliştirme deneyimi sağlar mı? Hayır. Benim REPL’imde ve IDE’mde tüm tanımlar ve değişkenler var. Tüm sembollerde otomatik tamamlama, çağrı ağacı, kullanım yerlerine gitme, güvenli refactoring; fonksiyonları tek başına çalıştırma, değiştirme ve sarmalama işlemlerini REPL ve uygulama içinde yapabiliyorum.
    Her şeyi tip sistemine kodlamak mı? İmkânsız. Çalışma zamanı doğrulaması gerekir.
    Gereksinimler değiştiğinde tip tanımlarını çözmeye de bol şans. Asıl belirleyici nokta bu. Statik tipler, mevcut durumda anladığınız domain veri modelini fazla erken katılaştırır. O model değişir; şansınız kötüyse aynı çalışma zamanı içinde birden fazla domain modeli varyasyonunu desteklemeniz gerekir. Özellikle kalıtım kullandıysanız daha da zorlanırsınız.
    Statik tiplerin derleyici optimizasyonu için büyük bir kaldıraç sağladığı doğru; ama dinamik tipli diller arasında statik tipleri isteğe bağlı ek özellik olarak sunanlar da var.
    Birçok kullanım senaryosunda, özellikle kurumsal geliştirmede, değişmezliği önceleyen fonksiyonel bir dinamik tipli dil uzun vadede büyük fayda sağlar.
    Güçlü tip savunucularının sık yaptığı kategori hatası, aynı kodun yalnızca tipsiz yazıldığını varsaymalarıdır. Gerçekte böyle yazılmaz.

    • Sonuçta herkes kendi deneyiminden tamamen farklı sonuçlar çıkardığı için kaçınılmaz olarak bunaltıcı bir tartışma.
      Neredeyse her noktada benim vardığım sonuç bunun tam tersi. Çalışma zamanı doğrulamasının gerekli olduğu sözü elbette doğru, ama çalışma zamanı doğrulamalarının çoğu önlenebilir.
      Gereksinim değişiklikleri konusunda ise statik tiplerin uyum sağlamayı kolaylaştırdığını düşünüyorum. Deneyimlediğim dinamik tip sistemlerinde veri yapılarıyla ilgili önemli varsayımlar her yere dağılmıştı; bazen ön/son koşul olarak dinamik biçimde kontrol ediliyor, bazen yalnızca testlerde bulunuyor, bazen de hiç kontrol edilmiyordu.
      Gereksinimi değiştirmek için bu örtük varsayımların tamamına etkisini akıl yürütmek gerekiyordu; bu yüzden değişiklik yapmak korkutucuydu. Yeni kodla uygulamayı ayağa kaldırmak kolay olsa da, akla gelmeyen nadir bir kod yolunu bozup bozmadığınızı bilmek çok zordu.
      “Bu arayüzü değiştirdin; buradaki kod yolunun buna bağlı olduğunu biliyor musun?” diyen bir statik analiz aşamasını çok daha fazla tercih ederim. Statik tipler tek yol değil ama aynı düzeyde dinamik doğrulama ve test kurmaktan çok daha az yük getirdiğini düşünüyorum.
    • REPL ve IDE’de tanımları/değişkenleri görmek, otomatik tamamlama ve refactoring yapmak güzel; ama yalnızca denetlemek istediğiniz kodu gerçekten çalıştırırken işe yarar. Benim deneyimime göre bu yaklaşım iyi ölçeklenmiyor.
      Tip sistemi çalışma zamanı doğrulamasını ortadan kaldırmaz ama doğru kullanılırsa dramatik biçimde azaltır.
      Gereksinimler değiştiğinde derleyicinin yeniden çalışması için tam olarak neyi düzeltmeniz gerektiğini söylemesi en iyi kısmı. Dinamik bir dilde aynı işi yaparsanız bunu kendiniz takip eder, birim testlerin patlamasını bekler ve kaçan bir yol olmaması için dua edersiniz.
    • Ben ise bu kısmı statik tiplerde çok daha kolay buldum.
      Belirli bir tipin kullanıldığı tüm yerleri çok daha güvenle bulabiliyor ve her birinin değişiklik gerektirip gerektirmediğine bakabiliyordum. Dinamik tipli ortamlarda bu iş çok daha ufak tefek ayrıntılarla dolu ve zahmetliydi.
    • Bu sizin deneyiminiz olabilir ama benimki değil. Herkese uyan tek bir doğru olmadığını düşünüyorum. Kendinize uygun olanı seçip devam etmek yeterli.
  • C++, Python ve JS ile yüz binlerce satır yazmış bir geliştirici olarak bile pek emin değilim. O kadar net değil
    Üçünde de üretkenim ama Python genelde kazanıyor. Yine de bir oyun motorunu ya da video codec’ini Python ile yazmam
    JavaScript tutarsız ve tuhaf, ama Netscape mirası hepimizi çoktan ona bağladı
    Çok nesne yönelimli, devasa iç içe sınıfların bol olduğu tarzlarda derleme/ayrıştırma zamanındaki statik tipler birçok hatayı azaltabilir. Ama nesne yönelimli yaklaşımın genel olarak felakete yakın olduğunu düşünmeye başladım; basit fonksiyonlar ve yapılandırılmış veri neredeyse her zaman sadelik ve sürdürülebilirlik açısından kazanıyor
    Modern language server’lar ve IDE’ler, JS/Python geliştirirken de birçok yazım hatasını yakalayabiliyor. Programlamanın birçok konusunda titizim, ama statik tipler ve dinamik tipler konusunda güçlü bir tarafım yok. İkisinin de milyonlarca başarılı projesi var

    • C++, tip sisteminden bağımsız olarak genel anlamda üretken olmak için epey zorlu bir dil
      Bir dilin sağlayabileceği en büyük üretkenlik artışının garbage collection olduğunu düşünüyorum. Çok daha basit sözdizimi ve tiplere sahip Go’nun nasıl karşılaştırılacağını daha çok merak ediyorum. Java da daha iyi olabilir. Lafı uzatsa da çoğu işte bilişsel yükü C++’ın yalnızca bir kısmı kadar
    • Python’da çoğunlukla fonksiyonel tarzda kod yazıyorum ama yine de tipler çok yardımcı oluyor
      Çok yazım hatası yapıyorum ve argüman sırasını da sık sık karıştırıyorum. Özellikle makine öğrenmesi yaparken tipler büyük yardım sağlıyor. Veri işlemeye 30 dakika harcadıktan sonra eğitim kodunun çökmesi en son isteyeceğim şey
      Python’ın kademeli tiplemesinin hızlı prototipleme ile, bir fonksiyon yeterince olgunlaştığında tip açıklamaları ekleme yöntemi arasında çok iyi bir orta nokta olduğunu düşünüyorum
    • Birkaç yıl önceki WWDC’deki protokol odaklı programlama (Swift) videosu hoşunuza gidebilir: https://www.youtube.com/watch?v=p3zo4ptMBiQ
  • Güçlü tiplerin zayıf tiplerden daha iyi olduğu tartışması sonuçlandı, ama statik tiplerin dinamik tiplerden daha iyi olup olmadığı sonuçlanmış değil
    Statik tip yanlıları derleyicinin tip değişmezlerini doğrulayarak “doğruluğu” kontrol etmesi gerektiğini düşünüyor; dinamik tip yanlıları ise bunun zaman kaybı olduğunu görüyor
    Ben kesinlikle ikinci taraftayım. Çünkü derleyici programın doğruluğunu değil, yalnızca tip doğruluğunu kontrol edebilir. Tip doğruluğu program doğruluğu için gerekli olabilir ama yeterli değildir. Statik tip yanlıları bunu kabul edemiyor ve statik tiplerin gerçekte olduğundan daha fazlasını garanti ettiğini sanıyor
    Yazıdaki birthdayGreeting örneğine bakalım. Yazar, birthdayGreeting("John", "20") içinde "20" sayı olmadığı için statik tiplerin bug’ı yakalamasına seviniyor. Ama birthdayGreeting(" ", 123) yakalanmıyor. " " bir isim değildir. birthdayGreeting("Anna," -12335) de yakalanmıyor. Tersine birthdayGreeting("Anna" 4.5) yakalanıyor; oysa 4.5 de yaş olarak görülebileceği için bunun aksine yanlış olduğu söylenebilir
    Bu önemli. “Tip bug’larını” yakalamak önemsiz derecede kolaydır, ama semantik bug’lar yıllarca gizli kalabilir. uint ile saklanan hesap bakiyesinin overflow olması, belirli bir yerde asal olması gerekirken olmayan bir sayı, boş olmaması gereken listeler gibi. Bağımlı tipler bile bu tür değişmezleri garanti edemez
    İnanması güçse uzay aracı patlamalarına veya araba kazalarına yol açan büyük bug’lara bakabilirsiniz. Bildiğim kadarıyla gerçek bir tip hatasının neden olduğu bir vaka yoktu; ezici çoğunluk semantik hatalardı
    [1] Çoğu kişi tipleri en az iki eksende, güçlü/zayıf ve statik/dinamik olarak görmek gerektiğini anlamıyor ve zayıf tiplerle dinamik tipleri sürekli karıştırıyor. C statik ve zayıf tiplidir, Python güçlü ve dinamik tiplidir, JavaScript ise zayıf ve dinamik tiplidir

    • Örneklerin önemli bir kısmı, tip sistemine bağlı olarak statik tiplerle gayet yakalanabilir. Ama daha önemli olan, “tip bug’larını yakalamak önemsiz derecede kolaydır” kısmı
      Tam da bu yüzden statik tip tarafındayım. O kadar önemsiz ki deklaratif olarak, kontrol edilen kodun hemen yanında, anında geri bildirimle, tüm çağrı noktalarında ve tüm alt ifadelerde/ifadelerde ele alınabilir
      Tip anotasyonu semantiğin ya da domain mantığının doğru olduğu anlamına gelmez; bunları hâlâ test etmek gerekir. Ama ilgilendiğiniz mantığa ortogonal onlarca önemsiz testin yerini alabilir. Açıkçası bu tür testleri eksiksiz yazan neredeyse kimse yok
    • Yazarıyım. Bu örneklerin karşı örnek değil, aksine benim savımı gösterdiğini düşünüyorum
      Yazının ilerleyen kısmında, kullanıcı girdisi gibi yerlerde tip oluştururken doğrulama yapıldığını söylemiştim. Bu yüzden Name tipi her zaman geçerlidir ve " " bir isim değildir. Tip geçerli bir ismi garanti ettiği için bizim kod tabanımızda kesinlikle yakalanır
      birthdayGreeting("Anna" 4.5) ve birthdayGreeting("Anna," -12335) JS’te number kayan noktalı olduğu için aslında geçerlidir. Yalnız yazarken aklımda tamsayı vardı. TS’den daha katı bir tip sisteminin, örneğin Rust’ın, değişmezleri daha iyi tanımlamaya yardımcı olabileceği başka bir örnek
      Özetle basit bir örnek göstereyim derken her zamanki gibi tüm tipleri sıkı tanımlamadım; bunun sonucunda tiple yakalanabilecek bug’lar daha da görünür oldu
    • Bu örnekleri ilginç kılan şey, bana göre gerekenin her zaman geçerli bir ismi temsil eden Name tipi ve her zaman geçerli bir yaşı temsil eden Age tipi olması
      Doğrulamayı bu tiplerin tek bir kurucusuna koyup, birthdayGreeting gibi birçok metot bu tipin değerlerini sorumluluk almadan kullanabilir
      Tip denetimi ya da en azından isteğe bağlı tip ipuçları ve statik analiz olmadan bu kalıbı iyi uygulamanın yolunu bilmiyorum. Bunun yerine her metotta girdileri doğrulamak fazla zahmetli; çağıranın geçerli değer verdiğini varsayıp büyük bir kaza çıkmasın diye test etmek de tatmin edici değil
    • Uzay aracı patlamasından söz edince aklıma hemen [1] geliyor. Bu ünlü kaza, bazı tipler için izin verilen aralıkların önceden tanımlandığı tip denetimiyle ilgiliydi ve senin görüşünle de örtüşüyor. birthdayGreetingin 1–150 aralığını kabul etmesini sağlamak ADA’da kolayca yapılabilir
      Uzay araçlarıyla ilgili kamuya açık sorunlar arasında daha iyi tip denetimiyle yakalanabilecek gibi görünen birkaç tane daha var. Metrik/imperyal birim dönüşümü de birimleri tipe koyarak çözülebilir. Ancak [2] durumunda sorun büyük olasılıkla entegrasyon testi tarafındaydı
      Elbette tip denetimi tüm kod sorunlarını, özellikle algoritma sorunlarını bulamaz ve testlerin yerini de tutmaz. Yine de geliştirme aşamasında anında geri bildirim ve tip ipuçları çok değerlidir
      Örnekte isim dizgesi bir kişi tipine ya da nesneye de dönüştürülebilir
      [1]: https://en.m.wikipedia.org/wiki/Ariane_flight_V88
      [2]: https://en.m.wikipedia.org/wiki/Mars_Climate_Orbiter
    • Derleyicinin program doğruluğunu değil, yalnızca tip doğruluğunu kontrol etmesinin neden zaman kaybına gerekçe olduğunu anlamıyorum
      Kusursuz çözüm yok, ama değerli birçok çözüm var
  • Bu konuda epey bir yakınsama oldu. Artık çoğu dil, ifade düzeyinde bir miktar tip çıkarımı sunuyor. C++’ta da auto var
    Bu sayede koddaki tip boilerplate’i büyük ölçüde azaldı. C++ for döngülerinde uzun yineleyici tiplerinin tamamını yazmak zorunda olduğumuz günler geride kaldı
    Fonksiyon bildirimleri ve struct alanları, kodu okuyabilmek için tip bilgisinin gerekli olduğu yerlerdir. Bir program birkaç yüz satırı aştığında ya da geliştirici sayısı biri geçtiğinde belli bir düzeyde açıklama/annotasyon şarttır
    Başlıca itiraz doğal olarak Python ve JavaScript kullanıcılarından geliyor. Python sonradan oldukça tuhaf, tavsiye niteliğinde bir tip sistemi ekledi; JavaScript de sonradan TypeScript’i ekledi. İkisi de sonradan eklenmiş tip sistemleri ve tipli kod ile tipsiz kodun karıştığı ortamlarda kullanılıyor. Bu acı verici
    LISP de onlarca yıl önce “flavors” ve Common LISP Object System ile sonradan bir tip sistemi eklemişti; o da pek hoş görünmüyordu. Çıkarılacak ders şu: Tip sistemini sonradan eklerseniz ortalık karışır

    • Python’ın tip sisteminin, koşullar düşünüldüğünde oldukça iyi olduğunu düşünüyorum
      Optional’ın None kullanmadan önce kontrolü zorunlu kılması ya da typing.Protocol üzerinden yapısal alt tipleme gibi iyi özellikler var. Python en baştan tipler düşünülerek tasarlansaydı daha iyi olurdu; ama mevcut Python koduyla bütünleşme ve hiçbir kodu bozmama gerekliliği düşünüldüğünde oldukça iyi iş çıkarılmış
      Python’da statik tiplerin daha büyük sorunu ekosistem ve alışkanlıklar. Özellikle birçok geliştiricinin Python’ı fiilen veri bilimci olarak kullanmasıyla bu daha da ağırlaştı. Doğru düzgün metot imzaları yazmaya üşenip *args/**kwargs’ı kötüye kullanıyorlar
      Metotların DataFrame’leri ya da sözlükleri karmakarışık bir çanta gibi ortalıkta dolaştırması çok yaygın. Bir metot sütun ya da alan ekleyip siliyorsa ve kodu çalıştırana ya da tüm satırları okuyana kadar veri çantasının içinde ne olduğunu bilmiyorsanız ekstra puan
      Elbette neredeyse her dilde benzer şeyler yapılabilir. C#’ta tüm tipleri dynamic olarak kullanmak ya da Go metotlarının hepsinin interface{} almasını sağlamak da mümkün. Ama Python uzun süre bu yaklaşımı aktif biçimde teşvik etti; bugün bile birçok başlangıç seviyesi eğitim, “*kwargs alırsanız fonksiyon imzasını değiştirmeniz gerekmez” fikrini korkunç bir tuzak olarak değil, zeki insanlar için ileri seviye bir özellik gibi sunuyor
    • Python ve TypeScript’in “tip sistemleri”, kademeli ve greenfield olmayan ortamlarda tiplerin devreye alınması için tasarlandı
      Kademeli geçiş için şartlar ve bu şekilde çalışmaları tamamen anlaşılır
    • Flavors ve CLOS “tip sistemi” değildir. “Nesne sistemi”dir ve özellikle çirkin de değillerdi
      Flavors, tip sistemi olmayan Lisp’e getirildi; daha sonra CLOS ise zaten tip sistemi olan bir Lisp’e, yani Common Lisp’e eklendi
    • TypeScript’in tip sistemi gerçekten şaşırtıcı derecede iyi. Keşke daha fazla tip sistemi bu kadar ifade gücüne sahip olsa
  • İnsanlar her zaman akıldan çok duygusal olarak tutundukları şeyler konusunda fanatik davrandı
    “Tipler bug’ları azaltır” iddiası gerçek olmaktan çok kulağa doğru gelen bir iddia
    https://blog.metaobject.com/2014/06/the-safyness-of-static-t...
    Deneme eksikliği de yoktu. Hatta bu iddianın yanlışlandığı söylenebilir
    Yine de kişisel olarak statik tipleri seviyorum. Bunun başlıca nedeni dokümantasyon etkisi; tesadüf müdür bilmem ama gerçekten sağlam ampirik kanıt bulunan olumlu etki de yalnızca bu tarafta

    • “Uzun ömürlü kod tabanlarını değiştirirken tipler bug’ları azaltır” ifadesinin pek tartışmalı olmadığını düşünüyorum
      En başta doğru kod yazmaktan çok regresyonları önlemek daha önemli olabilir; evrilmeyen koda bakarken bu kısmı değerlendiremezsiniz
      Somut olarak, büyük ve saf bir JavaScript projesinde bir nesne alanını kaldırmak doğası gereği mayın tarlasıdır ve geçmişte pek çok bug’a yol açmıştır. Buna karşılık tamamen TypeScript olan bir projede aynı değişikliği güvenle yapabilirsiniz
    • Çok güçlü bir iddia olduğundan uç bir örneğe bakalım: biçimsel olarak doğrulanmış CompCert’in ara katmanı var: https://users.cs.utah.edu/~regehr/papers/pldi11-preprint.pdf
      Bunun, çok güçlü statik tiplerin bug’ları azalttığına dair ampirik kanıt sayılabileceğini düşünüyorum
      Sonuçta birçok yorumun söylediği gibi tipler ikili bir evet/hayır meselesi değil; statik/dinamik, güçlü/zayıf gibi birçok ekseni olan geniş bir spektrum. Tip sistemleri arasında da büyük farklar var, insanların o tip sistemlerini probleme uygulama biçimleri arasında da
      Statik ve güçlü tipli bir dilde bile her şeyi string olarak temsil edip sürekli dönüştürebilirsiniz; bu aslında dinamik tipli bir dilde çalışmak gibidir. Tersine, tip sisteminin sunduğu araçlardan yararlanıp geçerli değerleri temsil eden sınıflar oluşturur ve önemli invariant’ları ifade ederseniz fayda görürsünüz
    • Güçlü statik tipleri, kodu kendi kendini belgeleyen hâle getirdiği için çok daha fazla tercih ediyorum
      Üretkenlik birkaç kat değil, birkaç büyüklük mertebesi artıyor. Bunu C, C++, Java, Python, JavaScript, TCL gibi bu spektrumun geniş bir alanını kapsayan birçok dili yoğun kullanmış biri olarak söylüyorum
      Yakın zamanda dokunmadığınız kodu, ister mevcut proje ister bağımlılık olsun, akıl yürütmek çok daha kolay hâle geliyor. Bir fonksiyonun döndürdüğü nesneyle tam olarak ne yapabileceğinizi anlamak için sürekli yan yollara sapmanız gerekmediğinden eldeki soruna daha fazla odaklanabiliyorsunuz
      Derlemenin geçtiği andaki hoş rahatlama hissi de var, ama bu ikincil
    • Statik tiplerin iddiası, tipler statik olduğu için tip bug’larını imkânsız hâle getirdiğidir
      Duygusal bağlılık ise “Ama tüm bug’ları ortadan kaldırmıyor ki!” ile karşılaşıldığında duyulan öfkeden ibaret
    • Biri “duygusal argümanlar rasyonel argümanlardan daha hızlı üretilebilir” dese nasıl hissederdiniz?
      Bu tartışma tam olarak öyle hissettiriyor
      Bir hashmap’i Apple ya da String gibi ele almaya çalıştığımda derleyicinin “olmaz” demesinin basit rasyonelliğini istiyorum