Test-Driven Development Eğitim Serisi — Bölüm 1 — TDD’nin Tarihçesi ve Düşünsel Soykütüğü
Faz 1: Temeller ve Felsefe

Test-Driven Development Eğitim Serisi — Bölüm 1 — TDD’nin Tarihçesi ve Düşünsel Soykütüğü
Faz 1: Temeller ve Felsefe
» İçindekiler » Bu Bölüm Neden Önemli » Tarih Öncesi: Test Düşüncesinin İlk Filizlenmeleri » C3 Projesi: Bir Disiplinin Doğum Yeri » JUnit’in Doğuşu ve xUnit Ailesi » Agile Manifesto ve Genişleyen Bağlam » 2003: Kanonik Metnin Yayını » Londra Okulu’nun Doğuşu: Mock Objects ve GOOS » 2007: Fowler’ın “Mocks Aren’t Stubs” Makalesi » Tamamlayıcı Kanonik Metinler: Feathers ve Meszaros » Software Craftsmanship Hareketi » 2014: “Is TDD Dead?” Tartışması » Modern Dönem: Eleştirel Sentez » Düşünsel Soykütüğü Haritası » İki Okulun Kristalleşmesi » Türkçe Yazın Bağlamında Bir Not » Bu Tarihten Çıkardığımız Üç Ders » Üç Gözlem Sorusu » Felsefi Mühür
» Bu Bölüm Neden Önemli
Bir disiplini öğrenmenin en hızlı yolu onun tarihini atlamaktır; en derin yolu ise onun tarihinden geçmektir. Bu iki yol arasındaki seçim, bir öğrencinin sadece “ne yapacağını bilen biri” mi yoksa “neden öyle yapması gerektiğini bilen biri” mi olacağını belirler. Tarih, bir pratiğin doğduğu bağlamı, çözmeye çalıştığı problemi, geçirdiği krizleri ve içine düştüğü tartışmaları içerir. Bütün bunlar bilinmeden öğrenilen bir pratik, dogma olur; dogma olan bir pratik ise ya kör bir biçimde uygulanır ya da kayıtsızca terk edilir.
Test-Driven Development’ın tarihi yazılım mühendisliği tarihinin son otuz yıllık serüveninde özel bir yere sahiptir. Pek az pratik onun gibi tek bir kişinin ismiyle özdeşleşmiştir (Kent Beck); pek az pratik onun gibi açık bir tartışma içinde olgunlaşmıştır (Classicist-Mockist ayrımı); pek az pratik onun gibi hem savunucuları hem de yaratıcısı tarafından eleştirilmiştir (“Is TDD Dead?” tartışmaları). Bu çetrefilli tarih, TDD’yi statik bir öğreti olmaktan çıkarıp canlı bir tartışma alanı hâline getirmiştir. Bu bölümün niyeti, o tartışma alanının haritasını çıkarmaktır; ki okur ileride hangi konunun nereden geldiğini, hangi terimin hangi metinden çıktığını, hangi tartışmanın hangi yılda kristalleştiğini bildiğinde, geri kalan bölümler ona yabancı değil tanıdık gelsin.

Yazılım pratikleri tarihten kopuk öğrenildiğinde dogmalaşır. “Mock kullan”, “önce test yaz”, “her test izole olmalı” gibi cümleler, doğdukları bağlamdan koparıldığında reçete hâline gelir; reçete hâline geldiğinde de uygulayıcısının zihninde tartışmaya kapalı, sezgi gerektirmeyen kurallar dizisine dönüşür. Oysa bu cümlelerin her biri bir tartışmanın sonucudur ve o tartışmanın iki tarafını da bilmek, cümleyi gerçek anlamda kullanabilmek için zorunludur. Bu yüzden Bölüm 1, bir tarih dersi gibi okunabilir ama bir tarih dersi değildir; her tarihsel notun arkasında, ileride seride tekrar karşımıza çıkacak bir kavramın tohumu vardır.
Bu bölümün sonunda okur, TDD’nin nereden geldiğini, hangi entelektüel akrabalarla beraber büyüdüğünü, hangi krizlerden geçtiğini ve bugün hâlâ neden tartışıldığını ana hatlarıyla bilecektir. Daha da önemlisi, ileri bölümlerde geçecek olan isimleri — Beck, Cunningham, Jeffries, Fowler, Freeman, Pryce, Feathers, Meszaros, Mancuso, Khorikov, Farley — bir isim listesi olarak değil, yaşayan bir entelektüel zincirin halkaları olarak hissedecektir.
» Tarih Öncesi: Test Düşüncesinin İlk Filizlenmeleri
Test-Driven Development bir gün birden ortaya çıkmadı. Onu mümkün kılan zihinsel ortam, onlarca yıl boyunca yazılım kalitesi üzerine düşünen mühendis ve akademisyenlerin birikimi ile kuruldu. Bu birikimin tamamını anlatmak ayrı bir kitabın konusudur; ama TDD’nin doğuşunu anlamak için bilinmesi gereken birkaç anahtar nokta vardır.
Edsger Wybe Dijkstra, 1969'da NATO tarafından düzenlenen Software Engineering konferansında yaptığı konuşmada ve daha sonra 1972'deki Turing Ödülü leksiyonunda, programcılığın bilimsel doğası üzerine söyleyeceği kelimeleri seçti. En çok hatırlanan cümlelerden biri şudur: “Program testing can be used to show the presence of bugs, but never to show their absence.” Bu cümlenin yüzeyi yanıltıcıdır; sanki Dijkstra testin değersiz olduğunu söylüyormuş gibi okunur. Oysa cümlenin ardındaki niyet farklıdır: testlerin sınırını çizmek, ve bu sınırın bilinmesinin testleri zayıflatmayacağını, aksine onları akıllı kullanmaya götüreceğini göstermektir. TDD bu sınırı kabul eder ve onunla barışık çalışır; bir test, kodun çalıştığını kanıtlamaz, ama belirli bir davranışın orada olduğunu göstermeye yarar. Bu fark, ilerideki “test coverage’a takılmamak” tartışmalarının zihinsel temelidir.
Glenford J. Myers, 1979'da yayımladığı The Art of Software Testing kitabıyla, testi bir mühendislik disiplini olarak ciddiye alan ilk kapsamlı çalışmayı ortaya koydu. Myers’ın kitabında, testlerin sadece pozitif vakalar için yazılmaması gerektiği, edge case’lerin sistemli aranmasının önemli olduğu, “psikolojik olarak” testçinin kodun çalışmasını umut etmek yerine çalışmadığını umut etmesi gerektiği anlatılır. Bu son nokta TDD’nin temel sezgilerinden biriyle çakışır: bir test geçerse mutluluk doğal değildir, bir test kırılırsa öğrenme vardır. TDD’nin “doğru nedenle kırmızı” prensibi, Myers’ın kitabında değil ama onun açtığı zihinsel patikada şekillenmiştir.
1980'lerin sonu ve 1990'ların başında, Smalltalk topluluğu yazılımın canlı, etkileşimli, çalıştığı yerden değiştirilebilir doğasını keşfetmekte ve bu doğanın getirdiği özgürlüğü test pratikleriyle desteklemenin yollarını aramaktaydı. Bu dönemin önemli figürlerinden biri Ward Cunningham’dı — wiki’nin mucidi, “teknik borç” metaforunu icat eden ve Beck’in kendi anlatımıyla “her sabah uyandığında kendini ona benzemeye çalışırken bulduğu” insan. Beck, 1994'te The Smalltalk Report dergisinde “Simple Smalltalk Testing: With Patterns” başlıklı bir makale yayımladı; bu makale, daha sonra xUnit ailesinin tohumu olacak SUnit framework’ünün hem tasarımını hem felsefesini anlatıyordu.

