Let me start off with the fact that I've been interested in the clean code principles for quite some time, I think it's very important to keep these principles in mind while developing software. Other people should be able to read and understand your code without a decipher ring and you should not have to move mountains to add a simple feature. With this I've embraced the words from our Uncle Bob and tried to bring his words into practice. Until my last personal project where I found myself wondering, what can I do to clean this code even more, it felt like cleanliness itself had become somewhat of a burden, taking the enjoyment out of just writing the code, I felt it had to be as clean as possible. Was I taking it too far?
The first extreme, the hoarder
In our career we will all come across the two extremes of cleanliness in the code bases we will work with. Let's start of with the most common of all, the hoarder code base. You know what I mean, that one project, where even by speaking it's name you'll see a tear running across the cheek of your fellow developers. Where you open a file, just to add a simple input field to a page and three hours later it feels like the code is swallowing you whole. It's a mess, there are classes of more then a thousand lines, changing one property in page one breaks pages five, six and eight and you have no idea why. Your feature or fix will be slapped in the code, maybe some duct tape is placed over it, just to keep it in place and even though you know you've probably made the code even worse, you close the file as fast as you can and deploy it. Hoping to never have to touch it again. How do you think this happens? Most people will probably say laziness. But it's not, at least in most cases. This cluttering happens one small decision at a time. You start of with a nice clean class, and just add a small thing here. It doesn't really belong here, but it's easy this way. The next person sees this and changes another small thing, there already was something in the class that didn't really belong there, and now there are several things in there. You see where this is going?
The second extreme, the showroom
This is the other extreme, not everybody will recognize this extreme as fast as they will the other one, but it is there. I like to call this code, the showroom code base. If you dig into your memory you'll find them, those projects where you kept cleaning and cleaning, making the code better. Adding some abstractions, a pattern here, another there, some more layers. Do I see a duplicate line there? Let's create a base class. More then 20 lines in the class? That has to be split up! This feels great when you are starting out, and you'll be able to keep this up for quite a while but then a new guy has to work on the project, or you have to switch to another project for a while. You come back and want to add that same simple input field. Knowing that the code is cleanliness itself you open the class, to find that you should go a layer deeper since it's not really the responsibility of that class. In the next one you go deeper as well, and deeper, and deeper, oh a factory. You just have to figure out which direction you should go and two hours later you think you have found it. But you can't just add this here, because it will appear in several places, you need to abstract it further only to find when creating the abstraction, other implementations need even more abstraction. What has happened here? The code got too clean, it's just like a showroom home, like in one of those catalogs ready to sell. It looks great, but if you look closely, it's not practical to use. There is no place to put your coat, not place to put your drink, no place to put the TV and is that even a full-size couch? But it does look great. This is mainly caused by software design books, articles and blogs that show us unrealistically clean code and give us the wrong goal. Code that follows all the rules and is perfectly consistent and abstracted is unattainable unless there is nobody living there.
Whats in between? Livable code
When you take the analogies I used, between a hoarded living space and a showroom living space, there is the living space that's actually being lived in, the livable space. The beautiful decorated room, with some mess. It's might not be as pretty as the showroom, but at least there is room for your TV with a console, and a couch that sits great. The same thing goes for code, in between these two extremes is the livable code. There is some duplicate code in there, some classes are a little big, but their names tell you just what they do and it's pretty easy to find your way in the code. There may be some places where it's still a mess, but slowly but surely we are changing that mess to make it better. This is the code base we should embrace. This is the code base that feels like home. This is the code base we love to work in!
How to get there
Although most project tend to go more to the hoarder extreme then the showroom extreme, the steps to get the code base to the place you want for them is the same. Follow the following steps to slowly but surely move your code base to a healthy livable place.
1. Don't make it worse!
When you are touching bad code, don't take the easy way out and make it even worse. Don't fix the whole file, but at least make sure it doesn't get worse. This can go both ways, to make the clutter worse, but of you are leaning more against a code base that is too clean, don't just add another layer to it.
2. Improvement over consistency
Five books on a pile and one on the shelf is better then all six in a pile. Every time the code is touched someone can move one of the books to the shelf. If you wait to move all at once, it's not going to happen. This seems hard for a lot of people because a lot of clean coding articles value consistency very much. But remember, the picture that these articles give you, is that of showroom code. While that beautiful code looks like a picture, we need some clutter to feel comfortable. If you look at it practically, having five classes that are a mess and one is like it should be, is better than having six classes that are a mess.
3. Inline everything
Stop putting on stories for refactoring, or taking a week of to fix that one file. It's great that you do this, but it creates other big bangs. You should incorporate this in the way you work every day. Follow the scout rule; Leave the code cleaner then you found it.
4. Be transparent
You need to be able to communicate with everybody what you are doing all the time. So don't hide the stuff that you are doing, like making a file a little better while touching it. Refactoring and cleaning up should be part of everything you do and be open about it. However keep in mind that you should not ask permission to do this! It's part of your job, just but be upfront about what you are doing. And also, don't ask for forgiveness. Again, it's not something you need permission for. You will make mistakes, you will clutter, you will overdo your refactors a lot of the times. It's actually important that you make these mistakes, so you know what to watch out for, you'll learn a lot from them.
Is it all in the code base?
You can probably guess the answer, no it's not. The most important part about software is not the people, it's not the code, it's the system. What I mean with this is that the code base and the team go hand in hand. If the code base is a mess, the team is a mess as well. This would mean that for any problem you have writing software you have two directions you can approach it. You can make changes in your team which will drive changes in your code base, or you can make changes in your code base which will drive changes in your team. For example if your code contains three implementations of "User login", you could consider this just tech debt, but it also represents an issue in communication within your team. Those different implementations should not have been there. So everything you read until now can also be changed by changing the team? Yes it can! Just start by making everybody in the team aware about this principle and start communicating about this topic in reflection to your code base on a regular base and see what happens.
Another important aspect to look at is what software actually is. It moved on from actually building a product and being done a long time ago. Applications keep evolving, we use continuous deployment, the products are never done. Software development should be seen as an experience, involving developers, managers, product owners and the clients, a group creative effort. More like a group of theater people putting together a play, then a group of workers fabricating something physical. While a lot of developers don't think of what they do as creative, the way we work in software nowadays actually makes a lot more sense in a model of creative people collaborating then it does for a manufacturing model. The more we can think about software as an interconnected part of code and people the closer we will get to a code base we're excited to work in. And you can do this, if you build trust with your team members, if you strengthen your connection, the code base will follow.
Architecture and big refactors
So now we know where we want our code to be, what the relation between our code base and the team is and how to get to the code base that we want. One thing I haven't mentioned until now is are solutions a lot of developers yearn for, this big refactors. You see yourself struggling with the awful code day in and day out dreaming of a rewrite. If we could only build it again, we would build it a lot better. Write that jQuery project in Ember, rewrite that Monolith into micro-services. And sometimes it works for a little while, but if you don't change the habits within the team, the clutter will sneak in again. You'll just end up with a tangled network of micro-services just like you had a tangled network of class definitions in your monolith. Or you'll go into the other extreme and over-engineer the whole project and create such a big mess of layers that nobody can't find anything without a full search and rescue crew with them. What is actually more effective is, changing it little by little. And let the people that live there do it. Teams should reach these insights for themselves, there should not be an outside architect role that tells them how to build things. Architects always seemed a great way to keep structure clean, but like I said before, the team that lives in the code base is connected to it, the architect is not. That is like a stylist coming to your house and telling you everything should look. Don't get me wrong, you should really ask help from someone that knows a lot about architecture should you need it, but it should never be the other way around.
Where did this all come from
I didn't think of the principle of livable code myself and don't want to take credit for it. It just made a lot of things fall into place for me and I really wanted to share it with the world, make people think about this. The first place I came in contact with it was on a blog post from Uncle Bob, called Too Clean? I found it a really interesting read and love his conclusion;
We should not be ashamed if our code looks a little bit lived in. On the other hand, we need to be diligent about cleaning up after ourselves; and not let the mess spin out of control.
The article from uncle Bob starts off with the mention of a talk by Sarah Mei, called Livable code, which was my real inspiration. A lot of the things you read above is my vision for software development after hearing her keynote. Should you have 45 minutes to spare, you should really watch it and hopefully, it will inspire you as much as it did me!
Top comments (22)
I think that
too clean
would be better expressed asoverengineered
.On the other hand, I just wanted to point that, while your living-room is something static and you know that you can tiddy it up in a Saturday morning because you did it in the past, a source code is always expanding and new features are built on top of the old ones.
Each little act of complacency, each "I will fix this later", can be amplified 100 times when a new developer takes over your code to add a new feature and, instead of spending the time to understand and fix it, just hacks his implementation to go around your bad abstraction.
Tecnical debt is a reality in every single source code, but interests can be high, and technical bankrupcy is something as real as financial bankrupcy.
Just be careful.
I agree, I think that building too clean is a big part part of over-engineering. While I don't think they are exactly the same, they are for a big part, but there are levels that clean code does not influence. Think of infrastructure and architecture level. Which are things that are quite easy to over-engineer. Nevertheless I completely agree with your vision and call for carefulness.
This is an absolutely brilliant metaphor and wonderfully written article. Well done!
Thanks, it took me a while to get myself to the point to actually start writing a blog post, but I'm glad I did, and glad that you like it :)
Really well written article with interesting points of view.
Agree. Fixin everything can be impossible, but correcting something step by step, and not just putting quickfix even with my favorite TODO comment (which will never get to state DONE) will gradually make the code better.
Unfortunatelly I noticed that developers sometimes confuse improvement with "doing it my way"
So I would suggest, if something can be done better - it's good to correct it BUT first it would be good to discuss this at least with other team member.
If the improvement is based on your knowledge it's good to share this knowledge with your team members. Sometimes it's just developer is not aware of other possible solution :)
One of my favorite rules :D
And I think the most important thing here in article is:
I agree that it's very common for developers to focus too much on how to correct the code - not how to teach other writing it correclty :)
Thanks for this article :) It was really great to read it :)
Thanks for the response. I really like your point of confusing improvement with doing it their own way. This happens quite a lot. And as you can see with all of these things, communication is key, work together as a team. Sarah mentions that instead of focusing on the individual professional, we should focus more on the team. Although I don't agree with her vision on that, since I think part of being professional is looking at the team you are working in, I think we can all agree that how you work as a team is of great influence on your code base.
Interesting subject, I don't think I agree but it's difficult to give a one-rule-fits-all in this scenario.
My initial thought is that your analogy for
too clean
is actually a fault in the design and perhaps a misuse of design patterns. As soon as code gets too complicated to understand it's an indication that you're not taking the correct approach.Logically, if we're not designing code for readability and maintainability, what are we designing for?
I think we should first of all design for functionality, and to be able to deliver this functionality on a regular base, we should also focus on readability and maintainability. Code that is too clean can be a fault in design, it can also be the misuse of a design pattern, or a lot of things for that matter. And a lot depends on interpretation. If you'd ask me a while ago to define you what I think design patterns are, I would have said something like; Their proven solutions for reoccurring problems. This is translatable to, if you face this problem, use this pattern because it is the best way to solve it. If you'd ask me the same question now I'd say; Their proven solutions that could help you solve reoccurring problems. Do you see the subtle difference? What I want to say with this, and all the things we use as guidelines, best practices, how to's and what not, these should trigger your own thought process, not just tell you how to do it. Coming back to the rooms, you are living in the code base with several people, and you have to figure out what works best for all those people, not just implement what outsiders say, because they don't have to live there.
Well, I hate to rain on your parade... but I don't see the point of writing this article.
Don't get me wrong: the topic is important, and you make some very good remarks, but...
Thanks for your reply. I never expected everybody to agree with my vision, that would totally miss one of my biggest points. There are a lot of guides, articles and what not out there, mine is one of them, as is your reply. I hope people read them, and start thinking for themselves. I do agree with you that lack of professionalism is certainly and issue, although it feels a little like saying everybody should be professional, so everybody should know what to do, how to act, have figured out how to find a solution to any problem. I use the term professional quite often, but I realize that I'm having a hard time actually defining what actually realistic professionalism is in our industry. What's you opinion on this?
Actually, I now take back the first statement in my previous reply because I guess that fostering this kind of discussion was the point of your article.
Regarding professionalism, for starters it should be noted that there are levels. So, one is never required to be perfect at everything at all times. But there are basic levels of professionalism. Though these levels are a bit fuzzy, in every industry there is a somewhat clear set of best practices and basic knowledge required for the professions in that industry. Basic knowledge is usually consolidated by academia and professional institutions (e.g., IEEE, ECMA, W3C, etc.). Best practices come from individual or collective professionals in the field, like Bob Martin, Martin Fowler, Mozilla, Apache, etc. There are also standards bodies and compilations of knowledge (see for instance computer.org/web/swebok/v3 ).
If a person doesn't know the best practices and/or basic knowledge in a particular field, I would venture to say that that person, at that time, is not a professional in that particular field. In a professional setting, that person can, at best, be a junior/intern/apprentice, and their work always has to be supervised.
Of course, best practices are always shifting and evolving. So, I would add a couple other requirements:
1) the ability to keep up with best practices;
2) the ability to contribute to the revision of best practices.
Great analogy!
If code is too clean it's really hard to keep it clean. To not get into that extreme I think you should take into consideration the amount of lines of code. A good refactor is one that makes the code readable and halves the original number of lines of code. (or whatever percentage works for your project, we just have a lot of duplicate code :P )
While a lot of guides give you these guidelines, like the number of lines per code for a class, they should remain guidelines. Don't treat these guidelines as facts and treat each file in it's own way to maximize it's readability, not it's compatibility with clean code guidelines. So don't make splitting halve of the lines in you class a goal, make the goal to make it easier to read, maintain and extend. If that leads to moving more than halve the lines to a different class, great, if it doesn't, don't try to enforce it.
Excellent article. I'm working on one right now and the question arose for me about too much cleanliness. It's an interesting balance, to share a technique about keeping code clean, but factoring in how that will actually play out in a mature code base or on a diverse team.
Thanks! I found more and more that when looking at code all I was thinking how it could be improved, cleaned and refactored. While it's great to have this awareness I think a key point in that balance is accepting the code base and not being ashamed of it.
Well done. What a dope read.
I'm in the process of updating some of our libraries, and I soon also realized the "too clean" pitfall one can fall into without even realizing.
It comes at you fast
A great piece.
Let me disagree with one statement:
A good architect lives in the code as any other engineer, but has more time to dedicate on observing and noticing emerging patterns and reshaping the code so that it's more optimal from the perspective of maintainability. A mediocre one will just walk around and infinitely talk about abstract models and patterns in vacuum without actually making decisions and applying them to the code.
Even if you don't have an "architect" role, every software engineer makes architectural decisions daily: how to name things and structure APIs (functions, components, modules, data fields), where to put code, how to organize data flows between components, etc.
I think this post speaks about a real-world example of a 'showroom codebase'.
Thanks for sharing that article, I think it's a great deep dive of a lot of things that can go wrong in a showroom code base.