Saya seorang insinyur listrik dan saya tidak tahu apa yang saya lakukan. Harap simpan pengelola kode saya di masa mendatang.
Baru-baru ini saya telah mengerjakan sejumlah program yang lebih kecil (dalam C #) yang fungsinya secara logis "prosedural". Sebagai contoh, salah satunya adalah program yang mengumpulkan informasi dari database yang berbeda, menggunakan informasi itu untuk menghasilkan semacam halaman ringkasan, mencetaknya, dan kemudian keluar.
Logika yang diperlukan untuk semua itu adalah sekitar 2000 baris. Saya tentu saja tidak ingin memasukkan semua itu dalam satu main()
dan kemudian "membersihkannya" dengan #region
s seperti yang dilakukan beberapa pengembang sebelumnya (bergidik).
Berikut adalah beberapa hal yang sudah saya coba tanpa banyak kepuasan:
Buat utilitas statis untuk setiap fungsionalitas kasar, misalnya DatabaseInfoGetter, SummaryPageGenerator, dan PrintUtility. Membuat fungsi utama terlihat seperti:
int main()
{
var thisThing = DatabaseInfoGetter.GetThis();
var thatThing = DatabaseInfoGetter.GetThat();
var summary = SummaryPageGenerator.GeneratePage(thisThing, thatThing);
PrintUtility.Print(summary);
}
Untuk satu program saya bahkan pergi dengan antarmuka
int main()
{
/* pardon the psuedocode */
List<Function> toDoList = new List<Function>();
toDoList.Add(new DatabaseInfoGetter(serverUrl));
toDoList.Add(new SummaryPageGenerator());
toDoList.Add(new PrintUtility());
foreach (Function f in toDoList)
f.Do();
}
Semua ini terasa benar. Ketika kode menjadi lebih panjang, kedua pendekatan ini mulai menjadi jelek.
Apa cara yang baik untuk menyusun hal-hal seperti ini?
sumber
Jawaban:
Karena Anda bukan programmer profesional, saya akan merekomendasikan untuk tetap berpegang pada kesederhanaan. Ini akan menjadi BANYAK lebih mudah bagi programmer untuk mengambil kode prosedural Anda, termodulasi dan membuatnya OO nanti, daripada bagi mereka untuk memperbaiki program OO yang ditulis dengan buruk. Jika Anda tidak berpengalaman, dimungkinkan untuk membuat program OO yang dapat berubah menjadi kekacauan yang tidak suci yang tidak akan membantu Anda atau siapa pun yang datang setelah Anda.
Saya pikir insting pertama Anda, kode "benda-hal ini" dalam contoh pertama adalah jalur yang benar. Jelas dan jelas apa yang ingin Anda lakukan. Jangan terlalu khawatir tentang efisiensi kode, kejelasan jauh lebih penting.
Jika segmen kode terlalu panjang, pecah menjadi potongan-potongan berukuran gigitan, masing-masing memiliki fungsinya sendiri. Jika terlalu pendek, pertimbangkan untuk menggunakan lebih sedikit modul dan membuat lebih banyak sambungan.
---- Catatan tambahan: Perangkap Desain OO
Bekerja dengan sukses dengan pemrograman OO bisa rumit. Bahkan ada beberapa orang yang menganggap seluruh model cacat. Ada buku yang sangat bagus yang saya gunakan ketika pertama kali belajar pemrograman OO bernama Thinking in Java (sekarang dalam edisi ke-4). Penulis yang sama memiliki buku yang sesuai untuk C ++. Sebenarnya ada pertanyaan lain pada Programmer yang berurusan dengan perangkap umum dalam pemrograman berorientasi objek .
Beberapa perangkap sangat canggih, tetapi ada banyak cara untuk menciptakan masalah dengan cara yang sangat mendasar. Sebagai contoh, beberapa tahun yang lalu ada seorang magang di perusahaan saya yang menulis versi pertama dari beberapa perangkat lunak yang saya warisi dan dia membuat antarmuka untuk semua yang mungkinsuatu hari nanti memiliki beberapa implementasi. Tentu saja, dalam 98% kasus hanya ada satu implementasi tunggal, jadi kode itu dimuat dengan antarmuka yang tidak digunakan yang membuat debugging sangat menjengkelkan karena Anda tidak dapat mundur melalui panggilan antarmuka, sehingga Anda akhirnya harus melakukan pencarian teks untuk implementasi (meskipun sekarang saya menggunakan IntelliJ memiliki fitur "Tampilkan Semua Implementasi", tetapi pada hari saya tidak memilikinya). Aturannya di sini sama dengan pemrograman prosedural: selalu hardcode satu hal. Hanya ketika Anda memiliki dua hal atau lebih, buat abstraksi.
Jenis kesalahan desain yang serupa dapat ditemukan di Java Swing API. Mereka menggunakan model terbitkan-berlangganan untuk sistem menu Swing. Ini membuat membuat dan men-debug menu di Swing menjadi mimpi buruk yang lengkap. Ironinya adalah itu sama sekali tidak ada gunanya. Hampir tidak pernah ada situasi di mana beberapa fungsi perlu "berlangganan" ke klik menu. Juga, terbitkan-berlangganan adalah macet total di sana karena sistem menu biasanya selalu digunakan. Ini tidak seperti fungsi berlangganan dan kemudian berhenti berlangganan secara acak. Fakta bahwa pengembang "profesional" di Sun membuat kesalahan seperti ini hanya menunjukkan betapa mudahnya bahkan bagi para profesional untuk membuat kesalahan besar dalam desain OO.
Saya adalah pengembang yang sangat ahli dengan pengalaman puluhan tahun dalam pemrograman OO, tetapi bahkan saya akan menjadi orang pertama yang mengakui ada banyak yang tidak saya ketahui dan bahkan sekarang saya sangat berhati-hati dalam menggunakan banyak OO. Saya biasa mendengarkan ceramah panjang dari seorang rekan kerja yang adalah seorang fanatik OO tentang bagaimana melakukan desain tertentu. Dia benar-benar tahu apa yang dia lakukan, tetapi sejujurnya saya kesulitan memahami program-programnya karena mereka memiliki model desain yang begitu canggih.
sumber
Pendekatan pertama baik-baik saja. Dalam bahasa prosedural, seperti C, pendekatan standar adalah untuk membagi fungsionalitas menjadi ruang nama - menggunakan kelas statis seperti
DatabaseInfoGetter
pada dasarnya adalah hal yang sama. Jelas pendekatan ini mengarah pada kode yang lebih sederhana, lebih modular dan lebih mudah dibaca / dipelihara daripada mendorong semuanya menjadi satu kelas, bahkan jika semuanya dipecah menjadi metode.Omong-omong, cobalah membatasi metode untuk melakukan tindakan sesedikit mungkin. Beberapa programmer lebih suka sedikit kurang granularity, tetapi metode besar selalu dianggap berbahaya.
Jika Anda masih berjuang dengan kompleksitas, kemungkinan besar Anda perlu memecah program Anda lebih jauh. Buat lebih banyak level dalam hierarki - mungkin
DatabaseInfoGetter
perlu merujuk beberapa kelas lain sepertiProductTableEntry
atau sesuatu. Anda sedang menulis kode prosedural tetapi ingat, Anda ADALAH menggunakan C #, dan OOP memberi Anda banyak alat untuk mengurangi kerumitan, misalnya:Juga, berhati-hatilah dengan kelas statis. Kelas basis data adalah kandidat yang baik .. selama Anda biasanya memiliki satu basis data .. Anda mendapatkan idenya.
Pada akhirnya jika Anda berpikir dalam fungsi matematika dan C # tidak sesuai dengan gaya Anda, coba sesuatu seperti Scala, Haskell, dll. Mereka juga keren.
sumber
Saya merespons terlambat 4 tahun tetapi ketika Anda mencoba melakukan hal-hal prosedural dalam bahasa OO maka Anda bekerja pada antipattern. Itu bukan sesuatu yang harus Anda lakukan! Saya menemukan sebuah blog yang membahas antipattern ini dan menunjukkan solusi untuknya, tetapi membutuhkan banyak refactoring dan perubahan pola pikir. Lihat kode prosedural dalam kode Berorientasi Objek untuk lebih jelasnya.
Seperti yang Anda sebutkan "ini" dan "itu", Anda pada dasarnya menyarankan bahwa Anda memiliki dua kelas yang berbeda. A Kelas ini (nama buruk!) Dan kelas itu. Dan misalnya Anda bisa menerjemahkan ini:
dalam hal ini:
Sekarang, akan menarik untuk melihat 2.000+ baris kode prosedural dan menentukan bagaimana berbagai bagian dapat dikelompokkan bersama dalam kelas yang terpisah dan memindahkan berbagai prosedur ke dalam kelas tersebut.
Setiap kelas harus sederhana dan fokus hanya pada melakukan satu hal. Dan sepertinya bagi saya bahwa beberapa bagian dari kode sudah berurusan dengan kacamata super, yang sebenarnya terlalu besar untuk berguna. DatabaseInfoGetter, misalnya, terdengar membingungkan. Apa itu? Kedengarannya terlalu generik. Namun SummaryPageGenerator sangat spesifik! Dan PrintUtility menjadi generik lagi.
Jadi, untuk memulai, Anda harus menghindari nama generik untuk kelas Anda dan mulai menggunakan nama yang lebih spesifik. Kelas PrintUtility, misalnya, akan lebih berupa kelas Print dengan kelas Header, kelas Footer, kelas TextBlock, kelas gambar dan mungkin beberapa cara untuk menunjukkan bagaimana mereka akan mengalir dalam cetakan itu sendiri. Semua ini bisa di PrintUtility namespace , meskipun.
Untuk database, cerita serupa. Bahkan jika Anda menggunakan Kerangka Entitas untuk akses basis data, Anda harus membuatnya terbatas pada hal-hal yang Anda gunakan, dan membaginya menjadi grup logis.
Tapi saya ingin tahu apakah Anda masih berurusan dengan masalah ini setelah 4 tahun. Jika demikian, maka itu adalah pola pikir yang perlu diubah dari "konsep prosedural" dan menjadi "konsep berorientasi objek". Yang menantang jika Anda tidak memiliki pengalaman ...
sumber
Saya berpendapat, Anda harus mengubah kode Anda sehingga Sederhana, Konsisten, dan Mudah Dibaca.
Saya menulis beberapa posting blog tentang topik ini, dan percayalah, mereka mudah dimengerti: Apa itu kode yang baik
Sederhana: Sama seperti papan sirkuit berisi bagian yang berbeda, masing-masing dengan tanggung jawab. Kode harus dibagi menjadi bagian-bagian yang lebih kecil dan lebih sederhana.
Konsisten: Gunakan patters, standar untuk penamaan elemen dan hal-hal. Anda menyukai alat yang bekerja dengan cara yang sama sepanjang waktu dan Anda ingin tahu di mana menemukannya. Sama dengan kode.
Dapat dibaca: Jangan menggunakan akronim kecuali mereka digunakan secara luas dan dikenal dalam domain yang ditargetkan oleh perangkat lunak (mattnz), lebih suka nama yang diucapkan yang jelas dan mudah dipahami.
sumber