Programmer defender lebih kuat dari entropi

© Dragon Ball. Goku.

Programmer-defender kapan saja dan di mana saja dalam kode mengharapkan munculnya masalah potensial dan menulis kode sedemikian rupa untuk melindungi diri mereka dari mereka terlebih dahulu. Dan jika Anda tidak dapat membela diri terhadap masalah, maka setidaknya pastikan bahwa konsekuensi dan dampaknya terhadap pengguna minimal.

Saya ingat efek FlashForward dari film Hollywood ketika protagonis melihat bencana yang akan datang dan tetap sangat tenang, karena dia tahu sebelumnya bahwa itu akan terjadi dan memiliki perlindungan dari itu. Gagasan di balik pemrograman defensif adalah untuk melindungi diri Anda dari masalah yang sulit atau tidak mungkin diprediksi. Seorang programmer keamanan mengharapkan kesalahan terjadi di mana saja dalam sistem dan pada waktu tertentu untuk mencegahnya sebelum menyebabkan kerusakan. Namun, tujuannya bukan untuk membuat sistem yang tidak pernah crash, itu masih mustahil. Tujuannya adalah untuk menciptakan sistem yang crash dengan anggun jika terjadi masalah yang tidak terduga.

Mari kita pahami lebih detail apa yang termasuk dalam konsep "jatuh anggun."

  • Jatuh cepat. Dalam hal terjadi kesalahan tak terduga, semua operasi harus diselesaikan segera, terutama jika perhitungan selanjutnya sulit atau dapat menyebabkan korupsi data.
  • Jatuh dengan rapi. Jika terjadi kesalahan, program harus membebaskan semua sumber daya, menghapus kunci, menghapus file sementara dan setengah direkam, menutup koneksi. Tunggu selesainya operasi kritis, yang interupsi yang dapat menyebabkan hasil yang tidak terduga. Atau cara aman untuk menghentikan operasi ini.
  • Jatuh dengan jelas dan indah. Jika ada yang rusak, pesan kesalahan harus sederhana, singkat dan berisi detail penting dari konteks sistem tempat kesalahan terjadi. Ini akan membantu tim yang bertanggung jawab atas sistem untuk mencari tahu masalah secepat mungkin dan memperbaikinya.

Tapi Anda mungkin punya pertanyaan.

Mengapa membuang waktu untuk masalah yang mungkin timbul di masa depan? Sekarang mereka tidak ada di sana, kodenya berfungsi dengan sempurna. Selain itu, masalah mungkin tidak pernah terjadi sama sekali. Bagaimanapun, profesional tidak melakukan rekayasa demi rekayasa ( YAGNI - Anda tidak akan membutuhkannya)!

Yang utama adalah pragmatisme


Andrew Hunt dalam buku "Programmer-pragmatis" memberikan definisi pemrograman defensif berikut - " paranoia pragmatis ."

Lindungi kode Anda dari:

  • kesalahan sendiri;
  • kesalahan orang lain;
  • kesalahan dan kegagalan dalam sistem lain yang terintegrasi dengan Anda;
  • kesalahan besi, lingkungan, dan platform tempat aplikasi Anda bekerja.

Mari kita bahas beberapa metode taktis dan strategis pemrograman defensif, berikut ini yang akan menciptakan sistem yang andal dan dapat diprediksi yang tahan terhadap kegagalan sewenang-wenang.

Beberapa tips mungkin tampak "kapten", tetapi dalam praktiknya, banyak pengembang bahkan tidak mengikuti mereka. Tetapi jika Anda mematuhi praktik dan pendekatan sederhana, ini akan secara signifikan meningkatkan stabilitas sistem Anda.

Jangan percaya siapapun


Data pengguna tidak dapat diandalkan secara default. Pengguna sering salah memahami apa yang tampak jelas bagi kami (sebagai pengembang sistem). Harapkan input yang salah dan selalu periksa.

Periksa juga jumlah input. Mungkin saja pengguna mengirim terlalu banyak. Pada saat yang sama, dari sudut pandang logika bisnis, ini adalah skenario yang benar. Tapi itu bisa menyebabkan pemrosesan terlalu lama. Apa yang bisa dilakukan dengan ini? Misalnya, jalankan secara tidak sinkron, jika jumlah data input melebihi batas tertentu dan spesifik bisnis memungkinkan Anda untuk memproses data di latar belakang.

Pengaturan aplikasi (misalnya, file konfigurasi) juga tunduk pada tampilan data yang salah di dalamnya. Seringkali, pengaturan program disimpan dalam JSON, YAML, XML, INI dan format lainnya. Karena semua ini adalah file teks, orang harus berharap bahwa cepat atau lambat seseorang akan mengubah sesuatu di dalamnya, dan program Anda akan mulai bekerja secara tidak benar. Itu bisa berupa pengguna akhir atau seseorang dari tim Anda.

Basis data, file, penyimpanan terpusat dari konfigurasi, registri - semua tempat ini dapat diakses oleh orang lain, dan cepat atau lambat mereka akan mengubah sesuatu di sana ( hukum Murphy ).

Inlet sampah → inlet sampah


