OutSystems App Development Best Practices Using the 3 Layer Architecture Canvas

As a Junior Developer, it's easy to let our brains focus on "making it work," completing our tasks, and delivering the functionality. And, in truthfulness, not always giving architecture considerations all the attention they deserve. 

Architecture Best Practices are the foundation stones of our applications. They provide us with a solid infrastructure to develop on and ensure we deliver a reliable solution that's easy to maintain and has the flexibility to scale and evolve.

Regardless of the level of experience, this is a concern that should be present in the back of our minds from the get-go.

In this article, we'll go head to head with the 3 Layer Canvas and explain its importance as a tool that ensures a solid architecture for our applications. We will also detail how to take advantage of it and use other related tools.

If you're new to Outsystems and still didn't cross paths with the Architecture Canvas, here are some suggestions to start testing the waters:

 

What is the Architecture Canvas, and Why Does it Matter?

How frustrating is it when you get a message that your module has outdated dependencies? You refresh them and publish the module, only to encounter the same message regarding the module you just used as Producer... This shouldn't happen, and minding Architecture Best Practices will help us prevent it.

The Architecture Canvas is a framework to support application architecture design. Using it to leverage the architecture design will ensure the abstraction of reusable services and lifecycle independence. It will minimize the impact of changes, making the application's maintenance easier.

It's composed of 3 layers, hence the name 3 Layer Canvas, namely Foundation layer, Core layer, and End-user layer. In each layer, we find different functionality used in a given module.

In the Foundation and Core modules, we find the reusable services: services connecting to external systems and services regarding business concepts, respectively. In contrast, the End-user modules are home to UI and processes, providing end-user functionality.

It supports the Architecture Design Process in a three-step exercise that keeps track of the evolution of the project as new concepts and needs come into place.

Junior Developers aren't responsible for the design process, as it requires more advanced skills. But in a nutshell, it can be similar to assembling a puzzle…

We organize the pieces, look for the corners, look for the edges, build the frame, divide the pieces according to colors, and all of this makes it easier to build it. The three steps are Disclose, Organize and Assemble, and the Architecture Canvas is present from the beginning.

Going back to the puzzle analogy, along the way, while assembling it, we keep looking at the pieces, re-organizing them, and understanding wherein the puzzle they belong. Similarly, the architecture design process is iterative: we'll keep going back and forth unveiling business concepts and requirements, organizing them, and translating them into our applications modules. 

As Junior Developers, it's our responsibility to develop the code that guarantees the maintainability of a solid and reliable architecture. We should validate that architecture best practices are being followed and understand when some refactoring is necessary to comply with a sound architecture.

 

How to Validate Module Architecture With the Architecture Canvas?

As newborn developers, some of the first concepts we come across are Producer e Consumer Modules, which provide information, actions, services, and so on, and which consume it. These are the pillars of the referencing concept, which we know better as "manage dependencies."

If we think about the visual aspect of the 3 Layer Canvas, there are three golden rules we must always abide by.

 

#1 - No Upward References

Modules in lower layers should not reference modules in higher layers.

 
 

As the image shows, Core 1 and Core 2 reference the Foundation and are referenced by the End-User 1 module. If the Foundation references the End-user 1, we’ll end up with circular dependencies; just imagine… Any change in the Foundation will make both core modules and the End-user 1 module outdated. And changes in the End-user 1 will make the Foundation outdated, which in turn will make the core modules outdated since they reference the Foundation. In reality, every module ends up depending on each other! Also, suppose a different module needs to reference some entity or some action, for instance, from Core 2. In that case, it will be dependent on the entire cluster. Thus, a change in any other module – Foundation, Core 1, or End-User 1 – to which it is not related will make it outdated without any real reason for it.

 

#2 - No Side References Among End-user Modules

End-user modules must remain isolated in order to have different lifecycles, so they shouldn’t provide reusable services.

 
 

Referencing one such module means we’ll also be referencing all lower layer modules this module references. So, similarly to the previous example, we inherit the whole cluster containing the End-user module being consumed.

Needless to say that cyclic references are an even worst practice, where End-User 1 consumes from End-User 2, as depicted in the picture, and is also providing something to it. It would be impossible to eliminate the warnings about outdated modules in this case.

 

#3 - No Cycle References Among Core Or Library Modules

Since side references are allowed in Core and Library modules, special attention is needed not to create cyclic references, as shown in the picture below, which would guarantee infinite back and forth broken dependencies.

 
 

The impact would be more negligible since these modules are on lower layers, thus impacting less the overall applications. Still, it would influence the modules in higher layers referencing these.

 

Which Tools Can We Use To Help Validate Module Architecture? 

There are two tools we can use, Discovery and Architecture Dashboard. We will focus on Discovery, a visual tool downloadable from the Forge. It provides a clear image allowing us to analyze the dependencies between modules and identify the violation of the rules discussed above.

 
 

It’s possible to see the modules consuming and being consumed and the elements being referenced.

 
 

Additionally, we can also check the violations and their details, find the responsible for the violation, the specific elements, and a suggestion of how to fix it.

 
 
 

How to Refactor To Comply With Architecture Best Practices?

The Refactoring process is a more complex one and can be challenging for a Junior Developer. Still, the way to start addressing it is by really getting to know the applications we are working on, what functionalities they intend to provide, who will use them, and what limitations they plan to overcome. This will allow us to better understand business concepts, how they relate to each other, and their specific lifecycles. And from there, isolate reusable components in Core or Foundation modules, depending on their nature, allowing these components to be referenced without violating any of the three rules we addressed earlier.


Conclusion

I’d like you to keep in mind the two main takeaways of this article: the importance of knowing your applications, which is the only way to understand the relationships between the different modules; and that you should regularly validate the compliance with architecture best practices.

Like this article? Share it:

Previous
Previous

Concepts for BIG OutSystems Projects (Part III)

Next
Next

Improving an OutSystems Software Factory