The common thesis is the easier product to use – the better it is for the customer. Easy-to-use products get higher adoption. They grow faster. Everyone can understand them. It gets to the point when companies use this to differentiate from competitors. “Easier-to-use” became equal to “better” in some ways.
As with any other bold statements, the reality seems to be more subtle. There is always a lot of “depends” when you try to reduce complexity for the product. And making it simply “easier to use” might not always be the best direction for the team.
Back in the 1980s, Larry Tesler has formulated the Law of Conservation of Complexity. He said that each application, no matter how simple, should have a certain level of inherent complexity. The real question is who will be dealing with it, users or engineers.
Every application must have an inherent amount of irreducible complexity. The only question is who will have to deal with it.
– Larry Tesler
Let’s say you’re building a task manager application for macOS. As soon as you create a project, you immediately inherit a whole stack of complexities. Your code should be compiled, packaged, signed, while the system should allocate and manage the process memory. User input has to be captured and processed. All of that is complexity.
Sure enough, we don’t have to deal with it. Most of the time, we don’t even have to know about that complexity. But this doesn’t change the fact that complexity is there. It’s only handled by other people.
Dealing with complexity takes resources. It’s in no way for free. Companies like Apple can easily afford to handle that much complexity. The problems creep out when smaller teams take more than they can manage.
What better example of complexity management can you find if not the product you developed. Flawless App1 is a tool to compare design & implementation and search for visual bugs. Building a tool for engineers is hard by itself. Additionally, we set ourselves a goal to make it “easy to use”. The key lesson here is that we didn’t specify what exactly should be “easy to use”, the whole system or a core part of it.
In retrospect, a lot of internal product problems could have been avoided if not for this goal. Additionally, Flawless App had to deeply integrate with iOS Simulator. So we could show the design and iOS app in real-time during the development process. This by itself brought a considerable complexity. iOS Simulator is not an open-platform. There is no documentation of how to build Simulator plugins2. But even without the integration complexity, lots of other product decisions were made along the way. And each product decision is, in a way, a complexity management decision as well.
On the surface, using the Flawless App is indeed simple: Open the application. Launch iOS Simulator right from the app if it’s not running. Drag & drop image or a Sketch file. That’s it. You can see design overlayed on top of the iOS app inside Simulator.
This seemingly simple process involved the following:
The list can go on and on. The complexity here is enormous because our goal was to make the product “easier to use”. We took all the complexity on our shoulders.
Now imagine that we had fewer conditions to take care of. Imagine the user would check iOS Simulator availability, not the Flawless App. So if the Simulator window is hidden, we’d simply return the appropriate error message, instead of trying to fix the problem for the user.
This way, Flawless App would have been slightly less intuitive to use. But we would have had less complexity to deal with as engineers. And this could have allowed us to focus on improving core comparison experience. In other words, take only the relevant complexity, not all of it.
Dealing with the complexity that doesn’t matter simply dilutes the product focus. When you’re a small team, the focus is invaluable.
There is no way to avoid complexity in software products. The only thing we can do is simply be mindful of the complexity we take on. This mindfulness partially comes from data analysis. Having a strong jobs-to-be-done basis, and usage statistics, come handy when dealing with internal complexity.
We can’t predict how every product decision turns out in the long run. But we can at least anticipate the future impact by asking the right questions. Let’s imagine you want to simplify a flow/feature in the product. Here are some themes that might be helpful to think about before doing so.
Starting with initial conditions makes it easier to evaluate the complexity in question. Optimizing a flow used by a few simply doesn’t bring enough value. This is especially important if you have a small team.
A similar question is: “How big of gain users can get from simplified flow?”. If the impact is small, it might be better to focus on other parts of the system.
For example, in Flawless App, we had a sub-system to track the iOS Simulator availability. As soon as you close Simulator, the application would suggest to open it. Building this sub-system wasn’t free. We could have spent this time on other parts of the system that are more impactful to the core experience.
Each flow optimization is highly dependent on an actual use-case. How exactly the complexity is being taken from the user. To reason about maintenance in a vacuum is unproductive most of the time. So I can’t say anything specific here. But raising this question alone can be a reminder of future maintenance expenses for each complexity you’re taking.
Another problem is that cost of moving complexity from users to the team might not be visible right away. Only when a certain scale reached, the cost might come up. So it’s useful to consider product growth projection as well.
Scenario modeling has been a common approach3 for improving predictions and reasoning about the future. Mainly it’s used to anticipate future outcomes when certain parameters are true. In our case, we’re trying to understand if this particular flow that critical. What will happen to the product if the complexity stays at the user’s side? Would you experience any reduction in usage?
There is a difference between removing functionality and changing it. Removing functionality takes it out for the users and engineers. No one has to deal with it. No one has to maintain it. And no one gets to use it.
For example, removing the Sketch files support in Flawless App would have significantly reduced the complexity. But it would have also reduced the value of the product. When it comes to removing parts of the product, trade-offs must be made.
Ironically, the more we try to simplify the product, the more complexity we take.
Sometimes one of the main product’s value is, in fact, taking the complexity from the user. But the product is a combination of things. You can’t take all of it and still have a quality product. Also, this could paralyze the team’s ability to deliver over time.
And that’s the key point I wanted to make. Take only the complexity that matters. The complexity that impacts the core experience. And of course, the complexity that you can afford.4
Easy-to-use products are expensive to build. Being aware of it goes a long way.
At the moment, Flawless App is not available for download or purchase. If you’re curious, feel free to read those articles: Review: Flawless App by Hacking with Swift, Flawless App Tutorial and Review by Peter Witham or How Flawless App Helps You Become a Better Designer and Developer on AppCoda. ↩
If you’re curious, here is an article I wrote on Hacking iOS Simulator with simctl and dynamic libraries. It explains how to inject custom code into Simulator. Modify its behavior and potentially make the iOS Simulator more useful. ↩
As far as I know, it’s been a common approach at least in the financial sector. Since the housing market crash in 2008, there was a policy, obligating banks to regularly practice crisis scenario modeling. This approach surely has a lot of downsides but that’s probably a topic for another article. ↩
The word “complexity” is mentioned 36 times in this article and I’m not sure how I feel about it. ↩