Ali Gündoğdu

maker

Production Masaüstü Ürünü İçin En Mantıklı Seçim Hala Wails, İşte Tabloların Yazmadığı İncelikleri

1 Ağustos 2026 · 8 dk okuma

Production Masaüstü Ürünü İçin En Mantıklı Seçim Hala Wails, İşte Tabloların Yazmadığı İncelikleri

Karşılaştırma Tablosu En Kolay Kısımdı

Wails’e neden geçtiğimi ayrı bir yazıda anlatmıştım. Electron ağır geldi, Tauri’nin Rust tarafı beni yordu, Wails ise Go’nun sadeliğiyle tam aradığım denge oldu. O yazının sonunda bir tablo var: dosya boyutu 20 MB, öğrenme eğrisi orta, build süreci sorunsuz. Hepsi doğru. Ama bugün dönüp baksam, o tablo aslında işin en kolay kısmıydı.

Çünkü bir aracı seçmek başka, onunla gerçek bir ürün göndermek başka. Seodisias’ı Wails ile yazdım ve o süreç bana şunu öğretti: internetteki her “Electron vs Tauri vs Wails” yazısı ilk beş dakikayı anlatıyor. wails init, wails dev, ekranda bir pencere. O beş dakika büyülü, evet. Ama o pencereyi başka birinin bilgisayarında sorunsuz açtırmak altı ay sürdü. Bu yazı o altı ayın notları. Tabloda görünmeyen kısım.

Baştan da söyleyeyim: bu bir vazgeçirme yazısı değil, tam tersi. Wails’le production’a çıktım, ürünüm her gün üç işletim sisteminde çalışıyor ve bugün baştan başlasam yine Wails derdim. Production için masaüstü ürün geliştirecek birine gönül rahatlığıyla öneriyorum. Aşağıdakiler pişmanlık listesi değil; o karara giderken kimsenin bana anlatmadığı, öğrenince işin keyfine dönüşen incelikler.

Köprü Demoda Temiz, Yükte Çöküyor

Wails’in en çok pazarlanan özelliği Go ile frontend arasındaki köprü. Go’da bir fonksiyon yazıyorsun, JavaScript’ten sanki yerel bir fonksiyonmuş gibi çağırıyorsun. Demoda büyüleyici. GetUser() yaz, arayüzden çağır, kullanıcı gelsin. Beş satır.

Sorun şu ki gerçek uygulamalar GetUser çağırmıyor. Seodisias bir crawler; tek bir taramada binlerce satır veri üretiyor. Ben de acemi refleksiyle ne yaptım: taramayı Go’da bitir, sonucun tamamını tek seferde arayüze döndür. Köprü zaten bunun için var, değil mi?

Değil. O binlerce satırı köprüden geçirmek demek, hepsini JSON’a serialize etmek, webview’e taşımak, orada tekrar parse etmek demek. Birkaç yüz satırda fark etmiyorsun. Birkaç bin satırda uygulama donuyor. Kullanıcı “çöktü mü acaba” diye pencereyi kapatmaya hazırlanıyor.

Dersin özü basit ama görmesi zaman aldı: köprü bir veri hattı değil, bir kontrol hattı. Ona “şu işi başlat”, “şunu iptal et”, “durum ne” dedirteceksin; içinden kamyon kamyon veri geçirmeyeceksin. Çözüm iki taraflı oldu. Go tarafında tarama artık sonucu biriktirip toptan dönmüyor; ilerledikçe runtime.EventsEmit ile arayüze olay yayıyor. Frontend bu olayları dinliyor, veriyi parça parça alıyor. Ekranda da her şeyi bir anda basmak yerine sanal kaydırma var; sadece görünen satırlar render ediliyor, gerisi bellekte bekliyor. Aynı problemi Seodisias’ın hikayesinde kısaca anmıştım; işte teknik karşılığı bu.

Her Şey Asenkron, Ve Bunu Kabul Etmelisin

Köprüdeki ikinci incelik daha sinsi. Go’da yazdığın bound fonksiyon, JavaScript tarafında senkron görünse de aslında bir Promise dönüyor. Yani await etmen gerekiyor, etmezsen elinde bir veri değil, bir söz kalıyor.

Bu kulağa küçük geliyor ama mimariyi baştan etkiliyor. Uzun süren bir işi, mesela yarım dakikalık bir taramayı düşün. Onu await edip beklersen arayüz o süre boyunca hiçbir şey söyleyemez. Kullanıcıya bir ilerleme çubuğu, bir “342 sayfa tarandı” sayacı göstermek istiyorsan, işi başlatan çağrı ile ilerlemeyi bildiren kanalı ayırmak zorundasın. Ben burada da olaylara döndüm: taramayı başlatan fonksiyon hemen dönüyor, ilerleme ayrı bir olay akışından geliyor.

