This last week I've been focusing on getting support for Director accounts to manage Teacher accounts, as defined in this GitHub issue. This involves not only backend work (getting the table ready, creating the classes, etc.) but also involves frontend work, which I'm terrible at! 😅 So I'm taking my time on this.
I'm not aiming for an award-winning design or anything, but I'm actually spending a lot of my time getting more familiar with Blade components and how to leverage it best, and I'm also getting acquainted with TailwindCSS. Those are two technologies I'm least proficient at because I'm a backend/API guy. So far I've been able to refactor the base layouts that come available with Laravel Breeze and make the base preparations for the store-related routes (including controllers and requests validation classes). As things start to make sense, I'm also adding tests to avoid breaking things as I move forward.
Besides all this, I've also been thinking about how isolated I wanted my User domain - which will group Teachers, Directors, Students, and Parents as they're all users of the application - from other domains and even from the application layer. We should be very careful about dependencies. Directly referencing classes from other domains or layers makes both parties tightly coupled, thus making it hard to refactor or move them away (i.e. to a different service). Even though this might seem something premature to introduce at this point, I can assure you that it will be harder to decouple them down the line, and that could lead us to push the problem even further to the future, delaying its resolution. So I really believe this is best defined early in our development stage.
But what considerations I'm taking, you might ask? Well, generally speaking, the main operations that I can think require cross-domain communication is getting and setting data from each domain's persistent layer. A naïve approach would be to directly reference any entity and/or model class, and that would work, but a better approach is to use one of the most famous implementations of the more general Mediator Pattern: the Repository Pattern.
By implementing repositories this early, I'm definitely adding complexity and slowing the initial development of the software, but it will allow for a more decoupled domain logic and will payout dividends in the future. This pattern forces encapsulation of interaction between objects by avoiding them from referencing each other, allowing the domains to evolve their internal implementation details independently, as long as the public APIs keep being respected and don't suffer any breaking changes.
If I didn't use this pattern, and start referencing classes directly, I might end up with many places to be refactored if a small implementation detail changes like, for example, a table column being renamed. And this is a very small example, but we can also think about different side-effects that need to happen after some record is saved, and that can be initiated within the repository. Notice the word: initiated. Don't forget about Single Responsibility! 😁