Sollten für eine ORM-unterstützende Datenvalidierung Einschränkungen auch in der Datenbank erzwungen werden?

13

Zusätzlich zu meinen (ActiveRecord-) Modellen habe ich immer Einschränkungen auf Datenbankebene angewendet. Aber ich habe mich gefragt, ob dies wirklich erforderlich ist?

Ein bisschen Hintergrund

Vor kurzem musste ich eine grundlegende automatisierte Zeitstempel-Generierungsmethode für ein Modell testen. Normalerweise würde der Test eine Instanz des Modells erstellen und es ohne Validierung speichern. Es gibt jedoch auch andere erforderliche Felder, die in der Tabellendefinition nicht nullwertfähig sind. Dies bedeutet, dass ich die Instanz nicht speichern kann, selbst wenn ich die ActiveRecord-Validierung überspringe. Ich überlege mir also, ob ich solche Einschränkungen aus der Datenbank selbst entfernen und den ORM damit umgehen lassen soll.

Mögliche Vorteile, wenn ich Einschränkungen in db, imo - überspringe

  • Kann eine Validierungsregel im Modell ändern, ohne die Datenbank migrieren zu müssen.
  • Kann die Validierung beim Testen überspringen.

Möglicher Nachteil?

Wenn es jedoch möglich ist, dass die ORM-Validierung fehlschlägt oder umgangen wird, prüft die Datenbank nicht, ob Einschränkungen vorliegen.

Was denkst du?

BEARBEITEN In diesem Fall verwende ich das Yii-Framework , das das Modell aus der Datenbank generiert. Daher werden auch Datenbankregeln generiert (obwohl ich sie auch nach der Generierung schreiben könnte).

n / a
quelle
3
Wenn Daten in Ihrer Datenbank routinemäßig ohne Verwendung Ihres ORM geändert werden können (andere Apps ohne Ihr ORM oder, schlimmer noch, direkter Datenbankzugriff durch Benutzer), muss sich die Validierung tatsächlich in der Datenbank befinden.
Marjan Venema

Antworten:

16

Ihr Leitsatz sollte sein, sich nicht zu wiederholen :

In der Softwareentwicklung ist Don't Repeat Yourself (DRY) ein Prinzip der Softwareentwicklung, das darauf abzielt, die Wiederholung von Informationen aller Art zu reduzieren, insbesondere in mehrschichtigen Architekturen. Das DRY-Prinzip lautet: "Jedes Wissen muss eine einzige, eindeutige und maßgebliche Repräsentation innerhalb eines Systems haben."

Das ORM ist im Wesentlichen eine zusätzliche Schicht (oder Schicht, wenn Sie es vorziehen), die sich bequem zwischen Ihrer Anwendung und Ihren Datenspeichern befindet. Ihre Einschränkungen sollten sich an einem Ort und nur an einem Ort befinden, sei es im ORM oder im Datenspeicher. Andernfalls werden Sie in Kürze verschiedene Versionen von diesen beibehalten. Das willst du wirklich nicht.

In der Praxis generieren die meisten halbwegs vernünftigen ORMs jedoch automatisch einen Großteil Ihrer Modelle aus Ihrem Datenschema. Obwohl es immer noch Duplikate gibt, ist die Wahrscheinlichkeit für Wartungsarbeiten gering, da der duplizierte ORM-Code jedes Mal nach demselben Muster generiert wird. Es wäre ideal, keinen doppelten Code zu haben, aber automatisch generierte Einschränkungen sind das zweitbeste.

Wenn Sie Ihre Einschränkungen an einem Ort haben, bedeutet dies nicht unbedingt, dass Sie alle Einschränkungen an demselben Ort haben sollten. Einige, wie Einschränkungen der referenziellen Integrität, sind möglicherweise besser für den Datenspeicher geeignet (gehen jedoch möglicherweise verloren, wenn Sie in einen anderen Datenspeicher wechseln), und andere, vor allem solche, bei denen es um komplexe Geschäftslogik geht, eignen sich besser für Ihren ORM. Es wäre besser, alle Äpfel in einem Korb zu haben, aber ...

Ausfälle

Sie erwähnen den ORM-Fehler. Dies ist für Ihre Frage absolut irrelevant. Ihre Anwendung sollte den ORM und die Datenspeicher als eine Einheit betrachten. Wenn dies fehlschlägt, schlägt dies fehl. Es ist keine gute Idee , den ORM zu umgehen, um direkt mit dem Datenspeicher zu kommunizieren .

Umgehen des ORM für alles andere

