Je construis des bibliothèques avec diverses petites fonctions utilitaires en C # et j'essaie de décider d'un espace de noms et d'une convention de dénomination de classe. Mon organisation actuelle est comme ceci:
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 {...}
Est-ce un bon moyen d'organiser l'espace de noms et les classes, ou existe-t-il un meilleur moyen? En particulier, il semble avoir le même nom dans l'espace de noms et le nom de classe (par exemple Company.TextUtils
namespace et TextUtils
class) est juste une duplication et suggère que le schéma pourrait être meilleur.
Il est très difficile de déterminer l'efficacité de votre stratégie de nommage indépendamment du reste de votre code.
L'espace de noms devrait donner une idée de sa place dans la structure générale de votre base de code, et le nom de classe décrirait généralement le type de fonctionnalité ou de concept qu'il représente dans cette zone.
Mis à part les mises en garde, dans votre exemple spécifique, si vous êtes susceptible d'avoir beaucoup plus de classes de type "Util", j'envisagerais de les placer sous Company.Utils.Maths
Etc. De cette façon, si vous avez besoin d'ajouter des fonctionnalités communes à plusieurs zones utilitaires, vous avez déjà un emplacement naturel pour cela.
Il y a un bon document qui contient beaucoup de règles que vous devez suivre pour être en conformité avec Microsoft: Framework Design Guidelines .
Une chose que vous devriez changer: Ne pas nommer les classes comme leur espace de noms. Cela conduira à des mélanges de compilateurs. Mais ne le fais pas. Trouvez un meilleur nom pour la classe de l'espace de noms.
Cela fait un moment que je n'ai pas travaillé avec C # ou l'écosystème .NET, donc je ne peux pas dire quelles sont les meilleures pratiques recommandées. Je recommanderais une modification de vos noms comme ceci:
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 {...}
Ce que j'ai fait ici, c'est supprimer "Utils" des noms d'espace de noms. Je pense que "Util" ne devrait pas être dans un espace de noms, car le Company.Text
l'espace de noms pourrait un jour contenir des classes qui ne sont pas des classes utilitaires de texte. Le Company.Math
l'espace de noms contient déjà ArbitraryPrecisionNumber
qui ne semble pas être un "utilitaire".
La suppression de "Util" de l'espace de noms élimine également toute confusion qui pourrait survenir en ayant deux choses avec le même nom (comme mentionné dans la réponse de Robert: https://softwareengineering.stackexchange.com/a/340440/13156 )
Une autre façon dont vous auriez pu organiser le code:
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 {...}
Dans ce cas, toutes les classes d'utilitaires résident dans le même espace de noms. Il n'y a plus Company.Text
espace de noms car il n'y avait qu'une classe utilitaire.
Personnellement, je trouve la première option un peu plus claire.
L'utilisation du même nom pour l'espace de noms et la classe à l'intérieur est problématique.
Si l'espace de noms contient plusieurs classes, pourquoi y aurait-il d'autres classes? cela ne semble pas correct, car le but du nom de l'espace de noms est de décrire toutes les classes qu'il contient, pas seulement une. Par exemple, si vous avez des classes JsonSerialization
, BinarySerialization
et XmlSerialization
dans un espace de noms, serait-il judicieux de nommer votre espace de noms XmlSerialization
?
Ce qui se produit généralement, c'est qu'en raison de l'extraction d'une classe d'un espace de noms existant, ou d'une fusion entre plusieurs classes ou d'une autre réorganisation, vous vous retrouvez avec un espace de noms contenant un majeur classe; progressivement, des classes mineures y sont mises car elles sont légèrement liées à la classe d'origine. Par exemple, un espace de noms LogParser
peut contenir une seule classe LogParser
, puis quelqu'un place LogConverter
, car il est assez lié à l'analyseur, puis LogSearcher
, etc. Le problème ici est que le nom de l'espace de noms n'a pas été changé: dès que LogConverter
a été ajouté, le nom aurait dû être changé en LogsProcessing
ou, simplement, Logs
.
Si l'espace de noms ne contient qu'une seule classe, cela peut être le signe d'un problème au sein de l'organisation du code.
Bien que j'ai vu à quelques reprises les situations où une seule classe avec les bons principes SOLID était très différente de toute autre chose dans la base de code et a donc été placée dans un espace de noms dédié, de tels cas sont rares Plus souvent, cela indique un problème. De même, rien ne vous empêche d'avoir une classe contenant une seule méthode, mais le plus souvent, de telles classes indiquent un problème.
Même si votre espace de noms ne contient qu'une seule classe, il existe généralement un moyen d'être plus spécifique lors du nommage de la classe et plus général lors du nommage de l'espace de noms. Imaginez une application qui, entre autres, devrait à un moment donné convertir des fichiers écrits au format ABC au format DEF. La conversion ne nécessite aucune désérialisation/sérialisation vers/depuis les objets métier et est effectuée en appliquant un tas d'expressions régulières suffisamment courtes pour être placées dans la classe de conversion elle-même appelée AbcToDefConverter
. Toute la logique de conversion prend environ 80 LLOC dans une dizaine de méthodes interdépendantes - semble être une situation où il n'est absolument pas nécessaire de diviser la classe existante, ni de créer des classes supplémentaires. Étant donné que la partie restante de l'application n'a rien à voir avec les conversions, la classe ne peut pas être regroupée avec d'autres classes dans des espaces de noms existants. On crée donc un espace de noms appelé AbcToDefConverter
. Bien qu'il n'y ait rien de mal en soi, on pourrait également utiliser un nom plus générique, tel que Converters
. Dans des langages tels que Python, où des noms plus courts sont préférés et où la répétition est lancée, il peut même devenir converters.Abc_To_Def
.
Par conséquent, tilisez des noms d'espaces de noms différents de ceux des classes qu'ils contiennent. Le nom d'une classe doit indiquer ce que fait la classe, tandis que le nom de l'espace de noms doit mettre en évidence ce qui est commun à toutes les classes qu'il contient.
Soit dit en passant, les classes d'utilité sont fausses par nature: au lieu de contenir quelque chose de spécifique, comme l'arithmétique de précision arbitraire, elles contiennent plutôt tout ce qui n'a pas trouvé son chemin dans les autres classes . C'est tout simplement une mauvaise dénomination, tout comme un répertoire Miscellaneous
sur un bureau - quelque chose qui indique le manque d'organisation.
La dénomination existe pour une raison: pour vous faciliter la vie lorsque vous avez besoin de trouver des choses plus tard. Vous savez que si vous avez besoin de dessiner un graphique, vous pouvez essayer de rechercher "graphique" ou "tracé". Lorsque vous devez modifier la façon dont une application génère des factures, vous recherchez "facture [e/ing]" ou "facture". De même, essayez d'imaginer un cas où vous vous direz: "hm, cette fonctionnalité devrait probablement se trouver dans misc". Je ne peux pas.
Regardez .NET Framework. La plupart de ces classes ne sont-elles pas des classes utilitaires? Je veux dire, ils ont peu de choses à voir avec le domaine des affaires. Si je travaille sur une application financière, ou un site Web de commerce électronique, ou la plate-forme d'éducation de prochaine génération, sérialiser XML ou lire des fichiers ou effectuer des requêtes SQL ou effectuer des transactions est tout ce qui est utile. Cependant, ils ne sont pas appelés UtilitySerialization
ou UtilityTransaction
et ils ne se trouvent pas dans l'espace de noms Utility
. Ils ont des noms propres, ce qui permet (et facile, merci aux développeurs .NET!) De les trouver quand j'en ai besoin.
Il en va de même pour vos classes que vous réutilisez couramment dans vos applications. Ce ne sont pas des classes d'utilité. Ce sont des classes qui font certaines choses, et les choses qu'elles font devraient en fait être les noms des classes.
Imaginez que vous avez créé du code qui traite des unités et de la conversion des unités. Vous pouvez l'appeler Utility
et être détesté par vos collègues; ou vous pouvez le nommer Units
et UnitsConversion
.