İçerikler

Go ile WebAssembly Uygulamaları Geliştirme: Kapsamlı Rehber

İçerikler

Go ile WebAssembly Uygulamaları Geliştirme: Kapsamlı Rehber

WebAssembly (WASM), tarayıcılarda native’e yakın hızda yüksek performanslı kod çalıştırmaya olanak tanıyarak web geliştirmeyi devrim niteliğinde değiştirdi. Go, mükemmel araçları ve sade sözdizimi ile WASM uygulamaları geliştirmek için ideal bir dildir. Bu kapsamlı rehberde, Go kullanarak WebAssembly uygulamalarını nasıl oluşturacağımızı, optimize edeceğimizi ve dağıtacağımızı keşfedeceğiz.

TL;DR

  • WebAssembly: Tarayıcılar için binary instruction formatı, native’e yakın performans sağlar
  • Go + WASM: Go kodunu tarayıcıda çalıştırmak için WASM’a derle
  • Temel Avantajlar: Performans, kod yeniden kullanımı, tip güvenliği ve modern araçlar
  • Kullanım Senaryoları: Görüntü işleme, oyunlar, veri görselleştirme, kriptografi ve daha fazlası
  • Production Ready: Optimizasyon teknikleri ile tam örnekler

1. WebAssembly Nedir?

WebAssembly (WASM), yüksek seviyeli diller için taşınabilir bir derleme hedefi olarak tasarlanmış binary instruction formatıdır. Go, Rust, C++ ve diğer dillerde yazılmış kodların web tarayıcılarında native’e yakın performansta çalışmasını sağlar.

1.1 Neden WebAssembly?

Geleneksel web uygulamaları JavaScript’e dayanır, ancak JavaScript, güçlü olmasına rağmen, hesaplama yoğun görevler için performans sınırlamalarına sahiptir. WebAssembly bunu şu şekilde ele alır:

  • Native’e yakın performans: Native kod hızlarına yakın çalışır
  • Dil bağımsız: Tercih ettiğiniz dilde yazın (Go, Rust, C++, vb.)
  • Güvenlik: Sandbox ortamında çalışır
  • Taşınabilirlik: Farklı platformlar ve tarayıcılarda çalışır
  • Küçük binary boyutu: Verimli kod temsili

1.2 WebAssembly vs JavaScript

WebAssembly ne zaman kullanılmalı:

  • CPU yoğun hesaplamalar (görüntü işleme, kriptografi, veri analizi)
  • Oyunlar ve grafik renderlama
  • Gerçek zamanlı ses/video işleme
  • Bilimsel hesaplama ve simülasyonlar
  • Mevcut Go uygulamalarından kod yeniden kullanımı

JavaScript ne zaman yeterli:

  • Basit DOM manipülasyonu
  • API çağrıları ve veri çekme
  • UI etkileşimleri
  • Hafif hesaplamalar

2. Go ve WebAssembly: Mükemmel Uyum

Go, Go 1.11’den beri WebAssembly derlemesi için mükemmel destek sunar. Go ekibi, Go kodunu WASM’a derlemeyi ve JavaScript ile etkileşime girmeyi oldukça basit hale getirmiştir.

2.1 Go WASM Mimarisi

2.2 Go WASM’in Temel Özellikleri

  • Basit derleme: Sadece GOOS=js GOARCH=wasm ayarlayın
  • JavaScript interop: Go ve JavaScript arasında kolay iletişim
  • Goroutines: Eşzamanlılık desteği (tarayıcı bağlamında sınırlı olsa da)
  • Standard library: Go standard library’nin çoğu WASM’da çalışır
  • Tip güvenliği: Derleme zamanı tip kontrolü

2.3 Tarayıcı Uyumluluğu

Tarayıcı Versiyon WASM Desteği Notlar
Chrome 57+ ✅ Tam En iyi performans
Firefox 52+ ✅ Tam Mükemmel debug araçları
Safari 11+ ✅ Tam İyi performans
Edge 16+ ✅ Tam Chromium tabanlı
Opera 44+ ✅ Tam Chromium tabanlı
IE 11 - ❌ Hayır Desteklenmiyor

Mobil Tarayıcı Desteği:

  • iOS Safari: iOS 11+
  • Chrome Android: 57+
  • Samsung Internet: 7.2+

2.4 Bundle Boyutu Karşılaştırması

Derleyici Tipik Boyut Kullanım Senaryosu
Standard Go 2-3 MB Tam standard library, büyük uygulamalar
TinyGo 100-500 KB Embedded, IoT, boyut kritik uygulamalar
Rust 50-200 KB Maksimum performans, minimal runtime
C/C++ 50-300 KB Legacy kod, performans kritik

Not: Gerçek boyutlar kod karmaşıklığına ve bağımlılıklara göre değişir.


3. İlk Go WASM Projenizi Kurma

Go ile basit bir “Hello World” WebAssembly uygulaması oluşturalım.

3.1 Proje Yapısı

1
2
3
4
5
go-wasm-example/
├── main.go
├── wasm_exec.js
├── index.html
└── go.mod

3.2 Temel Örnek: Hello World

main.go:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package main

import (
	"fmt"
	"syscall/js"
)

func main() {
	// Programın çalışmaya devam etmesi için bir channel oluştur
	c := make(chan struct{}, 0)

	// JavaScript'ten çağrılacak bir fonksiyon kaydet
	js.Global().Set("greet", js.FuncOf(greet))

	fmt.Println("Go WebAssembly initialized")
	
	// Programı canlı tut
	<-c
}

// greet, JavaScript'ten çağrılabilen bir fonksiyondur
func greet(this js.Value, args []js.Value) interface{} {
	name := "World"
	if len(args) > 0 {
		name = args[0].String()
	}
	
	message := fmt.Sprintf("Hello, %s! From Go WebAssembly", name)
	js.Global().Get("console").Call("log", message)
	
	return message
}

3.3 WebAssembly’ye Derleme

1
2
3
4
5
6
7
8
9
# Hedef işletim sistemi ve mimariyi ayarla
export GOOS=js
export GOARCH=wasm

# WASM binary'sini derle
go build -o main.wasm main.go

# JavaScript destek dosyasını kopyala
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .

3.4 HTML Loader

index.html:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Go WebAssembly Example</title>
</head>
<body>
    <h1>Go WebAssembly Demo</h1>
    <button onclick="testGreet()">Click Me!</button>
    <div id="output"></div>

    <script src="wasm_exec.js"></script>
    <script>
        const go = new Go();
        WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject)
            .then(result => {
                go.run(result.instance);
            });

        function testGreet() {
            const message = greet("Developer");
            document.getElementById("output").innerHTML = message;
        }
    </script>
</body>
</html>

3.5 Uygulamayı Çalıştırma

1
2
3
4
5
6
# Dosyaları basit bir HTTP sunucusu ile servis et
# Python 3
python3 -m http.server 8080

# Veya Node.js kullanarak
npx serve .

Tarayıcınızda http://localhost:8080 adresini açarak uygulamanın çalıştığını görebilirsiniz!


4. Gelişmiş Go WASM Desenleri

4.1 Go’dan DOM Manipülasyonu

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import (
	"syscall/js"
)

func main() {
	c := make(chan struct{}, 0)

	// Bir buton elementi oluştur
	document := js.Global().Get("document")
	body := document.Get("body")

	button := document.Call("createElement", "button")
	button.Set("innerHTML", "Click Me!")
	button.Set("onclick", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		alert := js.Global().Get("alert")
		alert.Invoke("Button clicked from Go!")
		return nil
	}))

	body.Call("appendChild", button)

	<-c
}

4.2 Go’dan JavaScript Fonksiyonlarını Çağırma

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
	"syscall/js"
)

func main() {
	c := make(chan struct{}, 0)

	// JavaScript'in Math.random() fonksiyonunu çağır
	math := js.Global().Get("Math")
	random := math.Get("random")
	result := random.Invoke()

	js.Global().Get("console").Call("log", "Random number:", result.Float())

	// Özel bir JavaScript fonksiyonunu çağır
	js.Global().Call("myJavaScriptFunction", "Hello from Go!")

	<-c
}

4.3 Karmaşık Veri Yapılarını Geçirme

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main

import (
	"encoding/json"
	"syscall/js"
)

type User struct {
	Name  string `json:"name"`
	Email string `json:"email"`
	Age   int    `json:"age"`
}

func main() {
	c := make(chan struct{}, 0)

	js.Global().Set("createUser", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		user := User{
			Name:  args[0].String(),
			Email: args[1].String(),
			Age:   args[2].Int(),
		}

		jsonData, _ := json.Marshal(user)
		js.Global().Get("console").Call("log", string(jsonData))

		return string(jsonData)
	}))

	<-c
}

4.4 Async İşlemler için Channel Kullanımı

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main

import (
	"syscall/js"
	"time"
)

func main() {
	c := make(chan struct{}, 0)

	js.Global().Set("asyncOperation", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		// Promise benzeri bir yapı oluştur
		handler := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
			resolve := args[0]

			// Async işi simüle et
			go func() {
				time.Sleep(2 * time.Second)
				resolve.Invoke("Operation completed!")
			}()

			return nil
		})

		promiseConstructor := js.Global().Get("Promise")
		return promiseConstructor.New(handler)
	}))

	<-c
}

4.5 Gerçek Multi-Threading için Web Workers

⚠️ Gelişmiş / Deneysel: WASM ile Web Workers, dikkatli uygulama gerektiren gelişmiş bir desendir. Bu yaklaşım, birden fazla WASM instance’ı, karmaşık mesaj geçirme ve potansiyel senkronizasyon sorunlarını içerir. Production’da kullanmadan önce kapsamlı test edin. Tarayıcı desteği ve davranışı değişebilir.

Go’nun goroutine’leri WASM’da tek thread üzerinde çalışırken, paralel çalıştırma için Web Workers kullanabilirsiniz:

worker.go:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
	"syscall/js"
)

func main() {
	c := make(chan struct{}, 0)

	// Ana thread'den çağrılacak fonksiyonu kaydet
	js.Global().Set("processInWorker", js.FuncOf(processInWorker))

	<-c
}

func processInWorker(this js.Value, args []js.Value) interface{} {
	data := args[0].String()
	
	// Ağır hesaplama
	result := performHeavyComputation(data)
	
	return result
}

