Increment ve Definition of Done: "Bitti" Ne Demek?
Definition of Done, Increment'in commitment'ıdır: onu karşılamayan item ne release edilebilir ne de Sprint Review'da gösterilebilir, Product Backlog'a döner. Yazı bir .NET ve Angular ekibi için somut bir Definition of Done yazıyor ve maddelerini bir GitHub Actions workflow'una çeviriyor: adımların yerel koşusunda zafiyetli transitive bir paket build'i NU1903 hatasıyla kırdı, commit edilmemiş OpenAPI dokümanı git diff'te exit code 1 verdi.
Sürüm notu: Bu yazı Scrum Guide 2020'yi (Kasım 2020, Ken Schwaber ve Jeff Sutherland) esas alır. Yazıdaki kodlar .NET 10 SDK (Software Development Kit) 10.0.402, Entity Framework Core (EF Core) 10.0.14, Microsoft.AspNetCore.OpenApi 10.0.14 ve xUnit v3 4.0.2 ile derlenip denenmiştir; workflow'daki her komut yerelde aynı sırayla çalıştırıldı.
Önce Tahmin Et
Bookstore'un Sprint 9 Review'ından iki gün önce board'da "Done" kolonunda yedi item var. Deniz bunların üçünün staging'e hiç deploy edilmediğini, birinin integration test'inin "geçici olarak" skip edildiğini ve birinin yeni bir endpoint eklediği halde OpenAPI dokümanının eski kaldığını fark ediyor. Ekip "kod yazıldı, review'dan geçti, o zaman bitti" diye düşünüyor.
Guide'a göre bu yedi item'dan kaçı Sprint Review'da gösterilebilir? Ve gösterilemeyenler nereye gider: bir sonraki Sprint'e otomatik taşınır mı, yoksa başka bir yere mi? Tahminini yaz; cevap Guide'da tek cümle.
Increment: Product Goal'e Somut Bir Basamak
Guide Increment'i Product Goal'e doğru somut bir basamak olarak tanımlıyor. Her Increment önceki bütün Increment'lerin üzerine eklenir ve hepsinin birlikte çalıştığından emin olmak için iyice doğrulanır. Değer sağlaması için Increment kullanılabilir olmalıdır. Üç kelimenin altını çiz: eklenir (ayrı bir dal değil, ürünün kendisi), doğrulanır (biri "çalışıyor" demekle değil, kontrolle), kullanılabilir (bir stakeholder eline alıp deneyebilir).
2020 sürümü iki yanlış varsayımı da açıkça düzeltiyor. Birincisi, bir Sprint'te tek Increment olmak zorunda değil; Sprint içinde birden çok Increment yaratılabilir ve Sprint Review'da bunların toplamı sunulur. İkincisi, Increment Sprint bitmeden stakeholder'lara teslim edilebilir; Guide Sprint Review'ın değeri release etmek için bir kapı olarak görülmemesi gerektiğini söylüyor. Bookstore'da saat dilimi bug'ının düzeltmesi Sprint'in üçüncü gününde Definition of Done'ı karşıladı ve aynı gün production'a çıktı; Review'da yalnızca sonucu konuşuldu.
Ve kuralın kendisi: Definition of Done'ı karşılamayan iş Increment'in parçası sayılamaz.
Definition of Done: Increment'in Commitment'ı
Her artifact'ın bir commitment'ı var; Increment'inki Definition of Done. Guide onu ürün için gereken kalite ölçülerini karşıladığında Increment'in durumunun resmi bir tarifi olarak tanımlıyor. Bir Product Backlog item Definition of Done'ı karşıladığı anda bir Increment doğar.
Baştaki sorunun cevabı da burada. Bir item Definition of Done'ı karşılamıyorsa release edilemez, hatta Sprint Review'da sunulamaz bile. Onun yerine ileride değerlendirilmek üzere Product Backlog'a döner. "Bir sonraki Sprint'e otomatik taşınır" diye bir kural yok; Product Owner onu yeniden sıralar ve belki bir sonraki Sprint'te en üstte olur, belki olmaz. Bookstore'un yedi item'ından dördü Review'da gösterilebilirdi; üçü backlog'a döndü.
Guide sahiplik konusunda da net. Definition of Done kurumun standardının bir parçasıysa bütün Scrum Team'ler onu asgari olarak uygular; değilse Scrum Team ürüne uygun bir Definition of Done yaratmak zorundadır. Developers ona uymakla yükümlüdür. Aynı ürün üzerinde birden çok Scrum Team çalışıyorsa hepsi aynı Definition of Done'ı birlikte tanımlar ve ona uyar. Retrospective'in inspect ettiği şeylerden biri de Definition of Done'ın kendisi; yani o da sabit değil, ekip olgunlaştıkça sıkılaşır.
Bookstore'un Definition of Done'ı
Bookstore ekibi .NET 10 backend ve Angular frontend'den oluşan ürünü için Definition of Done'ı şöyle yazdı. Bir item, aşağıdakilerin hepsi doğruysa Done:
- Değişiklik bir pull request'le main'e merge edildi ve en az bir Developer review'dan geçirdi.
- CI'da (Continuous Integration) build uyarısız geçti; unit ve integration test'ler yeşil, skip edilmiş test yok.
- Bilinen zafiyeti olan NuGet ya da npm paketi yok.
- API (Application Programming Interface) değiştiyse OpenAPI dokümanı güncel ve commit'te.
- Şema değiştiyse EF Core migration'ı için idempotent SQL (Structured Query Language) script'i üretildi ve review edildi.
- Staging'e deploy edildi ve smoke test geçti.
- Yeni ekran klavyeyle kullanılabiliyor ve form alanlarının label'ı var (temel accessibility kontrolü).
- Yeni endpoint için structured log ve en az bir metric var.
Bu listenin her maddesi Bookstore'un bir yarasından çıktı. OpenAPI maddesi, mobil uygulama ekibinin üç gün boyunca eski dokümana göre kod yazdığı Sprint'ten sonra eklendi. Log ve metric maddesi, iade endpoint'inin production'da neden yavaş olduğunu kimsenin göremediği bir hafta sonundan sonra.

