Dalam Test Driven Development (TDD) Anda mulai dengan solusi suboptimal dan kemudian menghasilkan yang lebih baik dengan menambahkan kasus uji dan dengan refactoring. Langkah-langkahnya seharusnya kecil, yang berarti bahwa setiap solusi baru akan entah bagaimana berada di lingkungan yang sebelumnya.
Ini menyerupai metode optimasi lokal matematika seperti gradient descent atau pencarian lokal. Keterbatasan yang terkenal dari metode tersebut adalah bahwa mereka tidak menjamin untuk menemukan optimum global, atau bahkan optimum lokal yang dapat diterima. Jika titik awal Anda dipisahkan dari semua solusi yang dapat diterima oleh sebagian besar solusi buruk, tidak mungkin untuk sampai ke sana dan metode ini akan gagal.
Untuk lebih spesifik: Saya sedang memikirkan sebuah skenario di mana Anda telah menerapkan sejumlah kasus uji dan kemudian menemukan bahwa kasus uji berikutnya akan memerlukan pendekatan yang sangat berbeda. Anda harus membuang pekerjaan sebelumnya dan memulai lagi dari awal.
Pemikiran ini sebenarnya dapat diterapkan pada semua metode gesit yang berjalan dalam langkah-langkah kecil, tidak hanya untuk TDD. Apakah analogi yang diajukan antara TDD dan pengoptimalan lokal ini memiliki kelemahan serius?
sumber
Jawaban:
Untuk membuat perbandingan Anda lebih memadai: untuk beberapa jenis masalah, algoritme pengulangan berulang sangat mungkin menghasilkan optima lokal yang baik, untuk beberapa situasi lain, mereka bisa gagal.
Saya bisa membayangkan situasi di mana ini bisa terjadi dalam kenyataan: ketika Anda memilih arsitektur yang salah dengan cara yang Anda butuhkan untuk membuat ulang semua tes yang ada lagi dari awal. Katakanlah Anda mulai menerapkan 20 kasus pengujian pertama Anda dalam bahasa pemrograman X pada sistem operasi A. Sayangnya, persyaratan 21 mencakup bahwa seluruh program perlu dijalankan pada sistem operasi B, di mana X tidak tersedia. Dengan demikian, Anda perlu membuang sebagian besar pekerjaan Anda dan mengimplementasikan kembali dalam bahasa Y. (Tentu saja, Anda tidak akan membuang kode sepenuhnya, tetapi port itu ke bahasa dan sistem baru.)
Ini mengajarkan kita, bahkan ketika menggunakan TDD, adalah ide yang baik untuk melakukan beberapa analisis & desain secara keseluruhan sebelumnya. Namun, ini juga berlaku untuk jenis pendekatan lain, jadi saya tidak melihat ini sebagai masalah TDD yang melekat. Dan, untuk sebagian besar tugas pemrograman dunia nyata Anda hanya dapat memilih arsitektur standar (seperti bahasa pemrograman X, sistem operasi Y, sistem basis data Z pada perangkat keras XYZ), dan Anda dapat relatif yakin bahwa metodologi iteratif atau gesit seperti TDD tidak akan membawa Anda ke jalan buntu.
Mengutip Robert Harvey: "Anda tidak dapat menumbuhkan arsitektur dari unit test." Atau pdr: "TDD tidak hanya membantu saya mencapai desain akhir terbaik, ini membantu saya sampai di sana dalam upaya yang lebih sedikit."
Jadi sebenarnya apa yang Anda tulis
mungkin menjadi kenyataan - ketika Anda memilih arsitektur yang salah, Anda cenderung tidak mencapai solusi yang diperlukan dari sana.
Di sisi lain, ketika Anda melakukan perencanaan keseluruhan sebelumnya dan memilih arsitektur yang tepat, menggunakan TDD harus seperti memulai algoritma pencarian berulang di area di mana Anda dapat mencapai "global maksimum" (atau setidaknya maksimum cukup baik) ) dalam beberapa siklus.
sumber
Saya tidak berpikir TDD memiliki masalah maxima lokal. Kode yang Anda tulis mungkin, seperti yang telah Anda perhatikan dengan benar, tetapi itulah sebabnya refactoring (menulis ulang kode tanpa mengubah fungsi) sudah ada. Pada dasarnya, ketika tes Anda meningkat, Anda dapat menulis ulang bagian signifikan dari model objek Anda jika Anda perlu sambil menjaga perilaku tidak berubah berkat tes. Tes nyatakan kebenaran invarian tentang sistem Anda yang, oleh karena itu, harus valid baik secara lokal maupun maksimum.
Jika Anda tertarik pada masalah yang berkaitan dengan TDD, saya dapat menyebutkan tiga yang berbeda yang sering saya pikirkan:
Masalah kelengkapan : berapa banyak tes yang diperlukan untuk menggambarkan sistem sepenuhnya? Apakah "pengkodean dengan contoh kasus" merupakan cara lengkap untuk menggambarkan suatu sistem?
Masalah pengerasan : apa pun antarmuka pengujian, perlu memiliki antarmuka yang tidak dapat diubah. Tes mewakili kebenaran invarian , ingat. Sayangnya kebenaran-kebenaran ini tidak diketahui sama sekali untuk sebagian besar kode yang kita tulis, paling-paling hanya untuk objek yang menghadap ke luar.
Masalah kerusakan pengujian : untuk membuat pernyataan dapat diuji, kita mungkin perlu menulis kode suboptimal (misalnya, kurang performan). Bagaimana kita menulis tes sehingga kodenya sebagus mungkin?
Diedit untuk menanggapi komentar: inilah contoh mengecualikan maksimum lokal untuk fungsi "ganda" melalui refactoring
Tes 1: ketika input adalah 0, kembalikan nol
Pelaksanaan:
Refactoring: tidak diperlukan
Tes 2: ketika input 1, kembalikan 2
Pelaksanaan:
Refactoring: tidak diperlukan
Tes 3: ketika input 2, kembalikan 4
Pelaksanaan:
Refactoring:
sumber
Apa yang Anda gambarkan dalam istilah matematika adalah apa yang kami sebut melukis diri sendiri ke sudut. Kejadian ini hampir tidak eksklusif untuk TDD. Di air terjun, Anda dapat mengumpulkan dan menuangkan persyaratan selama berbulan-bulan dengan harapan Anda dapat melihat global max hanya untuk sampai di sana dan menyadari bahwa ada ide yang lebih baik hanya di bukit berikutnya.
Perbedaannya adalah dalam lingkungan yang gesit yang Anda tidak pernah harapkan untuk menjadi sempurna pada titik ini sehingga Anda lebih dari siap untuk membuang ide lama dan pindah ke ide baru.
Lebih spesifik untuk TDD ada teknik untuk mencegah hal ini terjadi pada Anda saat Anda menambahkan fitur di bawah TDD. Ini adalah Prioritas Transformasi . Di mana TDD memiliki cara formal untuk Anda refactor, ini adalah cara formal untuk menambahkan fitur.
sumber
Dalam jawabannya , @Sklivvz dengan meyakinkan menyatakan bahwa masalahnya tidak ada.
Saya ingin berargumen bahwa itu tidak masalah: premis mendasar (dan raison d'être) dari metodologi iteratif secara umum dan Agile dan khususnya TDD pada khususnya, adalah bahwa tidak hanya optimum global, tetapi juga optimum lokal juga ' tidak diketahui. Jadi, dengan kata lain: meskipun itu masalah, tidak ada jalan lain untuk melakukannya dengan cara yang iteratif. Dengan asumsi bahwa Anda menerima premis dasar.
sumber
Dapatkah praktik TDD dan Agile berjanji untuk menghasilkan solusi yang optimal? (Atau bahkan solusi "baik"?)
Tidak persis. Tapi, itu bukan tujuan mereka.
Metode-metode ini hanya menyediakan "jalan aman" dari satu negara ke negara lain, mengakui bahwa perubahan memakan waktu, sulit, dan berisiko. Dan inti dari kedua praktik tersebut adalah untuk memastikan bahwa aplikasi dan kode tersebut layak dan terbukti memenuhi persyaratan dengan lebih cepat dan lebih teratur.
TDD berfokus pada memastikan setiap "potongan" kode memenuhi persyaratan. Secara khusus, ini membantu memastikan bahwa kode memenuhi persyaratan yang sudah ada sebelumnya, yang bertentangan dengan membiarkan persyaratan didorong oleh pengkodean yang buruk. Tapi, itu tidak membuat janji bahwa implementasinya "optimal" dengan cara apa pun.
Adapun proses Agile:
Agility tidak mencari solusi optimal ; hanya solusi yang berfungsi - dengan tujuan mengoptimalkan ROI . Ini menjanjikan solusi yang bekerja lebih cepat daripada nanti ; bukan yang "optimal".
Tapi, tidak apa-apa, karena pertanyaannya salah.
Optimal dalam pengembangan perangkat lunak adalah fuzzy, target yang bergerak. Persyaratan biasanya dalam fluks dan penuh dengan rahasia yang hanya muncul, sangat memalukan Anda, di ruang konferensi yang penuh dengan bos bos Anda. Dan "kebaikan intrinsik" dari arsitektur dan pengkodean solusi dinilai oleh pendapat yang dibagi dan subyektif dari rekan-rekan Anda dan pendapat manajerial Anda - tidak seorang pun di antara mereka yang mungkin benar-benar mengetahui apa pun tentang perangkat lunak yang baik.
Dalam Paling tidak, TDD dan Agile praktek mengakui kesulitan dan mencoba untuk mengoptimalkan untuk dua hal yang yang obyektif dan terukur: . Bekerja v Tidak-Bekerja dan Sooner v Nanti..
Dan, bahkan jika kita memiliki "bekerja" dan "lebih cepat" sebagai metrik objektif, kemampuan Anda untuk mengoptimalkannya terutama bergantung pada keterampilan dan pengalaman tim.
Hal-hal yang dapat Anda tafsirkan sebagai upaya menghasilkan solusi optimal meliputi hal-hal seperti:
dll ..
Apakah masing-masing dari hal - hal itu benar-benar menghasilkan solusi optimal akan menjadi pertanyaan besar lain untuk ditanyakan!
sumber
Satu hal yang tidak ada yang ditambahkan sejauh ini adalah bahwa "Pengembangan TDD" yang Anda gambarkan sangat abstrak dan tidak realistis. Mungkin seperti itu dalam aplikasi matematika di mana Anda mengoptimalkan suatu algoritma tetapi itu tidak banyak terjadi dalam aplikasi bisnis yang paling banyak dikerjakan oleh pembuat kode.
Di dunia nyata, tes Anda pada dasarnya menjalankan dan memvalidasi Aturan Bisnis:
Misalnya - Jika seorang pelanggan berusia 30 tahun yang tidak merokok dengan seorang istri dan dua anak, kategori premiumnya adalah "x" dll.
Anda tidak akan mengubah mesin penghitungan premium secara iteratif hingga benar untuk waktu yang lama - dan hampir pasti tidak saat aplikasi aktif;).
Apa yang sebenarnya Anda buat adalah jaring pengaman sehingga ketika metode perhitungan baru ditambahkan untuk kategori pelanggan tertentu, semua aturan lama tidak tiba-tiba rusak dan memberikan jawaban yang salah. Jaring pengaman bahkan lebih berguna jika langkah pertama debugging adalah membuat tes (atau serangkaian tes) yang mereproduksi kesalahan sebelum menulis kode untuk memperbaiki bug. Kemudian, satu tahun ke belakang, jika seseorang secara tidak sengaja menciptakan kembali bug asli, unit test istirahat sebelum kode bahkan diperiksa. Ya, satu hal yang memungkinkan TDD adalah bahwa Anda sekarang dapat melakukan refactoring dan merapikan barang-barang dengan percaya diri. tetapi itu seharusnya tidak menjadi bagian besar dari pekerjaan Anda.
sumber
Saya tidak berpikir itu akan menghalangi. Sebagian besar tim tidak memiliki siapa pun yang mampu menghasilkan solusi optimal bahkan jika Anda menuliskannya di papan tulis mereka. TDD / Agile tidak akan menghalangi mereka.
Banyak proyek tidak memerlukan solusi optimal dan yang diperlukan, waktu, energi dan fokus yang diperlukan akan dibuat di bidang ini. Seperti semua hal lain yang cenderung kita bangun, pertama, buat itu bekerja. Kemudian membuatnya cepat. Anda bisa melakukan ini dengan semacam prototipe jika kinerjanya begitu penting dan kemudian membangun kembali semuanya dengan kebijaksanaan yang diperoleh melalui banyak iterasi.
Ini bisa terjadi, tetapi yang lebih mungkin terjadi adalah ketakutan untuk mengubah bagian aplikasi yang kompleks. Tidak melakukan tes apa pun dapat menciptakan rasa takut yang lebih besar di bidang ini. Satu keuntungan dari TDD dan memiliki serangkaian pengujian adalah bahwa Anda membangun sistem ini dengan anggapan bahwa itu perlu diubah. Ketika Anda menemukan solusi optimal monolitik ini sejak awal, mungkin sangat sulit untuk berubah.
Juga, letakkan ini dalam konteks kekhawatiran Anda akan optimasi yang kurang, dan Anda tidak bisa tidak menghabiskan waktu untuk mengoptimalkan hal-hal yang seharusnya tidak Anda miliki dan menciptakan solusi yang tidak fleksibel karena Anda terlalu fokus pada kinerja mereka.
sumber
Dapat menipu untuk menerapkan konsep matematika seperti "optimal lokal" untuk desain perangkat lunak. Menggunakan istilah seperti itu membuat pengembangan perangkat lunak terdengar jauh lebih terukur dan ilmiah daripada yang sebenarnya. Bahkan jika "optimal" ada untuk kode, kita tidak memiliki cara untuk mengukurnya dan oleh karena itu tidak ada cara untuk mengetahui apakah kita telah mencapainya.
Gerakan gesit benar-benar merupakan reaksi terhadap keyakinan bahwa pengembangan perangkat lunak dapat direncanakan dan diprediksi dengan metode matematika. Baik atau buruk, pengembangan perangkat lunak lebih seperti kerajinan daripada sains.
sumber
fibonacci
, yang saya lihat digunakan sebagai contoh / tutorial TDD, lebih atau kurang bohong. Saya berani bertaruh tidak ada yang pernah "menemukan" fibonacci atau seri serupa dengan TDD'ing itu. Semua orang mulai dari yang sudah tahu fibonacci, yang curang. Jika Anda mencoba menemukan ini dengan menggunakannya, kemungkinan Anda akan menemui jalan buntu yang ditanyakan oleh OP: Anda tidak akan pernah bisa menggeneralisasikan seri dengan hanya menulis lebih banyak tes dan refactoring - Anda harus menerapkan matematika pemikiran!