Bagaimana Anda tahu jika perangkat lunak baik atau buruk berdasarkan pada metrik empiris?


18

Saya saat ini diminta untuk melihat proyek yang telah menyelesaikan pengembangan inti lima bulan lalu, tetapi masih memiliki tingkat cacat yang tinggi. Apa yang terjadi untuk sekitar setiap 10 cacat tetap, kami menaikkan setidaknya 4 dan dalam beberapa kasus 8 cacat.

Saya percaya praktik pengkodean di vendor buruk dan ada kesepakatan umum tentang ini. Namun, saya bertanya-tanya apakah ada masalah struktural dengan perangkat lunak? Kepadatan cacat adalah ukuran yang berguna, tetapi lebih jika perangkat lunak inti ditulis dengan buruk, maka yang dilakukan semua vendor adalah menggeser masalah.

Dalam infrastruktur lebih ditentukan jika sesuatu dibangun dengan buruk, pengukuran apa yang dapat Anda gunakan untuk perangkat lunak selain cacat per LOC?

Produk telah dalam tahap memperbaiki cacat selama 4 bulan dan masih belum cukup menyelesaikan cacat kritis. Kami tidak menyuntikkan fungsionalitas baru, hanya memperbaiki masalah regresi.

Ini menunjukkan masalah kualitas pengembangan, yang tidak puas. Namun, jika produk itu sendiri pada dasarnya cacat, itu adalah masalah yang berbeda. Masalahnya adalah basis kode inti telah ditulis dengan buruk dan memiliki dokumentasi terbatas, semua pengembang eksternal lakukan adalah mengalihkan masalah dari A ke B. Setelah tim pengembangan internal mengambil alih, saya khawatir mereka harus secara mendasar menulis ulang kode untuk Dapatkan fungsional.

Jadi, ketika Anda menerima produk dari pihak ketiga dan diminta untuk mendukungnya, kriteria penerimaan apa yang akan Anda gunakan untuk menentukan standar?

Selain meminta pengembang utama kami melakukan peer review kode per rilis, tidak yakin apa lagi yang bisa dilakukan?


8
Jika ada metrik empiris (yang dapat dihitung secara otomatis) yang berguna untuk perangkat lunak yang baik, maka orang akan menggunakannya dalam dokumen persyaratan. Penulis kompiler hanya akan mengoptimalkan untuk itu. Tidak akan pernah ada perbedaan pendapat tentang seberapa bagus perangkat lunak itu. Jelas, dunia tidak seperti itu. Itu adalah petunjuk kuat bahwa tindakan semacam itu tidak ada, atau setidaknya tidak ada yang diketahui.
Kilian Foth


Kerusakan terjadi karena berbagai alasan - kesalahan dengan spesifikasi, kesalahan dengan pengujian, persyaratan tidak jelas / berubah. Tidak semua dari mereka dapat dikaitkan dengan kesalahan pengembang.
Robbie Dee

debat metafisika, pertimbangkan untuk membaca di Diskusi dan mengapa mereka tidak mengajukan pertanyaan yang bagus
Agak

1
Pertanyaannya mungkin diutarakan suboptimal dengan terlalu banyak fokus pada cacat. Saya pikir pertanyaan dalam judul itu valid dan bukan duplikat (menilai kualitas sw di sini vs produktivitas dev dalam pertanyaan terkait)
Frank

Jawaban:


23

Kamu tidak.

Kualitas perangkat lunak sangat sulit diukur secara objektif. Cukup sulit sehingga tidak ada solusi. Saya menahan diri dalam jawaban ini untuk mencoba-coba tentang pertanyaan apakah ada solusi sama sekali, tetapi cukup tunjukkan mengapa mendefinisikan seseorang akan sangat sulit.

Penalaran berdasarkan status quo

Seperti yang ditunjukkan Kilian Foth, jika ada ukuran sederhana untuk perangkat lunak "baik", kita semua akan menggunakannya dan semua orang akan menuntutnya.

Ada proyek di mana manajer memutuskan untuk menegakkan metrik tertentu. Terkadang berhasil, terkadang tidak. Saya tidak mengetahui adanya korelasi yang signifikan. Terutama perangkat lunak sistem kritis (pikirkan pesawat terbang, mobil, dll.) Memiliki banyak persyaratan metrik untuk "memastikan" kualitas SW - Saya tidak mengetahui adanya penelitian yang menunjukkan bahwa persyaratan ini benar-benar menghasilkan kualitas yang lebih tinggi, dan saya memiliki pengalaman pribadi dengan kebalikan.

