Bagaimana Anda memutuskan di mana fungsi seharusnya berada dalam proyek skala besar?

8

Dalam situasi pengembangan saya saat ini, kami memiliki banyak DLL, executable, dan perpustakaan statis. Bagaimana Anda memutuskan apa yang harus masuk ke DLL? Apa yang harus dimasukkan ke dalam executable? Mengapa memiliki fungsi yang terpisah di berbagai file yang dapat dieksekusi? Saya berharap jawabannya akan singkat, tetapi tampaknya ini adalah topik yang banyak dibahas.

Bagaimana Anda memutuskan di mana fungsi berada di proyek skala besar (lebih dari satu file yang dapat dieksekusi)? Saya mengharapkan jawaban mulai dari, "Desain Bagus" hingga "Modularitas" hingga "Apa pun yang dimasukkan manajemen dalam dokumen persyaratan".

wfoster
sumber

Jawaban:

13

Memilih antara perpustakaan dan file yang dapat dieksekusi relatif sederhana: apakah masuk akal untuk mengeksekusi kode yang ingin Anda masukkan ke dalam executable sebagai program mandiri? Jika tidak, mungkin harus perpustakaan. Secara umum, saya lebih suka lapisan tipis yang dapat dieksekusi di atas sebanyak mungkin pustaka yang diperlukan, karena hal itu membuatnya lebih mudah untuk menggunakan kembali pustaka backend nanti dan mereka tidak terikat pada program tertentu.

Sejauh memutuskan bagaimana membagi kode Anda antara pustaka, Anda mungkin menemukan artikel Paman Bob Martin tentang granularity berguna.

Di dalamnya ia berbicara tentang struktur OO dan mendefinisikan beberapa prinsip yang dapat membantu Anda mengemas kode Anda dengan tepat. Ini juga dibahas secara lebih rinci dalam bukunya, Prinsip Agile, Pola, dan Praktek di C # .

Saya akan meringkas prinsip-prinsip di bawah ini:

Prinsip Penggunaan Kembali / Rilis Kesetaraan (REP)

Granule reuse adalah granul rilis. Hanya komponen yang dilepaskan melalui sistem pelacakan yang dapat digunakan kembali secara efektif. Butiran ini adalah paket.

Paman Bob mendefinisikan penggunaan kembali sebagai dapat secara statis atau dinamis menghubungkan perpustakaan yang digunakan kembali ke programnya dan tidak pernah harus melihat kode sumbernya. Ketika versi baru perpustakaan dirilis, ia bisa mengintegrasikannya ke dalam sistemnya.

Memperlakukan perpustakaan dengan cara ini hanya mendorong menjaga hal-hal terkait bersama dalam paket yang sama. Jika tidak, konsumen perpustakaan mungkin harus memutakhirkan ke versi baru tanpa alasan atau ketinggalan beberapa versi.

Prinsip Penggunaan Kembali Bersama (CRP)

Kelas-kelas dalam sebuah paket digunakan kembali bersama-sama. Jika Anda menggunakan kembali salah satu kelas dalam satu paket, Anda menggunakan kembali semuanya.

Prinsip ini mendukung yang di atas. Jika Anda memiliki kelas dalam paket yang sama yang tidak terkait satu sama lain, Anda mungkin memaksa pengguna perpustakaan Anda untuk memutakhirkan yang tidak perlu.

Prinsip Penutupan Umum (CCP)

Kelas-kelas dalam sebuah paket harus ditutup terhadap jenis perubahan yang sama. Perubahan yang memengaruhi paket memengaruhi semua kelas dalam paket itu.

Prinsip ini berbicara tentang pemeliharaan. Idenya di sini adalah mengelompokkan kelas-kelas berdasarkan pada bagaimana mereka mungkin perlu berubah. Dengan begitu perubahan Anda dapat dilokalkan ke satu bagian aplikasi dan tidak tersebar di mana-mana.

Prinsip Ketergantungan Acyclic (ACP)

Struktur dependensi antar paket harus menjadi Directed Acyclic Graph (DAG). Artinya, tidak boleh ada siklus dalam struktur ketergantungan.

Melarang dependensi siklik memungkinkan setiap paket untuk dikembangkan secara independen dan "dirilis" ke seluruh perusahaan ketika perubahan baru siap. Dengan cara ini Anda tidak berakhir dengan dua tim menemui jalan buntu, menunggu satu sama lain untuk menyelesaikan beberapa pekerjaan.

Adam Lear
sumber
2

