Yazılımcı Masalları

Masal 2

İki ev, bir avlu

İki uygulama aynı repoda mı yaşamalı, ayrı repolarda mı? Katmanya’da, Çarşı katında geçiyor. Kod var; kodu okumadan da masal takip edilir.

Merhaba, ben Kaşif Oğuz. Çarşı’da iki komşu ev buldum. Aralarına duvar mı örelim, avlu mu açalım?

Önce şunu oku Script yerini bilir mi?
Kaydır, sayfa çevrilsin

Bir ev, bir de küçüğü.

Çarşı’da büyük bir ev var: Uygulama Evi. Burada bir web uygulaması yapılıyor. Her akşam kapısından paketler çıkıyor, merdivenden yukarı, Evler’e taşınıyor.

Uygulamayı test etmek için küçük bir yardımcı lazım oldu: tarayıcıya kurulan bir eklenti. Butonlara basacak, sayfayı dolduracak, sonucu yazacak. Onun için de küçük bir ev kurulacak: Eklenti Evi.

Küçük ev büyüğünü çok iyi tanımalı. Hangi düğmenin nerede olduğunu, hangi ayarın ne işe yaradığını bilmeli.

Bu iki ev yan yana mı dursun, yoksa ayrı sokaklarda mı?

Komşular neden kopar?

Büyük ev bir gün bir düğmenin adını değiştiriyor. Küçük ev bunu duymazsa ertesi gün yanlış düğmeyi arıyor. Testler kırmızıya dönüyor, oysa uygulama bozuk değil, eklenti eski.

Evler ayrı sokaklardaysa haber geç ulaşıyor. Birinde yapılan değişiklik öbürüne ayrı bir iş olarak taşınmak zorunda.

Bu yüzden ilk sorduğum soru “hangi araç?” değil. İlk soru şu:

Bu iki ev ne sıklıkla birlikte değişiyor?

Her hafta birlikte değişiyorlarsa yan yana durmaları işe yarar. Yılda bir kez birlikte değişiyorlarsa ayrı durmaları daha az yük getirir.

Üç basamaklı merdiven.

Yan yana durmanın tek bir yolu yok. Üç basamak var, alttan üste.

Klasör: küçük ev, büyük evin içinde bir oda olur. Workspace: iki ev ayrı kalır ama aynı avluyu paylaşır. Monorepo aracı: avlunun kapısına bir bekçi kulübesi kurulur, kimin ne zaman çalışacağını o düzenler.

Her basamak dizin yapısını, kurulumu ve deploy akışını biraz daha değiştirir. Basamak çıkmanın maliyeti var.

Kendime koyduğum kural:

Bir üst basamağa ancak alttaki yetmediğinde çık.

Birinci basamak: bir oda.

En ucuz yol, eklentiyi büyük evin içinde bir klasöre koymak. Repo tek, package.json tek, kurulum tek komut.

Ama evin tek Çekmece Kaplumbağası var ve onun scripts çekmecesi doldukça doluyor. Uygulama ile eklentinin build akışları birbirine benzemiyor; her biri kendi satırlarını istiyor.

"scripts": {
  "dev": "vite",
  "build": "vite build",
  "dev:eklenti": "node scripts/dev-eklenti.js",
  "build:eklenti": "node scripts/build-eklenti.js",
  "test:eklenti": "node scripts/test-eklenti.js"
}

Bir şeye daha dikkat etmek gerek: uygulamanın paketine eklentinin kodu karışmamalı. Oda evin içinde ama eşyası ayrı kolide gitmeli. Bu basamak, scripts çekmecesi kapanmaz hale gelene kadar yeter.

Bu sahnedeki yaratık Çekmece Kaplumbağası

İkinci basamak: avlu.

İkinci basamakta küçük ev büyüğün içinden çıkar, yanına taşınır. İkisinin arasında bir avlu açılır. Avlu repodur. Her evin kendi kaplumbağası olur, yani kendi package.json’u. Her biri kendi scripts çekmecesini taşır, çekmeceler yeniden ferahlar.

