Saya seorang pengembang game yang bercita-cita tinggi, saya bekerja pada game indie sesekali, dan untuk sementara waktu saya telah melakukan sesuatu yang tampak seperti praktik yang buruk pada awalnya, tetapi saya benar-benar ingin mendapatkan jawaban dari beberapa programmer yang berpengalaman di sini.
Katakanlah saya memiliki file bernama enumList.h
tempat saya mendeklarasikan semua enum yang ingin saya gunakan dalam game saya:
// enumList.h
enum materials_t { WOOD, STONE, ETC };
enum entity_t { PLAYER, MONSTER };
enum map_t { 2D, 3D };
// and so on.
// Tile.h
#include "enumList.h"
#include <vector>
class tile
{
// stuff
};
Gagasan utamanya adalah bahwa saya mendeklarasikan semua enum dalam game dalam 1 file , dan kemudian mengimpor file itu ketika saya perlu menggunakan enum tertentu darinya, daripada mendeklarasikannya dalam file di mana saya perlu menggunakannya. Saya melakukan ini karena itu membuat hal-hal bersih, saya dapat mengakses setiap enum di 1 tempat daripada membuka halaman hanya untuk mengakses satu enum.
Apakah ini praktik yang buruk dan dapatkah hal itu memengaruhi kinerja?
sumber
materials_t
file yang tidak berurusan dengan materi harus dibangun kembali.enumList.h
melayani sebagai koleksi#include
s untuk file-file tersebut. Ini memungkinkan file yang hanya memerlukan satu enum untuk mendapatkannya secara langsung, sambil menyediakan paket tunggal untuk apa pun yang benar-benar menginginkan semuanya.Jawaban:
Saya benar-benar berpikir itu adalah praktik yang buruk. Ketika kita mengukur kualitas kode, ada sesuatu yang kita sebut "granularity". Granularity Anda sangat menderita dengan meletakkan semua enum tersebut dalam satu file tunggal dan karenanya rawatan juga akan terganggu.
Saya akan memiliki satu file per enum untuk menemukannya dengan cepat dan mengelompokkannya dengan kode perilaku fungsi spesifik (misalnya bahan enum dalam folder di mana perilaku material dll.);
Anda mungkin berpikir itu bersih, tetapi kenyataannya tidak. Ini menggabungkan hal-hal yang tidak termasuk bersama fungsionalitas dan modul dan mengurangi modularitas aplikasi Anda. Tergantung pada ukuran basis kode Anda dan bagaimana modular Anda ingin kode Anda terstruktur, ini dapat berkembang menjadi masalah yang lebih besar dan kode / dependensi yang tidak bersih di bagian lain dari sistem Anda. Namun, jika Anda hanya menulis sistem monolitik yang kecil, ini tidak berlaku. Namun, saya tidak akan melakukannya seperti ini bahkan untuk sistem monolitik kecil.
sumber
Ya, ini praktik yang buruk, bukan karena kinerja tetapi karena pemeliharaan.
Itu membuat hal-hal "bersih" hanya di OCD "mengumpulkan hal-hal serupa" cara. Tapi itu sebenarnya bukan jenis "kebersihan" yang bermanfaat dan bagus.
Entitas kode harus dikelompokkan untuk memaksimalkan kohesi dan meminimalkan pemasangan , yang paling baik dicapai dengan mengelompokkannya ke dalam modul fungsional yang sebagian besar independen. Pengelompokan mereka berdasarkan kriteria teknis (seperti menyatukan semua enum) mencapai yang sebaliknya - ini memasangkan kode yang sama sekali tidak memiliki hubungan fungsional dan menempatkan enum yang mungkin hanya digunakan di satu tempat ke dalam file yang berbeda.
sumber
Nah, ini hanya data (bukan perilaku). Yang terburuk yang mungkin / secara teoritis terjadi adalah bahwa kode yang sama dimasukkan dan dikompilasi lebih dari sekali menghasilkan program yang relatif lebih besar.
Sangatlah mustahil untuk memasukkan hal-hal tersebut ke dalam siklus operasi Anda, mengingat tidak ada kode perilaku / prosedural di dalamnya (tidak ada loop, tidak ada jika, dll).
Suatu program (yang relatif) lebih besar hampir tidak dapat memengaruhi kinerja (kecepatan eksekusi) dan, bagaimanapun juga, hanyalah masalah teoretis jarak jauh. Sebagian besar (mungkin semua) kompiler mengelola termasuk dengan cara yang mencegah masalah seperti itu.
IMHO, kelebihan yang Anda dapatkan dengan satu file (kode lebih mudah dibaca dan lebih mudah dikelola) sebagian besar melebihi kelemahan yang mungkin ada.
sumber
Bagi saya itu semua tergantung pada ruang lingkup proyek Anda. Jika ada satu file dengan katakanlah 10 struct dan itu adalah satu-satunya yang pernah digunakan, saya akan sangat nyaman memiliki satu file .h untuk itu. Jika Anda memiliki beberapa jenis fungsi, katakanlah unit, ekonomi, bangunan, dll. Saya pasti akan membagi beberapa hal. Buat units.h di mana semua struct yang berhubungan dengan unit berada. Jika Anda ingin melakukan sesuatu dengan unit di suatu tempat Anda harus menyertakan units.h yakin, tetapi juga merupakan "pengidentifikasi" yang bagus bahwa sesuatu dengan unit mungkin dilakukan dalam file ini.
Lihatlah dengan cara ini, Anda tidak membeli supermarket karena Anda memerlukan sekaleng coke;)
sumber
Saya bukan pengembang C ++, jadi jawaban ini akan lebih umum untuk OOA & D:
Biasanya, objek kode harus dikelompokkan dalam hal relevansi fungsional, tidak harus dalam hal konstruksi spesifik bahasa. Pertanyaan utama ya-tidak yang harus selalu ditanyakan adalah, "akankah pembuat kode akhir diharapkan menggunakan sebagian besar atau semua objek yang mereka dapatkan saat mengonsumsi perpustakaan?" Jika ya, kelompokkan. Jika tidak, pertimbangkan untuk memecah objek kode dan menempatkannya lebih dekat ke objek lain yang membutuhkannya (sehingga meningkatkan kemungkinan bahwa konsumen akan membutuhkan semua yang mereka akses).
Konsep dasarnya adalah "kohesi tinggi"; anggota kode (dari metode kelas hingga kelas di namespace atau DLL, dan DLL sendiri) harus diatur sedemikian rupa sehingga pembuat kode dapat memasukkan semua yang mereka butuhkan, dan tidak ada yang tidak mereka lakukan. Ini membuat desain keseluruhan lebih toleran terhadap perubahan; hal-hal yang harus diubah bisa, tanpa memengaruhi objek kode lain yang tidak perlu diubah. Dalam banyak keadaan, ini juga membuat aplikasi lebih hemat memori; DLL dimuat seluruhnya ke dalam memori, terlepas dari berapa banyak instruksi yang pernah dieksekusi oleh proses. Oleh karena itu, merancang aplikasi "lean" perlu memperhatikan seberapa banyak kode yang ditarik ke dalam memori.
Konsep ini berlaku di hampir semua level organisasi kode, dengan berbagai tingkat dampak pada pemeliharaan, efisiensi memori, kinerja, kecepatan bangun, dll. Jika seorang koder perlu merujuk header / DLL yang ukurannya agak monolitik hanya untuk mengakses satu objek, yang tidak bergantung pada objek lain di DLL itu, maka penyertaan objek itu di DLL mungkin harus dipikirkan kembali. Namun mungkin juga untuk melangkah terlalu jauh; DLL untuk setiap kelas adalah ide yang buruk, karena memperlambat kecepatan pembuatan (lebih banyak DLL untuk dibangun kembali dengan overhead terkait) dan menjadikan versi sebagai mimpi buruk.
Contoh kasus: jika penggunaan perpustakaan kode Anda di dunia nyata melibatkan sebagian besar atau semua enumerasi yang Anda masukkan ke dalam file "enumerations.h" tunggal ini, maka tentu saja kelompokkan mereka bersama-sama; Anda akan tahu di mana mencarinya untuk menemukan mereka. Tetapi jika pengkode pengkonsumsi Anda mungkin hanya membutuhkan satu atau dua dari selusin enumerasi yang Anda berikan di header, daripada saya akan mendorong Anda untuk menempatkan mereka ke perpustakaan yang terpisah dan menjadikannya ketergantungan dari yang lebih besar dengan sisa enumerasi . Itu memungkinkan coders Anda mendapatkan hanya satu atau dua yang mereka inginkan tanpa menautkan ke DLL yang lebih monolitik.
sumber
Hal semacam ini menjadi masalah ketika Anda memiliki beberapa pengembang bekerja pada basis kode yang sama.
Saya tentu saja melihat file global serupa menjadi nexus untuk menggabungkan tabrakan dan segala macam kesedihan pada proyek (lebih besar).
Namun, jika Anda adalah satu-satunya yang mengerjakan proyek, maka Anda harus melakukan apa pun yang paling Anda sukai, dan hanya mengadopsi "praktik terbaik" jika Anda memahami (dan setuju dengan) motivasi di baliknya.
Lebih baik membuat beberapa kesalahan dan belajar darinya daripada mengambil risiko terjebak dengan praktik pemrograman kultus kargo selama sisa hidup Anda.
sumber
Ya, itu adalah praktik buruk untuk melakukannya pada proyek besar. CIUMAN.
Rekan kerja muda mengganti nama variabel sederhana dalam file inti .h dan 100 insinyur menunggu 45 menit untuk semua file mereka dibangun kembali, yang memengaruhi kinerja semua orang. ;)
Semua proyek dimulai dari kecil, balon selama bertahun-tahun, dan kami mengutuk mereka yang mengambil jalan pintas awal untuk menciptakan utang teknis. Praktik terbaik, jaga agar konten global .h terbatas pada apa yang seharusnya bersifat global.
sumber
Dalam hal ini, saya akan mengatakan jawaban yang ideal adalah bahwa itu tergantung pada bagaimana enum dikonsumsi, tetapi dalam sebagian besar keadaan mungkin yang terbaik untuk mendefinisikan semua enum secara terpisah, tetapi jika salah satu dari mereka sudah digabungkan dengan desain, Anda harus memberikan sarana untuk memperkenalkan enum yang digabungkan tersebut secara kolektif. Akibatnya, Anda memiliki toleransi kopling hingga jumlah kopling yang disengaja sudah ada, tetapi tidak lebih.
Mempertimbangkan hal ini, solusi yang paling fleksibel kemungkinan untuk mendefinisikan masing-masing enum dalam file yang terpisah, tetapi menyediakan paket yang digabungkan ketika masuk akal untuk melakukannya (sebagaimana ditentukan oleh penggunaan yang dimaksud dari enum yang terlibat).
Menentukan semua enumerasi Anda di file yang sama memasangkannya bersama-sama, dan dengan ekstensi menyebabkan kode apa pun yang bergantung pada satu atau lebih enum bergantung pada semua enum, terlepas dari apakah kode tersebut benar-benar menggunakan enum lain.
renderMap()
lebih suka hanya tahu tentangmap_t
, karena jika tidak ada perubahan pada yang lain akan mempengaruhinya meskipun tidak benar-benar berinteraksi dengan yang lain.Namun, dalam kasus di mana komponen sudah digabungkan bersama, menyediakan beberapa enum dalam satu paket dapat dengan mudah memberikan kejelasan dan kesederhanaan tambahan, asalkan ada alasan logis yang jelas untuk enum yang akan digabungkan, bahwa penggunaan enum tersebut juga digabungkan, dan bahwa menyediakannya juga tidak memperkenalkan sambungan tambahan.
Dalam hal ini, tidak ada koneksi logis langsung antara tipe entitas dan tipe material (dengan asumsi bahwa entitas tidak terbuat dari salah satu material yang ditentukan). Namun, jika kami memiliki kasus di mana, misalnya, satu enum secara eksplisit tergantung pada yang lain, maka masuk akal untuk menyediakan satu paket berisi semua enum yang digabungkan (serta komponen yang digabungkan lainnya), sehingga penggandengan dapat terisolasi ke paket itu sebanyak mungkin.
Tetapi sayang ... bahkan ketika dua enum secara intrinsik digabungkan bersama, bahkan jika itu sekuat "enum kedua menyediakan subkategori untuk enum pertama", mungkin masih ada waktu di mana hanya satu enum yang diperlukan.
Oleh karena itu, karena kita tahu keduanya bahwa selalu ada situasi di mana mendefinisikan beberapa enumerasi dalam satu file dapat menambahkan kopling yang tidak perlu, dan bahwa menyediakan enum yang digabungkan dalam satu paket dapat memperjelas penggunaan yang dimaksudkan dan memungkinkan kita untuk mengisolasi kode kopling yang sebenarnya itu sendiri sebagai Sebisa mungkin, solusi ideal adalah mendefinisikan setiap enumerasi secara terpisah, dan menyediakan paket bersama untuk enum yang dimaksudkan untuk sering digunakan bersama. Satu-satunya enum yang didefinisikan dalam file yang sama akan menjadi yang secara intrinsik terhubung bersama, sehingga penggunaan salah satu mengharuskan penggunaan yang lain juga.
sumber