Apa yang akan membuatnya lebih mudah untuk mempertahankan kode dalam jangka panjang? Jika Anda memiliki fungsi yang tidak terkait dalam komponen yang sama (yaitu, dll, exe, unit yang dikompilasi), dan Anda harus mengubah satu fungsi, apakah itu akan merusak yang lain? Saat Anda melakukan perubahan pada suatu komponen, Anda harus menguji ulang semua komponen hilir tergantung pada SEMUA fungsi dalam komponen itu. Jika Anda membatasi fungsionalitas dalam setiap komponen, mengubah masing-masing komponen akan lebih berisiko.

Selain itu, Dengan memfokuskan komponen pada sejumlah kecil fungsi yang terkait erat, Anda akan memiliki waktu yang jauh lebih mudah untuk membuktikan bahwa satu komponen berperilaku seperti seharusnya.

Matthew Flynn
sumber
Selalu pikirkan skenario "DLL Neraka". Itu seperti yang dikatakan Pak Flynn, pikirkan apa yang terjadi ketika sesuatu berubah. Ketahuilah dependensi Anda dengan sangat baik dan pastikan Anda dapat menutupi skenario pemasangan tanpa rasa sakit bagi pengguna akhir.
NoChance
2

Cara sederhana untuk mendekati jawaban adalah dengan mengenali bahwa "DLL" adalah singkatan dari "dynamic-link library," dan istilah kuncinya adalah "library."

Apa yang Anda inginkan di perpustakaan normal? Buku bagus yang akan dibagikan oleh banyak pembaca (pengguna); barang-barang berguna yang mengumpulkan debu sampai direferensikan oleh pembaca (pengguna) untuk menjawab pertanyaan kritis pada saat yang mungkin putus asa; dan sumber daya yang menghubungkan pembaca (pengguna) dengan sumber daya lain. Pustaka kode serupa. Kami menyimpan hal-hal seperti kode yang sering dibagikan, modul referensi khusus atau bernilai tinggi, dan sumber daya kerangka arsitektur di dalamnya. Pustaka perangkat lunak dapat direpresentasikan dalam beberapa jenis artefak kode, seperti skrip, pustaka statis, pustaka dinamis, komponen, dan file sumber daya.

Secara umum, saya sarankan agar modul yang dapat dieksekusi Anda bertindak seperti skrip. Mereka dengan jelas menguraikan dan mengelola struktur dan aliran utama sistem Anda, tetapi meminta sumber daya dari perpustakaan Anda untuk menangani detail seluk beluk. Saya menemukan pendekatan ini lebih baik daripada memperkeruh logika tingkat tinggi dengan masalah implementasi tingkat rendah yang membingungkan dan terlalu khusus dan teknis.

Ketika mempertimbangkan bagaimana mengalokasikan kode Anda antara executable dan library, Anda perlu mempertimbangkan desain logis dan desain fisik.

Dalam sistem berorientasi objek, misalnya, penting untuk secara logis mengatur kode Anda untuk menetapkan tanggung jawab yang benar ke metode yang tepat di kelas yang tepat. Ini adalah bagian dari desain solusi logis. Desain logis Anda harus jelas, bersih, dan ramping dan harus dinyatakan dalam terminologi yang berhubungan baik dengan domain pengguna Anda.

Ketika Anda berencana untuk benar-benar menginstal sistem Anda di situs pengguna, Anda mungkin khawatir untuk membuat desain fisik yang menentukan bagaimana Anda akan menggabungkan kode Anda ke dalam satu set objek sumber daya perangkat lunak yang mudah digunakan (biasanya file) yang dapat dengan mudah dicampur dan dicocokkan. untuk kebutuhan sistem target tertentu. Menentukan sumber daya mana yang termasuk dalam paket penempatan yang umumnya melibatkan pertimbangan desain fisik tertentu yang tidak ada kaitannya dengan desain logis. Misalnya, Anda mungkin ingin menukar pustaka pemrosesan file gambar tertentu bergantung pada pelanggan mana yang akan menerima set objek penempatan tertentu.

Dalam praktiknya, Anda akan menemukan bahwa desain logis yang baik biasanya mengarah pada desain fisik yang baik.

Sebagai rangkuman, prinsip yang paling penting adalah pengemasan yang cerdas. Dengan mengatur materi kode Anda ke dalam pustaka yang sangat terkait, Anda berakhir dengan artefak kode yang dapat digunakan yang dapat Anda gunakan kembali dengan mudah, berpindah-pindah, atau memberikan.

John Tobler
sumber