Auch keine gute Idee. Dies kann jedoch verschiedene Gründe haben:

  1. Ältere Teile der Anwendung, die vor der Einführung des ORM erstellt wurden.

    Das ist eine schwierige Frage , und genau die Situation , die ich mit zu tun habe gerade jetzt , daher meine ständige Wiederholung von „Wartung Hölle“. Entweder behalten Sie die Nicht-ORM-Teile bei oder Sie schreiben sie neu, um das ORM zu verwenden. Die zweite Option ist anfangs vielleicht sinnvoller, aber es ist eine Entscheidung, die ausschließlich davon abhängt, was genau diese Teile Ihrer Anwendung tun und wie wertvoll ein vollständiges Umschreiben auf lange Sicht sein würde.

    Wenn Sie versuchen, einen Schlüssel in einer schlecht gestalteten MySQL-Tabelle mit 2 * 10 ^ 8 Zeilen zu ändern (ohne Ausfallzeiten), werden Sie verstehen, woher ich komme.

  2. Nicht ältere Teile der Anwendung, die unbedingt direkt mit dem Datenspeicher kommunizieren müssen:

    Noch kniffliger. ORMs sind ausgefallene Tools und kümmern sich um fast alles, aber manchmal stören sie einfach oder sind sogar völlig nutzlos. Das Schlagwort (buzzphrase wirklich) ist objektrelationale Impedance Mismatch , einfach ausgedrückt , es ist technisch nicht möglich Ihre ORM zu tun alles , was Ihre relationale Datenbank tut, und für einige der Dinge , die sie tun, gibt es eine erhebliche Leistungseinbuße.

Bemerkungen

Unter dem Gesichtspunkt der Datenintegrität MÜSSEN sich Einschränkungen auf die Datenbank und SOLLTEN sich auf die Anwendung beziehen. Was passiert, wenn auf Ihre Anwendung über eine Web- und eine Desktop-Anwendung, eine mobile App oder einen Webservice zugegriffen wird? - Luiz Damim

Hier wäre das Hinzufügen einer zusätzlichen Ebene äußerst hilfreich. Wenn es sich um eine Webanwendung handelt, würde ich eine REST-API verwenden. Ein allzu simpler Entwurf dafür wäre:

Bildbeschreibung hier eingeben

Der ORM würde sich zwischen der API und den Datenspeichern befinden, und alles, was hinter der API (einschließlich der API) steckt, würde als eine Einheit aus den verschiedenen Anwendungen betrachtet.

yannis
quelle
Normalerweise definieren Sie in Ihrem ORM ein Schema, das dann in die Datenbank gespiegelt wird, sodass Sie eine zweite Sicherheitsebene haben.
Josh K
2
@JoshK Du sagst zweite Stufe der Gewissheit, ich sage Wartungshölle. Das heißt aber nicht, dass Sie nicht Recht haben ...
yannis
Macht Sinn. Ich folge jetzt dieser Route. Vielen Dank!
na
1
Sobald Sie den Punkt überschritten haben, an dem ein oder zwei Entwickler Code- und Datenbankarbeiten ausführen , wird dies zu einem notwendigen Übel. Wenn Sie ein gutes ORM verwenden, werden auch Migrationen für Sie generiert. Wenn Sie zu einem Punkt heranwachsen, an dem Sie einen dedizierten DBA haben, führt kein Weg daran vorbei. Sie lassen keine Tabellen ohne Einschränkungen herumfließen. Eine einfache Möglichkeit, um zu verhindern, dass sich Personen ohne E-Mail anmelden, besteht darin, die Speicherebene einzuschränken.
Josh K
1
Unter dem Gesichtspunkt der Datenintegrität MÜSSEN sich Einschränkungen auf die Datenbank und SOLLTEN sich auf die Anwendung beziehen. Was passiert, wenn auf Ihre Anwendung über eine Web- und eine Desktop-Anwendung, eine mobile App oder einen Webservice zugegriffen wird?
Luiz Damim
20

Dies ist eine sehr schwer zu beantwortende Frage, und ich habe festgestellt, dass sie ein sehr kontroverses Thema ist.

Wie Yannis Rizos in seiner Antwort betonte, würde das Vorhandensein der Einschränkungslogik sowohl in der Datenbank als auch in der ORM-Ebene gegen DRY verstoßen, was "zu Albträumen bei der Wartung, schlechtem Factoring und logischen Widersprüchen führen kann".

Das Entfernen der Einschränkungslogik aus der Datenbank und das Beibehalten der Einschränkungslogik nur auf der ORM-Ebene funktionieren jedoch nicht, wenn eine der folgenden Bedingungen vorliegt:

  1. Manuelle DB-Updates (scheinen in jedem Unternehmen vorzukommen)

  2. DB-Aktualisierungen von einem anderen System, das die ORM-Einschränkungslogik nicht immer problemlos gemeinsam nutzen kann (z. B. ein Perl-Skript, das Routineaufgaben ausführt, wenn die ORM-Schicht im Ruhezustand implementiert ist und von einer Java-Anwendung für alltägliche Aktivitäten verwendet wird)

