Decoupling
Ini pada akhirnya tentang decoupling kepada saya pada akhir hari di tingkat desain yang paling mendasar tanpa nuansa karakteristik kompiler dan linker kami. Maksud saya Anda dapat melakukan hal-hal seperti membuat setiap header mendefinisikan hanya satu kelas, menggunakan pimpl, meneruskan deklarasi ke jenis yang hanya perlu dideklarasikan, tidak didefinisikan, bahkan mungkin menggunakan header yang hanya berisi deklarasi maju (mis .:) <iosfwd>
, satu header per file sumber , mengatur sistem secara konsisten berdasarkan jenis hal yang dinyatakan / didefinisikan, dll.
Teknik untuk Mengurangi "Ketergantungan Waktu Kompilasi"
Dan beberapa teknik dapat membantu sedikit tetapi Anda dapat menemukan diri Anda melelahkan praktik ini dan masih menemukan file sumber rata-rata di sistem Anda perlu pembukaan dua halaman dari #include
arahan untuk melakukan sesuatu yang sedikit bermakna dengan waktu pembuatan yang melambung tinggi jika Anda terlalu fokus mengurangi ketergantungan waktu kompilasi di tingkat tajuk tanpa mengurangi ketergantungan logis pada desain antarmuka Anda, dan sementara itu mungkin tidak dianggap "spageti header" dengan tegas, saya Masih akan mengatakan itu diterjemahkan ke masalah merugikan serupa dengan produktivitas dalam praktek. Pada akhirnya, jika unit kompilasi Anda masih membutuhkan banyak informasi untuk dapat melakukan apa saja, maka itu akan diterjemahkan untuk menambah waktu pembuatan dan mengalikan alasan Anda harus berpotensi kembali dan harus mengubah hal-hal sambil membuat pengembang merasa seperti mereka headbutting sistem hanya mencoba menyelesaikan koding harian mereka. Saya t'
Anda dapat, misalnya, membuat setiap subsistem menyediakan satu file header dan antarmuka yang sangat abstrak. Tetapi jika subsistem tidak dipisahkan satu sama lain, maka Anda mendapatkan sesuatu yang menyerupai spaghetti lagi dengan antarmuka subsistem tergantung pada antarmuka subsistem lainnya dengan grafik dependensi yang terlihat seperti berantakan untuk bekerja.
Teruskan Deklarasi ke Tipe Eksternal
Dari semua teknik yang saya gunakan untuk mendapatkan basis kode sebelumnya yang membutuhkan waktu dua jam untuk membangun sementara para pengembang kadang-kadang menunggu 2 hari untuk giliran mereka di CI pada server build kami (Anda hampir dapat membayangkan mesin-mesin itu sebagai binatang buangan yang kelelahan karena mencoba dengan panik. untuk mengikuti dan gagal saat pengembang mendorong perubahan mereka), yang paling dipertanyakan bagi saya adalah meneruskan menyatakan jenis yang didefinisikan dalam header lain. Dan saya berhasil mendapatkan basis kode itu hingga 40 menit atau lebih setelah bertahun-tahun melakukan ini dalam langkah-langkah tambahan sedikit ketika mencoba untuk mengurangi "header spaghetti", praktik yang paling dipertanyakan di belakang (seperti membuat saya melupakan sifat dasar dari desain sementara tunnel visioned pada saling ketergantungan header) maju menyatakan jenis didefinisikan dalam header lainnya.
Jika Anda membayangkan Foo.hpp
tajuk yang memiliki sesuatu seperti:
#include "Bar.hpp"
Dan itu hanya menggunakan Bar
di header cara yang membutuhkannya deklarasi, bukan definisi. maka mungkin tampak seperti no-brainer untuk menyatakan class Bar;
untuk menghindari membuat definisi yang Bar
terlihat di header. Kecuali dalam praktek sering Anda akan menemukan sebagian besar unit kompilasi yang menggunakan Foo.hpp
masih akhirnya perlu Bar
didefinisikan pula dengan beban tambahan karena harus memasukkan Bar.hpp
diri mereka di atas Foo.hpp
, atau Anda mengalami skenario lain di mana itu benar-benar membantu dan 99 % dari unit kompilasi Anda dapat bekerja tanpa termasuk Bar.hpp
, kecuali kemudian menimbulkan pertanyaan desain yang lebih mendasar (atau setidaknya saya pikir seharusnya saat ini) mengapa mereka perlu melihat deklarasi Bar
dan mengapaFoo
bahkan perlu repot untuk mengetahuinya jika itu tidak relevan dengan kebanyakan kasus penggunaan (mengapa membebani desain dengan dependensi ke yang lain yang hampir tidak pernah digunakan?).
Karena secara konseptual kita belum benar-benar dipisahkan Foo
dari Bar
. Kami baru saja membuatnya sehingga tajuk Foo
tidak perlu banyak info tentang tajuk Bar
, dan itu tidak hampir sama pentingnya dengan desain yang benar-benar membuat keduanya sepenuhnya independen satu sama lain.
Script Tertanam
Ini benar-benar untuk basis kode skala yang lebih besar tetapi teknik lain yang saya temukan sangat berguna adalah dengan menggunakan bahasa skrip tertanam untuk setidaknya bagian paling tinggi dari sistem Anda. Saya menemukan saya dapat menanamkan Lua dalam satu hari dan secara seragam dapat memanggil semua perintah di sistem kami (untungnya perintah itu abstrak, untungnya). Sayangnya saya menemui hambatan di mana para devs tidak mempercayai pengenalan bahasa lain dan, mungkin yang paling aneh, dengan kinerja sebagai kecurigaan terbesar mereka. Namun sementara saya dapat memahami masalah lain, kinerja seharusnya bukan masalah jika kita hanya menggunakan skrip untuk menjalankan perintah ketika pengguna mengklik tombol, misalnya, yang tidak melakukan loop sendiri yang berat (apa yang kami coba lakukan, khawatir tentang perbedaan nanodetik dalam waktu respons untuk klik tombol?).
Contoh
Sementara itu cara paling efektif yang pernah saya saksikan setelah teknik melelahkan untuk mengurangi waktu kompilasi dalam basis kode besar adalah arsitektur yang benar-benar mengurangi jumlah informasi yang diperlukan untuk satu hal dalam sistem untuk bekerja, tidak hanya memisahkan satu header dari yang lain dari kompiler. perspektif tetapi mengharuskan pengguna antarmuka ini untuk melakukan apa yang perlu mereka lakukan sambil mengetahui (baik dari sudut pandang manusia dan kompiler, benar decoupling yang melampaui dependensi kompiler) minimal.
ECS hanyalah salah satu contoh (dan saya tidak menyarankan Anda menggunakan salah satunya), tetapi dengan melihatnya menunjukkan kepada saya bahwa Anda dapat memiliki beberapa basis kode yang benar-benar epik yang masih dibangun dengan sangat cepat sambil dengan senang hati menggunakan templat dan banyak barang lainnya karena ECS, oleh alam, menciptakan arsitektur yang sangat terpisah dimana sistem hanya perlu tahu tentang database ECS dan biasanya hanya segelintir jenis komponen (kadang-kadang hanya satu) untuk melakukan hal mereka:
Desain, Desain, Desain
Dan jenis-jenis desain arsitektur yang terpisah pada tingkat manusia, konseptual ini lebih efektif dalam hal meminimalkan waktu kompilasi daripada teknik apa pun yang saya eksplorasi di atas ketika basis kode Anda tumbuh dan tumbuh dan tumbuh, karena pertumbuhan itu tidak sesuai dengan rata-rata Anda unit kompilasi mengalikan informasi jumlah yang diperlukan pada saat kompilasi dan waktu tautan untuk bekerja (sistem apa pun yang mengharuskan pengembang rata-rata Anda untuk memasukkan banyak hal untuk melakukan apa pun juga mengharuskan mereka dan bukan hanya kompiler untuk mengetahui banyak informasi untuk melakukan apa pun ). Ini juga memiliki lebih banyak manfaat daripada mengurangi waktu pembuatan dan mengurai tajuk, karena itu juga berarti pengembang Anda tidak perlu tahu banyak tentang sistem di luar apa yang diperlukan segera untuk melakukan sesuatu dengannya.
Jika, misalnya, Anda dapat menyewa pengembang fisika ahli untuk mengembangkan mesin fisika untuk game AAA Anda yang menjangkau jutaan LOC, dan ia dapat memulai dengan sangat cepat sambil mengetahui informasi minimum mutlak yang absolut sejauh hal-hal seperti jenis dan antarmuka yang tersedia serta konsep sistem Anda, maka itu akan secara alami diterjemahkan ke mengurangi jumlah informasi untuknya dan kompiler yang diperlukan untuk membangun mesin fisika, dan juga menerjemahkan ke pengurangan besar dalam waktu membangun sementara umumnya menyiratkan bahwa tidak ada yang menyerupai spaghetti di mana saja dalam sistem. Dan itulah yang saya sarankan untuk memprioritaskan di atas semua teknik lain ini: bagaimana Anda merancang sistem Anda. Melelahkan teknik lain akan menjadi icing di atas jika Anda melakukannya sementara, jika tidak,