Debugging in OutSystems

Nivaldo Pereira
11 min readMay 13, 2023

--

Disclaimer: this article is based on the book, Debugging by Dave Agans; on the OutSystems Documentation, and on my own experience.

Here, I intend to focus especially on the debugging part of an application.

This article is dedicated to debugging.

Debugging is a troubleshooting technique that helps detect and correct errors in software code. It happens through a step-by-step examination of the execution of a piece of code, and through a methodical analysis of code. The related input and output data, typically lead to the modification of a portion of the code, to implement a fix and eliminate the unwanted behavior.

Debugging is a natural part of developing software. And always remember that it is happening for a logical reason. It can be hard, and investigating a tricky bug requires a lot of focus. That is why debugging when you are tired, it is not a good idea.

A code is subject to many errors during execution. Logic Errors, meaning that the code is wrong and doesn’t do what the developer intended. Data Error, meaning that the code may be correct, but the date used, invalidates the operation. Other problems like performance, security, or connectivity issues also need detecting and fixing.

To be efficient in the art of debugging, using the OutSystems platform, you can use some rules, methods, and tools to better approach the situations where bugs are found.

1. Understand the OutSystems Platform

To debug efficiently, we need to know the OutSystems Platform. This means that we need to have a clear notion of the platform’s components and functionalities. It is also necessary to have a knowledge of the basic principles of programming in general and more specifically of OutSystems.

There will be many occasions when a lack of knowledge will cause you to spend more time than necessary fixing a bug. Well, in one way or another, that will be a learning moment, since you will learn something more about OutSystems. You will end up understanding the bug, and very likely one or other concept. So a bug can even be a good teacher.

When you have a bug ahead of you, it is important to have answers to any questions that may arise.

  • See the questions about the bug
  • Understand how to get the answer to the question
  • Repeat the process until there are no questions and the bug has been understood.

Understanding the underlying technologies is an advantage when investigating complex scenarios. For example, understanding that Cordova Plugins aren’t available when you run your Mobile App in Chrome on your computer helps you understand why it’s best practice to wrap Plugin calls inside Client Actions that test for Plugin availability and implement a graceful fallback when needed.

Knowing what Tools are available to you and picking the best one for the job can save you considerable time and effort.

2. Reproduce the bug

One of the things that seem to be obvious, but in fact often ends up being a mistake is, when we know about a bug, instead of going to see the error in the application, we go straight to the code.

Don’t jump to implement a fix before you truly understand the problem. It is important to witness the problem. That is, to make the application fail, without assuming anything that might be going wrong. Even because once the bug is fixed, we will want to test to see if there was a change in the behavior of the application, now working in the correct way.

It is important to see the bug happening to understand it better. Because if you understand the bug, you will know how to fix it.

When you reproduce a bug, it may generate an exception. Whenever a code operation fails in runtime, an Exception is thrown. When this happens, normal code execution is interrupted and is moved to an alternative Error Handler code flow. It is possible to define several error handler flows. Each flow is dedicated to specific errors (e.g. Database exceptions; Security exceptions; Customer exceptions).

OutSystems Types of Exceptions.

When OutSystems raises an exception, the ExceptionMessage property of the Exception Handler element is automatically filled in with a problem description. When you raise an exception in your logic, such as a User Exception, you must define the message in the Exception Message property of the Raise Exception element.

It is important to collect metrics/snapshots of the behavior before and after taking any actions. This will allow you to effectively measure the evolution of the behavior that prompted the debugging in the first place.

3. Quit thinking and look

Never guess or assume you know what the problem is before you’ve done your analysis! This is the time to use all the tools at your disposal to debug. This is the right time to use the:

In fact, it is the right time to use any and all tools that allow you to analyze the problem. When it comes to debugging, the OutSystems platform and a modern web browser like Chrome or Safari already give you a significant amount of capabilities.

In practical terms, debugging an application in OutSystems consists of pausing the application’s execution at specified breakpoints, allowing for analyses of the variables step by step and with data visualization in use.

Service Studio Debugger

So, how can we debug an app in OutSystems? There are 4 main steps to take when using the OutSystems debugger.

1. Add Breakpoints (Server and Client Side)

A breakpoint in Service Studio marks an element where the execution of a thread (server action, client action, awakened Timer action, a Process instance execution, or an integration method) is going to be suspended for debugging. Breakpoints can be added to elements of a process flow and to elements of an action flow. To add or remove a breakpoint in an element, Right-click on that element; Select the “Add Breakpoint” or “Remove Breakpoint” option in the pop-up menu. Or click on that element to select it and press F8. This shortcut toggles between add/remove breakpoints.

Add/remove breakpoints.

2. Start Debugger (The application will open in the browser)

The Debugger Tab is located in the lower pane of Service Studio and allows you to track all threads being debugged and examine module elements and runtime values.

OutSystems Debugger Tab.

The Debugger Tab contains three main areas:

  • The Debugger Toolbar (1)
  • The debugging context area (2)
  • The scope tabs area (3)

3. Run the Application

Run your application and see that the Debugger will suspend the execution in the breakpoints. It is the right time to analyze the value of the variables, to understand why the application it’s not behaving as expected.

4. Debug Code

The Debugger Toolbar provides you with a set of debugging commands to trace the execution of the thread being debugged. Go step by step and check what might be the issue. Use regular debugging operations, like Continue Request, Step Out, Step Over, and Step Into to analyze the behavior. You can also use options to suspend or abort the execution of the debugger.

