Spazio dei nomi C # e convenzione di denominazione delle classi per le librerie


26

Sto creando librerie con varie piccole funzioni di utilità in C # e sto cercando di decidere su uno spazio dei nomi e una convenzione di denominazione delle classi. La mia attuale organizzazione è così:

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 {...}

È un buon modo per organizzare lo spazio dei nomi e le classi o esiste un modo migliore? In particolare sembra che avere lo stesso nome nello spazio dei nomi e il nome della classe (ad es. Company.TextUtilsSpazio dei nomi e TextUtilsclasse) sia solo una duplicazione e suggerisce che lo schema potrebbe essere migliore.



5
Le linee guida di Microsoft raccomandano nomi singolari per enum (quindi SISuffixinvece di SISuffixes), e penso che singolare legga meglio. Suffix.A legge come "suffisso A". Inoltre, generalmente evito di ripetere i nomi da un livello superiore nella gerarchia. Cioè, invece di Company.SIUnits.SISuffixes, mi sporgerei verso Company.SI.SuffixeCompany.SI.Unit
Harrison Paine, il

Risposte:


9

È molto difficile determinare l'efficacia della tua strategia di denominazione in isolamento dal resto del codice.

Lo spazio dei nomi dovrebbe dare un'idea di dove si adatta all'ampia struttura della base di codice, e il nome della classe di solito descrive quale tipo di funzionalità o concetto rappresenta all'interno di quell'area.

Avvertenze a parte, nel tuo esempio specifico, se è probabile che tu abbia molte più classi di tipo "Util", prenderei in considerazione l'idea di metterle sotto Company.Utils.Mathsecc. In questo modo se hai bisogno di aggiungere funzionalità che è comune a più aree di utilità, hai già un luogo naturale per questo.


1
Sembra una buona idea. Smetti di preoccuparti troppo, basta lanciare tutto in "Company.Util".
utente

30

Esiste un bel documento che contiene molte regole da seguire per essere in linea con Microsoft: Framework Design Guidelines .

Una cosa che dovresti cambiare: non nominare le classi come loro spazio dei nomi. Ciò porterà a confusioni del compilatore. Non farlo. Trova un nome migliore per la classe dello spazio dei nomi.


3
Il collegamento diretto alle linee guida degli spazi dei nomi: msdn.microsoft.com/en-us/library/ms229026(v=vs.110).aspx
Pagotti

1
Che per coincidenza o no è anche lo stesso nome di un grande libro sull'argomento, scritto anche da persone Microsoft che hanno partecipato alla creazione del framework DotNet, con diverse osservazioni su cosa hanno fatto bene e dove hanno sbagliato. Vale la pena leggere: amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/…
Machado,

@nvoigt, potresti modificare la tua risposta per aggiungere un preventivo dal link fornito dal nostro amico Pagotti: " NON utilizzare lo stesso nome per uno spazio dei nomi e un tipo in quello spazio dei nomi. Ad esempio, non utilizzare Debug come nome dello spazio dei nomi e quindi fornisce anche una classe chiamata Debug nello stesso spazio dei nomi. Diversi compilatori richiedono che tali tipi siano pienamente qualificati. "
Machado,

2
Avvertenza: a volte un nome di prodotto è meglio dell'uso di un nome di società. Siamo stati in alcuni scenari in cui una società è stata acquisita e abbiamo dovuto produrre nuovi spazi dei nomi su tutta la linea e ripubblicare. Penso che questo sia molto minore, ma ho voluto sottolineare.
Jon Raynor il

1
Le linee guida di progettazione del framework Microsoft sono altamente discutibili, contengono false dichiarazioni su come funziona .NET e molto spesso non sono seguite dalla stessa Microsoft. Le loro linee guida per la denominazione sono buone, ma eviterei di collegare le linee guida generali con una dichiarazione secondo cui "dovresti seguirle".
Carl Leth,

6

