How to better streamline the business logic of the application with Trailblazer abstraction?

Marcin Lazar on 25 January 2018

Writing this article, I am aware that the glory days of Ruby, which has become so popular thanks to the Ruby on Rails framework, are slowly passing. A community has formed around this language in recent years, introducing (and continuing to do so) useful and innovative solutions for the development of web applications. Thanks to this community, one of the best solutions (in my opinion) has been created in terms of the organisation of application code and the division of business logic into an appropriate level of abstraction. That’s why today, I would like to present and show you how to better organise the application structure responsible for business logic.

To start with, let’s talk about spaghetti

In order to understand where I’m coming from better, I will explain what my problem was when I started creating web applications. So, starting from the beginning – PHP was my first language for creating more complex web applications. At the beginning, I was delighted to be able to connect to a database and retrieve information from it. Later I managed to implement a simple user registration. From what I remember, I was very happy with the goal achieved. However, when I came back to develop my super-advanced application, I found that… the code I wrote could be compared to spaghetti.

source: http://bit.ly/2BrnogH

HTML was interspersed with PHP and vice versa. In addition, somewhere below the form was a short script acting as the business logic for registration (recording user data and sending a welcome email), and all this was preceded by the validation of the data entered. Looking at this code then, I realised that web applications shouldn’t be created in this way. It was only a simple registration, but it was difficult to identify individual functions of the code without a deeper analysis. So I started searching the Internet for different patterns for separating PHP code into small, independent modules. After a long research I found, in my opinion, a great PHP framework, namely Symfony 2. It was based on MVC architecture and modelled on solutions from the Ruby on Rails world. Despite the fact that the application already had the MVC pattern implemented, I could not fully use its architectural advantages. I put all the business logic that my application contained in controllers that should never be used for this purpose. Perhaps I could have avoided this error if half of the online forums and guides did not promote such anti-patterns.

Beginnings with Ruby on Rails

I do not remember how much time I spent in the PHP world, but I remember that when I started to discover the world of Ruby on Rails, I was very surprised by all the possibilities this framework gave me. At the beginning, I continued to place logic in the controllers, which in the area of organising the application structure was a small advance, because all the validations in the framework architecture ended up in the model. After a short time of writing the application with a framework, I discovered that there is such a thing as callbacks in models. These callbacks allow the application to call a number of different operations, e.g. after saving or editing a given model in the database. I was very happy with the new possibilities that this concept provided. I started to move the structure of business logic from controllers to models. At the time, I did not know that I was following the fat model, skinny controller approach. In the end, I began to feel that I am writing applications that have some sort of an organised structure, and every script responsible for business logic has its place in the application.

The road to clutter

Over time, I started to write applications that implement increasingly complex business logic. Now it wasn’t enough to simply send an email to the user after registration or change the status of the message to read. Over time, the conditions under which the callback should be initiated become more and more complex. This had an impact on the readability of the code, which hindered its subsequent understanding by other developers (e.g. in the development of the project). I will use a very complicated example of the implementation of callbacks and validation in Rails models.

At first glance, everything looks fine. After a closer analysis, however, you can see that the business logic implemented during the creation of an object is intertwined with the logic created after its editing. You can also notice that the implementation of the logic code in this place becomes monolithic with the whole model. This model should really represent an abstraction of an object from the database and its connections to other model structures. Validations included in it are also closely related to this model. Let’s think about why this can be problematic. Let’s assume that in some part of the application you can create a user without having to assign a name, and in another part of the form, the name is required. You must write various kinds of instructions to check whether you have to perform the validation in a given operation. The more additional validation logic occurring under certain conditions, the messier your models will be.

In the right direction

After some time of coding using the Ruby on Rails framework, I found my first job. My mentor used the Form Object pattern when creating the application. These were objects that took various input data, but used only those that were declared in them. They also performed a list of operations to meet the selected logic. One object could perform only one operation, for example, it could write something to the database or edit something. I immediately came to like this approach in which the object performed ONLY one operation, e.g. by performing the object creation, it did not contain logic for editing. However, under this solution, the validations were still present in the model, which was almost satisfactory…