Beck’in kendi anlatımına göre, “test-first” düşüncesini çocukluk yıllarında, babasının kitaplığındaki eski bir programcılık kitabında karşılaştığı bir alıştırmadan almıştı. O kitapta yer alan ilkel bir öneri şuydu: bir programcı yazacağı her alt rutin için önce bir test çağrısı yazmalı, sonra alt rutini yazmalı, ve test çağrısının doğru çalıştığını görmeden bir sonraki alt rutine geçmemeliydi. Bu basit ama radikal fikir Beck’in zihninde kalmış, on yıllar sonra TDD adı altında dünyaya tanıtılacağı pratiğin tohumunu atmıştı. Beck bu hikayeyi sonradan defalarca anlattı; çünkü onu anlatmak, TDD’nin tek bir dahinin icadı olmadığını, aksine yıllarca uykuda bekleyen bir sezginin uyandırılması olduğunu vurgulamaktı.
» C3 Projesi: Bir Disiplinin Doğum Yeri
Yazılım mühendisliği tarihinde belirli projeler, belirli pratiklerin doğuş yeri olarak özel bir mit kazanır. C3 projesi de böyle bir projedir. Açık adıyla Chrysler Comprehensive Compensation System, Chrysler şirketinin maaş bordro sistemini Smalltalk diliyle yeniden yazmayı amaçlayan bir projeydi. 1993'te başlayan proje, 1996'da krize girdiğinde Kent Beck projeyi düzeltmesi için danışman olarak çağrıldı. Bu çağrı, sadece Beck’in değil, yazılım mühendisliği tarihinin de seyrini değiştirecekti.
Beck’in projeye gelişinden sonra olanlar, onun ekibiyle birlikte oluşturduğu pratikler bütünü olarak şekillendi. Bu pratikler yeni değildi — pair programming Smalltalk topluluğunda zaten vardı, continuous integration fikri eski mühendisliklerden gelirdi, automated testing on yıllardır bilinirdi. Beck’in yaptığı şey, bu pratikleri sentezlemek ve birbirini destekleyen bir bütün olarak adlandırmaktı. Adı “Extreme Programming” olarak konuldu; “extreme” kelimesi Beck’in bilinçli tercihidir, mesajı şudur: zaten iyi olduğunu bildiğimiz pratikleri uca kadar götürelim, ne olur görelim. Eğer test yazmak iyiyse, her gün test yazalım; eğer code review iyiyse, sürekli code review yapalım (pair programming bu fikrin uca taşınmış halidir); eğer entegrasyonu sık yapmak iyiyse, her commit’te yapalım.