È passato un po 'di tempo da quando ho lavorato con C # o l'ecosistema .NET, quindi non posso dire quali siano le migliori pratiche consigliate. Consiglierei una modifica ai tuoi nomi in questo modo:

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 {...}

Quello che ho fatto qui è rimuovere "Utils" dai nomi degli spazi dei nomi. Penso che "Util" non dovrebbe essere in uno spazio dei nomi, perché lo Company.Textspazio dei nomi un giorno potrebbe contenere classi che non lo sono classi di utilità di testo. Lo Company.Mathspazio dei nomi contiene giàArbitraryPrecisionNumber quale Non sembra essere una "utility".

La rimozione di "Util" dallo spazio dei nomi cancella anche qualsiasi confusione che potrebbe sorgere avendo due cose con lo stesso nome (come menzionato nella risposta di Robert: /software//a/340440/13156 )

Un altro modo in cui avresti potuto organizzare il codice:

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 {...}

In questo caso, tutte le classi di utilità risiedono nello stesso spazio dei nomi. Non ce n'è piùCompany.Text spazio dei nomi poiché l'unica cosa che c'era una classe di utilità.

Personalmente, trovo la prima opzione un po 'più chiara.


4

L'uso dello stesso nome per lo spazio dei nomi e la classe al suo interno è problematico.

  • Se lo spazio dei nomi contiene più di una classe, perché dovrebbero essere inserite lì altre classi? non sembra giusto, perché l'obiettivo del nome dello spazio dei nomi è descrivere tutte le classi al suo interno, non solo una. Ad esempio, se hai JsonSerialization, BinarySerializationeXmlSerialization classi in uno spazio dei nomi, avrebbe senso nominare il tuo spazio dei nomi XmlSerialization?

    Ciò che accade di solito è che a causa di un'estrazione di una classe da uno spazio dei nomi esistente o di un'unione tra più classi o altra riorganizzazione, ti ritrovi con uno spazio dei nomi contenente una classe maggiore ; progressivamente, le classi minori vengono messe lì perché sono leggermente correlate alla classe originale. Ad esempio, uno spazio dei nomi LogParserpuò contenere una singola classe LogParser, quindi qualcuno mette LogConverter, perché è abbastanza correlato al parser, quindi LogSearcher, ecc. Il problema qui è che il nome dello spazio dei nomi non è stato modificato: non appena è LogConverterstato aggiunto, il nome avrebbe dovuto essere cambiato in LogsProcessingo, semplicemente, Logs.

  • Se lo spazio dei nomi contiene solo una classe, potrebbe essere un segno di un problema all'interno dell'organizzazione del codice.

    Mentre ho visto alcune volte le situazioni in cui una singola classe con i giusti principi SOLID era molto diversa da qualsiasi altra cosa nella base di codice ed era quindi inserita in uno spazio dei nomi dedicato, tali casi sono rari. Più spesso, questo è indicativo di un problema. Allo stesso modo, nulla ti impedisce di avere una classe contenente un singolo metodo, ma il più delle volte tali classi indicherebbero un problema.

    Anche se il tuo spazio dei nomi contiene solo una classe, di solito c'è un modo per essere più specifico quando si nomina la classe e più generale quando si nomina lo spazio dei nomi. Immagina un'applicazione che, tra l'altro, dovrebbe in un determinato momento convertire i file scritti in formato ABC in formato DEF. La conversione non richiede alcuna deserializzazione / serializzazione da / verso gli oggetti business e viene eseguita applicando un gruppo di espressioni regolari che sono abbastanza brevi da essere inserite nella classe di conversione stessa chiamataAbcToDefConverter. Tutta la logica di conversione richiede circa 80 LLOC in circa dieci metodi interdipendenti: sembra una situazione in cui non è assolutamente necessario né dividere la classe esistente né creare classi aggiuntive. Poiché la parte rimanente dell'applicazione non ha nulla a che fare con le conversioni, la classe non può essere raggruppata con altre classi in spazi dei nomi esistenti. Quindi si crea uno spazio dei nomi chiamato AbcToDefConverter. Sebbene non ci sia nulla di intrinsecamente sbagliato in ciò, si potrebbe anche usare un nome più generico, come Converters. In linguaggi come Python, dove si preferiscono nomi più brevi e si ripete la ripetizione, potrebbe persino diventare converters.Abc_To_Def.

Pertanto, utilizzare nomi diversi per gli spazi dei nomi rispetto alle classi in essi contenute. Il nome di una classe dovrebbe indicare cosa sta facendo la classe, mentre il nome dello spazio dei nomi dovrebbe evidenziare ciò che è comune in tutte le classi inserite al suo interno.


A proposito, le classi di utilità sono sbagliate per natura: invece di contenere qualcosa di specifico, come l'aritmetica di precisione arbitraria, contengono piuttosto tutto ciò che non ha trovato la sua strada in altre classi . Questa è semplicemente una cattiva denominazione, proprio come aMiscellaneous directory su un desktop, qualcosa che indica la mancanza di organizzazione.

La denominazione esiste per un motivo: per semplificarti la vita quando devi trovare cose in un secondo momento. Sai che se devi disegnare un grafico, puoi provare a cercare "grafico" o "grafico". Quando devi cambiare il modo in cui un'app genera fatture, cercherai "fatturazione [e / ing]" o "fattura". Allo stesso modo, prova a immaginare un caso in cui ti dirai: "hm, questa funzione dovrebbe probabilmente essere trovata in misc". Non posso.

Guarda .NET Framework. La maggior parte di quelle classi non sono classi di utilità? Voglio dire, hanno poche cose a che fare con il dominio aziendale. Se lavoro su un'app finanziaria, su un sito Web di e-commerce o sulla piattaforma di formazione di prossima generazione, serializzare XML o leggere file o fare query SQL o eseguire transazioni è tutta una questione di utilità. Tuttavia, non vengono chiamati UtilitySerializationo UtilityTransactione non si trovano inUtility spazio nomi. Hanno nomi propri, che rendono possibile (e facile, grazie agli sviluppatori .NET!) Trovarli quando ne ho bisogno.

Lo stesso vale per le tue classi che riutilizzi comunemente nelle tue app. Non sono classi di utilità. Sono classi che fanno certe cose, e le cose che fanno dovrebbero effettivamente essere i nomi delle classi.

Immagina di aver creato del codice che si occupa delle unità e della conversione delle unità. Puoi nominarlo Utilityed essere odiato dai tuoi colleghi; oppure puoi nominarlo Unitse UnitsConversion.


7
"Le classi di utilità sono sbagliate per natura". Interessante. Quale soluzione proponete per qualcosa come una classe di utilità per le funzioni matematiche? In caso di un esempio di un oggetto Math è davvero necessario utilizzare le funzioni di là di operatori aritmetici di base?
FrustratedWithFormsDesigner,

1
Sono d'accordo con te, ma cosa suggerisci in alternativa?
utente


4
Ho ritardato la creazione di una libreria "utils" per il tempo più lungo, ma alla fine devi solo cedere. L'alternativa è avere DLL costituite da circa 3 righe di codice che è solo ingombrante (e mi ricorda il disordine delle dipendenze node.js è ) o copiare e incollare i metodi di utilità in ogni singola classe che potrebbe averne bisogno (per evitare di avere quella classe "raccolta di metodi casuali"). L'IMO alla fine è un male necessario.
Matti Virkkunen,

3
@FrustratedWithFormsDesigner: semplicemente ... Math? Non vedo come l'aggiunta di Utilitysuffisso a tutto ciò faciliterebbe la nostra vita. Quando usi il System.Math.Min()metodo .NET , preferiresti davvero scrivere SystemUtility.MathUtility.Min()? In tutti i casi, ho modificato pesantemente la mia risposta, quindi ora dovrebbe essere più chiara.
Arseni Mourzenko,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.