Pukul 07.15 pagi Dukungan teknis kami dibanjiri dengan pekerjaan. Selamat Pagi Amerika baru saja berbicara tentang kami dan banyak dari mereka yang mengunjungi situs kami untuk pertama kalinya mengalami kesalahan.
Kami benar-benar terburu-buru. Kami, saat ini, sebelum kehilangan kesempatan untuk mengubah pengunjung sumber daya menjadi pengguna baru, akan meluncurkan paket perbaikan. Salah satu pengembang menyiapkan sesuatu. Dia pikir ini akan membantu mengatasi masalah tersebut. Kami menempatkan tautan ke versi program yang diperbarui, yang belum mulai diproduksi, ke obrolan perusahaan, dan kami meminta semua orang untuk mengujinya. Itu berhasil!
Insinyur heroik kami menjalankan skrip untuk menyebarkan sistem dan setelah beberapa menit pembaruan berjalan ke pertempuran. Tiba-tiba, jumlah panggilan dukungan teknis berlipat ganda. Perbaikan mendesak kami memecahkan sesuatu, para pengembang mengambil menyalahkan git, dan para insinyur memutar kembali sistem ke keadaan sebelumnya pada waktu itu.

Penulis materi, terjemahan yang kami terbitkan hari ini, percaya bahwa semua ini bisa dihindari berkat TDD.
Mengapa saya menggunakan TDD?
Saya belum pernah berada dalam situasi seperti ini sejak lama. Dan bukan karena pengembang berhenti membuat kesalahan. Faktanya adalah bahwa selama bertahun-tahun sekarang, di setiap tim yang saya pimpin dan pengaruhi, metodologi TDD diterapkan. Kesalahan, tentu saja, masih terjadi, tetapi penetrasi ke dalam produksi masalah yang dapat "merobohkan" proyek telah menurun hampir nol, meskipun frekuensi pembaruan perangkat lunak dan jumlah tugas yang perlu diselesaikan selama pembaruan telah tumbuh secara eksponensial sejak saat itu ketika sesuatu terjadi yang saya bicarakan di awal.
Ketika seseorang bertanya kepada saya mengapa dia harus menghubungi TDD, saya menceritakan kisah ini kepadanya, dan saya dapat mengingat selusin lagi kasus serupa. Salah satu alasan paling penting mengapa saya beralih ke TDD adalah bahwa metodologi ini
meningkatkan cakupan tes dengan kode, yang menyebabkan
kesalahan produksi
40-80% lebih sedikit . Inilah yang paling saya sukai tentang TDD. Ini menghilangkan segunung masalah dari pundak pengembang.
Selain itu, perlu dicatat bahwa TDD menyelamatkan pengembang dari rasa takut membuat perubahan pada kode.
Dalam proyek-proyek yang saya ikuti, set modul otomatis dan tes fungsional hampir setiap hari mencegah kode masuk ke produksi, yang secara serius dapat mengganggu pekerjaan proyek-proyek ini. Sebagai contoh, sekarang saya melihat 10 pembaruan perpustakaan otomatis yang dibuat minggu lalu, sehingga sebelum merilisnya tanpa menggunakan TDD, saya takut mereka akan merusak sesuatu.
Semua pembaruan ini secara otomatis diintegrasikan ke dalam kode, dan sudah digunakan dalam produksi. Saya tidak memeriksa salah satu dari mereka secara manual, dan tidak khawatir sama sekali bahwa mereka dapat berdampak buruk pada proyek. Pada saat yang sama, untuk memberikan contoh ini, saya tidak perlu berpikir panjang. Saya baru saja membuka GitHub, melihat merger baru-baru ini, dan melihat apa yang saya bicarakan. Tugas yang sebelumnya diselesaikan secara manual (atau, lebih buruk lagi, masalah yang diabaikan) sekarang adalah proses latar belakang otomatis. Anda dapat mencoba melakukan sesuatu yang serupa tanpa cakupan kode yang baik dengan tes, tetapi saya tidak akan merekomendasikan melakukan ini.
Apa itu TDD?
TDD adalah singkatan dari Test Driven Development. Proses yang diterapkan dengan menerapkan metodologi ini sangat sederhana:
Tes mendeteksi kesalahan, tes berhasil diselesaikan, refactoring dilakukanBerikut adalah prinsip dasar untuk menggunakan TDD:
- Sebelum menulis kode implementasi untuk beberapa fitur, mereka menulis tes yang memungkinkan Anda untuk memeriksa apakah kode implementasi masa depan ini berfungsi atau tidak. Sebelum melanjutkan ke langkah berikutnya, tes dimulai dan diyakinkan bahwa ia melakukan kesalahan. Berkat ini, Anda dapat yakin bahwa tes tidak menghasilkan hasil positif palsu, itu adalah semacam tes dari tes itu sendiri.
- Mereka menciptakan implementasi peluang dan memastikan bahwa ia lulus ujian dengan sukses.
- Lakukan, jika perlu, kode refactoring. Refactoring, di hadapan tes yang dapat menunjukkan kepada pengembang apakah sistem itu bekerja dengan benar atau salah, menanamkan kepercayaan pada pengembang dalam tindakannya.
Bagaimana TDD membantu menghemat waktu yang dibutuhkan untuk mengembangkan program?
Pada pandangan pertama, mungkin terlihat bahwa tes menulis berarti peningkatan yang signifikan dalam jumlah kode proyek, dan bahwa semua ini membutuhkan banyak waktu ekstra dari pengembang. Dalam kasus saya, pada awalnya, semuanya hanya itu, dan saya mencoba memahami bagaimana, pada prinsipnya, mungkin untuk menulis kode yang dapat diuji, dan bagaimana menambahkan tes ke kode yang telah ditulis.
TDD dicirikan oleh kurva belajar tertentu, dan sementara pemula naik sepanjang kurva ini, waktu yang dibutuhkan untuk pengembangan dapat meningkat sebesar
15-35% . Seringkali inilah yang terjadi. Tetapi di suatu tempat sekitar 2 tahun setelah dimulainya penggunaan TDD, sesuatu yang luar biasa mulai terjadi. Yaitu, misalnya, saya mulai, dengan penulisan awal tes unit, pemrograman lebih cepat dari sebelumnya ketika TDD tidak digunakan.
Beberapa tahun yang lalu, saya menerapkan, dalam sistem klien, kemampuan untuk bekerja dengan potongan-potongan klip video. Yaitu, intinya adalah memungkinkan untuk memungkinkan pengguna untuk menunjukkan awal dan akhir fragmen rekaman, dan menerima tautan ke sana, yang memungkinkan untuk merujuk ke tempat tertentu dalam klip, dan bukan ke seluruh klip.
Saya tidak bekerja. Pemain mencapai ujung fragmen dan terus memainkannya, tetapi saya tidak tahu mengapa ini terjadi.
Saya pikir masalahnya adalah menghubungkan pendengar acara dengan tidak tepat. Kode saya terlihat seperti ini:
video.addEventListener('timeupdate', () => { if (video.currentTime >= clip.stopTime) { video.pause(); } });
Proses menemukan masalah tampak seperti ini: membuat perubahan, kompilasi, me-reboot, mengklik, menunggu ... Urutan tindakan ini diulangi berulang-ulang.
Untuk memeriksa setiap perubahan yang dimasukkan ke dalam proyek, perlu waktu hampir satu menit untuk dihabiskan, dan saya mengalami banyak sekali pilihan untuk menyelesaikan masalah (kebanyakan dari mereka 2-3 kali).
Mungkin saya membuat kesalahan dalam kata kunci waktu
timeupdate
? Apakah saya memahami fitur bekerja dengan API dengan benar? Apakah panggilan
video.pause()
? Saya membuat perubahan pada kode, menambahkan
console.log()
, kembali ke browser, mengklik tombol
, mengklik posisi yang terletak di ujung fragmen yang dipilih, dan kemudian dengan sabar menunggu sampai klip itu diputar sepenuhnya. Masuk ke dalam konstruksi
if
tidak mengarah ke apa pun. Itu tampak seperti petunjuk tentang kemungkinan masalah. Saya menyalin kata
timeupdate
dari dokumentasi API untuk benar-benar yakin bahwa saya tidak membuat kesalahan ketika memasukkannya. Saya memuat kembali halaman itu, klik lagi, tunggu lagi. Dan lagi, program ini menolak untuk bekerja dengan benar.
Saya akhirnya meletakkan
console.log()
luar blok
if
. "Itu tidak akan membantu," pikirku. Pada akhirnya,
if
itu sangat sederhana sehingga saya tidak tahu cara mengejanya dengan salah. Tetapi masuk dalam kasus ini berhasil. Saya tersedak kopi. "Apa-apaan itu!?" Saya pikir.
Hukum debugging Murphy. Tempat program yang tidak pernah Anda uji, karena Anda sangat yakin bahwa itu tidak dapat mengandung kesalahan, akan berubah menjadi tempat di mana Anda akan menemukan kesalahan setelah, setelah benar-benar kelelahan, Anda akan membuat perubahan ke tempat ini hanya karena bahwa mereka telah mencoba semua yang dapat mereka pikirkan.
Saya menetapkan breakpoint dalam program untuk memahami apa yang terjadi. Saya menjelajahi arti
clip.stopTime
. Yang mengejutkan saya, itu tidak
undefined
. Mengapa Saya melihat kode lagi. Ketika pengguna memilih waktu akhir fragmen, program menempatkan penanda untuk akhir fragmen di tempat yang tepat, tetapi tidak menetapkan nilai
clip.stopTime
. "Saya seorang idiot yang luar biasa," saya berpikir, "Saya tidak boleh diizinkan masuk ke komputer sampai akhir hidup saya."
Saya tidak melupakan ini dan bertahun-tahun kemudian. Dan semuanya - berkat sensasi yang saya alami, masih menemukan kesalahan. Anda mungkin tahu apa yang saya bicarakan. Dengan semua ini terjadi. Dan, mungkin, semua orang akan dapat mengenali diri mereka sendiri dalam meme ini.
Ini adalah bagaimana saya terlihat ketika saya memprogramJika saya menulis program itu hari ini, saya akan mulai mengerjakannya seperti ini:
describe('clipReducer/setClipStopTime', async assert => { const stopTime = 5; const clipState = { startTime: 2, stopTime: Infinity }; assert({ given: 'clip stop time', should: 'set clip stop time in state', actual: clipReducer(clipState, setClipStopTime(stopTime)), expected: { ...clipState, stopTime } }); });
Ada perasaan bahwa ada lebih banyak kode daripada di baris ini:
clip.stopTime = video.currentTime
Tapi itulah intinya. Kode ini bertindak sebagai spesifikasi. Ini adalah dokumentasi dan bukti bahwa kode berfungsi seperti yang disyaratkan oleh dokumentasi ini. Dan, karena dokumentasi ini ada, jika saya mengubah prosedur untuk bekerja dengan marker untuk waktu akhir fragmen, saya tidak perlu khawatir tentang apakah selama pengenalan perubahan ini saya melanggar operasi yang benar dengan waktu berakhirnya klip.
Ngomong -ngomong, ini adalah bahan yang berguna untuk menulis unit test, sama seperti yang baru saja kita lihat.
Intinya bukan berapa lama waktu yang diperlukan untuk memasukkan kode ini. Intinya adalah berapa lama untuk melakukan debug jika terjadi kesalahan. Jika kode salah, tes akan memberikan laporan kesalahan yang sangat baik. Saya akan segera tahu bahwa masalahnya bukan pengendali acara. Saya akan tahu bahwa itu ada di
setClipStopTime()
, atau di
clipReducer()
, di mana perubahan status diterapkan. Berkat tes ini, saya akan tahu tentang fungsi apa yang dilakukan oleh kode, apa yang sebenarnya ditampilkan, dan apa yang diharapkan darinya. Dan, yang lebih penting, kolega saya akan memiliki pengetahuan yang sama, yang, enam bulan setelah saya menulis kode, akan memperkenalkan fitur-fitur baru ke dalamnya.
Memulai proyek baru, saya, sebagai salah satu hal pertama, mengatur
skrip pengamat yang secara otomatis menjalankan tes unit setiap kali file tertentu diubah. Saya sering memprogram menggunakan dua monitor. Di salah satu dari mereka, konsol pengembang dibuka, di mana hasil skrip tersebut ditampilkan, di sisi lain, antarmuka lingkungan tempat saya menulis kode ditampilkan. Ketika saya membuat perubahan pada kode, saya biasanya, dalam 3 detik, mencari tahu apakah perubahan itu berfungsi atau tidak.
Bagi saya, TDD jauh lebih dari sekedar asuransi. Ini adalah kemampuan untuk secara konstan dan cepat, menerima informasi tentang status kode saya secara waktu nyata. Hadiah instan dalam bentuk tes yang lulus, atau laporan kesalahan instan jika saya melakukan kesalahan.
Bagaimana metodologi TDD mengajari saya cara menulis kode yang lebih baik?
Saya ingin membuat satu penerimaan, bahkan mengakui itu memalukan: Saya tidak tahu cara membuat aplikasi sebelum saya belajar TDD dan pengujian unit. Saya tidak bisa membayangkan bagaimana saya dipekerjakan sama sekali, tetapi setelah saya mewawancarai ratusan pengembang, saya dapat dengan yakin mengatakan bahwa banyak programmer yang berada dalam situasi yang sama. Metodologi TDD telah mengajarkan saya hampir semua yang saya tahu tentang dekomposisi dan komposisi komponen perangkat lunak yang efisien (maksud saya modul, fungsi, objek, komponen antarmuka pengguna, dll.).
Alasan untuk ini adalah bahwa unit test memaksa programmer untuk menguji komponen secara terpisah satu sama lain dan dari subsistem I / O. Jika modul dilengkapi dengan beberapa data input, modul tersebut harus memberikan data keluaran tertentu yang diketahui sebelumnya. Jika tidak, tes gagal. Jika ya, tes berhasil. Intinya di sini adalah bahwa modul harus bekerja secara independen dari sisa aplikasi. Jika Anda menguji logika negara, Anda harus dapat melakukan ini tanpa menampilkan apa pun di layar atau menyimpan apa pun ke database. Jika Anda menguji pembentukan antarmuka pengguna, maka Anda harus dapat mengujinya tanpa harus memuat halaman di browser atau mengakses sumber daya jaringan.
Antara lain, metodologi TDD mengajarkan saya bahwa hidup menjadi lebih mudah jika Anda berjuang untuk minimalis ketika mengembangkan komponen antarmuka pengguna. Selain itu, logika bisnis dan efek samping harus diisolasi dari antarmuka pengguna. Dari sudut pandang praktis, ini berarti bahwa jika Anda menggunakan kerangka kerja UI berbasis komponen seperti
React atau Angular, mungkin disarankan untuk membuat komponen presentasi yang bertanggung jawab untuk menampilkan sesuatu di layar dan komponen wadah yang tidak terhubung satu sama lain dicampur.
Komponen presentasi yang menerima properti tertentu selalu menghasilkan hasil yang sama. Komponen seperti itu dapat dengan mudah diverifikasi menggunakan unit test. Ini memungkinkan Anda untuk mengetahui apakah komponen berfungsi dengan benar dengan properti, dan apakah logika kondisional tertentu yang digunakan dalam pembentukan antarmuka benar. Misalnya, ada kemungkinan bahwa komponen yang membentuk daftar tidak boleh menampilkan apa pun selain undangan untuk menambahkan elemen baru ke daftar jika daftar kosong.
Saya tahu tentang prinsip pemisahan tanggung jawab jauh sebelum saya menguasai TDD, tetapi saya tidak tahu bagaimana berbagi tanggung jawab antara entitas yang berbeda.
Unit testing memungkinkan saya untuk mempelajari penggunaan mokas untuk menguji sesuatu, dan kemudian saya menemukan bahwa mengolok-olok adalah tanda bahwa ada
sesuatu yang salah dengan kode . Itu mengejutkan saya dan benar-benar mengubah pendekatan saya terhadap komposisi perangkat lunak.
Semua pengembangan perangkat lunak adalah komposisi: proses memecah masalah besar menjadi banyak masalah kecil, mudah dipecahkan, dan kemudian menciptakan solusi untuk masalah ini yang membentuk aplikasi. Tuxing demi pengujian unit menunjukkan bahwa unit atom dari komposisi, pada kenyataannya, bukan atom. Mempelajari cara menyingkirkan mok tanpa memengaruhi cakupan kode dengan tes memungkinkan saya belajar tentang cara mengidentifikasi alasan tersembunyi yang tak terhitung banyaknya untuk keterkaitan kuat entitas.
Ini memungkinkan saya, sebagai pengembang, untuk tumbuh secara profesional. Ini mengajari saya cara menulis kode yang lebih sederhana yang lebih mudah untuk diperluas, dipelihara, skala. Ini berlaku untuk kompleksitas kode itu sendiri, dan untuk pengorganisasiannya dalam sistem terdistribusi besar seperti infrastruktur cloud.
Bagaimana TDD menghemat waktu tim?
Saya sudah mengatakan bahwa TDD, di tempat pertama, mengarah pada
peningkatan cakupan kode dengan tes. Alasan untuk ini adalah bahwa kita tidak mulai menulis kode untuk mengimplementasikan beberapa fitur sampai kita menulis tes yang memeriksa operasi yang benar dari kode masa depan ini. Pertama kita menulis tes. Lalu kami membiarkannya diakhiri dengan kesalahan. Kemudian kami menulis kode untuk mengimplementasikan peluang. Kami menguji kode, kami menerima pesan kesalahan, kami mencapai kelulusan tes, kami melakukan refactoring dan ulangi proses ini.
Proses ini memungkinkan Anda untuk membuat "pagar" di mana hanya beberapa kesalahan bisa "melompat". Perlindungan kesalahan ini memiliki efek luar biasa pada seluruh tim pengembangan. Ini mengurangi rasa takut tim penggabungan.
Tingkat tinggi cakupan kode dengan tes memungkinkan tim untuk menyingkirkan keinginan untuk secara manual mengontrol perubahan apa pun, bahkan kecil, dalam basis kode. Perubahan kode menjadi bagian alami dari alur kerja.
Menyingkirkan rasa takut membuat perubahan pada kode mirip dengan kaburnya mesin tertentu. Jika ini tidak dilakukan, mesin pada akhirnya akan berhenti - sampai dilumasi dan dihidupkan ulang.
Tanpa rasa takut ini, proses mengerjakan program jauh lebih tenang dari sebelumnya. Permintaan tarik tidak ditunda sampai yang terakhir. Sistem CI / CD akan menjalankan tes, dan jika tes gagal, itu akan menghentikan proses membuat perubahan pada kode proyek. Pada saat yang sama, pesan kesalahan dan informasi tentang di mana mereka terjadi akan sangat sulit untuk tidak diperhatikan.
Ini intinya.
Pembaca yang budiman! Apakah Anda menggunakan TDD saat mengerjakan proyek Anda?