C3 projesinde test pratiği özellikle dikkat çekiciydi. Beck ve ekibi her yeni davranış için önce bir Smalltalk test sınıfı yazıyor, sonra production kodunu yazıyor, ve bu döngüyü her gün, her saat, her dakika tekrarlıyordu. Test yazımı bir “kalite güvence” aşaması değil, kod yazma aşamasının ayrılmaz bir parçası hâline gelmişti. Bu pratiğin Smalltalk’ın canlı geliştirme ortamında nasıl olduğunu hayal etmek için, bugünkü modern Java IDE’lerimizdeki “test çalıştır” düğmesinin yerine, kodun yazıldığı satırın altında anında çalışan ve sonucu hemen görselleştiren bir yapı düşünün. Test ve kod arasındaki geri bildirim döngüsü saniyeler ile ölçülüyordu.
Bu pratiğin somut bir tadı için, Beck’in 1994 makalesinde tanıttığı SUnit framework’ünün stilinde basit bir Smalltalk testinin nasıl göründüğüne bakalım. Aşağıdaki örnek tarihsel sadakat için stilize edilmiştir; gerçek SUnit kodunun semantiğini yansıtır:
"Smalltalk - SUnit stili, 1994 civarı"
MoneyTest>>testSimpleAdd
| result |
result := (5 dollars) + (5 dollars).
self assert: result = (10 dollars)
Bu basit kalıp, Beck’in zihninde son derece güçlü bir fikre dönüştü: bir geliştirici, henüz var olmayan bir davranışı test ile ifade edebilir, sonra o ifadenin gerçek olması için minimum kodu yazabilir, ve bu döngüyü tekrar tekrar yaparak hem davranış hem de yapı birlikte büyütülebilir. Bu fikrin kendisi yeni değildi; ama bunu disiplinli, sistemli ve adı konulmuş bir pratik olarak sunmak yeniydi.
C3 projesi 1999'da iptal edildi. Şirket ekonomik nedenlerle projenin geri kalanını sürdürmek istemedi. Yazılım mühendisliği tarihinin pek çok ironisinden biri budur: TDD’nin ve XP’nin doğum yeri olan proje, “başarılı” sayılmaz; oradaki pratiklerin ürettiği fikirler ise yazılım dünyasının tamamına yayıldı. Beck’in 1999'da yayımladığı Extreme Programming Explained: Embrace Change kitabı, C3'te şekillenen pratiklerin teorik özetini sunuyor ve “test-first programming” başlığı altında TDD’nin ilkel formunu tanımlıyordu. Henüz adı “Test-Driven Development” değildi; bu isim birkaç yıl içinde yerleşecekti.
» JUnit’in Doğuşu ve xUnit Ailesi
1997 sonlarında, Beck ve Erich Gamma (Gang of Four kitabının yazarlarından biri, daha sonra Eclipse’i, JGit’i ve VS Code’u şekillendirecek olan figür) Atlanta’dan Zürih’e uzun bir transatlantik uçuş yapıyorlardı. Bu uçuşta, Beck’in Smalltalk’taki SUnit deneyimini Java’ya taşımayı kararlaştırdılar. Uçağın inişine kadar JUnit’in ilk versiyonunu birlikte yazdılar. Bu uçuş anekdotu, yazılım folklorunun en sevilen hikayelerinden biri olarak kaldı; iki ustanın bir araya gelip, bir saatlerce sürecek beraberlikte, on yıllarca etkili olacak bir aracı doğurmasının somut örneği olarak hatırlanır.
JUnit’in tasarımı tesadüfi değildi; Gang of Four pattern’larının somut bir uygulamasıydı. Template Method ile test lifecycle’ı şekillendirilmiş, Composite ile test suite hiyerarşileri kurulmuş, Command ile test çağrıları soyutlanmıştı. Bu pattern’ların TDD ile yazılmış olması bir başka katmandı: Beck, JUnit’i geliştirirken JUnit’in kendisini test ediyordu. Bu “kendi kendini test etme” özelliği, TDD’nin sınırlarını test etmek için en güzel laboratuvarlardan biri oldu ve Beck’in Test-Driven Development: By Example kitabının ikinci yarısının ana konusu hâline geldi.
JUnit’in başarısı hızlıydı ve ardından gelenler kaçınılmazdı. xUnit ailesi, JUnit’in temel şablonunu farklı dillerde tekrar eden framework’lerden oluşur: NUnit (.NET, 2000), CppUnit (C++, 2000), PyUnit / unittest (Python, 2001, standart kütüphaneye dahil edildi), PHPUnit (PHP, 2002), Test::Unit (Ruby, 2000), Jasmine ve Mocha (JavaScript, daha sonraki yıllar) bunların önde gelenleridir. Bütün bu framework’ler aynı temel mantığı paylaşır: test sınıfları, test metodları, setup/teardown lifecycle’ı, assertion API’si. Bu ortak şablonun yaygınlaşması, TDD’nin sadece Java geliştiricilerinin pratiği değil, dillerüstü bir disiplin olarak konumlanmasını sağladı.

JUnit’in evrim hikayesi de TDD topluluğunun bir aynasıdır. JUnit 3, sınıf hiyerarşisi tabanlıydı; bütün test sınıflarınız TestCase'den türemek zorundaydı. JUnit 4 (2006), Java 5'in annotation desteğiyle birlikte gelen radikal bir yenilemeydi; @Test, @Before, @After annotation'ları ile inheritance bağımlılığı kalktı, parametrik testler, runner mekanizması ve daha esnek bir API geldi. JUnit 5 (2017) ise tamamen yeniden tasarlandı; JUnit Platform, JUnit Jupiter ve JUnit Vintage olmak üzere üç ayrı modüle bölündü, extension API'si genişledi, dynamic testler, nested testler ve diğer modern özellikler eklendi. Bu evrimi izlemek, TDD topluluğunun pratik ihtiyaçlarının nasıl geliştiğinin de izini sürmektir; her büyük JUnit sürümü, topluluğun o sıradaki "iyi test nasıl yazılır" düşüncesinin yansımasıdır.
» Agile Manifesto ve Genişleyen Bağlam
2001 Şubat’ında, Snowbird (Utah) kayak merkezinde 17 yazılım uzmanı bir araya geldi. Aralarında Kent Beck, Ward Cunningham, Martin Fowler, Robert C. Martin, Ron Jeffries, Andrew Hunt, Dave Thomas gibi isimler vardı. Bu toplantının sonunda ortaya çıkan dört değer ve on iki prensip, Agile Manifesto adıyla tarihe geçecekti. Manifesto’da “Test-Driven Development” cümle olarak geçmez; ama manifesto’nun ruhu — çalışan yazılım, değişime adapte olma, sürdürülebilir hız, teknik mükemmeliyet — TDD pratiğiyle doğrudan örtüşür.
Agile Manifesto’nun TDD için önemi, TDD’nin yalnız başına yaşaması mümkün olmayan bir pratik olduğunu çerçevelemesidir. TDD, daimi entegrasyon olmadan, iyi takım iletişimi olmadan, refactoring kültürü olmadan, çiftli/grup programlama olmadan tek başına ayakta kalmakta zorlanır. Agile Manifesto bu destekleyici pratikleri bir araya getirerek, TDD’nin doğal yaşam ortamını tanımladı. Bu yüzden bugün hâlâ TDD’yi pratik etmek isteyen takımların çoğu, kendiliğinden Agile pratiklerine kayar; çünkü TDD bu ortamda nefes alır.

