Dicke Modelle Vs. Business Logic, wo machen Sie den Unterschied?


16

Heute war ich mit einem anderen Entwickler in meiner Organisation in einer hitzigen Debatte darüber, wo und wie Methoden zu Klassen mit Datenbankzuordnung hinzugefügt werden können. Wir verwenden sqlalchemy, und ein Großteil der vorhandenen Codebasis in unseren Datenbankmodellen besteht aus kaum mehr als einer Menge zugeordneter Eigenschaften mit einem Klassennamen, einer nahezu mechanischen Übersetzung von Datenbanktabellen in Python-Objekte.

In dem Argument war meine Position, dass der Hauptwert der Verwendung eines ORM darin bestand, dass Sie den zugeordneten Klassen Verhalten und Algorithmen auf niedriger Ebene zuordnen können. Modelle sind erstens Klassen und zweitens beständig (sie könnten unter Verwendung von XML in einem Dateisystem beständig sein, Sie brauchen sich nicht darum zu kümmern). Seiner Ansicht nach ist jedes Verhalten "Geschäftslogik" und gehört notwendigerweise irgendwo anders als in das persistente Modell, das nur für die Datenbankpersistenz verwendet werden soll.

Ich bin sicher der Meinung, dass es einen Unterschied zwischen dem gibt, was Geschäftslogik ist, und dass dies getrennt werden sollte, da es eine gewisse Isolation von der unteren Ebene der Implementierung und der Domänenlogik gibt, die meiner Meinung nach die Abstraktion ist, die von den Modellklassen bereitgestellt wird Ich habe im vorigen Absatz darüber gestritten, aber es fällt mir schwer, den Finger auf das zu legen, was das ist. Ich habe ein besseres Gespür dafür, was die API sein könnte (was in unserem Fall HTTP "ReSTful" ist), indem Benutzer die API mit dem aufrufen, was sie tun möchten, und zwar unabhängig davon , was und wie sie tun dürfen fertig.


tl; dr: Welche Art von Dingen kann oder sollte in einer Methode in einer zugeordneten Klasse ablaufen, wenn ein ORM verwendet wird, und was sollte ausgelassen werden, um in einer anderen Abstraktionsebene zu leben?


Es scheint mir, dass zwei Probleme gleichzeitig besprochen wurden, nämlich das Problem der Persistenz. Modelle sind erstens Klassen und zweitens persistent (sie könnten persistent sein, wenn Sie XML in einem Dateisystem verwenden, brauchen Sie sich nicht darum zu kümmern). und der Grund für den Code. Normalerweise klärt sich das zumindest für mich, wenn ich mich frage, warum der Code geschrieben ist, welche Anforderung diesen Code erzwingt. Ist es die Anforderung des Kunden, wie das Programm funktioniert, oder ist es die Art und Weise, wie wir es implementieren. Für mich ist das erste die Geschäftslogik und das zweite, was Sie als Domänenlogik bezeichnen. Wie das hilft.

Antworten:


10

Ich bin meistens bei dir; Ihr Kollege scheint entweder für das Antipattern des anämischen Domänenmodells zu streiten oder für das Duplizieren des Modells in ein "Persistenzmodell" ohne offensichtlichen Nutzen (ich arbeite an einem Java-Projekt, in dem dies getan wurde, und es bereitet massive Probleme mit der Wartbarkeit) es bedeutet das Dreifache der Arbeit, wenn sich etwas am Modell ändert.

Welche Dinge können oder sollten in einer Methode in einer zugeordneten Klasse ausgeführt werden, wenn ein ORM verwendet wird, und was sollte ausgelassen werden, um in einer anderen Abstraktionsebene zu leben?

Faustregel: Die Klasse sollte eine Logik enthalten, die grundlegende Fakten zu den Daten beschreibt, die unter allen Umständen wahr sind. Logik, die spezifisch für einen Anwendungsfall ist, sollte sich an einer anderen Stelle befinden. Ein Beispiel ist die Validierung. Es gibt einen interessanten Artikel von Martin Fowler, in dem er darauf hinweist, dass dies als kontextabhängig angesehen werden sollte.


+1 für den zweiten Teil Ihrer Antwort. Was den ersten Teil betrifft, ich bin mir sicher, warum Sie sagen, dass das anämische Domänenmodell im Falle einer Änderung so viel zusätzliche Arbeit erfordert. Ich verstehe, dass die Veränderung auf irgendeine Weise stattfinden wird, aber in mehreren verschiedenen Klassen (was irgendwie schlecht ist), aber es ist fast das gleiche Ausmaß an Veränderung; Ich vermute?
NoChance

