Menulis kode yang kuat vs. rekayasa ulang

33

Bagaimana Anda tahu bahwa Anda sedang menulis kode paling kuat tanpa rekayasa ulang?

Saya mendapati diri saya berpikir terlalu banyak tentang setiap jalur yang mungkin diambil oleh kode saya, dan kadang-kadang terasa seperti buang-buang waktu. Saya kira itu tergantung pada jenis program yang Anda tulis, tetapi saya tidak ingin menggunakan terlalu banyak waktu saya memperhitungkan situasi yang tidak akan pernah terjadi.

Fran Sevillano
sumber
2
Kode itu di Agda2
SK-logic
sebuah contoh nyata akan sangat membantu mengemukakan pendapat Anda. :)
João Portela
Dapatkah saya memeriksa apakah Anda benar-benar bertanya tentang ketahanan, yaitu "kemampuan suatu sistem untuk terus bekerja di hadapan input yang tidak valid atau kondisi lingkungan yang penuh tekanan", karena beberapa jawaban tampaknya berpikir Anda berbicara tentang perluasan.
DJClayworth
Saya bekerja di bawah tenggat waktu gila dan itu untuk demo-ware, jadi saya bisa dengan cepat meretas dengan cepat tanpa kelumpuhan yang sempurna.
Ayub
1
Berikut ini adalah artikel yang berbicara tentang subjek: code-tag.com/2017/04/02/...
San

Jawaban:

39

Bagaimana Anda tahu bahwa Anda sedang menulis kode paling kuat tanpa rekayasa ulang?

Apa yang Anda anggap kode yang kuat? Kode yang sudah menjadi bukti di masa depan dan begitu kuat sehingga dapat menangani situasi apa pun? Salah, tidak ada yang bisa memprediksi masa depan! Dan salah lagi, karena itu akan menjadi kekacauan yang rumit dan tidak dapat dipelihara.

Saya mengikuti berbagai prinsip: Pertama dan terpenting YAGNI (belum) dan KISS , jadi saya tidak menulis kode yang tidak perlu. Itu juga secara efektif mencegah rekayasa berlebihan. Saya memperbaiki aplikasi ketika ekstensi diperlukan. Alat refactoring modern memungkinkan Anda dengan mudah membuat antarmuka dan bertukar implementasi setelahnya ketika Anda membutuhkannya.

Kemudian saya mencoba membuat kode yang saya tulis sekuat mungkin, yang mencakup menghilangkan sebanyak mungkin jalur yang bisa diambil oleh program (dan juga menyatakan) sebanyak mungkin dan sedikit pemrograman Spartan . Yang sangat membantu adalah fungsi / metode "atomik" yang tidak bergantung pada keadaan eksternal atau setidaknya tidak meninggalkan program dalam keadaan tidak konsisten ketika gagal. Jika Anda melakukannya dengan baik, itu juga sangat tidak mungkin bahwa Anda akan pernah berakhir dengan kode spaghetti dan itu juga merupakan berkah bagi pemeliharaan. Juga, dalam desain berorientasi objek, prinsip-prinsip SOLID adalah panduan hebat untuk kode yang kuat.

Saya benar-benar menemukan bahwa sering kali Anda dapat mengurangi kerumitan, misalnya ledakan kombinatorial dari jalur atau status program, dengan memikirkan secara mendalam tentang bagaimana Anda dapat mendesainnya sebagai jalur sekurus mungkin. Usahakan agar kombinasi yang ada seminimal mungkin dengan memilih pemesanan subrutin terbaik Anda dan mendesainnya untuk tujuan ini.

Kode robust adalah kode yang paling sederhana dan selalu bersih, tetapi kesederhanaan adalah sifat yang tidak selalu mudah dicapai. Namun, Anda harus berusaha keras untuk itu. Selalu hanya menulis kode sesederhana mungkin dan hanya menambah kompleksitas ketika Anda tidak punya pilihan lain.

Kesederhanaan itu kuat, kompleksitasnya rapuh.

Kompleksitas membunuh.

Elang
sumber
2
Karena tidak memiliki banyak kelas, pabrik, dan abstraksi. Ini sebuah paradoks, tetapi beberapa orang menyukai hal itu. Tidak tahu kenapa.
Coder
5
Ini SPARTA!!!
Tom Squires
4
Orang-orang yang belum melakukan ini selama dua puluh tahun tidak mengerti bagaimana kompleksitas dapat membunuh Anda. Mereka pikir mereka sangat pintar. Mereka bodoh, tidak pintar. Kompleksitas itu akan membunuhmu mati.
PeterAllenWebb
1
Robustness bukan tentang pemeriksaan di masa depan - ini tentang melanjutkan fungsi dengan input yang tidak valid atau lingkungan yang penuh tekanan - Code Complete p464.
DJClayworth
5
Kecuali si penanya menggunakan kata 'kuat' dalam arti yang berbeda dari yang saya pahami, Anda menjawab pertanyaan yang berbeda. Dia tidak bertanya "haruskah saya kode untuk memungkinkan persyaratan di masa depan" dia bertanya "kasus input tidak biasa apa yang harus saya tangani". Tidak ada YAGNI, KISS dan SOLID yang relevan. Apakah Anda perlu mengizinkan jutaan pengguna yang mencoba masuk secara bersamaan? Apa yang akan terjadi jika nama login dimulai dengan garis miring terbalik? Tak satu pun dari pertanyaan ini dijawab oleh YAGNI.
DJClayworth
8

