Existe-t-il des exemples d'approches non CRUD?

14

Je suis programmeur mais j'ai également travaillé comme archiviste. En tant qu'archiviste, il s'agit surtout de conserver les données.

J'ai souvent des disputes avec des collègues quand il s'agit d'opérations sur les données. Je n'aime pas trop le U et le D dans CRUD. Plutôt que de mettre à jour un enregistrement, je préfère en ajouter un nouveau et avoir une référence à l'ancien enregistrement. De cette façon, vous construisez une histoire de changements. Je n'aime pas non plus supprimer des enregistrements, mais plutôt les marquer comme inactifs.

Y a-t-il un terme pour cela? Fondamentalement, uniquement créer et lire des données? Y a-t-il des exemples de cette approche?

Pieter B
la source
1
Is there a term for this? Basically only creating and reading data?Bien sûr, il y a: CR; P
yannis
7
Du point de vue de l'utilisateur, c'est toujours CRUD. Je ne connais pas d'étiquettes spécifiques pour ce style d'implémentation, mais je pense que cela est courant dans de nombreuses applications. (Stack Exchange est un bon exemple ...)
Mark E. Haase
Vous voudrez peut-être regarder une conférence intitulée Le décalage d'impédance est notre faute .
Anton Barkovsky
+1 À un moment donné, quelqu'un va vouloir des rapports et il est très difficile de créer des rapports sur des données qui n'existent pas car elles ont été "mises à jour". Je trouve votre approche très prospective.
Chuck Conway
2
Vous pouvez également regarder une conférence sur Datomic: infoq.com/presentations/The-Design-of-Datomic
Marjan Venema

Réponses:

16

Le marquage d'un enregistrement comme supprimé est appelé suppression en douceur . Je n'ai jamais entendu de phrase alternative pour la mise à jour, mais je suppose que c'est parce que vous supprimez en douceur l'ancien enregistrement et en créez un nouveau.

Il convient de noter qu'il s'agit d'une technique controversée. Voir les liens: Con vs Pro .

pdr
la source
11

L'un des problèmes liés à la conservation d'un historique des modifications est qu'il encombre la base de données et peut considérablement augmenter sa taille (en fonction des modèles d'utilisation). Par conséquent, une bonne idée serait de stocker la piste d'audit dans un endroit séparé et de conserver les tables d'application réelles uniquement avec les données pertinentes. Ainsi, chaque fois qu'une opération CRUD est effectuée par l'application, la modification est enregistrée dans les tables d'audit et l'opération CRUD est effectuée sur les tables d'application (pas de suppression logicielle).

En gardant la piste d'audit séparée, vous disposez d'un magasin de données vierge avec lequel votre application peut interagir, tout en conservant l'historique des modifications si vous en avez besoin. Vous pouvez également désormais archiver la piste d'audit séparément ou même la détruire, selon les besoins de votre entreprise.

Système hors service
la source
3
Cette. De plus, l'intégrité référentielle devient un cauchemar; vous ne pouvez pas spécifier une clé étrangère pour "le seul enregistrement de cette table avec cette clé non unique qui n'est pas marquée comme supprimée". Vous contournez cela en conservant les données de la copie d'un enregistrement qui est sur le point d'être mis à jour dans une autre table, avant de mettre à jour cette "copie de travail" avec les nouvelles données, mais vous avez encore un gros volume de données à gérer.
KeithS
5

EventSourcing ressemble au modèle que vous recherchez peut-être.

Prenons un exemple en utilisant un simple objet "voiture" dont nous voudrions garder la trace de la couleur (un pseudo code C # suit).

public class Car {
  public string Color { get; set; }
  public Car() { this.Color = "Blue"; }
}

Avec une implémentation CRUD lorsque nous mettons à jour la couleur de la voiture, la couleur précédente serait perdue.

MyCar.Color = "Red";
MyCar.Save();  // Persist the update to the database and lose the previous data

Cette perte d'informations me semble être ce que vous aimeriez éviter le plus (d'où l'aversion pour la mise à jour et la suppression d'une partie du modèle CRUD).

Si nous devions réécrire la classe de voiture pour répondre aux événements lors de la mise à jour de sa modification, cela pourrait ressembler à ceci:

public class Car {
    public string Color { get; private set; } // Cannot be set from outside the class

    public void ApplyEvent(CarColorChangedEvent e) {
      this.Color = e.Color;
    }
}

Maintenant, comment pourrions-nous mettre à jour la couleur de cet objet? Nous pourrions créer un événement CarColorChanged !

var evnt = new CarColorChangedEvent("Red");
MyEventStore.save(evnt);
MyCar.ApplyEvent(evnt);

Remarquez l'absence d'une sauvegarde sur l'objet de modèle réel? En effet, au lieu de persister directement le modèle, nous persistons les événements qui mettent le modèle à l'état actuel. Ces événements devraient être immuables .

Maintenant, avançons rapidement et changeons la couleur plusieurs fois:

var evnt = new CarColorChangedEvent("Green");
MyEventStore.save(evnt);
MyCar.ApplyEvent(evnt);

var evnt = new CarColorChangedEvent("Purple");
MyEventStore.save(evnt);
MyCar.ApplyEvent(evnt);

Si nous regardions notre stockage d'événements (pourrait être une base de données de relations, basée sur un fichier, etc.), nous verrions une série d'événements liés à notre objet voiture:

CarColorChangedEvent => Red
CarColorChangedEvent => Green
CarColorChangedEvent => Purple

Si nous voulions reconstruire cet objet de voiture, nous pourrions le faire simplement en créant un nouvel objet de voiture et en appliquant les événements de notre magasin d'événements audit objet.

