My colleagues sometimes get into heated debates about the difference between a programmer and an engineer. The latter is more common in the US than the UK, and often people in the UK don’t really understand what is meant by it. My usual answer to this question is that words are made up and don’t mean anything, but my helpful answer to this question is that to me, programmer means “programs things”, engineer means “works with technical systems”, and the former is a subset of the latter.
Before I got hired as a software engineer by Rare, I studied mechanical engineering at university, which means designing mechanisms and structures. I learned lots of interesting stuff about different kinds of steel, but I also learned about the engineering principles behind designing any functional system. I use that knowledge at work daily, and even though I picked it up in the context of clevis pins and composite materials it applies very nicely to templated functions and explicit constructors. So here’s the end to end process I use for designing technical systems of any kind.
Know Your Hard Requirements
When you’re designing a mechanical system, the first thing you do is lay out where your part connects to the rest of the machine, and what movement it should allow or drive. Breaking problems down into a set of the simplest, most important requirements like this is a good way to start designing any technical system.
There’s two main benefits to this. Firstly, you have a working (if non-optimal) solution as soon as possible. It’s a good way to avoid having to scrap bits of your work later on when you realise your system is missing a critical piece of functionality.
Secondly it’s good for your mindset to focus on creating a solution that fits the requirements. This may seem obvious, but it’s easy to end up trying to fit a traditional or popular solution to your requirements when it could be totally wrong.
Say you’re designing a car suspension. Your contact points are where your design needs to be attached to the rest of the machine, so that’s the car body and wheel hub. A degree of freedom is what direction your contact points need to be able to move. So for our suspension, that’s that the wheel should be allowed to move vertically to accommodate bumps in the road. Now we don’t have to think about the fact that we’re designing a “suspension”, we just have to design a first draft of something that connects the contact points like this. A couple chunks of metal would probably do the job!
What’s important about these requirements is they can only be met or not met- they cannot have a scale attached to how well they can be met. Without any one of these “hard requirements” you haven’t designed a suspension. Without “sliding scale requirements” like low weight, low cost and high strength, you’ve just designed a bad one. Most importantly, sliding scale requirements can be met by optimising over several iterations. The hard requirements are much harder to fit in later without a full redesign or tacking them on.
All this is totally applicable to software engineering. Instead of your contact points, you’re thinking of what the input and output of your system is, and what parts of the larger system it needs to communicate with.
Know Your Measures Of Success
If we’ve got something that works, how do we know that it works well? What are our measures of success? For this, we’re going to define our measures of success as the benefits for the end user of our design, not the people making it. So, we’re not worrying about resources (People, time, skill, money, etc) required to produce the design for now.
If we’re designing a piece of software and we’ve met our hard requirements to solve our problem, the faster we make it run the better it is, right? Hmm.
I’m a strong believer in the idea that there is no best in engineering, there is only fit for purpose. If you’re one of the surprisingly few people who have heard the phrase “As useful as a chocolate teapot”, that might be your go-to example of useless, the worst to the fictional best. But this becomes meaningless if you’re not intending to use it to dole out hot beverages. It’s very fit for purpose as a novelty gift, and it is more, but not the most, fit for purpose as a snack.
What’s better image manipulation software, Adobe Photoshop or Microsoft Paint? Many people will tell you Photoshop of course- you can do so much more with it! But if this is true, why are purveyors of the finest internet memes still relying on Paint? Because it is the most fit for this purpose. Photoshop’s advanced tools are a great choice for a professional user making undetectable improvements to wedding photos. To any clueless fool superimposing your mate’s face onto a popular meme format before the joke goes stale, Paint’s speed, simplicity of use, and ready availability, is second to none.
So for our car suspension, what kind of car is it for? Is it a racing car that needs to be as light as possible for maximum speed? Or is it a family car, that can sacrifice speed for safety and ease of handling? Don’t forget that a family car still needs to be light enough to comfortably drive, but our acceptable window of values is much larger.
For your software, what’s important to your users? Is it a game, that needs to be rendering whole worlds at 60 frames per second on home computers? Or is it an analysis tool made for a specific hardware setup where the user can wait a little for an answer, but has other requirements like needing the maths to be precise as possible?
Know Your Costs
One of the most critical aspects of designing technical systems is that there’s no use designing something that you can’t actually produce. In the world of mechanical engineers, this means manufacturing a physical object and while RSI is no joke, I’m pretty confident trying to source 4mm diameter ball bearings has taken years off my life.
In software, it’s still a very tricky job and that’s the reason we have project managers to allocate resources of funds, staff and time effectively. Especially in games, where often our main measure of success is a super motivating one (Player value!), it can be hard to balance our benefits against the cost. The questions to ask here are
- What are the required resources for implementing this?
- Do we have the required resources?
- Is this the best use of these resources?.
This doesn’t mean that we should be leaving out small improvements or details. Some small improvements have big impact and are worth dedicating lots of resources to. Some small improvements only slightly add to the user experience but are very cheap to make. What’s important is that the resources spent should be proportionate to the value of the feature, not the size of the feature.
Apply Optimisations Iteratively
Premature optimisation is a very easy trap to fall into. My dissertation involved designing a mechanism that fit inside the handle of a rollator. I sat down and attempted to create the perfect design in one go, cleverly anticipating the need to keep the user’s hand in the right place on the handle. I blew the entire 6 weeks I had for this project designing this handle casing to be perfectly moulded to any hand size and never got the actual mechanism to work. All without any evidence that ergonomic shaping was needed!
The helpful part of the experience was learning that any optimisation that doesn’t come for free needs evidence, and defined parameters.
So good design is an iterative process. Create an iteration of your design, assess this design against your measures of success, and find ways to improve it against these metrics. Of course if every little tweak required a full reimplementation of the design, this would get very expensive, very fast. Especially if implementation means sourcing 4mm diameter ball bearings. Mechanical engineers have this down to an art, creating 3D models of designs and using complex mathematical software to analyse their physical properties. In software, we don’t have so much of an accepted process for proving out designs, but it may be worth writing a prototype version, free of inertia like code standards and unit tests.
If the finer points of this article pass you by, much of my advice boils down to:
- Think about what you want to achieve before you begin
- Find ways to achieve that using the resources that you have
- Regularly reassess your strategy
In software engineering, it’s not often stressed that so much of the work is about design. These are the kind of concepts that many engineers pick up subconsciously over time, but they’re rarely distinctly acknowledged and often conflated with project management, which is only part of the process. Mechanical engineering and software engineering are the areas I’ve studied, but I like to think that this mindset can help designing anything else too.
Thanks to Topher Winward for proofreading this article!