Java >> Java Tutorial >  >> Tag >> Spring

Der größte Fehler von Spring-Webanwendungen

Die Entwickler, die Spring Framework in ihren Anwendungen verwenden, sprechen gerne über die Vorteile der Abhängigkeitsinjektion.

Leider sind sie nicht so gut darin, die Vorteile wie das Prinzip der einzigen Verantwortung und die Trennung von Interessen in ihren Anwendungen zu nutzen.

Wenn wir uns eine von Spring betriebene Webanwendung ansehen, stehen die Chancen gut, dass die Anwendung unter Verwendung dieser gemeinsamen und gleichermaßen fehlerhaften Designprinzipien implementiert wird:

  1. Die Domänenmodellobjekte werden nur zum Speichern der Daten der Anwendung verwendet. Mit anderen Worten, das Domänenmodell folgt dem Antimuster des anämischen Domänenmodells.
  2. Die Geschäftslogik liegt in der Serviceschicht, die die Daten der Domänenobjekte verwaltet.
  3. Die Dienstschicht hat eine Dienstklasse für jede Entität der Anwendung.

Die Frage ist:

Wenn das so häufig vorkommt, wie kann es falsch sein?

Finden wir es heraus.

Alte Gewohnheiten sterben schwer

Der Grund, warum Spring-Webanwendungen so aussehen, ist, dass die Dinge schon immer so gemacht wurden und alte Gewohnheiten nur schwer abzulegen sind, insbesondere wenn sie von erfahrenen Entwicklern oder Softwarearchitekten durchgesetzt werden.

Das Problem ist, dass diese Leute sehr gut darin sind, ihre Meinung zu verteidigen. Eines ihrer Lieblingsargumente ist, dass unsere Anwendung dem Grundsatz der Trennung von Bedenken folgt, da sie in mehrere Schichten unterteilt wurde und jede Schicht spezifische Verantwortlichkeiten hat.

Eine typische Spring-Webanwendung hat die folgenden Schichten:

  • Die Webebene die für die Verarbeitung der Benutzereingaben und die Rücksendung der korrekten Antwort an den Benutzer verantwortlich ist. Der Web-Layer kommuniziert nur mit dem Service-Layer.
  • Die Dienstschicht die als Transaktionsgrenze fungiert. Es ist auch für die Autorisierung zuständig und enthält die Geschäftslogik unserer Anwendung. Die Dienstschicht verwaltet die Domänenmodellobjekte und kommuniziert mit anderen Diensten und der Repository-Schicht.
  • Die Repository-/Datenzugriffsschicht die für die Kommunikation mit dem verwendeten Datenspeicher verantwortlich ist.

Der Grundsatz der Trennung von Interessen wird wie folgt definiert:

Separation of Concerns (Soc) ist ein Gestaltungsprinzip zur Unterteilung eines Computerprogramms in verschiedene Abschnitte, sodass jeder Abschnitt ein separates Anliegen behandelt.

Obwohl es stimmt, dass eine typische Spring-Webanwendung diesem Prinzip in gewisser Weise folgt, ist die Realität, dass die Anwendung eine monolithische Serviceschicht hat, die zu viele Verantwortlichkeiten hat.

Genauer gesagt hat die Dienstschicht zwei Hauptprobleme:

Zunächst wird die Geschäftslogik der Anwendung auf der Dienstebene gefunden.

Dies ist ein Problem, da die Geschäftslogik über die Dienstschicht verstreut ist. Wenn wir überprüfen müssen, wie eine bestimmte Geschäftsregel implementiert ist, müssen wir sie zuerst finden. Das ist vielleicht nicht einfach.

Wenn dieselbe Geschäftsregel in mehreren Serviceklassen benötigt wird, besteht die Chance, dass die Regel einfach von einem Service auf einen anderen kopiert wird. Dies führt zu einem Wartungsalptraum.

Zweitens hat die Dienstebene eine Dienstklasse für jede Domänenmodellklasse.

Dies verstößt gegen das Single-Responsibility-Prinzip, das wie folgt definiert ist:

Das Single-Responsibility-Prinzip besagt, dass jede Klasse eine einzige Verantwortung haben sollte und dass die Verantwortung vollständig von der Klasse gekapselt werden sollte. Alle seine Dienste sollten eng an dieser Verantwortung ausgerichtet sein.

Die Dienstklassen haben viele Abhängigkeiten und viele zirkuläre Abhängigkeiten. Die Dienstschicht einer typischen Spring-Webanwendung besteht nicht aus lose gekoppelten Diensten, die nur eine Verantwortung haben. Es ist eher ein Netz aus eng gekoppelten und monolithischen Diensten.

