Chapter 13: Designing the Architecture of Your OutSystems Applications

In this chapter, we will understand how we should segment and lay out our modules and applications at the architecture level in order to allow for scalability, robustness, and security.

We will focus on the best practices and standards advised by OutSystems in order to understand the standard and regularly used model. This does not mean that in our professional careers there are no variant cases, but we must always consider the trade-off and the context scenario.

In this chapter, we will complement the information already explained in Chapter 4, Using Your Modules to Simplify and Encapsulate Your Code, and we can see this chapter as an extension of that one.

In order to better understand this topic, the chapter is divided into the following sections:

  • The importance of architecture
  • The 3 Layer Canvas (Architecture Canvas)
  • The architecture design process

By the end of this chapter, we should be able to understand why we should design a good architecture before starting to develop code and that architecture is not immutable during its life cycle. We'll also learn how to distribute our modules across Architecture Canvas layers and sub-layers and what each layer is used for.

Above all, this is an ongoing process, always in constant change. Applications change, new applications appear, others disappear and all this means that we have to constantly adjust the architecture of our software factory.

Excited? Let's get this trip started!

The importance of architecture

First of all, we need to understand why the existence of good architecture is important.

As applications are developed, their size and complexity grow, increasing the design problem and exceeding data structures and algorithms. Therefore, designing an architecture that facilitates the understanding of these components becomes a more-than-necessary path. Bad architecture can also impact performance, lead to life cycle issues, and cause dependency problems, increasing technical debt uncontrollably and potentially leading to more catastrophic scenarios. As with everything in life, no matter how good it is, we have to be smart when using it.

Among the aspects that need to be observed in this process, issues such as communication protocols, feature assignment to certain parts, and the control structure are included.

A clear example can be found in reactive web and mobile OutSystems applications, where a solution needs to rely on several layers to distinguish client-side and server-side components, as well as possible intermediate structures that may exist as needed.

This structuring, despite seeming laborious for professionals not used to it, aims to facilitate the organization of components and improve the flexibility and portability of the system, making maintenance much easier.

Based on these principles, OutSystems created a very solid, robust, and viable architectural model for application development: the Architecture Canvas (often called 3 Layer Canvas or just 3LC).

Furthermore, the method in which strong and weak references are managed between modules and consumed elements allows for very controlled flexibility and helps to reduce technical debt.

Tip

You can see more details about technical debt here: https://www.outsystems.com/blog/posts/technical-debt/.

So, what is the Architecture Canvas model all about? How is it divided? What are layers and sub-layers used for? Let's analyze this topic in the next section!

The 3 Layer Canvas (Architecture Canvas)

The Architecture Canvas is the tool that allows us to streamline and easily create a scalable, robust, and well-performing architecture.

This model is prepared and designed for the most critical scenarios with multiple applications and modules existing in an OutSystems factory.

The Architecture Canvas has layers and sub-layers in its base into which the application context is divided. Each layer and its respective sub-layers will contain applications and modules with different characteristics and types of functionality.

As such, the layers are organized as shown in Figure 13.1:

Figure 13.1 – Architecture Canvas (3 Layer Canvas) layers

Figure 13.1 – Architecture Canvas (3 Layer Canvas) layers

In addition, and in order to make the interpretation and segmentation of the code simpler and more correct, the same layers are divided into sub-layers, allowing a quicker inference of the nature of each module and application. The layers are organized as shown in Figure 13.2:

Figure 13.2 – Architecture Canvas (3 Layer Canvas) sub-layers

Figure 13.2 – Architecture Canvas (3 Layer Canvas) sub-layers

As we saw in Chapter 4, Using Your Modules to Simplify and Encapsulate Your Code, there are certain types of modules that best fit each of the Architecture Canvas layers. As such, for the Foundation Layer, we have the following:

  • Library modules
  • Extension modules
  • Blank modules

For the Core Layer, we have the following:

  • Service modules
  • Blank modules

For the End User Layer, we have the following:

  • Reactive web modules
  • Phone app modules
  • Tablet app modules
  • Blank modules