Saya mencoba menjaga keseimbangan, fokus pada

  • menangani semua jalur eksekusi yang mungkin dalam kasus penggunaan yang ada (ini adalah bagian "kekokohan"),
  • mengaktifkan fitur / persyaratan Saya cukup yakin bahwa akan datang di masa mendatang, dan
  • hal-hal yang saya tahu dari pengalaman yang akan dibutuhkan untuk pemeliharaan jangka panjang dari basis kode (yaitu menjaga kode tetap bersih dan dapat diuji).

Ini adalah area perbatasan yang tidak jelas - kadang-kadang saya berhasil melakukan pekerjaan yang tidak dibutuhkan, kadang-kadang saya gagal melakukan sesuatu yang ternyata diperlukan di kemudian hari. Jika kesalahannya tidak besar, saya baik-baik saja. Bagaimanapun, saya berusaha untuk belajar dari kesalahan saya.

Péter Török
sumber
Sebuah contoh akan bagus di sini menangani semua jalur eksekusi yang mungkin dalam kasus penggunaan yang ada
CodeYogi
5

Perbedaan antara kuat dan overengineering adalah perbedaan antara anggun menangani semua kasus penggunaan yang mungkin, bahkan kasus penggunaan aneh dan pinggiran yang TIDAK HARUS terjadi. Ketika saya mengatakan dengan anggun maksud saya, pengguna memasukkan kasus pengecualian yang aneh atau mengalami situasi yang membutuhkan fitur yang tidak didukung atau tidak ditentukan yang tidak ditentukan dan kode keluar dengan anggun tanpa menabrak atau memberi tahu pengguna tentang fungsi yang tidak didukung.

Overengineering di sisi lain dapat jatuh dalam ranah implementasi lengkap fitur yang tidak diperlukan atau diminta (beberapa fitur yang klien BUTUHKAN tetapi tidak pernah diminta!) ATAU itu dapat didefinisikan dengan menurunkan desain yang terlalu rumit atau terlalu rumit kode untuk menangani masalah yang relatif sederhana.

maple_shaft
sumber
4

1) Dapatkan persyaratan.

2) Tulis kode minimum untuk memenuhi persyaratan. Jika ada yang ambigu, tebaklah orang yang berpendidikan. Jika super ambigu, kembali ke 1.

3) Kirim ke pengujian.

4) Jika penguji mengatakan itu baik, dokumentasikan persetujuannya. Jika ada masalah, kembali ke 1.

Fokus pada lulus tes, bukan prediksi tes. Jika Anda tidak memiliki penguji ... dapatkan penguji! Mereka sangat penting tidak hanya untuk memverifikasi kebenaran kode, tetapi juga untuk seluruh proses pengembangan.

Morgan Herlocker
sumber
1
+1 untuk Fokus pada lulus tes, bukan prediksi tes, namun banyak pengembang seperti saya diharapkan melakukan keduanya namun karena kurangnya analis bisnis yang kuat.
maple_shaft
@maple_shaft - Sangat benar. Intinya adalah bahwa masalah ini muncul karena ketidakmampuan orang lain. Menekankan pada pekerjaan orang lain adalah jalan menuju kejenuhan. Jika perusahaan saya cukup bodoh untuk meminta saya melakukan piutang pada bulan itu, saya tidak akan terlalu kecewa pada diri saya sendiri jika itu tidak berjalan dengan baik. Menentukan persyaratan biasanya hanya memerlukan penjelasan tentang apa yang Anda lakukan sehari-hari, sehingga bisa otomatis. Jika tidak ada karyawan yang bisa melakukan itu, yah ... perusahaan mungkin dalam kesulitan.
Morgan Herlocker
3

Pertama-tama, pertahankan data dinormalisasi (tidak berlebihan) sebanyak yang Anda bisa. Jika data sepenuhnya dinormalisasi, tidak ada satu pun pembaruan pada data yang dapat membuatnya tidak konsisten.

Anda tidak selalu dapat menjaga data dinormalisasi, dengan kata lain Anda mungkin tidak dapat menghilangkan redundansi, dalam hal ini dapat memiliki kondisi yang tidak konsisten. Yang harus dilakukan adalah mentolerir ketidakkonsistenan dan memperbaikinya secara berkala dengan semacam program yang menyapu dan menambalnya.

Ada kecenderungan kuat untuk mencoba mengelola redundansi secara ketat melalui pemberitahuan. Ini tidak hanya sulit untuk memastikan mereka benar, tetapi dapat menyebabkan inefisiensi yang sangat besar . (Bagian dari godaan untuk menulis notifikasi muncul karena dalam OOP mereka didorong secara praktis.)

