You have a task assigned to you, and you donât like it. You are simply not in the mood. You donât know how to fix that damn bug. You have no idea how that bloody module was designed, and you donât know how it works. But you have to fix the issue, which was reported by someone who has no clue how this software works. You get frustrated and blame that stupid project manager and programmers who were fired two years ago. You spend hours just to find out how the code works. Then even more hours trying to fix it. In the end, you miss the deadline and everybody blames you. Been there, done that?
There is, however, an alternative approach that provides a professional exit from this situation. Here are some tips I recommend to my peers who code with me in Zerocracy projects. In a nutshell, Iâm going to explain how you can cut corners and remain professional, 1) protecting your nerves, 2) optimizing your projectâs expenses, and 3) increasing the quality of the source code.
Here is a list of options you have, in order of preference. I would recommend you start with the first one on the list and proceed down when you have to.
Create Dependencies, Blame Them, and Wait
This is the first and most preferable option. If you canât figure out how to fix an issue or how to implement a new feature, itâs a fault of the project, not you. Even if you canât figure it out because you donât know anything about Ruby and they hired you to fix bugs in a Ruby on Rails code baseâitâs their fault. Why did they hire you when you know nothing about Ruby?
So be positive; donât blame yourself. If you donât know how this damn code works, itâs a fault of the code, not you. Good code is easy to understand and maintain.
Donât try to eat spaghetti code; complain to the chef and ask him or her to cook something better (BTW, I love spaghetti).
How can you do that? Create dependenciesânew bugs complaining about unclear design, lack of unit tests, absence of necessary classes, or whatever. Be creative and offensiveâin a constructive and professional way, of course. Donât get personal. No matter who cooked that spaghetti, you have nothing against him or her personally. You just want another dish, thatâs all.
Once you have those dependencies reported, explain in the main ticket that you canât continue until all of them are resolved. You will legally stop working, and someone else will improve the code you need. Later, when all dependencies are resolved and the code looks better, try to get back to it again. If you still see issues, create new dependencies. Keep doing this until the code in front of you is clean and easy to fix.
Donât be a heroâdonât rush into fixing the bad code you inherited. Think like a developer, not a hacker. Remember that your first and most important responsibility as a disciplined engineer is to help the project reveal maintainability issues. Who will fix them and how is the responsibility of a project manager. Your job is to reveal, not to hide. By being a hero and trying to fix everything in the scope of a single task, youâre not doing the project a favorâyouâre concealing the problem(s).
Edit: Another good example of a dependency may be a question raised at, for example, Stack Overflow or a user list of a third-party library. If you canât find a solution yourself and the problem is outside of the scope of your projectâsubmit a question to SO and put its link to the source code (in JavaDoc block, for example).
Demand Better Documentation and Wait
All dependencies are resolved and the code looks clean, but you still donât understand how to fix the problem or implement a new feature. Itâs too complex. Or maybe you just donât know how this library works. Or youâve never done anything like that before. Anyhow, you canât continue because you donât understand. And in order to understand, you will need a lot of timeâmuch more than you have from your project manager or your Scrum board. What do you do?
Again, think positively and donât blame yourself. If the software is not clear enough for a total stranger, itâs âtheirâ fault, not yours. They created the software in a way thatâs difficult to digest and modify. But the code is clean; itâs not spaghetti anymore. Itâs a perfectly cooked lobster, but you donât know how to eat lobster! Youâve never ate it before.
The chef did a good job; he cooked it well, but the restaurant didnât give you any instructions on how to eat such a sophisticated dish. What do you do?
You ask for a manual. You ask for documentation. Properly designed and written source code must be properly documented. Once you see that something is not clear for you, create new dependencies that ask for better documentation of certain aspects of the code.
Again, donât be a hero and try to understand everything yourself. Of course youâre a smart guy, but the project doesnât need a single smart guy. The project needs maintainable code that is easy to modify, even by someone who is not as smart as yourself. So do your project a favor: reveal the documentation issue, and ask someone to fix it for you. Not just for you, for everybody. The entire team will benefit from such a request. Once the documentation is fixed, you will continue with your task, and everybody will get source code that is a bit better than it was before. Win-win, isnât it?
Reproduce the Bug and Call It a Day
Now the code is clean, the documentation is good enough, but youâre stuck anyway. What to do? Well, Iâm a big fan of test-driven development, so my next suggestion would be to create a test that reproduces the bug. Basically, this is what you should start every ticket with, be it a bug or a feature. Catch the bug with a unit test! Prove that the bug exists by failing the build with a new test.
This may be rather difficult to achieve, especially when the software youâre trying to fix or modify was written by idiots someone who had no idea about unit testing. There are plenty of techniques that may help you find a way to make such software more testable. I would highly recommend you read Working Effectively with Legacy Code by Michael Feathers. There are many different patterns, and most of them work.
Once you manage to reproduce the bug and the build fails, stop right there. Thatâs more than enough for a single piece of work. Skip the test (for example, using @Ignore annotation in JUnit 4) and commit your changes. Then add documentation to the unit test you just created, preferably in the form of a todo. Explain there that you managed to reproduce the problem but didnât have enough time to fix it. Or maybe you just donât know how to fix it. Be honest and give all possible details.
I believe that catching a bug with a unit test is, in most cases, more than 80% of success. The rest is way more simple: just fix the code and make the test pass. Leave this job to someone else.
Prove a Bugâs Absence
Very often you simply canât reproduce a bug. Thatâs not because the code is not testable and canât be used in a unit test but because you canât reproduce an error situation. You know that the code crashes in production, but you canât crash it in a test. The error stack trace reported by the end user or your production logging system is not reproducible. Itâs a very common situation. What do you do?
I think the best option here is to create a test that will prove that the code works as intended. The test wonât fail, and the build will remain clean. You will commit it to the repository and ⌠report that the problem is solved. You will say that the reported bug doesnât really exist in real life. You will state that there is no bugââour software works correctly; here is the proof: see my new unit test.â
Will they believe you? I donât think so, but they donât have a choice. They canât push you any further. Youâve already done somethingâcreated a new test that proves everything is fine. The ticket will be closed and the project will move on.
If, later on, the same problem occurs in production, a new bug will be reported. It will be linked to your ticket. Your experience will help someone investigate the bug further. Maybe that guy will also fail to catch the bug with a test and will also create a new, successful and âuselessâ test. And this may happen again and again. Eventually, this cumulative group experience will help the last guy catch the bug and fix it.
Thus, a new passing test is a good response to a bug that you canât catch with a unit test.
Disable the Feature
Sometimes the unit test technique wonât work, mostly because a bug will be too important to be ignored. They wonât agree with you when you show them a unit test that proves the bug doesnât exist. They will tell you that âwhen our users are trying to download a PDF, they get a blank page.â And they will also say they donât really care about your bloody unit tests. All they care about is that PDF document that should be downloadable. So the trick with a unit test wonât work. What do you do?
It depends on many factors, and most of these factors are not technical. They are political, organizational, managerial, social, you name it. However, in most cases, I would recommend you disable that toxic feature, release a new version, and close the ticket.
You will take the problem off your shoulders and everybody will be pleased. Well, except that poor end user. But this is not your problem. This is the fault of management, which didnât organize pre-production testing properly. Again, donât take this blame on yourself. Your job is to keep the code clean and finish your tickets in a reasonable amount of time. Their job is to make sure that developers, testers, DevOps, marketers, product managers, and designers work together to deliver the product with an acceptable number of errors.
Production errors are not programmersâ mistakes, though delayed tickets are. If you keep a ticket in your hands for too long, you become an unmanageable unit of work. They simply canât manage you anymore. Youâre doing something, trying to fix the bug, saying âIâm trying, Iâm trying âŚâ How can they manage such a guy? Instead, you should deliver quickly, even if it comes at the cost of a temporarily disabled feature.
Say No
OK, letâs say none of the above works. The code is clean, the documentation is acceptable, but you canât catch the bug, and they donât accept a unit test from you as proof of the bugâs absence. They also donât allow you to disable a feature, because it is critical to the user experience. What choices do you have? Just one.
Be professional and say âNo, I canât do this; find someone else.â Being a professional developer doesnât mean being able to fix any problem. Instead, it means honesty. If you see that you canât fix the problem, say so as soon as possible. Let them decide what to do. If they eventually decide to fire you because of that, you will remain a professional. They will remember you as a guy who was honest and took his reputation seriously. In the end, you will win.
Donât hold the task in your hands. The minute you realize youâre not the best guy for it or you simply canât fix itânotify your manager. Make it his problem. Actually, it is his problem in the first place. He hired you. He interviewed you. He decided to give you this task. He estimated your abilities and your skills. So itâs payback time.
Your âNo!â will be very valuable feedback for him. It will help him make his next important management decisions.
On the other hand, if you lie just to give the impression youâre a guy who can fix anything and yet fail in the end, you will damage not only your reputation but also the projectâs performance and objectives.