func performHeavyComputation(data string) string {
	// CPU yoğun işiniz burada
	return "Processed: " + data
}

main.html:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<script>
    // Bir Web Worker oluştur
    const worker = new Worker('worker.wasm.js');
    
    worker.onmessage = function(e) {
        console.log('Result:', e.data);
    };
    
    // Worker'a veri gönder
    worker.postMessage({ type: 'process', data: 'large dataset' });
</script>

4.6 Paylaşılan Bellek için SharedArrayBuffer

⚠️ Gelişmiş / Deneysel: Unsafe pointer manipülasyonu ile SharedArrayBuffer, gelişmiş ve potansiyel olarak tehlikeli bir desendir. Bu şunları gerektirir:

  • Özel tarayıcı güvenlik başlıkları (COOP/COEP)
  • Crash’leri önlemek için dikkatli bellek yönetimi
  • WASM bellek modelinin derinlemesine anlaşılması
  • Tarayıcılar arası kapsamlı test

Kapsamlı test ve uzmanlık olmadan production için önerilmez.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package main

import (
	"syscall/js"
	"unsafe"
)

func main() {
	c := make(chan struct{}, 0)

	js.Global().Set("useSharedMemory", js.FuncOf(useSharedMemory))

	<-c
}

func useSharedMemory(this js.Value, args []js.Value) interface{} {
	// JavaScript'ten SharedArrayBuffer al
	sab := args[0]
	
	// Altta yatan belleğe eriş
	// Not: Bu, uygun tarayıcı güvenlik başlıkları gerektirir
	// (Cross-Origin-Opener-Policy, Cross-Origin-Embedder-Policy)
	
	// Go slice'ına dönüştür (gelişmiş kullanım)
	length := sab.Get("byteLength").Int()
	ptr := unsafe.Pointer(uintptr(sab.Get("__go_mem").Int()))
	
	data := (*[1 << 28]byte)(ptr)[:length:length]
	
	// Paylaşılan belleği işle
	for i := range data {
		data[i] = data[i] * 2
	}
	
	return sab
}

Gerekli Güvenlik Başlıkları:

1
2
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

4.7 Streaming Derleme

1
2
3
4
5
6
7
// Daha hızlı başlangıç için WASM derlemesini stream et
async function loadWASM() {
    const response = await fetch('main.wasm');
    const wasmModule = await WebAssembly.compileStreaming(response);
    const instance = await WebAssembly.instantiate(wasmModule, go.importObject);
    go.run(instance);
}

4.8 Modül Önbellekleme Stratejileri

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// Derlenmiş WASM modüllerini önbelleğe al
const wasmCache = new Map();

async function loadCachedWASM(url) {
    if (wasmCache.has(url)) {
        return wasmCache.get(url);
    }
    
    const module = await WebAssembly.compileStreaming(fetch(url));
    wasmCache.set(url, module);
    return module;
}

5. Gerçek Dünya Örneği: Görüntü İşleme

Pratik bir örnek oluşturalım: tarayıcıda görüntülere filtre uygulayan bir görüntü işleme uygulaması.

5.1 Go’da Görüntü İşleme

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package main

import (
	"image"
	"image/color"
	"syscall/js"
)

func main() {
	c := make(chan struct{}, 0)

	js.Global().Set("applyGrayscale", js.FuncOf(applyGrayscale))
	js.Global().Set("applyBlur", js.FuncOf(applyBlur))

	<-c
}

func applyGrayscale(this js.Value, args []js.Value) interface{} {
	// JavaScript'ten görüntü verisini al
	imageData := args[0]
	data := imageData.Get("data")
	width := imageData.Get("width").Int()
	height := imageData.Get("height").Int()

	// Gri tonlamaya dönüştür
	length := data.Length()
	for i := 0; i < length; i += 4 {
		r := data.Index(i).Int()
		g := data.Index(i + 1).Int()
		b := data.Index(i + 2).Int()

		// Gri tonlama formülü
		gray := uint8(0.299*float64(r) + 0.587*float64(g) + 0.114*float64(b))

		data.SetIndex(i, gray)
		data.SetIndex(i+1, gray)
		data.SetIndex(i+2, gray)
		// Alpha kanalı (i+3) değişmeden kalır
	}

	return imageData
}

func applyBlur(this js.Value, args []js.Value) interface{} {
	imageData := args[0]
	data := imageData.Get("data")
	width := imageData.Get("width").Int()
	height := imageData.Get("height").Int()

	// Basit box blur (3x3 kernel)
	radius := 1 // Blur yarıçapı
	result := make([]uint8, data.Length())
	
	for y := 0; y < height; y++ {
		for x := 0; x < width; x++ {
			var r, g, b, a, count uint32
			
			// Çevredeki pikselleri örnekle
			for dy := -radius; dy <= radius; dy++ {
				for dx := -radius; dx <= radius; dx++ {
					nx := x + dx
					ny := y + dy
					
					// Sınır kontrolü
					if nx >= 0 && nx < width && ny >= 0 && ny < height {
						idx := (ny*width + nx) * 4
						r += uint32(data.Index(idx).Int())
						g += uint32(data.Index(idx + 1).Int())
						b += uint32(data.Index(idx + 2).Int())
						a += uint32(data.Index(idx + 3).Int())
						count++
					}
				}
			}
			
			// Değerlerin ortalamasını al
			idx := (y*width + x) * 4
			result[idx] = uint8(r / count)
			result[idx+1] = uint8(g / count)
			result[idx+2] = uint8(b / count)
			result[idx+3] = uint8(a / count)
		}
	}
	
	// Sonucu imageData'ya geri kopyala
	for i := 0; i < len(result); i++ {
		data.SetIndex(i, result[i])
	}
	
	return imageData
}

5.2 JavaScript Entegrasyonu

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<!DOCTYPE html>
<html>
<head>
    <title>Go WASM ile Görüntü İşleme</title>
</head>
<body>
    <input type="file" id="imageInput" accept="image/*">
    <canvas id="canvas"></canvas>
    <button onclick="processGrayscale()">Gri Tonlama</button>
    <button onclick="processBlur()">Blur</button>

    <script src="wasm_exec.js"></script>
    <script>
        const go = new Go();
        let imageData = null;

        WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject)
            .then(result => {
                go.run(result.instance);
            });

        document.getElementById("imageInput").addEventListener("change", function(e) {
            const file = e.target.files[0];
            const reader = new FileReader();
            
            reader.onload = function(event) {
                const img = new Image();
                img.onload = function() {
                    const canvas = document.getElementById("canvas");
                    canvas.width = img.width;
                    canvas.height = img.height;
                    const ctx = canvas.getContext("2d");
                    ctx.drawImage(img, 0, 0);
                    imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
                };
                img.src = event.target.result;
            };
            reader.readAsDataURL(file);
        });

        function processGrayscale() {
            if (!imageData) return;
            const processed = applyGrayscale(imageData);
            const canvas = document.getElementById("canvas");
            const ctx = canvas.getContext("2d");
            ctx.putImageData(processed, 0, 0);
        }

        function processBlur() {
            if (!imageData) return;
            const processed = applyBlur(imageData);
            const canvas = document.getElementById("canvas");
            const ctx = canvas.getContext("2d");
            ctx.putImageData(processed, 0, 0);
        }
    </script>
</body>
</html>

6. Performans Optimizasyonu

6.1 Performans Karşılaştırmaları: Go WASM vs JavaScript

📊 Benchmark Uyarısı: Aşağıda gösterilen benchmark sonuçları tipik senaryolara dayalı örneklerdir. Gerçek performans şunlara bağlı olarak önemli ölçüde değişebilir:

  • Tarayıcı motoru (Chrome V8, Firefox SpiderMonkey, Safari JavaScriptCore)
  • Donanım (CPU mimarisi, bellek hızı)
  • Optimizasyon seviyesi (derleyici bayrakları, tarayıcı optimizasyonları)
  • Kod karmaşıklığı ve veri boyutu
  • JavaScript motoru optimizasyonları (JIT derleme)

Bu sayılar mutlak garantiler değil, göreceli performans özelliklerini göstermek içindir. Her zaman kendi kullanım durumunuzu hedef ortamınızda test edin.

Gösterge amaçlı benchmark’larla performansı karşılaştıralım:

Fibonacci Hesaplama (n=40):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// Go WASM
func fibonacci(n int) int {
    if n <= 1 {
        return n
    }
    return fibonacci(n-1) + fibonacci(n-2)
}

// Benchmark sonuçları:
// Go WASM: ~850ms
// JavaScript: ~1200ms
// Native Go: ~450ms

Matris Çarpımı (1000x1000):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
func multiplyMatrices(a, b [][]float64) [][]float64 {
    n := len(a)
    result := make([][]float64, n)
    for i := range result {
        result[i] = make([]float64, n)
    }
    
    for i := 0; i < n; i++ {
        for j := 0; j < n; j++ {
            sum := 0.0
            for k := 0; k < n; k++ {
                sum += a[i][k] * b[k][j]
            }
            result[i][j] = sum
        }
    }
    return result
}

// Benchmark sonuçları:
// Go WASM: ~2.1s
// JavaScript (optimize edilmiş): ~3.8s
// Native Go: ~1.2s

Görüntü İşleme (1920x1080):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
func processImagePixels(data []uint8) {
    for i := 0; i < len(data); i += 4 {
        r := float64(data[i])
        g := float64(data[i+1])
        b := float64(data[i+2])
        
        // Gri tonlama dönüşümü
        gray := uint8(0.299*r + 0.587*g + 0.114*b)
        data[i] = gray
        data[i+1] = gray
        data[i+2] = gray
    }
}

// Benchmark sonuçları (frame başına):
// Go WASM: ~12ms
// JavaScript: ~28ms
// Native Go: ~8ms

Performans Özeti:

İşlem Go WASM JavaScript Hız Artışı
Fibonacci (n=40) 850ms 1200ms 1.41x
Matris Çarpımı (1Kx1K) 2.1s 3.8s 1.81x
Görüntü İşleme 12ms 28ms 2.33x
JSON Parse (10MB) 45ms 38ms 0.84x*

*Not: JavaScript’in V8 motoru JSON parsing için oldukça optimize edilmiştir, bu nedenle WASM bu özel görevde daha yavaş olabilir.