1
@Emmad Kareem: Der Kommentar handelte von spearaten Persistenz- und Domänenmodellen. Das Hinzufügen einer Eigenschaft zum Modell erfordert dann das Hinzufügen zu zwei Modellklassen (und nicht zu einer) sowie zu allen zwischen ihnen liegenden Zuordnungen (dies könnte theoretisch automatisch erfolgen, aber normalerweise ist es der Asshat, der es für eine gute Idee hielt, eine separate zu haben Das "Persistenzmodell" beschließt, diese Trennung zu rechtfertigen, indem es sie voneinander unterscheidet (z. B. Datentypen, die dem DB-Typmodell besser entsprechen). Dies ist das 2-fache des Änderungsbetrags, wobei X zwischen 0 und Stunden Produktivitätsverlust aufgrund von Unklarheiten schwankt Mapping-Probleme.
Michael Borgwardt

3

Dies ist ein Urteilsspruch, der wirklich von Ihrer voraussichtlichen Größe und dem Umfang Ihrer Entwicklung abhängt. Der starrste Ansatz besteht darin, die ORM-Typen auf eine Datenzugriffskomponente zu beschränken und POCOs in einer gemeinsamen Bibliothek als Typen zu verwenden, die von allen Ebenen referenziert und verwendet werden. Dies würde eine zukünftige physische Trennung sowie eine logische Trennung ermöglichen. Sie können auch festlegen, dass eine zusätzliche Ebene zwischen der Benutzeroberfläche und der Geschäftslogikebene vorhanden sein soll. Dies wird normalerweise als Facade- oder Business Interface-Schicht bezeichnet. In dieser zusätzlichen Ebene befindet sich Ihr "Use-Case-Code". Der einzelne lose gekoppelte Code wird von der Facade / BI-Schicht aufgerufen (z. B. Facade hat eine ProcessOrder () -Funktion, die die Geschäftslogik 1: M-mal aufruft, um alle zur tatsächlichen Verarbeitung des Auftrags erforderlichen Schritte auszuführen).

Trotzdem: Vielfach ist diese Menge an Architektur einfach unnötiger Overkill. Codieren Sie beispielsweise speziell für eine einfache Website, auf der Sie die Komponenten nicht zur Wiederverwendung verpacken möchten. Es ist absolut richtig, eine MVC-Website zu erstellen und EF-Objekte für diese Art von Lösung zu verwenden. Wenn die Site später skaliert werden muss, können Sie sich mit Clustering oder einem häufig verlorenen Prozess namens "Refactoring" befassen.


3

Erinnern Sie Ihren Kollegen nur daran, dass Sie die Modelle nicht überarchitektonisch verändern müssen, als wäre dies ein Java-Projekt. Der Vergleich zweier persistenter Objekte ist ein Verhalten, das jedoch nicht durch die Persistenzschicht festgelegt wird. Die 6-Bier-Frage lautet also: Warum haben Klassen, die nichts miteinander zu tun haben, etwas über dasselbe beschrieben? Sicher, Beharrlichkeit ist ein wichtiger Aspekt eines Modells, der separat behandelt werden kann, aber nicht ausreichend, um zu gewährleisten, dass es unabhängig von allem anderen behandelt wird. Wenn Sie mit Ihrem Auto fahren, es waschen oder kaputt machen, manipulieren Sie Ihr Auto die ganze Zeit.

Warum also nicht einfach all diese verschiedenen Aspekte in einer einzigen Modellklasse zusammenfassen? Sie benötigen eine Reihe von Klassenmethoden, die sich mit dauerhaften Objekten befassen - ordnen Sie sie einer Klasse zu. Sie haben eine Reihe von Instanzmethoden, die sich mit der Validierung befassen - fügen Sie sie in eine andere ein. Zum Schluss mischen Sie die beiden in und voila! Sie haben sich genau dort eine intelligente, selbstbewusste und umfassende Modelldarstellung verschafft.


1

Achten Sie neben anderen Antworten auf versteckte Cavehats, wenn Sie Rich Domain-Modelle mit einem ORM verwenden.

Ich hatte Probleme beim Injizieren von polymorphen Diensten in die beständigen Modellklassen, als ich versuchte, so etwas wie den folgenden Pseudocode zu erzielen:

Person john = new Person('John Doe')
Organisation company = organisation_repository.find('some id')
Employee our_collegue_john = company.hire(john)

In diesem Fall kann eine Organisation HRServicebeispielsweise eine Abhängigkeit als Konstruktor benötigen . Normalerweise können Sie die Instanziierung Ihrer Modellklassen bei Verwendung eines ORM nicht einfach steuern.

Ich habe Doctrine ORM und den Service-Container von Symfony verwendet. Ich musste den ORM auf eine weniger elegante Weise monkeypatchen und hatte keine andere Wahl, als Persistenz und Geschäftsmodelle zu trennen. Ich habe es noch nicht mit Sqlachemy versucht, dachte ich. Python könnte sich für dieses Zeug als flexibler als PHP erweisen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.