Trunk based development nedir? Küçük ekipler için rehber

Summary

Trunk based development, ekibin kodunu kısa ömürlü dallar üzerinden en az günde bir kez tek bir paylaşılan dala birleştirdiği bir modeldir. Tamamlanmamış işler feature flag arkasında gizlenir, böylece trunk her an yayınlanabilir kalır. Küçük ekipler için uzun dalların biriktirdiği çakışma borcunu azaltır. Başlamak için açık dalları listeleyin, bir flag mekanizması ekleyin ve işleri bir günde bitecek parçalara bölün. Yöntem mükemmel değildir, ama günlük hayatta işe yarar.

Tek bir dikey çizgi gösteren koyu bir masa ekranı, tek paylaşılan trunk metaforu

Trunk based development nedir? Ekibin herkesi tek bir paylaşılan dala, genelde main ya da trunk adını verdiğiniz dala, en az günde bir kez küçük değişiklikler birleştirdiği bir dallanma modelidir. Dal kullanacaksanız bu dallar haftalarca değil, saatlerce yaşar. Tamamlanmamış iş bir feature flag arkasında gizlenerek yayına girer ve trunk her commit'te yayınlanabilir durumda kalır. Fikrin özü bu. Adı kulağa egzotik gelse de yaptığı iş oldukça sade.

Şöyle düşünün. Üç hafta önce bıraktığınız bir yan projeyi açıyorsunuz. Özellik dalınız main'in 41 commit gerisinde, iki dosyada çakışma var ve üzerinde çalıştığınız kod artık etrafındaki kodla uyuşmuyor. Trunk based development, bu sahnenin yaşanmasını engelleyen alışkanlıktır.

Trunk based development aslında ne demek?

Trunk based development, geliştiricilerin tek bir paylaşılan dal üzerinde çalıştığı ve başka uzun ömürlü geliştirme dallarından kaçındığı bir kaynak kodu yönetimi modelidir. trunkbaseddevelopment.com referans sitesi modeli bu şekilde tanımlar. Çok küçük ekiplerde trunk'a doğrudan commit atmak sorun değildir. Pull request kullanmak da uygundur, yeter ki özellik dalları kısa ömürlü olsun ve tek bir çalışma akışından gelsin.

Üç kural modelin ağırlığının büyük kısmını taşır.

Eksik olan şeylere bakın. Ayrı bir develop dalı yok, her özellik için uzun bir release dalı yok ve sonunda herkesin kodun birbirine uymadığını öğrendiği bir entegrasyon aşaması yok. Eski modellerde asıl acı şurada: sorunlar biriktirilir ve hepsi bir anda ödenir. Kimse bunu bilerek seçmez, ama dallar uzadıkça bu faturanın büyüdüğünü fark etmek zorunda kalırsınız.

Tek bir kalın gövdesi ve birkaç kısa dalı olan uzun bir ağaç

Küçük ekipler için neden uzun ömürlü dallardan daha iyi?

Uzun ömürlü dallar bir borç gibidir. Bir dal yaşadığı her gün main'den biraz daha uzaklaşır ve bu faiz merge çakışmaları, eskimiş varsayımlar ve diff'i 60 dosyaya dokunduğu için kimsenin bitiremediği review'lar olarak geri döner. Bir dalın üç haftalık olduğunu fark ettiğinizde, borç çoktan birikmiş olur.

DORA'nın trunk based development sayfası State of DevOps araştırmasına dayanarak üç pratiği daha iyi teslim hızı, kararlılık ve erişilebilirlikle ilişkilendirir. Depoda üçten az aktif dal bulundurun. Trunk'a günde en az bir kez birleştirin. Kod dondurmalarından ve entegrasyon aşamalarından kaçının. Bunlar ölçülebilir hedefler ve bu alanda pek rastlanmayan türden somut şeyler. Yine de bu verilerin eski bir araştırma dalgasına dayandığını akılda tutun ve kendi ekibinizde sonucu kendiniz ölçün.

