Co-authors: Bruno Martinho, Gabriel Lundgren, João Ferreira, Mariana Bexiga, Rúben Gonçalves and Tiago M. Pereira
Developer experience — think of it as the user experience of programmers. Or, as we like to say, developers are people, too. And this means that they also feel pain. It can be physical, of course, but the pain we want to highlight here is the rather intense emotional pain — which turns physical after you despairingly hit your head on your desk — that comes with the disruption of your programming and thought flow. And who’s to blame? The framework you’re using.
By now, you’re probably aware that we like to talk about frameworks. “We” are the Data Visualization Team at OutSystems, who, in the inaugural article of this series, advocated for building components with the mindset of creating a framework for added productivity and efficiency.
As a unit whose work revolves around creating components for developers who program with our visual, low-code platform, we explained that the first step for creating a fantastic framework is picking the adequate tools and technologies.
Aaaand if we had skin-itching, dev-ingrained qualms about using the word “fantastic” to describe frameworks in that first article, these evaporated as soon as we began talking about the kind of developer experience we aim to provide. It must, indeed, be fantastic — hey, you must always aim high...
Tag along as we guide you through the second step of building a framework: how to provide a fantastic developer experience. Now, where did we get that idea from? Customers, of course.
Developer Experience First, Technology After
Before moving to the OutSystems R&D Team, two of our team members worked closely with customers as part of the Professional Services Team. That gave them a unique understanding of how the OutSystems platform is used and what the requirements are of the developers who use it. And, this knowledge, of course, shaped our entire work and our approach to problems.
With our distinct vision and experience, we set out to define a few guiding principles that would become our manifesto. These are our seven commandments:
- 1. Experience first, technology after — we don’t follow fads and prioritize the developer experience over technology trends.
- 2. The world is our customer; a customer doesn’t rule the world — we deeply value our customer’s feedback, but we’re also fans of the 80/20 rule. Before implementing a new feature, we must assess how many people we’re impacting.
- 3. Do not reinvent the wheel. Period.
- 4. No one’s left behind — products exist because they are used. We believe that our mission is to listen to users and help them extract the best out of the product. We support them, listen to their use cases, and we never ignore them. To answer their issues, we can alter the product or send a custom sample (more on that below). By helping users, we are creating forward motion in two directions: they learn more about the product and see their use case resolved, while we lean on their feedback to improve the product, documentation, and even our backlogs.
- 5. No third-party lock-in — we don’t wish to be limited to a single provider. We built our code architecture and framework to facilitate work with different providers.
- 6. Doing it the right way takes the same time as doing it wrong.
And finally, last but certainly not least, as this is the major focal point of this article:
- 7. Keep the feedback looping — we work in close collaboration with the developers that use our components and the OutSystems platform. We have tools to monitor our user forums. Being close to the developers who build apps with our product allows us some complacency: because we keep such a watchful eye on their pains, we get away with breaking changes. There’s a margin error that comes with trust, and they are aware that as soon as they complain, we’re here to fix it.
“Hang on,” you may be thinking. “Didn’t they say that the first step to building a framework was choosing the appropriate tools and technologies?” You are correct.
But if the tools you’ve picked for the task don’t serve your users (remember that in a framework your users are other developers), they should probably be left in your toolbox. When building a framework, you’re not simply developing an app for customers; you’re creating modular blocks that other developers will use to devise apps for their customers. So you better make something freakin’ okay (read: fantastic) with developers in mind instead of tinkering with the latest hot tools that will deliver a flashy yet underwhelming result.
Remember point three: do not reinvent the wheel. Respect the industry standards and design for consistency.
You will find that we will refer to our principles many times throughout this article. Our seven-rule manifesto is crucial to our work because its guidelines aren’t ornamental; they impact our decisions, and we can trace back our choices to each of them. For instance, “experience first, technology after” is a great principle, but it only works when you live up to it.
The Decision Tree
So how do we do it?
With the help of our Product Designer Mariana Bexiga, we created a visual decision tree that we use every time we need to add a new feature to one of our components. The tree allows us to determine how we should add it and where and visually explains the reasoning behind that decision. All in all, it’s a unique tool within OutSystems R&D — for now.
Our decision tree works almost like a parameter or placeholder, adding to our efficiency as a team. Farewell two-hour meetings, good riddance! We can now make decisions in 15 to 30 minutes just by following our tree when adding a new feature.
Components were often built in an ad hoc fashion, and that is precisely what we tried to avoid by creating our framework and our manifesto. It aligns our team towards a common goal and enables us to make quick and productive moves. Much like programmers follow coding standards and best practices, we put together a few best practices for components, and our matrix is a vital part of it.First, we start by evaluating whether the feature our users requested must be added or not — based on how much usage we predict it will have. If, for some reason, we decide not to add a feature immediately, we keep track of it and wait until we know that we must add it because the developers using the OutSystems platform truly need it. In this, we are quite medieval and believe that “pain will bring us the truth,” meaning that we purposely avoid giving viable workarounds to see how many people actually complain.
After that, we use the decision tree to understand how to add the new feature. This way, we can ensure consistency with other features, meaning that integration within the component and other components will be seamless, making our devs' lives easier.
A Whole Branch of Questions
Let's imagine that we want to add the Center property to the map. This property specifies the place where the map should be centered. The first question is, "Can it live isolated on the page?" In this case, we pick “no.” The Center feature can’t live isolated on the page and is intrinsically related to the map.
The next question is, "Can it be defined by a boolean, number, string, or identifier?" The Center needs to be defined by its coordinates (latitude and longitude) or address. So, the answer to this question is “yes.”
Those are some of the rules we follow when dealing with more complex properties. We like to provide a subset of options with relevant values instead of having an "open" field to ease the development process. For instance, in the case of Zoom, we decided to give devs a group of options (read a static entity) instead of having an Integer field (they can always extend it and add other values).
Next, we have the following question: "Is it mandatory or is it frequently used?"
We avoid having mandatory fields as much as possible and give smart defaults instead to speed up the development process. Usually, mandatory fields refer to lists or variables that the developer must define and that the pattern will not work without.
To answer the second part of the question — "Is it frequently used?" — we rely on data (from interviews, our community forums, and usage data). If we know other OutSystems / Forge components with similar properties, we check their usage to understand how developers are working with them. This way, we can make informed, data-driven decisions.
As far as the Center property, it wouldn't be a mandatory field, but our developers would use it frequently. The answer is “yes.”
And we reached the end of a branch! According to the tree, the center of the map must be a property at the root of the block, that is, one of the properties that are immediately shown to the developer given its relevance.
Keep Your Users Close, and Your Pain Points Closer
One of the reasons why we felt we needed a decision tree to support our decisions is because we’re so close to our users (see point seven of our manifesto). For us, that is crucial to provide the best developer experience.
Being close, however, brings you new insight into their needs — and with new needs come new decisions, which lead us back to our tree. You get the point.
Fast decisions mean faster actions. And with every problem we solve, thanks to our users’ feedback, our trust capital continues to grow. Users trust that we will make their experience better, which is invaluable. It’s how we keep on growing and improving as a team.
One of the ways we keep in touch with the developers that use OutSystems is by inviting them to an interview with the team. Feedback can be scarce in the first few days after you release a new component, so if we get comments or questions in our forum, we reach out to those developers to question how we can further improve their experience.
(Again, keep the feedback looping.)
But that’s not the only thing we do...
How We Keep Track of Users Feedback
We have devised clever ways never to lose track of the feedback we receive. If you read our previous article, you know we are motivated by laziness. Why chase inputs in many different platforms when they can come to you?
Picture this: you have multiple threads from multiple components. Now, you have to keep track of them. By keeping track, we mean something as simple as knowing which threads you already answered and provided the user with the right solution so that you can act upon the unattended ones and don’t miss that precious feedback.
Well, this can be a nightmare to manage, as more and more components fall under our hat. So, we needed to develop a new way to control the threads from our assets. With the help of scraping tools, we created an internal application that combs through all the questions from our components' forum pages and collects the following info:
- Date of creation
- Number of comments and likes
- Reply dates
The best part is that the app does all of this behind the scenes, which means that in short (and configurable) intervals, the scraping runs itself and collects the data to fill our five-component thread slots. It then highlights the ones that may need our attention either because they have new questions from our community or recent updates.
And, in case you’re wondering, the application could, of course, have been done differently, but it was built within the current limitations of the forum, which doesn't have any supported or public APIs to analyze the community posts and group the threads to answer our needs.
Sampling for Success
Finally, there’s nothing wrong with a bit of show and tell.
To amp up our developer experience, we focused on building rich samples, full of real-life examples, to help developers understand how they can use our components. Our samples are available for download on Forge, allowing users a live sneak preview of our components.
Since we have experience with development, we know that an excellent way to learn is by seeing and doing. The samples that we build have a double purpose (check out the ones we created for the OutSystems Maps and Data Grid Reactive components). They are documentation but you can download the source code and, instead of just reading the documentation, you can check how the sample was implemented.
This really helps reduce the learning curve and gives a sense of openness for our users, since we are showing and sharing our code (just like Git, where our repositories for OutSystems Maps and Data Grid Reactive, for example, are public and we have even received and accepted pull requests from people outside OutSystems).
In the end, we build the documentation and samples that we wish we had when we were (or are) in the developer seat. And ultimately, that is why we work so hard towards a fantastic developer experience — it takes one to know one.