6.2 WASM Binary Boyutunu Azaltma

1
2
3
4
5
6
7
8
# Kullanılmayan kodu hariç tutmak için build tag'leri kullan
go build -tags="no_net" -o main.wasm main.go

# Binary boyutunu azaltmak için -ldflags kullan
go build -ldflags="-s -w" -o main.wasm main.go

# Daha küçük binary'ler için TinyGo kullan (alternatif derleyici)
tinygo build -target wasm -o main.wasm main.go

6.3 TinyGo: Detaylı Karşılaştırma

TinyGo, embedded sistemler ve WebAssembly için tasarlanmış alternatif bir Go derleyicisidir ve önemli ölçüde daha küçük binary’ler üretir.

Binary Boyutu Karşılaştırması:

Derleyici Binary Boyutu Runtime Boyutu Toplam
Standard Go 2.1 MB 500 KB ~2.6 MB
TinyGo 180 KB 50 KB ~230 KB
TinyGo (optimize edilmiş) 95 KB 30 KB ~125 KB

Özellik Karşılaştırması:

Özellik Standard Go TinyGo
Standard Library Tam Alt Küme
Goroutines ✅ Tam ⚠️ Sınırlı
Reflection ✅ Tam ⚠️ Kısmi
CGO ✅ Evet ❌ Hayır
Binary Boyutu Büyük Küçük
Derleme Hızı Hızlı Daha Yavaş
Debugging Mükemmel İyi

TinyGo Ne Zaman Kullanılmalı:

TinyGo kullanın:

  • Binary boyutu kritik (< 500 KB)
  • Tam standard library’ye ihtiyacınız yok
  • Embedded/IoT cihazlar için geliştirme yapıyorsunuz
  • Bellek kısıtlı
  • Library sınırlamalarıyla çalışabilirsiniz

Standard Go ile devam edin:

  • Tam standard library desteğine ihtiyacınız var
  • Karmaşık reflection gerekli
  • CGO’ya ihtiyacınız var
  • Geliştirme hızı öncelik
  • Binary boyutu endişe değil

TinyGo Örneği:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# TinyGo kurulumu
# macOS
brew tap tinygo-org/tools
brew install tinygo

# TinyGo ile derleme
tinygo build -target wasm -o main.wasm -opt=z -scheduler=none main.go

# Daha fazla optimizasyon
tinygo build -target wasm -o main.wasm \
  -opt=z \
  -scheduler=none \
  -no-debug \
  -ldflags="-s -w" \
  main.go

Trade-off’lar:

  • Boyut vs Özellikler: TinyGo boyut için bazı özelliklerden feragat eder
  • Performans: Her ikisi de çoğu görev için benzer performans gösterir
  • Uyumluluk: Bazı Go paketleri TinyGo ile çalışmayabilir
  • Geliştirme: Standard Go daha iyi araçlar ve debugging sunar

6.4 Bellek Kullanımını Optimize Etme

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
	"syscall/js"
	"unsafe"
)

// Tahsislerden kaçınmak için buffer'ları yeniden kullan
var bufferPool = make([][]byte, 0, 10)

func getBuffer(size int) []byte {
	if len(bufferPool) > 0 {
		buf := bufferPool[len(bufferPool)-1]
		bufferPool = bufferPool[:len(bufferPool)-1]
		if cap(buf) >= size {
			return buf[:size]
		}
	}
	return make([]byte, size)
}

func returnBuffer(buf []byte) {
	if len(bufferPool) < cap(bufferPool) {
		bufferPool = append(bufferPool, buf)
	}
}

6.5 JavaScript-Go Sınır Geçişlerini Minimize Etme

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// Kötü: Birçok küçük çağrı
func processDataBad(items []js.Value) {
	for _, item := range items {
		js.Global().Get("console").Call("log", item.String())
	}
}

// İyi: Toplu işlemler
func processDataGood(items []js.Value) {
	results := make([]string, len(items))
	for i, item := range items {
		results[i] = item.String()
	}
	// Tüm sonuçlarla tek JavaScript çağrısı
	js.Global().Call("processBatch", results)
}

6.6 Bellek Havuzlama

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package main

import (
	"sync"
)

var bufferPool = sync.Pool{
	New: func() interface{} {
		return make([]byte, 0, 1024)
	},
}

func getBuffer() []byte {
	return bufferPool.Get().([]byte)
}

func returnBuffer(buf []byte) {
	buf = buf[:0] // Uzunluğu sıfırla, kapasiteyi koru
	bufferPool.Put(buf)
}

// Kullanım
func processData(data []byte) {
	buf := getBuffer()
	defer returnBuffer(buf)
	
	// İşleme için buf kullan
	buf = append(buf, data...)
	// ... işle ...
}

6.7 Sıfır Kopyalama Teknikleri

1
2
3
4
5
6
7
8
9
// JavaScript'e veri geçirirken gereksiz kopyalardan kaçının
func processLargeArray(data []byte) {
	// Kopyalamak yerine referans geçir
	jsArray := js.Global().Get("Uint8Array").New(len(data))
	js.CopyBytesToJS(jsArray, data)
	
	// Diziyi doğrudan kullan
	js.Global().Call("processArray", jsArray)
}

7. Test Stratejileri

WebAssembly uygulamalarını test etmek, birim testleri, entegrasyon testleri ve tarayıcı otomasyonunun bir kombinasyonunu gerektirir.

7.1 Go WASM Kodunu Birim Test Etme

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// main_test.go
package main

import (
	"testing"
)

func TestFibonacci(t *testing.T) {
	tests := []struct {
		input    int
		expected int
	}{
		{0, 0},
		{1, 1},
		{5, 5},
		{10, 55},
		{20, 6765},
	}

	for _, tt := range tests {
		result := fibonacci(tt.input)
		if result != tt.expected {
			t.Errorf("fibonacci(%d) = %d, expected %d", tt.input, result, tt.expected)
		}
	}
}

func TestImageProcessing(t *testing.T) {
	// Test görüntü verisi oluştur
	data := make([]uint8, 12) // 3x1 piksel RGBA
	data[0] = 255 // R
	data[1] = 128 // G
	data[2] = 64  // B
	data[3] = 255 // A
	
	processImagePixels(data)
	
	// Gri tonlama dönüşümünü doğrula
	if data[0] != data[1] || data[1] != data[2] {
		t.Error("Gri tonlama dönüşümü başarısız")
	}
}

Testleri Çalıştırma:

1
2
3
4
5
6
7
8
# WASM derlemesinden önce Go kodunu test et
go test ./...

# Coverage ile test
go test -cover ./...

# Belirli paketi test et
go test ./internal/processor

7.2 Node.js ile Entegrasyon Testi

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// test/integration/wasm.test.js
const { readFileSync } = require('fs');
const { instantiateSync } = require('@wasm/wasm');

describe('WASM Entegrasyon Testleri', () => {
    let wasmModule;
    
    beforeAll(async () => {
        const wasmBuffer = readFileSync('./main.wasm');
        wasmModule = await instantiateSync(wasmBuffer, {
            // Import object
        });
    });
    
    test('veriyi doğru şekilde işlemeli', () => {
        const result = wasmModule.exports.processData([1, 2, 3, 4]);
        expect(result).toBeDefined();
    });
});

7.3 Tarayıcı Otomasyon Testi

Playwright Kullanımı:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// test/e2e/wasm.spec.js
const { test, expect } = require('@playwright/test');

test('WASM yüklenir ve görüntüyü işler', async ({ page }) => {
    await page.goto('http://localhost:8080');
    
    // WASM'ın yüklenmesini bekle
    await page.waitForFunction(() => window.wasmLoaded === true);
    
    // Test görüntüsünü yükle
    const input = await page.$('input[type="file"]');
    await input.setInputFiles('./test/fixtures/test-image.jpg');
    
    // İşleme butonuna tıkla
    await page.click('button#process');
    
    // Sonucu doğrula
    const canvas = await page.$('canvas');
    const imageData = await canvas.evaluate((el) => {
        const ctx = el.getContext('2d');
        return ctx.getImageData(0, 0, el.width, el.height);
    });
    
    expect(imageData).toBeDefined();
});

Selenium Kullanımı:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// test/e2e/selenium_test.go
package e2e

import (
	"testing"
	"github.com/tebeka/selenium"
)

func TestWASMInBrowser(t *testing.T) {
	// Selenium WebDriver kurulumu
	capabilities := selenium.Capabilities{"browserName": "chrome"}
	wd, err := selenium.NewRemote(capabilities, "")
	if err != nil {
		t.Fatal(err)
	}
	defer wd.Quit()

	// Sayfaya git
	wd.Get("http://localhost:8080")

	// WASM'ın yüklenmesini bekle
	wd.Wait(func(wd selenium.WebDriver) (bool, error) {
		loaded, err := wd.ExecuteScript("return window.wasmLoaded === true", nil)
		return loaded.(bool), err
	})

	// Fonksiyonelliği test et
	result, err := wd.ExecuteScript("return processData([1,2,3])", nil)
	if err != nil {
		t.Fatal(err)
	}
	
	if result == nil {
		t.Error("WASM fonksiyonundan sonuç bekleniyordu")
	}
}

7.4 Performans Testi

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// test/benchmark/performance_test.go
package benchmark

import (
	"testing"
)

func BenchmarkWASMProcessing(b *testing.B) {
	data := make([]uint8, 1920*1080*4) // Full HD görüntü
	
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		processImagePixels(data)
	}
}

func BenchmarkJavaScriptInterop(b *testing.B) {
	items := make([]js.Value, 1000)
	for i := range items {
		items[i] = js.ValueOf(i)
	}
	
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		processDataGood(items)
	}
}

8. Hata Ayıklama ve Hata Kurtarma

8.1 Console Logging Kullanımı

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
package main

import (
	"fmt"
	"syscall/js"
)

func log(format string, args ...interface{}) {
	message := fmt.Sprintf(format, args...)
	js.Global().Get("console").Call("log", message)
}

func main() {
	log("Uygulama başlatıldı")
	log("Değer: %d", 42)
}

8.2 Source Maps

1
2
# Hata ayıklama için source map'lerle derle
go build -o main.wasm -gcflags="all=-N -l" main.go

8.3 Tarayıcı DevTools Derinlemesine İnceleme