Input yang lulus validasi dan mulai diproses harus bersih jika Anda ingin kode Anda melakukan apa yang Anda harapkan darinya.

Namun, praktik yang baik untuk melakukan pemeriksaan validasi data tambahan, termasuk ketika mereka sudah mulai diproses. Di tempat-tempat kritis (penagihan, otorisasi, data pribadi dan rahasia, dll.) Ini hampir merupakan persyaratan wajib. Ini diperlukan agar dalam kasus bug dalam kode atau masalah dengan validator data input, hentikan aliran eksekusi secepat mungkin. Sulit untuk membuat validasi kualitas dengan memeriksa semua skenario kesalahan yang mungkin terjadi, sehingga Anda dapat menggunakan metode yang lebih sederhana untuk memvalidasi bahwa program masih mengeksekusi dengan benar - pernyataan dan pengecualian.

Paranoid yang sehat adalah fitur khas semua pengembang profesional. Tetapi sangat penting untuk mencari keseimbangan optimal dan memahami kapan solusinya sudah cukup baik.

Pisahkan konfigurasi di sekitar lingkungan


Penyebab umum dari masalah adalah pemisahan konfigurasi yang tidak memadai antara lingkungan atau tidak adanya pemisahan seperti itu.

Ini dapat menyebabkan banyak masalah, misalnya:

  • lingkungan pengujian mulai membaca dan / atau menulis data dari produksi, basis data, antrian, dan sumber daya lainnya;
  • lingkungan pengujian menggunakan integrasi dan layanan eksternal dengan akun produksi;
  • pencampuran statistik, metrik, kesalahan dari lingkungan yang berbeda;
  • pelanggaran keamanan (pengembang, penguji dan anggota tim lainnya mendapatkan akses ke sumber daya produksi);
  • bug yang sulit diselidiki pada produksi (misalnya, bagian dari pesan dalam antrian hilang karena lingkungan pengujian mulai membacanya).

Ini hanya contoh, daftar lengkap masalah yang mungkin disebabkan oleh pemisahan konfigurasi yang tidak bertanggung jawab hampir tidak ada habisnya dan tergantung pada spesifikasi proyek.

Pemisahan data konfigurasi oleh lingkungan yang bertanggung jawab dapat secara signifikan mengurangi kemungkinan seluruh kelas masalah yang terkait dengan:

  • keamanan
  • keandalan;
  • dukungan dan penyebaran (Insinyur DevOps akan berterima kasih).

Selain itu, praktik yang baik untuk menyimpan data rahasia (kunci, token, kata sandi) di tempat terpisah yang dirancang khusus untuk menyimpan dan memproses rahasia. Sistem seperti itu mengenkripsi data dengan aman, memiliki sarana yang fleksibel untuk mengelola hak akses, dan juga memungkinkan Anda untuk dengan cepat mengubah kunci jika telah dikompromikan. Dalam hal ini, Anda tidak perlu membuat perubahan pada kode dan menggunakan kembali aplikasi. Ini sangat penting untuk sistem yang bekerja dengan transaksi keuangan, data rahasia atau pribadi.

Ingat efek cascading


Penyebab umum jatuhnya sistem besar dan kompleks adalah efek cascading. Kerusakan atau degradasi fungsi salah satu bagian sistem terjadi, dan satu per satu subsistem lain yang terkait dengannya mulai gagal. Dihamburkan sampai seluruh sistem menjadi sepenuhnya tidak dapat diakses.

Beberapa trik perlindungan:

  • gunakan timeout progresif (eksponensial) dengan elemen acak;
  • set nilai yang wajar untuk batas waktu koneksi dan batas waktu soket;
  • meramalkan kemunduran di muka dalam kasus kegagalan layanan individu. Lebih baik untuk sementara menurunkan beberapa fungsi, menonaktifkan layanan sama sekali, tetapi jangan mengambil risiko merusak seluruh sistem. Tetapi bayangkan bahwa dalam kasus ini pengguna melihat pesan yang dimengerti dan tidak menakutkan, dan tim dukungan dan pengembangan secepatnya mencari tahu tentang masalah tersebut.

Laporkan masalah dengan cepat


Semua sistem gagal. Terkadang sesuatu yang aneh terjadi pada mereka yang diharapkan oleh para pencipta "setiap 10 tahun sekali." Integrasi dan API eksternal secara berkala menjadi tidak tersedia atau merespons secara tidak benar. Membuat kemunduran untuk semua kasus seperti itu seringkali sulit, panjang, atau tidak mungkin. Antisipasi situasi ini sebelumnya dan laporkan secepat mungkin. Masuk ke tingkat ERROR atau ke sistem pemantauan - begitu saja. Menambahkan validasi tambahan ke pemeriksaan kesehatan bahkan lebih baik. Untuk mengirim pesan dari kode ke Slack, Telegram, PagerDuty atau layanan lain yang secara instan akan memberi tahu tim Anda tentang masalah tersebut sangat ideal.

Tetapi penting untuk memahami dengan jelas kapan masuk akal mengirim pesan secara langsung. Hanya jika kesalahan, situasi yang mencurigakan atau atipikal dikaitkan dengan proses bisnis dan penting bahwa orang atau sekelompok orang tertentu dalam tim menerima pemberitahuan secepat mungkin dan dapat merespons.