Dies würde bedeuten, dass Sie der DB nur die Einschränkungslogik hinzufügen und aus Ihrer ORM-Ebene entfernen , um eine DRY-Verletzung zu verhindern. Dies kann jedoch zu Fällen führen, in denen der Anwendungscode das tatsächliche Problem nicht erfolgreich erfassen und an den Benutzer weiterleiten kann (obwohl dies als Entwickler, der das Problem debuggt, höchstwahrscheinlich der Fall ist). Dies ist für einige Projekte möglicherweise nicht akzeptabel.

Ihre letzte Option besteht darin, die Erstellung der Integritätsbedingungen im ORM (und in jedem anderen System) aus den DB-Integritätsbedingungen (oder wirklich ... umgekehrt) zu automatisieren . Obwohl Sie letztendlich zwei oder mehr Implementierungen der Einschränkungen haben werden, stellt dies keine Verletzung des DRY-Prinzips dar, wie in "The Pragmatic Programmer" beschrieben, da diese die Verwendung der Codegenerierung empfehlen, um DRY-Verstöße zu vermeiden. Dies ist natürlich nicht so einfach, da zum Beispiel jede Änderung an einer DB-Einschränkung eine Neuerstellung und erneutes Bereitstellen aller Anwendungen erzwingen kann, die sie verwenden (nicht trivial für die Automatisierung).

Eigentlich müsste es von Fall zu Fall bewertet werden . Ich kann Ihnen sagen, dass mir bis jetzt leere Blicke begegnet sind, wenn ich vorschlage, dass die Beschränkungslogik nicht wiederholt wird.

smp7d
quelle
2
Bin gerade von der Arbeit gegangen und habe darüber nachgedacht, meine Antwort auf mehr oder weniger das zu erweitern, was du gerade gepostet hast. Gute Antwort!
Yannis
3

Ich würde der Datenbank definitiv Einschränkungen als Standardoption hinzufügen. Dies liegt daran, dass für ein Unternehmen Daten im Vordergrund stehen und die Datenqualität im Vordergrund steht. @Yannis Rizos brachte das DRY-Prinzip in die Diskussion ein. Nun, ein weiteres Prinzip ist die Tiefenverteidigung. Für Daten würde ich dieses Prinzip verwenden.

Ich habe in echten Unternehmen gearbeitet, in denen die DB vor 30 Jahren Daten erstellt hat. Es wurde und wird von COBOL-Anwendung und jetzt von einer .Net-Anwendung zugegriffen. In 10 Jahren kann es eine Anbieter-App sein, wer weiß. Es kam zu einem Zusammenschluss, und Millionen von Datenzeilen wurden konvertiert und mithilfe von SQL von der anderen Firma in diese Datenbank migriert. Kein ORM kann dies tun. Fazit: Daten bleiben, Anwendungen ändern sich, Art und Weise, wie Daten generiert werden, ändern sich. Warum also nicht das Risiko einer Datenbeschädigung verringern?

softveda
quelle
2

Ich denke, Sie tun beides in gewissem Maße.

  • Die Hauptbeschränkungen sollten in den ORM-Programmiersprachen liegen. Sie sind viel flexibler, lassen sich leichter testen und optimieren, wenn sich die Anforderungen ändern. Sie müssen sich zumindest keine Gedanken über DDL-Korrekturen machen. Und Sie vermeiden im Allgemeinen schwer zu testende Probleme mit der Datenregression.

  • Einige sehr harte und schnelle Einschränkungen sollten auch in der Datenbank vorhanden sein. Ich spreche zum Beispiel nicht von nicht nullbaren Namen. Ich spreche von Dingen wie der referentiellen Integrität oder der Anforderung von absolut entscheidenden Kennungen. Strukturelle Anforderungen, damit Ihr Code sich nicht mit "Was ist, wenn die Bestellung ein nicht vorhandenes Produkt enthält" befassen muss.

Wyatt Barnett
quelle
1

Die Datenbank ist IMO der einzige Ort, an dem DRY verletzt werden kann, denn wenn etwas Ihren ORM umgeht und schlechte Daten enthält, ist es das. Spiel ist aus. Korrupte Daten sind der Todesstoß.

Wayne Molina
quelle
Nur Datenbank? Ich kann mir viele Fälle vorstellen, in denen das mit Daten verbundene Verhalten auf mehreren Ebenen (logisch oder physisch) vorliegen sollte, auch wenn die Daten überhaupt nicht beibehalten werden. Manchmal ist es möglich, einen einzelnen Quellcode zu haben und die "Duplizierung" auf die bereitgestellten DLLs zu reduzieren.
mike30