C # Namespace e convenzione di denominazione delle classi per le librerie

22

Sto costruendo librerie con varie piccole funzioni di utilità in C #, e sto provando a 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 c'è un modo migliore? In particolare sembra che avere lo stesso nome nel namespace e nel nome della classe (ad esempio Company.TextUtils namespace e TextUtils class) sia solo una duplicazione e suggerisce che lo schema potrebbe essere migliore.

    
posta user 18.01.2017 - 15:45
fonte

4 risposte

9

È molto difficile determinare l'efficacia della strategia di denominazione rispetto al resto del codice.

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

A parte questo, nel tuo esempio specifico, se è probabile che tu abbia molte classi di tipo "Util", prenderei in considerazione la possibilità di metterle sotto Company.Utils.Maths ecc. In questo modo se hai bisogno di aggiungere funzionalità che sono comuni a più aree di servizio, hai già una posizione naturale per questo.

    
risposta data 18.01.2017 - 16:13
fonte
26

C'è un bel documento che contiene molte regole che dovresti seguire per essere in linea con Microsoft: Framework Design Guidelines .

Una cosa che dovresti cambiare: Non name classes come loro spazio dei nomi. Questo porterà ai mixup del compilatore. Non farlo. Trova un nome migliore per la classe del namespace.

    
risposta data 18.01.2017 - 16:30
fonte
5

È passato un po 'di tempo da quando ho collaborato con C # o con l'ecosistema .NET, quindi non posso dire quali sono le best practice consigliate attualmente. Ti consigliamo di modificare i 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 dei namespace. Penso che "Util" non dovrebbe essere in uno spazio dei nomi, perché lo spazio dei nomi Company.Text potrebbe un giorno contenere classi che sono classi di utilità di testo non . Lo spazio dei nomi Company.Math già contiene ArbitraryPrecisionNumber che non sembra essere una "utility".

La rimozione di "Util" dal namespace risolve anche qualsiasi confusione che potrebbe sorgere avendo due cose con lo stesso nome (come menzionato nella risposta di Robert: link )

Un altro modo in cui potresti aver organizzato 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 c'è più Company.Text namespace poiché l'unica cosa che esisteva era una classe di utilità.

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

    
risposta data 18.01.2017 - 20:34
fonte
3

Utilizzare lo 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 altre classi? non sembra giusto, perché l'obiettivo del nome del namespace è descrivere tutte le classi al suo interno, non solo una. Ad esempio, se hai JsonSerialization , BinarySerialization e XmlSerialization classi in uno spazio dei nomi, avrebbe senso denominare il tuo spazio dei nomi XmlSerialization ?

    Di solito succede che a causa dell'estrazione di una classe da uno spazio dei nomi esistente o di un'unione tra più classi o altre riorganizzazioni, ti trovi con uno spazio dei nomi contenente una classe maggiore ; progressivamente, le classi minori vengono inserite perché sono leggermente correlate alla classe originale. Ad esempio, uno spazio dei nomi LogParser può contenere una singola classe LogParser , quindi qualcuno mette LogConverter , perché è abbastanza correlato al parser, quindi LogSearcher , ecc. Il problema qui è che il nome del namespace non è stato modificato: non appena è stato aggiunto LogConverter , il nome deve essere stato modificato in LogsProcessing o, 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 un paio di volte le situazioni in cui una singola classe con i principi SOLID corretti era molto diversa da qualsiasi altra cosa nella base di codice ed è stata 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 potrebbero indicare 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 le altre cose, dovrebbe convertire in un dato momento i file scritti in formato ABC in formato DEF. La conversione non richiede alcuna deserializzazione / serializzazione agli / dagli oggetti business e viene eseguita applicando un gruppo di espressioni regolari che sono abbastanza brevi da essere inserite nella classe di conversione stessa chiamata AbcToDefConverter . Tutta la logica di conversione impiega circa 80 LLOC in una decina di metodi interdipendenti: sembra una situazione in cui non è assolutamente necessario né dividere la classe esistente né creare classi aggiuntive. Poiché la parte restante dell'applicazione non ha nulla a che fare con le conversioni, la classe non può essere raggruppata con altre classi negli spazi dei nomi esistenti. Quindi si crea uno spazio dei nomi chiamato AbcToDefConverter . Anche se non c'è nulla di intrinsecamente sbagliato in questo, si potrebbe anche usare un nome più generico, come Converters . In linguaggi come Python, dove i nomi più brevi sono preferiti e la ripetizione viene lanciata, può anche diventare converters.Abc_To_Def .

Pertanto, usa nomi diversi per i namespace che per le classi che contengono. 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 messe al suo interno.

A proposito, le classi di utilità sono errate per natura: invece di contenere qualcosa di specifico, come l'aritmetica di precisione arbitraria, contengono piuttosto tutto ciò che non è stato trovato in altre classi . Questa è semplicemente una cattiva denominazione, proprio come una directory Miscellaneous su un desktop, qualcosa che è indicativo della mancanza di organizzazione.

Il nome esiste per un motivo: per semplificarti la vita quando hai bisogno di trovare cose più tardi. Sai che se devi disegnare un grafico, puoi provare a cercare "grafico" o "trama". Quando hai bisogno di cambiare il modo in cui un'app genera fatture, cercherai "invoic [e / ing]" o "fattura". Allo stesso modo, prova ad immaginare un caso in cui dirai a te stesso: "hm, questa funzione dovrebbe probabilmente essere trovata in misc". Non posso.

Guarda .NET Framework. Non sono la maggior parte di quelle classi di classi di utilità? Voglio dire, hanno poche cose da fare con il dominio aziendale. Se lavoro su un'app finanziaria, su un sito di e-commerce o sulla piattaforma di formazione next gen, serializzare XML o leggere file o fare query SQL o eseguire transazioni è tutto roba di utilità. Tuttavia, non sono chiamati UtilitySerialization o UtilityTransaction e non si trovano nello spazio dei nomi Utility . Hanno nomi propri, che rendono possibile (e facile, grazie a sviluppatori .NET!) Di 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 essere effettivamente i nomi delle classi.

Immagina di aver creato un codice che si occupa di unità e conversione di unità. Puoi chiamarlo Utility e essere odiato dai tuoi colleghi; oppure puoi chiamarlo Units e UnitsConversion .

    
risposta data 18.01.2017 - 16:28
fonte

Leggi altre domande sui tag