Gaya kode yang bagus untuk memperkenalkan pemeriksaan data di mana-mana?


10

Saya memiliki proyek yang cukup besar ukurannya sehingga saya tidak dapat menyimpan setiap aspek lagi di kepala saya. Saya berurusan dengan sejumlah kelas dan fungsi di dalamnya, dan saya menyampaikan data.

Seiring waktu saya perhatikan bahwa saya terus mendapatkan kesalahan, karena saya lupa bentuk persis apa yang harus dimiliki data ketika saya meneruskannya ke fungsi yang berbeda ( misalnya, satu fungsi menerima dan menghasilkan array string, fungsi lain, yang saya tulis kemudian, menerima string yang disimpan dalam kamus dll., jadi saya harus mengubah string yang sedang saya kerjakan dari memiliki mereka dalam array menjadi memiliki mereka dalam kamus ).

Untuk menghindari selalu harus mencari tahu apa yang pecah di mana, saya mulai memperlakukan setiap fungsi dan kelas sebagai "entitas yang terisolasi" dalam arti bahwa ia tidak dapat mengandalkan kode luar yang memberikan input yang benar dan harus melakukan pemeriksaan input itu sendiri (atau, dalam beberapa kasus, menyusun kembali data, jika data diberikan dalam bentuk yang salah).

Ini sangat mengurangi waktu yang saya habiskan untuk memastikan bahwa data yang saya berikan "cocok" ke setiap fungsi, karena kelas dan fungsi itu sendiri sekarang memperingatkan saya ketika beberapa input buruk (dan kadang-kadang bahkan memperbaiki itu) dan saya tidak harus pergi dengan debugger melalui seluruh kode lagi untuk mencari tahu di mana sesuatu menjadi kacau.

Di sisi lain, ini juga meningkatkan kode keseluruhan.
Pertanyaan saya adalah, apakah gaya kode ini sesuai untuk menyelesaikan masalah ini?
Tentu saja, solusi terbaik adalah dengan sepenuhnya memperbaiki proyek dan memastikan data memiliki struktur yang seragam untuk semua fungsi - tetapi karena proyek ini terus berkembang, saya akan menghabiskan lebih banyak dan mengkhawatirkan kode bersih daripada benar-benar menambahkan barang baru .

(FYI: Saya masih pemula, jadi tolong permisi jika pertanyaan ini naif; proyek saya menggunakan Python.)


1
Kemungkinan duplikat dari Seberapa defensif seharusnya kita?
nyamuk

3
@gnat Ini mirip, tetapi alih-alih menjawab pertanyaan saya, ada memberikan saran ("menjadi defensif seperti yang Anda bisa") untuk contoh khusus yang disebutkan OP, yang berbeda dari permintaan saya yang lebih umum.
user7088941

2
"tetapi karena proyek ini terus berkembang, saya akhirnya akan menghabiskan lebih banyak dan khawatir tentang kode bersih daripada benar-benar menambahkan hal-hal baru" - ini terdengar seperti Anda harus mulai khawatir tentang kode bersih. Kalau tidak, Anda akan menemukan produktivitas Anda melambat dan melambat karena setiap fungsionalitas baru semakin sulit untuk ditambahkan karena kode yang ada. Tidak semua refactoring perlu "lengkap", jika menambahkan sesuatu yang baru itu sulit karena kode yang disentuhnya, refactor hanya dengan kode yang menyentuh itu dan catat apa yang ingin Anda tinjau kembali nanti
matt freake

3
Ini adalah masalah yang sering dihadapi orang yang menggunakan bahasa yang diketik dengan lemah. Jika Anda tidak ingin atau dapat beralih ke bahasa yang diketik dengan lebih ketat, jawabannya hanya "ya, gaya kode ini sesuai untuk menyelesaikan masalah ini" . Pertanyaan selanjutnya?
Doc Brown

1
Dalam bahasa yang diketik ketat, dengan tipe data yang tepat ditentukan, kompiler akan melakukan ini untuk Anda.
SD

Jawaban:


4

Solusi yang lebih baik adalah memanfaatkan fitur dan tooling bahasa Python.