Penalaran dengan kontra-intelijen

Juga diisyaratkan oleh Kilian, dan lebih umum diucapkan sebagai "setiap metrik dapat dan akan dimainkan".

Apa artinya memainkan metrik? Ini adalah permainan yang menyenangkan bagi pengembang: Anda memastikan nilai metrik terlihat sangat baik, sambil melakukan hal-hal yang sangat menyebalkan.

Katakanlah Anda mengukur cacat per LOC. Bagaimana saya memainkannya? Mudah - tambahkan saja kode! Buat kode bodoh yang menghasilkan no-operasi lebih dari 100 baris dan tiba-tiba Anda memiliki lebih sedikit cacat per LOC. Terbaik dari semua: Anda benar-benar menurunkan kualitas perangkat lunak seperti itu.

Kekurangan alat disalahgunakan, definisi ditingkatkan semaksimal mungkin, cara-cara yang benar-benar baru ditemukan .. pada dasarnya, pengembang adalah orang-orang yang sangat pintar dan seandainya Anda hanya memiliki satu pengembang di tim Anda yang bersenang-senang memainkan metrik, maka metrik Anda akan dipertanyakan.

Ini bukan untuk mengatakan bahwa metrik selalu buruk - tetapi sikap tim terhadap metrik ini sangat penting. Secara khusus, ini menyiratkan itu tidak akan berfungsi dengan baik untuk setiap hubungan subkontraktor / vendor pihak ke-3.

Penalaran dengan penargetan yang salah

Yang ingin Anda ukur adalah kualitas perangkat lunak. Apa yang Anda ukur adalah satu atau beberapa metrik.

Ada celah antara apa yang Anda ukur dan apa yang Anda yakini akan memberi tahu Anda. Kesenjangan ini agak besar bahkan.

Itu terjadi setiap saat di semua jenis bisnis di sekitar kita. Pernah melihat keputusan berdasarkan KPI (indikator kinerja utama)? Ini masalah yang sama - Anda ingin perusahaan bekerja dengan baik, tetapi Anda mengukur sesuatu yang lain.

Penalaran dengan kuantifikasi

Metrik dapat diukur. Yang merupakan satu-satunya alasan kami berurusan dengan mereka sama sekali. Kualitas perangkat lunak, bagaimanapun, jauh melampaui entitas terukur ini dan memiliki banyak hal yang sangat sulit untuk diukur: Seberapa mudah dibaca kode sumbernya? Seberapa diperluas desain Anda? Seberapa sulit bagi anggota tim baru untuk bergabung? dll. dll

Menilai kualitas perangkat lunak hanya dengan metrik dan menutup mata terhadap bagian kualitas yang tidak dapat Anda ukur tentu tidak akan berhasil dengan baik.

edit:

Ringkasan

Biarkan saya menunjukkan bahwa di atas adalah semua tentang menilai secara objektif apakah perangkat lunak baik atau buruk berdasarkan metrik. Ini berarti, ia tidak mengatakan apa pun tentang apakah dan kapan Anda harus menerapkan metrik.

Sebenarnya, ini adalah implikasi searah: metrik buruk menyiratkan kode buruk. Searah berarti bahwa kode yang buruk tidak menjamin metrik yang buruk, juga metrik yang baik tidak menjamin kode yang baik. Di sisi lain, ini dengan sendirinya berarti Anda dapat menerapkan metrik untuk menilai perangkat lunak - ketika Anda mengingat implikasi ini.

Anda mengukur perangkat lunak A, dan metriknya menjadi sangat buruk. Maka Anda dapat yakin bahwa kualitas kodenya buruk. Anda mengukur perangkat lunak B dan metriknya ok, maka Anda tidak memiliki petunjuk apa pun tentang kualitas kode. Jangan tertipu dengan berpikir "metrik baik = kode baik" ketika itu benar-benar hanya "kode baik => metrik baik".

Intinya, Anda dapat menggunakan metrik untuk menemukan masalah kualitas, tetapi bukan kualitas itu sendiri.