Chrome DevTools:

  1. Sources Sekmesi:

    • Go kaynak kodunda breakpoint’ler ayarla
    • WASM çalıştırmasını adım adım izle
    • Çağrı yığınını incele
  2. Memory Sekmesi:

    • WASM bellek kullanımını izle
    • Bellek sızıntılarını tespit et
    • Bellek büyüme desenlerini analiz et
  3. Performance Sekmesi:

    • WASM çalıştırmasını profile et
    • Darboğazları tespit et
    • JavaScript-WASM sınır ek yükünü ölç

Firefox DevTools:

  • Mükemmel WASM hata ayıklama desteği
  • Source map entegrasyonu
  • Bellek profiling araçları

8.4 WASM Crash’lerini Yakalama

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package main

import (
	"fmt"
	"syscall/js"
)

func safeCall(fn func() interface{}) interface{} {
	defer func() {
		if r := recover(); r != nil {
			errorMsg := fmt.Sprintf("WASM panic: %v", r)
			js.Global().Get("console").Call("error", errorMsg)
			
			// Hata takip servisine bildir
			js.Global().Call("reportError", map[string]interface{}{
				"type":    "wasm_panic",
				"message": errorMsg,
				"stack":   getStackTrace(),
			})
		}
	}()
	return fn()
}

func getStackTrace() string {
	// Stack trace yakala
	return "Stack trace burada"
}

// Kullanım
func processData(data []byte) {
	safeCall(func() interface{} {
		// Panic olabilecek kodunuz
		return processDataUnsafe(data)
	})
}

8.5 Bellek Sızıntısı Tespiti

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package main

import (
	"fmt"
	"runtime"
	"syscall/js"
	"time"
)

func monitorMemory() {
	ticker := time.NewTicker(5 * time.Second)
	defer ticker.Stop()
	
	for range ticker.C {
		var m runtime.MemStats
		runtime.ReadMemStats(&m)
		
		js.Global().Get("console").Call("log", fmt.Sprintf(
			"Alloc: %d KB, Sys: %d KB, NumGC: %d",
			m.Alloc/1024,
			m.Sys/1024,
			m.NumGC,
		))
		
		// Bellek kullanımı yüksekse uyar
		if m.Alloc > 50*1024*1024 { // 50 MB
			js.Global().Call("alert", "Yüksek bellek kullanımı tespit edildi!")
		}
	}
}

func main() {
	go monitorMemory()
	// ... kodunuzun geri kalanı
}

8.6 Performans Profiling Araçları

Chrome Performance API Kullanımı:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// WASM çalıştırmasını profile et
async function profileWASM() {
    const perf = performance.now();
    
    // WASM fonksiyonunu çağır
    wasmModule.exports.heavyComputation();
    
    const duration = performance.now() - perf;
    console.log(`WASM çalıştırması: ${duration}ms sürdü`);
}

Performance Observer Kullanımı:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
const observer = new PerformanceObserver((list) => {
    for (const entry of list.getEntries()) {
        if (entry.entryType === 'measure') {
            console.log(`${entry.name}: ${entry.duration}ms`);
        }
    }
});

observer.observe({ entryTypes: ['measure'] });

// WASM fonksiyonunu ölç
performance.mark('wasm-start');
wasmModule.exports.processData();
performance.mark('wasm-end');
performance.measure('wasm-execution', 'wasm-start', 'wasm-end');

8.7 Hata Kurtarma Stratejileri

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package main

import (
	"errors"
	"fmt"
	"syscall/js"
)

type WASMError struct {
	Code    string
	Message string
}

func (e *WASMError) Error() string {
	return e.Message
}

func recoverFromError(fn func() error) error {
	defer func() {
		if r := recover(); r != nil {
			// Panic'i hataya dönüştür
			err := &WASMError{
				Code:    "PANIC",
				Message: fmt.Sprintf("%v", r),
			}
			handleError(err)
		}
	}()
	
	err := fn()
	if err != nil {
		handleError(err)
	}
	return err
}

func handleError(err error) {
	js.Global().Call("onWASMError", map[string]interface{}{
		"error": err.Error(),
	})
}

9. Dağıtım ve Production

9.1 Build Script

build.sh:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash

set -e

# WASM derle
export GOOS=js
export GOARCH=wasm
go build -ldflags="-s -w" -o public/main.wasm ./cmd/wasm

# Destek dosyalarını kopyala
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" public/

# wasm-opt ile optimize et (Binaryen'den)
if command -v wasm-opt &> /dev/null; then
    wasm-opt -Oz public/main.wasm -o public/main.optimized.wasm
    mv public/main.optimized.wasm public/main.wasm
    echo "WASM wasm-opt ile optimize edildi"
fi

echo "Build tamamlandı!"

9.2 CI/CD Pipeline

GitHub Actions Örneği:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
name: Build and Deploy WASM

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Set up Go
      uses: actions/setup-go@v4
      with:
        go-version: '1.21'
    
    - name: Install wasm-opt
      run: |
        wget https://github.com/WebAssembly/binaryen/releases/download/version_116/binaryen-version_116-x86_64-linux.tar.gz
        tar -xzf binaryen-version_116-x86_64-linux.tar.gz
        sudo mv binaryen-version_116/bin/wasm-opt /usr/local/bin/        
    
    - name: Build WASM
      run: |
        export GOOS=js
        export GOARCH=wasm
        go build -ldflags="-s -w" -o public/main.wasm ./cmd/wasm
        cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" public/
        wasm-opt -Oz public/main.wasm -o public/main.optimized.wasm
        mv public/main.optimized.wasm public/main.wasm        
    
    - name: Run tests
      run: go test ./...
    
    - name: Upload artifacts
      uses: actions/upload-artifact@v3
      with:
        name: wasm-build
        path: public/
    
    - name: Deploy to CDN
      if: github.ref == 'refs/heads/main'
      run: |
        # Deployment script'iniz burada
        echo "Production'a dağıtılıyor..."        

GitLab CI Örneği:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
stages:
  - build
  - test
  - deploy

build_wasm:
  stage: build
  image: golang:1.21
  script:
    - export GOOS=js GOARCH=wasm
    - go build -ldflags="-s -w" -o public/main.wasm ./cmd/wasm
    - cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" public/
  artifacts:
    paths:
      - public/
    expire_in: 1 hour

test:
  stage: test
  image: golang:1.21
  script:
    - go test -v ./...

deploy:
  stage: deploy
  script:
    - echo "Dağıtılıyor..."
  only:
    - main

9.3 Sıkıştırma ile Servis Etme

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# nginx.conf
server {
    location ~ \.wasm$ {
        add_header Content-Type application/wasm;
        add_header Cross-Origin-Opener-Policy same-origin;
        add_header Cross-Origin-Embedder-Policy require-corp;
        
        gzip on;
        gzip_vary on;
        gzip_types application/wasm;
        gzip_comp_level 9;
        
        brotli on;
        brotli_types application/wasm;
        brotli_comp_level 11;
        
        # 1 yıl için cache
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

9.4 CDN Konfigürasyonu

Cloudflare:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// WASM optimizasyonu için Cloudflare Workers
addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  const url = new URL(request.url)
  
  if (url.pathname.endsWith('.wasm')) {
    const response = await fetch(request)
    const wasm = await response.arrayBuffer()
    
    // Opsiyonel: Daha fazla optimizasyon
    // const optimized = await optimizeWASM(wasm)
    
    return new Response(wasm, {
      headers: {
        'Content-Type': 'application/wasm',
        'Content-Encoding': 'br', // Brotli sıkıştırma
        'Cache-Control': 'public, max-age=31536000, immutable',
      },
    })
  }
  
  return fetch(request)
}

AWS CloudFront:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "CacheBehaviors": {
    "*.wasm": {
      "Compress": true,
      "MinTTL": 31536000,
      "ForwardedValues": {
        "QueryString": false
      }
    }
  }
}

10. Güvenlik Düşünceleri

10.1 WASM Güvenlik Modeli

WebAssembly, birkaç güvenlik özelliğiyle sandbox ortamında çalışır:

  • Bellek İzolasyonu: Her WASM modülünün kendi linear belleği vardır
  • Doğrudan Sistem Erişimi Yok: Dosya sistemi veya ağa doğrudan erişemez
  • Same-Origin Policy: Tarayıcının same-origin policy’sine tabidir
  • Tip Güvenliği: Güçlü tip sistemi birçok yaygın güvenlik açığını önler

10.2 Girdi Doğrulama

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package main

import (
	"errors"
	"strings"
	"syscall/js"
)

func validateInput(data js.Value) error {
	if data.IsNull() || data.IsUndefined() {
		return errors.New("input null veya undefined olamaz")
	}
	
	// String uzunluğunu doğrula
	if data.Type() == js.TypeString {
		str := data.String()
		if len(str) > 10000 {
			return errors.New("input çok büyük")
		}
		// Zararlı desenleri kontrol et
		if containsMaliciousPattern(str) {
			return errors.New("zararlı input tespit edildi")
		}
	}
	
	return nil
}

func containsMaliciousPattern(input string) bool {
	malicious := []string{
		"<script>",
		"javascript:",
		"onerror=",
		"eval(",
	}
	
	lower := strings.ToLower(input)
	for _, pattern := range malicious {
		if strings.Contains(lower, pattern) {
			return true
		}
	}
	return false
}

10.3 XSS Koruması

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
func sanitizeOutput(data string) string {
	// HTML özel karakterlerini escape et
	replacements := map[string]string{
		"<":  "&lt;",
		">":  "&gt;",
		"&":  "&amp;",
		"\"": "&quot;",
		"'":  "&#x27;",
	}
	
	result := data
	for old, new := range replacements {
		result = strings.ReplaceAll(result, old, new)
	}
	return result
}

func safeSetInnerHTML(element js.Value, content string) {
	sanitized := sanitizeOutput(content)
	element.Set("innerHTML", sanitized)
}

10.4 Bellek Güvenliği

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
func safeArrayAccess(arr []byte, index int) (byte, error) {
	if index < 0 || index >= len(arr) {
		return 0, errors.New("index sınırların dışında")
	}
	return arr[index], nil
}

func processDataSafely(data []byte, maxSize int) ([]byte, error) {
	if len(data) > maxSize {
		return nil, errors.New("veri boyutu maksimumu aşıyor")
	}
	
	// Orijinali değiştirmemek için kopya oluştur
	result := make([]byte, len(data))
	copy(result, data)
	
	// Güvenli şekilde işle
	// ...
	
	return result, nil
}

