(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.