Apakah ada prinsip rekayasa perangkat lunak yang menghubungkan penggunaan kembali dan biaya uji regresi pada sistem produksi?

12

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:

  1. '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.

  2. 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).

Hawkeye
sumber
2
Anda membuat pernyataan lambaian tangan bahwa “ kami mengamati [...] bahwa semakin banyak 'digunakan kembali' kami, semakin banyak biaya [penerimaan] uji coba naik ” - dapatkah Anda mengembangkannya? Bukankah seharusnya tes penerimaan menjadi agnostik dari detail implementasi seperti hierarki warisan, dan bukannya bermain melalui skenario penggunaan, misalnya?
amon
2
Pertanyaan Anda menarik, tetapi berisi beberapa asumsi yang sangat bias seperti "penggunaan kembali adalah konsekuensi dari OO" atau bagian yang disebutkan @amon. Saya sarankan Anda menghapus bagian "OO" sepenuhnya dari itu, karena pertanyaan inti Anda independen dari bahasa pemrograman atau pemrograman OO. Dan sangat tidak jelas jenis "penggunaan kembali" apa yang ada dalam pikiran Anda - "penggunaan kembali" adalah istilah yang luas, penggunaan kembali copy-paste berbeda dari penggunaan kembali komponen atau perpustakaan.
Doc Brown
Terima kasih, itu sangat membantu. Saya telah menghapus referensi ke OO - dan memperluas gagasan tentang menyentuh kode bersama, (atau kode yang akan menjadi kode bersama).
hawkeye
1
Dalam bentuk saat ini, saya kira saya akan menjawab hanya "tidak, saya tidak berpikir begitu" untuk pertanyaan Anda - yang saya kira tidak akan terlalu memuaskan untuk pertanyaan Anda. Atau apakah Anda tertarik pada prinsip dan praktik untuk benar-benar mengurangi biaya pengujian ketika membangun sistem besar seperti milik Anda dengan beberapa komponen yang dapat digunakan sendiri?
Doc Brown

Jawaban:

11

kami tidak ingin mengubah kode yang dapat dibagikan, karena itu akan menyebabkan dampak uji regresi yang besar

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 :

API publik, seperti berlian, selamanya. Anda memiliki satu kesempatan untuk melakukannya dengan benar, jadi berikan yang terbaik.


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.concurrentpaket-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 Stringrepresentasi internal yang melibatkan perubahan substringkinerja. Komentar dari pengembang fitur di Reddit menguraikan berapa banyak upaya yang terlibat dalam perubahan ini:

Analisis awal keluar dari kelompok GC pada tahun 2007 ...

Secara internal tim kinerja Oracle mengelola serangkaian aplikasi dan tolok ukur yang representatif dan penting yang mereka gunakan untuk mengevaluasi perubahan kinerja. Rangkaian aplikasi ini sangat penting dalam mengevaluasi perubahan ke substring. Kami mengamati baik-baik perubahan kinerja dan perubahan jejak kaki. Tidak dapat dihindari, seperti halnya dengan perubahan signifikan, ada regresi di beberapa aplikasi serta keuntungan di yang lain. Kami menyelidiki regresi untuk melihat apakah kinerja masih dapat diterima dan kebenaran dipertahankan ...

Jawaban saya tidak dimaksudkan untuk menjadi lengkap tetapi merupakan ringkasan yang sangat singkat tentang apa yang hampir enam bulan kerja khusus ...

agas
sumber
Sepertinya kami berdua mengerjakan jawaban secara paralel, dengan banyak pemikiran serupa ...
Doc Brown
@DocBrown ya, sangat menarik bahwa kami juga menjawab hampir bersamaan, sekitar satu jam setelah pertanyaan diedit ke dalam bentuk
nyamuk
9

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.

Doc Brown
sumber
0

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.

ozz
sumber