Convención de nombres de clase y espacio de nombres C # para bibliotecas

26

Estoy creando bibliotecas con varias funciones pequeñas de utilidad en C #, y estoy tratando de decidir sobre un espacio de nombres y una convención de nomenclatura de clases. Mi organización actual es así:

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

¿Es esta una buena manera de organizar el espacio de nombres y las clases, o hay una mejor manera? En particular, parece que tener el mismo nombre en el espacio de nombres y el nombre de la clase (por ejemplo, Company.TextUtilsespacio de nombres y TextUtilsclase) es solo una duplicación y sugiere que el esquema podría ser mejor.

usuario
fuente
55
Las pautas de Microsoft recomiendan nombres singulares para enumeraciones (así que en SISuffixlugar de SISuffixes), y creo que ese singular se lee mejor. Suffix.A se lee como "sufijo A". Además, generalmente evito repetir nombres desde un nivel superior en la jerarquía. Es decir, en lugar de Company.SIUnits.SISuffixes, me inclinaría hacia Company.SI.SuffixyCompany.SI.Unit
Harrison Paine
2
@richzilla thecodelesscode.com/case/220
Tin Man

Respuestas:

9

Es muy difícil determinar qué tan efectiva es su estrategia de nombres aisladamente del resto de su código.

El espacio de nombres debería dar una idea de dónde encaja en la estructura amplia de su base de código, y el nombre de la clase generalmente describiría qué tipo de funcionalidad o concepto representa dentro de esa área.

Dejando a un lado las advertencias, en su ejemplo específico, si es probable que tenga muchas más clases de tipo 'Util', consideraría ponerlas debajo, Company.Utils.Mathsetc. Un lugar natural para ello.

richzilla
fuente
1
Eso suena como una buena idea. Deje de preocuparse demasiado, simplemente ingrese todo en "Company.Util".
usuario
30

Hay un buen documento que contiene muchas reglas que debe seguir para estar en línea con Microsoft: Pautas de diseño de marcos .

Una cosa que debe cambiar: no nombre las clases como su espacio de nombres. Eso conducirá a mezclas de compiladores. Solo no lo hagas. Encuentre un mejor nombre para la clase del espacio de nombres.

nvoigt
fuente
3
El enlace directo a las pautas de espacios de nombres: msdn.microsoft.com/en-us/library/ms229026(v=vs.110).aspx
Pagotti
1
Que por coincidencia o no, también es el mismo nombre de un gran libro sobre el tema, también escrito por personas de Microsoft que participaron en la creación del marco DotNet, con varias observaciones sobre lo que hicieron bien y dónde hicieron mal las cosas. Vale la pena leerlo: amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/…
Machado
@nvoigt, ¿podría editar su respuesta para agregar una cita desde el enlace que nuestro amigo Pagotti proporcionó: " NO use el mismo nombre para un espacio de nombres y un tipo en ese espacio de nombres. Por ejemplo, no use Debug como nombre de espacio de nombres y luego también proporcione una clase llamada Debug en el mismo espacio de nombres. Varios compiladores requieren que tales tipos estén completamente calificados ".
Machado
2
Advertencia: a veces un nombre de producto es mejor que usar un nombre de empresa. He estado en algunos escenarios donde se compró una empresa y tuvimos que producir nuevos espacios de nombres en todos los ámbitos y volver a lanzarlos. Creo que esto es muy pequeño, pero quería señalarlo.
Jon Raynor
1
Las pautas de diseño del marco de Microsoft son altamente cuestionables, contienen declaraciones falsas sobre cómo funciona .NET, y muy a menudo no son seguidas por Microsoft. Sus pautas de nomenclatura son buenas, pero evitaría vincular las pautas generales con una declaración de que "debe seguirlas".
Carl Leth el
6

Ha pasado un tiempo desde que trabajé con C # o el ecosistema .NET, así que no puedo decir cuáles son las mejores prácticas actuales recomendadas. Recomiendo un cambio en sus nombres como este:

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

Lo que he hecho aquí es eliminar "Utils" de los nombres del espacio de nombres. Creo que "Util" no debería estar en un espacio de nombres, porque el Company.Textespacio de nombres podría algún día contener clases que no sean clases de utilidad de texto. El Company.Mathespacio de nombres ya contiene ArbitraryPrecisionNumberque no parece ser una "utilidad".

