tldr: Rules of non-shitty software for the impatient.

Seeing the rapid technological advancements in recent years, from widespread internet and smartphone usage, to the abundance of communication, information, knowledge and entertainment, along with the now starting AI revolution, it’s easy to embrace the sentiment “What a time to be alive!”. I certainly share this enthusiasm. But looking more closely under the hood at your daily experience with software these days, doubts may arise and you may start to wonder if it’s really as shiny as it appears. I at least do so and there are also others who raise that question.

There is a great talk by Jonathan Blow with the title Preventing the Collapse of Civilization. Despite its seemingly broad and dramatic title, it is a very good talk about software quality and complexity. With these topics placed in the larger historical context of technical progress, the name fits the talk very well. Investing time in it is well worth it. In case time is a rare resource for you, watch with increased playback speed. Even if you don’t agree with everything or even most things, there are many interesting thoughts and perspectives on the topic of technical progress, software quality and complexity.

In this article, I will pick up some thoughts from the talk but will also share some additional thoughts and perspectives on the topic of software quality. Especially with nowadays popular SaaS, there are some additional aspects to be discussed. So, this is my perspective on the topic of (non) shitty software.

Software shittiness

Going back to square one: what makes up shitty and non-shitty software?

Reasons for shitty software can be broadly categorized into two areas:

  • Technical issues
  • Usability issues

It could be argued that technical issues may also lead to usability issues from a user’s perspective. On a general level, I can sympathize with this viewpoint. Indeed, software that constantly crashes, runs slowly, and is unresponsive is hardly usable and certainly has “usability issues”. However, when analyzing the root causes and methods to address these issues, I see two distinct categories. For lack of better terms, I refer to them as technical vs. usability issues in this article.

Technical Issues

Let’s begin by looking into technical issues which come in various forms:

  • Bugs
  • Responsiveness
  • Wasteful use of resources

Common to these kind of issues is that these are “simple” issues in your source code. You can measure, track and fix them and then everything should be fine. Therefore, there are no excuses why your software should suffer from technical issues mid-/long-term. Certainly, software development is challenging and most software begins with technical issues, particularly when it is used in ways not anticipated by the developer. However, since these issues are clearly measurable, the software should evolve into a stable form without technical issues. Once identified and fixed, technical issues should be covered by automated regression tests, so we even have technical solutions for convergence to software without technical issues. This makes it even more surprising when seeing the technical quality of widely used software nowadays.

Bugs

Functionality breaks more or less randomly. Either with meaningless error messages (“something went wrong” - “yes, I see that”) or none at all. We all know them and they happen more often than they should. See entertaining examples of this in the “We don’t expect software to work any more” section of the “Preventing the Collapse of Civilization” talk.

Personally, I don’t really buy into the “The market won’t pay for it!” excuse mentioned in the talk. First because in my opinion with lots of software nowadays we don’t have really functional markets. See more detailed thoughts on this topic later.

And secondly companies make lots of money with their software and margins are traditionally very high in software businesses. Would companies go bancrupt when focusing on delivering stable software? Would competitors outcompete them? I doubt that very much. There are also regulated industries with software development (automotive, medicines) with a very high focus on technical quality and earning good money.

I think it is hard to get objective measures about the reasons. But I see following aspects to play a role:

  • Complexity
    Software and tech stacks becoming more and more complex. Complexity makes developers slow and increase the likeliness of technical issues. One interesting aspect of complexity: there seem to be two different kinds of complexity.
    • Intrinsic complexity
      Some problems are complex in it self, no matter how you formulate, transform or partition the problem is is an inherently complex problem to solve.
    • Artificial complexity
      Apart from intrinsic complex problems we tend to see more and more artificial complexity. Overly generalization and leaky abstractions, distribution across teams, lacking understanding of the problem all lead to artificial complexity. Especially artificial complexity makes it hard to reason about your system and your code which facilitate technical issues.
  • Large organizations
    Large organizations are a challenge in itself and not helping in regards of technical and usability quality. Most likely they don’t have holistic product developement. Each team sees only it’s own little small part. Apart from leading to considerable increased complexity this also leads to slow turn-around cycles makes it very hard doing larger scale changes. Organizational structure bleeds into technical structure (Conway’s law). Organizational complexity leads to artificial complexity.
  • Weak competition
    I think weak or lack of competition is especially in the SaaS and enterprise area a factor. Once established at an audience software can get away with lots of technical issues. Especially if quality is degrading over time. And I think one big reason for this is, that companies get away with it because of vendor lockin. Switching cost of most software is large. If switching software would be as easy as buying a new hammer or ordering from a different delivery service this would make huge difference. But with vendor lockin most users will have to pay more for reducing quality over time, there is just weak to no market pressure towards more (features, quality) for less (money) after initial establishing the market in a particular domain.
  • “Move fast and break things
    There is no free lunch. Especially not regarding high technical quality. And although I can symphatize with the idea of early validation and validating your business ideas based on a MVP this is not sustainable to achieve high technical quality.
    Sometimes I wonder if certain company / software never moved on from the “move fast and break things” even already having an established product with many users. For these you don’t want to break things. You want to make sure to catch all issues before release.

What about test automation and test-driven development?

There are people who promise you the holy grail for solving all your technical issues: test automation or even test-driven development. And whereas I see test automation (like automation in general) as a very powerful tool in the developers toolbox, I find it often to be oversold in sometimes almost religous ways. There is a quote from Edsger W. Dijkstra quote which I find very telling: “Testing shows the presence, not the absence of bugs”. I’m not arguing against test automation but details matter here and it is not a free lunch automatically leading to high quality software. It very much depends on the details of your tests and what your are testing for. What does this mean regarding your software quality? Use test automation but see it as one of many tools in your toolbox and don’t expect it to automatically solve your technical issues or leading to high quality software. Additionally, in my experience, you want explorative manual testing to identify unexpected usage and behaviour which aren’t covered by your automated tests (yet). Although there is a great joke at the expensive of QA engineers:

“A QA engineer walks into a bar. Orders a beer. Orders 0 beers. Orders 99999999999 beers. Orders a lizard. Orders -1 beers. Orders a ueicbksjdhd.

First real customer walks in and asks where the bathroom is. The bar bursts into flames, killing everyone.”

For me, this is even more of an argument for additional explorative testing to increase the chances someone asks for the bathroom before the first customer.

For code checkers and static code analysis tools same basic expectation apply as to test automation. These are useful and powerfull tools in your toolbox but don’t expect them to magically lead to technical solid software.

Responsiveness

A more subtle technical topic is responsiveness, respectively lack of responsiveness and slow software. While technically not a bug in the literal sense it is nevertheless an increasingly annoying technical issue. Especially in the SaaS context. Coming from a background of games development I might be more sensitive in the area than others. But generally software should not feel slow. Slow software wastes users’ most precious resource: their lifetime. Besides generally slow and unresponsive software you also can experience especially annoying combinations of UI re-layouts with slow/unresponsive software. Oh, what fun it is to click on a button at the same time the UI re-layouting the buttons and a different function is triggered than intended.

How to ensure fast and responsive software? I guess the first step would be to be aware of the issue and having responsiveness and performance as explicit goals for your software. Neglecting any thought towards performance and dismissing concerns as ‘premature optimization’ will almost certainly ensure your software will be slow. At least if it is non-trivial or used on non-trivial input. If you already used the “premature optimization” argument in the past, chances are high you used it in a wrong context (at least this seems to be the standard today). Please read this article who put some context to the original meaning of this quote: “The Fallacy of Premature Optimization”. And even better checkout “Performance Excuses Debunked” by Casey Muratori where he is going into details about performance excuses.

For games 60fps are considered to have a good responsiveness. Thats 16.66ms (0.01666 seconds) of time available for doing the complete work for one frame. There are some exceptions of slower running systems (eg. AI) but everything where you want good responsiveness should fit into 16.66 ms. Some developers make considerable efforts to reach 16.66ms instead of 33.33ms (30fps) to have better responsiveness. Not every software needs to hit this target but I think it is a helpful reference and also should set expectations. Developers should think in milliseconds and not hundreds of milliseconds or seconds. At least for all interactive elements of their software.

In case you won’t check out “Performance Excuses Debunked” here is a spoiler and warning regarding effort expectation: depending on your experience and performance awareness it might not possible to reach good responsive late in a software project. You might end up in a situation where you practically have to throw away your software or re-architecture large parts of it to fix performance. So better be aware throughout your project from the beginning.

Wasteful use of resources

Non-shitty software should respect the resources of their users. The most precious one, user-lifetime, is so important, that I’ve discussed it separately previously. But also other things like battery power, CPU/RAM, disk space, network traffic shouldn’t be wasted. Compared to all other discussed technical aspects I think these are the easiest to forgive, as long as the waste stays reasonable.

I just wanted it mention it for completeness but won’t go into more detail.

What to do about technical issues?

So what can we do about technical issues? Are there any best practices? Some were already discussed but let’s discuss some general advice:

  • “Dogfooding / Eat your own dogfood”
    Using your own software in non-trivial cases helps a lot to at least raise awareness about technical issues. So if possible use your own software, intensively.
  • Focus on quality
    It’s hard work to keep or increase the technical quality of you software and keep it high. You have to invest in it.
  • KISS - Keep it simple, stupid!
    As complexity increases likeliness of technical issues increases, try to reduce complexity. This should be an ongoing effort.
  • Meaningful error messages
    This is actually a very simple thing to do but too often not done. Put a little bit of effort into your error messages/logging. The message should not tell you that something went wrong. The user already know this. The message should give details about what went wrong, possible reasons and possible ways to solve the issue. This are helpful error messages.
  • Easy way for bug reports (from within the software)
    As a developer it should be in your interest to get feedback about technical issues. Forcing the user to create an account somewhere or search for a contact on some webpage or support portal is annoying and will decrease the chance and quality of reports. In best case you should be able to directly report issues from withing your software including some technical infos/logs about the issue, directly collected from withing the software. Depending on privacy policy and tooling you also might to automatically collect data regarding technical issues. If possible do this, but be aware that this is not sufficient. There always will be issues won’t be catched by your logging. Logical errors and glitches probably won’t be detected. So additional make it easy for the user to report any issues.
  • Automated regression tests Once you’ve fixed an issue, it should not be re-introduced in some later release. So implement a regression test for it.

Usability Issues

Now to the category of usability issues and why I see them as distinct to technical issues. Whereas technical issues are rather easy to quantify:

  • does the features work always as expected (number of error messages and bug reports)
  • latency times
  • consumed CPU, RAM, battery-lifetime, network traffic

usability issues are not as easily quantifable and mostly not directly related to technical implementation issues. Often they are more related to the business model and UI/UX of the software:

  • User Interface / User eXperience (UI/UX) issues
  • User agency, ownership and privacy

In game development exists the phrase “easy to learn, hard to master” which means the game should be approachable, self explaining and easy to get into but should provide enough depth for experts and long term players. Something similar applies to software in general. It should be approachable, easy to learn and use for the simple use cases but not have dumbed down interface restricting experienced users or restricting the usability for users with more experience or more complex use cases.

Especially with web based software nowadays UI/UX often seem to be more dumbed down and restricted, limiting the usability to some guided user flows. It’s less like an approachable tool adaptable to the user’s needs. In general I experience a lot of modern software to be limited in usability and instead of empowering me as an user patronize with some basic use cases and flows. Often with a minimal viable UI/UX.

I see this as UI/UX issues mostly but these also affect user agency. I’m not in control as an user utilizing the software according to my needs, but have to adapt my use cases to dumbed down UI/UX of the software.

But there are are more fundamental issues than patronizing UI/UX: ownership of data and privacy. With web based software you often don’t really own the data you generate. Often the software vendor has full control and insight into the data you generate. Which is very problematic regarding privacy, ownership and user agency.

I see this as biggest problem with all the web based software and SaaS model nowadays. Especially as it increases the vendor lockin and prevents market mechanisms to work in the users favor.

In the context of online platforms the term “enshitification” was coined which very well describes the lifecycle you commonly see with online platforms. From my perspective we nowadays see an enshitifacation of SaaS in general. Enabled by lacking data ownership for the user.

User agency, Ownership and the “Software Market”

What are my expectations of software regarding user agency and ownership?

Software is a tool to operate on user data. The user should have full ownership of their user data.

What do I mean by full data ownership and why do I see it as so important?

Let me try to explain it with a metaphor:

Software should be a tool like a hammer. If you don’t like your current hammer, just go to the hardware store buy a different one and continue with your work. You don’t have to start from scratch, when switching hammer during a project. You don’t have to buy special other tools to convert your project to be compatible with the new hammer. It’s very easy and inexpensive to change your hammer.

Instead of being like a hammer, software nowadays is more like a marriage. Once commited, separation becomes expensive and painful.

Software needs to become again more like a tool instead of an experience or service.

In more concrete terms full data ownership means for me in best case equivalent access to my data as the software/service utilises itself. But at least machine readable format and automatable access to my data. The machine readable format should have same data quality as used by the software/service internally. So a paper print out or PDF export of my data doesn’t qualify for full ownership.

What about entertainment software and social networks?

In a broader sense this also works for social networks. User data (content) is published and shared with other users. I don’t see any technical reason, why a user can’t have ownership over his postings, likes, messages and contacts. Without having looked into the details, bluesky might be a try in this direction.

With entertainment software (games, streaming services) the expectation becomes less obvious. As the software is used to experience data (content) provided from the developer. So the majority of involved data is not user data but vendor data and it does’t make sense to expect user ownership on vendor data. But even in these cases often the user generates data. Often this data is utilized by the vendor to improve his service. The play history, their favourites/ratings and all other generated data should be owned be the user. These are also the things you want to take with you when migrating to a different service.

What about software subscriptions and SaaS?

They are totally fine. As long as users keep full data ownership.

If the software doesn’t deliver the expected quality or cost benefit ratio degrades, users can move to a different software with same or different license model. Users regain their freedom of choice when their data is not held hostage so the software license itself looses importance.

How to get their? What is missing?

That’s indeed a very good question. Regulation would be one way. I’m not sure if there are other ways which lead to more widespread full user data ownership in larger parts of the software industry. Most software developers probably don’t have any incentive for that.

As a thought experiment:

Given some established software type. A first mover to full user data ownership with otherwise comparable quality and scope probably has an incentive to differentiate itself from other existing solutions. But what happens after the initial growth period? When the majority of people moved to the new solution with full data ownership. Others developers will start to utilize the data availability and provide additional tooling and building their own business. The initial first mover will want to further optimize his growth and the easiest and most powerful lever would be the full data ownership. Especially as this can degrade over time, being available on paper, not in practice or just inconvenient.

So I’m not too optimistic for convergence in this direction by market forces but I’m happy to be proven wrong.

Local-First-Software

Before closing this discussion about (non-)shitty-software, I need to mention local-first software which aims to have non-shitty software with online collaboration but with full data ownership for the user. And the good thing there is a growing community around these local-first principles and even better there is tech in the form of libraries like automerge enabling easier development of local-first software. So, if you are interested in creating software with full user ownership look for local-first software.

The growing community and technology around local-first software is encouraging that we might see more non-shitty software in the future.

TL;DR: Rules of non-shitty software

Whew, this was a lot to read. So let’s just close with my personal rules for
non-shitty software:

  1. Always respects user agency, full data ownership and privacy
    • The data belongs to the user. Software is a tool for operating on user data. The user is free to select any software to use on their data.
      • Full data ownership means the data is available to the user in an automatable and machine-readable way, in the same quality as internally used by the software.
  2. Is local-first and works always, even without connectivity
    • In cases the software can’t be local-first due to fundamental reasons, all other rules still apply.
  3. Is stable and robust
    • Stability and robustness are prioritized over features and release frequency
  4. Is responsive without lag and loading animations
    • It doesn’t waste the users most precious resource: lifetime
  5. Provides meaningful and precise error messages in case of errors
  6. Offers an easy way for feedback and problem reports