Secara umum, apa pun yang tergantung pada urutan waktu peristiwa, pesan, dll., Akan rentan dan membutuhkan banyak kode pertahanan. Peristiwa dan pesan adalah karakteristik data dengan redundansi, karena mereka mengkomunikasikan perubahan dari satu bagian ke bagian lain, berusaha mencegah inkonsistensi.

Seperti yang saya katakan, jika Anda harus memiliki redundansi (dan kemungkinan cukup bagus, Anda harus), yang terbaik adalah untuk dapat a) mentolerir, dan b) memperbaikinya. Jika Anda mencoba untuk mencegah ketidakkonsistenan hanya melalui pesan, pemberitahuan, pemicu, dll., Anda akan merasa sangat sulit untuk membuatnya kuat.

Mike Dunlavey
sumber
3
  • menulis untuk digunakan kembali.
  • menulis tes. sepele, nontrivial, beberapa yang rumit bukan kepalang untuk melihat bagaimana menangani dalam kondisi seperti itu. tes juga akan membantu Anda menentukan bentuk antarmuka.
  • tulis programnya agar gagal (mis. pernyataan). kode saya memiliki banyak penggunaan kembali dan saya menguji banyak kasus - ada lebih banyak pengecekan / penanganan kesalahan daripada implementasi aktual (berdasarkan jumlah baris).
  • penggunaan kembali.
  • segera perbaiki hal-hal yang salah.
  • belajar dan bangun dari pengalaman.

kesalahan akan muncul di sepanjang jalan, tetapi mereka (untungnya) akan dilokalisasi dan mereka akan (dalam kebanyakan kasus) muncul sangat awal dalam pengujian. manfaat lain dari penggunaan kembali adalah bahwa klien / pemanggil dapat menyimpan sebagian besar pemeriksaan kesalahan / perancah menggunakan apa yang dibawa oleh implementasi.

pengujian Anda kemudian akan menentukan kemampuan program Anda dan seberapa kuat mereka - teruslah menambahkan tes sampai Anda puas dengan tingkat keberhasilan dan input; meningkatkan, memperluas, dan memperkuat sesuai kebutuhan.

justin
sumber
2

Saya membuat perbedaan ini dengan menulis kode dengan perilaku yang jelas, tetapi belum tentu optimal untuk operan eksekusi yang sangat tidak mungkin. Sebagai contoh, ketika saya cukup yakin (terbukti, tetapi tidak diuji) bahwa sebuah matriks akan positif pasti, saya memasukkan pernyataan atau pengecualian ke dalam program untuk menguji keadaan, tetapi jangan menulis jalur kode sendiri untuk itu. Dengan demikian, perilaku didefinisikan, tetapi tidak optimal.

thiton
sumber
2

Robustness: Tingkat di mana suatu sistem terus berfungsi di hadapan input yang tidak valid atau kondisi lingkungan yang penuh tekanan. (Kode Lengkap 2, p464)

Pertanyaan penting di sini adalah menanyakan seberapa penting ketahanan bagi Anda. Jika Anda Facebook, sangat penting bahwa situs web Anda terus berfungsi ketika seseorang memasukkan karakter khusus ke dalam input, dan bahwa server Anda tetap aktif ketika 100 juta pengguna masuk secara bersamaan. Jika Anda menulis skrip untuk melakukan operasi umum yang hanya Anda lakukan, Anda tidak terlalu peduli. Di antara ada banyak level. Membuat keputusan tentang seberapa banyak ketahanan yang Anda butuhkan adalah salah satu keterampilan penting yang harus dipelajari pengembang.

Prinsip YAGNI berlaku untuk menambahkan fitur yang mungkin dibutuhkan suatu program. Tapi prinsip itu tidak berlaku untuk ketahanan. Pemrogram cenderung untuk melebih-lebihkan kemungkinan bahwa ekstensi di masa mendatang akan diperlukan (terutama jika itu yang keren) tetapi mereka meremehkan kemungkinan terjadi kesalahan. Juga, jika ternyata fitur yang dihilangkan diperlukan setelahnya, programmer dapat menulisnya nanti. Jika ternyata diperlukan pengecekan kesalahan yang dihilangkan, kerusakan dapat terjadi.

Oleh karena itu sebenarnya lebih baik berbuat salah di samping melakukan pemeriksaan untuk kondisi kesalahan yang tidak biasa. Tapi ada keseimbangan. Beberapa hal yang perlu dipertimbangkan dalam keseimbangan ini:

  • Seberapa sering kesalahan ini terjadi?
  • Berapa biaya kesalahan ini terjadi?
  • Apakah ini untuk penggunaan internal atau eksternal?

Jangan lupa bahwa orang dapat - dan akan - mencoba menggunakan program Anda dengan cara yang tidak terduga. Lebih baik jika sesuatu yang dapat diprediksi terjadi ketika mereka melakukannya.

Sebagai garis pertahanan terakhir, gunakan assert atau shutdown. Jika terjadi sesuatu yang tidak dapat Anda atasi cara menghadapinya, matikan program. Itu biasanya lebih baik daripada membiarkan program berjalan dan melakukan sesuatu yang tidak terduga.

DJClayworth
sumber