10 Gün, 46 Sürüm ve Dört Yapay Zekâ Aboneliği: AhdCode v1.0.0

İlk AhdCode yazısını yazarken projenin nasıl başladığını anlatmıştım. O yazıda bir konuda dalga geçerken kendi programlama dilimi yazmaya başlamamı, ilk tasarım kararlarını ve birkaç gün içerisinde ortaya çıkan yapıyı anlatmıştım.

Aradan yalnızca yaklaşık on gün geçti.

Bu kez geriye dönüp baktığımda, ilk yazıyı yazdığım anda bile olayların henüz ne kadar başında olduğumu fark ettim.

Çünkü AhdCode'un ilk on günü; birkaç tehlikeli soru, binlerce cevap, sayısını artık takip etmediğim tokenlar, dört farklı yapay zekâ aboneliği, iki neredeyse tamamen dolmuş ChatGPT sohbeti ve sonunda 46 release (AHD tercümesi: sürüm) ile sonuçlandı.

Ve bugün elimde:

AhdCode v1.0.0

var.

Üstelik geriye dönüp ilk gece koyduğum hedeflerle bugün çalışan sistemi yan yana koyduğumda fark ettiğim şey yalnızca sürüm numarasının hızlı ilerlemiş olması değil.

Başlangıçta:

“Bir gün bunu da yapabilir miyiz?”

diye konuştuğum şeylerin önemli bir kısmı artık gerçekten dilin içerisinde.

Küçük bir not: Bu yazıda doğal olarak bol miktarda yazılım ve programlama dili terimi geçiyor. Yazı sizi teknik ayrıntılarla boğmasın diye gerekli gördüğüm yerlerde parantez içinde kısa “AHD tercümeleri” bıraktım. Teknik olarak birebir sözlük karşılığı olmaktan çok, o cümlede neyi kastettiğimi hızlıca anlatmaları yeterli.

Her Şey Birkaç Tehlikeli Soruyla Başladı

Geriye dönüp gerçek konuşma kayıtlarına baktığımda olayların benim hatırladığımdan bile daha hızlı geliştiğini fark ettim.

27 Ağustos, 21:15.

Sorduğum soru kabaca şuydu:

“Dünyada gerçekten sıfırdan, yapay zekâ olmadan bir programlama dili yazabilecek kadar yazılım bilen bir milyon kişi var mıdır?”

Normal şartlarda bu soru biraz tartışılır, birkaç görüş ortaya atılır ve konu kapanır.

Bende kapanmadı.

21:23.

Sekiz dakika sonra:

“AhdCode diye bir dil çıkarsak bu proje ne kadar sürer?”

Ardından C mi kullanalım, Go mu kullanalım, compiler (AHD tercümesi: derleyici) nasıl çalışsın, web tarafı nasıl olsun, native executable (AHD tercümesi: işletim sisteminin doğrudan çalıştırabildiği yerel program) üretelim mi derken saat ilerledi.

İlk fikirlerden biri AhdCode kaynak kodunun C'ye çevrilmesi ve gerisini clang ya da gcc gibi mevcut araçlara bırakmaktı. Böylece doğrudan makine kodu üretmek, register allocation (AHD tercümesi: işlemcideki sınırlı yazmaçları hangi verinin kullanacağını belirleme işi), farklı işlemci mimarileri ve optimizer (AHD tercümesi: üretilen kodu daha verimli hâle getiren katman) gibi alanlarla ilk günden uğraşmak zorunda kalmayacaktık.

Fakat benim asıl hedefim yalnızca compiler teorisini deneyen küçük bir oyuncak değildi.

İstediğim şey daha çok şuydu:

Terminalden kendi dilimi çalıştırayım; kendi local server'ını (AHD tercümesi: bilgisayarımda çalışan yerel sunucusunu) açabilsin, MySQL'e bağlanabilsin, HTML, CSS ve JavaScript ile birlikte kullanılabilsin ve günün birinde PHP'nin yaptığı bazı işleri kendi yaklaşımıyla yapabilecek bir dil olsun.

Bu hedef C tarafındaki runtime (AHD tercümesi: program çalışırken ona hizmet eden çalışma zamanı altyapısı) yükünü gereksiz yere büyütüyordu.

Böylece Go fikri ortaya çıktı.

AhdCode kaynak kodu önce Lexer (AHD tercümesi: kodu anlamlı küçük parçalara ayıran katman) ve Parser'dan (AHD tercümesi: bu parçaların dilin kurallarına göre nasıl bir yapı oluşturduğunu çözen katman) geçecek, AST (AHD tercümesi: kodun ağaç biçimindeki soyut yapısı) oluşturulacak, semantic kontroller (AHD tercümesi: kod biçimsel olarak doğru olsa bile anlam bakımından geçerli mi kontrolleri) yapılacak, ardından Go koduna dönüştürülecek ve en sonunda native executable üretilecekti.

Go'nun garbage collection (AHD tercümesi: kullanılmayan belleğin otomatik temizlenmesi), string (metin) ve map (anahtar-değer) yapıları, HTTP altyapısı, concurrency desteği (AHD tercümesi: birden fazla işin birlikte yürütülebilmesi), JSON işlemleri ve geniş ekosistemi sayesinde enerjiyi AhdCode'un kendisine harcamak çok daha mantıklı görünüyordu.

O gece verilen en önemli mimari kararlardan biri buydu.

28 Ağustos, 02:49.

Yaklaşık beş saat önce teorik olarak dünyada kaç kişinin programlama dili yazabileceğini merak eden ben, artık şu cümleyi kuruyordum:

“AhdCode isimli kendime ait bir dil üretmek istiyorum. Prompt (AHD tercümesi: yapay zekâya verdiğim ayrıntılı talimat) ve spec (AHD tercümesi: dilin nasıl davranacağını tanımlayan teknik şartname) yazdım, bir inceler misin?”

Fakat burada küçük bir noktayı özellikle belirtmem gerekiyor.

Bu beş saat yalnızca soru sorup cevap bekleyerek geçmedi. Soruların cevaplarını verdim, seçenekleri tartıştım, kararları aldım, gereksinimleri netleştirdim ve AhdCode'un nasıl bir dil olacağını adım adım şekillendirdim.

Dolayısıyla geçiş yalnızca:

“Acaba yapılabilir mi?”

sorusundan:

“Spec burada.”

aşamasına geçiş değildi.

O beş saat aynı zamanda dilin ilk karakterinin oluştuğu dönemdi.

Noktalı virgül kullanmak istemiyor muyum?

Fonksiyonların görünümü nasıl olacak?

Değişken tanımlama ile sonradan değer değiştirme birbirinden açık biçimde ayrılmalı mı?

Bir fonksiyona yanlış türde veri gönderildiğinde hata compiler aşamasında mı yakalanmalı?

Modüller hangi isimlerle ve nasıl içeri alınmalı?

Bir alias (AHD tercümesi: uzun bir modül adına verilen kısa isim) başka bir isimle çakışırsa ne olmalı?

Hata sistemi kullanıcıya yalnızca “yanlış” mı demeli, yoksa yanlışın nerede ve neden olduğunu da anlatmalı mı?

Go'nun hangi davranışları AhdCode'a sızmamalı?

Bunların önemli bir kısmının cevabını daha compiler ortada yokken vermeye başlamıştım.