Misalnya, dalam fungsi 1, input yang diharapkan adalah array string, di mana string pertama menunjukkan judul sesuatu dan yang kedua adalah referensi bibliografi. Dalam fungsi 2 input yang diharapkan masih berupa array string, tetapi sekarang peran string tersebut terbalik.

Masalah ini dikurangi dengan a namedtuple. Ini ringan dan memberikan makna semantik yang mudah bagi anggota array Anda.

Untuk mengambil manfaat dari beberapa pemeriksaan jenis otomatis tanpa beralih bahasa, Anda dapat memanfaatkan petunjuk jenis . IDE yang baik dapat menggunakan ini untuk memberi tahu Anda ketika Anda melakukan sesuatu yang bodoh.

Anda juga tampaknya khawatir tentang fungsi yang basi ketika persyaratan berubah. Ini dapat ditangkap dengan pengujian otomatis .

Meskipun saya tidak mengatakan bahwa pengecekan secara manual tidak pernah tepat, penggunaan fitur bahasa yang tersedia yang lebih baik dapat membantu Anda memecahkan masalah ini dengan cara yang lebih dapat dipertahankan.


+1 untuk mengarahkan saya ke namedtupledan semua hal baik lainnya. Saya tidak memahaminya namedtuple- dan sementara saya tahu tentang pengujian otomatis, saya tidak pernah benar-benar menggunakannya dan tidak menyadari betapa hal itu akan membantu saya dalam kasus ini. Semua ini tampaknya sama baiknya dengan analisis statis. (Pengujian otomatis bahkan mungkin lebih baik, karena saya dapat menangkap semua hal halus yang tidak akan terperangkap dalam analisis statis!) Jika Anda tahu yang lain, tolong beri tahu saya. Saya akan membiarkan pertanyaan terbuka beberapa saat lagi, tetapi jika tidak ada jawaban lain datang, saya akan menerima pertanyaan Anda.
user7088941

9

OK, masalah sebenarnya dijelaskan dalam komentar di bawah ini:

Misalnya, dalam fungsi 1, input yang diharapkan adalah array string, di mana string pertama menunjukkan judul sesuatu dan yang kedua adalah referensi bibliografi. Dalam fungsi 2 input yang diharapkan masih berupa array string, tetapi sekarang peran string tersebut terbalik

Masalahnya di sini adalah penggunaan daftar string di mana urutannya menandakan semantik. Ini adalah pendekatan yang sangat rawan kesalahan. Alih-alih, Anda harus membuat kelas khusus dengan dua bidang bernama titledan bibliographical_reference. Dengan begitu Anda tidak akan mencampuradukkannya, dan Anda menghindari masalah ini di masa depan. Tentu saja ini memerlukan beberapa refactoring jika Anda sudah menggunakan daftar string di banyak tempat, tapi percayalah, itu akan lebih murah dalam jangka panjang.

Pendekatan umum dalam bahasa jenis dinamis adalah "mengetik bebek", yang berarti Anda tidak benar-benar peduli tentang "jenis" objek yang diteruskan, Anda hanya peduli jika itu mendukung metode yang Anda panggil. Dalam kasus Anda, Anda hanya akan membaca bidang yang dipanggil bibliographical_referencesaat Anda membutuhkannya. Jika bidang ini tidak ada pada objek yang diteruskan, Anda akan mendapatkan kesalahan, dan ini menunjukkan jenis yang salah diteruskan ke fungsi. Ini sama baiknya dengan cek tipe apa pun.


Kadang-kadang masalah th bahkan lebih halus: Saya melewati tipe yang benar, tetapi "struktur internal" dari input saya mengacaukan fungsi: Misalnya, dalam fungsi 1, input yang diharapkan adalah array dari string, di mana string pertama menunjukkan judul sesuatu dan yang kedua referensi bibliografi. Dalam fungsi 2 input yang diharapkan masih berupa serangkaian string, tetapi sekarang peran string tersebut terbalik: String pertama harus menjadi referensi bibliografi dan yang kedua harus menjadi referensi bibliografi. Saya kira cek ini pantas?
user7088941