Tahan. Secara efektif Anda mengatakan bahwa perangkat lunak mirip dengan sepotong teks, yaitu bentuk literatur. Memahami perbandingan antara produk fisik dan kode agar berbeda. Namun, humaniora telah menandai PHD sejak lama dan harus mengukur kualitas. Saya pikir masalah di sini secara teknis menandai kode sulit. Tetapi terapkan metrik lain seperti dua aplikasi dengan harga yang sama di toko aplikasi, tetapi satu memiliki lebih banyak fungsi dan peringkat yang lebih baik, yaitu yang Anda beli.
Teknologi

Untuk poin Anda yang lain di sekitar pengukuran, itu adalah perbandingan. Jika Anda mendukung tiga produk yang berbeda, Anda akan berpendapat bahwa fungsi dukungan Anda secara alami akan seperti yang mereka dapat membaca kode sumber dengan mudah dan anggota baru untuk mengadopsi. Ini akan menjadi produk yang paling sedikit Anda dapatkan tiketnya / ubah permintaannya. Jadi mungkin singkatnya jawabannya adalah Anda tidak dapat menilai kode perangkat lunak berdasarkan garisnya. Tetapi oleh pengguna akhir dan mereka yang mendukungnya dan apakah itu dapat dipertahankan maju dengan gangguan minimal pada sistem produksi.
Teknologi

1
Saya setuju bahwa kualitas perangkat lunak secara keseluruhan sulit diukur dengan metrik, tetapi ada beberapa metrik yang dapat menunjukkan atau cenderung kurang berkualitas.
Jon Raynor

Oke, bermain metrik bisa menjadi masalah. Tetapi saya pikir yang lebih buruk adalah jika saya dihukum karena melakukan hal yang benar. Saya baru saja memperbaiki kerusakan dengan mengganti 100 baris kode buruk dengan satu panggilan pustaka satu baris dan Anda memberi tahu saya memperburuk kode menurut metrik Anda? Itu tidak akan memotivasi saya untuk melakukan pekerjaan dengan baik.
svick

Jika Anda "dihukum", Anda tidak menggunakan metrik dengan benar. Mengaitkan metrik ke produktivitas programmer adalah cara tertentu, meskipun tipikal, untuk gagal.
Frank

13

Ya, Anda dapat memberi tahu kode bahwa ada masalah kualitas dengan melihat metrik pada tingkat tertentu.

Lebih khusus lagi, jalankan alat analisis kompleksitas pada basis kode dan Anda akan mendapatkan gagasan apakah kode itu baik atau buruk.

Misalnya, Anda dapat menjalankan monitor sumber .

Apa yang akan Anda katakan adalah betapa rumit kode ini. Saya dapat memberi tahu Anda setiap sistem bermasalah yang saya alami memiliki angka buruk. Kompleksitas pada 10 hingga 100 metode jauh di atas batas yang dapat diterima. Angka yang mengerikan. Kompleksitas yang mengerikan, bersarang, mendalam, dll. Ini akan menyebabkan banyak masalah, tingkat cacat tinggi yang konstan, sulit untuk membuat perubahan, tanpa merusak sesuatu yang lain, dll.

Hal lain adalah cacat. Seiring waktu sistem akan stabil. Idealnya, cacat baru harus cenderung nol atau merata ke angka rendah, yang berarti cacat baru dan saat ini akan berkurang seiring waktu.

Plotnya akan terlihat seperti ini:

Cacat Seiring Waktu Kerusakan Seiring Waktu

Jika mereka tetap konstan atau meningkat, maka perangkat lunaknya tidak bagus. Hanya 4 bulan Anda masuk, jadi saya akan memberikannya beberapa bulan lagi hingga satu tahun. Setelah 6 bulan hingga satu tahun, jika Anda mengalami cacat yang terus-menerus, kualitasnya buruk. Tim Anda mengembangkan bola lumpur lainnya .

Tes selanjutnya. Apakah kamu memilikinya? Jika tidak ada kualitas maka kurang, lebih banyak bug, lebih banyak churn. Jika Anda memilikinya, metrik seperti cakupan kode baik untuk mengetahui berapa banyak kode yang dicakup, tetapi tidak akan mengukur kualitas . Saya telah melihat angka cakupan kode yang luar biasa tetapi tes sebenarnya adalah omong kosong. Mereka tidak menguji perilaku atau fungsi apa pun dari sistem. Pengembang hanya menulis mereka untuk meningkatkan angka metrik untuk manajemen. Jadi, Anda harus menjalani tes dan harus bagus. Metrik cakupan kode sendiri bukan merupakan indikator kualitas.

