14 February 2022 / Last updated: 14 Feb 2022

The balenaCloud dashboard: why we change stuff and move things

There’s a lot of thought and reasoning behind what seem like trivial changes that I want to share with you all publicly. From the outside, I feel that the effort that we put in to ensure things such as product longevity, maintainability, and reliability may not be obvious, so I want to explore that today.
Chris here, your friendly neighborhood product guy, back with another attempt to take down a barrier and expose more of what goes on at balena to the world. A while back I wrote about why we renamed applications to fleets, a seemingly simple change of terminology but with a lot of hidden thought and reasoning. We got a bunch of useful feedback and comments on that post, which was really valuable to myself and the wider team as well. This time I’m going to write a bit about the balenaCloud dashboard and why you may notice things changing and moving around.
Grab your beverage of choice and let’s dig in, then after that feel free you are encouraged to head to the comments section and let me have it - we all really appreciate your feedback and comments.

Nobody wants another CRUD app

Firstly, let’s explore a bit about why the balenaCloud dashboard exists in the first place. The dashboard is, for the most part, the go-to place for managing everything to do with your usage of the platform. Sure, we also have the command-line interface (CLI), the software development kit (SDK), and a documented API for direct access to your data, but the dashboard is the easy-to-use, graphical, web-based interface the majority of people use to get things done.
At least, that’s what we’re aiming for.
Given that it’s so important, we need to make sure that it works, is fully maintained, reliable, and grows with you as your fleets grow. In order to do this, we take on not only the job of building new features, but also planning a sane roadmap that prioritizes the features that everyone out in the world uses to get their work done, making sure that nothing breaks along the way.

Pleasing growth, some maintenance

We need to constantly keep track of the work we’re doing to ensure that anything we add does not end up exponentially increasing the maintenance workload. We need to make sure that the growth does not stall because everyone is spending their time maintaining what we’ve already built. Sounds easy, but this is a tricky thing to achieve and requires a certain mindset.
In order to keep the amount of maintenance low, we’re constantly reviewing what we have running in production to ensure that what we build is created in the most reusable and repeatable manner possible. At the same time, we need to give users a consistent experience. It’s easy to throw another modal here, another checkbox there, and work in an additive manner all day long, but what we want to do is make sure all of our changes are intentional and add features with referenceable reasoning.
We want to build a coherent experience, creating elements and functionality that all works in the same manner without surprises or other unexpected behavior. One of the key ways we do this is using a library of reusable UI components: Rendition. Give it a try; it’s open source!

Hunting for hard problems

One more thing of key importance is to give everyone on our team the opportunity to work on something that is a unique challenge. Nobody wants to feel like their time is being wasted, so building a new CRUD app for the nth time is perhaps not the best thing someone could be spending their time doing. But, building the app that builds CRUD apps? Maybe!
The point here is that we’re looking to solve for the bigger picture: to always go one abstraction layer higher, to make sense of the technology, and to complete the hard-mode challenge before it becomes critical and starts to hold back further development.
We want to give everyone using the dashboard the best possible experience we can, deliver the features that everyone needs and wants, all whilst enjoying the process and avoiding wasted effort. This means we will occasionally rethink the way things are implemented and change them.

“The version of the dashboard you are viewing is out of date”

If you’re a balenaCloud user, chances are you’ve experienced the notice that pops up to let you know that there’s a new version of the dashboard. You may have experienced this a lot.
The reason you see this frequently is because we develop on a ‘merge = deploy’ principle. This means that if a change is fit to be merged to the main branch, we believe it’s ready to deploy so that everyone gets the benefit of the new version as soon as possible. Regardless of if it’s a bug fix or a feature, if we believe we’ve made a change that makes the product better than before, why not get it in the hands of the people as soon as possible?
Some days, we deploy to production 10 times. You could argue that we could batch up those changes and deploy them all at once, but that’s how things end up getting blocked or delayed. If something is broken and preventing you from managing your fleet, a 12-hour wait is a long time. A one hour wait is a long time. Even a 15-minute wait is a long time if your team is out on site somewhere waiting to deploy a device, so why not automatically deploy as soon as that fix is available?