1
@ user7088941: Masalah yang Anda gambarkan dapat dengan mudah diselesaikan dengan memiliki kelas dengan dua bidang: "title" dan "bibliographical_reference". Anda tidak akan mencampuradukkannya. Mengandalkan urutan dalam daftar string tampaknya sangat rawan kesalahan. Mungkin ini masalah yang mendasarinya?
JacquesB

3
Ini jawabannya. Python adalah bahasa berorientasi objek, bukan daftar-kamus-of-string-to-integers-oriented (atau apa pun) bahasa. Jadi, gunakan benda. Objek bertanggung jawab untuk mengelola negara mereka sendiri dan menegakkan invarian mereka sendiri, objek lain tidak dapat merusaknya, pernah (jika dirancang dengan benar). Jika data tidak terstruktur atau semi-terstruktur memasuki sistem Anda dari luar, Anda memvalidasi dan mengurai sekali pada batas sistem dan mengonversi ke objek kaya sesegera mungkin.
Jörg W Mittag

3
"Aku benar-benar akan menghindari refactoring terus-menerus" - blok mental ini adalah masalahmu. Kode yang baik hanya muncul dari refactoring. Banyak refactoring. Didukung oleh unit test. Terutama ketika komponen perlu diperluas atau dikembangkan.
Doc Brown

2
Aku mengerti sekarang. +1 untuk semua wawasan dan komentar yang bagus. Dan terima kasih kepada semua untuk komentar mereka yang sangat membantu! (Ketika saya menggunakan beberapa kelas / objek, saya menyelingi mereka dengan daftar yang disebutkan, yang, seperti yang saya lihat sekarang, bukan ide yang baik. Pertanyaannya tetap bagaimana cara terbaik untuk mengimplementasikan ini, di mana saya menggunakan saran konkret dari jawaban JETMs. , yang benar-benar membuat perbedaan radikal dalam hal kecepatan untuk mencapai kondisi bebas bug.)
user7088941

3

Pertama-tama, apa yang Anda alami saat ini adalah bau kode - cobalah untuk mengingat apa yang menyebabkan Anda menjadi sadar akan bau dan mencoba mengasah hidung "mental" Anda, semakin cepat Anda melihat kode mencium bau semakin cepat - dan lebih mudah - Anda dapat memperbaiki masalah yang mendasarinya.

Untuk menghindari selalu harus mencari tahu apa yang pecah di mana, saya mulai memperlakukan setiap fungsi dan kelas sebagai "entitas yang terisolasi" dalam arti bahwa ia tidak dapat mengandalkan kode luar yang memberikan input yang benar dan harus melakukan pemeriksaan input itu sendiri.

Pemrograman defensif - seperti teknik ini disebut - adalah alat yang valid dan sering digunakan. Namun, seperti semua hal, penting untuk menggunakan jumlah yang tepat, terlalu sedikit cek dan Anda tidak akan mengalami masalah, terlalu banyak dan kode Anda akan terlalu membengkak.

(atau, dalam beberapa kasus, menyusun kembali data, jika data diberikan dalam bentuk yang salah).

Itu mungkin ide yang kurang bagus. Jika Anda melihat bagian dari program Anda memanggil fungsi dengan data yang diformat secara tidak benar, TETAPKAN BAGIAN itu , jangan ubah fungsi yang dipanggil untuk dapat mencerna data yang buruk.

Ini sangat mengurangi waktu yang saya habiskan untuk memastikan bahwa data yang saya berikan "cocok" ke setiap fungsi, karena kelas dan fungsi itu sendiri sekarang memperingatkan saya ketika beberapa input buruk (dan kadang-kadang bahkan memperbaiki itu) dan saya tidak harus pergi dengan debugger melalui seluruh kode lagi untuk mencari tahu di mana sesuatu menjadi kacau.

Meningkatkan kualitas & pemeliharaan kode Anda adalah penghemat waktu dalam jangka panjang (dalam arti itu saya harus sekali lagi memperingatkan terhadap fungsi koreksi diri yang Anda buat dalam beberapa fungsi Anda - mereka mungkin menjadi sumber bug yang berbahaya. Hanya karena Anda Program tidak crash & burn bukan berarti itu berfungsi dengan benar ...)