Sonrası ise biraz daha uzun sürdü.

Binlerce cevap, sayısını tutmadığım tokenlar, yüzlerce tasarım kararı ve giderek tuhaflaşan sorular...

“Bir modülün kısa adı başka bir modülle çakışırsa hangisi kazanacak?”

“Bu hata compile-time'da mı yakalanmalı, runtime'a kadar yaşamasına izin mi vermeliyiz?”

“Bunu eski sürümde yazmış biri varsa şimdi kodu kırılır mı?”

“Bir dosya başka bir modül tarafından aynı anda kullanılıyorsa ne olacak?”

“Path (AHD tercümesi: dosya veya klasör yolu) Windows'ta da aynı davranacak mı?”

“LaTeX tamam da TikZ (AHD tercümesi: LaTeX içinde şekil ve grafik çizmeye yarayan sistem) de eklesek sertifika kenarlığı çizebilir miyiz?”

Son sorunun ilk geceki compiler planında bulunmadığını özellikle belirtmek isterim.

Çalışınca Gelen En Büyük Problem: Daha Fazlasını İstemek

Başlangıçta hedefi özellikle küçük tutmak istiyordum.

Birkaç temel veri tipi.

Fonksiyonlar.

Koşullar.

Döngüler.

Listeler.

Modüller.

Ve çalışan bir compiler.

İlk aşamada class (sınıf) bile gereksiz görünüyordu. Generics (AHD tercümesi: aynı yapıyı farklı veri türleriyle güvenli biçimde kullanabilme sistemi) yoktu. Reflection (AHD tercümesi: programın çalışma sırasında kendi yapısını inceleyebilmesi) yoktu. Operator overloading (AHD tercümesi: + veya - gibi operatörlere özel davranışlar tanımlama) yoktu. Büyük framework (AHD tercümesi: uygulamayı belirli bir mimari içinde kurmaya yarayan hazır çatı) sistemleri yoktu.

Kısacası ilk planın temel felsefesi şuydu:

“Java'yı yeniden icat etmeyelim.”

Bu yaklaşım gayet mantıklıydı.

Yaklaşık birkaç saat boyunca.

Çünkü ilk çalışan kodu gördüğünüz anda çok tehlikeli başka bir soru ortaya çıkıyor:

“Peki bununla başka ne yapabiliriz?”

Bende bu sorunun ilk ciddi cevabı oldukça doğal bir yerden geldi:

LaTeX.

Matematikçi olduğum için AhdCode'un yalnızca ekrana çıktı veren bir dil olarak kalması yerine doğrudan matematiksel ve akademik belge üretebilmesi fikri çok erken aşamada ilgimi çekti.

Böylece standart kütüphanenin ilk büyük genişlemelerinden biri LaTeX tarafında oldu.

Fakat LaTeX geldikten sonra bu kez yalnızca belge üretmek değil, o belgelere girecek veriyi işlemek de önemli hâle geldi.

Böylece Data (veri işleme) tarafı geldi.

Ardından doğal olarak CSV (AHD tercümesi: tablo biçimindeki verilerin basit metin dosyalarında saklandığı yaygın format).

Veri okunabiliyorsa bir sonraki soru çok gecikmedi:

“Peki bunu görselleştirsek?”

Böylece Plot (grafik çizimi) ortaya çıktı.

Plot ile veri ve matematik tarafı genişleyince tekrar LaTeX'e döndüm. İlk LaTeX desteğinin yalnızca temel belge üretmesi artık yeterli görünmüyordu; modülün kapsamı genişlemeye başladı.

Yani standart kütüphanenin gelişimi düz bir:

Modül 1
Modül 2
Modül 3
Modül 4

listesi şeklinde ilerlemedi.

Daha çok:

LaTeX
   ↓
Data
   ↓
CSV
   ↓
Plot
   ↓
LaTeX'in genişlemesi
   ↓
Regex
   ↓
Word
   ↓
XML
   ↓
Excel
   ↓
...

şeklinde birbirini doğuran ihtiyaçlar zincirine dönüştü.

Regex (AHD tercümesi: metin içinde desen aramaya ve eşleştirmeye yarayan düzenli ifadeler) metin ve veri işlemlerinde yeni olanaklar açtı.

Word desteği gelince AhdCode yalnızca matematiksel belge değil, daha genel amaçlı belgeler de üretebilmeye başladı.

XML (AHD tercümesi: veriyi etiketlerle yapılandırarak saklayan metin tabanlı format) başka veri biçimlerini sisteme taşıdı.

Excel ise veri işleme ve belge üretme taraflarını tekrar birbirine bağladı.

Sonrasında File, Path, Environment, SQLite, MySQL, PDF, Archive ve başka araçlar da bu yapının üzerine eklenmeye devam etti.

Bir noktada fark ettim ki web tarafına tam anlamıyla geçmeden önce, normalde çok daha sonra düşünürüm dediğim pek çok temel araç zaten tamamlanmıştı.

Daha da hoşuma giden taraf, bunların birbirinden kopuk özellikler olarak gelmemesiydi.

Bir sürümde eklenen şey, birkaç sürüm sonra gelecek başka bir modülün altyapısını hazırlıyordu. Data CSV'yi, CSV Plot'u anlamlı hâle getiriyor; Plot tekrar LaTeX'i genişletme ihtiyacı doğuruyor; belge ve veri araçları ilerledikçe Word, XML ve Excel gibi modüller doğal biçimde zincire ekleniyordu.

Böylece standart kütüphanede yalnızca modül sayısı artmıyordu; modüller arasında giderek daha anlamlı bir ilişki de kuruluyordu.

Sürümler birbirinin üstüne oturmaya başladı.

Sanırım AhdCode'da şu ana kadar en gurur duyduğum konulardan biri de bu.

Hızlı geliştirmek kolay olabilir.

Hızlı geliştirirken önceki yirmi sürümü parçalamamak daha zor.

En Tehlikeli Sorular Genellikle Küçük Görünür

AhdCode'un gelişimini belirleyen şey yalnızca büyük özellikler olmadı.

Asıl zaman alan konular çoğu zaman birkaç kelimelik sorulardı.

Örneğin:

“Bir Constant'ın içindeki liste değiştirilebilir mi?”

İlk bakışta küçük bir soru.

Ama cevabı dilin immutable (AHD tercümesi: oluşturulduktan sonra değiştirilemeyen) veri yaklaşımını belirliyor.

Eğer yalnızca değişkenin kendisini koruyup içindeki listenin değişmesine izin verirseniz başka bir davranış elde ediyorsunuz; iç yapıya kadar değişmezliği zorunlu tutarsanız başka bir dil felsefesine geçmiş oluyorsunuz.

Ben ikinci yaklaşımın daha tutarlı olduğuna karar verdiğimde, aslında yalnızca tek bir keyword'ün davranışına değil, AhdCode'un sabitlik anlayışına karar vermiş oldum.

Bir başka örnek:

“Null burada ne yapacak?”

Bu da birkaç kelime.

Ama cevabı type system'den (tip sistemi: hangi verinin nerede kullanılabileceğini belirleyen kurallar) runtime davranışına kadar pek çok alanı etkiliyor.

Bir değer gerçekten boş olabilir mi?

Boş olabilecek bir değer, boş olamayacak bir yere aktarılabilir mi?

Compiler bunu önceden görebiliyorsa neden program çalışana kadar beklesin?

