Saya telah bekerja pada sistem transaksi keuangan besar untuk bank yang menangani Pensiun dan Investasi. Setelah 15 tahun perubahan fitur, biaya uji regresi manual telah naik menjadi $ 200 ribu per rilis. (10 juta LOC, $ 10 juta ditransaksikan per hari). Sistem ini juga berinteraksi dengan 19 sistem lain di sekitar perusahaan yang memindahkan banyak data. Sistem ini diterapkan di Jawa.
Namun yang kami amati, adalah bahwa semakin 'digunakan kembali' kami, semakin banyak biaya uji regresi. (Alasannya adalah bahwa Anda perlu "menguji kode yang Anda sentuh" - dan menggunakan kembali / berbagi kode berdampak pada banyak tempat ketika disentuh. Jadi, meskipun 'KERING - Jangan Ulangi Diri Sendiri' - yaitu jangan salin dan tempel kode - kami mengamati insentif keuangan untuk menyalin dan menempel kode. Ini untuk menurunkan biaya uji regresi, karena kami tidak ingin memodifikasi kode yang dapat dibagikan, karena itu akan menyebabkan dampak uji regresi yang besar.)
Pertanyaan saya, adakah prinsip rekayasa perangkat lunak yang menggambarkan hubungan antara penggunaan kembali dan biaya uji regresi?
Alasan saya mengajukan pertanyaan ini adalah bahwa ada manfaat biaya dalam mendekomposisi sistem menjadi bagian yang lebih kecil untuk diuji.
Asumsi:
'Tes regresi' berarti 'tes penerimaan' - yaitu kelompok lain yang menghabiskan waktu untuk menulis tes baru dan menggunakan kembali sistem terhadap nama bisnis, termasuk pengaturan lingkungan dan data.
Saya tahu reaksi spontan terhadap biaya uji regresi besar adalah 'tes yang lebih otomatis'. Ini adalah prinsip yang baik. Di lingkungan ini ada beberapa tantangan.
(a) Pengujian otomatis kurang bermanfaat melintasi batas sistem, kecuali jika sistem itu juga memiliki cakupan pengujian otomatis yang tinggi. (Lingkungan tantangan pengaruh).
(B) Secara budaya sulit untuk mendapatkan momentum pada waktu programmer atau investasi modal pada cakupan tes otomatis tinggi ketika sistem Anda sudah besar dan kompleks.
(c) Biaya pemeliharaan pengujian otomatis disembunyikan di proyek, dan karenanya mudah dibuang di tingkat proyek.
(D) Ini hanya realitas budaya bekerja di bank.
(e) Saya sedang bekerja untuk menyelesaikan masalah ini dengan cara yang berbeda (dekomposisi).
sumber
Jawaban:
Suara di atas benar bagi saya. Yang lebih penting adalah kode, semakin banyak dibagikan, semakin tinggi persyaratan kualitas, semakin banyak jaminan kualitas harus terlibat ketika itu berubah.
Karena sistem Anda diimplementasikan di Java, Anda dapat melihat contoh di atas di sana, di Java standard libraries (JDK). Rilis utamanya jarang, dan disertai dengan pengujian yang sangat memakan waktu. Dan bahkan rilis kecil dijalankan melalui test suite JCK yang sangat komprehensif untuk memverifikasi tidak adanya regresi.
Anda mungkin berpikir ini entah bagaimana menghambat evolusi kode bersama, dan ... ya ini benar. Semakin banyak dampak dan risiko yang terkait dengan perubahan kode, semakin Anda harus berhati-hati dalam melakukannya, semakin banyak upaya yang harus dilakukan untuk menguji rilisnya.
Idealnya, kualitas rilis kode yang dibagikan secara luas harus sedemikian rupa sehingga tidak memerlukan perubahan besar sama sekali (kecuali untuk peningkatan yang jarang terjadi). Garis pemikiran ini tercermin dalam kutipan terkenal Joshua Bloch :
Dengan kata di atas, sepertinya beberapa masalah yang Anda uraikan disebabkan oleh strategi pengembangan kode bersama yang tidak efisien. Secara khusus, ini terlihat sangat menyusahkan bahwa untuk kode yang digunakan kembali, hanya dua opsi yang dipertimbangkan: duplikat kode ini atau memasukkannya langsung ke pustaka bersama "inti".
Membatasi hanya dua opsi ini tidak perlu dan, sekali lagi, Anda dapat menemukan contoh bagaimana hal itu dapat dilakukan dengan lebih baik di JDK yang Anda gunakan. Lihatlah
java.util.concurrent
paket-paket ( JSR 166 ) - sampai rilis Java 5, ini adalah perpustakaan yang terpisah, bukan bagian dari rilis inti JDK.Pikirkan itu, itu pilihan ketiga yang Anda abaikan, dan yang cukup pragmatis, yang perlu Anda pertimbangkan pada "awal" kode bersama yang baru. Ketika Anda hanya mencari beberapa kode yang dapat dibagi antara 2-3 komponen, tidak ada yang memaksa Anda untuk segera memasukkannya ke dalam API inti dari sistem.
Anda dapat mengemas dan merilis kode bersama "tidak dewasa" ini sebagai pustaka terpisah, seperti yang dilakukan pada utilitas bersamaan Java. Dengan cara ini membebaskan Anda dari kebutuhan pengujian regresi penuh, karena Anda hanya dapat menggunakan sejumlah kecil komponen yang terlibat. Sebagai hasilnya, Anda memiliki lebih banyak kelonggaran untuk memodifikasi dan meningkatkan kode bersama ini dan untuk menguji cara kerjanya dalam produksi.
Setelah pustaka Anda matang dan cukup stabil untuk memberi Anda keyakinan bahwa perubahan lebih lanjut di dalamnya tidak mungkin, Anda dapat mempertimbangkan dimasukkannya ke pustaka inti sistem, sama seperti utilitas bersamaan akhirnya dimasukkan ke dalam JDK.
Contoh konkret tentang berapa banyak upaya (termasuk pengujian) yang mungkin terlibat dalam mengubah kode yang sangat sering digunakan dapat ditemukan, sekali lagi, di JDK. Dalam rilis 7u6 mereka mengubah
String
representasi internal yang melibatkan perubahansubstring
kinerja. Komentar dari pengembang fitur di Reddit menguraikan berapa banyak upaya yang terlibat dalam perubahan ini:sumber
Saya tidak berpikir ada metrik untuk menghitung "biaya untuk tes regresi / LOC dari kode yang digunakan kembali". Dan saya tidak berpikir ada orang yang menginvestasikan begitu banyak waktu dan uang untuk membangun sistem "besar" yang sama dua kali, satu versi dengan banyak komponen yang resuable, dan satu tanpa, untuk melakukan penelitian serius tentang itu.
Tetapi saya telah melihat masalah yang disebabkan oleh penggunaan kembali seperti milik Anda sebelumnya, dan mungkin Anda tertarik pada beberapa pemikiran tentang bagaimana menangani ini dengan lebih baik.
Pertama, ini sebenarnya bukan menggunakan kembali yang merupakan masalah Anda - itu lebih merupakan upaya untuk membangun komponen yang dapat digunakan kembali sendiri dan menggunakannya di seluruh sistem Anda. Saya yakin Anda melakukan banyak penggunaan kembali paket perangkat lunak besar di mana masalah Anda tidak muncul: pikirkan seluruh tumpukan Java yang Anda gunakan, atau mungkin beberapa komponen pihak ketiga (diasumsikan Anda puas dengan komponen itu). Tetapi apa yang berbeda dengan perangkat lunak itu, misalnya, perpustakaan Java, sementara komponen Anda yang dapat digunakan kembali menyebabkan Anda begitu banyak biaya pengujian regresi tambahan? Berikut adalah beberapa hal yang saya rasa bisa berbeda:
komponen-komponen tersebut sangat matang dan stabil
mereka dikembangkan dan diuji sepenuhnya dalam isolasi, oleh organisasi yang sama sekali berbeda
untuk (kembali) menggunakannya, Anda tidak perlu mengubahnya (sebenarnya Anda tidak bisa bahkan jika Anda menginginkannya, karena Anda tidak memelihara kode sumbernya)
Anda tidak mendapatkan versi baru setiap hari, hanya pembaruan kecil (maksimum per bulan), atau pembaruan besar dalam interval per tahun
sebagian besar pembaruan dirancang agar kompatibel 100% ke bawah, terutama pembaruan kecil
Jadi untuk membuat komponen reuseable Anda menjadi lebih sukses, Anda harus menyesuaikan beberapa hal dari atas untuk pengembangan Anda sendiri:
untuk setiap komponen yang dapat digunakan kembali, memiliki tanggung jawab yang jelas siapa yang melakukan pemeliharaan dan memastikan bahwa semua orang yang menggunakan kembali komponen dapat memastikan untuk mendapatkan perbaikan bug segera jika masalah muncul.
menetapkan kebijakan versi dan rilis yang ketat. Ketika mengembangkan komponen yang dapat digunakan kembali, jangan lepaskan "untuk semua orang" setiap hari (setidaknya, tidak jika itu berarti menjalankan uji regresi $ 200K penuh pada sistem). Sebagai gantinya, biarkan versi baru hanya dipublikasikan dari waktu ke waktu, dan menyediakan mekanisme untuk memungkinkan pengguna komponen tersebut menunda perubahan ke versi baru.
semakin sering suatu komponen digunakan kembali, yang lebih penting adalah bahwa ia menyediakan antarmuka yang stabil dan perilaku yang kompatibel ke bawah.
komponen yang dapat digunakan kembali membutuhkan suite uji yang sangat lengkap untuk mengujinya secara terpisah.
Banyak dari hal-hal ini akan berarti bahwa biaya membangun komponen itu sendiri akan meningkat, tetapi juga akan mengurangi biaya perubahan yang disebabkan oleh regresi yang gagal.
sumber
Meskipun mungkin ada kenaikan "yang dapat diamati" dalam biaya karena lebih banyak pengujian yang diperlukan, jenis refactoring biasanya membuat kode lebih dapat dipertahankan di masa depan karena Anda mengurangi hutang teknis dalam sistem.
Mudah-mudahan ini akan mengurangi bug di masa depan, dan membuat fitur baru atau perubahan pada fitur yang ada lebih mudah diimplementasikan.
Lebih mudah, maksud saya mereka harus mengambil lebih sedikit waktu dan karena itu lebih murah.
Mengurangi, lebih mudah dan lebih sedikit adalah istilah yang agak samar-samar di sini dan tabungan di masa depan (atau lebih tepatnya berharap untuk disimpan) tidak mungkin untuk dihitung karena belum terjadi.
Basis kode yang lebih sederhana harus memungkinkan karyawan baru, atau karyawan yang ada pindah ke proyek untuk mempercepat lebih cepat, terutama untuk sistem besar.
Ini juga dapat mengurangi pergantian staf sehingga moral anggota proyek yang ada dapat ditingkatkan.
Tentu saja tidak dijamin bahwa Anda akan mendapatkan manfaat ini, tetapi ini adalah hal-hal yang harus dipertimbangkan bersamaan dengan biaya (seperti peningkatan pengujian) yang dapat diukur.
Bahkan, kode yang lebih baik pada akhirnya harus mengurangi biaya pengujian dari waktu ke waktu, bahkan jika ada peningkatan awal karena apa yang Anda jelaskan.
sumber