Open olivierobert opened 4 years ago
Not all all, I already read a little bit Trailblazer but not apply for this architecture. I will explain some knowledge when design an architecture.
The operations layer first. For old design, some developer will implement the business logic in the model, the model will be heavy day by day and this violate Single Responsibility in SOLID principle. Each model after fetch data from database will put it on the model and generate the method related and if we implement so much method in this one, it will make the system very slow. Back to Operation layer, the reason why I declared that it is like a Service Object, the Service Object that mean It was born as a container of various business logic in which the object to handle does not belong entirely to any model and the benefit of Service Object is that it helps us to focus all the logic of functions into a separate object without having to subdivide it into controllers and models as usual. It will reduce a lot of code lines in controller and model, and make the project easy to read for the newbie, reuse and maintenance.
I very like for second question. You are right, if we use the gem to validate the param it will reduce the bugs. But in some project I was worked. We have some issues for this project that have some special business logic and need to create some model to prepare for the main business. If in the last step, the params assigned from FE are not correct, we must rollback all of the flow, it is nightmare. So that, I created the param layer to support validate the params that assigned from the FE. In the test project I don't use any gem to support, because it is so small, but I suggest to use the Virtus gem to validate the type of the params and implement the library like a gem to support them. The benefit of this layer are : can return immediately to FE if the params are not correct, don't touch so much to the model but still validate on the model to make sure the correct data. And the last one is can easy to understand what the params need for a request, and of course, it will reduce code lines on controller and easy to maintain.
The lib is the folder store the class is not depend on any business logic. In the requirement, I have just create a module which name is SReport and write some common code and hardly to change over the time. You can see it just have the basic method adapt for any report type, and in the future if you want to generate for the new reports, you need to extend the BaseReport and implement the data for fill to this one. A module in the lib folder can pack like a gem and can bring it to any project.
The services layer has responsibility work with the business logic outside the project. I bring the google search service to the services layer because it don't depend on the project business logic. It maybe is integrate with Paypal, Google, Elasticsearch or something likes that.
And the last one is presenter layer. It is simple a layer to cook the data before render to the view. This layer should not much business logic in here. And it can reuse the code and make it more clearly.
That are all the reason I choices the architecture. If you have new idea or feedback, feel free to contact me.
I understand the choices. But when working in teams, it's also important to follow team or frameworks conventions:
/lib
is generally a good idea but it's less used in Rails as models take care of both data modelling and persistence. So in general services or form objects are used.So overall, you need to find a balance between custom architecture and using what the frameworks provides you i.e. you need to find a balance and decide when using Rails conventions and when not :-)
Actually, I still validate the params in the models, my idea is response to the FE quickly with basic invalid values and don't need to touch on models so much. You are right in that case because the architecture will depend on the business logic of project too. Thanks for your suggestion.
As you went a less conventional way to organized the Rails application (at least not the one document on Rails Guides) - which is not an issue 😇 - can you please explain your decisions.
I can see some inspiration from clean code architecture, Trailblazer and also some DDD architecture. But I would like to hear from your rationale.
Kind of related, why not going with either
ActiveModel::Validator
fro params (or even Form Objects using schema-lessActiveModel
)?ActiveModel
would do lots of heavy lifting. Or maybe even Dry::Validation for a more functional approach. I am all for Plain Old Ruby Objects (POROs) but libraries can save time and avoid bugs too :-)