Eliminar "Util" del espacio de nombres también aclara cualquier confusión que pueda surgir al tener dos cosas con el mismo nombre (como se menciona en la respuesta de Robert: /software//a/340440/13156 )

Otra forma en que podría haber organizado el código:

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

En este caso, todas las clases de utilidad residen en el mismo espacio de nombres. No hay más Company.Textespacio de nombres ya que lo único que había era una clase de utilidad.

Personalmente, encuentro la primera opción un poco más clara.

FrustratedWithFormsDesigner
fuente
4

Usar el mismo nombre para el espacio de nombres y la clase dentro de él es problemático.

  • Si el espacio de nombres contiene más de una clase, ¿por qué se colocarían otras clases allí? no se siente bien, porque el objetivo del nombre del espacio de nombres es describir todas las clases dentro de él, no solo una. Por ejemplo, si tiene JsonSerialization, BinarySerializationy XmlSerializationclases en un espacio de nombres, ¿tendría sentido nombrar su espacio de nombres XmlSerialization?

    Lo que generalmente sucede es que debido a una extracción de una clase de un espacio de nombres existente, o una fusión entre múltiples clases u otra reorganización, te encuentras con un espacio de nombres que contiene una clase principal ; progresivamente, las clases menores se colocan allí porque están ligeramente relacionadas con la clase original. Por ejemplo, un espacio de nombres LogParserpuede contener una sola clase LogParser, y luego alguien lo pone LogConverter, porque está bastante relacionado con el analizador LogSearcher, etc. El problema aquí es que el nombre del espacio de nombres no cambió: tan pronto como LogConverterse agregó, el nombre debería haber sido cambiado a LogsProcessing, o, simplemente, Logs.

  • Si el espacio de nombres contiene solo una clase, podría ser un signo de un problema dentro de la organización del código.

    Si bien he visto algunas veces las situaciones en las que una sola clase con principios SÓLIDOS adecuados era muy diferente de cualquier otra cosa en la base del código y, por lo tanto, se colocó en un espacio de nombres dedicado, estos casos son raros. Más a menudo, esto es indicativo de un problema. Del mismo modo, nada le impide tener una clase que contenga un único método, pero la mayoría de las veces, esas clases indicarían un problema.

    Incluso si su espacio de nombres contiene solo una clase, generalmente hay una manera de ser más específico al nombrar la clase, y más general al nombrar el espacio de nombres. Imagine una aplicación que, entre otras cosas, debería en un momento dado convertir archivos escritos en formato ABC a formato DEF. La conversión no requiere ninguna deserialización / serialización hacia / desde los objetos comerciales, y se realiza mediante la aplicación de un conjunto de expresiones regulares que son lo suficientemente cortas como para colocarlas dentro de la clase de conversión llamadaAbcToDefConverter. Toda la lógica de conversión requiere aproximadamente 80 LLOC en aproximadamente diez métodos interdependientes; parece una situación en la que no hay absolutamente ninguna necesidad de dividir la clase existente ni de crear clases adicionales. Dado que la parte restante de la aplicación no tiene nada que ver con las conversiones, la clase no se puede agrupar con otras clases en espacios de nombres existentes. Entonces uno crea un espacio de nombres llamado AbcToDefConverter. Si bien no hay nada inherentemente incorrecto en eso, también se podría usar un nombre más genérico, como Converters. En lenguajes como Python, donde se prefieren nombres más cortos y se repite la repetición, incluso puede llegar a ser converters.Abc_To_Def.

Por lo tanto, utilice nombres diferentes para los espacios de nombres que para las clases que contienen. El nombre de una clase debe indicar lo que está haciendo la clase, mientras que el nombre del espacio de nombres debe resaltar lo que es común en todas las clases incluidas en él.


Por cierto, las clases de utilidad son incorrectas por naturaleza: en lugar de contener algo específico, como la aritmética de precisión arbitraria, más bien contienen todo lo que no ha encontrado su camino en otras clases . Esto es simplemente una mala denominación, al igual que un Miscellaneousdirectorio en un escritorio, algo que indica la falta de organización.

Los nombres existen por una razón: para facilitarle la vida cuando necesite encontrar cosas más tarde. Usted sabe que si necesita dibujar un gráfico, puede intentar buscar "gráfico" o "gráfico". Cuando necesite cambiar la forma en que una aplicación genera facturas, buscará "factura [e / ing]" o "factura". Del mismo modo, trate de imaginar un caso en el que se diga a sí mismo: "hm, esta característica probablemente debería encontrarse en misceláneos". No puedo

Mira .NET Framework. ¿No son la mayoría de esas clases clases de utilidad? Quiero decir, tienen pocas cosas que hacer con el dominio comercial. Si trabajo en una aplicación financiera, o en un sitio web de comercio electrónico, o en la plataforma educativa de la próxima generación, serializar XML o leer archivos o hacer consultas SQL o realizar transacciones es todo de utilidad. Sin embargo, no se llaman UtilitySerializationo UtilityTransaction, y no están en el Utilityespacio de nombres. Tienen nombres propios, que hacen posible (y fácil, ¡gracias a los desarrolladores de .NET!) Encontrarlos cuando los necesito.

Lo mismo ocurre con sus clases que suele reutilizar en sus aplicaciones. No son clases de utilidad. Son clases que hacen ciertas cosas, y las cosas que hacen deberían ser los nombres de las clases.

Imagina que has creado un código que se ocupa de las unidades y la conversión de unidades. Puede nombrarlo Utilityy ser odiado por sus colegas; o puedes nombrarlo Unitsy UnitsConversion.

Arseni Mourzenko
fuente
77
"Las clases de utilidad son incorrectas por naturaleza". Interesante. ¿Qué solución propone para algo como una clase de utilidad de función matemática? ¿Debería ser realmente necesaria una instancia de un objeto matemático para usar funciones más allá de los operadores aritméticos básicos?
FrustratedWithFormsDesigner
1
Estoy de acuerdo contigo, pero ¿qué sugieres como alternativa?
usuario
2
Lo
llamaré
44
Retrasé la creación de una biblioteca "utils" por el tiempo más largo, pero eventualmente solo tienes que rendirte. La alternativa es tener archivos DLL que consisten en aproximadamente 3 líneas de código, lo cual es engorroso (y me recuerda el desastre de dependencias node.js es ), o copiar y pegar sus métodos de utilidad en cada clase que los necesite (para evitar tener esa clase de "colección de métodos aleatorios"). OMI al final es un mal necesario.
Matti Virkkunen
3
@FrustratedWithFormsDesigner: ¿simplemente ... Math? No veo cómo agregar Utilitysufijo a todo nos facilitaría la vida. Cuando utilice el System.Math.Min()método .NET , ¿preferiría realmente escribir SystemUtility.MathUtility.Min()? En todos los casos, edité mucho mi respuesta, por lo que debería ser más clara ahora.
Arseni Mourzenko