Küçük görünen bir null kararı bir anda kontrol akışını, tip güvenliğini ve hata mesajlarını aynı masaya getiriyor.

Sonra başka bir soru geliyor:

“Bu davranışı değiştirirsek daha önce yazılmış AhdCode dosyaları ne olacak?”

Bu noktadan sonra konu yalnızca yeni özellik eklemek olmaktan çıkıyor ve geriye dönük uyumluluk meselesine dönüşüyor.

Bir programlama dilinin aslında syntax'tan (AHD tercümesi: dilin yazım ve sözdizimi kuralları) çok daha fazlası olduğunu bu süreçte çok daha iyi gördüm.

Bir özellik tek başına güzel görünebilir.

Ama dilin geri kalanıyla çelişiyorsa güzel görünmesi yeterli değil.

Happy path'i (AHD tercümesi: her şeyin beklendiği gibi kullanıldığı normal senaryo) çalıştırmak çoğu zaman kolay.

Benim daha çok ilgimi çeken şey ise kendi aramızda zamanla destroyer path (AHD tercümesi: sistemi bilerek saçma ve uç durumlarla zorladığım yıkıcı test yolu) dediğim taraf oldu.

Normal bir kullanıcı:

write("Hello AhdCode")

yazar.

Ben ise bir süre sonra:

“Peki null ile string'i toplarsam?”

“Unicode karakterle null byte'ı (AHD tercümesi: sayısal değeri sıfır olan ve bazı sistemlerde metnin sonunu ifade edebilen özel bayt) aynı yere koyarsam?”

“Buraya kapanmamış HTML etiketi verirsem?”

“Aynı koleksiyonu üzerinde dolaşırken değiştirmeye çalışırsam?”

“Yanlış türde veriyi doğru görünüyormuş gibi birkaç fonksiyon boyunca taşımaya çalışırsam?”

diye dolaşmaya başladım.

Bir şey bozulduğunda da ilk tepkim çoğu zaman:

“Güzel. Demek ki burada hâlâ konuşmamız gereken bir şey var.”

oluyordu.

Çünkü böyle bir projede hatanın ortaya çıkması yalnızca düzeltilmesi gereken bir bug (AHD tercümesi: yazılım hatası) anlamına gelmiyor.

Bazen hata, dilin henüz cevap vermediği bir tasarım sorusunu görünür hâle getiriyor.

İlk Tahminler Konusunda Küçük Bir Problem

İlk gece yaptığımız süre tahminlerine şimdi dönüp bakmak oldukça eğlenceli.

Konuştuğumuz tablo kabaca şuydu:

Bir haftada:

“Bak, kendi dilimiz çalışıyor.”

diyebileceğimiz bir demo.

İki veya dört haftada küçük gerçek projelerde kullanılabilecek bir yapı.

Bir veya iki ay içerisinde ise dokümantasyonu olan, belirli araçlara sahip, kullanılabilir bir AhdCode 0.1.

Bu tahmin teknik açıdan gayet makuldü.

Hesaba katmadığımız tek değişken bendim.

Yaklaşık on gün sonra proje 46 release görmüş ve AhdCode v1.0.0 noktasına ulaşmıştı.

Dolayısıyla bundan sonra AhdCode için süre tahmini yaparken klasik yazılım geliştirme değişkenlerinin yanına bir tane daha eklemek gerekebilir:

“Geliştirici gece saat 02:00'de yeni bir şey merak edecek mi?”

Bu değişkenin şu ana kadarki değeri maalesef sürekli true (AHD tercümesi: evet, maalesef yine merak etti).

Bir de bunun yanına:

“Merak ettiği şeyi sabaha bırakacak mı?”

değişkenini eklemek gerekebilir.

Onun mevcut değeri konusunda da çok umutlu değilim.

46 Release: Hızdan Çok Bir Hayatta Kalma Stratejisi

Burada “10 günde 46 release” cümlesinin yanlış anlaşılmasını da istemiyorum.

Bu benim ne kadar hızlı kod yazdığımı göstermek için kullandığım bir sayı değil.

Zaten kodun önemli bir kısmını yapay zekâ modelleri üretti.

46 release biraz da projeyi çökertmeden ilerleyebilmenin yöntemi oldu.

Bir özelliği ekledik.

Test ettik.

Eski davranışları kontrol ettik.

Dokümantasyonu güncelledik.

Sonra sürümü dondurduk.

Bu sayede bir sonraki özellik geldiğinde elimizde yalnızca “dün çalışıyordu galiba” dediğimiz belirsiz bir kod tabanı değil, nerede durduğumuzu bildiğimiz bir sürüm vardı.

Proje büyüdükçe en büyük korkum yeni bir özellik ekleyememek değil, daha önce doğru çalışan bir davranışı fark etmeden bozmak olmaya başladı.

İlk günlerde temel soru:

“Compiler bunu kabul ediyor mu?”

iken birkaç gün sonra soru:

“Compiler bunu kabul ediyor ama gerçekten kabul etmesi gerekiyor mu?”

hâline geldi.

Bir kod parçasının derlenebiliyor olması artık tek başına başarı kriteri değildi.

Doğru davranışı mı temsil ediyor?

Eski sürümle tutarlı mı?

Hata verdiğinde doğru yerde mi veriyor?

Bir sonraki özelliğin önünü açıyor mu, yoksa ileride taşımamız gereken yeni bir yük mü oluşturuyor?

Bence programlama dili geliştirme sürecindeki en önemli değişimlerden biri de buydu.

Dört Yapay Zekâ, İki Dolmuş Sohbet ve Bilinmeyen Sayıda Token

İlk AhdCode yazısında da özellikle belirtmiştim:

AhdCode'un bütün kodunu tek başıma oturup yazdığımı iddia etmiyorum.

On günlük sürecin sonunda bu durum çok daha belirgin hâle geldi.

Farklı zamanlarda farklı yapay zekâ modellerinden yararlandım.

Bir model implementation (AHD tercümesi: tasarlanan şeyi gerçekten koda dökme) konusunda daha iyi sonuç veriyordu.

Bir diğeri uzun dosyaları inceleyip mimari sorunları bulmakta daha başarılıydı.

Başka biri testlerde yakalanabilecek uç durumları üretmede daha faydalı olabiliyordu.

Bazen bir modelin yazdığı kodu diğerine incelettim.

Bazen ikisinin de ortak kararından şüphelenip üçüncü bir modele:

“İkisi de böyle diyor ama ben yine de tatmin olmadım. Bir de sen eleştir.”

dedim.

Sonuçta AhdCode için aktif olarak kullandığım yapay zekâ aboneliği sayısı dörde çıktı.

ChatGPT tarafında ise yalnızca AhdCode konuştuğum iki ayrı sohbet neredeyse tamamen doldu.

Harcanan token sayısını bir süre takip ettim.

Sonra ruh sağlığım açısından takip etmemeye karar verdim.

2026 yılında kendi programlama dilinizi geliştirirken dört farklı yapay zekâyı birbirlerinin kodlarını denetlemek üzere görevlendirmek biraz absürt görünebilir.

Fakat şaşırtıcı biçimde işe yarıyor.

Hatta bazen en faydalı sonuç, modellerin aynı fikirde olması değil birbirleriyle çelişmesi oluyordu.

