Tek mimari kuralı, üç dil: archlint artık Go + TypeScript + Python
Polyglot bir repoda 'domain altyapıyı import etmesin' kuralı her dilde aynı; değişen, import'un nasıl çözüldüğü. archlint'e TypeScript ve Python ekledim — tek architecture.json üç dilin sınırlarını CI'da zorluyor.
archlint’i ilk yazdığımda sadece Go biliyordu. Ama tipik bir sistem tek dil değil: Go API, TypeScript frontend, Python worker’ları. Üçünde de aynı mimari niyet var — “domain katmanı altyapıyı import etmesin” — ama o kuralı üç dilde birden zorlayan tek bir araç yoktu. Şimdi archlint üçünü de yönetiyor, tek bir architecture.json ile.
Sınır dile bağlı değil; sözdizimi bağlı
Katman düzeyinde kural her dilde aynıdır: domain → db yasak. Diller arasında değişen şey kuralın kendisi değil, import’un nasıl yazıldığı ve hangi dosyaya çözüldüğü:
- Go: mutlak paket yolu —
github.com/acme/app/internal/db. Çözüm: modül-prefix’ini sıyır →internal/db. - TypeScript: göreli (
../db/repo) ya da alias (@/db/repo). Çözüm: göreliyi dosyanın konumuna, alias’ıtsconfigyoluna göre çöz. - Python: noktalı + göreli —
from ..db.repo import find_order. Çözüm: göreli noktaları dosyanın paketine göre yukarı çık, sonra modülü yola çevir.
archlint hepsini tek bir şeye indirger: repo-göreli bir yol → bir katman. O noktadan sonra motor aynı: “bu dosya hangi katmanda, bu import hangi katmana gidiyor, kural izin veriyor mu?”
Tek config, karışık repo
İşin güzel yanı: aynı dosya üç dilli bir monorepo’yu birden yönetebiliyor. Katman adları ortak, yollar dile özel:
{
"module": "github.com/acme/app",
"aliases": { "@/": "web/src/" },
"layers": {
"domain": ["internal/domain", "web/src/domain", "workers/app/domain"],
"infra": ["internal/infra", "web/src/infra", "workers/app/infra"]
},
"rules": { "domain": [], "infra": ["domain"] }
}
domain katmanı üç serviste de var (Go internal/, TS web/src/, Python workers/app/) ve hiçbirinde altyapıyı import edemez. Tek kural, üç dil, tek CI kapısı.
Nasıl çalışıyor: dil-eklenebilir mimari
İçeride bir Language arayüzü var: her dil yalnızca iki şeyi bilir — bir dosyanın import’larını çıkarmak ve bir import’u repo-göreli yola çözmek. Linter’ın geri kalanı dil-agnostik. Yeni bir dil eklemek = yeni bir Language implementasyonu.
Disiplin aynen korundu: tree-sitter (CGo, ağır bağımlılık) yerine, Go’yu stdlib go/parser ile (kesin), TS ve Python’ı regex tarayıcılarla okuyorum. Dürüst sınır: bunlar tam parser değil — yorum ya da string içindeki import-benzeri bir satır false-positive olabilir. README’de açıkça yazıyor.
Denemek için: üç örnek
Her biri kasıtlı bir ihlal içeriyor:
archlint check examples/sample # Go → internal/domain/bad.go
archlint check examples/ts-sample # TS → src/domain/bad.ts ("@/" alias çözülür)
archlint check examples/py-sample # Python → app/domain/bad.py ("..db.repo" çözülür)
Üçü de aynı çıktıyı verir: domain → db is not allowed, exit 1, CI kırmızı.
Bunun neden bir wiki sayfasından daha iyi olduğunu sade.dev’de ayrı yazdım: yazılı bir mimari karar, onu her commit’te kontrol eden bir şey olmadan çürür. Şimdi o “şey” üç dilde birden çalışıyor. Sıradaki sınır hangi dil olsun istersen — yaz, sıraya koyayım.
Yorumlar
Yorum yapmak için GitHub hesabınızla giriş yapmanız yeterli. Yorumlar GitHub Discussions üzerinde saklanır.