XP’nin TDD üzerindeki spesifik etkisini de altını çizmek gerekir. XP, on iki temel pratiği vardı ve bu pratikler birbirini desteklemek üzere tasarlanmıştı. Continuous integration olmadan test-first çalışmaz; çünkü testler sürekli çalışıyor olmalıdır. Pair programming TDD’yi destekler; çünkü iki kişi birlikte düşünürken testin “doğru nedenle kırmızı” olup olmadığı daha kolay görülür. Collective ownership, testlerin tüm takım tarafından yazılmasını ve sürdürülmesini sağlar; aksi takdirde testler kişisel uzmanlık alanı hâline gelip eskimeye başlar. XP’nin bu bütünsel doğası unutulduğunda, TDD bağlamından koparılmış bir kurallar dizisine indirgenir; bu indirgeme, ilerideki “TDD çalışmıyor” şikayetlerinin pek çoğunun arkasındadır.
» 2003: Kanonik Metnin Yayını
Kent Beck’in Test-Driven Development: By Example kitabı 2003'te yayımlandı. Bu tarih, TDD’nin “isim altında bir disiplin” olarak resmî doğumudur. Kitabın yapısı bilinçliydi; iki bölüme ayrılmıştı. İlk bölüm, “Money” örneği üzerinden TDD’yi öğretiyordu — para birimi dönüşümleri, toplama, çoklu para birimleri ile çalışma gibi senaryolar üzerinden adım adım kırmızı-yeşil-refactor döngüsü uygulanıyordu. İkinci bölüm ise daha radikaldi: xUnit framework’ünün kendisini TDD ile yazıyordu. Yani Beck, test yazmak için kullanılan aracı, test yazarak inşa ediyordu. Bu özyinelemeli yapı, kitabın hem felsefi hem pedagojik gücünün kaynağı oldu.
Kitabın katkıları sayısızdır; ama birkaçı bu seri boyunca tekrar tekrar karşımıza çıkacağı için burada vurgulamak gerekir. “Red, green, refactor” mantrası bu kitapta sistematize edildi; daha önce de var olan bir akış, burada üç kelimelik bir disiplin çağrısına dönüştürüldü. “Fake it till you make it” stratejisi ile “obvious implementation” ve “triangulation” stratejilerinin bir disiplin örüntüsü olarak tanımlanması bu kitabın katkısıdır; bir test geçirilirken hangi stratejinin seçileceği, geliştiricinin durumla ilişkisine göre değişir ve Beck bunu bir karar matrisi olarak değil, sezgi geliştirme rehberi olarak sunar. “Baby steps” kavramı da bu kitapta belirginleşti; “test öyle küçük bir adımla geçmeli ki, bir sonraki adım belirginleşsin” prensibi, ileride TDD pratiğinin estetik boyutunun temeli olacaktı.

Bir kanonik metnin gerçek gücü, sonraki çalışmaların ona referans verecek kadar net bir omurga sunmasındadır. Beck’in 2003 kitabı bu omurgayı kurdu. Bundan sonraki tüm TDD literatürü — ister bu omurgayı genişletsin, ister ona itiraz etsin — bu kitaba göndermeli olarak konumlanır. Bir başka deyişle: TDD üzerine yazılan her şey, ya bu kitabın bir parça çocuğudur ya da bu kitaba karşı doğmuştur. Bu seri de bu kitabı kendi entelektüel anavatanı olarak kabul eder.
Beck’in kitabının başına yerleştirdiği bir cümle, kitabın felsefi mührünü oluşturur ve bu seri boyunca hatırlatmaya değer bir cümledir:
“Clean code that works is, in my experience, a rare commodity. Writing clean code that works, and proving it works, beat-by-beat, is the topic of this book.” — Kent Beck, Test-Driven Development: By Example (2003)
“Beat-by-beat” deyişi — adım adım, vuruş vuruş — TDD’nin müzikal ritmine işaret eder. Bir geliştirici tek başına kod yazıyor olabilir, ama bir TDD pratisyeni bir ritmi takip eder, ve bu ritim onun zihninde içselleşmiş bir metronom gibi çalışır.
» Londra Okulu’nun Doğuşu: Mock Objects ve GOOS
2000'lerin başında Londra’da, Tim Mackinnon, Steve Freeman, Philip Craig, Nat Pryce ve diğer geliştiricilerden oluşan bir topluluk, TDD pratiğinin farklı bir yönüne odaklanıyordu. Bu yön, interaction-based testing veya mock objects olarak bilinecek olandı. Mackinnon ve ekibinin 2000'de yayımladığı Endo-Testing: Unit Testing with Mock Objects makalesi, bu yaklaşımın resmi başlangıcı sayılır. Aynı dönemde jMock framework’ü ortaya çıktı ve Java dünyasında mock-based TDD’nin yaygınlaşmasını sağladı.
Bu yaklaşımın özgün katkısı şuydu: bir nesnenin doğru davranışını test etmek için, o nesnenin dış dünyaya gönderdiği mesajları doğrulamak yeterli olmalıdır. Eğer bir OrderService, başarılı bir sipariş üzerine NotificationSender'a "müşteriyi bilgilendir" mesajı gönderiyorsa, biz bunu doğrulamak için gerçek bir notification sender'ı çalıştırmak zorunda değiliz; sadece "doğru mesaj gönderildi mi" diye bakabiliriz. Bu fikir, Tell, Don't Ask prensibiyle birleşerek, nesnelerin bağımsız aktörler olarak modellenmesi anlayışını besledi.
2009'da Steve Freeman ve Nat Pryce, Growing Object-Oriented Software, Guided by Tests (GOOS) kitabını yayımladılar. Bu kitap, Londra okulunun kanonik metni olarak yerini aldı. Kitap, “Auction Sniper” adlı gerçek bir uygulamayı baştan sona TDD ile geliştirir; ama bunu yaparken sıradan TDD kitaplarında bulunmayan bir kademe içerir: acceptance test’ten başlanır, dış katmandan iç katmana doğru çalışılır, ve her katmanda bir alt katmanın arayüzü mock’lar yardımıyla keşfedilir. Bu yöntem Outside-In TDD olarak adlandırıldı ve Londra okulunun pratik amblemi oldu.

GOOS kitabının getirdiği bir diğer önemli fikir, “need-driven development” yani ihtiyaç güdümlü geliştirme kavramıdır. Bu kavrama göre, bir nesnenin işbirlikçileri (collaborators) ve onlardan ihtiyaç duyduğu mesajlar, testlerin yazılması sürecinde keşfedilir. Bir test yazarken “bu metodun şu yardımcıya ‘bunu yap’ demesi gerekiyor” dediğinizde, o yardımcının arayüzü o anda keşfedilmiş olur. Bu yaklaşım, klasik OOP eğitimlerinde anlatılan “önce sınıfları tasarla, sonra ilişkilerini düşün” yaklaşımının tam tersidir; tasarım, testlerin ihtiyaçları aracılığıyla ortaya çıkar.
Londra okulunun yükselişi, Detroit okulunun (Beck’in orijinal yaklaşımı) yanlış olduğunu söylemek anlamına gelmiyordu; ama farklı bir TDD vurgusunu temsil ediyordu. Yıllar içinde bu iki okulun yan yana varlığı, TDD topluluğu içinde sağlıklı bir tartışma kültürü yarattı. Bu tartışmanın resmi adlandırılması ise 2007'de gelecekti.
» 2007: Fowler’ın “Mocks Aren’t Stubs” Makalesi
Martin Fowler’ın 2007'de yayımladığı Mocks Aren’t Stubs makalesi, TDD topluluğu içinde uzun zamandır var olan ama henüz isim verilmemiş bir gerilimi sistemli biçimde adlandırdı. Bu makalede Fowler, TDD’yi pratik eden iki ayrı düşünce okulu olduğunu açıkça ortaya koydu:
Classicist (veya Detroit Style) okulu, Beck’in orijinal yaklaşımına yakındır. Bu okul, state-based verification kullanır: bir testten sonra nesnenin durumunun beklenen durum olup olmadığına bakılır. Test doubles minimal kullanılır; gerçek nesneler tercih edilir. Tasarım inside-out ilerler; çekirdek domain’den başlanır, dışa doğru genişletilir.

