Bukankah sesuatu yang bermutasi pada akhirnya memanipulasi keadaan?
Ya, tetapi jika itu di belakang fungsi anggota kelas kecil yang merupakan satu-satunya entitas di seluruh sistem yang dapat memanipulasi negara privatnya, maka negara itu memiliki cakupan yang sangat sempit.
Apa yang harus Anda hadapi dengan keadaan sesedikit mungkin artinya?
Dari sudut pandang variabel: beberapa baris kode harus dapat mengaksesnya sebaik mungkin. Persempit cakupan variabel ke minimum.
Dari garis sudut pandang kode: karena beberapa variabel harus dapat diakses dari garis kode itu mungkin. Mempersempit jumlah variabel yang baris kode bisa mungkin akses (bahkan tidak peduli bahwa banyak apakah itu tidak mengaksesnya, semua yang penting adalah apakah itu bisa ).
Variabel global sangat buruk karena mereka memiliki ruang lingkup maksimum. Bahkan jika mereka diakses dari 2 baris kode dalam basis kode, dari baris POV kode, variabel global selalu dapat diakses. Dari POV variabel, variabel global dengan tautan eksternal dapat diakses ke setiap baris kode di seluruh basis kode (atau setiap baris kode yang menyertakan header). Meskipun hanya diakses oleh 2 baris kode, jika variabel global dapat dilihat hingga 400.000 baris kode, daftar tersangka langsung Anda ketika Anda menemukan bahwa statusnya tidak sah maka akan memiliki 400.000 entri (mungkin dengan cepat dikurangi menjadi 2 entri dengan alat, tetapi bagaimanapun, daftar langsung akan memiliki 400.000 tersangka dan itu bukan titik awal yang menggembirakan).
Kemungkinannya adalah, juga, bahwa bahkan jika variabel global mulai hanya dimodifikasi oleh 2 baris kode di seluruh basis kode, kecenderungan yang disayangkan dari basis kode untuk berevolusi mundur akan cenderung memiliki jumlah yang meningkat secara drastis, hanya karena itu dapat meningkat sebanyak pengembang, panik untuk memenuhi tenggat waktu, melihat variabel global ini dan menyadari bahwa mereka dapat mengambil jalan pintas melalui itu.
Dalam bahasa yang tidak murni seperti C ++, bukankah manajemen negara benar-benar melakukan apa yang Anda lakukan?
Sebagian besar, ya, kecuali Anda menggunakan C ++ dengan cara yang sangat eksotis yang membuat Anda berurusan dengan struktur data yang tidak dapat diubah dan pemrograman fungsional murni - ini juga sering menjadi sumber sebagian besar bug ketika manajemen negara menjadi kompleks, dan kompleksitasnya adalah sering merupakan fungsi dari visibilitas / pemaparan kondisi itu.
Dan apa cara lain untuk berurusan dengan keadaan sesedikit mungkin selain membatasi variabel seumur hidup?
Semua ini berada di ranah pembatasan ruang lingkup variabel, tetapi ada banyak cara untuk melakukan ini:
- Hindari variabel global mentah seperti wabah. Bahkan beberapa fungsi setter / pengambil global bodoh mempersempit visibilitas variabel itu secara drastis, dan setidaknya memungkinkan beberapa cara untuk mempertahankan invarian (mis: jika variabel global tidak boleh diizinkan menjadi nilai negatif, setter dapat mempertahankan invarian itu). Tentu saja, bahkan desain setter / pengambil di atas apa yang seharusnya menjadi variabel global adalah desain yang sangat buruk, maksud saya adalah bahwa itu masih jauh lebih baik.
- Buat kelas Anda lebih kecil jika memungkinkan. Kelas dengan ratusan fungsi anggota, 20 variabel anggota, dan 30.000 baris kode yang menerapkannya akan memiliki variabel pribadi yang agak "global", karena semua variabel tersebut akan dapat diakses oleh fungsi anggotanya yang terdiri dari 30k baris kode. Anda mungkin mengatakan "kompleksitas negara" dalam kasus itu, sementara mendiskontokan variabel lokal di setiap fungsi anggota, adalah
30,000*20=600,000
. Jika ada 10 variabel global yang dapat diakses di atas itu, maka kompleksitas negara mungkin seperti 30,000*(20+10)=900,000
. "Kompleksitas keadaan" yang sehat (jenis metrik pribadi saya yang ditemukan) harus dalam ribuan atau di bawah untuk kelas, bukan puluhan ribu, dan jelas bukan ratusan ribu. Untuk fungsi gratis, ucapkan ratusan atau kurang sebelum kita mulai mengalami sakit kepala serius dalam perawatan.
- Dalam nada yang sama seperti di atas, jangan mengimplementasikan sesuatu sebagai fungsi anggota atau fungsi teman yang dapat nonmember, nonfriend hanya menggunakan antarmuka publik kelas. Fungsi tersebut tidak dapat mengakses variabel pribadi kelas, dan dengan demikian mengurangi potensi kesalahan dengan mengurangi ruang lingkup variabel pribadi tersebut.
- Hindari mendeklarasikan variabel jauh sebelum mereka benar-benar dibutuhkan dalam suatu fungsi (yaitu, hindari gaya warisan C yang menyatakan semua variabel di bagian atas fungsi bahkan jika mereka hanya membutuhkan banyak baris di bawah ini). Jika Anda tetap menggunakan gaya ini, setidaknya usahakan untuk fungsi yang lebih pendek.
Beyond Variables: Efek Samping
Banyak pedoman yang saya sebutkan di atas adalah menangani akses langsung ke keadaan mentah (variabel). Namun dalam basis kode yang cukup kompleks, hanya mempersempit ruang lingkup variabel mentah tidak akan cukup untuk dengan mudah alasan tentang kebenaran.
Anda dapat memiliki, katakanlah, struktur data pusat, di balik antarmuka abstrak yang benar-benar PADAT, sepenuhnya mampu mempertahankan invarian dengan sempurna, dan masih berakhir dengan banyak kesedihan karena paparan yang luas dari keadaan sentral ini. Contoh keadaan pusat yang tidak selalu dapat diakses secara global tetapi hanya dapat diakses secara luas adalah grafik adegan pusat dari mesin game atau struktur data lapisan tengah Photoshop.
Dalam kasus seperti itu, gagasan "negara" melampaui variabel mentah, dan hanya untuk struktur data dan hal-hal semacam itu. Ini juga membantu mengurangi ruang lingkup mereka (mengurangi jumlah baris yang dapat memanggil fungsi yang secara tidak langsung bermutasi).
Perhatikan bagaimana saya dengan sengaja menandai antarmuka sebagai merah di sini, karena dari tingkat arsitektur yang luas dan diperbesar, mengakses antarmuka itu masih bermutasi, meskipun secara tidak langsung. Kelas dapat mempertahankan invarian sebagai hasil dari antarmuka, tetapi itu hanya berjalan sejauh dalam hal kemampuan kita untuk alasan tentang kebenaran.
Dalam hal ini, struktur data pusat berada di belakang antarmuka abstrak yang bahkan mungkin tidak dapat diakses secara global. Ini mungkin hanya disuntikkan dan kemudian secara tidak langsung bermutasi (melalui fungsi anggota) dari sejumlah fungsi di basis kode kompleks Anda.
Dalam kasus seperti itu, bahkan jika struktur data dengan sempurna mempertahankan invariannya sendiri, hal-hal aneh dapat terjadi pada tingkat yang lebih luas (mis: pemutar audio dapat mempertahankan semua jenis invarian seperti bahwa level volume tidak pernah melampaui kisaran 0% hingga 100%, tapi itu tidak melindunginya dari pengguna menekan tombol play dan memiliki klip audio acak selain yang dia baru saja mulai bermain sebagai suatu peristiwa yang dipicu yang menyebabkan daftar putar untuk perombakan dengan cara yang valid tetapi masih perilaku yang tidak diinginkan, glitchy dari perspektif pengguna luas).
Cara untuk melindungi diri Anda sendiri dalam skenario kompleks ini adalah "menyumbat" tempat-tempat dalam basis kode yang dapat memanggil fungsi yang pada akhirnya menyebabkan efek samping eksternal bahkan dari pandangan yang lebih luas tentang sistem yang melampaui keadaan mentah dan di luar antarmuka.
Aneh seperti ini terlihat, Anda dapat melihat bahwa tidak ada "negara" (ditampilkan dalam warna merah, dan ini tidak berarti "variabel mentah", itu hanya berarti "objek" dan bahkan mungkin di belakang antarmuka abstrak) sedang diakses oleh banyak tempat . Fungsi masing-masing memiliki akses ke negara lokal yang juga dapat diakses oleh pusat pembaruan, dan negara pusat hanya dapat diakses oleh pusat pembaruan (membuatnya tidak lagi pusat tetapi lebih bersifat lokal).
Ini hanya untuk basis kode yang benar-benar kompleks, seperti permainan yang menjangkau 10 juta baris kode, tetapi ini dapat sangat membantu dalam mempertimbangkan kebenaran perangkat lunak Anda, dan menemukan bahwa perubahan Anda menghasilkan hasil yang dapat diprediksi, ketika Anda secara signifikan membatasi / menghambat angka tersebut tempat yang dapat bermutasi menyatakan kritis bahwa seluruh arsitektur berputar untuk berfungsi dengan benar.
Di luar variabel mentah adalah efek samping eksternal, dan efek samping eksternal adalah sumber kesalahan bahkan jika mereka terbatas pada beberapa fungsi anggota. Jika satu muatan fungsi kapal dapat secara langsung memanggil beberapa fungsi anggota tersebut, maka ada muatan fungsi dalam sistem yang secara tidak langsung dapat menyebabkan efek samping eksternal, dan yang meningkatkan kompleksitas. Jika hanya ada satu tempat di basis kode yang memiliki akses ke fungsi anggota tersebut, dan bahwa satu jalur eksekusi tidak dipicu oleh peristiwa sporadis di semua tempat, tetapi dijalankan dengan cara yang sangat terkontrol dan dapat diprediksi, maka itu mengurangi kompleksitas.
Kompleksitas Negara
Bahkan kompleksitas negara adalah faktor yang agak penting untuk dipertimbangkan. Struktur sederhana, dapat diakses secara luas di belakang antarmuka abstrak, tidak begitu sulit untuk dikacaukan.
Struktur data grafik kompleks yang mewakili representasi logis inti dari arsitektur kompleks cukup mudah untuk dikacaukan, dan dengan cara yang bahkan tidak melanggar invarian grafik. Grafik berkali-kali lebih kompleks daripada struktur sederhana, dan itu menjadi lebih penting dalam kasus seperti itu untuk mengurangi kompleksitas yang dirasakan dari basis kode untuk mengurangi jumlah tempat yang memiliki akses ke struktur grafik sedemikian hingga minimum absolut, dan di mana strategi "pusat pembaruan" semacam itu yang membalikkan paradigma tarikan untuk menghindari sporadis, dorongan langsung ke struktur data grafik dari semua tempat dapat benar-benar terbayar.