For more details on each of these types of modules, we can consult the Applying modules to the correct layers section in Chapter 4, Using Your Modules to Simplify and Encapsulate Your Code.

Taking these layers and their properties into account, we can start thinking about how to design the architecture of our applications.

In the next section, let's see the architecture design process recommended by OutSystems.

The architecture design process

Designing an architecture is a process that must include the following three important steps:

  1. Disclose: Find out the business concepts of the project and what kind of integrations they need. We must consider the functional and non-functional requirements of the business concepts.
  2. Organize: Organize and distribute the concepts across the Architecture Canvas layers.
  3. Assemble: Organize and match these concepts with recommended patterns. We must bear in mind that we must join concepts if they are conceptually related and we must separate them if they have different life cycles and/or are too complex.

At the end of these three steps comes one of the most important phases: iteration. We must iterate this cycle of steps as many times as necessary until we have a solid, understandable, and scalable architecture. Furthermore, we must bear in mind that an architecture is not immutable and we may have to repeat this process even during other phases of the project than the design phase.

One of the processes that we should consider in addition to the creation of modules is how we can organize them at the application level, in other words, in addition to the layer and sub-layer with which each module is concerned, we also have to consider in which applications they should be placed. This is because in a software factory with some complexity, we must consider the issue of reuse and development concepts with which business subjects is concerned.

For this, we must always consider that an application is inserted in the layer of its topmost-level module, as we can see in Figure 13.3:

Figure 13.3 – Applications distributed in the Architecture Canvas

Figure 13.3 – Applications distributed in the Architecture Canvas

The distribution of modules by applications and their insertion in layers must respect three fundamental principles, as we can see in Figure 13.4:

Figure 13.4 – Architecture violations to avoid

Figure 13.4 – Architecture violations to avoid

These three principles must be taken seriously to ensure that our developments allow us to scale in the future, always with high robustness. They are explained in detail as follows:

  • No upward references: A module from a lower layer should never reference a module from a higher layer (for example, a module from the Core Layer should not reference an end user module). The same for applications: a lower-layer application must not reference an upper-layer application.
  • No side references among end user modules: An End User Layer module must not reference another end user module. The only exception is when only screens are referenced. Screens are considered a weak reference, as the only thing referenced in the consumer module is the screen URL of the producer module. The same principle holds true for applications. Applications from the End User Layer must not reference applications from that same layer, even if the module they are consuming is from a lower layer.
  • No cycles: A consumer module must not simultaneously be a producer module of the module it is consuming. This leads to problems with refreshing dependencies, since whenever you update one of the modules the other will always get outdated and vice versa. The only way to solve this problem is by publishing a solution. If this scenario happens, the concepts shared in the same module should be considered, either in an existing one or in a new module, which may belong to a different sub-layer (it could be a business logic module, _BL, an engineering module, _ENG, or in the case of synchronization, a _SYNC module).

    Tip

    You can see more details about these three rules of validating application architecture here: https://success.outsystems.com/Support/Enterprise_Customers/Maintenance_and_Operations/Designing_the_Architecture_of_Your_OutSystems_Applications/Validating_your_application_architecture.

Another issue that we should pay attention to is application composition. By this, we mean that it is often not easy to understand when we should divide our applications into smaller ones to ensure the correct reuse of features.

For this, there are four rules that help us obtain the desired results:

  • Correctly layer your modules: We must place our modules in the correct layer and sub-layer according to the purpose of the code they contain. This helps to ensure the absence of breaches, allowing you to maintain a sustainable architecture.
  • Correctly layer your applications: We should use the same Architecture Canvas rules and principles that we use in application modules.
  • Don't mix different owners: If we have applications or modules in which developers of multiple projects work, it becomes difficult to manage the complexity of the requirements, since the life cycles of different projects will probably be different. In this case, developments should be separated into separate modules/applications in order to promote ownership and avoid bottlenecks:
Figure 13.5 – Split application ownership

Figure 13.5 – Split application ownership

  • Don't mix different sponsors: We shouldn't mix different sponsors in the same applications, as the difference in line of business, budget, and requirements can impact everyone else. Applications should be separated by sponsor whenever necessary to avoid collisions or points of indecision, thus ensuring autonomy in the life cycle:
Figure 13.6 – Splitting applications by sponsors

Figure 13.6 – Splitting applications by sponsors

These rules must be applied with care, as misinterpretations of contexts can lead to wrong and painful separations for our developments. We must always keep in mind that the goal is for the architecture to be as sustainable as possible, with great scalability, while maintaining the highest level of performance and security. We must always remember that architecture is an ever-changing concept and we must design it in such a way as to have a heightened capacity to respond to this change.

Sometimes, to meet all these rules, we need to change the application modules; that is, the application to which these modules belong has to be another one. This is normal to ensure the correct applicational and functional layer since, as we mentioned earlier, applications assume the module layer contained in itself with the highest layer.

In order to change the module in Service Studio, we must access the application where the module is and click on the move button, as we can see in Figure 13.7:

Figure 13.7 – Move module button in Service Studio

Figure 13.7 – Move module button in Service Studio

We can find more complex cases, such as having to put logic that we have inside a module in a new module of another layer and sub-layer. This happens when the logic does not match the purpose of the module into which it is inserted.

To solve this, we must do the following:

  1. Identify the logic to be moved to another module:
Figure 13.8 – Identified logic to move to another module

Figure 13.8 – Identified logic to move to another module

Basically, we select the logic we want to change modules for and copy it.

  1. Create a new module inserted in the desired layer and sub-layer:
Figure 13.9 – Creating a new module in the correct layer

Figure 13.9 – Creating a new module in the correct layer

We create a module of the desired type. In this example, as we are talking about service core logic, we create a module of the Service type in an application of the Core Layer.

  1. Move the identified logic from the current module to the new one:
Figure 13.10 – Moving identified logic to the new module

Figure 13.10 – Moving identified logic to the new module

Here, we paste the actions (the logic) that we copied from the original module.

  1. Reference the logic required in the original module to the new module:
Figure 13.11 – Reference the logic through the Manage Dependencies window

Figure 13.11 – Reference the logic through the Manage Dependencies window

In the original module, or in any module that needs to consume the actions that migrated to the new module, just open the Manage Dependencies window, select the new module, and select the actions in question.

This way, the logic is isolated in a module in the correct layer and sub-layers.

Tip

You can see more details about designing the architecture of your OutSystems applications here: https://success.outsystems.com/Support/Enterprise_Customers/Maintenance_and_Operations/Designing_the_Architecture_of_Your_OutSystems_Applications/Validating_your_application_architecture.

Given the information we've covered throughout this chapter, we can now better understand the effectiveness of applying modules to their correct layer (as we mentioned earlier, you can find more information in Chapter 4, Using Your Modules to Simplify and Encapsulate Your Code).

To support us in these journeys, we have three tools that can help us:

These tools can help us support various tasks in the design, development, and refactoring process of our architectures. In addition to making everything more visual (if it weren't for low code), it allows us to access information that we would otherwise hardly be able to access.

Let's think of developing application solutions as building a house: if the foundations are well made, the house will be more robust and it will be easier to extend it. These principles and rules are the foundations that will guarantee a promising future for our solutions.

Summary

In this chapter, we learned that it is important to design a robust, scalable, performant, and secure application, in order to support the growth of solutions, both in volume and in complexity.

We learned that we can do this by applying an architectural model called the Architecture Canvas (or 3 Layer Canvas), and we examined its layers and sub-layers and what types of modules fit into each of them.

In addition, we analyzed the process of designing an architecture, including its steps (disclose, organize, assemble, and iterate through them as often as necessary) and which rules and principles serve as a foundation for this process. We saw some refactoring techniques to align the architecture with the expected model and mentioned some useful tools for OutSystems architecture support.

But how much further can we go? Now that we have figured out how to build our "home," how far can we go? Can we "stretch" the OutSystems universe beyond what already exists?

Of course! We can use other tools and techniques to do this, and without further ado, we'll see how in the next chapter: Chapter 14, Integrating OutSystems with Your Ecosystem!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.102.160