Avlunun kapısında da bir kaplumbağa durur: kök package.json. Onun workspaces çekmecesinde bir Sıfır Treni var. Trenin vagonunda Boncuk Örümceği’nin ördüğü bir ip duruyor: packages/*. Bu ip “packages klasöründeki her ev bu avluya ait” demek.

{
  "name": "avlu",
  "private": true,
  "workspaces": ["packages/*"]
}

Yapı şöyle görünür: packages/uygulama ve packages/eklenti, her birinin içinde kendi package.json’u.

Bu sahnedeki yaratık Sıfır Treni Bu sahnedeki yaratık Boncuk Örümceği

Kurulum Ustası.

Avluya bir usta gelir: Kurulum Ustası, yani npm. Ona kökte npm install dersin.

Usta kapıdaki kaplumbağanın trenine bakar, iki evi bulur. Bağımlılıkları kurar, kökteki node_modules klasörüne her eve giden bir kısayol (symlink) koyar. Kilit defteri tek olur: kökte bir package-lock.json. Tek bir eve iş vermek için -w bayrağı var, --workspace’in kısa adı.

npm install                    # kökten, iki ev birden
npm run build -w eklenti       # yalnız Eklenti Evi
npm run build --workspaces     # her ev kendi build'ini çalıştırır

Bu basamağın asıl kazancı ustanın değişmemesi. Yeni gelen biri yine kökte npm install diyor. Deploy akışı yine npm’i çağırıyor.

pnpm’in de kendi workspace’i var, ama o başka bir usta: kurulum komutu pnpm install olur, kilit defteri pnpm-lock.yaml olur. Ustayı değiştirmek, kurulumu ve deploy akışını da değiştirmek demek.

Üçüncü basamak: bekçi kulübesi.

Ev sayısı artınca avlu kalabalıklaşır. Turborepo ya da Nx gibi bir monorepo aracı avlunun kapısına bir bekçi kulübesi kurar.

Bekçi evlerin birbirine bağımlılığına bakar, işleri doğru sırayla başlatır. Bir evin sonucunu saklar; o ev değişmediyse işi yeniden yaptırmaz.

On evli bir mahallede bu çok zaman kazandırır. İki evli bir avluda ise yeni bir dosya, yeni komutlar ve öğrenilecek yeni bir düzen getirir. Kazanç küçük, yük büyük olabilir.

Kulübeyi kurmanın zamanı, bekleme süresi gerçekten can sıktığında gelir.

Sepetli Okur.

Bu evlerde çalışırken yanımda yapay zekâ asistanı var. Ben ona Sepetli Okur diyorum: ona hangi evi gösterirsem oradaki kâğıtları sepetine koyup okuyor.

Avlu büyüdükçe sepete giren kâğıt artar. Asistanı avlunun kapısında başlatırsam iki evin de kâğıtlarını görebilir. Okuduğu bağlam büyür, işi yavaşlar, ilgisiz bir kâğıda takılabilir.

Ama ters taraf da var. Evler ayrı sokaklarda dursa bile ikisini birbirine uygun tutmak için asistana iki evi de göstermem gerekecek. Yani bağlamın maliyeti iki yolda da var.

Avluda bunu yönetmenin bir yolu var: asistanı tek bir evin kapısında başlatırım, öbür eve yalnızca gerektiğinde götürürüm.

Önce deneme, sonra karar.

Bu tartışma konuşarak bitmiyor. Herkesin daha önce sıkıldığı bir monorepo var, herkesin haklı bir korkusu var.

Bu yüzden bir dalda küçük bir avlu kuruyorum: iki ev, bir kök kaplumbağa, bir usta. Sonra şu soruları soruyorum. Kurulum hâlâ tek komut mu? Deploy akışında ne değişti? Bir hafta içinde kaç değişiklik iki evi birden etkiledi? Asistan ne kadar okudu?

Cevaplar iyiyse avlu kalır. Kötüyse dalı silerim, evler eskisi gibi ayrı durur. Denemeyi geri almak ucuz. Bu masaldan aklımda kalan:

Doğru cevap yok, eşikler var. Hangi eşikte olduğunu bilen, hangi basamakta duracağını da bilir.

Dürüst not.

Bu masal bir araç önermiyor. Basamağı değiştiren şeyler şunlar: iki evin birlikte değişme sıklığı, scripts çekmecesinin büyüklüğü, ev sayısı, bekleme süresi, asistanın okuduğu bağlam. Bu eşiklerin sayısını bilmiyoruz; her ekip kendi denemesiyle bulur.

Masaldaki npm davranışını kendimiz denedik (npm 10.9.8, boş iki paketli bir avlu): kökten npm install iki kısayol açtı, -w tek paketi, --workspaces ikisini çalıştırdı. Gerçek bir uygulamayla, gerçek bir deploy akışıyla denemedik.

Workspace’e geçmek klasör yollarını değiştirir. Deploy akışı aynı ustayı çağırsa da yolları güncellemek gerekebilir; “korur” değil, “daha az değiştirir” demek doğru. Monorepo aracının yükü “büyük olabilir” diye yazıldı, ölçülmedi. Bazı ekipler iki pakette de araçtan memnun kalıyor.

Asistanın bağlamı ne kadar büyüttüğünü ölçmedik; sepet benzetmesi yönü anlatıyor, miktarı değil. Kaynak bir konuşma notu. Karar henüz verilmedi, deneme yapılacak.

Sıra sende

Elinde birbirine bağlı iki proje var mı? Son 20 değişikliğe bak: kaçında ikisi birden değişti?

git log --name-only -20

Bu komut her değişikliğin dokunduğu dosyaları gösterir. Sayı yüksekse avlu düşün, düşükse duvar da iş görür.

Senin evlerin ne sıklıkla birlikte değişiyor?

Kaynak notu: npm belgeleri, npm help workspaces ve npm help package-json (workspaces alanı). Masalın kararları bir iş notundan arındırılarak alındı; kişi, kurum ve ürün adı yok, örnek kurgusal.

Fikirler ve hikâyeler Oğuz’dan. Metinleri ve çizimleri yapay zekâyla birlikte üretiyoruz; her sayfayı Oğuz okuyup onaylıyor. Bir DemirCraftCo işi.

Başa dön