Ich habe im Laufe der Jahre viele Entwickler gesehen, die das Repository-Muster mit Laravel verwendeten und versuchten, saubere Architekturkonzepte auf ihre Anwendungen anzuwenden, aber oft missverstanden sie das allgemeine Konzept der Verwendung eines Frameworks wie Laravel .
Bevor ich anfange und einigen Steinen ausweichen muss, von denen ich weiß, dass ihr sie mir in den Weg werfen könntet, möchte ich eines klarstellen: Dies ist meine Meinung als Software-Ingenieur, der mit mehreren Sprachen und Frameworks gearbeitet, Software von Grund auf neu erstellt hat usw Pflege alter Legacy-Codebasen. Mein Wort ist nicht endgültig, und wie immer glaube ich, dass die akzeptableste Antwort auf jede Frage zur Softwareentwicklung lautet: „Es hängt davon ab, welchen Kompromiss Sie bereit sind, um Ihr Problem zu lösen.“
Also, ohne weitere Umschweife, kommen wir zum Thema.
Clean Architecture ist eine Software-Design-Philosophie, die darauf abzielt, Systeme zu schaffen, die einfach zu warten, zu testen und zu verstehen sind. Es betont die Trennung von Belangen und die Schaffung von Grenzen zwischen verschiedenen Teilen des Systems, um sicherzustellen, dass sich Änderungen in einem Teil nicht negativ auf andere auswirken. Diese Architektur wurde von Robert C. Martin (Onkel Bob) populär gemacht und wird häufig verwendet, um die Organisation von Code so zu steuern, dass er gegenüber Änderungen der Geschäftsregeln oder technischen Anforderungen widerstandsfähig ist.
Kurz gesagt schlägt Bob vor, dass Ihre Anwendung in Schichten aufgeteilt werden sollte, die den Schlüsselprinzipien folgen, damit Ihre Geschäftslogik von externen Abhängigkeiten entkoppelt werden kann, sodass sie mobil sind und einen einzigen Verantwortungskontext haben. Aber dies wird kein Artikel über saubere Architektur sein; Ich wollte uns darüber nur auf den gleichen Stand bringen.
Bei Frameworks sprechen wir von einer engen Kopplung von Abhängigkeiten. Sie haben Laravel wahrscheinlich nicht ausgewählt, um Doctrine damit zu verwenden; Sie haben sich wahrscheinlich dafür entschieden, Eloquent zu verwenden. Das Gleiche gilt für alle Framework-Funktionen, die Sie möglicherweise finden – Sie wählen das Framework aus Gründen der Entwicklungsgeschwindigkeit und Bequemlichkeit aus.
Meine Frage lautet also: Warum sollten Sie etwas, das Sie als einfach ausgewählt haben, mit einer zusätzlichen Komplexitätsebene versehen?
Warten Sie, hassen Sie mich nicht dafür, dass ich das sage. Sie können mit Laravel immer noch eine saubere Architektur anpassen oder sogar verwenden, aber der wichtigste Aspekt jeder Architekturentscheidung ist ein klares Verständnis dafür, was Sie erreichen möchten und welche Vor- und Nachteile diese Entscheidungen haben.
Es ist eine schwere Entscheidung, und Sie können Ihre Meinung mitten in der Implementierung ändern. Software sollte nicht unveränderlich sein, oder? Ich habe einen ganzen Artikel über Softwarequalität, in dem ich diese Flagge hisse.
Wie auch immer, zurück zu Laravel und sauberer Architektur. Einer der nervigsten Ansätze ist meiner bescheidenen Meinung nach die Verwendung des Repository-Musters mit Eloquent, und das hat mich motiviert, diesen Artikel zu schreiben.
Das Repository-Muster ist ein Entwurfsmuster, das zwischen der Domänen- und der Datenzuordnungsschicht vermittelt und als speicherinterne Sammlung von Domänenobjekten fungiert. Ziel ist es, die Domänen- und Datenzuordnungsebenen zu entkoppeln.
Die Repository-Definition ist also eine Domäneneinheit. Warum? Weil es mit der Domäne interagiert und definiert, wie die Infrastruktur mit der Domäne interagiert, indem es als Vertrag zwischen der Domäne und der Infrastrukturschicht unserer Anwendung fungiert.
Lassen Sie mich zunächst eine schlechte Implementierung des Repository-Musters zeigen, die ich oft in Laravel-Anwendungen sehe, und es dann für Sie beheben:
// app/Repositories/UserRepositoryInterface.php <?php namespace App\Repositories; interface UserRepositoryInterface { // ...methods definitions }
// app/Repositories/UserRepository.php <?php namespace App\Repositories; class UserRepository implements UserRepositoryInterface { // ...implementation }
Wie Sie im obigen Code sehen können, wird der „Vertrag“ mit der Domäne und der Infrastruktur nicht innerhalb der Domäne, sondern innerhalb der Infrastruktur selbst definiert. Ja, der App-Namespace ist Teil der Anwendungsschicht und enthält alles, was nicht zur Domäne gehört.
Jetzt wollen wir sehen, wie ich dasselbe umsetzen würde:
// domain/Repositories/UserRepositoryInterface.php <?php namespace Domain\Repositories; interface UserRepositoryInterface { // ...methods definitions }
// app/Repositories/UserRepository.php <?php namespace App\Repositories; use Domain\Repositories\UserRepositoryInterface; class UserRepository implements UserRepositoryInterface { // ...implementation }
Beachten Sie, dass wir jetzt eine richtige Domänenschicht und eine Anwendungsschicht haben. Es ist ganz einfach zu bekommen, oder?
Lass uns jetzt ein wenig nachdenken. Da die Repository-Schnittstelle nun Teil der Domäne ist, können wir ihr nicht einfach Abhängigkeiten von anderen Ebenen hinzufügen. Hier ist ein schlechtes Beispiel, um es zu erklären:
// app/Repositories/UserRepositoryInterface.php <?php namespace App\Repositories; use App\Models\User; interface UserRepositoryInterface { public function find(int $id): User|null; // ...other methods }
Noch nicht klar? Lassen Sie es mich auf die Domänenebene verschieben:
// domain/Repositories/UserRepositoryInterface.php <?php namespace Domain\Repositories; use App\Models\User; interface UserRepositoryInterface { public function find(int $id): User|null; // ...other methods }
Sehen Sie das Problem? Wir injizieren ein Eloquent-Modell, das Teil der Infrastrukturschicht ist, in unsere Domäne. Dies koppelt unsere Domain eng an Eloquent, was den Zweck des Repository-Musters zunichte macht.
But how do we solve it? Well, it is not as hard as you might think. You probably already heard about Entities, right? So, let’s fix it:
// domain/Repositories/UserRepositoryInterface.php <?php namespace Domain\Repositories; use Domain\Entities\User; interface UserRepositoryInterface { public function find(int $id): User|null; // ...other methods }
// domain/Entities/User.php <?php namespace Domain\Entities; class User { public function __construct( public int $id; public string $name; public string $email; ) {} // ...other properties and methods }
Our domain layer is now clean from external dependencies, and if we want to move the whole domain to another framework, we can do it.
Now, how do we implement our Repository in our Laravel application? Let me show you:
// app/Repositories/EloquentUserRepository.php <?php namespace App\Repositories; use Domain\Repositories\UserRepositoryInterface; use Domain\Entities\User; use App\Models\User as EloquentUser; class EloquentUserRepository implements UserRepositoryInterface { public function find(int $id): ?User { $eloquentUser = EloquentUser::find($id); return $eloquentUser ? $this->toDomain($eloquentUser): null; } private function toDomain(EloquentUser $eloquentUser): User { return new User( $eloquentUser->id, $eloquentUser->name, $eloquentUser->email ); } }
Now we have a proper implementation of the Repository pattern in Laravel using Eloquent. You can create any other Repository implementation, such as PDOUserRepository.php, DoctrineUserRepository.php, and many others without injecting any dependency into your Domain layer.
Back to what I said in the subject of this article, I’ll complement that, in my humble opinion, using the Repository Pattern with Laravel is just overengineering, and you need a really good reason to do it.
You are adding an extra layer of complexity to your application that you may not need at all, or even worse, it will not guarantee that your business logic is actually isolated into the Domain layer.
What are you trying to achieve here? Think about it. You might end up missing out on many nice functionalities from Laravel or at least making their usage overly complicated.
Are you not sure if Laravel is the best framework for your application and you might move your application to Symfony in the future? Sure, go for the Domain and the Repository. Do you need to replace your SQL database with a NoSQL database later? Maybe it is a good justification. But do you really need it, or is it just charm?
One common argument is that the Repository helps to put some business logic into a separate layer. This normally gives me the creeps because there are better approaches for splitting your logic. Repositories are just for acting as a middle layer to connect the data layer and domain, nothing else. If you want to split your business logic, you should make use of something else — but this is another subject.
In conclusion, while the Repository pattern and clean architecture principles offer significant benefits in terms of maintainability and separation of concerns, their application in a Laravel context often introduces unnecessary complexity. Laravel is designed for simplicity and rapid development, and adding layers of abstraction can complicate this process.
Before implementing the Repository pattern, it is essential to evaluate your project’s specific needs. If decoupling your domain logic from Laravel’s infrastructure is a genuine necessity due to future migrations or a need for flexibility, then the complexity might be warranted. However, for many Laravel applications, leveraging Eloquent directly aligns better with the framework’s strengths and keeps the codebase simpler and more maintainable.
Ultimately, the decision should be driven by a clear understanding of your project’s requirements, balancing the trade-offs involved. Overengineering can lead to more problems than it solves, so aim to keep your solutions as straightforward as possible while still achieving your design goals. The primary objective of any architecture is to solve problems, not to create new ones.
Das obige ist der detaillierte Inhalt vonIhre Laravel-Anwendung mit Repository ergibt keinen Sinn. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!