Kısım II · İnşaat · Bölüm 21
Programlama Dilleri Haritası
Dillerin neden bu kadar çok olduğu ve neye göre ayrıldığı (The landscape of programming languages)
Neden burada: C'yi gördük (Bölüm 9) ve JavaScript'i kullanıyoruz, ama ikisi arasında yüzlerce dil daha var. İnşaata başlamadan önce dillerin neden bu kadar çok olduğunu ve hangi ölçülere göre birbirinden ayrıldığını bir harita olarak kuruyoruz. Bir önceki bölümde (20) tarayıcıya vardık ve merdiven bitti; bu bölüm Kısım II'nin kapısı: bundan sonra bir dil adı duyduğunda onu bu haritaya yerleştirebileceksin.
Neye dayanıyor: Bölüm 7 (makine dili: tüm dillerin sonunda indiği yer), 9 (derleyici ve tip: bu bölümün ölçü dili) ve 10 (bellek yönetimi ve güvenliği: 21.4'ün temeli).
- Kat 10Bizim uygulamamızHukuk dersleri, puan, seri, leaderboard. Bütün alt katların sunduğu imkânlarla kurulur. Kısım II.
- Kat 9Web ve tarayıcı: HTML, CSS, JavaScriptTarayıcı denen programın anladığı diller: iskelet, görünüm, davranış. Bölüm 20, 23–26.
- Kat 8Ağ ve internetBilgisayarların birbirine bit göndermesi; IP, TCP, DNS, HTTP. Bölüm 19–20.
- Kat 7İşletim sistemi (macOS, Windows, Linux)Donanımın idaresi: programlara işlemci zamanı, bellek ve dosya dağıtır. Bölüm 13–18.
- Kat 6Gömülü yazılım (firmware) ve açılışDüğmeye basınca ilk çalışan program; işletim sistemini başlatır. Bölüm 12.
- Kat 5Programlama dilleri ve derleyiciİnsanın okuyabildiği kodu (C, Go, JavaScript) makine diline çeviren araçlar. Bölüm 9–11; bu bölümde dillerin tamamının haritası.
- Kat 4Makine dili ve assemblyİşlemcinin doğrudan anladığı, bitlerden oluşan komutlar. Bölüm 7.
- Kat 3İşlemci ve bellek (CPU, RAM)Komutları tek tek getirip çalıştıran makine ve verinin durduğu yer. Bölüm 6, 8.
- Kat 2Devreler: hesap ve hafızaKapılardan kurulan toplayıcılar ve hatırlayan devreler. Bölüm 4–5.
- Kat 1Transistör ve mantık kapılarıElektrikle açılıp kapanan anahtarlar. Bölüm 3.
- Kat 0Elektrik ve bit (zemin)Var ya da yok, 1 ya da 0. Bölüm 2.
Bu bölümde dört şeyi yapacağız. Önce Kısım II'nin kapısından girip Kısım I'den ne taşıdığımızı ve ne inşa edeceğimizi söyleyeceğiz. Sonra programlama dillerini birbirinden ayıran beş soruyu öğreneceğiz: ne kadar makineye yakın, nasıl çalıştırılıyor, tipleri ne zaman denetleniyor, bellek kim tarafından yönetiliyor, hangi düşünce biçimini destekliyor. Sonra bu beş soruyla on bir dilin kartını çıkaracağız. Son olarak, bizim uygulamamızın neden TypeScript, Go ve SQL ile yazılacağını bu haritadan okuyacağız. Bölümün sonunda "Şu dil neden var, nerede kullanılır?" sorusuna rastgele bir cümle değil, bir harita yerleşimi olarak cevap verebileceksin.
Kısım II'ye hoş geldin
Kısım I, bir binanın temelini ve taşıyıcı sistemini anlattı: elektrikten bite (Kat 0), kapılardan işlemciye (Kat 1–3), makine dilinden C'ye (Kat 4–5), işletim sistemine (Kat 7), ağa ve web'e (Kat 8–9). Bölüm 20'de "adres çubuğuna yazıp Enter'a basınca ne olur?" sorusunu baştan sona cevapladık ve tarayıcının HTML, CSS ve JavaScript'i çalıştıran bir program olduğunu gördük. Merdiven bitti; şimdi o merdivenin tepesinde duran katlara, yani senin ve Emre'nin gerçekten yapacağı işe geliyoruz.
Kısım II'nin işi inşaat. Kısım I'de binayı okuduk; burada yeni bir kat dikiyoruz: hukuk uygulamamız. Önümüzdeki yirmi altı bölüm (21–46) şu sırayı izler: önce ön yüz (frontend), yani kullanıcının gördüğü ve dokunduğu kısım: HTML, CSS, JavaScript (23–26), sonra bu kodun düzenlenmesi, kayıt altına alınması ve araçları (27–29), sonra tiplerle güvenli hale getirilmesi, React ve mobil (30–33); ardından arka uç (backend): sunucu, API, Go, veritabanı, önbellek, güvenlik (34–41); en sonda test, yayına alma, mimari ve yapay zekâ agent'larıyla çalışma (42–46). Bu bölüm o inşaatın malzeme kataloğu: hangi dil hangi iş için üretilmiş.
Kısım I'den neyi alıyoruz
- Bit ve tip fikri (Bölüm 2): bitlerin anlamı onları okuyan kuraldadır. Bu bölümün "tip sistemi" kavramı, o fikrin programlama dilindeki halidir.
- Komut ve makine dili (Bölüm 6, 7): işlemci yalnızca makine dilini anlar. Bütün dillerin ortak sorusu "benim yazdığım metin sonunda bunlara nasıl dönüşüyor?" olacak.
- C, derleyici, pointer (Bölüm 9, 10): C'yi ölçü olarak kullanacağız. Diğer dillerin çoğu "C'nin yaptığı şeyi şu farkla yapıyor" diye tarif edilebilir.
- Süreç ve iş parçacığı (Bölüm 14): Go ve JavaScript'in eşzamanlılığa farklı yaklaşımını anlamak için gerekecek (burada yalnızca değineceğiz).
- Tarayıcı ve HTTP (Bölüm 20): ön yüz dillerinin neden "tarayıcının dili" olduğunu açıklar.
Bir uyarı: bu bölümde bir sürü dil adı geçecek ve hiçbirini öğrenmeyeceksin. Amaç dil öğretmek değil, dillere nereden bakılacağını göstermek. Bir dil adı gördüğünde içinden "bu hangi seviyede, nasıl çalışıyor, tipleri nasıl, belleği kim yönetiyor, nerede kullanılıyor?" diye sorabilmen yeterli. Sonraki bölümler tam üç dili ayrıntılı işleyecek: JavaScript (25–26), TypeScript (30), Go (36–37) ve ayrıca SQL (38–39).
21.1 Seviye: düşük seviyeli ve yüksek seviyeli diller
İlk soru: bir dil, makineye ne kadar yakın? Bölüm 7'de merdivenin en altını görmüştük: makine dili (işlemcinin doğrudan anladığı bit desenleri) ve onun insan okuyabilsin diye yazılmış hali olan assembly. Bu iki dil, "işlemcinin dili"dir. Learn C++ sitesinin tarifiyle, bunlar düşük seviyeli diller (low-level languages) sayılır, çünkü makinenin mimarisinden çok az soyutlama sunarlar: dil, çalışacağı işlemcinin komut kümesine göre biçimlenmiştir.1
Bunun bedelini Learn C++ üç maddede sayar: düşük seviyeli programlar taşınabilir değildir (başka bir işlemci mimarisine geçirmek zordur), yazmak o mimarinin ayrıntılı bilgisini gerektirir ve okunması zordur. Karşılığında bir tek şey kazanılır: hızlıdır.1 Bu yüzden assembly bugün yalnızca hızın hayati olduğu küçük parçalarda yazılır.
Buna karşılık yüksek seviyeli diller (high-level languages) insanın düşünme biçimine yakındır: komutları doğal dile ve matematiğe benzer, aynı iş çok daha az satırla yazılır ve belirli bir işlemciye bağlı değildir.1 Bir benzetme: bir yemek tarifini "ocağın düğmesini 3. konuma getir, 4 dakika bekle, düğmeyi kapat" diye yazabilirsin (düşük seviye: belirli bir ocağa özgü), ya da "suyu kaynat" diye (yüksek seviye: hangi ocak olduğu umurunda değil). İkincisi, her mutfakta işler; ama senden bir şeyi saklar: tam olarak neyin nasıl yapıldığını.
Seviye bir ikili değil, bir cetvel
Pratikte seviye bir cetveldir. Assembly en altta; yukarı doğru C, C++, Rust; daha yukarıda Go, Java, Swift; en üstte Python, JavaScript gibi betik dilleri. Learn C++ bile C++'ın tam ortada durduğunu söyler: teknik olarak yüksek seviyelidir ama daha yeni dillerle kıyaslanınca "orta seviyeli" denebilir; güçlü yanı, ihtiyaca göre hem aşağıda (hız ve ince kontrol için) hem yukarıda (rahatlık için) çalışabilmesidir.1 Bu yüzden "C düşük seviyeli mi?" sorusunun tek cevabı yoktur; "C, assembly'ye göre yüksek, JavaScript'e göre düşük" demek daha doğrudur.
Seviye neyi belirler? Bellekle ve donanımla ne kadar doğrudan konuştuğunu. C'de bir bellek adresini elle tutarsın (Bölüm 10); JavaScript'te bellek adresi diye bir kavram yoktur. Yukarı çıktıkça rahatlık, güvenlik ve taşınabilirlik artar; aşağı indikçe hız, kontrol ve öngörülebilirlik. Kat planında yükseklik arttıkça soyutlama arttığı gibi.
21.2 Çalıştırma biçimi: derlenen, yorumlanan, anında derleme
İkinci soru: yazdığın metin işlemciye nasıl ulaşıyor? Learn C++, yüksek seviyeli bir programın çalışmadan önce makine diline çevrilmesi gerektiğini ve bunun için iki ana yolun olduğunu söyler: derleme ve yorumlama.1
Derlenen diller
Derleyici (compiler) kaynak kodun tamamını okuyup makine koduna çeviren bir programdır; sonuç, işletim sisteminin doğrudan başlatabileceği bir çalıştırılabilir dosyadır (Bölüm 9'daki clang/gcc deneyi). Çalıştırırken derleyiciye artık gerek yoktur, kaynak kodu da dağıtmak zorunda değilsin.1 Bu çeviri program çalışmadan önce, bir kez yapılır; çalışırken çeviri masrafı yoktur. C, C++, Go, Rust bu gruptadır. Bir eşdeğer: bir kitabı bir kez Türkçeye çevirip yayımlamak; her okuyucu doğrudan Türkçe sürümü okur.
Derlemenin bir yan yararı da şudur: derleyici kodunu çalışmadan önce baştan sona okuduğu için bazı hataları (yanlış tip, olmayan değişken) program kimseye ulaşmadan yakalayabilir. Biraz sonra tiplerde (21.3) bu fikre döneceğiz.
Yorumlanan diller
Yorumlayıcı (interpreter) ise kaynak kodu önceden çevirmez; programı satır satır okur ve komutları o anda çalıştırır. Learn C++'a göre yorumlayıcılar derleyicilerden daha esnektir ama program her çalıştırıldığında yorumlama işi yinelendiği için çalışma sırasında daha verimsizdir.1 Benzetme: simültane tercüman. Her konuşmada baştan çevirir; esnektir (konuşma değişse de çevirir) ama her seferinde emek harcar.
CS50'nin Python haftası, farkı tam bu terimlerle söyler: C derlenen bir dildir; Python ise yorumlanan bir dildir, programı ayrıca derlemezsin, doğrudan Python yorumlayıcısına verirsin. Ders notu bunun bir bedelini de açıkça yazar: derlenen programa göre (genellikle çok küçük) bir yavaşlama olabilir.2 Kerem'in prototipi bu gruptadır: JavaScript'i tarayıcıya dosya olarak veriyorsun, derleme adımı yok.
Ara kod ve sanal makine
İki uç arasında üçüncü bir yol var: kodu önce makineye değil, hayali bir makineye çevirmek. Java bunun klasik örneğidir. Oracle'ın Java öğreticisine göre kaynak kod önce .java uzantılı düz metin dosyalarına yazılır; javac derleyicisi bunları .class dosyalarına çevirir. Bir .class dosyası işlemcinin yerel diliyle değil, ara kod (bytecode) ile yazılmıştır: bu, Java Sanal Makinesi'nin (sanal makine (virtual machine, JVM)) makine dilidir. Sonra java aracı programı bu sanal makinenin bir örneğiyle çalıştırır.3 Yani ortada bir yazılım olarak yazılmış "sahte işlemci" var; her gerçek işletim sistemi ve işlemci için bir kez bu sahte işlemcinin gerçeklemesi yazılırsa, aynı ara kod hepsinde çalışır. Kotlin de JVM hedeflendiğinde Java uyumlu ara kod üretir.8
Anında derleme
Peki yorumlama yavaşsa, JavaScript neden bu kadar hızlı? Cevap anında derleme (JIT, Just-In-Time compilation). MDN'in tarifiyle JIT, bir ara temsilin ya da yüksek seviyeli dilin (örneğin JavaScript ya da Java ara kodu) çalışma sırasında makine koduna çevrilmesidir. JIT derleyiciler kodu çalışırken izler, sık çalışan kısımları ("sıcak noktalar", hot spots) belirler ve kazanç masraftan büyükse yalnızca onları makine koduna çevirir; işlemci artık o kısmı doğrudan çalıştırır. MDN, bunun modern tarayıcılarda JavaScript'i hızlandırmak için yaygın olarak kullanıldığını söyler.4 Bu işi yapan program JavaScript motorudur: Chrome'daki V8, Firefox'taki SpiderMonkey, Safari'deki JavaScriptCore.4
Sonuç şu: "JavaScript yorumlanan bir dildir" cümlesi hem doğru hem eksiktir. Dilin tanımı yorumlanabilir bir metindir (derleme adımı yok, kaynağı olduğu gibi veriyorsun), ama modern motorlar içeride yorumlama ve JIT derlemeyi birlikte kullanır. Dilin kendisi "derlenen" ya da "yorumlanan" olmaz; bir gerçekleme olur. Bu yüzden bu başlığı sınıflandırma değil, bir cetvel olarak oku:
| Biçim | Çeviri ne zaman? | Örnek dil | Bir yan yararı |
|---|---|---|---|
| Derlenen | Çalışmadan önce, bir kez, makine koduna | C, C++, Go, Rust | Hızlı; kaynak dağıtmak gerekmez |
| Yorumlanan | Çalışırken, satır satır | Python (CS50'nin tarifiyle) | Derleme adımı yok, esnek |
| Ara kod + sanal makine | Önce ara koda, sonra sanal makinede | Java, JVM üzerinde Kotlin | Aynı ara kod birçok platformda |
| Anında derleme (JIT) | Çalışırken, yalnızca sık çalışan kısımlar | Tarayıcıda JavaScript | Esneklik ve hız arası denge |
"Derlenen dil hızlıdır, yorumlanan yavaştır" ezberi iki yönden eksiktir. Birincisi, hız yalnızca çalıştırma biçimine bağlı değil: algoritma (Bölüm 11), bellek erişimi (Bölüm 8) ve ağ beklemesi çoğu zaman daha belirleyicidir. İkincisi, bizim uygulamamızın zamanının çoğu hesapla değil, sunucudan cevap beklemekle geçecek; böyle işlerde "dilin hızı" ikinci planda kalır.
21.3 Tip sistemleri: statik ve dinamik, güçlü ve zayıf, tip çıkarımı
Bölüm 2.8'in sonuç cümlesini hatırla: bitlerin anlamı, onları okuyan kuraldadır; bir değere hangi kuralla bakılacağını söyleyen etikete veri tipi demiştik. Tip sistemi (type system), bir dilin bu etiketleri nasıl yönettiğine dair kurallar bütünüdür: her değerin bir tipi olur, hangi işlemlerin hangi tiplere yapılabileceği belli olur ve dil, kurala aykırı bir işlem görürse bir şey yapar. "Bir şey yapar" kısmındaki fark, iki ayrı eksen doğurur.
Statik ve dinamik: tipler ne zaman denetlenir?
MDN'in tanımıyla statik tipli (statically-typed) bir dilde (Java, C, C++ gibi) değişken tipleri derleme zamanında bellidir; çoğu dilde tipi programcının açıkça yazması gerekir.4 Dinamik tipli (dynamically-typed) dillerde (JavaScript gibi) ise yorumlayıcı değişkenin tipini çalışma zamanında, o anki değerine bakarak belirler.4 Aynı hatanın iki dilde ne zaman ortaya çıktığına bak. Aşağıdaki C satırı bir metni sayı kutusuna koymaya çalışıyor; kodu gcc ile derlediğimde (bu bölüm için denedim) program hiç çalışmadan şu hatayı aldım:
int x = "merhaba";
// gcc: error: initialization of 'int' from 'char *' makes integer from pointer without a cast
Python'da benzer hata ancak o satıra gelince patlar: print('5' + 1) çalışırken TypeError: can only concatenate str (not "int") to str verir. Programın o satıra hiç gelmediği bir kullanıcı yolunda hata sessizce bekler. Statik tiplilik, bu tür hataları kimse çalıştırmadan önce yakalar; dinamik tiplilik ise esneklik ve kısa kod karşılığında hata avını çalışma zamanına bırakır.
Güçlü ve zayıf: tipler karışınca ne olur?
İkinci eksen farklıdır: tipler karıştığında dil ne yapar? Tip zorlaması (type coercion), MDN'in tarifiyle, değerlerin bir tipten diğerine otomatik, örtük çevrilmesidir. MDN'in örneği: "5" + 9 JavaScript'te "59" verir, çünkü 9 metne çevrilir ve metinler birleştirilir.5 Bölüm 2'deki "5" + 1 örneğinin aynısı. Oysa Python aynı işlemde hata verir ve karıştırmaya izin vermez. Bu fark gündelik dilde zayıf tipli (weakly typed) (karıştırmaya izin veren, otomatik çeviren) ve güçlü tipli (strongly typed) (karıştırmayı reddeden) diye anılır.
Dürüst bir not: "güçlü/zayıf" statik/dinamik kadar kesin bir ayrım değil, bir derece. Resmî belgeler çoğunlukla bu iki kelimeden kaçınır; örneğin Microsoft C# için "güçlü tipli" der ve bunu, derleme zamanında bilinen tipler ve yanlış kullanımda derleyicinin uyarması olarak açıklar.11 Yani kelimeler dilden dile farklı anlamlarda kullanılabilir; sen eksenin kendisini hatırla: tipler karışınca dil sessizce çeviriyor mu, yoksa reddediyor mu? Bu ikisi birbirinden bağımsızdır:
| Tipler derleme zamanında | Tipler çalışma zamanında | |
|---|---|---|
| Karışmaya sert | Go, Rust, Java | Python |
| Karışmaya esnek | (C'de bazı örtük dönüşümler var) | JavaScript |
(Tablodaki yerleşim bir ders kolaylığıdır; bu dillerin belgeleri hep bu kelimeleri kullanmaz.)
Tip çıkarımı: yazmadan bilmek
Statik tipliliğin gündelik zahmeti her değişkenin yanına tip yazmaktır. Tip çıkarımı (type inference) bu zahmeti azaltır: derleyici değerden tipi kendisi çıkarır. TypeScript el kitabından örnek: let helloWorld = "Hello World"; yazdığında TypeScript bu değişkenin string olduğunu kendisi bilir ve tipi sen yazmak zorunda kalmazsın.6 Swift de çıkarsanmış tipleri kodu daha temiz ve hataya daha az açık tutmak için kullandığını söyler.8 Böylece statik tipliliğin güvencesi, dinamik dil kadar kısa yazımla bir arada gelir. TypeScript'i Bölüm 30'da ayrıntılı göreceğiz.
21.4 Bellek yönetimi: elle, çöp toplayıcı, sahiplik
Bölüm 10'da C'de malloc ile bellek ayırıp free ile geri vermeyi gördük ve unutulursa bellek sızıntısı olduğunu, yanlış kullanılırsa programın çöktüğünü ya da güvenlik açığı doğduğunu not ettik. Bu sorun bütün dillerin ortak derdidir: bellek sonlu, programlar sürekli ona ihtiyaç duyar, bir noktada "bu parçaya artık gerek yok" diye geri verilmesi gerekir. Dilleri üç büyük yaklaşım ayırır.
Elle yönetim
MDN'in bellek yönetimi sayfası şöyle ayırır: C gibi düşük seviyeli dillerde malloc() ve free() gibi elle bellek yönetimi ilkelleri vardır; JavaScript gibi dillerde ise bellek nesneler yaratılınca otomatik ayrılır, kullanılmayınca otomatik geri alınır.5 Elle yönetimin artısı tam kontrol ve sıfır ek masraftır; eksisi, "bellek artık gerekmiyor mu?" sorusuna her seferinde insanın doğru cevap vermesi gerektiğidir. Bu, MDN'in deyişiyle belleğin yaşam döngüsünde en çok sorunun doğduğu ve en zor olan adımdır.5
Çöp toplayıcı
Çöp toplayıcı (garbage collector, GC) bu kararı programcıdan alır. Program çalışırken arka planda bir mekanizma belleği izler, artık erişilemeyen parçaları bulur ve geri alır. MDN bunun bir yaklaşım olduğunu da dürüstçe belirtir: "Bu bellek hâlâ gerekli mi?" sorusu genel olarak çözülemez bir problemdir; çöp toplayıcılar bunun kısıtlı bir çözümünü uygular.5 JavaScript, Go, Swift ve C# belgeleri otomatik bellek yönetimini açıkça söyler;5811 Java'nın HotSpot sanal makinesi birden çok çöp toplayıcı sunar, Python'un standart kütüphanesinde bir gc modülü vardır.18 Go'nun tasarımcıları bunu bilerek seçtiler: büyük, eşzamanlı bir programda kaynak yönetimini idare edilebilir kılmak için en azından güvenli bir otomatik bellek yönetimi gerekli görüldü.7 Bedeli: GC'nin çalışması için zaman ve bellek harcanır ve tam olarak ne zaman çalışacağı programcının elinde değildir. Go SSS belgesi bu tartışmayı kendisi açar ("Why do garbage collection? Won't it be too expensive?" başlığı).7
Sahiplik
Üçüncü yol Rust'ın yoludur. Rust Kitabı'nın tarifi: bazı dillerin düzenli olarak kullanılmayan belleği arayan çöp toplayıcısı var; bazılarında programcı belleği açıkça ayırıp serbest bırakmalı; Rust ise üçüncü bir yaklaşım kullanır: bellek, derleyicinin denetlediği kurallardan oluşan bir sahiplik (ownership) sistemiyle yönetilir. Kurallar ihlal edilirse program derlenmez; ve kitap, sahipliğin hiçbir özelliğinin programı çalışırken yavaşlatmadığını söyler.9 Kurallar üç tanedir: Rust'taki her değerin bir sahibi vardır, aynı anda yalnızca bir sahibi olabilir ve sahip kapsamın (scope) dışına çıkınca değer atılır (dropped).9
Bu kuralın nasıl hissettirdiğini Rust Kitabı'ndaki küçük örnekle gör: let s1 = String::from("hello"); let s2 = s1; satırlarından sonra s1'i kullanmaya çalışırsan, derleyici error[E0382]: borrow of moved value: `s1` hatasıyla programı reddeder. Çünkü değer s2'ye taşındı, artık sahibi o.9 Hata, program çalışmadan önce, derlemede yakalanır. Bu, Bölüm 10'daki "bellek güvenliği" sorununa gelen üçüncü cevap: ne insana güven (C), ne çalışırken bir bekçi (GC), ne de derleyicinin önceden kanıtlaması (Rust). Rust'ın resmî sitesi bunu "çöp toplayıcısız, çalışma zamanı olmadan hız ve bellek güvenliği" diye özetler.9
| Yaklaşım | Kim karar verir? | Ne zaman? | Örnek diller |
|---|---|---|---|
| Elle | Programcı | Yazarken | C, (C++'ın bir kısmı) |
| Çöp toplayıcı | Çalışma zamanındaki bekçi | Çalışırken | Java, Go, Python, JavaScript, C# |
| Sahiplik | Derleyici | Derlerken | Rust |
21.5 Paradigmalar: bir problemi nasıl düşünürsün?
Dillerin beşinci ayrımı teknik değil, düşünsel: paradigma (paradigm), bir dilin kod yazmaya dair önerdiği düşünce biçimidir. Python belgeleri, bir dilin birden çok paradigmayı destekleyebileceğini açıkça söyler: Python nesne yönelimli olduğu gibi yordamsal ve fonksiyonel stili de destekler.2 Kotlin de "hem nesne yönelimli hem fonksiyonel yapılar var, ikisini ya da karışımını kullanabilirsin" der.8 Yani paradigmalar dilleri kutulara kilitleyen etiketler değil, yazma tarzlarıdır. Beş tane bilmek yeter.
Buyurgan ve yordamsal
Buyurgan programlama (imperative programming): bilgisayara sırayla ne yapacağını söylersin: şunu yap, sonra bunu, durum değişsin, sonra şuna bak. Bölüm 9'da yazdığın C programları böyleydi. Yordamsal programlama (procedural programming) bunun bir adım ötesidir: adımları ad verilmiş parçalara (yordam, yani fonksiyon) bölersin ve onları çağırırsın. C bu tarzın tipik örneğidir. Bizim uygulamada: "cevabı kontrol et, doğruysa puanı artır, seriyi güncelle, ekranı yenile."
Nesne yönelimli
Nesne yönelimli programlama (OOP, object-oriented programming), MDN'in tarifiyle, verinin nesneler içine sarıldığı ve işlemin parçalarına değil nesnenin kendisine uygulandığı yaklaşımdır.10 Üç kavram öğren: sınıf (class), bir tür şeyin kalıbı (örneğin "Soru": metin, şıklar, doğru şık, puan değeri); nesne (object), o kalıptan üretilmiş somut bir örnek ("Anayasa'nın üstünlüğü" sorusu); kalıtım (inheritance), bir sınıfın başka bir sınıfın özelliklerini devralması ("ÇoktanSeçmeliSoru" ve "AçıkUçluSoru" ikisi de "Soru"nun özelliklerini taşır). Java, C#, Kotlin, Swift, Python bu tarzı güçlü destekler; MDN'e göre JavaScript de nesne açısından yoğun bir dildir, "prototip tabanlı" bir modeli vardır ama tipik OOP için class sözdizimi de sunar.10 Nesne fikrini JavaScript tarafında Bölüm 25'te göreceğiz.
Fonksiyonel
Fonksiyonel programlama (functional programming) işi, durumu değiştiren adımlar yerine fonksiyonların birleşimi olarak kurar: bir fonksiyon girdi alır, çıktı verir, başka bir şeyi bozmaz; fonksiyonlar da değer gibi dolaştırılabilir. Kotlin belgeleri bunun için birinci sınıf destek (yüksek dereceli fonksiyonlar, fonksiyon tipleri, lambda) olduğunu söyler.8 Bunu Bölüm 25'te, JavaScript'te fonksiyonların değişkene atanıp başka fonksiyona verilmesi olarak canlı göreceksin ve Bölüm 31'de React'in neden büyük ölçüde bu fikre yaslandığını anlayacaksın.
Bildirimsel
Son paradigma diğerlerinden farklıdır. Bildirimsel programlama (declarative programming)'da nasıl yapılacağını değil, ne istediğini söylersin; nasılını sistem bulur. İki tanıdık örnek bu kitapta yer alıyor. HTML bildirimseldir: "burada bir başlık, altında bir paragraf olsun" dersin; tarayıcı bunu nasıl çizeceğini kendisi bilir (Bölüm 23). SQL de öyle: MDN SQL'i "tablo tabanlı veritabanlarında veri güncellemek, almak ve hesaplamak için tasarlanmış tanımlayıcı (descriptive) bir bilgisayar dili" olarak tarif eder;10 "puanı 100'den fazla olan kullanıcıları getir" dersin, veritabanı hangi yoldan bulacağını kendisi seçer (Bölüm 38). Hukuk dilinde: buyurgan, bir usul kanunu gibi adım adım "önce şunu, sonra bunu yap" der; bildirimsel, bir hak tanımı gibi sonucu söyler, yolunu mahkemeye bırakır.
Bir soruda doğru sayısını ve bonusu verip puanı hesaplayan en küçük fonksiyon (her doğru 10 puan, artı bonus). Beş dilde de çalıştırdım; hepsi puan(4, 5) için 45 yazdırdı.
// C: tipler yazılır, derlenir
int puan(int dogru, int bonus) { return dogru * 10 + bonus; }
# Python: tip yok, girinti kapsamı belirler
def puan(dogru, bonus):
return dogru * 10 + bonus
// JavaScript: tip yok, süslü parantez
function puan(dogru, bonus) { return dogru * 10 + bonus; }
// Go: tipler parametrenin yanında
func puan(dogru int, bonus int) int { return dogru*10 + bonus }
// Java: sınıf içinde, tipler yazılır
static int puan(int dogru, int bonus) { return dogru * 10 + bonus; }
Gövde hepsinde aynı çarpma ve toplama. Fark, çevresinde: tipler yazılıyor mu, nasıl bloklanıyor, nerede derleniyor. İşte bu bölümün haritası, bu çevrenin haritasıdır. JavaScript'te puan("4", 5) çağırırsan da 45 çıkar (metin sayıya çevrilir, çünkü * metni sayıya zorlar); ama "5" + 1 yine "51" verir. Zayıf tipliliğin iki yüzü.
21.6 Dil kartları: nerede ve neden
Artık beş eksenle her dile bakabiliriz. Her kart: dilin özü, beş eksendeki yeri, nerede kullanıldığı. Kartlardaki nitelikleri resmî belgelerden aldım; yazarken emin olmadığım hiçbir şeyi (örneğin hangi yıl çıktığı) eklemedim.
C
Bölüm 9–10'daki dilimiz. Derlenen, statik tipli, bellek elle yönetilen, yordamsal. Linux çekirdeği C ile yazılıdır (daha doğru: gcc ile, GNU lehçesiyle derlenen C).12 Nerede: işletim sistemleri, sürücüler, gömülü yazılım. Neden: donanıma en yakın yüksek seviyeli dil; bellek davranışı açıktır. Dikkat: bellek güvenliğini sana bırakır.
C++
C'nin üstüne nesne yönelimli (ve başka) özellikler ekleyen dil. Derlenen, statik tipli, elle bellek yönetimi (modern pratiklerle). Learn C++, onu "orta seviyeli" diye tarif eder: ihtiyaca göre hem düşük hem yüksek seviyede çalışabilir.1 Dilin yaratıcısı Bjarne Stroustrup'un kullanım listesinde Chromium tarayıcısı, Firefox, Doom III motoru, Microsoft ve EA oyunları yer alır.13 Nerede: oyun motorları, tarayıcılar, performansın kritik olduğu uygulamalar. Neden: hız ve kontrol, ama C'den daha çok kavram var.
Python
Python belgelerinin tarifiyle yorumlanan, etkileşimli, nesne yönelimli, dinamik tipli bir dildir; yordamsal ve fonksiyonel stili de destekler. Büyük bir standart kütüphanesi vardır ve taşınabilirdir.2 Yaratıcısı Guido van Rossum Şubat 1991'de ilk sürümü yayımladı.2 Stack Overflow Developer Survey 2025, Python'un 2024'ten 2025'e 7 puanlık sıçramasını yapay zekâ, veri bilimi ve arka uç için "gidilecek dil" olmasına bağlar.14 Nerede: veri analizi, yapay zekâ ve makine öğrenmesi (Kısım III'ün micrograd'ı Python'dur), betikler. Neden: okunması kolay, hızlı yazılır. Bedeli: hız (CS50: derlenen programa göre küçük bir yavaşlama).2
JavaScript
Tarayıcının dili ve bizim ön yüz dilimiz. Dinamik tipli, zayıf tipli (örtük çeviri yapar), çöp toplayıcılı, V8 gibi motorlarda JIT ile çalışır. Stack Overflow 2026 anketinde en çok kullanılan dildir: katılımcıların %62,0'ı, üst üste 12. yıl bu listenin başında.14 Nerede: tarayıcı ve (Node.js ile) sunucu. Neden: tarayıcıda çalışan tek dil; bu yüzden zorunlu. Ayrıntısı Bölüm 25.
TypeScript
Resmî tarifle: JavaScript'in her özelliğini sunar ve üstüne bir tip sistemi ekler; mevcut çalışan JavaScript kodu aynı zamanda TypeScript kodudur.6 Amacı, el kitabının deyişiyle, JavaScript programları için statik bir tip denetleyicisi olmaktır; çünkü programcıların en yaygın hataları tip hatalarıdır.6 Nerede: büyük JavaScript projeleri; bizim ön yüzümüz. Neden: hataları çalışmadan yakalar. Tarayıcı TypeScript'i doğrudan çalıştırmaz; önce JavaScript'e çevrilir (Bölüm 30, 29).
Go
Go SSS belgesine göre Robert Griesemer, Rob Pike ve Ken Thompson 21 Eylül 2007'de beyaz tahtada yeni bir dilin hedeflerini çizmeye başladılar. Gerekçeleri: büyük yazılım projelerini kurmanın gereksiz karmaşıklığından bıkmışlardı, çok çekirdekli işlemciler yaygınlaşıyordu ve eşzamanlılığı verimli ve güvenli programlamak için dillerin yardımı azdı. Çözüm: eşzamanlılık için birinci sınıf destek ve güvenli otomatik bellek yönetimi.7 Derlenen, statik tipli, çöp toplayıcılı. Nerede: sunucular, bulut altyapısı, ağ servisleri. Neden: sade, hızlı derlenir, eşzamanlılık kolay. Bizim arka ucumuz; Bölüm 36.
Rust
Rust Kitabı'na göre Rust, yüksek seviyeli rahatlıkla düşük seviyeli kontrol arasındaki çatışmayı gidermeyi hedefler: bellek gibi ayrıntıları kontrol etme imkânı verir, ama bu kontrolün geleneksel zahmeti olmadan.9 Derleyici, eşzamanlılık hataları dahil, ince hataları içeren kodu derlemeyi reddederek "kapı bekçisi" rolü oynar.9 Derlenen, statik tipli, sahiplik sistemiyle bellek yönetimi. Nerede: güvenli sistem yazılımı, performansın kritik olduğu servisler. Neden: C'nin hızı, ama bellek hatasına karşı derleyici güvencesi. Bizim yığınımızda yok; ama Linux çekirdeği belgeleri çekirdeğin Rust desteği olduğunu söylüyor.12
Java ve Kotlin
Java: yüksek seviyeli, nesne yönelimli, javac ile ara koda derlenip JVM'de çalışan dil (21.2).3 Statik tipli, çöp toplayıcılı. Kotlin: JetBrains'in geliştirdiği, açık kaynaklı, statik tipli dil; proje 2010'da başladı, ilk resmî sürüm Şubat 2016'da çıktı. JVM, Android, JavaScript, Wasm ve yerel koda derlenebilir; Java ile %100 uyumludur ve Java'ya göre kabaca %40 daha az satır gerektirdiği tahmin edilir.8 Android'in resmî sitesi Kotlin'in profesyonel Android geliştiricilerinin %60'ından fazlası tarafından kullanıldığını söyler.15 Nerede: Android uygulamaları ve kurumsal sunucular. Neden: Android'in resmî dili ve eski kurumsal yazılım birikimi. Biz Android'i doğrudan Kotlin'le değil, Expo ile (Bölüm 22, 32) yazacağız.
Swift
Apple'ın tarifiyle "tüm Apple platformları için güçlü ve sezgisel" dil; swift.org'a göre genel amaçlı, modern, güvenli, çıkarsanmış tipleri ve otomatik bellek yönetimi olan bir dildir.8 Nerede: iPhone, iPad, Mac uygulamaları. Neden: Apple'ın yerel geliştirme dili. Yine Expo bizi doğrudan Swift yazmaktan kurtarır.
SQL
Programlama dili olmaktan çok sorgulama dili: MDN'in tarifiyle tablo tabanlı veritabanlarında veri güncellemek, almak, hesaplamak için tasarlanmış tanımlayıcı bir dildir.10 Bildirimsel. 2026 anketinde en çok kullanılan ikinci dil (%58,4) ve Postgres en çok kullanılan veritabanı (%57,9).14 Nerede: her yerde veri saklayan sistem. Neden: veriyi "ne istediğini" söyleyerek sorgulamak. Bizim yığınımızda Postgres ile (Bölüm 38–39).
Kısaca: C#, PHP, Ruby
- C#: Microsoft'un dili. Çok platformlu, genel amaçlı, nesne yönelimli ama fonksiyonel özellikler de alan, derlenen ve güçlü tipli bir dil; C, C++, JavaScript, TypeScript ve Java kullandıysan sözdizimi tanıdık gelir.11 2026 anketinde ilk onda (%27,1).14
- PHP: resmî sitesi "özellikle web geliştirmeye uygun, popüler, genel amaçlı bir betik dili" der; bir blogdan en büyük sitelere kadar çok yerde çalışır.16 Sunucu tarafında web için.
- Ruby: Yukihiro "Matz" Matsumoto'nun yarattığı, sadelik ve dengeye önem veren bir dil; resmî sitesi, dilin sevenlerinin onu güzel ve sanatsal bulduğunu söyler.17
Stack Overflow 2026 listesine göre en çok kullanılan on dil: JavaScript (%62,0), SQL (%58,4), HTML/CSS (%58,2), Python (%58,0), Bash/Shell (%51,3), TypeScript (%43,8), Java (%27,6), C# (%27,1), PowerShell (%24,6), C++ (%24,3).14 Dikkat: listede HTML/CSS, SQL ve Bash da var; yani "dil" kelimesi burada genişçe kullanılıyor. 2025 anketinde Go %16,4, Rust %14,8, Kotlin %10,8, Swift %5,4 idi.14 Küçük görünen payların büyük etkisi olabilir; çünkü bir dil bir niş için seçilir. Anket "neyin iyi olduğunu" değil, "kaç kişinin kullandığını" ölçer.
21.7 Bizim yığınımız: TypeScript + Go + SQL
Dört katı bir arada görmek için bir tablo:
| Parça | Dil | Seviye / çalışma | Tip | Bellek | Neden |
|---|---|---|---|---|---|
| Ön yüz (web ve mobil) | TypeScript | Yüksek; JavaScript'e çevrilip motorda JIT | Statik (JS'e tip ekler) | Çöp toplayıcı | Tarayıcının ve React Native'in dili JavaScript; üstüne tip güvencesi |
| Arka uç | Go | Yüksek; derlenen, makine kodu | Statik | Çöp toplayıcı | Sade, hızlı, eşzamanlılık kolay |
| Veri | SQL | Bildirimsel; veritabanı çalıştırır | Tablo şeması | Veritabanı yönetir | Veriyi "ne istediğimizi" söyleyerek sorgulamak |
Üç dilin üç ayrı işi var; birbirinin yerini tutmaz. TypeScript kullanıcının elinde çalışır (telefon, tarayıcı); Go sunucuda çalışır; SQL veritabanıyla konuşmanın dilidir. Bu bir tesadüf değil, Bölüm 22'de göreceğimiz istemci–sunucu ayrımının dil karşılığı. Seçimin gerekçeleri tek cümleyle:
- Neden TypeScript, saf JavaScript değil? Çünkü uygulama büyüdükçe tip hataları (yanlış alan adı, boş değer) çoğalır ve TypeScript bunları çalıştırmadan önce yakalar (21.3). Agent'ların yazdığı kod için bu özellikle değerli: derleyici ikinci bir gözdür.
- Neden Go? Go belgelerinin açıkladığı hedefler (büyük projelerde sadelik, eşzamanlılık, güvenli bellek yönetimi, derlenen hız) bir arka ucun ihtiyaçlarıyla örtüşür (21.6). Ayrıntı: Bölüm 36.
- Neden SQL? Verinin kalıcı ve sorgulanabilir olması için; Postgres en yaygın seçim (21.6).
"Yığın" bu kitapta iki ayrı şeyi anlatıyor. Bölüm 10'daki yığın, belleğin bir bölgesidir (stack, öbek/heap'in karşıtı). Buradaki teknoloji yığını (tech stack) ise bir ürünün üst üste dizilmiş dil ve araç kümesidir. Kelime ortak, kavram tamamen farklı; bağlamdan ayırt et.
Hukuk-Duolingo'nun yazılım yığını bu bölümün haritasında şöyle yerleşir. Prototip: HTML + CSS + vanilla JavaScript; derleme yok, tarayıcıya dosya olarak verilir (21.2). Hedef ön yüz: Expo + TypeScript. Hedef arka uç: Go. Veri: Postgres (SQL) ve önbellek için Redis. Agent'ların yazdığı bir Go dosyası ile bir TypeScript dosyası bir arada geldiğinde, hangi dilin hangi katta çalıştığını artık biliyorsun: biri kullanıcının cihazında (JIT'li motor ya da cihazın JavaScript ortamı), diğeri sunucuda (derlenmiş makine kodu). Hata mesajları da buna göre yorumlanır: "type error" ve derleme hatası TypeScript/Go tarafında çalıştırmadan önce çıkar; "undefined is not a function" gibi bir çalışma zamanı hatası JavaScript'in dinamik doğasını işaret eder.
Kerem'in prototipini bu haritaya yerleştir: index.html bildirimsel (HTML), style.css bildirimsel (CSS), script.js buyurgan ve kısmen fonksiyonel (JavaScript). Üç farklı "düşünce biçimi" bir arada. Neden böyle ayrıldığı sonraki dört bölümün konusu.
C'de gördüğün her kavram bu bölümde bir ekseni açtı. Derleyici (9.1) → derlenen/yorumlanan ekseni (21.2). Tip (9.3) ve Bölüm 2.8'in "anlam bağlamdadır" fikri → tip sistemleri (21.3). malloc/free ve bellek güvenliği (10.4–10.5) → bellek yönetimi, çöp toplayıcı ve sahiplik (21.4). Yani bu bölümde yeni bir şey öğrenmedin; C'de tanıdığın seçimlerin diğer dillerde farklı yapıldığını gördün. Bir dili C'nin aynasında okumak, kitabın geri kalanında seni sürüklenmekten koruyacak ana alışkanlık.
Bu bölümde neler kuruldu
Diller beş eksende ayrılır. Seviye: assembly ve makine dili düşük, C/C++/Rust orta-yüksek, Python/JavaScript çok yüksek; yukarı çıktıkça rahatlık, aşağı indikçe hız ve kontrol. Çalıştırma biçimi: derlenen (önceden makine koduna), yorumlanan (çalışırken), ara kod ile sanal makine (Java/JVM) ve anında derleme (JIT; tarayıcıda JavaScript). Tip sistemi: statik (derlemede denetim) ve dinamik (çalışırken), güçlü (karıştırmayı reddeden) ve zayıf (örtük çeviren); tip çıkarımı yazma zahmetini azaltır. Bellek yönetimi: elle (C), çöp toplayıcı (Java, Go, JavaScript, Python) ve sahiplik (Rust). Paradigma: buyurgan, yordamsal, nesne yönelimli, fonksiyonel, bildirimsel (HTML, SQL); diller birden çok paradigmayı karıştırır. On bir dilin kartında her birinin nerede ve neden kullanıldığını gördük; bizim teknoloji yığınımız TypeScript (ön yüz), Go (arka uç), SQL (veri) ve her biri farklı bir kata ve farklı bir işe hizmet ediyor.
Terimler sözlükte, Bölüm 21 başlığı altında.
Learn C++, "Introduction to programming languages": makine dili, assembly, yüksek seviyeli dil ve derleme/yorumlama farkı, kısa ve açık. Derinleşmek için: Rust Kitabı, "What Is Ownership?" (bellek yönetiminin üç yolu) ve Go SSS'nin "Origins" kısmı (bir dilin neden tasarlandığı).
Takıldığın her yeri yapay zekâ öğretmenine sor. Bir öneri: ondan, tanımadığın bir dilde (örneğin Go) yazılmış on satırlık bir kodu sana satır satır açıklamasını iste ve her satır için şu beş soruyu sor: seviye, çalıştırma, tip, bellek, paradigma. Birkaç tur sonra haritayı kendi başına uygulayabilirsin.
Bölüm sonu soruları
Kitaba bakmadan cevapla. Kâğıt kalem serbest.
.class dosyasına derlenince içinde ne bulunur?javac kaynağı JVM'in makine dili olan ara koda (bytecode) çevirir; sonra JVM bunu çalıştırır. Bkz. 21.2.int x = "merhaba"; satırı C'de ne zaman hata verir?"5" + 1 neden "51" verir?let ad = "Kerem" yazınca TypeScript string tipini kendisi çıkarır. Statik güvence, dinamik dilin kısalığıyla gelir. Bkz. 21.3.Örnek cevabı göster
Çünkü çalıştırma biçimi dilin değil, gerçeklemenin özelliğidir. JavaScript kaynak olarak yorumlanabilir metin gibi verilir ama modern motorlar (V8 gibi) çalışırken sık çalışan kısımları JIT ile makine koduna çevirir; yani yorumlama ve derleme bir arada olur. Java da önce ara koda derlenir, sonra sanal makinede çalışır. Bu yüzden "derlenen/yorumlanan" kesin bir iki kutu değil, bir cetveldir (21.2).
Örnek cevabı göster
Örnek: TypeScript statik tiplidir ve tip hatalarını çalıştırmadan yakalar; ayrıca tarayıcı ve React Native JavaScript'i çalıştırdığı için ön yüz için doğal seçimdir. Go derlenen, statik tipli ve çöp toplayıcılı, eşzamanlılığı birinci sınıf destekleyen bir dildir; sunucuda çok isteği aynı anda karşılamak için uygundur. SQL bildirimsel olduğu için veriyi nasıl bulacağını değil ne istediğimizi söyler; veritabanı yolu kendisi seçer (21.3–21.7).
Kaynaklar
- Learn C++, Introduction to programming languages: düşük seviyeli diller, yüksek seviyeli diller, derleme ve yorumlama, C++'ın "orta seviye" konumu.
- Python Yazılım Vakfı, General Python FAQ (Python nedir, ilk sürüm Şubat 1991); CS50x 2026, Lecture 6 ders notları: Python yorumlanan dil, C ile karşılaştırma. Kaynak: CS50 Hafta 6 notları.
- Oracle, The Java Tutorials: About the Java Technology:
.java→javac→.class(bytecode) → JVM. - MDN, Glossary: JIT; Glossary: JavaScript engine; Static typing; Dynamic typing.
- MDN, Glossary: Type coercion; Memory management: elle yönetim, çöp toplayıcı, sorunun genel olarak çözülemezliği.
- TypeScript, The TypeScript Handbook ve TypeScript for JavaScript Programmers: tip çıkarımı, JavaScript ile ilişki.
- Go, Frequently Asked Questions (FAQ): Origins, history (21 Eylül 2007), eşzamanlılık ve çöp toplama gerekçesi.
- Kotlin, FAQ; Swift.org, About Swift: çıkarsanmış tipler, otomatik bellek yönetimi.
- Klabnik & Nichols, The Rust Programming Language, "What Is Ownership?" ve Introduction; rust-lang.org.
- MDN, Glossary: OOP; Glossary: SQL.
- Microsoft Learn, A tour of C#: C#'ın genel amaçlı, derlenen, güçlü tipli oluşu.
- The Linux Kernel documentation, Programming Language: çekirdeğin C ile yazılması, Rust desteği.
- Bjarne Stroustrup, C++ Applications: C++ ile yazılmış uygulama listesi.
- Stack Overflow, Developer Survey 2026, Technology ve 2025, Technology.
- Android Developers, Kotlin and Android: Kotlin'in profesyonel Android geliştiricilerinin %60'ından fazlasınca kullanılması.
- PHP, php.net: PHP'nin tanımı.
- Ruby, About Ruby: Matz ve dilin tasarım felsefesi.
- Oracle, Java SE 21 HotSpot Virtual Machine Garbage Collection Tuning Guide; Python, gc — Garbage Collector interface.