Mockist (veya London Style) okulu, Freeman, Pryce ve diğer Londra topluluğunun yaklaşımına yakındır. Bu okul, interaction-based verification kullanır: bir testten sonra nesnenin işbirlikçilerine doğru mesajları gönderip göndermediğine bakılır. Test doubles yoğun kullanılır. Tasarım outside-in ilerler; en dış katmandan başlanır, içe doğru kazılır.
Fowler’ın makalesinin ne dediği kadar ne demediği de önemlidir. Fowler, bu iki okuldan birinin doğru, diğerinin yanlış olduğunu söylemez. Aksine, her ikisinin de geçerli olduğunu, her birinin kendi güçlü yanları ve zayıflıkları olduğunu, ve bir geliştiricinin uygun olduğu bağlamda uygun olanı seçmesi gerektiğini söyler. Bu nüanslı tutum, Fowler’ın yıllar içinde topluluğa kazandırdığı şeylerden biridir: dogmatik kamplaşmaya değil, eleştirel sentez yapmaya yönelten bir düşünce alışkanlığı.
Makalenin yan getirilerinden biri, test doubles taksonomisinin netleşmesidir. Fowler, Gerard Meszaros’un aynı yıl yayımlanacak olan xUnit Test Patterns: Refactoring Test Code kitabındaki taksonomisini referans alır: Dummy, Stub, Spy, Mock, Fake. Bu beş kategori, günümüze kadar test doubles üzerine konuşmanın ortak dili oldu. Maalesef günlük dilde herkes her şeye “mock” demeye devam eder; ama profesyonel bir tartışmada bu kategorilerin doğru kullanımı, konuşmacının olgunluğunun göstergesidir.
» Tamamlayıcı Kanonik Metinler: Feathers ve Meszaros
2004 ve 2007 yılları, TDD literatürüne iki başka kanonik metin daha ekledi. Bu metinler, Beck’in 2003'teki çerçevesini tamamlayan ama farklı yönlere bakan yapıtlardı.
Michael Feathers, 2004'te Working Effectively with Legacy Code kitabını yayımladı. Bu kitabın getirdiği en radikal fikir, “legacy code”un yeni bir tanımıydı: “Legacy code is code without tests.” Yani bir kodun eski mi yeni mi olduğu, ne zaman yazıldığı, hangi dilde olduğu önemli değildir; eğer testleri yoksa, o kod legacy’dir. Bu tanım, dünyanın her tarafındaki yazılım takımlarını rahatsız etti; çünkü kendi yazdıkları “yeni” kodun da legacy olabileceğini fark ettiler.

Feathers kitabında, test edilemeyen koda nasıl test eklenebileceğine dair sistemli bir yöntem sunar. Seam kavramı — kodun davranışını değiştirmeden test için bir kesim noktası bulunabilen yer — bu kitabın anahtarıdır. Sprout Method (yeni davranışı ayrı bir metoda alıp test etmek), Wrap Method (mevcut metodu sarmalayan yeni bir metoda yer açmak), Extract and Override (bir parçayı extract edip alt sınıfta override edilebilir kılmak) gibi teknikler, TDD’yi sadece “yeşil alanda” değil, “kahverengi alanda” — yani var olan kod tabanında — da uygulanabilir kılar. Bu seri, Bölüm 26'da Feathers’ın araç setini detaylı olarak işleyecektir.
Gerard Meszaros, 2007'de xUnit Test Patterns: Refactoring Test Code kitabını yayımladı. Bu kitap, test kodunun da production kodu kadar — hatta ondan daha fazla — özen istediği fikrini sistemleştirdi. Test smell’leri (kötü test kokuları), test refactoring teknikleri, test doubles taksonomisi, fixture organizasyonu gibi konular bu kitapta kapsamlı biçimde işlendi. Mystery Guest, Fragile Test, Erratic Test, Obscure Test gibi smell isimleri Meszaros’un terminolojisidir ve bu isimler bugün TDD topluluğunun ortak dilini oluşturur. Bu seri, Bölüm 29'da test smell’leri Meszaros referansıyla derinlemesine işleyecektir.
» Software Craftsmanship Hareketi
2008'de bir grup geliştirici, Software Craftsmanship Manifesto’yu yayımladı. Bu manifesto, Agile Manifesto’nun “alıntılarına” bir parçaydı; “Agile’ın söylediklerinin yetersiz kaldığını” ima eden bir tutumla, dört yeni değer ekliyordu: çalışan yazılımdan öte iyi yapılandırılmış yazılım, değişime adapte olmaktan öte sürekli değer katmak, müşteri işbirliğinden öte üretken ortaklıklar, bireyler ve etkileşimlerden öte profesyonellerden oluşan bir topluluk.
Bu hareketin TDD ile ilişkisi son derece sıkıdır. Software Craftsmanship’in önde gelen isimlerinden Sandro Mancuso, Robert C. Martin, Steve Freeman ve diğerleri, TDD’yi profesyonel bir yazılım geliştiricinin omurga pratiklerinden biri olarak görüyorlardı. Mancuso’nun 2014'te yayımlanan The Software Craftsman: Professionalism, Pragmatism, Pride kitabı, TDD’yi sadece bir teknik pratik değil, bir mesleki ahlak olarak konumlandırır. “Profesyonel bir geliştirici, kendisinin yazdığı kodun çalıştığını kanıtlamadan teslim etmez” cümlesi, Mancuso’nun en sık tekrarlanan iddialarından biridir.