Untuk akhirnya menjawab pertanyaan Anda: Ya, pemrograman defensif (yaitu memverifikasi validitas parameter yang disediakan) adalah - dalam derajat yang sehat - strategi yang baik. Yang mengatakan , seperti yang Anda katakan sendiri, kode Anda tidak konsisten, dan saya akan sangat menyarankan Anda menghabiskan waktu untuk memperbaiki bagian-bagian yang berbau - Anda mengatakan Anda tidak ingin khawatir tentang kode bersih sepanjang waktu, menghabiskan lebih banyak waktu untuk "membersihkan" daripada pada fitur baru ... Jika Anda tidak menjaga kode Anda bersih, Anda mungkin menghabiskan dua kali waktu "menyelamatkan" dari tidak menjaga kode bersih pada squashing bug DAN akan mengalami kesulitan menerapkan fitur baru - utang teknis dapat hancurkan kamu.


1

Tidak apa-apa. Saya menggunakan kode di FoxPro, di mana saya memiliki TRY..CATCH memblokir hampir di setiap fungsi besar. Sekarang, saya kode dalam JavaScript / LiveScript dan jarang memeriksa parameter dalam fungsi "internal" atau "pribadi".

"Berapa banyak untuk diperiksa" tergantung pada proyek / bahasa yang dipilih lebih dari itu tergantung pada keterampilan kode Anda.


1
Saya kira, itu COBA ... MENANGKAP ... LUPA. Anda melakukan kebalikan dari apa yang diminta OP. IMHO, maksud mereka adalah menghindari ketidakkonsistenan, sementara Anda memastikan bahwa program tersebut tidak meledak ketika mengenai satu.
maaartinus

1
@maaartinus itu benar. Bahasa pemrograman biasanya memberi kita konstruksi yang mudah digunakan untuk mencegah aplikasi meledak - tetapi bahasa pemrograman konstruksi memberi kita untuk mencegah ketidakkonsistenan yang tampaknya jauh lebih sulit untuk digunakan: setahu saya, terus-menerus memperbaiki segala sesuatu dan menggunakan kelas yang paling sesuai aliran informasi dalam aplikasi Anda. Inilah tepatnya yang saya tanyakan - apakah ada cara yang lebih mudah untuk memperbaikinya.
user7088941

@ user7088941 Itu sebabnya saya menghindari bahasa yang diketik dengan lemah. Python hanya fantastis, tetapi untuk hal yang lebih besar, saya tidak dapat melacak apa yang saya lakukan di tempat lain. Oleh karena itu, saya lebih suka Java, yang agak verbose (tidak begitu banyak dengan fitur Lombok dan Java 8), memiliki pengetikan yang ketat dan alat untuk analisis statis. Saya sarankan Anda untuk mencoba beberapa jenis bahasa karena saya tidak tahu bagaimana menyelesaikannya sebaliknya.
maaartinus

Ini bukan tentang parameter pengetikan yang ketat / longgar. Ini tentang mengetahui parameter yang benar. Bahkan jika Anda menggunakan (integer 4 byte), Anda mungkin perlu memeriksa apakah itu dalam kisaran 0,10 misalnya. Jika Anda tahu bahwa parameter selalu 0..10 Anda tidak perlu memeriksanya. FoxPro tidak memiliki array asosiatif misalnya, sangat sulit untuk beroperasi dengan variabel-variabelnya, cakupannya dan sebagainya .. itu sebabnya Anda harus memeriksa cek cek ..
Michael Quad

1
@ user7088941 Ini bukan OO, tapi ada aturan "gagal cepat". Setiap metode non-pribadi harus memeriksa argumennya dan melempar ketika ada sesuatu yang salah. Tidak ada try-catch, tidak ada upaya untuk memperbaikinya, cukup tiup saja setinggi langit. Tentu, pada tingkat yang lebih tinggi, pengecualian akan dicatat dan ditangani. Karena tes Anda menemukan sebagian besar masalah sebelumnya dan tidak ada masalah yang disembunyikan, kode konvergen ke solusi bebas bug jauh lebih cepat daripada ketika toleran terhadap kesalahan.
maaartinus
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.