10.5 Content Security Policy (CSP)

1
2
3
4
5
<!-- index.html -->
<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; 
               script-src 'self' 'wasm-unsafe-eval'; 
               object-src 'none';">

Nginx CSP Header:

1
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; object-src 'none';";

10.6 Güvenli WASM Yükleme

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// Güvenli WASM instantiation
async function loadWASMSecurely(url, expectedHash) {
    const response = await fetch(url);
    const wasmBuffer = await response.arrayBuffer();
    
    // Bütünlüğü doğrula (basitleştirilmiş örnek)
    const hash = await crypto.subtle.digest('SHA-256', wasmBuffer);
    const hashArray = Array.from(new Uint8Array(hash));
    const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
    
    if (hashHex !== expectedHash) {
        throw new Error('WASM bütünlük kontrolü başarısız');
    }
    
    return WebAssembly.instantiate(wasmBuffer, go.importObject);
}

11. Sınırlamalar ve Düşünceler

11.1 WASM’da Go Runtime Sınırlamaları

  • Goroutines: Sınırlı eşzamanlılık (tek thread çalıştırma)
  • Network: Doğrudan ağ erişimi yok (JavaScript üzerinden gitmeli)
  • Dosya Sistemi: Doğrudan dosya sistemi erişimi yok
  • CGO: WASM build’lerde desteklenmiyor
  • Bazı paketler: Tüm Go standard library paketleri WASM’da çalışmaz

11.2 Tarayıcı Uyumluluğu

  • Modern tarayıcılar (Chrome, Firefox, Safari, Edge) WASM’ı destekler
  • Eski tarayıcılar polyfill gerektirebilir
  • Mobil tarayıcı desteği iyidir ama kapsamlı test edin

11.3 Performans Düşünceleri

  • İlk yükleme süresi: WASM binary’leri indirilmeli ve derlenmeli
  • Bellek kullanımı: Go runtime ek yük ekler
  • JavaScript interop: Sınırı geçmenin maliyeti vardır

11.4 Yaygın Tuzaklar

Bellek Sızıntıları:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// ❌ Kötü: Temizlik olmadan fonksiyon oluşturma
func registerHandler() {
	js.Global().Set("handler", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		// Handler kodu
		return nil
	}))
	// Fonksiyon hiç serbest bırakılmıyor!
}

// ✅ İyi: Temizlik için referans sakla
var handler js.Func

func registerHandler() {
	handler = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		// Handler kodu
		return nil
	})
	js.Global().Set("handler", handler)
}

func cleanup() {
	handler.Release() // Bittiğinde serbest bırak
}

Goroutine Sorunları:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
	"context"
	"syscall/js"
	"time"
)

// ❌ Kötü: Goroutine WASM modülünden daha uzun yaşayabilir
func processAsync() {
	go func() {
		time.Sleep(10 * time.Second)
		js.Global().Call("callback") // Modül kaldırılmışsa başarısız olabilir
	}()
}

// ✅ İyi: İptal için context kullan
func processAsync(ctx context.Context) {
	go func() {
		select {
		case <-time.After(10 * time.Second):
			js.Global().Call("callback")
		case <-ctx.Done():
			return // Temiz çıkış
		}
	}()
}

Tip Dönüşümleri:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// ❌ Kötü: Kontrol etmeden tip varsayma
func processValue(val js.Value) {
	str := val.String() // String değilse panic olabilir
}

// ✅ İyi: Önce tipi kontrol et
func processValue(val js.Value) {
	if val.Type() != js.TypeString {
		return // Hatayı yönet
	}
	str := val.String()
	// String'i işle
}

Goroutine Bellek Sızıntıları:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package main

import (
	"context"
	"time"
)

// ❌ Kötü: Hiç durmayan goroutine'ler
func badHandler() {
	for {
		go func() {
			// Sonsuz döngü - hiç durmaz
			for {
				time.Sleep(time.Second)
				// Hiç tamamlanmayan iş
			}
		}()
	}
}

// ✅ İyi: İptal için context kullan
func goodHandler(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			return // Temiz çıkış
		default:
			go func() {
				ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
				defer cancel()
				
				// Timeout ile iş yap
				doWork(ctx)
			}()
		}
	}
}

Channel Deadlock’ları:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// ❌ Kötü: Alıcı olmadan unbuffered channel
func badChannel() {
	ch := make(chan int)
	ch <- 42 // Alıcı yoksa deadlock
}

// ✅ İyi: Buffered channel kullan veya alıcı olduğundan emin ol
func goodChannel() {
	ch := make(chan int, 1) // Buffered
	ch <- 42
	
	// Veya default ile select kullan
	select {
	case ch <- 42:
		// Gönderildi
	default:
		// Bloke olurdu, zarif şekilde yönet
	}
}

JavaScript Değer Yaşam Döngüsü:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// ❌ Kötü: JavaScript değerlerini serbest bırakmama
func badJSValue() {
	obj := js.Global().Get("someObject")
	// obj'yi kullan ama hiç serbest bırakma
	// obj sonsuza kadar bellekte kalır
}

// ✅ İyi: Bittiğinde serbest bırak (gerekirse)
func goodJSValue() {
	obj := js.Global().Get("someObject")
	defer obj.Release() // Fonksiyon çıktığında serbest bırak
	
	// obj'yi kullan
	value := obj.Get("property")
	return value
}

Dizi Sınırları:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// ❌ Kötü: Sınır kontrolü yok
func badArrayAccess(arr []byte, idx int) byte {
	return arr[idx] // Panic olabilir
}

// ✅ İyi: Her zaman sınırları kontrol et
func goodArrayAccess(arr []byte, idx int) (byte, error) {
	if idx < 0 || idx >= len(arr) {
		return 0, errors.New("index sınırların dışında")
	}
	return arr[idx], nil
}

Eşzamanlı Map Erişimi:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// ❌ Kötü: Eşzamanlı map yazma
var cache = make(map[string]interface{})

func badCache(key string, value interface{}) {
	cache[key] = value // Race condition!
}

// ✅ İyi: sync.Map veya mutex kullan
var safeCache = sync.Map{}

func goodCache(key string, value interface{}) {
	safeCache.Store(key, value) // Thread-safe
}

// Veya mutex ile
var (
	cache = make(map[string]interface{})
	cacheMu sync.RWMutex
)

func goodCacheWithMutex(key string, value interface{}) {
	cacheMu.Lock()
	defer cacheMu.Unlock()
	cache[key] = value
}

12. Yaygın Sorunları Giderme

12.1 WASM Modülü Yüklenemiyor

Belirtiler:

  • Boş sayfa veya console hataları
  • “Failed to fetch” hataları
  • .wasm dosyası için 404 hataları

Çözümler:

  1. MIME Tipini Kontrol Et:
1
2
3
4
# nginx.conf
location ~ \.wasm$ {
    add_header Content-Type application/wasm;
}
  1. CORS Header’larını Doğrula:
1
2
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, OPTIONS";
  1. Tarayıcı Console’unu Kontrol Et:
1
2
3
4
5
6
7
8
9
// Hata yönetimi ekle
WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject)
    .then(result => {
        go.run(result.instance);
    })
    .catch(error => {
        console.error("WASM yükleme hatası:", error);
        // JavaScript'e geri dön
    });
  1. Dosya Yollarını Doğrula:
1
2
3
4
5
<!-- Yolların doğru olduğundan emin ol -->
<script src="./wasm_exec.js"></script>
<script>
    fetch("./main.wasm") // Relatif veya mutlak yol
</script>

12.2 Bellek Tükenmesi Hataları

Belirtiler:

  • “Out of memory” hataları
  • Tarayıcı sekmesi çöküyor
  • Yavaş performans

Çözümler:

  1. Binary Boyutunu Azalt:
1
2
3
4
5
# TinyGo kullan
tinygo build -target wasm -opt=z -o main.wasm main.go

# Veya wasm-opt ile optimize et
wasm-opt -Oz main.wasm -o main.optimized.wasm
  1. Bellek Havuzlamayı Uygula:
1
2
3
4
5
6
// Tahsis etmek yerine buffer'ları yeniden kullan
var bufferPool = sync.Pool{
    New: func() interface{} {
        return make([]byte, 0, 1024)
    },
}
  1. Streaming API’lerini Kullan:
1
2
3
4
5
6
7
8
// Veriyi parçalar halinde işle
async function processLargeData(data) {
    const chunkSize = 1024 * 1024; // 1MB parçalar
    for (let i = 0; i < data.length; i += chunkSize) {
        const chunk = data.slice(i, i + chunkSize);
        await wasmModule.exports.processChunk(chunk);
    }
}
  1. Bellek Kullanımını İzle:
1
2
3
4
5
6
7
func checkMemory() {
    var m runtime.MemStats
    runtime.ReadMemStats(&m)
    if m.Alloc > 50*1024*1024 { // 50MB
        runtime.GC() // Zorunlu garbage collection
    }
}

12.3 Yavaş İlk Yükleme Süresi

Belirtiler:

  • WASM yüklenmeden önce uzun gecikme
  • Kötü first contentful paint
  • Kullanıcı boş ekran görüyor

Çözümler:

  1. Streaming Derleme Kullan:
1
2
// fetch + compile'den daha hızlı
const module = await WebAssembly.compileStreaming(fetch("main.wasm"));
  1. Code Splitting Uygula:
1
2
3
4
5
6
7
8
// Önce kritik kodu yükle, geri kalanını sonra
async function loadCriticalWASM() {
    const critical = await WebAssembly.instantiateStreaming(
        fetch("critical.wasm")
    );
    // Kritik olmayan kodu sonra yükle
    setTimeout(() => loadNonCriticalWASM(), 2000);
}
  1. Sıkıştırmayı Etkinleştir:
1
2
3
4
gzip on;
gzip_types application/wasm;
brotli on;
brotli_types application/wasm;
  1. Yükleme Göstergesi Göster:
1
2
3
4
5
6
7
8
<div id="loading">WASM yükleniyor...</div>
<script>
    WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject)
        .then(result => {
            document.getElementById("loading").style.display = "none";
            go.run(result.instance);
        });
</script>