Software Craftsmanship hareketinin pratik etkilerinden biri, mentorship ve workshop kültürünün yayılmasıdır. London Software Craftsmanship Community (LSCC), Codurance gibi yapılar, TDD’yi atölyeler ve “code retreat” etkinlikleriyle öğretmenin yaygın metodu hâline geldi. Bir TDD pratisyeninin yetişme süreci, sadece kitap okumak değil, başka bir TDD pratisyeniyle birlikte kod yazmak olarak görüldü. Bu pratik geleneği, TDD’nin neden bireysel öğrenmeye dirençli olduğunun temel açıklamasıdır.
» 2014: “Is TDD Dead?” Tartışması
2014 Nisan’ında, David Heinemeier Hansson (DHH, Ruby on Rails’in yaratıcısı), kişisel blogunda TDD is dead. Long live testing. başlıklı bir yazı yayımladı. Bu yazıda DHH, TDD’nin tasarımı bozduğunu, aşırı mock kullanımına yol açtığını, “test edilebilirlik” adı altında doğal olmayan abstractionlar yarattığını, ve sonuç olarak ürettiği kodun gerçek sorunları çözmediğini iddia ediyordu. Yazı topluluk içinde fırtına etkisi yarattı.
Bu fırtınaya cevap olarak, Kent Beck, Martin Fowler ve David Heinemeier Hansson bir araya gelerek dokuz haftalık bir Google Hangouts dizisi düzenlediler. Is TDD Dead? adı verilen bu konuşmalar, TDD topluluğu içindeki en derin entelektüel tartışmaların kayıt altına alındığı yer oldu. Burada konuşulan konular, sadece “TDD iyi mi kötü mü” değil, çok daha incelikli sorulardı:
İlk soru: TDD’nin tasarım baskısı her zaman olumlu mu? DHH’nin iddiası, bazen bu baskının “yapay” abstractionlar ürettiğiydi; “Repository”, “Service”, “Manager” gibi sınıfların ortaya çıkmasının asıl nedeni domain ihtiyacı değil, test edilebilirlik kaygısıydı. Beck ve Fowler bu eleştiriye kısmen katıldılar; aşırı abstraction’ın gerçekten bir tehlike olduğunu, ama dikkatli pratisyenler tarafından bertaraf edilebileceğini savundular.

İkinci soru: Unit test mi, integration test mi? DHH, gerçek değerin integration testlerinde olduğunu, unit testlerinin “implementasyon detaylarına bağımlı” olduğu için kırılgan kaldığını söyledi. Bu eleştiri, J.B. Rainsberger’in birkaç yıl önce yayımladığı Integrated Tests Are A Scam makalesinin tam tersi pozisyonu temsil ediyordu. Fowler bu tartışmada her iki tarafa da yer verdi: integration testler değerlidir ama yavaştır; unit testler hızlıdır ama bağlamdan kopuktur; iki türün dengesi önemlidir.
Üçüncü soru: TDD ne zaman uygundur? Bu, tartışmanın en olgun çıktısı oldu. Hangi senaryolarda TDD’nin maliyeti getirisini aşar, hangilerinde tam tersi olur sorusu açıkça konuşuldu. Spike çalışmaları, exploratory prototype’lar, ML kodu, performance-critical hotspot’lar gibi alanlarda TDD’nin “katı disiplin” olarak uygulanmasının verimsiz olabileceği konusunda Beck dahi mutabık kaldı. Bu olgunluk, TDD’nin dogma olmaktan çıkıp bağlama duyarlı bir profesyonel araç olarak konumlanmasını destekledi.
“Is TDD Dead?” tartışmasının sonunda TDD ölmedi; aksine olgunlaştı. Topluluk, tartışmadan önce dogmatik savunmalarla iş gören bir hale geldiyse, tartışmadan sonra nüanslı, bağlama duyarlı, eleştirel düşünmeye yatkın bir kültür kazandı. Bu olgunluk, modern TDD pratiğinin karakterini belirledi.
» Modern Dönem: Eleştirel Sentez
2014 sonrası dönem, TDD’nin “ergenliğini bitirip yetişkinliğe geçtiği” yıllar olarak okunabilir. Bu dönemde ortaya çıkan literatür, ne TDD’nin saf savunusunu yapıyor ne de onu reddediyor; aksine, TDD’yi modern yazılım mühendisliğinin diğer pratikleriyle birlikte konumlandıran eleştirel sentezler üretiyor.
Vladimir Khorikov’un 2020'de yayımlanan Unit Testing Principles, Practices, and Patterns kitabı bu dönemin en önemli yapıtlarından biridir. Khorikov, Detroit okulunun modern bir savunusunu yapar; Mockist yaklaşımın aşırılıklarını eleştirir, “observable behavior” kavramını merkeze alır, ve “implementation details’ı test etmek yerine sadece dışarıdan gözlemlenebilen davranışı test etmek” prensibini sistematize eder. Khorikov’un katkısı, TDD’yi Detroit/London tartışmasının ötesine taşıyıp, iyi testlerin neye benzediği sorusuna nüanslı bir cevap vermesidir. Bu seri, Bölüm 9 ve 11'de Khorikov’un argümanlarını detaylı olarak işleyecektir.

Dave Farley’nin 2021'de yayımlanan Modern Software Engineering: Doing What Works to Build Better Software Faster kitabı, TDD’yi continuous delivery bağlamına yerleştirir. Farley, sürekli teslimat pratiklerinin TDD olmadan mümkün olmadığını gösterir; trunk-based development, feature flag’ler, deployment pipeline’ları gibi pratiklerin TDD ile nasıl birbirini desteklediğini anlatır. Farley’nin perspektifi, TDD’yi bireysel bir geliştirici disiplini olmaktan çıkarıp organizasyonel bir mühendislik kültürünün parçası olarak konumlandırır. Bu seri, Bölüm 32'de Farley’nin yaklaşımına dönecektir.
Kent Beck’in 2024'te yayımladığı Tidy First? A Personal Exercise in Empirical Software Design kitabı, Beck’in TDD üzerine son söylediği şeydir. Bu kitapta Beck, refactoring’in mikro versiyonu olan “tidyings” kavramını işler; küçük, sürekli, az riskli kod düzeltmelerinin TDD pratiğine entegre edilmesini önerir. Bu yaklaşım, TDD’yi sadece kod yazma değil, kod bakımı disiplini olarak da genişletir. Kitabın altbaşlığındaki “empirical software design” deyişi de önemlidir: Beck, yazılım tasarımının ampirik bir alan olduğunu, kuralların değil deneyimin rehber olması gerektiğini savunur. Bu vurgu, TDD’nin başlangıcından beri taşıdığı zanaat ruhuyla uyumludur.
» Düşünsel Soykütüğü Haritası
Yukarıda anlattığımız tarihsel hattın bütününü tek bir görselde toparlamak, okurun zihnindeki kavramların yerleşmesine yardım eder. Aşağıdaki diyagram, TDD’nin düşünsel soykütüğünü ana noktalarıyla gösterir.