Dadurch ist es schwer zu verstehen, zu pflegen und wiederzuverwenden.

Das mag etwas hart klingen, aber die Serviceschicht ist oft der problematischste Teil einer Spring-Webanwendung.

Zum Glück für uns ist nicht alle Hoffnung verloren.

Befreiung

Die aktuelle Situation ist schlecht, aber nicht völlig hoffnungslos. Lassen Sie uns herausfinden, wie wir uns von alten Gewohnheiten befreien können.

Zunächst müssen wir die Geschäftslogik unserer Anwendung von der Dienstschicht in die Domänenmodellklassen verschieben.

Warum dies sinnvoll ist, sollte uns klar werden, wenn wir an folgendes Beispiel denken:

Nehmen wir an, ich bin eine Dienstklasse und Sie ein Domänenmodellobjekt. Wenn ich dir sage, dass du von einem Dach springen sollst, würdest du es vorziehen, ein Vetorecht zu meiner Entscheidung zu haben?

Die Verlagerung der Geschäftslogik von der Dienstschicht in die Domänenmodellklassen bietet uns drei Vorteile:

  1. Die Verantwortlichkeiten unseres Kodex sind logisch aufgeteilt. Die Serviceschicht kümmert sich um die Anwendungslogik und unsere Domänenmodellklassen kümmern sich um die Geschäftslogik.
  2. Die Geschäftslogik unserer Anwendung findet sich an einem einzigen Ort. Wenn wir überprüfen müssen, wie eine bestimmte Geschäftsregel implementiert wird, wissen wir immer, wo wir suchen müssen.
  3. Der Quellcode der Serviceschicht ist sauberer und enthält keinen Copy-Paste-Code.

Zweitens müssen wir die unternehmensspezifischen Dienste in kleinere Dienste unterteilen, die nur einem einzigen Zweck dienen.

Wenn unsere Anwendung beispielsweise eine einzige Dienstklasse hat, die CRUD-Vorgänge für Personen und Vorgänge im Zusammenhang mit Benutzerkonten bereitstellt, sollten wir sie in zwei separate Dienstklassen unterteilen:

  • Der erste Dienst stellt CRUD-Operationen für Personen bereit.
  • Der zweite Dienst stellt Vorgänge bereit, die sich auf Benutzerkonten beziehen.

Das gibt uns drei große Vorteile:

  1. Jede Dienstklasse hat einen logischen Satz von Verantwortlichkeiten.
  2. Jede Dienstklasse hat weniger Abhängigkeiten, was bedeutet, dass sie keine eng gekoppelten Giganten mehr sind. Sie sind kleinere und lose gekoppelte Komponenten.
  3. Die Dienstklassen sind einfacher zu verstehen, zu warten und wiederzuverwenden.

Diese zwei einfachen Schritte helfen uns, die Architektur unserer Anwendung zu bereinigen und die Produktivität und Zufriedenheit unserer Entwicklerkollegen zu steigern.

Nun fragen wir uns vielleicht, ob all dies wirklich notwendig ist und wenn ja, wann es wichtig ist, diese Probleme anzugehen?

Manchmal ist das Leben schwarz und weiß

Ich habe oft ein Argument gehört, dass wir der "Architektur" nicht viel Aufmerksamkeit schenken sollten, weil unsere Anwendung klein und einfach ist. Obwohl dieses Argument etwas Wahres enthält, müssen wir uns daran erinnern, dass ein Projekt, das klein anfängt, zu etwas viel Größerem heranwachsen kann.

Wenn wir das nicht berücksichtigen, wenn es passiert, sind wir am Arsch.

Das Segeln in unbekannten Gewässern mag wie eine schlechte Idee klingen, aber wir müssen uns daran erinnern, dass die Titanic auf einer vertrauten Route segelte, als sie von einem Eisberg getroffen wurde, der sie versenkte. Das Gleiche könnte gerade mit unserer Anwendung passieren.

Wir müssen den Mut haben, STOP zu rufen wenn die Dinge außer Kontrolle geraten.

P.S. Wenn Sie bereit sind, die rote Pille zu nehmen, empfehle ich Ihnen, Whoops! Where did my architecture go von Olivier Gierke (oder sehen Sie sich seine SpringOne2GX-Präsentation zum gleichen Thema an). Aber Vorsicht, das Kaninchenloch geht viel tiefer als Sie denken.


Java-Tag