12.4 JavaScript Interop Hataları

Belirtiler:

  • “Cannot read property” hataları
  • Tip hataları
  • Tanımsız fonksiyon çağrıları

Çözümler:

  1. Her Zaman Tipleri Kontrol Et:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func safeGetProperty(obj js.Value, key string) (string, error) {
    if obj.IsNull() || obj.IsUndefined() {
        return "", errors.New("nesne null veya undefined")
    }
    
    prop := obj.Get(key)
    if prop.IsUndefined() {
        return "", errors.New("özellik bulunamadı")
    }
    
    if prop.Type() != js.TypeString {
        return "", errors.New("özellik string değil")
    }
    
    return prop.String(), nil
}
  1. Opsiyonel Parametreleri Yönet:
1
2
3
4
5
6
7
8
func processWithDefaults(this js.Value, args []js.Value) interface{} {
    value := 0
    if len(args) > 0 && !args[0].IsUndefined() {
        value = args[0].Int()
    }
    // Varsayılan değerle kullan
    return process(value)
}
  1. Fonksiyon Varlığını Doğrula:
1
2
3
4
5
6
// Çağırmadan önce WASM fonksiyonunun var olduğunu kontrol et
if (window.wasmModule && typeof window.wasmModule.myFunction === 'function') {
    window.wasmModule.myFunction();
} else {
    console.error("WASM fonksiyonu mevcut değil");
}

12.5 Performans Sorunları

Belirtiler:

  • Beklenenden daha yavaş
  • Yüksek CPU kullanımı
  • UI donuyor

Çözümler:

  1. JavaScript-WASM Sınır Geçişlerini Minimize Et:
1
2
3
4
5
6
7
// ❌ Kötü: Birçok küçük çağrı
for i := 0; i < 1000; i++ {
    js.Global().Call("processItem", items[i])
}

// ✅ İyi: Toplu işlemler
js.Global().Call("processBatch", items)
  1. Web Workers Kullan:
1
2
3
// Ağır işi worker'a aktar
const worker = new Worker('worker.wasm.js');
worker.postMessage({ type: 'process', data: largeData });
  1. Profile Et ve Optimize Et:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// Go'nun yerleşik profiling'ini kullan
import _ "net/http/pprof"

// Veya tarayıcı performance API'sini kullan
func profileFunction(fn func()) {
    start := time.Now()
    fn()
    duration := time.Since(start)
    js.Global().Get("console").Call("log", 
        fmt.Sprintf("Fonksiyon süresi: %v", duration))
}

12.6 Tarayıcı Uyumluluk Sorunları

Belirtiler:

  • Chrome’da çalışıyor ama Firefox’ta çalışmıyor
  • Mobil tarayıcı sorunları
  • Eski tarayıcı hataları

Çözümler:

  1. Özellik Tespiti:
1
2
3
4
5
if (!WebAssembly) {
    // JavaScript'e geri dön
    console.warn("WebAssembly desteklenmiyor");
    loadJavaScriptFallback();
}
  1. Polyfill’ler:
1
2
<!-- Eski tarayıcılar için -->
<script src="https://polyfill.io/v3/polyfill.min.js?features=WebAssembly"></script>
  1. Progressive Enhancement:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
async function loadWithFallback() {
    try {
        if (typeof WebAssembly !== 'undefined') {
            await loadWASM();
        } else {
            loadJavaScriptVersion();
        }
    } catch (error) {
        console.error("WASM başarısız, JS fallback kullanılıyor:", error);
        loadJavaScriptVersion();
    }
}

12.7 Hata Ayıklama İpuçları

Verbose Logging Etkinleştir:

1
2
3
4
5
6
7
8
const debug = true

func logDebug(format string, args ...interface{}) {
    if debug {
        js.Global().Get("console").Call("log", 
            fmt.Sprintf("[WASM] "+format, args...))
    }
}

Source Maps Kullan:

1
go build -gcflags="all=-N -l" -o main.wasm main.go

Tarayıcı DevTools:

  • Chrome DevTools Sources sekmesini kullan
  • Go kodunda breakpoint’ler ayarla
  • WASM belleğini incele
  • Profiling için Performance sekmesini kullan

13. En İyi Uygulamalar

13.1 Kod Organizasyonu

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
project/
├── cmd/
│   ├── wasm/
│   │   └── main.go
│   └── server/
│       └── main.go
├── internal/
│   ├── wasm/
│   │   └── handlers.go
│   └── shared/
│       └── models.go
├── pkg/
│   └── processor/
│       └── image.go
└── web/
    ├── index.html
    └── assets/

13.2 Hata Yönetimi

1
2
3
4
5
6
7
8
func safeCall(fn func() interface{}) interface{} {
	defer func() {
		if r := recover(); r != nil {
			js.Global().Get("console").Call("error", fmt.Sprintf("Hata: %v", r))
		}
	}()
	return fn()
}

13.3 Tip Güvenliği

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// JavaScript değerleri için tip güvenli wrapper'lar kullan
type JSObject struct {
	Value js.Value
}

func (j JSObject) GetString(key string) string {
	return j.Value.Get(key).String()
}

func (j JSObject) GetInt(key string) int {
	return j.Value.Get(key).Int()
}

14. Framework Entegrasyonu

14.1 React Entegrasyonu

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// useWASM.ts
import { useEffect, useState } from 'react';

export function useWASM() {
    const [wasm, setWasm] = useState<any>(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState<Error | null>(null);

    useEffect(() => {
        async function loadWASM() {
            try {
                const go = new (window as any).Go();
                const result = await WebAssembly.instantiateStreaming(
                    fetch('main.wasm'),
                    go.importObject
                );
                go.run(result.instance);
                setWasm((window as any).wasmModule);
                setLoading(false);
            } catch (err) {
                setError(err as Error);
                setLoading(false);
            }
        }
        loadWASM();
    }, []);

    return { wasm, loading, error };
}

// Component kullanımı
function ImageProcessor() {
    const { wasm, loading } = useWASM();
    const [processed, setProcessed] = useState<string>('');

    const handleProcess = () => {
        if (wasm) {
            const result = wasm.processImage(imageData);
            setProcessed(result);
        }
    };

    if (loading) return <div>WASM yükleniyor...</div>;

    return (
        <div>
            <button onClick={handleProcess}>İşle</button>
            {processed && <img src={processed} />}
        </div>
    );
}

14.2 Vue Entegrasyonu

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<template>
  <div>
    <button @click="processData" :disabled="!wasmLoaded">
      Veriyi İşle
    </button>
    <div v-if="result">{{ result }}</div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';

const wasmLoaded = ref(false);
const result = ref('');

onMounted(async () => {
  const go = new (window as any).Go();
  await WebAssembly.instantiateStreaming(
    fetch('main.wasm'),
    go.importObject
  );
  go.run();
  wasmLoaded.value = true;
});

function processData() {
  if ((window as any).wasmModule) {
    result.value = (window as any).wasmModule.processData();
  }
}
</script>

14.3 Svelte Entegrasyonu

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<script lang="ts">
  import { onMount } from 'svelte';
  
  let wasm: any = null;
  let result = '';
  
  onMount(async () => {
    const go = new (window as any).Go();
    const instance = await WebAssembly.instantiateStreaming(
      fetch('main.wasm'),
      go.importObject
    );
    go.run(instance);
    wasm = (window as any).wasmModule;
  });
  
  function process() {
    if (wasm) {
      result = wasm.processData();
    }
  }
</script>

<button on:click={process} disabled={!wasm}>
  İşle
</button>
<p>{result}</p>

14.4 TypeScript Tip Tanımlamaları

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// wasm.d.ts
declare global {
  interface Window {
    wasmModule: {
      processImage: (data: ImageData) => ImageData;
      processData: (data: number[]) => number[];
      fibonacci: (n: number) => number;
    };
    Go: new () => {
      importObject: WebAssembly.Imports;
      run: (instance: WebAssembly.Instance) => void;
    };
  }
}

export {};

15. Gerçek Dünya Production Vaka Çalışmaları

15.1 Vaka Çalışması: Görüntü İşleme Platformu

Şirket: TechCorp Imaging
Zorluk: Sunucu gidiş-dönüşleri olmadan tarayıcıda 4K görüntüleri işlemek
Çözüm: Go WASM görüntü işleme pipeline’ı

Sonuçlar:

  • Performans: JavaScript implementasyonundan 3.2x daha hızlı
  • Binary Boyutu: 450 KB (TinyGo kullanarak)
  • Kullanıcı Deneyimi: Sunucu yüklemesi olmadan gerçek zamanlı önizleme
  • Maliyet Tasarrufu: Sunucu işleme maliyetlerinde %60 azalma

Implementasyon:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// Görüntü işleme pipeline'ı
// Not: Bunlar placeholder fonksiyonlar - görüntü library'nize göre implement edin
func ProcessImagePipeline(data []byte, operations []Operation) ([]byte, error) {
    // Görüntüyü decode et (image paketi veya üçüncü parti library kullanarak)
    img, err := decodeImage(data)
    if err != nil {
        return nil, err
    }
    
    // İşlemleri uygula
    for _, op := range operations {
        switch op.Type {
        case "resize":
            img = resizeImage(img, op.Params)
        case "filter":
            img = applyFilter(img, op.Filter)
        case "compress":
            img = compressImage(img, op.Quality)
        }
    }
    
    // Tekrar byte'lara encode et
    return encodeImage(img)
}

// Yardımcı tipler (örnek)
type Operation struct {
    Type   string
    Filter string
    Params map[string]interface{}
    Quality int
}

Öğrenilen Dersler:

  • Büyük görüntüler için bellek yönetimi kritik
  • Toplu işlemler tek tek çağrılardan daha verimli
  • İşleme sırasında kullanıcı geri bildirimi gerekli

15.2 Vaka Çalışması: Finansal Veri Görselleştirme

Şirket: FinanceApp
Zorluk: Milyonlarca veri noktasıyla karmaşık finansal grafikleri render etmek
Çözüm: Veri işleme için Go WASM, render için Canvas API

Sonuçlar:

  • Performans: Grafik render’ında 5x daha hızlı
  • Bellek: Tarayıcı bellek kullanımında %40 azalma
  • Kullanıcı Memnuniyeti: Algılanan performansta %85 iyileşme

Karşılaşılan Zorluklar:

  • İlk WASM yükleme süresi (code splitting ile çözüldü)
  • Uzun süreli oturumlarda bellek sızıntıları (uygun temizlikle çözüldü)
  • Tarayıcı uyumluluk sorunları (polyfill’lerle çözüldü)

15.3 Vaka Çalışması: Oyun Motoru

Şirket: IndieGame Studio
Zorluk: Mevcut Go oyun mantığını web’e taşımak
Çözüm: Go WASM oyun motoru

Sonuçlar:

  • Kod Yeniden Kullanımı: Oyun mantığının %80’i masaüstü versiyonundan yeniden kullanıldı
  • Performans: Orta seviye cihazlarda 60 FPS
  • Geliştirme Süresi: JavaScript’te yeniden yazmaktan %50 daha hızlı

Ana Optimizasyonlar:

  • Daha küçük binary için TinyGo kullanıldı (280 KB)
  • Oyun varlıkları için object pooling uygulandı
  • JavaScript-WASM sınır çağrıları optimize edildi

16. Migration Rehberi: JavaScript’ten Go WASM’a

16.1 Ne Zaman Migrate Edilmeli

İyi Adaylar:

  • CPU yoğun hesaplamalar
  • Mevcut Go kod tabanı
  • Performans kritik işlemler
  • Karmaşık algoritmalar

Uygun Değil:

  • Basit DOM manipülasyonu
  • Hafif işlemler
  • JavaScript framework’leriyle sıkı bağlı
  • Sık değişen kod

16.2 Migration Adımları

Adım 1: Hot Path’leri Belirle

1
2
3
4
// JavaScript kodunuzu profile edin
console.time('expensiveOperation');
expensiveOperation();
console.timeEnd('expensiveOperation');

Adım 2: Go’ya Çıkar

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// main.go
package main

import "syscall/js"

func main() {
    c := make(chan struct{}, 0)
    js.Global().Set("expensiveOperation", js.FuncOf(expensiveOperation))
    <-c
}

func expensiveOperation(this js.Value, args []js.Value) interface{} {
    // JavaScript mantığınızı buraya port edin
    result := compute(args[0].Int())
    return result
}

Adım 3: Kademeli Migration

1
2
3
4
5
6
7
8
9
// Uyumluluk için JavaScript wrapper'ı koruyun
function expensiveOperation(input) {
    // Önce WASM'ı dene, JS'e geri dön
    if (window.wasmModule && window.wasmModule.expensiveOperation) {
        return window.wasmModule.expensiveOperation(input);
    }
    // Orijinal JavaScript'e geri dön
    return expensiveOperationJS(input);
}

Adım 4: Kapsamlı Test

  • Go kodu için birim testleri
  • WASM modülü için entegrasyon testleri
  • Tarayıcı uyumluluk testi
  • Performans benchmark’ları

16.3 Yaygın Migration Desenleri

Desen 1: Fonksiyon Değiştirme

1
2
3
4
5
6
7
// Önce
function processData(data) {
    // JavaScript implementasyonu
}

// Sonra
// Aynı imzaya sahip Go WASM fonksiyonu

Desen 2: Class Migration

1
2
3
4
5
6
7
8
// JavaScript class yerine Go struct
type DataProcessor struct {
    config Config
}

func (p *DataProcessor) Process(data []byte) []byte {
    // İşleme mantığı
}

17. İzleme ve Gözlemlenebilirlik

17.1 Performans İzleme

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// WASM performans metriklerini takip et
class WASMMonitor {
    constructor() {
        this.metrics = {
            loadTime: 0,
            executionTimes: [],
            memoryUsage: [],
        };
    }

    trackLoadTime() {
        const start = performance.now();
        return () => {
            this.metrics.loadTime = performance.now() - start;
            this.reportMetrics();
        };
    }

    trackExecution(functionName, fn) {
        return (...args) => {
            const start = performance.now();
            const result = fn(...args);
            const duration = performance.now() - start;
            
            this.metrics.executionTimes.push({
                function: functionName,
                duration,
                timestamp: Date.now(),
            });
            
            return result;
        };
    }

    reportMetrics() {
        // Analytics servisine gönder
        fetch('/api/metrics', {
            method: 'POST',
            body: JSON.stringify(this.metrics),
        });
    }
}

17.2 Sentry ile Hata Takibi

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
	"syscall/js"
)