Ulasan kode, apakah Anda melakukannya? Jika tidak, kualitasnya kurang. Ini sangat penting dengan pengembang junior. Jika Anda lincah, cukup tambahkan tugas tinjauan kode ke cerita Anda yang disebut "tinjauan kode". Jika manajemen ingin melacak angka, Anda akan memerlukan alat yang melacak ulasan seperti Crucible . Saya pikir angka atau metrik ulasan kode tidak begitu penting di sini selain fakta bahwa mereka harus menjadi bagian dari proses Anda. Tidak setiap check-in membutuhkan ulasan. Tetapi, ulasan dapat membantu memastikan orang tidak menciptakan kembali roda atau menulis kode yang tidak dapat dipahami dan / atau dipelihara orang lain.

Akhirnya, Anda hanya perlu menilai kode, tidak ada metrik yang akan membantu di luar sana. Setiap proyek kode yang bermasalah memiliki kualitas ini:

  • Struktur data buruk. Semuanya adalah string, atau XML dilewatkan di mana-mana dan diuraikan di mana-mana, objek dewa, atau struktur data generik yang tidak perlu atau rumit, tanpa model domain.
  • Kurangnya organisasi atau struktur, proyek non-sepele harus memiliki beberapa divisi atau layering yang memisahkan logika. Lihat di sini ... Jika Anda tidak melihat jenis organisasi atau pemisahan ini (pencampuran logika di mana-mana) maka sistem akan lebih sulit untuk dipelihara dan dipahami.
  • Lebih dari abstraksi. Terkadang kebalikannya benar, sistemnya terlalu abstrak. Jika semuanya adalah antarmuka dan kelas abstrak, atau Anda harus menavigasi melalui satu ton kelas tipe "wrapper", kualitasnya akan buruk karena pengembang baru tidak akan dapat menavigasi melalui objek mengasapi.
  • Kode sulit dipahami. Jika pengembang berpengalaman Anda dan jika Anda melihat kode yang sulit dipahami, itu akan memiliki masalah kualitas. Metrik pribadi saya adalah bahwa jika saya melihat kode dan sulit mengikuti atau membuat saya merasa bodoh, atau saya merasa seperti saya membuang banyak siklus otak untuk mencari tahu logika, maka itu kode yang buruk. Jika pengembang berpengalaman mengalami kesulitan mengikuti, maka bayangkan bagaimana rasanya bagi pengembang yang lebih baru. Mereka akan menimbulkan masalah.

Saran saya akan menjalankan analisis kompleksitas pada kode. Jangan membagikan hasil, sebaliknya tindak lanjuti hasil, lakukan investigasi independen (lihat kode) dan tentukan kesehatan keseluruhan basis kode. Dari sini, bentuk rencana aksi dan coba remediasi beberapa area kompleks kode.


3
Anda menulis: "Metrik pribadi saya adalah jika saya melihat kode dan sulit mengikuti atau membuat saya merasa bodoh, atau saya merasa seperti saya membuang banyak siklus otak untuk mencari tahu logika, maka itu kode yang buruk". Semakin tua saya semakin saya sangat setuju dengan ini. Sebelumnya saya pikir ini adalah sudut pandang yang sombong. Namun, sekarang saya telah melihat banyak proses yang tampaknya rumit di refactored menjadi kode yang elegan. Saya menyadari bahwa kode yang sulit hampir selalu bisa ditulis lebih jelas.
Ivan

Terima kasih, Jon. Referensi yang Anda berikan bermanfaat. Untuk lebih jelasnya, perangkat lunak sudah berumur lebih dari satu tahun dan cacat belum hilang. Saya pribadi belum mengkodekan bertahun-tahun, saya sudah menjadi tipe manajer terlalu lama dan bukan yang teknis. Membaca, Bangun, dan buku itu menggemakan pikiran saya. IE, perangkat lunak yang berjalan pada akan menjadi tanda-kirim seberapa baik telah ditulis. Terima kasih banyak lagi.
Teknologi

