Halo, Habr!
Untuk waktu yang lama dan hampir tidak berhasil, kami telah mencari kepala yang cerdas yang ingin menggulingkan Tn. Kent Beck di pasar - yaitu, kami mencari seseorang yang siap untuk menulis buku tentang TDD untuk kami. Dengan contoh nyata, cerita tentang kerucut dan prestasi Anda sendiri. Ada sangat sedikit buku tentang hal ini, dan Anda tidak akan membantah klasik ... mungkin itu sebabnya kami belum bertemu kepala ini.
Oleh karena itu, kami memutuskan untuk tidak hanya mengingatkan diri sendiri lagi bahwa kami mencari orang seperti itu, tetapi juga untuk menawarkan terjemahan artikel yang agak kontroversial, yang penulisnya, Doug Arcuri, berbagi pemikirannya sendiri tentang mengapa TDD tidak pernah menjadi arus utama. Mari kita bahas apakah dia benar, dan jika tidak, mengapa.
Ini bukan pengantar pengembangan melalui pengujian. Di sini saya akan mempresentasikan ide-ide saya sendiri tentang me-reboot disiplin ini dan berbicara tentang kesulitan praktis pengujian unit.Programmer legendaris Kent Beck adalah penulis metodologi (pengembangan melalui pengujian) TDD dalam pengertian modernnya. Kent juga, bersama dengan Erich Gamma, berkontribusi pada penciptaan JUnit, kerangka pengujian yang banyak digunakan.
Dalam bukunya yang
dijelaskan XP (edisi kedua), Kent menjelaskan bagaimana
prinsip -
prinsip dibentuk di persimpangan
nilai -
nilai dan
praktik . Jika Anda membuat daftar konsep dan menggantinya dalam semacam formula, Anda akan mendapatkan transformasi.
[KISS, Quality, YAGNI, ...] + [Testing, Specs, ...] == [TDD, ...]
Saya sangat menghormati pekerjaan ini, yang bagi Kent merupakan pekerjaan seumur hidup - tidak hanya untuk mahakarya pemrogramannya, tetapi juga karena fakta bahwa dia tanpa lelah mengeksplorasi esensi
kepercayaan ,
keberanian ,
pelimpahan ,
kesederhanaan , dan
kerentanan . Semua atribut ini sangat diperlukan untuk penemuan Extreme Programming (XP).
TDD adalah prinsip dan
disiplin yang ditaati di komunitas XP. Disiplin ini sudah berusia 19 tahun.
Pada artikel ini saya akan membagikan pendapat saya tentang bagaimana TDD berhasil berasimilasi. Kemudian saya akan membagikan pengamatan pribadi yang menarik yang muncul selama sesi TDD saya. Akhirnya, saya akan mencoba menjelaskan mengapa TDD tidak menembak sekeras kelihatannya. Ayo pergi.
TDD, penelitian dan profesionalismeSelama 19 tahun terakhir, disiplin TDD telah menjadi bahan perdebatan di komunitas pemrograman.
Pertanyaan pertama yang akan ditanyakan oleh analis profesional adalah "berapa persentase pengembang yang menggunakan TDD hari ini?" Jika Anda bertanya kepada teman Robert Martin (Paman Bob) dan teman Kent Beck tentang ini, jawabannya akan menjadi "100%".
Just Paman Bob yakin bahwa
tidak mungkin menganggap diri Anda seorang profesional jika Anda tidak mempraktikkan pengembangan melalui pengujian .
Paman Bob telah terlibat erat dalam disiplin ini selama beberapa tahun, jadi wajar untuk memperhatikannya dalam ulasan ini. Paman Bob membela TDD dan secara signifikan memperluas batas-batas disiplin ini. Anda dapat yakin bahwa saya sangat menghormati Paman Bob dan dogmatismenya yang pragmatis.
Namun, tidak ada yang mengajukan pertanyaan berikut: "setelah semua, berlatih berarti" menggunakan secara sadar "- tetapi itu tidak memungkinkan untuk menilai persentase, kan?" Menurut pendapat subjektif saya, kebanyakan programmer
tidak berurusan dengan TDD bahkan untuk periode simbolik apa pun.
Kenyataannya adalah kita benar-benar tidak tahu angka-angka ini, karena tidak ada yang secara aktif menyelidiki persentase ini. Semua data spesifik terbatas pada sejumlah kecil perusahaan yang dikumpulkan di situs web
WeDoTDD . Di sini Anda akan menemukan statistik perusahaan seperti itu, wawancara dengan mereka yang berlatih TDD sepanjang waktu, tetapi daftar ini tidak besar. Selain itu, itu tidak lengkap, karena bahkan pencarian sederhana mengungkapkan organisasi besar lainnya yang terlibat dalam TDD - tetapi, mungkin, tidak pada kapasitas penuh.
Jika kita tidak tahu berapa banyak perusahaan yang mempraktikkan TDD, pertanyaan berikut muncul: "Seberapa efektif TDD, dilihat dari kemampuannya yang terukur"?
Anda mungkin akan senang bahwa selama bertahun-tahun sejumlah penelitian telah dilakukan yang mengkonfirmasi efektivitas TDD. Di antara mereka pasti ada laporan otoritatif dari
Microsoft ,
IBM , University of North Carolina dan
University of Helsinki .
Diagram ekspresif diambil dari laporan dari Universitas Helsinki.Hingga taraf tertentu, laporan ini membuktikan bahwa kepadatan kesalahan dapat dikurangi hingga 40-60%, yang membutuhkan lebih banyak pekerjaan; runtime meningkat 15-35%. Angka-angka ini sudah mulai dilacak dalam buku-buku dan metodologi industri baru, khususnya di komunitas DevOps.
Sebagian menjawab pertanyaan-pertanyaan ini, kita beralih ke yang terakhir: "Apa yang bisa saya andalkan ketika saya mulai berlatih TDD?" Untuk jawaban itu saya merumuskan pengamatan pribadi saya tentang TDD. Mari kita beralih ke mereka.
1. TDD membutuhkan pendekatan verbalKetika berlatih TDD, kita mulai menemui fenomena "penunjukan target." Sederhananya, proyek singkat seperti mempersiapkan tes gagal dan sukses adalah tantangan intelektual yang serius bagi pengembang. Pengembang harus mengartikulasikan dengan jelas: "Saya percaya bahwa tes ini akan berhasil" dan "Saya percaya bahwa tes ini akan gagal" atau "Saya tidak yakin, biarkan saya bercermin setelah saya mencoba pendekatan ini."
IDE telah menjadi untuk pengembang yang bebek karet yang memohon untuk secara aktif berbicara dengannya. Paling tidak, di perusahaan TDD, percakapan seperti ini harus bergabung menjadi buzz berkelanjutan.
Pikirkan dulu - lalu ambil langkah Anda berikutnya (atau langkah-langkah).
Penguatan seperti itu memainkan peran kunci dalam komunikasi: memungkinkan Anda tidak hanya untuk memprediksi langkah Anda berikutnya, tetapi juga untuk merangsang Anda untuk menulis kode yang
paling sederhana untuk memastikan bahwa tes unit berlalu. Tentu saja, jika pengembang diam, maka ia hampir pasti akan kehilangan arahnya, setelah itu ia harus kembali ke trek.
2. TDD memompa memori motorPengembang, membuat jalan melalui siklus TDD pertamanya, dengan cepat merasa lelah - setelah semua, proses ini tidak nyaman dan terus-menerus terhenti. Ini adalah situasi umum dengan aktivitas apa pun yang baru saja dimulai, tetapi belum dikuasai. Pengembang akan menggunakan jalan pintas, mencoba mengoptimalkan siklus ini untuk mengisi tangannya dan meningkatkan memori motor.
Memori motor sangat diperlukan agar pekerjaan menyenangkan dan berjalan seperti jarum jam. Dalam TDD, ini diperlukan karena pengulangan tindakan.
Dapatkan lembar cheat dengan cara pintas seperti itu. Dapatkan hasil maksimal dari pintasan keyboard Anda di IDE Anda untuk membuat loop efektif. Lalu terus mencari.
Hanya dalam beberapa sesi, pengembang sempurna menguasai pemilihan cara pintas, khususnya, beberapa sesi cukup untuk merakit dan menjalankan uji coba. Ketika Anda berlatih membuat artefak baru, menyorot teks, dan menavigasi melalui IDE, semua ini akan tampak alami bagi Anda. Akhirnya, Anda akan menjadi profesional sejati dan menguasai semua teknik refactoring: khususnya, mengekstraksi, mengganti nama, menghasilkan, membesarkan, memformat ulang, dan keturunan.
3. TDD membutuhkan setidaknya sedikit pemikiran atas tindakan mereka terlebih dahuluSetiap kali pengembang berpikir tentang memulai TDD, ia perlu mengingat peta mental singkat dari tugas-tugas yang perlu diselesaikan. Dalam pendekatan tradisional untuk pemrograman, peta seperti itu tidak selalu ada, dan tugas itu sendiri dapat disajikan "di tingkat makro" atau memiliki sifat penelitian. Mungkin pengembang tidak tahu bagaimana menyelesaikan masalah, tetapi hanya kira-kira membayangkan tujuan. Tes unit diabaikan untuk mencapai tujuan ini.
Sambil duduk di tempat kerja dan diakhiri dengan "duduk" yang lain - cobalah juga melakukan ritual dari ini. Pikirkan dan daftar dulu. Main dengannya. Daftar lebih lanjut. Kemudian lanjutkan, lakukan, pikirkan. Rayakan. Ulangi beberapa kali. Kemudian pikirkan lagi dan berhenti.
Bersabarlah tentang pekerjaan. Lacak apa yang sudah dilakukan - centang kotak. Jangan pernah lipat sampai setidaknya ada satu. Pikirkan!
Mungkin kata-kata dalam daftar akan membutuhkan waktu yang tidak sesuai dengan siklus kerja. Namun, sebelum Anda mulai, Anda harus memiliki daftar. Tanpa itu, Anda tidak tahu ke mana Anda akan pindah. Tidak ada tempat tanpa kartu.
// // "" -> // "a" -> // "aa" -> // "racecar" -> // "Racecar" -> // //
Pengembang harus membuat
daftar tes seperti yang dijelaskan oleh Kent Beck. Daftar tes memungkinkan Anda untuk memecahkan masalah dalam bentuk siklus yang lancar saling masuk. Di atas daftar tes, Anda perlu terus-menerus memproses dan memperbarui, meskipun hanya beberapa detik sebelum tes. Jika daftar tes lulus hampir sepenuhnya minus tahap terakhir, maka hasilnya adalah "merah", dan seluruh tes gagal.
4. TDD tergantung pada komunikasi dengan rekan kerjaSetelah daftar di atas selesai, beberapa langkah mungkin diblokir, karena mereka tidak cukup jelas menggambarkan apa yang harus dilakukan. Pengembang tidak mengerti daftar tes. Sebaliknya juga terjadi - daftar ini terlalu kasar, di mana ada banyak asumsi tentang persyaratan yang belum dirumuskan. Jika Anda mendapatkan sesuatu seperti ini, segera berhenti.
Bertindak tanpa TDD dapat menghasilkan implementasi yang terlalu rumit. Bekerja dengan gaya TDD, tetapi tanpa berpikir, tanpa daftar, tidak kalah berbahaya.
Jika Anda melihat ada celah dalam daftar tes, berdirilah dan ucapkan dengan lantang.
Dalam TDD, pengembang harus memahami produk apa yang harus dilakukan, dipandu oleh gagasan persyaratan yang diperlukan dalam interpretasi pemilik - dan tidak lebih. Jika persyaratan dalam konteks ini tidak jelas, maka daftar tes mulai berantakan. Kegagalan ini perlu didiskusikan. Diskusi yang tenang dengan cepat membantu membangun kepercayaan diri dan rasa hormat. Selain itu, ini adalah bagaimana putaran umpan balik cepat terbentuk.
5. TDD membutuhkan arsitektur berulangKembali ke edisi pertama bukunya XP, Kent menyarankan bahwa tes harus menjadi kekuatan pendorong di balik arsitektur. Namun, selama beberapa tahun, banyak cerita muncul tentang bagaimana tim-tim sprint menemukan tembok di beberapa sprint.
Tentu saja, membangun arsitektur berdasarkan tes tidak rasional. Paman Bob sendiri setuju dengan para ahli lain bahwa itu tidak baik. Diperlukan peta yang lebih luas, tetapi tidak terlalu jauh dari daftar tes yang Anda kembangkan βdi lapanganβ.
Bertahun-tahun kemudian, Kent juga menyuarakan tesis ini dalam bukunya
TDD By Example .
Daya saing dan
keamanan adalah dua bidang utama di mana TDD tidak dapat menjadi kekuatan pendorong, dan pengembang harus menghadapinya secara terpisah. Kita dapat mengatakan bahwa daya saing adalah tingkat desain sistem yang berbeda, daya saing perlu dikembangkan oleh iterasi, mengoordinasikan proses ini dengan TDD. Ini terutama benar hari ini, karena beberapa arsitektur berkembang menuju
paradigma reaktif dan ekstensi reaktif (
reaktivitas adalah daya saing di puncaknya).
Bangun peta yang lebih besar dari keseluruhan organisasi. Membantu melihat hal-hal sedikit dalam perspektif. Pastikan Anda dan tim bergerak dalam jalur yang sama.
Namun, ide yang paling penting adalah
organisasi seluruh sistem, dan satu organisasi TDD tidak disediakan. Faktanya adalah bahwa tes unit adalah hal tingkat rendah. Arsitektur iteratif dan orkestrasi TDD kompleks dalam praktiknya dan membutuhkan kepercayaan antara semua anggota tim, pemrograman pasangan dan ulasan kode yang solid. Tidak sepenuhnya jelas bagaimana mencapai ini, tetapi segera Anda dapat melihat bahwa sesi desain singkat harus dilakukan bersamaan dengan implementasi daftar tes di bidang subjek.
6. TDD mengungkapkan kerapuhan unit test dan menurunkan implementasiTes unit memiliki satu fitur menyenangkan, dan TDD sepenuhnya memberikannya. Mereka tidak mengizinkan untuk membuktikan kebenarannya. E.V.Dijkstra bekerja pada masalah ini dan membahas bagaimana bukti matematika mungkin dalam kasus kami yang akan mengisi celah ini.
Sebagai contoh, dalam contoh berikut, semua tes yang terkait dengan palindrom tidak sempurna hipotetis yang ditentukan oleh logika bisnis diselesaikan. Contoh dikembangkan menggunakan metodologi TDD.
// @Test fun `Given "", then it does not validate`() { "".validate().shouldBeFalse() } @Test fun `Given "a", then it does not validate`() { "a".validate().shouldBeFalse() } @Test fun `Given "aa", then it validates`() { "aa".validate().shouldBeTrue() } @Test fun `Given "abba", then it validates`() { "abba".validate().shouldBeTrue() } @Test fun `Given "racecar", then it validates`() { "racecar".validate().shouldBeTrue() } @Test fun `Given "Racecar", then it validates`() { "Racecar".validate().shouldBeTrue() }
Memang, ada kekurangan dalam tes ini. Tes unit rapuh bahkan dalam kasus yang paling sepele. Mereka tidak pernah berhasil membuktikan kebenarannya, karena jika kami mencobanya akan membutuhkan kerja mental yang luar biasa, dan masukan yang diperlukan untuk ini tidak mungkin dibayangkan.
// , fun String.validate() = if (isEmpty() || length == 1) false else toLowerCase() == toLowerCase().reversed() // , fun String.validate() = length > 1 length > 1
length > 1
dapat disebut
implementasi degenerate . Cukup memadai untuk menyelesaikan tugas, tetapi itu sendiri tidak melaporkan apa pun tentang masalah yang kami coba selesaikan.
Pertanyaannya adalah - kapan pengembang harus berhenti menulis tes? Jawabannya tampak sederhana: ketika itu sudah
cukup dari sudut pandang logika bisnis , dan tidak sesuai dengan pembuat kode. Ini bisa melukai
semangat desain kami, dan kesederhanaan bisa
membuat orang kesal . Perasaan-perasaan ini dikompensasi oleh kepuasan saat melihat kode bersih kita sendiri dan pemahaman bahwa kode selanjutnya dapat dengan yakin di-refactored. Semua kode akan sangat rapi.
Perhatikan bahwa untuk semua yang tidak dapat diandalkan, tes unit diperlukan. Pahami kekuatan dan kelemahan mereka. Jika gambar lengkap tidak bertambah, mungkin kesenjangan ini akan membantu mengisi
pengujian mutasi .
TDD memiliki manfaatnya, tetapi metodologi ini dapat mengalihkan kita dari membangun istana pasir yang tidak perlu. Ya, ini adalah
batasan , tetapi berkat itu, Anda dapat bergerak lebih cepat, lebih jauh, dan lebih andal. Mungkin inilah yang ada dalam pikiran Paman Bob ketika menggambarkan apa, dari sudut pandangnya, artinya
menjadi seorang profesional .
Tapi! Tidak peduli seberapa rapuh tes unit bagi kami, mereka adalah mutlak harus. Merekalah yang mengubah
ketakutan menjadi
keberanian . Tes memberikan refactoring kode yang lembut; selain itu, mereka dapat berfungsi sebagai
panduan dan
dokumentasi untuk setiap pengembang baru yang dapat segera mendapatkan jalur dan bekerja untuk kepentingan proyek - jika proyek ini dicakup oleh unit test.
7. TDD menunjukkan loop terbalik dari pernyataan pengujianAmbil satu langkah lebih jauh. Untuk memahami dua fenomena berikut, kami mempelajari peristiwa berulang yang aneh. Untuk memulai, mari kita lihat FizzBuzz. Ini daftar tes kami.
// 9 15. [OK] // , 3, Fizz . // ...
Kami maju beberapa langkah. Sekarang tes kami gagal.
@Test fun `Given numbers, replace those divisible by 3 with "Fizz"`() { val machine = FizzBuzz() assertEquals(machine.print(), "?") } class FizzBuzz { fun print(): String { var output = "" for (i in 9..15) { output += if (i % 3 == 0) { "Fizz " } else "${i} " } return output.trim() } } Expected <Fizz 10 11 Fizz 13 14 Fizz>, actual <?>.
Secara alami, jika kita menduplikasi data pernyataan yang diharapkan dalam
assertEquals
, maka hasil yang diinginkan tercapai, dan pengujian dilakukan.
Terkadang tes gagal memberikan hasil yang benar diperlukan untuk lulus tes. Saya tidak tahu harus menyebutkan nama acara semacam itu ... mungkin
pengujian voodoo . Berapa kali Anda melihat ini - sebagian tergantung pada kemalasan dan etiket Anda saat pengujian, tetapi saya telah memperhatikan hal-hal seperti itu berkali-kali ketika seseorang mencoba untuk mendapatkan implementasi yang bekerja secara normal dengan set data yang siap pakai dan dapat diprediksi.
8. TDD menunjukkan urutan transformasiTDD dapat menjebak Anda. Kebetulan pengembang bingung dalam transformasi yang dilakukan oleh dirinya sendiri, yang ia gunakan untuk mencapai implementasi yang diinginkan. Pada titik tertentu, kode uji berubah menjadi hambatan di mana kita berhenti.
Jalan
buntu terbentuk. Pengembang harus mundur dan melucuti, menghapus beberapa tes untuk keluar dari perangkap ini. Pengembang tetap tidak terlindungi.
Paman Bob kemungkinan akan mengalami kebuntuan selama bertahun-tahun dalam karirnya, setelah itu, tampaknya, ia menyadari bahwa, untuk lulus ujian, Anda perlu menetapkan urutan tindakan yang tepat untuk meminimalkan kemungkinan memasuki jalan buntu. Selain itu, ia harus menyadari kondisi lain.
Semakin spesifik pengujian, semakin umum kode tersebut .
Urutan transformasi. Anda harus selalu berusaha untuk opsi paling sederhana (di bagian atas daftar).Ini adalah
kondisi prioritas Transisi . Tampaknya, ada urutan risiko refactoring tertentu, yang siap kami raih setelah lulus tes. Biasanya yang terbaik adalah memilih opsi konversi yang diperlihatkan di bagian paling atas daftar (paling sederhana) - dalam hal ini, kemungkinan masuk ke jalan buntu tetap minimal.
TPP atau
Analisis Uji Paman Bob , dapat dikatakan, adalah salah satu fenomena paling menarik, teknologi, dan menarik yang saat ini diamati.
Gunakan untuk menjaga kode Anda sesederhana mungkin.
Cetak daftar TPP dan letakkan di meja Anda. Periksa dengan dia untuk menghindari jalan buntu. Buat aturan: pesanan harus sederhana.
Ini menyimpulkan kisah pengamatan utama saya. Namun, di bagian akhir artikel saya ingin kembali ke pertanyaan yang kami lupa jawab di awal: "Berapa persentase programmer profesional yang menggunakan TDD hari ini?" Saya akan menjawab: "Saya pikir ada beberapa dari mereka." Saya ingin menyelidiki pertanyaan ini di bawah dan mencoba menjelaskan alasannya.
Apakah TDD tertanam dalam praktik?Sayangnya tidak. Secara subyektif, tampaknya persentase pendukungnya rendah, dan saya terus mencari data. Pengalaman saya dalam merekrut, kepemimpinan tim dan pengembangan diri (yang membuat saya terpesona) memungkinkan saya untuk melakukan pengamatan berikut.
Alasan 1: Kurang kontak dengan budaya pengujian yang sebenarnyaSaya bisa berasumsi bahwa sebagian besar pengembang tidak memiliki kesempatan untuk belajar dan bekerja dalam
budaya pengujian yang sebenarnya.
Budaya pengujian adalah lingkungan di mana pengembang secara sadar berlatih dan meningkatkan dalam seni pengujian. Mereka terus melatih kolega yang masih belum memiliki pengalaman yang cukup di bidang ini. Umpan balik telah dibuat di setiap pasangan dan setiap kelompok permintaan yang membantu semua peserta untuk mengembangkan keterampilan pengujian. Selain itu, ada dukungan serius dan rasa sikut di seluruh hierarki insinyur. Semua manajer memahami esensi pengujian dan meyakininya. Ketika tenggat waktu mulai habis, disiplin pengujian tidak dibuang, tetapi terus diikuti.
Mereka yang beruntung menguji diri mereka dalam budaya pengujian seperti itu, misalnya, saya memiliki kesempatan untuk melakukan pengamatan seperti itu. .
2:TDD, ,
xUnit Patterns Effective Unit Testing . , -, , , . .
. , . . , , , β¦ .
3:: , , . , , ; - , β .
4:, , TDD . , .
, , : Β« , Β». : , Β« Β» β .
β .
KesimpulanXP β
,
. β , . TDD.
, , . «» , , β , .
XP Explained. , , ., - .
, β , . , , , .
, , , .
TDD Β« Β» , . TDD . TDD .
. TDD , . TDD β , , . , TDD , . , .
@Test fun `Given software, when we build, then we expect tests`() { build(software) shoudHave tests }
, TDD β ,
,
. . , , , .