Bu harita statik bir grafik değildir; her isim, her tarih, her ok bir hikayedir. Yukarıdaki anlatım boyunca her birinin yerini gösterdik. İleride seride bir referans geldiğinde — örneğin “Meszaros’un terminolojisi” veya “Khorikov’un eleştirisi” — bu haritaya geri dönüp o ismin nereye düştüğünü hatırlamak çoğu zaman okurun zihnini berraklaştıracaktır.
» İki Okulun Kristalleşmesi
Tarihsel anlatımın belki en önemli alt çıktısı, Classicist ve Mockist okulların yıllar içinde nasıl kristalleştiğinin anlaşılmasıdır. Bu kristalleşme bir günde olmadı; pek çok kitabın, makalenin ve tartışmanın birikimi sonucunda netleşti. Aşağıdaki diyagram bu kristalleşme sürecini özetler:

Bu kristalleşme, ileride Faz 3'ün konusu olacak. Şimdilik bilmemiz gereken şudur: TDD topluluğu, başlangıçta tek bir okul olarak başladı, zaman içinde iki dala ayrıldı, bu iki dal birbirini eleştirerek olgunlaştı, ve günümüzde her iki dalın da değerli içgörüler sunduğu kabul edilen bir sentez noktasına geldi. Bu yolculuğu bilmek, “TDD nasıl yapılmalı” sorusunun tek bir doğru cevabı olmadığını, bağlama göre değişen profesyonel kararlar olduğunu anlamak için zemin oluşturur.
» Türkçe Yazın Bağlamında Bir Not
Türkiye’de TDD üzerine bağımsız yerli kaynak son derece azdır. Mevcut içeriklerin büyük çoğunluğu, yabancı kaynakların kısaltılmış özetleri veya belirli bir framework’ün dokümantasyonunun çevirisi şeklindedir. Beck’in Test-Driven Development: By Example kitabı Türkçeye çevrilmiştir ama erişimi sınırlıdır; Fowler’ın Refactoring kitabının çevirisi vardır ama TDD’nin Türkçe yazınında bütüncül bir konumlanması yoktur. Akademik makalelerde TDD’ye değinilir ama mühendislik pratiği olarak değerlendirilmesi nadirdir.

Bu eksikliğin pratik sonucu, Türkiye’deki yazılımcı topluluğunun TDD ile ilişkisinin parçalı ve kişisel kalmasıdır. TDD’yi öğrenen bir geliştirici, onu genellikle bireysel çabasıyla, İngilizce kaynaklardan, dağınık bir biçimde öğrenir. Bu öğrenmenin niteliği büyük ölçüde geliştiricinin sebatına bağlıdır; sistemli bir Türkçe yol haritası yokluğunda, pek çok geliştirici TDD’yi yarı yolda terk eder veya yanlış öğrenir. Bu seri, bu eksikliği gidermeyi açık bir hedef olarak benimser; ama eksikliğin tarihsel köklerini de unutmamak gerekir, çünkü bu kökler okurun karşı karşıya olduğu öğrenme zorluğunun bir kısmının gerçek nedenidir.
Bir başka not olarak, Türkiye’deki bazı şirketler — özellikle e-ticaret, bankacılık ve telekom sektörlerinde — TDD’yi kurumsal olarak benimsemiş ve içsel kültürlerinin bir parçası hâline getirmiştir. Bu şirketlerdeki Tech Lead’lerin ve Software Architect’lerin tecrübesi, ne yazık ki çoğu zaman dışarıya yazılı bir biçimde paylaşılmaz. Bu seri, bu sessiz birikimin bir kısmını da dilin içine taşımayı umut eder; ama bu birikimin tamamına ulaşmak ancak topluluğun kendisinin yazmasıyla mümkündür.
» Bu Tarihten Çıkardığımız Üç Ders
Otuz yıllık bir hikayeyi anlatıp ders çıkarmadan bırakmak, tarihi sadece bir folklor olarak okumak olur. Oysa bir disiplinin tarihini öğrenmenin pratik amacı, o tarihten uygulanabilir içgörüler çıkarmaktır. Bu bölümün anlattığı tarihten üç ders çıkarmak özellikle anlamlıdır.
Birinci ders, TDD’nin kolektif bir keşif olduğudur. Kent Beck’in adı disiplinle özdeşleşmiştir ama TDD tek başına Beck’in icadı değildir. Ward Cunningham’ın etkisi, Erich Gamma’nın katkısı, Tim Mackinnon ve Londra topluluğunun zenginleştirmesi, Michael Feathers’ın legacy boyutunu açması, Gerard Meszaros’un terminolojiyi sistemleştirmesi, Martin Fowler’ın okulları adlandırması, Steve Freeman ve Nat Pryce’ın Outside-In’i kristalleştirmesi olmadan, bugünkü TDD anlayışı imkansızdır. Bu, sadece tarih bilgisi değil, pratiğe ait bir derstir: TDD’yi öğrenmek de kolektif bir süreçtir; yalnız başına öğrenilmesi nadiren mümkündür. Eğer takımınızda TDD’yi pratik etmek istiyorsanız, en az bir arkadaşınızla birlikte başlamak, bireysel başlamaktan kıyaslanamayacak kadar yüksek başarı oranı sağlar.