Çünkü iki farklı yaklaşım görünce son kararı neden verdiğimi düşünmek zorunda kalıyordum.

Bu süreçte yapay zekâyla yazılım geliştirme konusunda da önemli bir şey öğrendim.

Bir yapay zekânın çok iyi kod yazabiliyor olması, sizin ne istediğinizi bilme zorunluluğunuzu ortadan kaldırmıyor.

Aksine proje büyüdükçe karar verme yükü daha da artıyor.

İlk gün:

“Bunu yap.”

demek yeterli olabilir.

Onuncu gün ise artık şu soruların cevaplarını bilmeniz gerekiyor:

  • Bu özellik AhdCode'un mevcut tasarım felsefesine uyuyor mu?
  • Daha önce verdiğimiz hangi kararı etkiliyor?
  • Geriye dönük uyumluluğu kırıyor mu?
  • Aynı işi yapan ikinci bir API (AHD tercümesi: farklı yazılım parçalarının birbirleriyle nasıl konuşacağını belirleyen arayüz) mı oluşturuyoruz?
  • Bu özellik standart kütüphanede doğru yerde mi duruyor?
  • Kullanıcı bunu yanlış kullandığında hangi hatayı görecek?
  • Bu hata mesajı gerçekten kullanıcıya yardımcı oluyor mu?
  • Test etmediğimiz bir platform davranışı var mı?
  • Bu özellik gerçekten gerekli mi?
  • Yoksa yalnızca yapılabildiği için mi ekliyoruz?

Son sorunun giderek daha önemli hâle geldiğini düşünüyorum.

Çünkü yapay zekâ çağında bir şeyi yapabilmek giderek ucuzluyor.

Bir özelliğin birkaç saat içerisinde yazılabiliyor olması artık onu eklemek için tek başına yeterli bir gerekçe değil.

Ne yapılmaması gerektiğine karar vermek ise hâlâ pahalı.

Bir Noktada Dil Yetmedi, Araçları da Yazmaya Başladım

İlk gece aklımda esas olarak dil vardı.

Lexer.

Parser.

Tip sistemi.

Compiler.

Native executable.

Ama bir programlama dilini gerçekten kullanmaya başladığınız anda yalnızca compiler'ın varlığı yetmiyor.

Kod yazarken editörün sizi tanımasını istiyorsunuz.

Kaydettiğiniz anda dosyanın yeniden derlenmesini istiyorsunuz.

Kodun biçimini tek komutla düzeltmek istiyorsunuz.

Bazen küçük bir şeyi denemek için dosya oluşturmak bile istemiyorsunuz.

İşte bu noktada proje yalnızca AhdCode dilinden çıkıp AhdCode araç zincirine dönüşmeye başladı.

Language Server

Bunların en önemlilerinden biri LSP, yani Language Server Protocol (AHD tercümesi: editör ile programlama dilinin analiz araçlarını konuşturan standart) desteği oldu.

AHD tercümesiyle: Editörün AhdCode'u gerçekten tanımasını sağlayan arka plandaki dil servisi.

Bugün:

ahdcode lsp

ile AhdCode'un kendi language server'ı çalışıyor.

Bu yalnızca kırmızı çizgi çizip:

“Burada galiba hata var.”

diyen küçük bir sistem de değil.

Diagnostics (AHD tercümesi: kod hatalarını ve uyarıları editörde gösterme) var.

Hover (AHD tercümesi: bir ismin üzerine gelince türünü ve bilgisini gösterme) var.

Completion (AHD tercümesi: otomatik kod tamamlama önerileri) var.

Go to Definition (AHD tercümesi: kullanılan bir ismin tanımlandığı yere tek hareketle gitme) var.

Document Symbols (AHD tercümesi: dosyadaki Function, Class ve benzeri yapıları listeleme) var.

Signature Help (AHD tercümesi: bir Function çağrılırken hangi parametrelerin beklendiğini gösterme) var.

Find References (AHD tercümesi: seçilen bir ismin nerelerde kullanıldığını bulma) var.

Rename (AHD tercümesi: bir ismi yalnızca metin olarak değil, gerçekten aynı sembol olan yerlerde güvenli biçimde yeniden adlandırma) var.

Semantic highlighting (AHD tercümesi: kodu yalnızca kelimeye değil, anlamına göre renklendirme) var.

Inlay hints (AHD tercümesi: editörde satırın içine küçük tür veya parametre ipuçları yerleştirme) var.

Quick fix ve code action (AHD tercümesi: belirli hatalar için editörden uygulanabilen hazır düzeltme ve işlemler) desteği var.

Auto import (AHD tercümesi: kullanılan bir sembolün gerekli modülünü otomatik ekleme) var.

Document formatting (AHD tercümesi: açık dosyayı AhdCode'un standart yazım biçimine getirme) var.

Workspace symbol araması (AHD tercümesi: proje içindeki Function, Class ve benzeri tanımları arama) var.

Folding ve selection ranges (AHD tercümesi: kod bloklarını katlama ve anlamlı kod parçalarını kademeli seçme) var.

Daha da önemlisi, bunların arkasında editör için ayrıca uydurulmuş ikinci bir AhdCode anlayışı bulunmuyor.

LSP kendi parser'ını veya kendi tip sistemini icat etmiyor.

Compiler hangi lexer, parser ve semantic analiz sistemini kullanıyorsa language server da aynı gerçek frontend'den (AHD tercümesi: kaynak kodu okuyup anlamlandıran compiler'ın ön tarafı) bilgi alıyor.

Yani compiler:

“Bu yanlış.”

derken editörün:

“Bence doğru olabilir.”

demesi gibi iki ayrı evren oluşturmamaya çalıştım.

Kaydedilmemiş editör içeriğinin bile analiz edilebilmesi de işin benim hoşuma giden taraflarından biri.

VS Code eklentisi de aynı ahdcode lsp sunucusunu kullanıyor.

Dolayısıyla önceki taslaklarda:

“Language Server geliştirilebilir.”

diye yazmam artık doğru değil.

Elbette ileride daha fazla özellik eklenebilir.

Ama günlük kullanım için belirlediğim LSP yüzeyi zaten tamamlanmış durumda.

Formatter

Aynı şey formatter (AHD tercümesi: kodu dilin standart görünümüne otomatik olarak sokan araç) için de geçerli.

ahdcode format program.ahd

ile kaynak kod tek bir canonical (AHD tercümesi: dilin standart kabul ettiği) biçime getirilebiliyor.

Formatter yalnızca boşlukları rastgele düzenleyen bir metin aracı değil.

AST-aware (AHD tercümesi: kodu düz metin gibi değil, yapısını anlayarak işliyor).

Yani kodun yapısını biliyor.

Yorumları koruyor.

String escape'lerini (AHD tercümesi: \n gibi metin içindeki özel karakter gösterimlerini) koruyor.

Interpolation (AHD tercümesi: değişken veya ifadeyi doğrudan metnin içine yerleştirme) davranışını bozmuyor.

Multiline string (AHD tercümesi: birden fazla satıra yayılan metin) içeriğine dokunmuyor.

Geçersiz kaynak kodu yarım yamalak biçimlendirmeye çalışmıyor.

Ve aynı kodu tekrar tekrar formatladığınızda sonuç değişmiyor.

format(format(source)) == format(source)