Bir de iptal meselesi var ki bunu hiçbir başlangıç rehberi anlatmıyor. Kullanıcı bir taramayı başlattı, yarısında vazgeçti. O goroutine hala çalışıyor, hala istek atıyor. Onu nasıl durduracaksın? Cevap Go’nun kendi içinde: context.Context. Uygulama açılışında gelen context’i taramaya taşıyorsun, iptal düğmesi bu context’i cancel ediyor, çalışan goroutine bunu görüp temiz kapanıyor. Wails sana bu context’i veriyor, ama onunla ne yapacağın sana kalmış. Kimse söylemiyor, sonradan öğreniyorsun.

Wails “Chrome Gömmüyor” Diyor, Bu İyi Haber Değil Sadece

Electron’un 150 MB’ı nereden geliyor? İçine bütün bir Chromium gömdüğü için. Wails bunu yapmıyor, işletim sisteminin kendi webview’ini kullanıyor. Boyut avantajının kaynağı bu. Herkes bunu bir zafer olarak yazıyor.

Yazmayan kısım şu: bu, uygulamanın her işletim sisteminde farklı bir tarayıcıyla çalıştığı anlamına geliyor. Windows’ta WebView2, yani Edge motoru. macOS’ta WebKit, yani Safari’nin motoru. Linux’ta WebKitGTK. Üçü de aynı HTML’i aynı gösterir sanıyorsun; göstermiyor.

Ben bunu en beklemediğim yerde yedim: fontlar. macOS’ta tertemiz duran arayüz, Windows’ta bir tık farklı hizalanıyordu; bir yerde satır kayıyor, bir yerde ikon metne yapışıyordu. Tarih seçici, kaydırma davranışı, bazı CSS özelliklerinin desteği webview’den webview’e değişiyor. “Bende çalışıyordu ama Windows’ta açılmadı” cümlesinin Electron’la öldüğünü sanıyordum. Ölmedi, sadece kılık değiştirdi: artık backend’de değil, CSS’te ve webview farklarında yaşıyor.

Buradan çıkardığım kural: geliştirmeyi tek işletim sisteminde yapıp “nasılsa hepsinde aynıdır” dememek. Ben Mac’te geliştiriyordum ama Windows’ta düzenli test etmeden hiçbir arayüzü bitmiş saymadım. Bu, Wails’in gizli vergisi. Boyuttan kazandığını test yükünde bir miktar geri ödüyorsun.

Asıl Ölümcül Vadi: İmza

Şimdiye kadar anlattıklarım kod problemleri. Çözülüyor, keyifli bile. Ama üretimle prototip arasındaki o ölümcül vadiyi burada bir kez daha geçtim ve beni en çok yıpratan kısım kod değildi.

Uygulamayı derledim, çalışıyor, güzel. Bir arkadaşıma “şunu indir bir dene” dedim. macOS uygulamayı açmayı reddetti: “hasarlı, çöp kutusuna taşımak ister misiniz.” Hasarlı falan değildi. İmzasızdı. Gatekeeper imzasız ve notarize edilmemiş her uygulamaya bu muameleyi yapıyor. Kullanıcının uygulamayı açması için terminalden komut girmesi ya da ayarlarla boğuşması gerekiyor. Kimse bunu yapmaz. Ben yapmazdım.

Bu vadinin adımlarını saymak kolay, geçmek değil. macOS tarafında bir Apple Developer hesabı, bir Developer ID sertifikası, uygulamayı imzalamak, sonra Apple’ın sunucusuna gönderip notarize ettirmek. Windows tarafında ayrı bir hikaye: imzalamazsan SmartScreen kullanıcıya “bilinmeyen yayıncı, bu uygulama bilgisayarınıza zarar verebilir” diye kırmızı bir ekran gösteriyor. Onu geçmek için bir code signing sertifikası, ve o sertifikanın maliyeti ve kurulum derdi. Üstüne Windows’ta WebView2 çalışma zamanının kullanıcıda kurulu olmasını garantilemek gibi ayrı bir başlık.

Bunların hiçbiri Wails’in suçu değil, işletim sistemlerinin güvenlik politikası. Ama Wails yazıları bundan hiç bahsetmiyor. “20 MB build, tek komut” diyorlar, o 20 MB’lık dosyanın kullanıcının makinesinde açılabilmesi için haftalarca uğraşacağını yazmıyorlar. Dürüst olayım: Seodisias’ın altı ayının belki iki ayı kodla, geri kalanı bu tür “gönderilebilirlik” işleriyle geçti. Kodun bittiği yer, ürünün bittiği yer değil.

Build Tek Komut, ve Üç Platformu Tek Mac’ten Çıkarıyorum

wails build gerçekten tek komut, doğru. Ve burada Wails’in hakkını teslim etmek gerekiyor: bugün üç platformun build’ini de tek makineden, Mac’imden çıkarıyorum. Windows build’ini doğrudan Mac’ten cross-compile ile alıyorum; Go’nun cross-compile rahatlığı Wails’te büyük oranda korunmuş. Linux tarafı biraz daha nazlı, çünkü işin içine WebKitGTK gibi sistem bağımlılıkları giriyor; onu da Docker’la çözdüm: Linux imajında build alan bir konteyner, o da tek komut. Yani “her platform için ayrı makine parkı kur” derdi yok; bir Mac ve bir Docker, üç işletim sistemi.

Asıl vakit yiyen kısım build değil, az önce anlattığım imza zinciri; o platform başına ayrı yürüyor. Benim buradan çıkardığım somut tavsiye şu: release ritüelini ilk fırsatta scriptleştir. Ben build, paketleme ve imza adımlarını tek bir akışa bağladım; “yeni sürüm çıkarayım” düşüncesi bir öğleden sonra projesi olmaktan çıkıp on dakikalık bir ritüele döndü. Elle yaptığın her sürüm, seni bir sonraki sürümü çıkarmaktan soğutur; scriptleşen sürüm ise çıkarma isteği uyandırır.

Go Tarafı: Wails Değil, Disiplin

Bir de Wails’in doğrudan sorumlu olmadığı ama masaüstünde canını yakan bir alan var: eş zamanlılık. Crawler yüzlerce isteği paralel yönetiyor. Go’nun goroutine modeli bu iş için biçilmiş kaftan, ama biçilmiş kaftan da ölçü ister. İlk denememde beş yüz goroutine aynı anda salıverdim; karşı sunucu rate limit’e takıldı, bağlantılar koptu, yarım kalan işler bellekte birikti.

Çözüm masaüstüne özel değil, ama masaüstünde daha görünür: aynı anda kaç iş çalışacağını sınırlayan bir semaphore, bir worker havuzu, ve uygulama kapanırken çalışan her şeyin temiz durması. Sunucuda bir goroutine sızıntısı fark edilmeden aylarca yaşayabilir; masaüstünde kullanıcı uygulamayı kapattığında pencere kapanıp arka planda işlemcinin dönmeye devam etmesi anında şikayet konusu olur. Masaüstü seni disipline zorluyor, çünkü kullanıcının makinesi senin izlediğin bir sunucu değil.

Yine Wails Der miydim

Bütün bu dertleşmeden sonra soru şu: baştan başlasam yine Wails mi seçerdim? Evet. Tereddütsüz. Hatta bir adım öteye gideyim: bugün production için bir masaüstü ürünü geliştirecek olsam, en mantıklı seçim hala Wails.

Çünkü anlattığım dertlerin çoğu Wails’e özel değil; masaüstü uygulaması göndermenin doğasında var. İmza, notarize, webview farkları, dağıtım; bunları Electron’la da Tauri’yle de yaşardım, üstelik çoğunu daha ağır yaşardım. Wails’in bana verdiği şey, backend’i Go’nun sadeliğiyle yazabilmek, Rust’ın öğrenme eğrisine takılmadan iş görebilmek ve sonunda kullanıcıya şaka gibi küçük bir uygulama teslim edebilmekti: Seodisias’ın bugünkü production build’i 8 MB. Vaktiyle tabloya 20 MB yazmıştım; gerçek, kendi tahminimden bile derli toplu çıktı. Electron dünyasından gelen biri için bu rakam bir yazım hatası gibi görünüyor, değil. O söz tutuldu, ürün bugün production’da her gün çalışarak tutmaya devam ediyor.

Ama artık o parlak karşılaştırma tablolarına başka gözle bakıyorum. “Dosya boyutu” satırı tahminimden bile iyi çıktı, bugünkü build 8 MB; ve o satır yine de tablonun en önemsiz satırı. Asıl satırlar tabloda yok: köprüden veri değil kontrol geçir, her webview’i ayrı test et, imza için hafta ayır, dağıtımı ilk günden otomatikleştir. Bir aracın gerçek maliyeti kurulum ekranında değil, onu başkasının bilgisayarında sorunsuz açtırdığın gün ortaya çıkıyor.

Yunus’un dediği gibi, “az söz erin yüküdür.” Ben de sözü uzatmayayım: Wails’i seç, ama beş dakikalık demoya değil, gönderme işinin kendisine hazırlan. Tablo seni içeri alır; seni ayakta tutan, tablonun yazmadığı incelikler olur.

Ve bu yolda takıldığın bir yer olursa bana yaz. Köprüde donan tablodan Gatekeeper’ın “hasarlı” mesajına kadar bu çukurların hepsine düştüm, hepsinden bir notla çıktım; o notları paylaşmayı seviyorum.