Mejores prácticas para usar espacios de nombres en C ++ [cerrado]

38

Hace unos meses leí el Código Limpio del Tío Bob , y ha tenido un profundo impacto en la forma en que escribo el código. Incluso si parecía que estaba repitiendo cosas que todo programador debería saber, ponerlas todas juntas y ponerlas en práctica resulta en un código mucho más limpio. En particular, descubrí que dividir las funciones grandes en muchas funciones pequeñas y dividir las clases grandes en muchas clases pequeñas es increíblemente útil.

Ahora para la pregunta. Todos los ejemplos del libro están en Java, mientras que he estado trabajando en C ++ durante los últimos años. ¿Cómo se extenderían las ideas en Clean Code al uso de espacios de nombres, que no existen en Java? (Sí, sé sobre los paquetes de Java, pero en realidad no es lo mismo).

¿Tiene sentido aplicar la idea de crear muchas entidades pequeñas, cada una con una responsabilidad claramente definida, a los espacios de nombres? ¿Debería un pequeño grupo de clases relacionadas estar siempre envuelto en un espacio de nombres? ¿Es esta la forma de administrar la complejidad de tener muchas clases pequeñas, o sería prohibitivo el costo de administrar muchos espacios de nombres?

Editar: mi pregunta se responde en esta entrada de Wikipedia sobre los principios del paquete .

Dima
fuente
77
Otro ejemplo de una buena pregunta para desarrolladores reales se cerró . Si este no es el sitio de stackexchange para preguntar sobre las mejores prácticas para desarrolladores, ¿qué es?
Sam Goldberg
@SamGoldberg: se pone mejor. Encontré una buena respuesta a esta pregunta aquí: en.wikipedia.org/wiki/Package_Principles . Publiqué esta respuesta, y un moderador la eliminó, porque simplemente publiqué el enlace y no tuve tiempo de copiar / pegar el contenido.
Dima
1
Creo que mi única crítica a la pregunta sería, en lugar de hacer varias preguntas al final, tratar de resumirla en una sola pregunta, por ejemplo, "¿cuáles deberían ser los criterios para determinar si los elementos deberían estar en el mismo espacio de nombres o espacios de nombres diferentes? ".
Sam Goldberg

Respuestas:

22

(No he leído Clean Code y no sé mucho de Java).

¿Tiene sentido aplicar la idea de crear muchas entidades pequeñas, cada una con una responsabilidad claramente definida, a los espacios de nombres?

Sí, tal como lo hace con la refactorización en múltiples clases y múltiples funciones.

¿Debería un pequeño grupo de clases relacionadas estar siempre envuelto en un espacio de nombres?

Sin responder realmente: sí, al menos debería usar un espacio de nombres de nivel superior. Esto puede basarse en un proyecto, organización o lo que desee, pero el uso de pocos nombres globales reducirá los conflictos de nombres. Un solo espacio de nombres para agrupar todo lo demás debajo de él solo introduce un nombre global. (Excepto las funciones externas "C", pero eso se debe a la interoperabilidad de C y solo afecta a otras funciones externas "C").

¿Debería un pequeño grupo de clases relacionadas estar envuelto en un espacio de nombres dedicado a ellos? Probablemente. Especialmente si te encuentras usando un prefijo común en esas clases: FrobberThing, FrobberThang, FrobberDoohickey, debes considerar un espacio de nombre: frobber :: Thing, etc. Esto todavía estaría debajo de su espacio de nombres raíz u otro espacio de nombres si son parte de un proyecto más grande.

¿Es esta la forma de administrar la complejidad de tener muchas clases pequeñas, o sería prohibitivo el costo de administrar muchos espacios de nombres?

Tomando el ejemplo anterior de nombres prefijados, no es más difícil administrar frobber :: Thing que FrobberThing. Incluso puede ser más fácil con algunas herramientas, como la documentación y la finalización del código. Hay una diferencia con ADL, pero esto puede funcionar a su favor: menos nombres en los espacios de nombres asociados hacen que ADL sea más fácil de entender, y puede usar declaraciones para inyectar nombres específicos en un espacio de nombres u otro.

Los alias de espacio de nombres le permiten usar un nombre más corto para un espacio de nombres más largo en un contexto específico, lo que nuevamente permite un uso más fácil:

void f() {
  namespace CWVLN = Company_with_very_long_name;  // Example from the standard.
  // In this scope, use CWVLN::name instead of Company_with_very_long_name::name.
  namespace fs = boost::filesystem;  // Commonly used.
}

Considere Boost, que tiene un solo espacio de nombres raíz, boost y luego muchos espacios de subnombres (boost :: asio, boost :: io, boost :: filesystem, boost :: tuples, etc.) para varias bibliotecas. Algunos nombres se "promueven" al espacio de nombres raíz:

Todas las definiciones están en namespace :: boost :: tuples, pero los nombres más comunes se levantan a namespace :: boost con el uso de declaraciones. Estos nombres son: tuple, make_tuple, tie y get. Además, ref y cref se definen directamente debajo del espacio de nombres :: boost.

La mayor diferencia de los idiomas con módulos "reales" es lo común que es usar una estructura más plana, lo que ocurre principalmente porque así es como funciona a menos que haga un esfuerzo adicional y específico para definir nombres anidados.

Fred Nurk
fuente
+1 @Fred Nurk para el análisis completo en lugar de las respuestas de una línea. No tiene que leer el libro para saber de qué se trata la pregunta. Este hilo de comentarios expone los conceptos y las diferencias que un programador de C ++ y Java podría tener en este libro. Comentario de código limpio en Amazon
Marlon
8

Debe tener un espacio de nombres maestro para todo su código. Esto lo distingue del código externo con respecto a los espacios de nombres.

Dentro de su espacio de nombres maestro, dependiendo del tamaño y la complejidad, puede abrir espacios de nombres secundarios. Aquí es donde los nombres claramente significan algo dentro de un contexto, y los mismos nombres pueden usarse dentro de un contexto diferente.

En particular, si tiene un nombre genérico que suena como FileInfo que significa algo particular dentro de un contexto, colóquelo en un espacio de nombres.

También puede usar una clase para esto, aunque una clase no es extensible, por lo que no puede agregar nuevas declaraciones a la clase sin modificar su encabezado.

CashCow
fuente
3

Los espacios de nombres no son un concepto de módulo, por lo que los usaría solo donde pudieran ocurrir conflictos de nombres.

Brainlag
fuente
44
No estoy seguro de lo que quieres decir. ¿Por qué un conjunto de clases relacionadas envueltas en un espacio de nombres no sería un módulo?
Dima
No hay restricciones dentro del espacio de nombres. En un módulo, puede decir que solo se puede acceder a una clase, función o variable dada desde el interior del módulo. En un espacio de nombres esto no es posible, es solo un prefijo para el nombre.
Brainlag
3
Parece que no estamos de acuerdo con la definición de un módulo . Para mí, cualquier cosa que agrupe entidades relacionadas y tenga un nombre descriptivo es un módulo, independientemente de si proporciona encapsulación o no.
Dima
3
La restricción de acceso es ortogonal a los módulos. De hecho, tiene sistemas exitosos como Python que definitivamente son más "módulos" que los espacios de nombres de C ++, pero no imponen restricciones de acceso.
Fred Nurk
Creo que esta es una de las mejores prácticas que figuran en los libros de Scott Meyer
Rafael
1

Java tiene espacios de nombres, simplemente no se llaman así. In javax.swing.* javaxes un espacio de nombres y swinges un subespacio de nombres. No he leído el libro para saber qué dice sobre los paquetes de Java, pero los mismos principios se aplicarían directamente a los espacios de nombres en cualquier idioma.

Una buena heurística es que usa un espacio de nombres cuando desea escribir el mismo prefijo para las clases una y otra vez. Por ejemplo, recientemente escribí algunas clases llamadas OmciAttribute, OmciAlarm, OmciMe, etc. y me di cuenta de que necesitaba dividir Omci en su propio espacio de nombres.

Karl Bielefeldt
fuente
1

Me gustan los espacios de nombres profundos (que generalmente significan tres niveles).

  • Tengo el nombre de la empresa.
  • aplicación / util / lib / etc.
  • Nombre del proyecto / o paquete según corresponda

Dependiendo de la situación, puedo tener un nivel más

  • detalles (detalles de implementación específicos de la plataforma)
  • utils (objeto de utilidad que aún no se ha movido a utilidad general).
  • lo que sea que necesite
Martin York
fuente