We’ve all been there. You come to a company and face tons of bad code. Are these developers so weak to make it right and you are the only one who knows? If not, why is it there, and how to cope with it? Let’s figure it out.
What is a bad code? We may determine bad code as a code, that is not good (hello, Captain Obvious). And Martin Fowler has written the perfect book about it. But in reality, your code may have good test coverage, clean naming, patterns, but still be bad due to permanent changes and how flexible it is to these changes. On the other side, it might be so abstract and flexible, that in reality, nobody except you knows how to make changes in it. Remember these tons of inheritance, bridges, and factories? In this topic, I like the evolution of a software engineer comic.
Let’s see how these changes affect your delightful code during its lifetime and what to do with it. To see the nature of changes in a systematic way, we're going to use the Cynefin framework. Whatever problem you solve It helps you to attribute it to one of the four areas:
- Simple. Everything is clear. There are always strict rules and no fantasy is needed. The call center is a good example — each operator has rules and instructions on how to make a conversation.
- Complicated. There is more the one way to achieve the goal. You need an expert to choose from. For example, a software architect is that expert when you decide on a database solution or proper language/framework.
- Complex. You know the goal and you can move. But there is no clear way, it’s like a labyrinth. Usually, it happens when you build a new product. You calculated economics, probably made some customer development. But have no idea what is the final state. Experiments are your weapons.
- Chaotic. No patterns, just act. For example, an accident happened — everything is down, the network is busy, support chokes.
Cynefin allows you to classify every problem you face and leads us to two thoughts:
- If we know the final state of the project, there are no excuses. Probably, the previous team was frankly bad or you are the only genius. All the changes are predictable, just do it right or find where you mistaken. But make no mistake — in the 21st century all successful software gets changed.
- When building new products we are in a complex area. It means nobody knows the final state of the product, even your CEO. Hence, there is no project documentation or it might be, but not the final one. The only thing you can do is to start moving.
What to do if you don’t know the final state? Armed with your experience you project the first architecture and implement the first features — MVP is ready.
Then, comes a surprise — customers don’t buy it. The product requires changes, and, what a surprise — your sunny code too. But, wait, how about your brilliant architecture? There are several scenarios:
- You planned everything and predict a few steps ahead. You have a strong organized team and move forward. Unlikely, but if it happened — you are the treasure of the company. Just lead it to success.
- You planned everything and predict a few steps ahead. But, nobody else understands your flight of fantasies. The sign of this situation is when you code 10x faster than your teammates. Did you hire a weak team or made a wrong choice by starting to code all yours? I often see how a strong developer comes to lead the project and plants his own libraries without any reasonable advantages instead of using verified best practices from the community. Just because he made it. I hope you didn’t recognize yourself.
- Some changes don’t fit your code, because they are too radical. For sure, you have a plan for how to change it, but there is no time for it — crunches appear. And then another one. Still, you make your code clean, write tests, and generally, everything is not so bad. But if you’d have to code the product as it is again, you’d make it in a different way because you know the things you didn’t even suspect in the past.
The scenarios are clean. How to not fall into the trap? We have two goals—to build a great product and feel satisfied with the technologies. To get it closer, I made a few takeaways.
Understand the area of the problem
Don’t let yourself be fooled. If there is a best practice to solve the problem — don’t waste your time and use it. But don’t forget to know why it is the best.
Is there more than one way to solve this right? Look for an expert, probably he has invested more time on it than you will ever have.
Don’t limit yourself to coding.
The more you understand the product — the more forward-thinking you can be when planning an architecture. The better architecture you thought over— the more time in the future you have to make real features against fighting the code. Hence, the more product hypotheses you can check, which finally leads to a higher probability of success.
Have you ever thought what is the actual difference between middle and senior developers? How cool she knows Python or another language? No. How fast she can write the code? Probably, sometimes. But no. How difficult tasks can she solve? Maybe. But in reality, there are always controversial examples.
The main difference is in experience — how many cases you already have in your brain. And how many mistakes you’ve already made. This experience allows you to look beyond and predict. Armed with this knowledge you solve the problem differently. It may not appear instantly, but you’ll see the difference with time. Probably, when you’ll need to make a huge change in the code, or someday you wonder that you are not threatened with the problems your competitors met because you’ve already thought about it. So, collect as many cases as possible. Always learn, explore how others do. Organize and record it.
Hire more experienced people than you
Whatever the outcome, this strategy wins because stronger people are more likely to see what you do not see yet. It gives you a higher probability to plan your technologies for years.