The natural corollary to trying to manage complexity is a desire to keep things simple. Which is, in general, a good thing to do. Simpler code is easier to maintain, easier to debug, easier to test, and just plain easier. But even though we’re on a never-ending quest to make things “simple,” it’s easy to get distracted by heuristics that aren’t really good proxies for simplicity, and as a result make things more complicated than they need to be.
Read more: Keep it simple, stupidWhen talking about simplicity, we need to start with something simplicity is not, and that’s lines of code (more or fewer). To start, let’s look at the case of being overly clever, and using some obtuse 1 or 2 line bit of abstract trickery to do something that can be done explicitly over 5-10 lines of code. Yes, in that instance more lines of code are certainly simpler to understand. But there’s also times where you have dozens of lines of convoluted logic, tons of branching paths that, after some time and thought, can be condensed into a more straightforward flow can reduce the number of lines of code and be simpler. So are 1 of these instances some sort of simplicity paradox? No, but like “best practices,” it’s easy to see these examples to focus on the characteristics of a situation, rather than the principles behind the decisions.
Code simplicity isn’t about the code at all (as counter-intuitive as that may seem) – it’s about the developer having to read, understand, and work with the code. In other words, simplicity is another way of discussing code’s readability – which means emphasizing clarity and focus in the code. By the way, “code” here refers to more than just lines in {insert your favorite programming language here}. It also organization, variable and method names, and meaningful comments (the kind that discuss data state and the applicable business rules).
It’s also worth mentioning that just because something is simple doesn’t mean it isn’t powerful – the 2 terms aren’t mutually exclusive. In fact, you can very often get something that seems like it can do a lot, written by developers who seem to be able to put out new updates with ease, precisely because people put a lot of work in up-front keeping the code as simple as possible. As a result, the codebase is easier to understand (which makes onboarding new developers and reviewing new code easier), and easier to test (so you can develop faster without fear of regressions), letting developers focus their time, energy, and complexity budget on the parts of their problem domain that are actually complicated. And, spoiler alert, the most successful companies are generally the ones that manage to find ways to simplify those complicated parts too.
It’s the “saying ‘no’ a thousand times for every ‘yes'” philosophy Apple used to swear by. More “stuff” adds more complexity, and more complexity is more friction in using your product. That makes your users think more about how to use your application when they should be thinking about the thing they’re accomplishing because they used your application. Now, some products try to solve this problem by doing the thinking for you, and just making something happen automatically. It’s important to understand something – this doesn’t actually make things simpler. If you’re making an honest effort at this then you likely have a bunch of code to collect user behavior, and then use that to try to “predict” what they want to do given any context. And here’s the thing – if you’re right, it’s a slight convenience, but if you’re wrong then your software is actively angering them by doing what they don’t want. How often are you right by the way? Do you have any way of measuring that?
On the other hand, you can offer a simpler experience by letting the user easily tell you what they want, and then doing that. No need to track and capture a bunch of behavior, no need to run machine learning or intuit preferences, just simply following simple instructions. It’s the exact same output, but with a high satisfaction rate because you didn’t over-complicate things trying to think for your users.
There’s a lot of complexity involved in software, but it’s our job to reduce it as much as possible. That includes breaking the problem down into simpler chunks, keeping the logic as simple as possible, making the code as simple to comprehend as possible, making interacting with the software as simple to do as possible, and making it as simple as possible for users to end up in the state they actually wanted (as opposed to the state you assumed they wanted). If we succeed in doing that, our software is just plain better.