Je suppose que ceci est une autre question sur le codage dur et les meilleures pratiques. Supposons que j'ai une liste de valeurs, disons fruits, stockées dans la base de données (elle doit figurer dans la base de données car la table est utilisée à d'autres fins, telles que les rapports SSRS), avec un ID:
1 Apple
2 Banana
3 Grapes
Je peux les présenter à l'utilisateur, il en sélectionne un, il est stocké dans son profil sous le nom FavouriteFruit et l'identifiant stocké dans son enregistrement dans la base de données.
En ce qui concerne la logique des règles métier / domaine, quelles sont les recommandations pour attribuer une logique à des valeurs spécifiques. Si l'utilisateur a sélectionné Grapes, je souhaite effectuer une tâche supplémentaire. Quel est le meilleur moyen de référencer la valeur Grapes:
// Hard coded name
if (user.FavouriteFruit.Name == "Grapes")
// Hard coded ID
if (user.FavoriteFruit.ID == 3) // Grapes
// Duplicate the list of fruits in an enum
if (user.FavouriteFruit.ID == (int)Fruits.Grapes)
ou autre chose?
Bien sûr, le FavouriteFruit sera utilisé dans toute l'application, la liste peut être ajoutée ou modifiée.
Quelqu'un peut décider qu'il veut renommer 'Grapes' en 'Grape', ce qui casse l'option de chaîne codée en dur.
L'ID codé en dur n'est pas tout à fait clair, cependant, comme indiqué, vous pouvez simplement ajouter un commentaire pour identifier rapidement l'élément.
L'option enum implique la duplication de données de la base de données, ce qui semble faux, car elles risquent de ne pas être synchronisées.
Quoi qu'il en soit, merci d'avance pour vos commentaires ou suggestions.
MyApplication.Grape.ID
est le bégaiement, pour ainsi dire. Un "Apple" n'est pas un "Red_Apple", pas plus qu'un ID de 3, c'est aussi 4. Donc, le potentiel de renommer "Apple" en "Red_Apple" n'a pas plus de sens que de déclarer que 3 est 4 (et peut-être même 3). Le but d'une énumération est d'extraire son ADN numérique. Alors peut-être qu'il est temps de vraiment dissocier les clés de base de données relationnelles arbitraires qui n'ont littéralement aucune signification dans les modèles commerciaux.Réponses:
Évitez les cordes et les constantes magiques à tout prix. Ils sont complètement hors de question, ils ne devraient même pas être considérés comme des options. Cela semble ne vous laisser qu’une seule option viable: les identificateurs, c’est-à-dire les énumérations. Cependant, il existe aussi une option supplémentaire qui, à mon avis, est la meilleure. Appelons cette option "Objets préchargés". Avec les objets préchargés, vous pouvez effectuer les opérations suivantes:
Ce qui vient de se passer ici, c’est que j’ai évidemment chargé toute la ligne de
Grape
mémoire dans la mémoire, et j’ai donc son identifiant prêt à être utilisé pour des comparaisons. Si vous utilisez un mappage relationnel-objet (ORM), il est encore meilleur:(C'est pourquoi je l'appelle "Objets préchargés".)
Par conséquent, lors du démarrage, je charge tous mes tableaux "d'énumération" (petits tableaux tels que les jours de la semaine, les mois de l'année, les genres, etc.) dans la classe de domaine d'application principale. Je les charge par leur nom car, bien évidemment, il
MyApplication.Grape
faut recevoir la ligne "Grape" et j'affirme que chacun d'entre eux est trouvé. Sinon, nous avons une erreur d'exécution garantie au démarrage, qui est la moins maligne de toutes les erreurs d'exécution.la source
Grape = fetchRow( Fruit.class, NameColumn, "Grape" );
Et si vous faites quelque chose de mal,AssertionError
vous le saurez.enum
aurait été une chaîne magique. Le point essentiel est la concentration de toutes les liaisons par nom dans un seul endroit , la validation de toutes ces informations lors du démarrage et la sécurité .La vérification par rapport à la chaîne est la plus lisible, mais elle remplit une double fonction: elle est utilisée à la fois comme identifiant et comme description (qui peut changer pour des raisons non liées).
Je divise généralement les deux tâches en champs distincts:
Où description peut changer (mais pas "Grapes" à "Banana"), mais le code n'est pas autorisé à changer, jamais.
Bien que cela soit principalement dû au fait que nos identifiants sont presque toujours générés automatiquement, ils ne conviennent donc pas. Si vous pouvez choisir les identifiants librement, vous pouvez peut-être garantir qu'ils sont toujours corrects et les utiliser.
Aussi, combien de fois quelqu'un modifie-t-il réellement "Grapes" en "Grape"? Peut-être que rien de tout cela n'est nécessaire.
la source
Ce que vous attendez ici, c'est que la logique de programmation s'adapte automatiquement à l'évolution des données. Les options statiques simples telles qu'Enum ne fonctionnent pas ici car vous ne pouvez pas ajouter d'énums supplémentaires au runtime.
Quelques motifs que j'ai vus:
En général, j'aime bien que les données soient complètes en termes de référence aux actions que cela implique - même si les actions elles-mêmes peuvent être mises en œuvre ailleurs. Tout code déterminant des actions indépendantes des données vient de fragmenter votre représentation de données, ce qui risque fort de diverger et de conduire à des bogues.
la source
Les stocker aux deux endroits (dans une table et dans un ENUM) n'est pas si mal. Le raisonnement est le suivant:
En les stockant dans une table de base de données, nous pouvons appliquer l'intégrité référentielle dans la base de données via des clés étrangères. Ainsi, lorsque vous associez une personne ou une entité quelconque à un fruit, il ne s'agit que d'un fruit qui existe dans la table de la base de données.
Les stocker en tant que ENUM est également logique car nous pouvons écrire du code sans chaînes magiques et le rendre plus lisible. Oui, ils doivent rester synchronisés, mais ce serait vraiment difficile d'ajouter une ligne à ENUM et une nouvelle instruction insert à la base de données.
Une chose, une fois qu'un ENUM est défini, ne change pas sa valeur. Par exemple, si vous aviez:
NE PAS renommer Grape en Grapes. Ajoutez simplement un nouvel ENUM.
Si vous avez besoin de migrer des données, appliquez une mise à jour pour déplacer tout le raisin vers le raisin.
la source
Vous avez raison de poser cette question, c’est une bonne question alors que vous essayez de vous défendre contre l’évaluation de conditions inexactes.
Cela dit, l’évaluation (vos
if
conditions) ne doit pas nécessairement être au centre de la façon dont vous la contournez. Faites plutôt attention à la manière dont vous propagez les modifications susceptibles de générer un problème de "désynchronisation".Approche de la chaîne
Si vous devez utiliser des chaînes, pourquoi ne pas exposer la fonctionnalité de modification de la liste via l'interface utilisateur? Concevez le système de manière à mettre
Grape
à jourGrapes
, par exemple, tous les enregistrements en cours de référencementGrape
.Approche d'identification
Je préférerais toujours faire référence à un identifiant, malgré la compromission d'une certaine lisibilité.
The list may be added to
peut être à nouveau quelque chose dont vous seriez averti si vous exposiez une telle fonctionnalité de l'interface utilisateur. Si vous êtes préoccupé par la réorganisation d'éléments modifiant l'identifiant, propagez à nouveau une telle modification vers tous les enregistrements dépendants. De même à ci-dessus. Une autre option (suivant la convention de normalisation appropriée, serait d’avoir une colonne enum / id et de faire référence à unFruitDetail
tableau plus détaillé , qui contient une colonne 'Order' que vous pouvez rechercher).De toute façon, vous pouvez voir que je suggère de contrôler l’amendement ou la mise à jour de votre liste. Que vous le fassiez par le biais d'un ORM ou de tout autre accès aux données, il est déterminé par les spécificités de votre technologie. Ce que vous êtes essentiellement en train de faire est d’exiger que les personnes qui s’éloignent de la DB pour de tels changements - ce qui me convient. La plupart des principaux CRM feront la même exigence.
la source
Un problème très commun. La duplication du côté client de données peut sembler violer les principes de DRY , mais cela est dû à la différence de paradigme entre les couches.
Avoir l'énumération (ou quoi que ce soit) en décalage avec la base de données n'est pas si rare en plus. Vous avez peut-être transféré une autre valeur dans une table de métadonnées pour prendre en charge une nouvelle fonctionnalité de rapport qui n'est pas encore utilisée dans le code côté client.
Cela se produit parfois aussi dans l'autre sens. Une nouvelle valeur enum est ajoutée côté client, mais la mise à jour de la base de données ne peut avoir lieu tant que l'administrateur de base de données n'a pas appliqué les modifications.
la source
En supposant que nous parlions de ce qui est essentiellement une recherche statique, la troisième option - l'énumération - est fondamentalement le seul choix sensé. C'est ce que vous feriez si la base de données n'était pas impliquée, alors c'est logique.
La question devient alors celle de savoir comment garder synchronisés les énumérations et les tables statiques / de recherche dans la base de données. Malheureusement, ce n’est pas un problème pour lequel je dispose d’une réponse complète.
Par choix, je fais toute la maintenance de mon schéma en code et je peux donc garder une relation entre la construction de l'application et la version attendue du schéma, il est donc simple de garder la recherche et l'enum synchronisés, faire. Ce serait mieux s'il était plus automatisé (et également un test d'intégration automatisé pour s'assurer que les énumérations et les correspondances aideraient), mais ce n'est pas quelque chose que j'ai implémenté.
la source