Semua masalah teknis dan penyimpangan lainnya harus ditangani dengan cara standar - pemantauan, peringatan, penebangan.

Tembolok yang sering digunakan dan / atau data terkini


Program dan orang memiliki satu kesamaan - mereka cenderung menggunakan kembali data yang sering digunakan atau baru-baru ini ditemui. Dalam sistem yang sangat dimuat, Anda harus selalu mengingat ini dan menyimpan data di tempat terpanas di sistem.

Strategi caching sangat tergantung pada spesifikasi proyek dan data. Jika data bisa berubah, ada kebutuhan untuk pembatalan cache. Karena itu, pertimbangkan sebelumnya bagaimana Anda akan melakukan ini. Dan pikirkan juga risiko apa yang mungkin terjadi jika data yang sudah ketinggalan zaman muncul di cache, cache tidak berfungsi, dll.

Ganti operasi yang mahal dengan yang murah


Bekerja dengan string adalah salah satu operasi paling umum dalam program apa pun. Dan jika ini tidak dilakukan secara optimal, itu bisa menjadi operasi yang mahal. Dalam berbagai bahasa pemrograman, spesifikasi bekerja dengan string mungkin berbeda-beda, tetapi Anda harus selalu mengingatnya.

Dalam aplikasi besar dengan basis kode besar, kode yang ditulis bertahun-tahun yang lalu sering ditemukan bekerja tanpa kesalahan, tetapi tidak optimal dalam hal kinerja. Seringkali, perubahan dangkal dalam struktur data dari array / daftar ke tabel hash memberikan dorongan serius (bahkan jika hanya di tempat lokal dalam kode).

Terkadang Anda dapat meningkatkan kinerja dengan menulis ulang algoritme untuk menggunakan operasi bitwise. Tetapi bahkan dalam kasus-kasus langka ketika dibenarkan, kodenya sangat kompleks. Karena itu, ketika membuat keputusan, pertimbangkan keterbacaan kode dan fakta bahwa kode tersebut perlu didukung. Hal yang sama berlaku untuk optimasi rumit lainnya: hampir selalu, kode seperti itu menjadi sulit dibaca dan sangat sulit untuk dipertahankan. Jika Anda masih memutuskan optimisasi yang rumit, jangan lupa untuk menulis komentar yang menjelaskan apa yang ingin Anda lakukan dengan kode ini dan mengapa ditulis seperti itu.

Pada saat yang sama, optimasi harus diperlakukan dengan pragmatisme yang sehat:

  • jika dibutuhkan Anda, sebagai pengembang, selama beberapa detik atau menit - masuk akal untuk segera melakukannya;
  • jika lebih, masuk akal untuk melakukannya segera hanya ketika Anda 100% yakin akan kebutuhannya. Dalam semua kasus lain, masuk akal untuk menunda, menulis dalam kode TODO, mengumpulkan lebih banyak informasi, berkonsultasi dengan kolega, dll.

Optimalisasi prematur adalah akar dari segala kejahatan (Donald Knuth)

Menulis ulang dalam bahasa tingkat yang lebih rendah


Ini adalah langkah ekstrem. Bahasa tingkat rendah hampir selalu lebih cepat dibandingkan dengan bahasa tingkat yang lebih tinggi. Tetapi solusi ini memiliki harga - mengembangkan program semacam itu lebih lama dan lebih sulit. Terkadang, menulis ulang bagian-bagian penting dari sistem dalam bahasa tingkat rendah, Anda dapat mencapai peningkatan produktivitas yang serius. Tetapi ada efek samping - biasanya solusi seperti itu hilang di lintas platform dan dukungan mereka lebih mahal. Karena itu, buat keputusan dengan hati-hati.

Sendiri di lapangan bukan seorang pejuang


Sebagai kesimpulan, saya ingin mencatat satu hal yang lebih penting, mungkin yang paling penting. Langkah-langkah yang kami pertimbangkan dalam paragraf sebelumnya hanya akan berfungsi jika semua anggota tim mematuhinya dan semua orang memiliki pemahaman tentang siapa yang bertanggung jawab atas apa dan apa yang perlu dilakukan jika terjadi situasi kritis. Adalah penting bahwa setelah memperbaiki masalah, mengadakan pertemuan (Post Mortem) dengan semua orang yang tertarik dan mencari tahu mengapa masalah ini muncul dan apa yang dapat dilakukan untuk mencegah masalah ini terjadi di masa depan. Dalam banyak kasus, perubahan teknis dan proses diperlukan. Dengan setiap Post Mortem baru, sistem Anda akan menjadi lebih dapat diandalkan, tim akan lebih berpengalaman dan kohesif, dan entropi di alam semesta akan sedikit kurang;)

Artikel ini sebagian menggunakan bahan dari Mengapa Pemrograman Defensif adalah Cara Terbaik untuk Pengkodean yang Kuat (Ravi Shankar Rajan).

Source: https://habr.com/ru/post/id472922/


All Articles