Bir programlama dili yazmaya başlarken formatter'ın bu kadar erken gündeme geleceğini düşünmemiştim.

Fakat kendi kodunuzu yüzlerce dosyada görmeye başlayınca:

“Bu dilin resmi görünümü ne?”

sorusu da syntax kadar gerçek bir soru hâline geliyor.

REPL

Bir de REPL var.

AHD tercümesiyle: Dosya oluşturmadan terminalde AhdCode satırlarını yazıp sonucunu anında görebildiğiniz etkileşimli ortam.

Terminalde yalnızca:

ahdcode

yazınca persistent (AHD tercümesi: önceki tanımları hatırlayan) bir AhdCode oturumu açılabiliyor.

Örneğin:

ahd> x := 5
ahd> x = x + 1
ahd> x
6

şeklinde ilerlemek mümkün.

Burada da ayrı bir oyuncak yorumlayıcı yazmadım.

Normal lexer, parser, semantic checker ve AhdCode'un alt temsil katmanları dosya derlemesiyle ortak kullanılıyor.

Değişkenler oturum boyunca yaşayabiliyor.

Function'lar ve Class'lar yaşayabiliyor.

List ve Pair gibi nesneler kimliklerini koruyor.

Modüller kullanılabiliyor.

File işlemleri yapılabiliyor.

Hatta SQLite veritabanı bile interaktif oturum içerisinde açık kalabiliyor.

Kısacası bir noktada:

“Kendi dilimi derleyebiliyorum.”

seviyesi:

“Kendi dilimi günlük olarak kullanırken ihtiyaç duyduğum araçların önemli kısmı da var.”

seviyesine dönüştü.

İlk Gecenin Web Hedefi Ne Oldu?

Burada ilk gece konuştuğumuz web hedeflerine ayrıca dönmek istiyorum.

Çünkü önceki anlatımımda bunlar hâlâ önümde duran gelecek hedefleriymiş gibi bir izlenim oluşabiliyor.

Aslında durum büyük ölçüde tam tersi.

27 Ağustos gecesi kafamdaki hedeflerden biri şuydu:

“PHP gibi web tarafında kullanılabilecek bir şey olsun. MAMP açmak zorunda kalmayayım. Kendi local server'ını açsın, MySQL'e bağlansın ve içinde HTML, CSS, JavaScript kullanabileyim.”

O gece bunu ileride ulaşılacak büyük aşamalardan biri olarak görüyordum.

Bugün ise AhdCode:

ahdcode init web

ile başlangıç web yapısını oluşturabiliyor.

Üstelik tek bir boş şablon da değil.

Empty.

Basic.

Admin.

MVC.

CRUD.

gibi farklı başlangıç yapıları seçilebiliyor.

AHD tercümesiyle: Boş klasörde tek tek dosya hazırlamak yerine, AhdCode size çalışmaya başlayabileceğiniz web uygulaması iskeletini kuruyor.

Sonrasında:

ahdcode dev app.ahd

ile uygulamayı geliştirme modunda ayağa kaldırabiliyorum.

Bu komut kaynak kodu derliyor, çalıştırıyor ve ilgili dosya grafiğini izliyor.

Kod değiştiğinde tekrar build (AHD tercümesi: kaynak kodu yeniden derleyip çalıştırılabilir hâle getirme) ediyor.

Yeni build başarılıysa çalışan uygulamayı yenisiyle değiştiriyor.

Yeni build bozuksa çalışan son doğru uygulamayı öldürmüyor.

Yani bir syntax hatası yaptığım için tarayıcıdaki çalışan uygulama bir anda tamamen yok olmuyor.

Bir sonraki başarılı save (AHD tercümesi: dosyanın yeniden kaydedilmesi) geldiğinde devam ediyor.

Bu küçük görünen detaylardan biri ama kullanmaya başlayınca çok değerli oluyor.

Yerel geliştirme isimleri bile işin içine girdi.

Örneğin uygulamanın alan adına göre:

ahdakademi.test

gibi bir local identity (AHD tercümesi: yalnızca kendi bilgisayarımda o projeye verdiğim yerel alan adı) oluşturulabiliyor.

İlk izin verildikten sonra AhdCode bu yerel isimleri kendi geliştirme akışı içerisinde yönetebiliyor.

Yani ilk gece hayal ettiğim:

“Kendi dilimin dosyasını yazayım, terminalden çalıştırayım ve tarayıcıdan açayım.”

kısmı artık bir hedef değil.

Çalışan özellik.

Framework Demeye Çekiniyordum, Dokümantasyon Benden Daha Cesur Davrandı

Web tarafını konuşurken bir süre özellikle:

“Framework demeyeyim.”

diye düşündüm.

Çünkü aklımdaki hedef devasa bir Laravel, Django veya benzeri sistem üretmek değildi.

Ben yalnızca AhdCode ile rahat biçimde gerçek server-side (AHD tercümesi: işin esas mantığının tarayıcıda değil sunucuda çalıştığı) web uygulamaları yazabilmek istiyordum.

Fakat proje büyüdükçe:

HTTP.

HTML.

Cookies (AHD tercümesi: tarayıcıda tutulan küçük kimlik veya durum bilgileri).

Server-side sessions (AHD tercümesi: oturum verisini kullanıcıya vermek yerine sunucuda tutma).

Forms (AHD tercümesi: web formlarından gelen veriyi alma ve işleme).

Validation (AHD tercümesi: gelen verinin kurallara uygun olup olmadığını kontrol etme).

CSRF (AHD tercümesi: kullanıcının haberi olmadan onun adına sahte form isteği gönderilmesine karşı koruma).

Flash messages (AHD tercümesi: örneğin “Kayıt başarıyla tamamlandı” gibi bir sonraki sayfada bir kez gösterilip kaybolan mesajlar).

Routes (AHD tercümesi: hangi web adresinin hangi Function tarafından karşılanacağını belirleyen yollar).

Route groups (AHD tercümesi: benzer web yollarını ortak kurallarla gruplama).

Guards (AHD tercümesi: bir isteğin ilgili sayfaya geçmesine izin verilip verilmeyeceğini kontrol eden kapılar).

Layouts (AHD tercümesi: birden fazla sayfanın paylaştığı ortak sayfa iskeletleri).

Components (AHD tercümesi: tekrar kullanılabilen küçük arayüz parçaları).

Static assets (AHD tercümesi: CSS, JavaScript, görsel ve font gibi doğrudan sunulan dosyalar).

Web starters (AHD tercümesi: yeni projeye hazır başlangıç yapısı kuran şablonlar).

gibi parçalar bir araya geldi.

