You’re probably familiar with something called “bad” cholesterol. It's known to cause a plethora of health issues, which, if unmanaged, can affect how your body functions. In the long run, it increases the likelihood of getting some really nasty diseases.
Well, the same goes for technical debt. If left unmanaged, it can hinder your systems, making any sudden movement or change ever more complicated and risky.
Choosing junk food because it's faster than preparing a meal has the same effect on your body, as does technical debt on software. So what's technical debt? I'm glad you asked. Technical debt is a measure of the cost of reworking a solution, and it's caused by choosing an easy, yet limited solution.
Eventually it may reach a point where there’s nothing you can do to make it go away. You’ll live with it accepting that any small change may cause a huge impact or worse, unknown side-effects. You will also need to start doing things very carefully, and slowly, hoping that you don’t exert too much stress on your system which may cause it to topple over and fail. Of course, there’s another option. Completely replace the indebted solution with a new healthy, state-of-the-art product ... and starting the whole process again.
The truth is that when building a solution, each line of code ends up becoming technical debt that needs to be managed. But like most things, there’s two sides to every story. For instance, there’s “good” and “bad” cholesterol. Good cholesterol helps you fight “bad” cholesterol, keeping your levels down. Similarly, building “good” code minimizes technical debt and helps keep your system healthy. A healthy system can adapt and change at great speed with a lower level of risk.
How to Manage Your Technical Debt
It's no secret that technical debt has been around since the first line of code was punched into those perforated cards long ago. This is why we have always concerned ourselves with managing it and finding new and better ways to keep it down to a minimum. And, that’s where the Architecture Dashboard comes into play.
During NextStep 2019, we launched the Architecture Dashboard as an OutSystems assistant to OutSystems developers, team leads and architects. It helps them follow best practices and avoid common pitfalls during OutSystems application development.
After analyzing an application’s low-code implementation and execution metrics it produces recommended solutions. Our users can then put in place improvements such as performance, security, architecture, user experience.
It’s been in development for a few years now, and some of you may even have had the pleasure of working with it in your projects before its official launch. It has come to be an invaluable tool for many of the teams who build their solutions with OutSystems and want to keep their technical debt down. It has also helped my team understand why seemingly healthy code may be a problem in the long-run. The tool helps us to technically grow as creators and managers of future technical debt.
What’s in the Secret Sauce?
If there’s one thing we don’t want to keep to ourselves, it’s the recipe for a healthy application. Yet, instead of instructing you on how to bake your application, this tool gives you the freedom to run wild, then looks for certain patterns you may accidently have dropped into the code. Like a head chef, this tool is always on the lookout, suggesting where you need to change your code and why you need to avoid doing things that way. You’ll be able to deliver your applications to the world’s best critics (usually your customers) without worry.
These patterns are based on best practices from both the software development industry standards and development in OutSystems. Each pattern that's detected in your application adds technical debt to one or more of the following: Performance, Security, Architecture, and Maintainability.
Standing on the Shoulders of Giants
The Architecture Dashboard has been in development for some time and has finally reached a stage where it needs to evolve to the next level. Until now, architects, developers and team leads had used it to reduce the amount of debt that's generated, fixing issues as they were identified. The information was delivered "per application" and could be filtered by teams that work in the factory. Yet, there was no bird's-eye view of how bad (or good) things actually were. There was no way to identify the applications or teams that generated the most debt. You could look at an individual application or module's list of findings, but there was no holistic view of the entire factory.
It was a good starting point for small factories, yet as they started to grow, becoming the core platform for enterprise systems, it just wasn't enough. We now had many sources churning out debt at different speeds, unknowingly impacting other applications.
To plan how to deal with it, in which order, anticipating any fallout, we needed a bird' s-eye view of the entire factory.
How to leverage the vast information already generated by displaying it cohesively? And, could we deliver this without losing any available features, but rather by adding to this already robust and mature product?
It was an easy decision, we were going to build this new experience as a Reactive Web Application. We would take advantage of the speed and ease of use this new technology delivers while sticking to the robust code-analysis engine that already existed, and that had proven customer value several times over.
Besides, what better way to showcase the latest OutSystems features than using them to build cool new tools?
A Bird’s-Eye View
Though a list of findings is an efficient way of fixing problems in the code, we needed visual cues to identify the applications or modules where the technical debt resides. Visual cues would give us the distance we needed to understand what fixes to target first. We devised a visual representation of all applications and modules, using a color scale, each one was assigned to a specific level of debt.
Since our goal is to support large factories, it could mean that showing all applications on the screen is overwhelming and unusable. The ability to pan and zoom around the canvas was essential, especially in such situations, and besides that, it looks great! Also, so you don’t get lost, a minimap shows you exactly where you are on the main canvas.
Learning to Ride a Bike, Again — With Reactive Web
Building a Reactive Web Application brings a whole new set of features we were eager to use, such as data fetching actions and having the application react to our data changes without having to manually refresh web blocks when something happens. The event-driven architecture and the ease with which we can put in place different actions for different events almost takes the fun out of having to worry about them.
Luckily though, a whole new set of challenges present themselves, and that’s a wonderful way to keep us entertained. With Reactive Web, we need to rethink how we build our apps because now our screen components are aware of changes that occur and can automatically react to them. Of course, we still need to tell them how to react, but we don’t explicitly need to refresh any web block or click on a hidden button when something happens.
Although events also exist in traditional web applications, we still need to manually react to those events, to refresh the blocks that need reloading. With Reactive Web, all web blocks dependant on a parameter, are automatically informed that the event occurred, and their “OnParametersChange” action is called.
So how is this a challenge?
Since the components are now aware of their surroundings, we must guarantee everything happens in sequence. So this means we must build the event handlers in such a way that they get triggered at the right time.
A momentary distraction when changing an input parameter may trigger an unintended event on many components, and in turn, may cause those components to trigger a change that bubbles over, causing another parameter change on components. You can see how this can quickly get out of hand. A tiny mistake can have a domino effect across an entire application. It may lead to bizarre flickering as the blocks load different data, and it lasts until the events are all dealt with, to display the expected data. If you’re lucky.
In traditional web, this was not a problem since the refresh of the components occurred manually, and more often than not, we would forget to refresh a specific component and then spend some time trying to understand why the app wasn’t accepting our changes.
With traditional web that wasn't an issue, and more often than not, we'd forget to refresh a component, then spend some time figuring out why the app wasn't accepting our changes. Now that these events are automatic and "semi-simultaneous," we no longer need to refresh the components, but we lose control over which one runs first. We must be mindful of the impact of a single change in a parameter, and how it may impact the screen, we must also be event-aware, figuring out the correct order of events.
Separating and Syncing All Things
Thinking of our future applications as independent pieces, each with a specific purpose, led us to follow an approach that separates the current code analysis engine from the new Architecture Dashboard experience we intended to build. This brought its own challenges since we needed both applications to be completely independent of each other while having the mechanisms in place to communicate when needed.
To correctly decide which APIs we would create and at which intervals, we would update data, and even which APIs were going to be used on-demand, we needed to plan the whole user experience. We want the users to see their entire factory, quickly navigating the apps and modules, and assessing technical debt at a glance. Yet when we request the analysis report, we may accept a little extra loading time to get the detailed results.
There’s also configuration data, such as application types, that we need to synchronize to the new experience. It could be sent across with each snapshot, but that would increase the payload, duplicating a lot of the information, fattening it up unnecessarily. We also want the engine to continue owning this information, and if it changes on that side, we can update the new experience accordingly.
As each customer's data is kept separate in a tenant in the engine, so keeping that information separate in the new experience is even more critical than merely keeping data in sync. Consequently, the tenant information is also synchronized between both applications allowing all users to access their data and only their data seamlessly.
The Best of Two Worlds
I'm wrapping up this blog post at the very start of this journey, namely the entry point to the new experience–the login mechanism.
While the original Architecture Dashboard was built using traditional web technology, the new experience was built using the Reactive Web capabilities of OutSystems 11. We had to ensure seamless navigation between the two, without hindrance to working on either or both experiences.
Keeping two applications login mechanism and tenant switching in sync requires the applications to handle them themselves. We set it up so that when the user logs into the original traditional web version of Architecture Dashboard, using existing credentials, they are automatically logged-into the new experience.
Thus, when navigating to and from the new experience, the user is unaware that he's traversing years of technological evolution, and that these two technologies are working side by side.
We’re Just Getting Started
We envision a future Architecture Dashboard that helps all customers effectively manage their technical debt.
We are using OutSystems to build OutSystems tools you need to keep your applications running as smoothly as possible. We're making it possible for you to manage the technical debt that is generated, increasing the quality of all your systems by eliminating issues before they cause any damage and, more importantly, keeping aligned with the ever-changing needs of the market.