C # namespace dan konvensi penamaan kelas untuk perpustakaan

26

Saya sedang membangun perpustakaan dengan berbagai fungsi utilitas kecil di C #, dan mencoba untuk memutuskan pada namespace dan konvensi penamaan kelas. Organisasi saya saat ini seperti ini:

Company
Company.TextUtils
    public class TextUtils {...}
Company.MathsUtils
    public class MathsUtils {...}
    public class ArbitraryPrecisionNumber {...}
    public class MathsNotation {...}
Company.SIUnits
    public enum SISuffixes {...}
    public class SIUnits {...}

Apakah ini cara yang baik untuk mengatur namespace dan kelas, atau apakah ada cara yang lebih baik? Secara khusus sepertinya memiliki nama yang sama di namespace dan nama kelas (misalnya Company.TextUtilsnamespace dan TextUtilskelas) hanyalah duplikasi dan menunjukkan bahwa skema tersebut bisa lebih baik.

pengguna
sumber
5
Pedoman Microsoft merekomendasikan nama tunggal untuk enum (jadi SISuffixalih-alih SISuffixes), dan saya pikir singular lebih baik dibaca. Suffix.A terbaca sebagai "suffix A". Juga, saya biasanya menghindari pengulangan nama dari tingkat atas dalam hierarki. Itu, alih-alih Company.SIUnits.SISuffixes, saya condong ke arah Company.SI.SuffixdanCompany.SI.Unit
Harrison Paine
2
@richzilla thecodelesscode.com/case/220
Tin Man

Jawaban:

9

Sangat sulit untuk menentukan seberapa efektif strategi penamaan Anda dalam isolasi dari sisa kode Anda.

Namespace harus memberikan beberapa ide di mana ia cocok dengan struktur luas basis kode Anda, dan nama kelas biasanya menggambarkan jenis fungsi atau konsep yang diwakilinya dalam area itu.

Selain peringatan, dalam contoh spesifik Anda, jika Anda cenderung memiliki lebih banyak kelas tipe 'Util', saya akan mempertimbangkan untuk menempatkannya di bawah Company.Utils.Mathsdll. Dengan begitu, jika Anda perlu menambahkan fungsionalitas yang umum untuk beberapa area utilitas, Anda sudah memiliki lokasi alami untuk itu.

richzilla
sumber
1
Itu terdengar seperti ide yang bagus. Berhentilah khawatir terlalu banyak, hanya lob itu semua ke "Perusahaan. Gunakan".
pengguna
30

Ada dokumen bagus yang berisi banyak aturan yang harus Anda ikuti agar sejalan dengan Microsoft: Framework Design Guidelines .

Satu hal yang harus Anda ubah: Jangan beri nama kelas sebagai namespace mereka. Itu akan menyebabkan mixup kompilator. Hanya saja, jangan. Temukan nama yang lebih baik untuk kelas namespace.

tidak ada
sumber
3
Tautan langsung ke pedoman namespaces: msdn.microsoft.com/en-us/library/ms229026(v=vs.110).aspx
Pagotti
1
Yang secara kebetulan atau tidak juga merupakan nama yang sama dari sebuah buku hebat tentang masalah ini, juga ditulis oleh orang-orang Microsoft yang berpartisipasi dalam pembuatan kerangka kerja DotNet, dengan beberapa komentar tentang apa yang mereka lakukan dengan benar dan di mana mereka mendapatkan kesalahan. Layak dibaca: amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/…
Machado
@nvoigt, bisakah Anda mengedit jawaban Anda untuk menambahkan kutipan dari tautan yang diberikan teman kami oleh Pagotti: " JANGAN gunakan nama yang sama untuk namespace dan tipe dalam namespace itu. Misalnya, jangan gunakan Debug sebagai nama namespace dan kemudian juga menyediakan kelas bernama Debug di namespace yang sama. Beberapa kompiler membutuhkan tipe seperti itu untuk sepenuhnya memenuhi syarat. "
Machado
2
Peringatan: Kadang-kadang nama Produk lebih baik daripada menggunakan nama Perusahaan. Berada dalam beberapa skenario di mana perusahaan dibeli dan kami harus menghasilkan ruang nama baru di seluruh papan dan dirilis ulang. Saya pikir ini sangat kecil tetapi ingin menunjukkannya.
Jon Raynor
1
Pedoman desain kerangka kerja Microsoft sangat dipertanyakan, berisi pernyataan salah tentang cara kerja .NET, dan sangat sering tidak diikuti oleh Microsoft sendiri. Pedoman penamaan mereka baik, tetapi saya akan menghindari menghubungkan keseluruhan panduan dengan pernyataan bahwa "Anda harus mengikuti" mereka.
Carl Leth
6