İkinci ders, disiplinin tartışma içinde olgunlaştığıdır. “Is TDD Dead?” tartışması TDD topluluğu için bir kriz değil, olgunlaşma anı oldu. Fikirler kendiliklerinden olgunlaşmazlar; eleştirildiklerinde, sorgulandıklarında, savunulduklarında olgunlaşırlar. Bu, kişisel öğrenmeniz için de geçerlidir. TDD’yi öğrenmenin en hızlı yolu, onu pratik ederken karşılaştığınız sıkıntıları başkalarıyla tartışmak, “burada ne yapmalıyım” sorusunu açıkça sormak, ve aldığınız cevapları kendi pratiğinizle karşılaştırmaktır. TDD’yi sessizce öğrenmeye çalışan bir geliştirici, çoğu zaman aynı yanlışları yıllarca tekrar eder.

Üçüncü ders, “ortodoks TDD” diye bir şeyin olmadığıdır. Tarih boyunca TDD pratiği değişti, dallandı, eleştirildi, yenilendi. Bugün hâlâ açık tartışmalar vardır: ne kadar mock kullanılmalı, integration testleri ne ağırlıkta olmalı, BDD ile TDD’nin sınırı nerede çizilmeli, AI destekli kod üretimi TDD’yi nasıl değiştirecek. Bu açıklık, bir zayıflık değil, disiplinin canlı olmasının işaretidir. Sizden beklenen, “TDD’yi doğru yapan biri” olmak değil, kendi pratiğinizin gerekçelerini düşünebilen biri olmaktır. Bu seri size kuralları öğretmeyecektir; size kuralları eleştirel biçimde değerlendirme yetisi kazandırmaya çalışacaktır.

» Üç Gözlem Sorusu
Birinci soru: Bu bölümde anlatılan tarihsel figürlerden hangisinin yazılarını okumayı en çok merak ediyorsunuz? Bu merak, sizin TDD ile ilişkinizin hangi yönünü temsil ediyor olabilir? Beck’in pedagojik sadeliğine mi, Freeman ve Pryce’ın titiz sistemleştirmesine mi, Feathers’ın legacy mücadelesine mi, Khorikov’un eleştirel bakışına mı çekiliyorsunuz? Hangisi olursa olsun, bu seçim size kendiniz hakkında bir şey söylüyor.
İkinci soru: Şu an pratik ettiğiniz TDD (eğer pratik ediyorsanız), Classicist okula mı Mockist okula mı daha yakın? Bu cevabı bilinçli olarak mı verdiniz, yoksa bunu hiç düşünmemiş olabilir misiniz? Eğer hiç düşünmediyseniz, geriye dönüp son yazdığınız test sınıflarına bakın: kaç tane mock var, kaç tane assertion var, ne kadarı state’i kontrol ediyor, ne kadarı interaction’ı kontrol ediyor? Bu basit sayım, sizin hangi okula meylettiğinizin hızlı bir göstergesidir.
Üçüncü soru: Eğer 1996'da C3 projesinde Beck’le birlikte çalışıyor olsaydınız, hangi pratiklere doğal olarak meylederdiniz, hangilerine direnirdiniz? Bu sorunun cevabı, bugün TDD’yi öğrenirken karşılaşacağınız iç dirençlerin de habercisidir. Tarihten öğrenmenin bir yolu, kendinizi o tarihin içine koymaktır; bu zihinsel egzersiz, kendinizi tanımanın da hızlı bir yoludur.

» Felsefi Mühür
Bu bölümün anlattığı otuz yıllık hikayeyi tek bir cümleye sığdırmak imkansızdır. Ama bir uzlaşma cümlesi varsa, o cümle Steve Freeman ve Nat Pryce’ın GOOS kitabının önsözünde yer alır:
“The work of design is to think about how to assemble systems. The work of testing is to ensure that what we assembled does what we intended. When done well, these two activities are inseparable.” “Tasarımın görevi, sistemlerin nasıl bir araya getirileceğini düşünmektir. Testin görevi ise, bir araya getirdiğimiz şeyin amaçladığımız şekilde çalıştığından emin olmaktır. Doğru yapıldığında, bu iki faaliyet birbirinden ayrılamaz.”
- — Steve Freeman & Nat Pryce, Growing Object-Oriented Software, Guided by Tests (2009)*
Bu cümle, tarihimizin bize öğrettiği şeyin özüdür. Tasarım ve test, doğru yapıldığında birbirinden ayrılamaz iki etkinliktir. Otuz yıl boyunca yazılım mühendisliği topluluğu, bu iki etkinliği nasıl bir araya getireceğini öğrenmeye çalıştı. TDD bu öğrenmenin en somut ve en başarılı meyvesi oldu. Geri kalan tüm bölümler, bu meyvenin tadına varmaya, içindeki çekirdekleri tanımaya, ve onu kendi bahçenize ekmeye yönelik bir rehberdir.

Bir sonraki bölümde, bu tarihten beslenen ve onu pratiğe çeviren çekirdek mekanizmaya — **Red-Green-Refactor döngüsüne** — geçiyoruz. Otuz yıllık birikimi, üç kelimelik bir mantraya nasıl indirebildiğimizi, ve bu üç kelimenin altında nasıl bir derinlik yattığını birlikte keşfedeceğiz.
**İçindekiler… « Önceki [Giriş: Yola Çıkmadan Önce] » Sonraki **[Bölüm 2 — Red-Green-Refactor: Çekirdek Döngünün Anatomisi] » https://gitlab.com/sahin.yelkenci2/tdd-pure-java » https://gitlab.com/sahin.yelkenci2/tdd-spring
메타데이터
- post_id
- 756add372b46
- slug
- test-driven-development-eğitim-serisi-bölüm-1-tddnin-tarihçesi-ve-düşünsel-soykütüğü-756add372b46
- url
- https://medium.com/@sahinyelkenci/test-driven-development-e%C4%9Fitim-serisi-b%C3%B6l%C3%BCm-1-tddnin-tarih%C3%A7esi-ve-d%C3%BC%C5%9F%C3%BCnsel-soyk%C3%BCt%C3%BC%C4%9F%C3%BC-756add372b46
- canonical_url
- https://medium.com/@sahinyelkenci/test-driven-development-e%C4%9Fitim-serisi-b%C3%B6l%C3%BCm-1-tddnin-tarih%C3%A7esi-ve-d%C3%BC%C5%9F%C3%BCnsel-soyk%C3%BCt%C3%BC%C4%9F%C3%BC-756add372b46
- author_url
- https://medium.com/@sahinyelkenci
- status
- ok
- fetched_at
- 2026-07-24 23:22:17