Principled Design

What makes good software?

These are obvious candidates, but even here there is room for debate between the individuals who work on the software.

One property of software that I like to see is a consistency of vision, which tends to be easy enough to achieve with a one man team over a short period, but is more challenging to maintain over a longer period or with more people. By “vision”, I mean a high level consistency of understanding of what the software is meant to solve (and what it’s not meant to solve) and the general way in which it sets about that. Over a longer period of time, it’s very easy to forget what properties of the software were important when it was created, and therefore how its fitness of purpose should be evaluated.

These sorts of high level concepts are easily lost from documentation but are important for new people working on a piece of software to understand. I’m a big fan of giving a software library a mission statement, but I’ve found that a list of principles is very useful in a number of ways, including fostering debate.

What principles are important to me?

Here’s the exercise – make a list of principles you feel that are important to how you build something that you’re working on.

Here are some guidelines for making this list:

Keep it short and sweet (~10 items)

Prefer ideas that force people to go out of their way over things that are expected

Avoid being specific to a particular solution (though this may sometimes be called for)

Don’t worry about order

Ensure that each principle is clearly communicated, but brief

You may add explanations about the reason for adopting a principle afterwards

Principles can be changed after they are agreed, but doing so ought to mean that you need to address the parts where your software violates them, or consider if you need to start again.

Pick only principles that can be evaluated against an implementation; if you can’t then you still lack concreteness or clarity

If your organization already has principles for software construction you need to make sure your principles are not contradicting them

Put it somewhere it’s easily found for reference

The goal of this list is to:

Foster debate within the team or with stakeholders about what is important

Help constrain the shape of the solution, without dictating the implementation

Provide an explanation and motivation for inconvenient choices

Provide a checklist for evaluating new features/changes

Help you to realize when a new feature or change would compromise the original principles and therefore lead to an inconsistent and confusing design

A quick bit of reasoning about the principles:

It’s important to be brief because the point is to communicate things to other people quickly and the principles need to be easy to remember. You want to keep the list short, so that you have a reasonable chance of sticking to it, and describe each item at a higher-level, so that the items provide value to a large area of your software, rather than small pockets. Principles are not rules, they can be broken, but there should always be a conversation about doing so.

If everyone in your company believes in XP, TDD etc, then having a principle that your software is unit tested doesn’t require anyone to go out of their way. However, if all of your technology is generally tied to a very particular tech stack and environment but you need this new software to be usable, for instance by a build system, outside of that environment, that’s a good principle to put down.

You should pick a solution because it achieves your goals and fits with your principles, not because you picked it up-front and put a principle around it. Principles should provoke a discussion about when an existing solution doesn’t fit any more rather than enforcing blind continuation. Note that the principle itself trumps the explanation, so an explanation could be a specific example, but that should not limit the principle.

Avoid things like “The software should be well written”, or “The game design should be meaningful to players”. These ideas are subjective and open to interpretation, as well as being almost impossible to evaluate.

A nice thing is that this can be applied at almost any level, to almost anything. You can make some company-wide architectural principles, personal principles or principles for a library.

Some example principles & explanations

Modular – the libraries should not require each other. Requirements will change or be different for new projects, new components will develop. This should be embraced without requiring us to discard the whole set of tools.

Standard Formats – the tools should use standard formats, allowing tools to be written in other languages or scripts.

Local testing – parts of the solution that are vendor specific must be testable locally through the use of interfaces & dependency injection

Minimal Setup – the software should be easy to deploy

Iteration time is important

Familiar – The solution should be familiar to game designers using it, and quick to teach programmers to develop with

HTTP First – REST/JSON based network APIs are preferred over custom formats and transports.

Push – deployments should be pushed, not pulled at random times by cron jobs / hup / agents.

Free of Game logic – our back-end services will not be polluted by game-specific logic, but will use generic feature flags to achieve the desired behaviors

Software development hot air

This just provides a tool for communication, discussion and a bit of periodic reflection on what you find important. These things are achievable in other ways, but I’ve found that this is a lightweight way to help you mold your solution to set of concrete underlying ideas that might otherwise be lost. The constraints provided give other people a map to follow in understanding the path that you took, and a chance to follow in your footsteps (or express their differences).

Principles are a purer motivation than practices. Practices can become rote. You can sprint, groom the backlog, do stand-ups, and still not be Agile. By keeping principles close to your heart, you, your team, your code-base and your practices can be in a continual cycle of self-evaluation and evolution without it being haphazard. Challenge yourself to live up to your principles.