I did not have to wait long because I found out that there is a framework called Trailblazer, which was said to contain an interesting solution for organising business logic. So I started to find out more about it.

Information about Trailblazer

I have learned that Trailblazer is a typical framework that adds more levels of abstraction to the basic MVC pattern. It has much better technological solutions than Rails and a defined internal convention to be followed. A lot could be written about Trailblazer, but this article is not a coding tutorial. My goal is to show the organisation of the application structure and business logic of the code. Therefore, I will present the advantages of Trailblazer implementation and examples of its use.

Only two abstractions that Trailblazer implements are sufficient to implement business logic:

Contract – An object that contains a definition of the necessary data expected in a given operation, and which is responsible for their validation.

Operation – A set of steps needed to handle a specific business action, e.g. CreatePost

Folder structure and nomenclature

As previously mentioned, Trailblazer has a defined convention. The entire business logic of the application should be included in the concepts folder, which is located in the main application directory (app). The subdirectories contain folders whose names represent the models. The folder named contracts contains contracts whose names correspond to the names of the operations. As you can easily guess, all the operations are in the folder called operations.

Operations

An operation is the heart of Trailblazer architecture. It includes tasks such as searching for or creating a new model and checking the correctness of incoming data using the contract object. The following example illustrates the construction of the operation that creates a new Post model, at the same time fulfilling the tasks in sequence in accordance with the business logic.

Individual fragments of logic are performed by steps, which in my opinion is a brilliant solution – just look at them and you can immediately see what is being done in sequence in the operation. It is worth mentioning that if a given step fails, the whole operation is interrupted.

In the first step, a new Post model is created, and in the next step the currently logged-in user is assigned as its owner. To assign the data sent to your operation to the newly created model, you must first validate it. As I wrote earlier, that is what contracts are for. A contract specifies the properties and rules for the validation of operations. But what is a contract? A contract is an object that is initialised by an operation, which verifies the correctness of data that has been passed to it. Through it, specific data is first selected from the input data, which can then be validated in it. In a contract, you can also specify which input data should be assigned to a given attribute of our model. The following example shows the implementation of a contract for your operation.

In the above example, the property method is used to define all parameters that you want to capture, validate and ultimately assign to your model. As you can guess, the validation block contains a definition of the rules validating the contract’s attributes.

In the next step, using the contract you will check that the parameters sent to your operation are correct. If your contract has passed the validation, it means that the parameters are correct. The last step is to assign data from the contract to the model and save it in the database. Well done, your operation is complete! Now you can use it anywhere in the application.

Your controllers only know as much as they should. They capture the HTTP request and direct it to the operation. The application’s logic does not leak into the web framework.

In summary

Trailblazer is a genius concept of creating web application structures. It helps us organise large code structures into small independent modules. It can be said that thanks to its structure, it relieves the MVC pattern from the need to implement application logic in it. I think it’s a good idea to use it for larger projects that have extensive business logic or are meant to be constantly expanded. Due to its modularity, Trailblazer is ideal for implement it in existing applications in which new functions are introduced. From my point of view, the use of Trailblazer in small projects, when we predict that business logic is unlikely to be too complex, is pointless. It may turn out that you will spend more time on the correct configuration than on creating a working part of the application.

Trailblazer pros:

  • Ease of application development
  • Ease of code and logic testing
  • Good code organisation
  • The possibility of parallel work on individual project modules by different teams.
  • Modular structure
  • Possibility of applying the framework to an already existing application and further conflict-free development using the new architecture

Trailblazer cons:

  • Complicated configuration
  • Large number of processes taking place automatically without the intervention and knowledge of the programmer
  • Pretty high entry threshold
  • Complicated DRY validations

 

We used Trailblazer in MyPhsar project, which you can find here.

 

, , , , , , , , , , , , , ,

You might also like

Check Appchance web and mobile app services
Download a free template
of a functional specification