Ve bugün AhdCode dokümantasyonu bu yapıyı açıkça first-party Web framework (AHD tercümesi: dilin yanında hazır gelen, AhdCode'un kendi resmî web çatısı) olarak tanımlıyor.

Burada önemli olan benim için hâlâ büyüklüğü değil.

Web katmanı da AhdCode'un genel felsefesini takip ediyor.

Örneğin sayfalar, layout'lar ve component'ler başka gizemli bir template dilinde (AHD tercümesi: HTML üretmek için ayrıca öğrenilmesi gereken ikinci bir özel sözdiziminde) değil, normal AhdCode Function'ları olarak yazılabiliyor.

HTML katmanı güvenli metin üretimini merkeze alıyor.

Runtime'da ayrıca framework kaynak koduna ihtiyaç bırakmadan native executable üretilebiliyor.

Yani:

“AhdCode kullanıyorum ama aslında gizlice başka bir template dili ve başka bir runtime daha öğreniyorum.”

gibi bir yapı istemedim.

Web tarafının da mümkün olduğunca dilin geri kalanına benzemesini istedim.

Veritabanı: SQLite'tan MySQL'e, Sonra Kendi Aracına

İlk gece açıkça MySQL diyordum.

Ama veritabanı tarafı orada kalmadı.

Önce typed (AHD tercümesi: tip bilgisi taşıyan) SQLite köprüsü geldi.

Ardından gerçek MySQL sunucularına bağlanabilen MySQL desteği geldi.

Sorgular parameter-bound (AHD tercümesi: SQL metniyle kullanıcı verisini birbirine yapıştırmak yerine değerleri güvenli parametreler olarak gönderen) çalışıyor.

Transaction (AHD tercümesi: birden fazla veritabanı işlemini tek bütün hâlinde başarıya ulaştırma veya geri alma) yapısı var.

MySQL kullanan bir AhdCode programının build sırasında internetten driver (AHD tercümesi: programın MySQL ile konuşmasını sağlayan bağlantı kütüphanesi) aramasına ihtiyaç kalmaması için gerekli sürücü de paketle birlikte taşınıyor.

Yani offline build (AHD tercümesi: internet bağlantısı olmadan da programı derleyebilme) hedefi burada da korunuyor.

Sonra bir yerde şu noktaya geldim:

“Madem MySQL ve SQLite var, bunları rahat yönetmek için neden kendi aracımız olmasın?”

Böylece AhdDataStudio ortaya çıktı.

Ve burada benim özellikle sevdiğim bir ayrıntı var:

AhdDataStudio compiler'ın içine gömülmüş gizli bir yönetim ekranı değil.

AhdCode ile yazılmış gerçek bir AhdCode uygulaması.

Yani dil kendi geliştirme aracını kendisiyle üretmeye başladı.

Terminalde:

ahdcode databases

yazınca paketle gelen AhdDataStudio açılabiliyor ve MySQL ile SQLite tarafını yönetebiliyor.

Bir dil projesinin benim için “gerçekleşmeye” başladığını gösteren anlardan biri de bu oldu.

Çünkü artık yalnızca:

“AhdCode ile kullanıcı uygulaması yazılabilir.”

demiyordum.

AhdCode'un kendi ekosistemindeki araçlardan birini de AhdCode ile yazmıştım.

Web'den Veri Almak: HTTP'den Scraping'e

Web tarafı yalnızca browser'a HTML döndürmekle de kalmadı.

Outbound HTTP client geldi.

AHD tercümesiyle: AhdCode yalnızca kendisine gelen web isteklerini cevaplamakla kalmayıp başka web servislerine de istek gönderebilir hâle geldi.

Bu sayede JSON API'lerle (AHD tercümesi: iki yazılımın JSON veri gönderip alarak konuştuğu web servisleriyle) konuşmak mümkün.

Gemini gibi dış servislerin API'lerine de standart HTTP araçları üzerinden istek gönderilebiliyor.

Burada özellikle “Gemini modülü” demiyorum.

AhdCode içerisinde Gemini'ye özel gizli bir AI vendor katmanı (AHD tercümesi: yalnızca belirli bir yapay zekâ sağlayıcısına özel ayrı entegrasyon sistemi) bulunmasına gerek yok.

HTTP varsa, JSON varsa ve servis standart bir API sunuyorsa zaten onunla konuşabilirsiniz.

Sonra HTML parsing (AHD tercümesi: gelen HTML metnini programın anlayıp üzerinde gezebileceği bir belge yapısına dönüştürme) geldi.

Bir HTTP isteğinden dönen HTML metni:

HTML document yapısına dönüştürülebiliyor.

Tag'e (AHD tercümesi: div, a, table gibi HTML etiketine) göre seçim yapılabiliyor.

ID'ye göre seçim yapılabiliyor.

Class'a göre seçim yapılabiliyor.

Attribute'lara (AHD tercümesi: href veya data-* gibi HTML öğesi özelliklerine) göre seçim yapılabiliyor.

Parent-child ve descendant ilişkileri (AHD tercümesi: bir HTML öğesinin doğrudan veya daha derinde hangi öğelerin içinde bulunduğu ilişkiler) üzerinden öğeler bulunabiliyor.

Bunun doğal sonucu da scraping oldu.

AHD tercümesiyle:

Bir web sayfasını al.

HTML'ini çöz.

İstediğin öğeleri seç.

Veriyi çıkar.

İstersen işle.

İstersen SQLite veya MySQL'e yaz.

İstersen başka bir API'ye gönder.

İstersen sonuçtan CSV, Excel, Word, PDF veya grafik üret.

İşte burada standart kütüphanenin ilk günlerde kurduğum zincir mantığı tekrar kendisini göstermeye başladı.

Data tek başına değildi.

CSV tek başına değildi.

Plot tek başına değildi.

HTTP tek başına değildi.

HTML parser tek başına değildi.

MySQL tek başına değildi.

Bir noktadan sonra bu parçaları bir araya getirip gerçek iş akışları kurabilmek mümkün hâle geldi.

Benim için standart kütüphane oluşturmanın asıl değeri de burada.

v1.0.0: Bitti Değil, Tamamlanmış Bir Temeli Var

AhdCode v1.0.0 benim için “proje bitti” anlamına gelmiyor.

Ama artık:

“Daha asıl hedeflerin hiçbirine ulaşmadım.”

anlamına da kesinlikle gelmiyor.

Hatta bugün repository'nin kendi tanımı oldukça net:

Dil, toolchain (AHD tercümesi: compiler, CLI, formatter, LSP, REPL ve geliştirme araçlarının oluşturduğu araç zinciri) ve Web framework tarafı v1.0.0 için belirlenen özellik yüzeyi açısından tamamlanmış durumda.

Bunu ilk gece kafamda bulunan hedeflerle karşılaştırınca durum daha da ilginç görünüyor.

Kendi syntax'ı olan derlenen bir dil istiyordum.

Var.

Go'yu arka tarafta kullanıp kullanıcıya Go yazdırmayan bir yapı istiyordum.

Var.

Native executable üretmesini istiyordum.

Var.

Terminalden rahat çalıştırmak istiyordum.

Var.

Persistent REPL istiyordum.

Var.

Formatter istiyordum.

Var.

Editörün dili gerçekten anlamasını istiyordum.

LSP var.

Üstelik yalnızca autocomplete değil, günlük kullanımda beklediğim temel language tooling yüzeyi tamamlanmış durumda.

VS Code entegrasyonu istiyordum.

Var.

Web projesi için başlangıç yapısını otomatik kurmak istiyordum.

ahdcode init web bunu yapıyor.

Birden fazla starter istiyordum.

Empty, Basic, Admin, MVC ve CRUD seçenekleri var.

Yerelde app.ahd dosyasını çalıştırıp tarayıcıdan açmak istiyordum.

ahdcode dev app.ahd bunu yapıyor.

Üstelik save geldiğinde rebuild/restart döngüsünü de yönetiyor.

MySQL'e bağlanabilsin istiyordum.

Var.

SQLite da var.

Üstelik ikisini yönetmek için AhdCode ile yazılmış AhdDataStudio da var.

HTML, CSS ve JavaScript ile gerçek web uygulamaları yazabilmek istiyordum.

Var.

Server-side session, forms, validation, CSRF ve routing gibi gerçek uygulama ihtiyaçlarını karşılayabilsin istiyordum.

Bunlar da var.

Dışarıdan veri alabilsin istiyordum.

HTTP client var.

Web sayfalarını okuyabilsin istiyordum.

HTML parser ve selector sistemi var.

Scraping yapabilsin istiyordum.

Mevcut HTTP ve HTML araçlarını bir araya getirerek yapılabiliyor.

Dolayısıyla önümdeki mesele artık AhdCode'u:

“Gerçek bir şey yapabilir.”

seviyesine getirmek değil.

O eşik geçildi.

Bundan sonraki işlerin önemli bölümü yeni bir temel yeteneği sıfırdan icat etmekten çok, mevcut yüzeyi daha da olgunlaştırmak üzerine.

Performans geliştirilebilir.

Platform desteği daha da güçlenebilir.

Mevcut API'ler zamanla daha da rafine edilebilir.

Web ergonomisi geliştirilebilir.

Yeni standart modüller eklenebilir.

LSP'nin bugün bilinçli olarak kapsam dışında tuttuğu daha ileri refactoring araçları (AHD tercümesi: programın davranışını değiştirmeden kodun yapısını güvenli biçimde dönüştüren araçlar) ileride düşünülebilir.

Ve elbette büyük eksik araçlardan biri hâlâ debugger tarafı.

LSP ile debugger aynı şey değil.

Bugün AhdCode'un Language Server'ı oldukça kapsamlı olsa da Debug Adapter Protocol (AHD tercümesi: editör ile debugger'ın standart biçimde konuşmasını sağlayan protokol) tabanlı gerçek bir debugger (AHD tercümesi: programı adım adım çalıştırıp değişkenleri izleyerek hata ayıklamaya yarayan araç) henüz sistemin parçası değil.

Yani hâlâ yapılacak şey var.

Fakat artık yapılacaklar listesinin karakteri değişti.

İlk gün:

“Bunu mümkün hâle getirebilir miyiz?”

sorusu baskındı.

Bugün:

“Mümkün hâle getirdiğimiz bu şeyi nasıl daha düzgün, daha tutarlı ve daha rahat kullanılabilir yaparız?”

sorusu daha önemli.

Başlangıçta sınırları genişletmeye çalışıyordum.

Şimdi o sınırların içinde nasıl daha düzenli yaşayacağımızı düşünüyorum.

Bence sürüm numarasından daha önemli olan değişim de tam olarak bu.

v1.0.0'ın Asıl Değeri: Bir Referans Noktası

Yazılım dünyasında 1.0.0 garip bir psikolojik sınır.

Sanki:

0.x.x = hâlâ deniyoruz
1.0.0 = tamamdır, bitti

gibi düşünülebiliyor.

Ben AhdCode'a böyle bakmıyorum.

Benim için v1.0.0:

“Artık ne yaptığımızı biliyoruz.”

demek.

Hatta ilk on günün sonunda buna bir cümle daha ekleyebilirim:

“Başta yapmak istediğimiz şeylerin önemli bir kısmını da artık gerçekten yapabiliyoruz.”

Bu, bundan sonra hiçbir şey değişmeyecek demek değil.

Daha çok, değişiklikleri hangi temel üzerine yapacağımızın artık daha belirgin olması demek.

Dil elbette gelişecek.

Yeni modüller gelebilir.

Mevcut özellikler olgunlaşabilir.

Bazı şeyler sadeleşebilir.

Bazı API'lerin ikinci sürümleri gelebilir.

Muhtemelen bugün çok mantıklı bulduğum bazı API'lere birkaç ay sonra bakıp:

“Bunu hangi akla hizmet böyle yapmışız?”

diyeceğim.

İlk geceki hedeflerle bugünkü sistemi yan yana koyunca ortaya çıkan tablo zaten bunu gösteriyor: AhdCode artık birkaç keyword (anahtar kelime) anlayan deneysel bir parser değil; dili, standart kütüphanesi, araç zinciri, web katmanı ve veri-belge araçları birlikte çalışan bir sistem.

Bunlardan daha önemlisi ise artık özellikleri değerlendirebileceğim bir referans noktası oluşmuş olması.

Yeni bir fikir geldiğinde:

“AhdCode bunu yapabilir mi?”

sorusunun yanında:

“Bu gerçekten AhdCode'a benziyor mu?”

diye de sorabiliyorum.

Ve bence daha da önemlisi:

AhdCode'un artık ne olmaması gerektiği konusunda da daha net bir fikrim var.

Sonuç: On Gün Önce Bir Soruydu, Bugün v1.0.0

27 Ağustos gecesi programlama dili geliştirmenin gerçekten ne kadar ulaşılmaz olduğunu sorguluyordum.

On gün sonra elimde AhdCode v1.0.0 var.

Eğer 27 Ağustos gecesi bana:

“On gün sonra bunun 46 release'i olacak.”

deseler muhtemelen inanmazdım.

“Aynı proje için dört yapay zekâ aboneliği kullanacaksın.”

deseler biraz daha inanabilirdim.

“İki ChatGPT sohbetini neredeyse sadece bu programlama dilini konuşarak dolduracaksın.”

deseler muhtemelen:

“O olabilir.”

derdim.

Ama v1.0.0 gerçekten ilk planımda yoktu.

Daha da ilginci, ilk gece:

“Bir gün yaparsak güzel olur.”

diye konuştuğum şeylerin önemli kısmının on gün sonra çalışan özellikler hâline gelmiş olmasıydı.

Web uygulaması geliştirmekten yerel geliştirme sunucusuna, MySQL ve SQLite'tan editör araçlarına, formatter ve REPL'den dışarıdan veri çekip HTML parse etmeye kadar ilk gecede uzak hedef gibi duran başlıkların önemli kısmı artık çalışan sistemin parçaları.

Bu yüzden temel soru da değişti:

“Yapabilir miyiz?”

sorusundan:

“Nasıl daha iyi yaparız?”

sorusuna dönüşmüş durumda.

Bu süreç bana yapay zekânın kod üretme hızından daha önemli bir şeyi de gösterdi:

Kod üretiminin hızlanması, hangi şeyi yapacağımıza ve onu nasıl yapacağımıza karar verme yükünü ortadan kaldırmıyor.

Bir dilin syntax'tan ibaret olmadığını çok daha iyi gördüm.

Compiler'ların nasıl düşündüğünü öğrendim.

Bir API tasarımında verilen küçük bir kararın onlarca sürüm sonra bile karşınıza çıkabileceğini gördüm.

Bir hata mesajının yalnızca teknik ayrıntı değil, dilin kullanıcıyla kurduğu iletişimin bir parçası olduğunu gördüm.

Bir modülün tek başına güçlü olmasından çok, diğer modüllerle tutarlı davranmasının değerini gördüm.

Compiler ile editör araçlarının aynı gerçek dil analizini paylaşmasının önemini gördüm.

Bir dilin yalnızca kodu çalıştırmasının değil, o kodu yazarken size nasıl bir geliştirme deneyimi sunduğunun da ürünün bir parçası olduğunu gördüm.

Ve yapay zekâyla büyük bir proje geliştirirken yalnızca kod üretim hızının değil, denetimin ve karar verme kalitesinin de ölçeklenmesi gerektiğini öğrendim.

En önemlisi ise ilk geceden beri zihnimde dolaşan:

“Ben olsam nasıl yapardım?”

sorusunun cevabını gerçekten çalışan bir şey üzerinde deneme fırsatı buldum.

İlk AhdCode yazısının sonunda:

“Belki üç kişi kullanır. Belki yalnızca ben kullanırım.”

demiştim.

Bu düşüncem değişmedi.

Bir programlama dilinin benim için değerli olması için milyonlarca kullanıcıya ulaşmasına gerek yok.

Bu on günün sonunda değişen yalnızca AhdCode'un özellik sayısı değildi.

Benim projeye bakışım da değişti.

İlk günlerde her çalışan özellik projenin sınırlarını biraz daha dışarı itiyordu; bugünse aynı ölçüde önemli olan, o sınırların içinde kalan parçaların gerçekten birlikte ve tutarlı çalışması.

AhdCode hâlâ merakla büyüyen bir proje.

Ama artık:

“Çalışan bir programlama dili çıkarabilir miyim?”

deneyinin çok ötesinde.

İlk gece kafamda çizdiğim temel kullanım alanlarının büyük kısmı bugün gerçekten çalışıyor.

Hatta ilk gece konuşmadığım bazı araçlar bile bugün sistemin tamamlanmış parçaları hâline gelmiş durumda.

Bu yüzden bundan sonraki dönem bana biraz farklı geliyor.

Daha fazla özellik eklemek elbette mümkün.

Muhtemelen ekleyeceğim de.

Gece 02:00 değişkenimizin hâlâ true olduğunu unutmayalım.

Ama artık her merakın otomatik olarak yeni bir özellik olmak zorunda olmadığını da öğreniyorum.

Bazen bir sonraki büyük gelişme yeni bir modül eklemek değil, mevcut on modülün birbirleriyle daha düzgün konuşmasını sağlamak olabilir.

Bazen yeni bir syntax eklemek yerine mevcut syntax'ı daha tutarlı hâle getirmek daha değerlidir.

Bazen:

“Bunu da yaptık.”

demek yerine:

“Bunu artık güvenle kullanabiliriz.”

demek daha büyük bir ilerlemedir.

Sanırım ben de AhdCode'la birlikte bunu öğrendim.

Bence v1.0.0 için bundan daha uygun bir nokta olamazdı.

Şimdilik AhdCode'un hikâyesinin ikinci bölümünü de burada kapatayım.

Eylül ayının ilk yazısında yine birlikteydik. Bir sonraki yazının konusu ne olur, açıkçası ben de bilmiyorum. Son on güne bakınca önceden konu tahmininde bulunmamın çok güvenilir olmadığı zaten ortada.

Ama en kötü ihtimalle 27 Eylül'de buradayım.

Çünkü gelenek bozulmazsa yeni yaşıma, yani 28'ime yazdığım mektupla yine burada olacağım.

O zamana kadar AhdCode v1.0.0'ın gerçekten v1.0.0 olarak kalıp kalmayacağı konusunda ise herhangi bir garanti veremiyorum.

İlk yazının sonunda biraz daha yavaş ilerleyeceğimi söyleyip ardından on günde 46 release çıkardığım düşünüldüğünde, bu konuda vereceğim sözlerin hukuki bağlayıcılığı da pek yüksek olmayacaktır.

Bir sonraki yazıya kadar hoşça kalın.


Ek: “Peki Go ile Tam Olarak Ne Yaptın?”

Yazının burasına kadar gelip hâlâ “AhdCode Go'yu kullanıyor ama bu tam olarak ne demek?” diye merak edenler için çok küçük ve temsili bir örnek bırakayım.

AhdCode'da şöyle bir kod yazdığımızı düşünelim:

number: Int := 9
if number % 3 == 0 {
    write("Evet")
} else {
    write("Hayır")
}

İnsan gözüyle burada olan şey oldukça basit:

Bir sayı tanımlıyoruz. Sayı 3'e tam bölünüyorsa Evet, bölünmüyorsa Hayır yazıyoruz.

Compiler ise bunu doğrudan bizim gibi okumuyor.

İlk olarak Lexer, kaynak kodu küçük anlamlı parçalara ayırıyor. AHD tercümesiyle kabaca şöyle:

number   → isim
:        → tür geliyor
Int      → tam sayı türü
:=       → ilk değer ataması
9        → sayı
if       → koşul başlıyor
number   → değişken
%        → bölümden kalan
3        → sayı
==       → eşit mi?
0        → sayı
write    → çıktı ver

Ardından Parser bu parçaların birbirleriyle ilişkisini çözüyor.

Yani yalnızca “burada if gördüm” demiyor; kabaca:

Bir Int değişkeni tanımla.
Sonra:
    number % 3 == 0
koşulunu kontrol et.
Doğruysa:
    write("Evet")
Değilse:
    write("Hayır")

şeklinde programın yapısını çıkarıyor.

Semantic kontroller de araya girip örneğin number gerçekten sayı mı, % işlemi burada kullanılabilir mi, koşul gerçekten doğru/yanlış değeri üretiyor mu gibi soruları kontrol ediyor.

Bu aşama önemli; çünkü kodun yalnızca gramer olarak doğru görünmesi yetmiyor. Yazdığı şeyin dilin kuralları içinde anlamlı olması da gerekiyor.

Bütün bunlar geçildikten sonra AhdCode'un Go backend'i bu yapıyı temsili olarak şuna benzeyen Go koduna dönüştürüyor:

number := 9
if number%3 == 0 {
    fmt.Println("Evet")
} else {
    fmt.Println("Hayır")
}

Son aşamada ise Go'nun kendi derleyicisi devreye giriyor ve bu kodu işletim sisteminin doğrudan çalıştırabileceği programa çeviriyor.

Yani en kısa AHD tercümesiyle:

AhdCode
   ↓
Lexer: "Burada hangi parçalar var?"
   ↓
Parser: "Bu parçalar ne anlatıyor?"
   ↓
Semantic Analysis: "Anlattığı şey mantıklı mı?"
   ↓
Go Backend: "Bunu Go ile nasıl ifade ederim?"
   ↓
go build
   ↓
Çalıştırılabilir program

Burada önemli olan nokta şu:

Kullanıcı Go yazmıyor.

Kullanıcı AhdCode yazıyor.

Lexer, Parser, tip sistemi ve semantic kurallar AhdCode'a ait.

Language Server da aynı gerçek compiler frontend'ini (AHD tercümesi: kodu okuyup anlamlandıran lexer, parser ve semantic analiz tarafını) kullanıyor.

Formatter da AhdCode syntax'ını ve AST'sini biliyor.

REPL de aynı dil kurallarıyla çalışıyor.

Go ise bütün bu kararların ardından ortaya çıkan yapının bilgisayarda çalıştırılabilir hâle gelmesinde güçlü bir arka plan sağlıyor.

Benim Go ile yaptığım şey kabaca buydu:

AhdCode'un karakterini ve kurallarını Go'ya teslim etmek değil, AhdCode'un ne söylediğini Go'nun çalıştırabileceği bir biçime çevirmek.

Go motoru çalıştırıyor; direksiyonda hâlâ AhdCode oturuyor.