Technical debt: move fast without crushing your later self

A month ago, as we were enjoying the evening around some beers with a part of the Equisense team, we had a great discussion about technical debt. After a couple hours thinking about our development process and how we interact together, we realized we simply did not have the same notion of what technical debt is, what falls in this notion and what is simply the normal way to build the product in a startup evolving at a fast pace (even more for a hardware startup).

The thing we concluded with Benoit is that these differences boil down to the programming paradigm every one is mostly used to:

It is normal for a firmware engineer like Cyril to focus on the instructions the processing unit has to perform and on the memory used at each operation. He is optimizing for the sensor to have the biggest autonomy and to use the most compact and handy components available. For Cyril, technical debt is an instruction which could have been avoided, resulting in useless computation time and lost energy on the sensor’s battery. For Cyril, copying an array should be avoided if possible: “Just use pointers and in-place processing”.

Another view of technical debt is the version formulated by Vincent, our Android developer. He has been working with Functional and Reactive Programming for some years and uses Kotlin as a primary language for the development of the application. He fully embraced functional programming as a way to increase readability, maintainability and modularity. It allows him to build layers of abstraction on top of connectivity tools, third-party libraries, data access, etc… In Vincent’s paradigm, technical debt could be a design choice not setting the right level of abstraction for a given service, making the use of a dependency necessary in a large portion of the application and preparing a much harder refactoring later on.

One last way technical debt is perceived is through Benoit’s eyes. As the CEO of a post-delivery, post-seed startup, time-to-market is so vital that building a system in a more complete way than required now is a sleeping asset (CFOs will see how this is an issue).

Source: xkcd

How can visions of technical debt be so different?

Simple, they’re not. In both Vincent’s and Cyril’s cases, the development of a piece of code to produce a feature in a given time induced modifications which are opposite to the key objective the person for their part. In both cases, the choice was not a mistake: we’re here to build the product our users will be willing to use every day, not to over-engineer our work to impress the tech team. That’s why technical debt is not synonym with bad code. The initial definition of the concept was phrased by Ward Cunningham and summarizes well the trade-off between speed of delivery and necessity of rewrites:

Shipping first time code is like going into debt. A little debt speeds development so long as it is paid back promptly with a rewrite...

In a nutshell, technical debt means reporting to later some rework in order to achieve a desirable objective earlier on, while being fully aware of it at the beginning. That’s the main difference with writing bad code, which also builds up a pile of rework for later, but does not achieve to get features out quickly. Even worse, bad code is usually written without having thought about the trade-off actually being made, or estimated the amounts of work, both that was avoided today and that was postponed to later.

Something concrete: Firebase at Equisense

Since the early testers and users, Equisense required a way to host the large amount of data generated by the Motion sensors. When I was working with the founders at the very beginning of the project, we stored everything on personal cloud spaces, we were the only people generating data and everything remained manageable that way up to roughly a hundred sessions. As the mobile apps were being developed and more and more riding sessions were recorded, the team adopted Parse, a Back-end as a Service provided by Facebook and then moved to Firebase, a similar platform acquired by Google.

Why use these services? Because time, money and focus are limited resources. Equisense was building the Motion sensor and the mobile applications to which it connects, that was what was announced and due to the backers of the Kickstarter campaign. For that speed of development and delivery, borrowing for our technical debt was an obvious choice and we would repeat it if we had to start again from the ground up. Firebase fitted our use case perfectly in the first months in the sense that we just wanted the users to be able to create, save and view their sessions.

Dilbert negotiating with legacy systems (NB: these are squirrels, not gophers☺)

Now what? Time to pay back and move on

The context of Equisense Motion is a bit different now, we moved on to mass production, improving our analysis techniques based on feedback from the community, getting some new features out on a regular basis. As we are extending the product, we notice how we slowly diverge from the single user-data relation Firebase is based on: we need more freedom for some features we are planning on delivering next year.

Another point is the maturity the technical team has come to, boiling down to:

  • Complementary backgrounds from mobile, web development, robotics and control, applied mathematics.
  • Getting used to working together, understanding and respecting everyone’s process, priorities and mindset.

This cohesion and maturity is even enhanced by the absolute flatness of the tech team, not having a CTO is the symbol for this.

Still, paying the debt you created in an earlier stage doesn’t mean you should not outsmart the problem: as we realized the maturity of the team and how opinionated we all are about the development of our back-end, we decided to take it on ourselves. One of the central reasons is that the subject is strongly connected to all components of the product, our bet is to be smarter through collective intelligence than by bringing in a new teammate who would have to adapt to our workflow, to the requirements and to our business logic.

So, how to deal with technical debt for speed and sustainability?

The second point with taking on this new part of the project is: how do we avoid building useless debt, how do we minimize the technical “interest rate” to keep the metaphor.

The first point was to use collective intelligence instead of starting alone: the pure loss of 3 days of a developer’s time is more expensive than the use of 2 hours of 5 people when it results in a tangible outcome.

The second point was to try out things instead of discussing them, building a small JSON API using a stack taught us more about the logic behind it than reading blog articles for the same amount of time.

But this will be the subject of another article, for now let’s get back to building our API ;)