Definition of Done'ı Kodla Kontrol Etmek
Scrum mühendislik pratiği dayatmıyor; ama "bitti" kelimesinin anlamını bir insanın hafızasına bırakmak transparency'yi zayıflatıyor. Bookstore'un yaklaşımı: maddelerin kontrol edilebilir olanlarını CI'a taşımak, geri kalanlar için pull request şablonunda bir kontrol listesi tutmak. İlk adım, bilinen zafiyeti olan paketlerin build'i kırması. NuGet audit bu durumları NU1902 (orta), NU1903 (yüksek) ve NU1904 (kritik) uyarılarıyla bildiriyor; bunları hataya çevirmek yeterli:
<Project>
<PropertyGroup>
<!-- bilinen zafiyetli paket varsa build kırılsın -->
<WarningsAsErrors>$(WarningsAsErrors);NU1902;NU1903;NU1904</WarningsAsErrors>
</PropertyGroup>
</Project>
Bu dosya repository kökündeki Directory.Build.props; bütün projelere uygulanıyor. İlk çalıştırmada build gerçekten kırıldı ve sebep ekibin doğrudan eklemediği bir paketti:
src/Bookstore.Api/Bookstore.Api.csproj : error NU1902: Warning As Error: Package 'System.Security.Cryptography.Pkcs' 9.0.11 has a known moderate severity vulnerability, https://github.com/advisories/GHSA-2fmv-rv2c-59x7
src/Bookstore.Api/Bookstore.Api.csproj : error NU1903: Warning As Error: Package 'System.Security.Cryptography.Pkcs' 9.0.11 has a known high severity vulnerability, https://github.com/advisories/GHSA-846f-f764-76mx
Paketin nereden geldiğini dotnet nuget why gösteriyor:
$ dotnet nuget why src/Bookstore.Api System.Security.Cryptography.Pkcs
Project 'Bookstore.Api' has the following dependency graph(s) for
'System.Security.Cryptography.Pkcs':
[net10.0]
└── Microsoft.EntityFrameworkCore.SqlServer (v10.0.14)
└── Microsoft.Data.SqlClient (v6.1.7)
└── System.Security.Cryptography.Pkcs (v9.0.11)
Ekip transitive paketi System.Security.Cryptography.Pkcs 10.0.14'e doğrudan referansla yükseltti ve build yeniden yeşile döndü. Bu madde Definition of Done'da olmasaydı uyarı build log'undaki yüzlerce satır arasında kaybolacaktı; Sprint'in "bitmiş" işi bilinen bir zafiyetle production'a çıkacaktı.
İkinci adım workflow'un kendisi. Her madde ayrı bir step; hangi maddenin kırıldığı pull request'te adıyla görünüyor:
name: definition-of-done
on:
pull_request:
branches: [main]
jobs:
dod:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-dotnet@v6
with:
global-json-file: global.json
- run: dotnet tool restore
# NU1902-NU1904 hata: bilinen zafiyetli paket yok
- run: dotnet build -c Release
- run: dotnet test -c Release --no-build
# build'de üretilen OpenAPI dokümanı commit'tekiyle aynı olmalı
- run: git diff --exit-code -- src/Bookstore.Api/Bookstore.Api.json
# migration script'i üretilip release'e eklenir
- run: dotnet ef migrations script --idempotent -p src/Bookstore.Api -o artifacts/migrate.sql
- uses: actions/upload-artifact@v7
with:
name: migrate-sql
path: artifacts/migrate.sql
OpenAPI kontrolünün arkasındaki fikir basit. Projede Microsoft.Extensions.ApiDescription.Server paketi var ve OpenApiDocumentsDirectory property'si proje klasörünü gösteriyor; böylece her build OpenAPI dokümanını yeniden üretip Bookstore.Api.json dosyasına yazıyor. Developer endpoint ekleyip yeni dokümanı commit etmeyi unutursa CI'daki build dosyayı değiştiriyor ve git diff --exit-code sıfırdan farklı bir kodla dönüyor. Emre'nin ISBN (International Standard Book Number) ile kitap arayan endpoint'i eklediği branch'te yerel koşu:
$ dotnet build -c Release
0 Warning(s)
0 Error(s)
$ git diff --exit-code --stat -- src/Bookstore.Api/Bookstore.Api.json
src/Bookstore.Api/Bookstore.Api.json | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
exit code: 1
Build ve test yeşil, ama Definition of Done karşılanmadı: API sözleşmesi değişti ve bunu tüketen kimse göremiyor. Emre güncel dokümanı commit ettiğinde aynı adım exit code: 0 ile geçti. Endpoint'in kendisi ve OpenAPI üretimi ASP.NET Core Web API serisinin ".NET 10 Yenilikleri: ASP.NET Core'da AddValidation, OpenAPI 3.1 ve Server-Sent Events" yazısında; pipeline'da test ve quality gate tasarımı CI/CD Temelleri serisinin "Pipeline'da Test: Hızlı Geri Bildirim, Quality Gate'ler ve Flaky Test'ler" yazısında; migration script'inin deploy'daki yeri Deployment Stratejileri serisinin "Migration'ların Deploy'daki Yeri: Expand-Contract, EF Core Migration Bundle ve Geriye Uyumlu Şema" yazısında anlatılıyor.
Otomatikleşmeyen maddeler (accessibility, log ve metric, staging smoke test) pull request şablonunda bir kontrol listesi olarak duruyor. Otomasyonun amacı insanı çıkarmak değil; insanın dikkatini otomatikleştirilemeyen maddelere ayırmak.
Definition of Done ile Acceptance Criteria Farkı
İkisi sık karıştırılıyor. Acceptance criteria tek bir item'a özgüdür: "İade talebi yalnız teslimden sonraki 14 gün içinde açılabilir" gibi. Definition of Done ise bütün Increment için geçerli kalite standardıdır: her item için aynı, item'ın içeriğinden bağımsız. Bir item'ın Done olması için ikisinin de sağlanması gerekir: item kendi kriterlerini karşılar, Increment de ekibin kalite standardını.
Pratik bir ayrım testi: bir madde her item için aynen tekrar ediyorsa Definition of Done'a aittir; yalnızca bu item'ı anlatıyorsa acceptance criteria'dır. Acceptance criteria yazma tekniği ilerideki Requirements Analysis serisinin konusu.
Undone Work ve Hardening Sprint
2010 Guide'ında "undone work" diye bir kavram vardı; 2011 revizyonu bu referansı kaldırdı. Bugünkü Guide'da ara durum yok: bir item ya Definition of Done'ı karşılar ve Increment'in parçasıdır ya da Product Backlog'a döner. "Yüzde 90 bitti" diye bir şey Increment'e girmez.
Definition of Done yalnızca "kod yazıldı ve review'dan geçti" seviyesinde tutulursa ne olur? Test, entegrasyon, performans ve deploy hazırlığı her Sprint birikir ve bir noktada ekip release'ten önce "hardening sprint" adı verilen, hiç feature üretmeyen ve yalnızca bu birikimi temizleyen bir Sprint ilan eder. Bu, her Sprint'in kullanılabilir bir Increment üretmesi ilkesinin açık bir ihlali; aynı zamanda transparency'nin de: Review'da "bitmiş" görünen iş aslında bitmemişti. Hardening sprint'in tedavisi daha uzun bir hardening sprint değil, Definition of Done'ı sıkılaştırmak ve Sprint'te daha az ama gerçekten bitmiş iş seçmek.
Üretimde Dikkat
Definition of Done'ın sağlığı için Bookstore iki sayıya bakıyor. Birincisi escaped defect, yani Done sayılıp production'da bulunan hata. Bu sayı yükseliyorsa Definition of Done'da bir madde eksik ya da kâğıtta var ama uygulanmıyor. İkincisi, Done'dan production'a geçen süre. Bir item Done olduğu halde haftalarca release edilmiyorsa ya release süreci Definition of Done'ın dışında kalmış ağır bir adım ya da "Done"ın anlamı "release edilebilir" değil. Guide'ın beklediği, Done olan işin release edilebilir olması.
CI'daki kontrol sayısı arttıkça pipeline yavaşlar; Definition of Done'ı otomatikleştirmenin bir maliyeti var. Bookstore'un kuralı: pull request pipeline'ı on dakikayı geçerse ekip Retrospective'te hangi kontrolün nereye taşınacağını konuşuyor. Pipeline'ı ölçmek ve hızlandırmak, DORA (DevOps Research and Assessment) metrikleriyle birlikte, CI/CD Temelleri serisinin "Pipeline'ı Ölçmek ve Hızlandırmak: DORA Metrikleri, Cache ve Paralellik" yazısında.
Ölçekte kural sabit: aynı ürün üzerindeki bütün ekipler aynı Definition of Done'ı paylaşır. İki ekibin farklı "bitti" tanımı olduğunda entegre Increment'in kalitesi en zayıf tanım kadar olur.
Sık Düşülen Tuzaklar
Definition of Done'ı yalnız "kod yazıldı" seviyesinde tutmak ve hardening sprint doğurmak. Yukarıda anlatıldığı gibi bu, kaliteyi Sprint'in dışına itmek demek.
Definition of Done'ın bir wiki sayfasında yazılı olup hiç kontrol edilmemesi. Ekip her Sprint maddeleri "bu sefer atlayalım" diye esnetiyorsa, yazılı bir Definition of Done'ın transparency'ye katkısı sıfırdır; hatta yanıltıcıdır.
Done olmayan item'ı Review'da "neredeyse bitti" diye göstermek. Guide bunu açıkça yasaklıyor; stakeholder'a gösterilen her şey Definition of Done'ı karşılamış olmalı ki inspection gerçek veriye dayansın.
Definition of Done'ı bir kerede mükemmel yazmaya çalışmak. İlk Sprint'te Bookstore'un listesi dört maddeydi; her madde bir Retrospective'ten geldi. Ekibin bugün karşılayamayacağı bir Definition of Done ise her Sprint ihlal edilen bir belgeye dönüşür.
Küçük Bir Deneme
★☆☆ Ekibinin Definition of Done'ını yaz; yazılı değilse son Sprint'te "bitti" denen üç item'ı al ve neyin yapıldığını madde madde çıkar. Bu üç listenin ortak kesişimi, ekibinin fiili Definition of Done'ı.
★★☆ Definition of Done'ındaki maddeleri "CI'da otomatik kontrol edilebilir" ve "insan kontrolü gerekir" diye ikiye ayır. İlk gruptan bir maddeyi bu yazıdaki gibi bir pipeline step'ine çevir ve bilerek kırdığın bir branch'te sıfırdan farklı exit code ile durduğunu gör.
★★★ Son üç ayın escaped defect'lerini listele ve her birinin hangi Definition of Done maddesi olsaydı yakalanacağını yaz. En çok tekrar eden maddeyi bir sonraki Retrospective'te Definition of Done'a ekleme önerisi olarak getir.
Increment hazır ve gerçekten bitmiş. Bir sonraki yazıda Sprint'in son iki event'ine geçiyoruz: Sprint Review'da bu Increment'i stakeholder'larla nasıl inspect ettiğimiz ve Sprint Retrospective'te kendi çalışma biçimimizi, Definition of Done dahil, nasıl iyileştirdiğimiz.