var MyCar = new Car();
var events = MyDatabase.SelectEventsForCar("CarIdentifierHere");
foreach(var e in events) {
  MyCar.ApplyEvent(e);
}
Console.WriteLine(MyCar.Color); // Purple

Avec le flux d'événements, nous pouvons restaurer l'état de la voiture à une période antérieure simplement en créant un nouvel objet voiture et en appliquant uniquement les événements que nous voulons:

var MyCar = new Car();
var event = MyDatabase.GetFirstEventForCar("CarIdentifierHere");
MyCar.ApplyEvent(e);
Console.WriteLine(MyCar.Color); // Red
Mike
la source
5

Event Sourcing est la voie à suivre, et vous devriez jeter un œil à ce que Greg Young a à dire à ce sujet.

http://goodenoughsoftware.net/

Jetez également un œil à cette présentation sur sa base de données (Event Store). Vous pouvez également trouver d'autres vidéos.

http://oredev.org/2012/sessions/a-deep-look-into-the-event-store

Je n'irais pas pour la réponse "soft-deletes" à moins que vous n'ayez spécifiquement besoin de pouvoir rechercher des éléments supprimés, mais alors vous ne devriez pas les considérer comme supprimés mais plutôt archivés. Je pense que la terminologie est assez importante ici.

Je ne voudrais pas non plus conserver une "table des versions". Toutes les "tables de version" que j'ai jamais vues (y compris celle que j'essaie de nettoyer en ce moment - 7 ans de données corrompues à cause de bugs ... et aucun moyen de récupérer cela même si nous avons des données historiques .. . parce que c'est tout aussi corrompu) finit par être corrompu en raison de bogues dans le code et à la fin vous perdez toujours des données parce que vous ne pouvez jamais revenir en arrière et recréer les données que la corruption a gâché.

Avec le modèle de sourcing d'événements, ce n'est pas le cas. Vous pouvez toujours rejouer exactement ce que l'utilisateur a fait. C'est la différence très importante entre CRUD et Event Sourcing. L'architecture Event Sourcing enregistre les événements dans un magasin d'événements, et non les objets de données ou les objets de modèle de domaine. Un événement peut facilement affecter plusieurs objets. Pensez simplement à une solution de panier d'achat où vous convertissez chaque article du panier d'achat en une commande réelle. Un événement affecte tous les objets d'article ainsi que les objets du panier, qui sont transformés en objet de commande.

Si vous avez conservé une copie versionnée de chaque ligne dans chaque table de la base de données, alors imaginez l'horreur d'avoir à revenir en arrière à un horodatage spécifique, sans parler de la quantité insensée d'espace et de surcharge de performances dans la maintenance de cette table de version.

Avec Event Sourcing, vous pouvez facilement rembobiner, en rejouant simplement les événements jusqu'à un certain moment. Des avances rapides peuvent être mises en place en utilisant des instantanés, mais c'est une question d'implémentation.

Mais le véritable avantage que je pense que vous aimerez, étant donné que vous êtes particulièrement intéressé à ne pas perdre de données, est que si vous découvrez un bogue dans le code qui enregistre ces données, vous n'avez pas besoin de revenir en arrière et de nettoyer les données (ce qui est souvent impossible car les données ne sont presque jamais complètes). Au lieu de cela, corrigez le bug et rejouez tous les événements. Ensuite, vous aurez une base de données avec de belles données correctes.

En cas de débogage, à quelle fréquence avez-vous demandé à l'utilisateur de vous dire ce qu'il a fait ... pourquoi ne pas simplement rejouer ce qu'il a fait et parcourir ensuite le code! Assez chouette hein.

J'espère que cela t'aides.

Jay Pete
la source
2

Pas précisément votre exemple, mais dans les anciens systèmes financiers, vous disposiez d'un stockage WORM . Si vous aviez besoin de "mettre à jour", vous avez écrit un nouvel enregistrement et vous avez toujours fait référence au dernier enregistrement comme actuel mais aucune donnée validée ne pourrait jamais être écrasée.

Beaucoup de gens ont repris cette idée dans les systèmes ultérieurs. J'ai entendu ce que vous décrivez appelé tables WORM, mais seulement dans ces cercles.

Facture
la source
2

Oui, c'est assez courant dans les systèmes d'entreprise, il existe essentiellement deux approches: -

  • "bi - temporel" dans lequel chaque enregistrement a un horodatage valide à partir de et valide (l 'enregistrement "actuel" ayant une date valide de "pour toujours" - nul, "9999-12-31" ou une valeur élevée). Les enregistrements ne sont jamais supprimés à la place, la date "valide pour" est définie à l'heure actuelle et dans le cas d'une mise à jour, un nouvel enregistrement est inséré avec un valide à partir de l'heure actuelle et une date toujours valide.
  • "table d'historique" - chaque fois qu'un enregistrement est modifié, une copie de l'ancien enregistrement est sauvegardée dans une table d'historique / journal avec un horodatage pour l'événement.

Il existe de grandes variations de granularité pour les deux approches. Par exemple, si la quantité de widgets sur un article de commande est modifiée, conservez-vous l'historique de la commande entière ou seulement de cet article?

De manière générale, "bi-temporel" représente beaucoup de travail supplémentaire et ne vaut la peine que si vous avez de nombreux cas d'utilisation comme "l'auditeur obtient le statut de la commande au 31 décembre".

James Anderson
la source
-2

fondamentalement crud ne peut pas être achevé sans ces 4 choses. Crud signifie créer, lire, mettre à jour et supprimer, donc lorsque vous essayez seulement de lire des données, vous pouvez utiliser une requête simple pour cela, mais ces trois choses sont attachées à l'une et à l'autre et à des concepts simples de base de données

Tayyab Vohra
la source