The Debugger Toolbar.

The scope tabs area allows setting the entry point and starting a new debug session. This tab is only visible when the debugger is not running.

The scope tabs area.

Service Center

We can often get errors, and we don’t quite know where they occur or where to start investigating.

A very interesting way to have something to start with and be more efficient in finding the bug is through the logs generated by the platform.

To access the logs, access Service Center (https://<your_server>/ServiceCenter) and click on the Monitoring menu. There, you will be able to get the logs you want to get (e.g., Errors or General). By monitoring what is going on, you will be able to analyze and correlate the logs to find out details on errors that have occurred, so they can be fixed in the code; or find out problematic patterns that may require code changes not to cause future errors.

Logged events are not limited to errors. They also include benign situations for which diagnostics may be required (e.g. Screen rendering and Database query durations; Web Service calls).

Service Center page, in the Monitoring menu.

Error Anatomy

In the logs, you can go to their detail, where you will get relevant information, that will help you find the bug. Through this data, it becomes much easier to see where the error occurred. So, it is crucial to understand well the information that appears in the stack field of the detail page.

This relevant information is related to:

  • When the error was logged;
  • The name of the module that requested writing the error;
  • The message generated by the exception when the error occurred;
  • Data obtained from the environment at the time of the error;
  • The stack trace shows the entire code that ran at the time the error was triggered.
  • Other pieces of information are also logged.
Error detail.

The stack is a very useful part to understand. There you can often understand or infer the path followed to the place where the error occurred (e.g. Module, Screen, Action). It may be possible to find the Module, Screen, and even the Action where the error occurred.

Stack trace, showing where the error occurred.

4. Anticipate the bugs

Here, it is important to understand that the development moment is crucial to anticipate the bugs that might be found. It is when you can put the logs that during debugging can help you find the problem, or at least help in its analysis.

Things you can/should do during development consist of:

  • Writing good comments and documentation is key;
  • Follow OutSystems recommended Best Practices;
  • Make peers code review, and test as you develop your code;
  • Leverage tools like AI Mentor Studio that can perform automated analysis of your code base and flag potential issues before you deploy code beyond your development environment;
  • Write clean code. And if you want to know more, see Joost Landgraf’s article about Clean code in OutSystems.

Here I suggest briefly, the approach when developing, in order to make your life much easier and faster to debug:

  • Write some code that does one thing.
  • Get that thing to work the way you want, and as intended.
  • Repeat the process to the next chunk of code.

5. Divide and Conquer

Divide and conquer is an algorithm design type. It works by recursively breaking a problem into two (or more) smaller problems of a similar nature. If you can solve the little issue, you can solve a bigger one too.

“How often have I said to you that when you have eliminated the impossible, whatever remains, however improbable, must be the truth?” — Sherlock Holmes

Overall the idea is to narrow the search with successive approximation. This way, you will eventually narrow down to the problematic part.

You can use a divide-and-conquer strategy to converge on the point of failure by picking points partway through system execution and determine if the problem occurs before or after the point of examination.

6. Change one thing at a time

Isolate the key factor. Understand what’s wrong before fixing it. Change one thing at a time. Compare it with a good one, and determine what you changed since the last time it worked.

It is important to do one change at a time. Do that to avoid having a completely different code, in which you will have no margin of comparison with the code that had the bug.

By doing one change at a time it is possible to make a direct correlation and observation of which change caused the expected result, without the influence of other factors that may obscure or create confusion about the expected result. Changing as few things as possible makes it less likely you will introduce a new bug with an unnecessary change.

7. Talk to the Dummy (“Fala para o boneco”)

Surely there were many times when trying to explain your problem, you ended up finding the solution. Well, it’s the famous “talking to the dummy” or “rubber duck debugging”, which turns out to be a fantastic problem-solving technique.

If you’ve heard about it, you certainly know what I’m talking about. And when I say “talking to the dummy”, it can actually be to another human (even if they don’t know anything about programming), or it can also be to an inanimate object. The final goal is always to have that “Eureka moment”.

Of course, there are many times when we talk to outsiders, and they end up giving us useful tips on how to solve the bug. Therefore, it is always a good idea to expose your problem.

8. Solve the Impossible

The truth is that some bugs can seem “impossible” to solve. Some weird bugs can try to drive us crazy. Particularly if:

  • They are difficult to reproduce;
  • Or if your mental model of the platform has some missing pieces;
  • One of your assumptions is wrong;
  • It is an intermittent bug.

But with some creativity, patience, and assertiveness, and sometimes after talking to someone, you can achieve the impossible, and solve the bug.

Some ideas include:

  • Look for patterns related to time;
  • It is happening in one or in more servers;
  • Get detailed logs when the error happens;
  • Look at user input (Might have a special character);
  • Look for changes after a deployment;
  • Check the dependencies;
  • Go back to the code and documentation and try to see with maximum detail how this bug could possibly be happening
  • Ask for help in the OutSystems Forums
  • If the bug is in a .Net Extension, I would advise seeing this article from Luis Oliveira or this video from OutSystems.

Corollary

To finish, I want to say that, when debugging, your attitude matters. The way you face the bug can be the differential between finding the bug quickly or not. Having an action plan of how to attack the bug matters. And following a consistent process helps build good habits and make you more effective.

--

--

Nivaldo Pereira
Nivaldo Pereira

Written by Nivaldo Pereira

Dad, Husband, OutSystems Champion, Dreamer

No responses yet