Tek başına çalışan biri ya da üç kişilik bir ekip için argüman daha da basit. Küçük birleştirmeler kolay review edilir, kolay geri alınır ve altı ay sonra git blame ekranında "eski ben burada ne düşünüyordu?" diye baktığınızda da kolay anlaşılır. Büyük bir diff'i anlamaya çalışmak yerine tek bir commit'in amacını okumak yeter.

Bunu yapmak için üç neden var, yapmamak için bir neden var. Nedenler: daha küçük diff'ler, CI'dan daha hızlı geri bildirim ve cuma günü tereddütsüz deploy edebileceğiniz bir main. Yapmamak için neden ise şu: testleriniz zayıfsa, her gün birleştirmek hatayı sadece daha hızlı yayar. Buna aşağıda geri döneceğiz.

Bir de zihinsel bir kayma var. Uzun dallarda çalışan geliştirici, kodunu bir sunum gibi hazırlar: önce tamamlar, sonra gösterir. Trunk based development'ta ise kod küçük parçalar halinde ortaya çıkar ve herkes bunu her gün görür. Bu, yazılımın nasıl ilerlediğine dair görünürlüğü artırır. Ekipteki biri bozuk bir şey fark ettiğinde, bunu saatler ya da günler sonra değil, o gün öğrenir. Kimse kimseyi bekletmez, çünkü çalışan kod her zaman küçük bir adım uzaktadır.

Kısa ömürlü dal mı, yoksa doğrudan main'e commit mi?

İkisi de trunk based development sayılır. Fark, koda girmeden önce ne kadar güvenlik istediğinizde.

Tek başınıza ya da bir partnerle çalışıyorsanız, yerel build'iniz bir dakikadan kısa sürüyorsa ve testlerinize güveniyorsanız main'e doğrudan commit atmak işe yarar. Çoğu bağımsız geliştirici bunu zaten, adına bir şey demeden yapıyor. Bu, mevcut en hızlı döngüdür.

Kısa ömürlü dallar ve pull request'ler, ikinci ya da üçüncü bir kişi katıldığında ya da birleştirmeden önce CI'ın temiz bir checkout üzerinde çalışmasını istediğinizde anlam kazanır. Disiplin "kısa" kelimesinde saklı. Ertesi güne kalan bir dal, bıraktığınız modele şimdiden kayıyor demektir.

İşe yarayan pratik bir rutin:

Bir değişiklik bir günde bitmiyorsa çözüm daha uzun bir dal değil. Çözüm, değişikliği daha ince dilimlere ayırmak.

Yarım işi main'i bozmadan nasıl yayınlarsınız?

Bu soru çoğu insanı durdurur. Her gün birleştiriyorsanız, henüz var olmayan özelliklerin kodunu da birleştirmiş olursunuz. İki teknik bu sorunu çözer.

İlki feature flag. Yeni kod yolu birleştirilir ama kapalı tutulur, kullanıcılar onu hiç görmez. Flag, bir ortam değişkeninde duran boolean kadar basit olabilir:

const showNewCheckout = process.env.FEATURE_NEW_CHECKOUT === "true";

export function Checkout() {
  return showNewCheckout ? <NewCheckout /> : <OldCheckout />;
}

Yan proje için bu yeterlidir. Hedefleme, kademeli yayın ya da yeniden deploy etmeden bir acil durum anahtarı gerektiğinde ise yönetilen bir servis hakkını hak eder.

İkincisi branch by abstraction. Veritabanı istemcisi ya da ödeme sağlayıcısı değiştirmek gibi daha büyük değişikliklerde işe yarar. Eski uygulamanın önüne bir arayüz koyarsınız, yeni uygulamayı aynı arayüzün arkasında geliştirirsiniz, çağıranları parça parça taşırsınız ve sonra eskisini silersiniz. Her adım trunk'a küçük bir birleştirmedir ve hiçbir şey uzun bir dalda beklemez.

Açık ve kapalı durumdaki fiziksel anahtarlar, feature flag benzetmesi

Flag'lerle ilgili bir uyarı: flag'ler borçtur. Bir yıl kodda kalan flag, kılık değiştirmiş bir daldır. Her flag'e bir sahip ve bir kaldırma tarihi verin, özellik tamamen yayına girince de silin.