Sementara firasat tentang apakah kode itu baik atau buruk dapat membantu menemukan kode yang buruk, mereka hampir tidak metrik. Dan proses otomatis untuk mendeteksi "kode buruk" berdasarkan pemformatan dan penamaan metode / variabel tidak benar-benar melakukan apa pun kecuali menegakkan konvensi penamaan yang konsisten dalam tim (yang sementara baik tidak menjamin atau mengukur kualitas kode aktual).
jwenting

2
Selain kompleksitas siklomatik, kedalaman warisan, tingkat penggabungan kelas, dan saya yakin beberapa lainnya, dapat menjadi indikator hebat kode sub-par. Mereka tidak dapat digunakan hanya sebagai indikator kualitas, tetapi mereka dapat memberikan titik awal yang cukup bagus.
RubberDuck

3

Yang menyedihkan dengan metrik adalah Anda akhirnya dapat meningkatkan nilai yang dihasilkan dari metrik Anda, tetapi bukan kualitas yang ingin diukur oleh mereka ...

Di Visual Studio, ada pengaturan untuk memperlakukan peringatan kompiler sebagai kesalahan. Sekarang beberapa orang tidak memahami peringatan, dan untuk mendapatkan kode yang dikompilasi, akan menggunakan trik sederhana (seperti ´pragma nonaktifkan peringatan´ atau menambahkan kata kunci nnew´ ke fungsi / properti yang menyembunyikan anggota non-virtual dari suatu basis kelas).

Jika Anda memiliki akses ke kode sumber, Anda dapat menjalankan analisis kode statis. Untuk proyek .Net, Anda dapat menggunakan misalnya FxCop atau ReSharper InspectCode. Ketika digunakan oleh tim pengembang dengan benar, alat akan membantu meningkatkan kualitas. Tapi tentu saja, beberapa "perbaikan" untuk menghapus peringatan tanpa memahaminya adalah mungkin.

Anda dapat melihat tes otomatis / UnitTests: seberapa bagus cakupan kode? Tetapi cakupan saja tidak akan memberi tahu Anda jika tes benar-benar memeriksa kode, atau hanya menjalankannya sekali.

Berjuang untuk kualitas tinggi adalah sikap, yang dapat didukung oleh banyak alat dan metrik mereka, tetapi metrik tanpa sikap pengembang tidak membantu.


3

Satu hal yang harus Anda perhatikan selain mengumpulkan metrik seperti injeksi cacat adalah mencari tahu sumber cacat. Seringkali berkaitan dengan spesifikasi.

Pada dasarnya, ini adalah kesalahan dalam spesifikasi, sebuah ambiguitas dalam spesifikasi, meninggalkan implan untuk memutuskan atau itu bug dalam implementasi.

Pendekatan yang lebih kualitatif adalah dengan bertanya apakah perangkat lunak itu berguna? Jika Anda terlihat cukup keras, Anda dapat menemukan cacat pada perangkat lunak apa pun. Namun, jika itu bekerja dengan cukup baik untuk menghasilkan uang, maka itu mungkin tidak terlalu buruk.


1
+1 Jawaban luar biasa - gagal mengatasi sumber bug membuat pintu tetap terbuka untuk bug lebih lanjut dari sumber yang sama
Robbie Dee

3

Bawah, tidak ada cara untuk mengetahuinya.

Untuk pertanyaan awal (sebelum jawaban filosofis): Apa yang harus dilakukan dan dilakukan oleh produk? Mengukur dengan jumlah cacat / kepadatan tidak cukup. Saya tidak tahu apakah ini adalah perpustakaan, atau aplikasi, seberapa besar basis kode, seberapa besar domain masalahnya, atau seberapa parah tingkat cacatnya. Misalnya, tidak menangani salah satu dari 123 format input bisa menjadi cacat sepele atau penghenti acara, tergantung pada pentingnya format yang tidak ditangani dengan benar. Dan lebih baik daripada tidak ada standar tinggi.

Asumsi yang saya buat untuk pertanyaan ini: Ada perbedaan antara Kode dan Perangkat Lunak. Saya mendefinisikan perangkat lunak sebagai apa yang digunakan klien / pengguna untuk memecahkan masalah, sedangkan kode adalah bahan pembangun perangkat lunak.