Removing friction whenever we can

Similarly, within the team we look for the most friction-free development cycle possible. If someone on the team builds a new feature, we obviously want to get their work into production as soon as possible so people can try it and we can start to gather feedback and iterate. We want to work in the open and let the world see the fruits of our labor as soon as we possibly can. There’s also nothing better than seeing your hard work out in the world and having people use it to achieve great things.
To achieve this means that the full deployment pipeline is completely automated. From PR to production, anyone on the team can make a change to the dashboard and have it in production in minutes. That is, if they can get it past the ever-watchful eyes of the frontend team, who are omnipresent and heavily invested in making sure what makes it to production meets all of the criteria that I describe here.
I’ll keep my dirty hardware hacker hands away from the dashboard, I promise. Maybe.

Chasing data-driven deliciousness

We’re proud of the work we do at balena. We believe the data model that supports the balenaCloud platform is an awesome thing, and represents the entities we work with day to day in a logical manner. This includes things like fleets, devices, releases, users, organizations, teams, etc.; we put a lot of thought into making sure relationships between these entities work well and that the structure makes sense.
It then stands to reason that any UI that works with this model should want to reflect that, and expose that structure and those relationships.
When it comes to the dashboard, we can do it and we’re on the road and heading for that destination; but we’re not there yet. In the past, functionality has not always been put in the most logical place, and people (including myself) have become used to it in those places. So for those of us who are comfortable with the dashboard and where things are today, it means we’re going to notice things moving around. We’re going to notice settings and functionality move to different places.
This can be frustrating at times, even more so when you’re trying to get a job done. However, we’re transitioning to a point where everything should make a lot more sense and have reasoning behind it. We’re hoping that the changes won't be too jarring, and that navigating and finding what you need will be easier in the future.
In terms of real change, it’s going to mean structuring entities so the manner in which they are presented matches the manner in which their data is stored. Actions and settings applying to those entities should be directly connected and easy to find, and not be mixed up with those belonging to related entities. It doesn’t make sense to have actions (those things which don’t affect the data model) and settings (those that do) for a device present at the fleet level. They may be present on the device list so you can apply them to a group or batch of devices at once, but they don’t belong to the fleet entity itself.
It may seem like a trivial thing, or a technicality, but it’s really important when it comes to organizing a UI and structuring functionality in a predictable way.
In addition, it’s going to mean ensuring that functionality is well organized and placed intentionally. It’s going to mean that when we’re adding a checkbox, or an icon, we’re going to go in-depth, understand why that icon is even necessary, and solve for the general use case. We’ll identify what sort of element it should be and abide by UI conventions. This means that next time we need to add one, we can follow that convention and reduce the amount of work required. It means that when we do add that icon, its state should be informed by the data model for the entity which it relates to.

Angling for an automatically awesome UI

It stands to reason that if we want to produce our dashboard in a way that’s fully based on reasoning and logic, and follows a structure provided by the underlying data model, that we could abstract our work to a higher level and programmatically express that same reasoning.
Imagine a situation where the data model is represented accurately with an API. Every aspect of that data is allocated structured API endpoints. We then have a data model with a predictable and fully implemented API.
What if we then are able to apply our abstracted reasoning and logic that describes how we want to create our UI? If we pull this off, suddenly we’re on a path to allowing us to generate our dashboard fully automatically.
A new field is added to an entity? No problem - the data model is updated, the API spec is updated, and the UI is automatically regenerated and now includes that new field. Sounds cool, right?
It’s a hard problem to solve, so it’s not going to happen all in one go. However, what we can do in the short term, and more in line with the point of this article, is gradually migrate specific components of the dashboard to be automatically generated. We may not yet be able to generate the entire dashboard, but we’re already automatically generating certain parts of it.
You may see elements like lists, menus, forms, etc. all subtly changing, and this is the reason why. We of course want to offer the same functionality, but we want to generate the elements automatically, so you may notice small changes to bring those elements in line with the underlying data model. In some places, we are already close, and so these changes will be minimal. In other places, there are larger differences that require bigger changes.
With the realization of this concept, we’re making serious progress towards the goal of creating a predictable, maintainable, and high quality dashboard, all whilst doing it with the least amount of repetitive work we possibly can. This allows us to focus our time in the places where it has the most impact, and to cut down on the amount of maintenance required.

So, why do we change stuff and move things?

Finally, the author has come back; back to the point of this beautiful piece of long-form wordsmithing. As a quick recap, we’ve got:
  • A desire to build reliable and feature-rich products without exponentially growing our maintenance burden, all while keeping the task enjoyable
  • An automated deployment pipeline that gets PRs into production lickety split
  • Moving toward a data-driven UI and pursuing a fully automatically generated one at that
All of this adds up to a product that changes frequently and develops at a rapid pace, but we think that it’s all for a good cause. At the end of the day, we owe it to our users to enable them to build and manage their fleets, achieve their goals, and to enjoy a friction-free experience whilst doing so. We owe it to ourselves to make sure we can continue to develop and offer the tools to do this in the long-term.

Communicating change

OK, so I have explained a bunch about the reasoning behind these changes to help you understand why we’re doing this work, but how can you keep up with the changes and understand what’s actually happening on a day to day basis?
I personally think it’s really important that we share the work we’re doing with people, and we hope to be continually improving in that regard and will endeavour to keep increasing the amount we do. Similarly, when we’re making many changes with such a high update rate, we want the list of changes to be easily accessible to the users of the product.

NEW: balenaCloud changelog

We recently added a changelog to the balenaCloud dashboard to do just that. You’ll now notice a version number in the bottom left corner of the dashboard. It’s a version number for the dashboard that’s currently running in your browser.
Clicking the version will open up a modal with the changelog exposed. This has been an awesome thing to get out into the world, as it’s allowing everyone to see the changes, try the new features, and understand a bit more about how much effort we are putting in. We’re continuing to work on our changelog entries and in the future looking to expand into providing descriptions as well. Look out for changes that mention “AutoUI”!
The version number that’s exposed here is a Semver version number. The basic premise is that the leftmost number represents a major version change, the middle number a minor version change, and the rightmost a patch. Semver uses terms such as ‘breaking API change’ for major versions, but what this essentially means is that the interface to this piece of software has been changed in a fundamental way.
Given that within the dashboard we’re not interfacing with APIs, but rather interfacing with humans, we are trying to use that approach to set version numbers. A breaking human-interface change could be considered as something that requires the user to change their thinking and adopt the new version. This could be as simple as moving an item in the menu; the important part is that the user behavior before the change is not the same after the change.
The dashboard is only one component of many, but we intend to apply this same approach elsewhere and share as much information about what’s happening with regard to development of these products as possible.

Thanks to you

Thanks for taking the time to read my waffle, and again thank you for your patience as we work to deliver the most rational and maintainable tools we possibly can to make your lives easier and reduce friction in the work you’re doing. We think it’s important to work hard to expose our inner workings and culture to the world; there’s no reason we can think of why this kind of discussion needs to happen behind closed doors and so we’d love for you to give us your feedback.
We realize that stopping what you’re doing in order to submit a bug report, ask for support, or otherwise give feedback is an annoyance and a bunch of extra work, and so we appreciate every single piece of input we get. Rest assured everything is heard and used to help improve things in the future.
The approach described here today is something that we strongly believe in and will continue to apply across all of our products, not just the dashboard. Similarly, we’ll continue to look for more ways to expose what we’re doing to the world, share our culture, and allow everyone to have a say.
As always, I’ll be hanging out in the comments section below to discuss anything in more detail and answer any questions you may have. Ciao!
by Chris Crocker-WhiteHardware Hacker turned Product guy