Clean Architecture : Complexity over Simplicity ?
Why are developers obsessed with Clean Architecture? Does it make our app simpler or more complex? What do we misunderstand about Clean Architecture, and what should we rather focus more on?
A few weeks ago, I posted a reply on Twitter about why developers are obsessed with Clean Architecture. Since it received good attention, I thought of expanding that tweet into a blog post.
TL; DR
Since we are going to talk about complexity over simplicity, the first question that comes to our mind is…
1. Why is writing software complex?
Writing software would have been easy if it were only written by machines, since machines run on logic, it is easy for us to understand and predict. But as we know, software is written by humans, and humans run on feelings. And, human feelings are one of the most complex things to understand. Even humans themselves don't know where they come from.
We are so attached to our feelings that when our code does not work as expected, we first blame the machine, not ourselves. We either say “There is a bug in the language” or “It works on my machine” or “Select is broken.” 1
Still, software is much easier to understand if it's written and maintained by a solo developer, a.k.a. Indie Hackers. However, those software are exceptions rather than the norm. Broadly speaking, software is not built by just one person. It's a group of people who build it. It's a collaboration.
Software is more sociological in nature than technological. 2
Even if you are the only developer on the team, you still need to collaborate with the CEO, designer, and QA, who do not write code but still have an impact on how you write the code.
This is similar to how a chess player and a football player approach the game. A football player needs a lot of collaboration skills with other players compared to a chess player. Also, a football player's relationship with their team players plays an important role in how well they perform on the field.
So, writing software is complex NOT because of the tech stack or programming languages3; it's complex because of us. We, as humans and as developers, make things complex.
More People == More Complexity
Now, if we know the problem, why do we still make things complex?
2. Why do developers love complexity?
Humans run on feelings, and one of the most significant feelings that all humans seek is The Feeling of Importance.4
We seek this feeling in various forms by expecting praise from people, buying things, getting likes on social media, and creating beautiful Instagram Reels. Ironically, I am also expecting some praise for this small essay. Now, what does this have to do with complexity in programming?
Because of this feeling, most developers want to associate themselves with something bigger, something that makes a big impact on the world. FAANG companies are representative 5 of those impacts.
Saying "I work for one of FAANG companies" in your friend circle and peer group gives you a very high level of importance. No wonder Getting into FAANG courses sells out fast.
However, most developers work in either small startups or service-based companies. Hence, we try to emulate that feeling by building applications similar to FAANG companies in our apps, influenced by their talks and blog posts. And, one of them is Clean Architecture.
By building applications with Clean Architecture, it gives us a feeling that we are building applications at a level similar to FAANG, which, in reality, we are not.
Let’s compare two examples. 6
The left one uses all the latest shiny features from Dart 3.0, while the right one uses a simple for-loop. Which one do you think is easier to read and maintain?
The problem is that while implementing any solution, we miss the Context.
Dairy products are good for health in general, but it's not good if you're lactose intolerant.
Those companies are giants with thousands of employees, and as mentioned earlier, the more people you have, the more complexity it adds. This complexity justifies it for them.
Most of the complexities we introduce in our codebase are not required. Instead, we should focus on simpler approaches.
3. Why doing simple things is not simple?
Let me try to keep it simple 😁. In my opinion, there might be two reasons. First, we misunderstand easy with simple, and second, the most important one is that Simple things don't get much attention.
The beauty of simplicity is that no one notices it. Great UX is when users don't notice the UX. A great manager is the one where you feel you don't need one. 7
Let me illustrate with a code example. Let's say we want to show a message to the user about how many items have been added to the cart.
To make the message user-friendly, we should follow proper English grammar. For zero items, we should say "No items found," and for any other number, we intend to show the number while maintaining the pluralization of the word "item/items."
The above example shows the message properly. The function concatenates the string message with some conditions. Now, below is another version of the solution.
This function simply returns the full string based on a number using a switch case. Now, which example do you feel is simpler and easier to read?
It's the second one because the first is difficult to read and extend, while the second is much simpler to read and easy to extend.
I know this example is very trivial, but the point I am trying to make is the simplicity of the solution. The first solution seems clever but complex, and the second is simpler but does not look clever. That’s why developers prefer the first one because it looks clever, which creates unnecessary complexities.
And, the hard part about writing simple code is that you need to first understand what complex code looks like. Basically, it's a cycle you have to go through.
Simple → Complex → Simple
I really like the quote from Sandy Metz on this:8
You should not reach for abstractions, but instead, you should resist them until they absolutely insist upon being created
4. What do developers misunderstand about Clean Architecture?
You might think I am against using Clean Architecture, but I am not.
Most developers who talk about Clean Architecture actually have never read the book. If you read the book, then you will find that in that 500-page-long book, only 2–3 chapters are dedicated to the famous Clean Architecture onion diagram.
What most developers do is that they acquire surface knowledge about Clean Architecture from a blog, video, or course (nothing against those mediums). They take the onion diagram as a blueprint and blindly start creating entities, repositories, DTOs, and so on in their project without understanding the in-depth knowledge behind Clean Architecture.
The Clean Architecture is NOT about creating entities, use cases, and DTOs; rather, it is more about the separation of concerns, creating boundaries, managing dependencies, SOLID principles, coupling, and cohesion. That’s what 80% of the book talks about.
In this information era, we have a lot of information but less WISDOM. It's good to know that a tomato is a fruit, but it's wisdom not to put it in a fruit salad. 9
Because of this, we build a lot of shallow knowledge, memorizing things and implementing them as they are, missing the abstract idea, the deep knowledge. That's why, Clean Architecture has become an Escape hatch for developers.
It is similar to how we think that traveling the world will solve our problems. Similarly, we think that using Clean Architecture, MVVM, MVI or any new famous state management library will solve all our codebase issues.
Okay, if clean architecture is not the solution, then what should we do?
5. What are the things developers should focus on?
1. Practice, Practice, and Practice
There is a 10K-hour rule that suggests that mastering a skill requires investing 10,000 hours in focused deliberate practice. There is no scientific evidence to support that you can master a skill without much practice. 10
You cannot get six-pack abs by just reading a fitness book.
2. Focus on Abstract Ideas/Deep Knowledge
Rather than fixating on specific frameworks, such as Clean Architecture, or the best state management solution, or debating which programming language is superior, focus on abstract ideas or in-depth knowledge.
Understand principles like SOLID, cohesion, coupling, dependency management, and separation of concerns. Abstract thinking helps identify similarities or patterns in any codebase.
3. Choose Your Learning Sources
Don't limit your learning to only sources like YouTube, blogs, or courses. Read books for more in-depth knowledge, get a mentor, or the best approach is to build things yourself.
Iterative learning with failure will give you a lot of deep knowledge compared to step-by-step learning without any failure.
4. Learn Techniques to Transform Code into Any Structure
Learn timeless techniques like testing and safe refactoring.
If you master these two, then you can transform any ugly codebase into a better structure or into any architecture pattern you like confidently.
This skill allows you to make changes without fear of breaking things. By learning safe refactoring with safety nets like tests, you can navigate through any old legacy codebases.
5. Start Small
Start by applying abstract ideas from small places.
Begin by doing it at the function level, then move to the class level, and then to the directory level. After that, move to the feature level, and finally, consider the entire app level. Starting small and incrementally leveling up will help you grasp and implement abstract principles effectively.
Also, if you make a mistake, small changes are easy to revert.
Also, all of the above points are my main focus while teaching Flutter in my online classes. Flutter or any other framework is a tool to build something, but the real focus should be on fundamental and abstract ideas.
6. But what if my app needs to scale? Can I avoid complexity forever?
Honestly, I haven't worked on a FAANG-scale project, but I have worked on a few where we had scaling issues. Most apps don't need as much scale as we expect them to. When we talk about scale, we often think about FAANG, but those companies are fewer in number. Most of them are startups or service-based companies.
I mostly worked on Frontend technologies. In my opinion, most scaling issues are a backend challenge compared to the Frontend because the Frontend runs independently on a device, whereas the Backend needs to handle multiple requests at once.
However, there are cases when you need to scale on both sides. In that case, if you know the techniques I described above, then you can easily migrate your app to a more scalable architecture.
If you focus on the right set of skills and concentrate on the right things, you can essentially convert any app to be scalable. However, in my experience, we usually get it wrong when it comes to what to scale. So before you go down that route, make sure to measure and compare your solution before going live.
Does that mean we won’t have any complexity forever?
That’s not true. Some apps are complex to build and maintain, such as banking, finance, healthcare, flight aviation, and so on. The point is not to avoid complexity altogether. It's to recognize the fact that most of the time, we, as humans, introduce unnecessary complexity. Recognizing when complexity is essential and when it's self-imposed through our feelings is crucial.
7. Conclusion
Writing software is complex because it involves humans who run on feelings. Hence, we should recognize this fact and not attach our emotions to the code we write.
Rather, we should look for simpler solutions by focusing on fundamental and abstract ideas and learning techniques that help us transform any codebase safely in small steps.
That’s It, Folks
If you are interested in Flutter coding challenges, then you can subscribe to the new Substack below. Checkout details below.
Also, If you enjoyed this blog, then would you be able to do me a quick favor and share this with your friends and colleagues? I'd really appreciate it and I think it could be valuable to them.
Tip #33, pg. 95: https://pragprog.com/tips/
Chapter 1 - Somewhere Today, A Project is Failing: Peopleware - Productive Projects and Teams
Of course, JavaScript is the exception here 😂
Chapter 2 - The Big Secret of Dealing with People: How to win friends and influence people
There are companies that make big impacts but are not on the FAANG list. Like Stripe, OpenAI, etc.
Although there are expectations, when you have a terrible manager who blocks work instead of making progress. In that case, you definitely don’t need them.
Trying Too Hard: Same As Ever
Is Drilling Worth it? : Why don’t students like school?
I really enjoyed reading this one. Thank you. Recently I am building a project with Next.js and I realized that I made the project really complex myself 😂.
Thank you for reminding!
Good read!