func reportError(err error, context map[string]interface{}) {
	js.Global().Call("Sentry", map[string]interface{}{
		"captureException": err.Error(),
		"setContext":      context,
	})
}

// Kullanım
func processData(data []byte) error {
	if err := validate(data); err != nil {
		reportError(err, map[string]interface{}{
			"function": "processData",
			"dataSize": len(data),
		})
		return err
	}
	return nil
}

17.3 Analytics Entegrasyonu

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
func trackEvent(eventName string, properties map[string]interface{}) {
	js.Global().Call("analytics", map[string]interface{}{
		"track": eventName,
		"properties": properties,
	})
}

// Kullanım
func processImage() {
	start := time.Now()
	// Görüntüyü işle
	duration := time.Since(start)
	
	trackEvent("image_processed", map[string]interface{}{
		"duration_ms": duration.Milliseconds(),
		"image_size":   len(imageData), // Örnek: gerçek görüntü boyutunu kullan
	})
}

18. Maliyet Analizi

18.1 Geliştirme Maliyetleri

Zaman Yatırımı:

  • İlk kurulum: 2-4 saat
  • Öğrenme eğrisi: 1-2 hafta (Go başlayanlar için)
  • Migration: 1-2 hafta (mevcut kod için)
  • Test ve optimizasyon: 1 hafta

Ekip Gereksinimleri:

  • Go geliştiricisi (veya Go öğrenen)
  • WASM’a aşina frontend geliştiricisi
  • Cross-browser test için QA

18.2 Bakım Yükü

Devam Eden Maliyetler:

  • Go versiyon güncellemeleri
  • Tarayıcı uyumluluk testi
  • Performans izleme
  • Hata düzeltmeleri ve optimizasyonlar

Tahmini: Çeyrek başına ilk geliştirme zamanının %10-20’si

18.3 Altyapı Maliyetleri

CDN Maliyetleri:

  • WASM binary depolama: ~$0.01 per GB
  • Bant genişliği: ~$0.05 per GB
  • Örnek: 1MB WASM, 100K kullanıcı/ay = ~$5/ay

Karşılaştırma:

  • Sunucu İşleme: $50-500/ay (kullanıma bağlı)
  • WASM (İstemci tarafı): $5-20/ay (sadece CDN)
  • Tasarruf: Sunucu maliyetlerinde %70-95 azalma

18.4 Bundle Boyutu vs Performans Trade-off

Yaklaşım Bundle Boyutu Performans Maliyet
Saf JavaScript 50 KB Baseline Düşük
Go WASM (Standard) 2-3 MB 2-3x daha hızlı Orta
Go WASM (TinyGo) 200-500 KB 2-3x daha hızlı Düşük
Hybrid (JS + WASM) 300-800 KB 1.5-2x daha hızlı Düşük

Öneri: Boyut ve performansı dengelemek için production’da TinyGo kullanın.


19. Alternatif Araçlar ve Runtime’lar

19.1 Wasmer

Wasmer, sunucu tarafı çalıştırma için bağımsız bir WebAssembly runtime’ıdır.

1
2
3
4
5
# Wasmer kurulumu
curl https://get.wasmer.io -sSfL | sh

# WASM modülünü çalıştır
wasmer run main.wasm

Kullanım Senaryoları:

  • Sunucu tarafı WASM çalıştırma
  • Plugin sistemleri
  • Sandbox kod çalıştırma

19.2 Wasmtime

Wasmtime, küçük, hızlı ve güvenli bir WebAssembly runtime’ıdır.

1
2
3
4
5
# Wasmtime kurulumu
curl https://wasmtime.dev/install.sh -sSf | bash

# WASM modülünü çalıştır
wasmtime main.wasm

Kullanım Senaryoları:

  • Edge computing
  • Serverless fonksiyonlar
  • Microservices

19.3 WASM Paket Yöneticileri

WAPM (WebAssembly Package Manager):

1
2
3
4
5
6
7
8
# WAPM kurulumu
curl https://get.wapm.io/install.sh -sSfL | sh

# Paket kurulumu
wapm install package-name

# Paketi çalıştır
wapm run package-name

19.4 Geliştirme Araçları Ekosistemi

Araçlar:

  • wasm-pack: WASM paketlerini derle ve yayınla
  • wasm-bindgen: Rust/Go ve JavaScript arasında binding’ler oluştur
  • wasm-opt: WASM binary’lerini optimize et (Binaryen’den)
  • wasm2wat: Hata ayıklama için WASM’ı metin formatına dönüştür

20. Kullanım Senaryoları ve Örnekler

20.1 Veri Görselleştirme

  • Gerçek zamanlı grafik renderlama
  • Büyük veri seti işleme
  • Matematiksel hesaplamalar

20.2 Oyunlar

  • 2D/3D oyun motorları
  • Fizik simülasyonları
  • Oyun mantığı işleme

20.3 Kriptografi

  • İstemci tarafı şifreleme
  • Hash hesaplamaları
  • Dijital imzalar

20.4 Medya İşleme

  • Görüntü filtreleri ve efektler
  • Ses işleme
  • Video encode/decode

21. Production Hazırlık Kontrol Listesi

Go WASM uygulamanızı production’a dağıtmadan önce aşağıdaki kontrol listesini tamamladığınızdan emin olun:

Binary Optimizasyonu

  • Binary boyutu optimize edildi (< 500KB tercihen TinyGo ile)
  • Build tag’leri ile kullanılmayan kod kaldırıldı
  • Dead code elimination etkinleştirildi (-ldflags="-s -w")
  • wasm-opt -Oz ile WASM optimize edildi
  • Sıkıştırma etkinleştirildi (gzip/brotli)

Performans

  • İlk yükleme süresi < 3 saniye
  • First contentful paint < 1.5 saniye
  • JavaScript-WASM sınır çağrıları minimize edildi
  • Bellek kullanımı izlendi ve optimize edildi
  • Performans benchmark’ları tamamlandı
  • Ağır görevler için Web Workers uygulandı (gerekirse)