Bu modeli denemeden önce CI'ınızda ne olmalı?

Güvenlik ağı olmadan trunk based development sadece hızlı bozulmadır. Her gün birleştirme alışkanlığına geçmeden önce üç şey gerekir.

Bu üç şeyin hiçbiri pahalı değildir, ama hiçbirini atlamamak gerekir. Eksik olan bir parça, her gün yapılan birleştirmeyi bir risk olarak değil, bir kontrol olarak gösterir. Yani CI yoksa her merge bir zar atışına dönüşür. CI varsa aynı merge bir doğrulama adımı olur.

Statik analiz ucuz bir ek katmandır. Açık hatalar, güvenlik kokuları ve tekrar eden kod gibi bir grup sorunu, bir insan diff'i okumadan önce yakalar.

Tek review yapan kişiyseniz, riskli noktalara işaret eden araçlar daha da fazla işe yarar. Çünkü sürekli dokunduğunuz dosyanın bir karmaşaya dönüştüğünü size kimse söylemeyecek.

İlk gün ağır bir pipeline kurmanız gerektiği fikrinden vazgeçin. main'i kuran, lint'leyen, test eden ve deploy eden tek bir workflow dosyası gayet iyi bir başlangıçtır. Mükemmel değil, ama çalışıyor ve kurmaya değer. İlk çalışan sürüm budur, sonra sıkılaştırırsınız.

Release dalları, hotfix'ler ve hâlâ dikkat isteyen konular

Trunk based development release dallarını yasaklamaz. Bazı ekipler bir release'ten hemen önce trunk'tan bir dal açar, sertleştirir, yayınlar ve siler. Diğerleri trunk'tan doğrudan release yapar ve bir hata çıktığında ileriye doğru düzeltir. Sık deploy edilen bir web uygulaması için ileriye doğru düzeltme neredeyse her zaman daha basittir.

Mobil uygulamalar ve mağaza incelemesi yavaş olan her şey farklıdır. Orada, kullanıcıların elindeki sürümü yamalayabilmek için sürüm başına kısa ömürlü bir release dalı tutabilirsiniz. Yine de kural geçerlidir: düzeltmeler önce trunk'a girer, sonra cherry-pick ile release dalına taşınır. Tersi asla olmaz.

Gece bir kafe masasında koyu kod editörü açık bir laptop

Hotfix'ler de aynı mantığı izler. trunk'ta düzeltin, deploy edin, bitti. Hiç geri birleştirilmeyen ayrı bir hotfix dalı, iki ayrı geçmişin ortaya çıkmasının yoludur.

Uygulamada en sık görülen hata, acil bir düzeltmenin release dalında yapılıp trunk'a hiç taşınmamasıdır. Bir sonraki sürümde aynı hata geri gelir ve kimse neden olduğunu hemen anlayamaz. Bu yüzden her hotfix için küçük bir kontrol listesi işinize yarar: düzeltme trunk'a girdi mi, test eklendi mi, release dalına doğru taşındı mı. Üç maddelik bu liste, iki haftada bir yaşanan bir karışıklığı önler.

Gerçekçi bir ilk hafta

İlk gün, reponun bugün nasıl dallandığına bakın. Açık dalları listeleyin ve her birinin yaşını not edin. Birkaç günden eski olanlar birleştirilmek ya da silinmek için adaydır. Bu tek başına sürtünmenin nerede olduğunu çoğu zaman gösterir.

İkinci gün flag mekanizmasını ekleyin. Bir ortam değişkeni bile yeterlidir. Devam eden bir özelliği seçin, giriş noktasını bu flag'in arkasına koyun ve elinizdeki kısmı birleştirin.

Üçüncü ila beşinci günler alışkanlığı değiştirin. Her işi bir günde inebilecek parçalara bölün ve CI geçtiğinde her parçayı birleştirin. İlk parçaların çok küçük gelmesini bekleyin. Öyle değiller. Uykuda bekleyen bir veritabanı kolonu ya da kullanılmayan bir fonksiyon commit'i, güvenli, review edilmiş ve zaten entegre olduğu için iyi bir ilerleme birimidir.

