Ovid / dbix-class-report

Create arbitrary DBIx::Class resultsets on the fly
8 stars 2 forks source link

Not an issue, a question #5

Open hbarnard opened 4 years ago

hbarnard commented 4 years ago

I'm converting an old application to Mojolicious at the moment. Plenty of SQL that doesn't quite fit into the DBix paradigm (ugh). Is there a way of using this with Mojolicious? Has anyone tried?

Ovid commented 4 years ago

The short answer is "yes". However, if your SQL doesn't need to change, you might find DBIx::Class::ResultSource::View a better fit.

The long answer deals with my long-standing frustration about how poorly MVC has been taught. Had we been teaching it well, the answer would be obvious. (no offense. This isn't directed at you!)

Mojolicious encourages a MVC architecture, but unfortunately, many people misunderstand that. Unfortunately, many people think the data model is what is meant by the "M" in MVC, when it's not. The "model" should be your business model (or application) which sits on top of your data model (often an ORM).

For the purposes of this discussion, we should rely on the diagram below. It's not the only way of handling this, but it's a clean way and it's certainly one that I find powerful. In fact, we're currently building out an OpenAPI Mojolicious application for a client using the structure below. It makes life much easier than what I often find in client code.

+-------------------+            /-------------------\
|                   |            |                   |
|       View        |------------>      Client       |
|                   |            |                   |
+---------^---------+            \-------------------/
          |                                |
          |                                |
          |                                |
+-------------------+                      |
|                   |                      |
|    Controller     <----------------------.
|                   |
+---------^---------+
          |
          |
          |
+---------v---------+
|                   |
|    Application    |
|      (Model)      |
|                   |
+---------^---------+
          |
          |
          |
+---------v---------+
|                   |
|       Data        |
|                   |
+-------------------+

It's of paramount importance to understand that the application layer (what is traditionally referred to as "the model") and the data model are separate. The view and the controller should not access the data model directly. Instead, the controller contacts the application and the application contacts the data model.

The reason for this separation of concerns is simple: if the data model changes extensively—as is often the case in applications—the application logic can be adjusted to ensure that the controller receives the same information. This ensures that the view and the controller do not have to change if the underlying schema changes.

This separation makes applications easier to develop.

The View

The view is the client's "view" of an application. In this case, it's typically HTML or JSON. The client sends a request which is routed to the appropriate controller and receives the "view" information.

The Controller

The controller receives a request and redispatches that request to the application (e.g., the model). The application returns data which is then formatted and sent to the view. The controller should not contain any logic beyond what is necessary to dispatch a request and format the response for the view. As mentioned above, at no point should any controller class access the data layer.

The application layer completely encapsulates the data layer. Thus, if we later fetch data from a different database, a cache, calculate the data, or use a remote service to fetch the data, the controller and view layers should have no reason to change.

The Business Model (Application)

In this paradigm, the "model" layer refers to the business model, not the data model. For our purposes, we mean the "application." The application isn't the view or the controller. It's a headless application that contains all logic necessary to accomplish the task at hand. We refer to it as the "application" instead of the "model" to make it clear that we're not talking about the data model.

The application receives a request from the controller. It handles the business logic, including interacting with the data layer, and returns a well-defined response to the controller. The application has no knowledge of the view.

The Data Model

The data model is the lowest layer in our application. The data model is responsible for CRUD: creating, reading, updating, and deleting data. As of this writing, our data model only consists of an ORM. Later, it may query ElasticSearch, Redis, external services, or other sources of data. These should all be kept separate (e.g., the ORM shouldn't be querying Redis). It's the responsibility of the application layer to manage these sources.

Answering Your Question

So given the above, of course DBIx::Class::Report can be used. It goes into the data layer and the model (application) layer above might or might not consult it for information.

You can also read my article Fixing MVC in Web Applications for code examples.

hbarnard commented 4 years ago

Hi, thanks for this. In fact my 'business' layer is as you describe, away from the data model, even in the old code. My main intention at the moment is to deprecate a great deal of elderly custom code, including DBI based by swapping it for DBix based code in the data model layer. But, in doing that, I'm losing some granular 'control' and need to bridge that gap in one or two bits of the application, hence the question.