Güvenlik

  • Girdi doğrulama uygulandı
  • XSS koruması yerinde
  • Content Security Policy (CSP) header’ları ayarlandı
  • CORS header’ları doğru yapılandırıldı
  • Bellek güvenlik kontrolleri uygulandı
  • Hata mesajları hassas bilgi sızdırmıyor

Altyapı

  • WASM dosyaları için CDN yapılandırıldı
  • Doğru MIME tipi (application/wasm) ayarlandı
  • Cache header’ları yapılandırıldı (uzun vadeli cache)
  • Sunucuda sıkıştırma etkinleştirildi
  • HTTP/2 veya HTTP/3 etkinleştirildi
  • İzleme ve uyarı sistemi kuruldu

Test

  • Birim test coverage > %80
  • Entegrasyon testleri geçiyor
  • Tarayıcı uyumluluk testi yapıldı (Chrome, Firefox, Safari, Edge)
  • Mobil tarayıcı testi tamamlandı
  • Performans testleri geçiyor
  • Bellek sızıntısı testleri tamamlandı
  • Hata yönetimi testleri yerinde

Hata Yönetimi

  • Hata takibi uygulandı (Sentry, vb.)
  • WASM crash’leri yakalanıyor ve loglanıyor
  • JavaScript’e geri dönüş uygulandı
  • Kullanıcı dostu hata mesajları
  • Hata kurtarma mekanizmaları yerinde

Dokümantasyon

  • API dokümantasyonu tamamlandı
  • Deployment rehberi yazıldı
  • Troubleshooting rehberi mevcut
  • Performans optimizasyon rehberi dokümante edildi
  • Kod yorumları ve örnekler eklendi

İzleme

  • Performans metrikleri takip ediliyor
  • Hata oranları izleniyor
  • Bellek kullanımı izleniyor
  • Yükleme süresi takip ediliyor
  • Kullanıcı analytics entegre edildi
  • Kritik sorunlar için uyarılar yapılandırıldı

Tarayıcı Desteği

  • Chrome 57+ test edildi
  • Firefox 52+ test edildi
  • Safari 11+ test edildi
  • Edge 16+ test edildi
  • Mobil tarayıcılar test edildi
  • Desteklenmeyen tarayıcılar için geri dönüş

Kod Kalitesi

  • Kod review yapıldı
  • Linting geçti
  • Bellek sızıntısı tespit edilmedi
  • Goroutine’ler düzgün yönetiliyor
  • JavaScript değerleri düzgün serbest bırakılıyor
  • Tip güvenliği zorunlu

Dağıtım

  • CI/CD pipeline yapılandırıldı
  • CI’da otomatik test
  • Staging ortamı test edildi
  • Rollback planı hazırlandı
  • Deployment dokümantasyonu tamamlandı

22. Örnek Projeler ve Kaynaklar

Açık Kaynak Go WASM Projeleri

Go WASM ile ilgili açık kaynak projeleri ve örnekleri araştırmak için GitHub’da şu terimlerle arama yapabilirsiniz:

  • go wasm - Genel Go WASM projeleri
  • golang webassembly - Go WebAssembly uygulamaları
  • tinygo wasm - TinyGo ile WASM projeleri

Popüler kategoriler:

  • Görüntü işleme kütüphaneleri
  • Oyun motorları
  • Kriptografi araçları
  • Veri görselleştirme kütüphaneleri

Öğrenme Kaynakları

Resmi Dokümantasyon:

Eğitim İçerikleri:

  • YouTube’da “Go WebAssembly” veya “Go WASM” aramaları ile video tutoriallar
  • WebAssembly topluluğu tarafından paylaşılan öğretici içerikler

Topluluk:


23. Sonuç: Go WASM Ne Zaman Kullanılmalı?

Go’nun WebAssembly desteği, web geliştirme için heyecan verici imkanlar açıyor. Go kodunu WASM’a derleyerek, tarayıcıda Go’nun tip güvenliği, mükemmel araçları ve performans özelliklerinden yararlanabilirsiniz. Ancak projeniz için doğru teknolojiyi seçmek çok önemlidir.

Go WASM Ne Zaman Kullanılmalı?

✅ Go WASM kullanın:

  1. Mevcut Go kod tabanınız varsa

    • Masaüstü/sunucu Go uygulamalarını web’e taşıma
    • Kod yeniden kullanımı öncelik
    • Ekip zaten Go biliyor
  2. CPU yoğun hesaplamalar

    • Görüntü/video işleme
    • Veri analizi ve dönüşümleri
    • Kriptografik işlemler
    • Bilimsel hesaplama
  3. Performans kritik

    • JavaScript’ten 2-3x hızlanmaya ihtiyaç
    • Büyük veri setlerini işleme
    • Gerçek zamanlı hesaplamalar
  4. Tip güvenliği önemli

    • Karmaşık iş mantığı
    • Finansal hesaplamalar
    • Veri doğrulama
  5. Daha büyük binary boyutlarını kabul edebilirsiniz

    • Standard Go: 2-3 MB (birçok uygulama için kabul edilebilir)
    • TinyGo: 200-500 KB (iyi bir denge)

❌ Go WASM kullanmayın:

  1. Basit DOM manipülasyonu

    • JavaScript daha basit ve hızlı
    • Performans avantajı yok
  2. Bundle boyutu kritik

    • Mobil-öncelikli uygulamalar
    • < 100 KB bundle’a ihtiyaç
    • Rust veya saf JavaScript düşünün
  3. Sık JavaScript interop

    • Ağır DOM manipülasyonu
    • Sıkı framework entegrasyonu
    • JavaScript sınır ek yükü faydaları olumsuz etkiliyor
  4. Hızlı prototipleme

    • JavaScript iterasyon için daha hızlı
    • Go derlemesi sürtünme yaratıyor

Go WASM vs Rust WASM vs JavaScript

Kriter Go WASM Rust WASM JavaScript
Binary Boyutu 200KB-3MB 50-200KB 10-50KB
Performans 2-3x JS 3-5x JS Baseline
Öğrenme Eğrisi Orta Dik Kolay
Araçlar Mükemmel İyi Mükemmel
Ekosistem Büyük Büyüyor Çok Büyük
Tip Güvenliği Güçlü En Güçlü Zayıf
Bellek Güvenliği İyi Mükemmel İyi
En İyi Mevcut Go kodu, dengeli ihtiyaçlar Maksimum performans, minimal boyut Çoğu web uygulaması

Deneyime Dayalı Önerim:

  • Go WASM seçin eğer zaten Go kullanıyorsanız, iyi performansa ihtiyacınız varsa ve 200KB+ bundle’ları kabul edebiliyorsanız. Geliştirici deneyimi mükemmel ve kod yeniden kullanımı değerli.

  • Rust WASM seçin eğer maksimum performansa, en küçük binary boyutuna ihtiyacınız varsa veya performans kritik library’ler inşa ediyorsanız. Öğrenme eğrisi daha dik ama sonuçlar etkileyici.

  • JavaScript seçin çoğu web uygulaması için. V8 optimizasyonlarıyla modern JavaScript, kullanım durumlarının %90’ı için yeterince hızlıdır. WASM’ı yalnızca gerçek bir performans darboğazı tespit ettiğinizde düşünün.

Gerçek Dünya Karar Çerçevesi

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// Karar ağacı
if hasExistingGoCode && needsPerformance {
    return "Go WASM"
} else if needsMaxPerformance && sizeCritical {
    return "Rust WASM"
} else if simpleApp || rapidPrototyping {
    return "JavaScript"
} else if cpuIntensive && canAcceptSize {
    return "Go WASM (TinyGo)"
} else {
    return "JavaScript + Optimize"
}

Go WASM’ın Geleceği

Go’nun WebAssembly desteği gelişmeye devam ediyor:

  • TinyGo’da daha iyi optimizasyon
  • Daha küçük binary boyutları
  • Gelişmiş JavaScript interop
  • Daha iyi hata ayıklama araçları
  • Sunucu tarafı WASM için WASI desteği

Ekosistem olgunlaşıyor ve Go WASM daha fazla kullanım durumu için uygun bir seçenek haline geliyor.

Son Düşünceler

Go WASM, web geliştirme cephanenizde güçlü bir araçtır. Gümüş kurşun değildir, ancak uygun şekilde kullanıldığında önemli faydalar sağlayabilir:

  • Performans: CPU yoğun görevler için JavaScript’ten 2-3x daha hızlı
  • Kod Yeniden Kullanımı: Mevcut Go kod tabanlarından yararlanın
  • Tip Güvenliği: Hataları derleme zamanında yakalayın
  • Geliştirici Deneyimi: Mükemmel araçlar ve ekosistem

Ancak, optimize etmeden önce her zaman ölçün. Birçok uygulama WASM’a ihtiyaç duymaz ve JavaScript genellikle pragmatik seçimdir. Açık bir performans gereksiniminiz veya yararlanabileceğiniz mevcut Go kodunuz olduğunda Go WASM kullanın.

Ana Çıkarımlar

  1. WebAssembly yüksek performanslı web uygulamalarını mümkün kılar
  2. Go, WASM geliştirme için mükemmel araçlar sağlar
  3. Spesifik ihtiyaçlarınız için doğru aracı seçin
  4. Optimize etmeden önce performansı ölçün
  5. Farklı tarayıcılar ve cihazlarda kapsamlı test edin

Sonraki Adımlar

  • Küçük başlayın: Belirli bir performans kritik fonksiyon için basit bir Go WASM modülü oluşturun
  • Ölçün: Faydaları doğrulamak için kullanım durumunuzu benchmark edin
  • Optimize edin: TinyGo, wasm-opt ve en iyi uygulamaları kullanın
  • İterasyon yapın: Production deneyiminden öğrenin ve yaklaşımınızı geliştirin

Unutmayın: En iyi teknoloji seçimi, geliştirici verimliliğini ve kullanıcı deneyimini korurken sorununuzu etkili bir şekilde çözen seçimdir.


Go ve WebAssembly ile mutlu kodlamalar! 🚀


Hızlı Referans

Temel Komutlar:

1
2
3
4
5
6
7
8
# WASM derle
GOOS=js GOARCH=wasm go build -o main.wasm main.go

# TinyGo ile derle
tinygo build -target wasm -o main.wasm main.go

# Optimize et
wasm-opt -Oz main.wasm -o main.optimized.wasm

Önemli Kaynaklar: