The principle of least astonishment applied to code design

In a previous post I stated that “when you want to write a singleton, drink a single malt instead”. I also mentioned the “Golden Hammer” pattern which leads to poor design and low maintainability. The bottom line of it is : code design is not made of simple recipes you can use for every need. It is all about analysis and thinking. And it’s something you can (well, must) apply every day.

Application development is a world of rules. Unless you lived in a cave the last twenty years, you’re aware of design patterns, SOLID principles, test-driven development and some other best practices, you may even apply (please: not the singleton). The principle of least astonishment is not one of them in the first place, it was mostly established as a rule of thumb for user interfaces. But if we think about it, it’s a rule we can apply on software design and architecture.

According to Wikipedia

The principle of least astonishment (POLA) (alternatively “principle/law/rule of least astonishment/surprise”)[1][2] applies to user interface and software design.[3] A typical formulation of the principle, from 1984, is: “If a necessary feature has a high astonishment factor, it may be necessary to redesign the feature.”[4]

That sounds mostly related on how the application is designed from the user’s perspective.

In general engineering design contexts, the principle means that a component of a system should behave in a way that users expect it to behave; that is, users should not be astonished by its behavior.

Not only that If the user is too astonished to use the feature we should redesign the feature, we also must design the feature as the user feels how the feature should be. That means we need to define personas and try to think like them, act with their own purposes and habits (habits are really important here).

If you are involved in a software creation you always have to keep in mind that you don’t work for yourself. Of course, the finality of the project is to satisfy the End-Users as those people are customers and they may pay for the product you created, however you must have in mind all the other actors while working on the project.

In the developer’s world, its first users are the other developers

Writing code in its widest sense means taking many decisions : languages, frameworks, libraries, coding style, how the configuration is stored and many (really many) other matters. In many cases, a decision implies a consistent set of choices. For instance, if you decide to write a web application with Symfony, you also choose to :

  • use PHP as a backend language
  • use namespaces
  • write controllers to handle user interactions

You may also :

  • manage dependencies with Composer
  • write code according to PSR-2
  • write configuration using YAML syntax in the config/ folder
  • use dependency injection
  • use Twig to render views
  • use Doctrine to interact with the database

But none of these are mandatory. You are free to decide how to use Symfony to build your application. You can use a home-made configuration system, write your own ORM and store all the dependencies in a dedicated folder, the application will work. Certainly with bugs, a lot of workarounds and annoying tricks, but you’ll manage to have it running on a live environment. And everyone in your team will hate you just because you didn’t behave the way they expected, making each of your decisions hard to understand. Just because you didn’t apply the Principle Of Least Astonishment when you designed your application. In that case, doing the right thing would have been simply using the tools and standards provided by the framework like every developers expect you to do. And because it is done in the the obvious way, it follows the Principle of Least Astonishment.

In fact, we are talking about something really personal. When you play by the rules, you are open to compromises and you are ready to learn how to work according to standards even if you didn’t choose them. That’s teamwork. It’s not about skills, it’s all about attitude. That’s what I call empathic programming as you never write code for yourself, you always write code for the others and as such, you always think about them while you’re doing your job. And the first folks you must think about when you write code are your teammates, the poor lads who will have to read it and understand it in order to maintain it. If you played by the rules and ask yourself “how another developer will react ?” before taking decisions, they’ll love you and praise your work.

POLA to the rescue of Empathic Programming

But wait, what are we talking about ? The Principle of least astonishment or Empathic Programming ? Well, both. Because there are closely tight in the development’s context. Being an empathic programmer involves asking to oneself “what would be the least surprising to another programmer in that code ?”, which is very close to the real POLA. When we design user interfaces, we try to make it easy to understand and “with which our users are likely to be familiar”. It’s the same when we talk about programming, all my teammates need to understand what I did in a short amount of time. And for that, they need me to write my code in a predictable manner. If something in the code or a user interface causes surprise, it brings confusion and a lower trust in it, as we lose the ability to anticipate its behavior. And please, please stop answering “I know it’s confusing but I wrote a comment” ! Why ? Because you just add more confusion with an inaccurate explanation (sometimes full of typos) which becomes outdated as soon as another developer tries to add something to it. Writing a comment to balance a high level of complexity is just lazy, the best you can do is to refactor the code (in most cases this is the solution).

Think about all those times you were forced to deal with a 400 lines-of-code method full of weird comments, imbricated if statements and many other bad surprises that caused many troubles to achieve an apparently simple task. Yes, you’ve been one of them too and you know how it is unpleasant to go through this. This trouble comes from an usual flaw in the way we achieve development tasks : we focus on the result, not on the way to do it. Which leads to technical debts, tensions between teammates and sometimes unsolvable bugs. Programming with the others in mind will help you improve your code quality as you care about how about how the others will understand what you did.

Being an empathic programmer also involves the ability to accept criticism and to learn from others. Of course, you need other people to criticize your work with respect, but you also need to know that it cannot be perfect and how to improve it at the right moment (now or later).