Sudah lama sejak saya bekerja dengan C # atau ekosistem .NET jadi saya tidak bisa mengatakan apa praktik terbaik yang disarankan saat ini. Saya akan merekomendasikan perubahan pada nama Anda seperti ini:

Company
Company.Text
    public class TextUtils {...}
Company.Math
    public class MathUtils {...}
    public class ArbitraryPrecisionNumber {...}
    public class MathsNotation {...}
Company.SI
    public enum SISuffixes {...}
    public class SIUnits {...}

Apa yang saya lakukan di sini adalah menghapus "Utils" dari nama namespace. Saya pikir "Util" tidak boleh dalam namespace, karena Company.Textnamespace suatu hari nanti bisa berisi kelas yang bukan kelas utilitas teks. The Company.Mathnamespace sudah mengandung ArbitraryPrecisionNumberyang Tampaknya tidak menjadi "utilitas".

Menghapus "Util" dari namespace juga menghapus semua kebingungan yang mungkin timbul dengan memiliki dua hal dengan nama yang sama (seperti yang disebutkan dalam jawaban Robert: /software//a/340440/13156 )

Cara lain Anda dapat mengatur kode:

Company
Company.Util
    public class TextUtils {...}
    public class MathUtils {...}
Company.Math
    public class ArbitraryPrecisionNumber {...}
    public class MathsNotation {...}
Company.SI
    public enum SISuffixes {...}
    public class SIUnits {...}

Dalam hal ini, semua kelas utilitas berada di namespace yang sama. Tidak ada lagi Company.Textnamespace karena satu-satunya yang ada adalah kelas utilitas.

Secara pribadi, saya menemukan opsi pertama sedikit lebih jelas.

FrustratedWithFormsDesigner
sumber
4

Menggunakan nama yang sama untuk namespace dan kelas di dalamnya bermasalah.

  • Jika namespace berisi lebih dari satu kelas, mengapa kelas lain diletakkan di sana? rasanya tidak benar, karena tujuan dari nama namespace adalah untuk menggambarkan semua kelas di dalamnya, bukan hanya satu. Misalnya, jika Anda memiliki JsonSerialization, BinarySerializationdan XmlSerializationkelas di namespace, apakah masuk akal untuk memberi nama namespace Anda XmlSerialization?

    Apa yang biasanya terjadi adalah bahwa karena ekstraksi kelas dari namespace yang ada, atau gabungan antara beberapa kelas atau reorganisasi lainnya, Anda menemukan diri Anda dengan namespace yang mengandung kelas utama ; secara progresif, kelas-kelas minor ditempatkan di sana karena mereka sedikit terkait dengan kelas asli. Misalnya, namespace LogParserdapat berisi satu kelas LogParser, dan kemudian seseorang meletakkannya LogConverter, karena itu cukup terkait dengan parser, lalu LogSearcher, dll. Masalahnya di sini adalah bahwa nama namespace tidak berubah: segera setelah LogConverterditambahkan, the nama seharusnya diubah menjadi LogsProcessingatau, sederhananya Logs,.

  • Jika namespace hanya berisi satu kelas, itu mungkin merupakan tanda masalah dalam organisasi kode.

    Walaupun saya telah melihat beberapa kali situasi di mana satu kelas dengan prinsip SOLID yang tepat sangat berbeda dari apa pun dalam basis kode dan oleh karena itu dimasukkan ke dalam namespace khusus, kasus seperti itu jarang terjadi. Lebih sering, ini merupakan indikasi masalah. Demikian pula, tidak ada yang mencegah Anda memiliki kelas yang berisi metode tunggal, tetapi lebih sering daripada tidak, kelas tersebut akan menunjukkan masalah.

    Bahkan jika namespace Anda hanya berisi satu kelas, biasanya ada cara untuk lebih spesifik ketika memberi nama kelas, dan lebih umum ketika memberi nama namespace. Bayangkan aplikasi yang, antara lain, pada saat tertentu harus mengkonversi file yang ditulis dalam format ABC ke format DEF. Konversi tidak memerlukan deserialisasi / serialisasi ke / dari objek bisnis, dan dilakukan dengan menerapkan banyak ekspresi reguler yang cukup pendek untuk dimasukkan ke dalam kelas konversi itu sendiri yang disebutAbcToDefConverter. Semua logika konversi membutuhkan sekitar 80 LLOC dalam sekitar sepuluh metode yang saling tergantung — sepertinya situasi di mana sama sekali tidak perlu untuk memecah kelas yang ada, atau membuat kelas tambahan. Karena bagian aplikasi yang tersisa tidak ada hubungannya dengan konversi, kelas tidak dapat dikelompokkan dengan kelas lain di ruang nama yang ada. Jadi seseorang menciptakan namespace yang disebut AbcToDefConverter. Meskipun tidak ada yang salah secara inheren dalam hal itu, orang juga bisa menggunakan nama yang lebih umum, seperti Converters. Dalam bahasa seperti Python, di mana nama yang lebih pendek lebih disukai dan pengulangan dilemparkan, itu bahkan menjadi converters.Abc_To_Def.

Oleh karena itu, gunakan nama yang berbeda untuk ruang nama daripada kelas yang dikandungnya. Nama kelas harus menunjukkan apa yang dilakukan kelas, sementara nama namespace harus menyoroti apa yang umum di semua kelas yang dimasukkan ke dalamnya.


By the way, kelas utilitas secara alami salah: alih-alih mengandung sesuatu yang spesifik, seperti aritmatika presisi sewenang-wenang, mereka lebih berisi segala sesuatu yang belum menemukan jalannya di kelas lain . Ini hanyalah penamaan yang buruk, sama seperti Miscellaneousdirektori di desktop — sesuatu yang menunjukkan kurangnya organisasi.

Penamaan ada karena suatu alasan: untuk membuat hidup Anda lebih mudah ketika Anda perlu menemukan barang nanti. Anda tahu bahwa jika Anda perlu menggambar bagan, Anda dapat mencoba mencari "bagan" atau "plot". Saat Anda perlu mengubah cara aplikasi membuat faktur, Anda akan mencari "faktur" atau "tagihan". Demikian pula, coba bayangkan sebuah kasus di mana Anda akan berkata pada diri sendiri: "hm, fitur ini mungkin bisa ditemukan di misc" Saya tidak bisa.

Lihatlah .NET Framework. Bukankah sebagian besar dari kelas utilitas kelas? Maksud saya, ada beberapa hal yang berkaitan dengan domain bisnis. Jika saya bekerja pada aplikasi keuangan, atau situs web e-commerce, atau platform pendidikan generasi berikutnya, membuat serialisasi XML atau membaca file atau melakukan query SQL atau melakukan transaksi adalah semua hal yang bermanfaat. Namun, mereka tidak dipanggil UtilitySerializationatau UtilityTransaction, dan mereka tidak ada dalam Utilitynamespace. Mereka memiliki nama yang tepat, yang memungkinkan (dan mudah, terima kasih. Pengembang NET!) Untuk menemukannya ketika saya membutuhkannya.

Hal yang sama datang untuk Anda kelas Anda sering menggunakan kembali dalam aplikasi Anda. Mereka bukan kelas utilitas. Mereka adalah kelas-kelas yang melakukan hal-hal tertentu, dan hal-hal yang mereka lakukan sebenarnya haruslah nama-nama kelas tersebut.

Bayangkan Anda membuat beberapa kode yang berkaitan dengan unit dan konversi unit. Anda dapat menyebutkannya Utilitydan dibenci oleh kolega Anda; atau Anda dapat memberi nama Unitsdan UnitsConversion.

Arseni Mourzenko
sumber
7
"Kelas utilitas pada dasarnya salah". Menarik. Solusi apa yang Anda usulkan untuk sesuatu seperti kelas utilitas fungsi Matematika? Haruskah instance objek Math benar-benar diperlukan untuk menggunakan fungsi di luar operator aritmatika dasar?
FrustratedWithFormsDesigner
1
Saya setuju dengan Anda, tetapi apa yang Anda sarankan sebagai alternatif?
pengguna
4
Saya menunda membuat pustaka "utils" untuk waktu yang lama, tetapi akhirnya Anda hanya harus menyerah. Alternatifnya adalah memiliki DLL yang terdiri dari sekitar 3 baris kode yang hanya rumit (dan mengingatkan saya pada kekacauan dependensi node.js adalah ), atau menyalin dan menempelkan metode utilitas Anda ke setiap kelas yang mungkin membutuhkannya (untuk menghindari kelas "kumpulan metode acak"). IMO pada akhirnya itu adalah kejahatan yang perlu.
Matti Virkkunen
3
@FrustratedWithFormsDesigner: cukup ... Math? Saya tidak melihat bagaimana menambahkan Utilitysufiks pada segalanya akan membuat hidup kita lebih mudah. Saat menggunakan System.Math.Min()metode .NET , apakah Anda lebih suka menulis SystemUtility.MathUtility.Min()? Dalam semua kasus, saya banyak mengedit jawaban saya, jadi itu harus lebih jelas sekarang.
Arseni Mourzenko