Haftanın sonunda iki şeyi bileceksiniz: testlerinize yeterince güvenip güvenmediğinizi ve kodunuzun hangi kısımlarının küçük değişikliklere direnç gösterdiğini. İkisi de faydalıdır ve ikisi de uzun dallarda çalışırken görünmez.

Bunu anlamak için dashboard'a ihtiyacınız yok. Dalların ne kadar yaşadığına, main'in ne sıklıkla kırmızı olduğuna ve bir değişikliğin ilk commit'ten üretime kadar ne kadar sürdüğüne bakın. Dal yaşı azalıyorsa ve deploy'lar sıkıcı hale geliyorsa, alışkanlık işe yarıyor demektir.

Flag'lerin arkasındaki özelliklerin kullanıcıya etkisini ölçmek istiyorsanız, bir deney aracı yayını gerçek metriklerle ilişkilendirebilir. Tahmin yürütmek yerine veriye bakarsınız.

Tek kişilik bir ekip için düz bir defter de işe yarar. Bir ay boyunca her hafta merge-to-deploy süresini yazın. Trend, tek bir sayıdan daha fazla şey anlatır.

Geçmeli misiniz, yoksa beklemeli misiniz?

Tek başınızda, bir partnerle ya da güvenmediğiniz ama geliştirebileceğiniz testleri ve CI'si olan küçük bir ekipte çalışıyorsanız geçin. Denemenin maliyeti bir hafta biraz rahatsız edici küçük commit'lerdir. Uzun dallarda kalmanın maliyeti ise çakışmalarla ve yavaş review'larla ödenir ve her yeni katkıda bulunanla birlikte büyür.

Hiç otomatik testiniz yoksa ve geri alma yolunuz yoksa bekleyin. Önce bunu düzeltin, çünkü test edilmemiş bir trunk'a her gün birleştirme yapmak acıyı sadece başka yere taşır.

Bu mükemmel bir yöntem değil. Ama işe yarar bir yöntem. Mevcut projenizde bir sonraki küçük değişikliği seçin, bugün birleştirin ve nasıl hissettirdiğine bakın. Bu gece yayına girebilecek en küçük dilim hangisi?

Frequently asked questions

Trunk based development ile GitFlow arasındaki temel fark nedir?
GitFlow develop, uzun release ve feature dalları kullanır. Trunk based development ise tek bir paylaşılan dalı ve kısa ömürlü dalları tercih eder. Birleştirme sıklığı ve dalların yaşı iki model arasındaki en belirgin farktır.
Her gün trunk'a birleştirmek zorunda mıyım?
Zorunlu değilsiniz, ama DORA araştırması günde en az bir birleştirmeyi hedef olarak önerir. Birleştirme aralığını 24 saatin altında tutmak çakışma riskini ciddi biçimde düşürür.
Feature flag kullanmadan trunk based development yapılabilir mi?
Evet, yapılmaya hazır olmayan kod zaten kullanıcıya görünmüyorsa. Ama çoğu ekipte yarım işi gizlemenin en kolay yolu flag'lerdir. Flag yoksa yeni kodu çağıran kısmı ertelemek gerekir.
Yan proje için trunk based development uygun mu?
Evet. Tek başına çalışan biri için en hızlı döngü, main'e küçük commit'ler atmaktır. Test ve geri alma yolu varsa bu model bir yan projede sorunsuz çalışır.
Release dalına hiç ihtiyaç duyulmaz mı?
Her zaman değil. Sık deploy edilen web uygulamaları genellikle ileriye doğru düzeltme ile yetinir. Mağaza incelemesi yavaş olan mobil uygulamalarda ise sürüm başına kısa ömürlü bir release dalı mantıklı olabilir.
Hangi test seviyesi gerekli?
Her push'ta çalışan ve gerçek hataları yakalayan bir test seti yeterlidir. Kapsam yüzdesi tek başına bir hedef değildir. Önemli olan, kötü bir değişikliğin birleştirilmeden önce fark edilmesidir.