Perangkat lunak hanya dapat diukur secara subyektif. Artinya, metrik yang penting untuk perangkat lunak adalah apakah orang menggunakannya untuk memecahkan masalah. Metrik ini tergantung pada perilaku orang lain, karenanya secara subjektif. Catatan: Untuk beberapa masalah, sepotong perangkat lunak mungkin cukup berguna, dan karenanya dianggap berkualitas tinggi (Excel untuk perhitungan), tetapi bukan perangkat lunak berkualitas untuk masalah yang berbeda (Excel untuk memutar file MP3).

Kode dapat (biasanya) diukur dengan metrik empiris . Tetapi interpretasi itu bukan 'ya / tidak' untuk kualitas, atau bahkan benar-benar pada skala '0 ke N'. Metrik mengukur terhadap standar. Jadi, metrik dapat menemukan bidang perhatian yang ditentukan oleh standar, tetapi tidak adanya bidang yang menjadi perhatian bukan bukti bahwa ini adalah kode kualitas. Misalnya, metrik yang berguna: Apakah Mengkompilasi? Tidak -> Tidak berkualitas. Ya -> ???. Apakah ini lulus Tes Unit? Tidak? Mungkin? (karena, Apakah Kode Kualitas Uji Unit?), Ya -> ???.

Jadi, seperti Godel's Incompleteness Proof menunjukkan untuk aksioma matematika (yaitu, ada pernyataan matematika yang tidak dapat dibuktikan benar atau salah untuk setiap aksioma yang terbatas), saya tidak berpikir kita bisa benar-benar menjawab 'apakah kualitas ini kode?' untuk setiap bagian kode. Secara intuitif, mungkin ada pemetaan di sana antara metrik perangkat lunak untuk menjawab kualitas dan aksioma matematis untuk menjawab yang terbukti benar atau salah.

Cara lain untuk membuat argumen ini, adalah melangkah ke bahasa alami. William Shakespeare, Lewis Carroll dan Mark Twain semuanya adalah penulis sukses, dan disukai banyak orang karena kualitas tulisan mereka. Namun standar tata bahasa, kosa kata, gaya atau suara apa yang dapat kita terapkan yang akan secara konsisten menilai mereka lebih tinggi daripada siswa kelas 12 acak? Dan, sementara dimungkinkan untuk membuat beberapa ukuran sintetis untuk ketiganya, bagaimana itu akan menilai Buku Yohanes (KJV), JRR Tolkien, Homer, Cervantes, dll? Lalu lempar ke Burroughs, Faulkner, Hemingway, Sylvia Plath, dan sebagainya. Metrik tidak akan berfungsi.


2

Saya akan mengukur ini dengan mengaudit (dan mencari penyimpangan dalam) proses mereka.

Saya akan mencari bukti proses untuk mengirimkan yang melibatkan kontrol sumber pusat, sistem pembangunan pusat dan proses yang memastikan kode diuji sebelum integrasi ke dalam cabang yang dirilis.

Saya juga akan mencari bukti bagaimana mereka telah memodifikasi proses mereka dalam menanggapi situasi di mana cacat telah melewati proses pembebasan mereka.

Jika mereka tidak dapat melewati tingkat audit ini, maka Anda tidak dapat mengharapkan mereka untuk memberikan rilis yang andal dan konsisten.

Jika mereka lulus audit ini, dan terus meningkatkan proses mereka maka konsistensi output mereka cenderung meningkat dari waktu ke waktu.

Jika ini tidak memperbaikinya, maka kemungkinan mereka memiliki masalah arsitektur kode yang membuat memperluas dan menguji basis kode mereka saat ini bermasalah, dalam hal ini tidak ada pilihan yang baik.


Ini adalah jenis jawaban yang saya cari.
Teknologi

0

Jika Anda mencari pengukuran yang sepenuhnya otomatis, maka saya sarankan orang-orang ini: Grup Peningkatan Perangkat Lunak

Ini pada dasarnya merupakan agregat dari berbagai metrik yang dapat secara otomatis diekstraksi dari kode sumber (seperti, cakupan tes unit, ukuran fungsi, keterikatan kelas, duplikasi, LOC, dll.). Nilai-nilai tersebut kemudian dikonversi menjadi peringkat bintang 1-5.

masukkan deskripsi gambar di sini

Mereka juga memiliki buku yang layak menggambarkan semua metrik mereka dalam praktik yang layak dibaca: 'Membangun perangkat lunak yang dapat dipertahankan' .

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.