35 habits that make you write bad code
Bad habits are hard to break. It's even harder if you don't realize that what you're doing is undermining your work. In my experience as a programmer, I've seen a lot of poor practices —not just around code, but around teamwork skills as well. I've been guilty of practicing many of these bad habits myself. Today, I'm going to share with you what I think are the top 35 bad programming habits among four categories: Code organization, teamwork, writing code, and testing & maintenance.
Code organization
1. Saying "I'll fix it later"
The habit of postponing code fixes is not merely a problem of priorities.
Organizing your issue tracker might get you somewhere, but you also need to have a way of tracking smaller issues that come up. Adding "TODO" comments is a quick way of making sure you don't miss anything.
2. Insisting on a one-liner solution
Being obsessive with coming up with short code that does a lot is a normal thing, we all go through that. It's like solving a puzzle, you find a combination of functions and regular expressions that turns 20 code lines into 2 or 3. Unfortunately, it doesn't result in readable code, and that's generally the far more important outcome. Make your code accessible first, then clever.
3. Making pointless optimizations
Another place where we often misplace our efforts is optimizations. It sounds great to reduce the size of your website a few bytes, but won't gzip make up for it anyway, and aren't requests more important? How about having less functions in your code or coming up with a faster way to calculate something? Leave all that for when you're at the end of a project, because more often than not, requirements will change and your time will have been wasted.
4. Convincing yourself that styling issues are not that important
If I've learned anything over years of looking at other people's code, it's that coding style issues are the most popular thing that developers like to postpone. Maybe it's hard for inexperienced coders to see what good will come out of them, but over time it will become evident that once code quality derails, a snowball effect will turn any project into a complete mess. Be strict about best practices even if they seem negligible. Set up code checking and linting tools to give yourself space to worry about the more important things.
5. Sweeping things under the rug
Either by catching and ignoring exceptions, or by using libraries that don't report errors (such as jQuery), there are many ways to sweep things under the rug. But once the time comes when one of those errors becomes a priority, the challenge of fixing it will be multiple times greater, considering that you won't have a clue where to begin. An easy way of averting this is by logging those ignored errors so you can study them later.
6. Using names that don't add information
Naming is hard, but there's an easy way to make sure your variable and function names are at least of decent quality. So long as they add some kind of information that the rest of the code doesn't convey, other developers will have an easier time reading your code. The reason that naming is so important is that it's easier to read the names to get a general idea of what the code does, than to go into the details and calculations being done in it, so take advantage of that and make your code deliver more value through a good naming style.
7. Ignoring proven best practices
Code reviews, test-driven development, quality assurance, deployment automation. These practices are among the ones that have been consistently shown to be extremely valuable. A great reference about what's proven to work in software development is the book Making Software: What Really Works, and Why We Believe It. Take the time to learn how to do them properly, and your development process will improve in all of your projects, in ways that will surprise you.
Teamwork
8. Abandoning plans too early
A sure way of making your system inscrutable is to not commit to a plan that you've decided on. Having half-done modules will lead to tightly coupled code as soon as you try to make those unfinished modules work with each other. This kind of complication also comes up when a project has changes in the leadership roles and the new leads decide that having it their way is more important than architectural consistency.
9. Insisting on a plan that has little chance of working
Just as abandoning your plans can cause problems, so can sticking to a plan that doesn't work. That's why you should share your ideas with your team, to get feedback and advice when the going gets rough. Sometimes a different perspective can make all the difference.
10. Working on your own all the time
You should strive towards sharing your progress and ideas with the team. It might sometimes happen that you think you're going the right way but you're not, so constant communication is very valuable. In the same way, it's valuable to others for you to discuss ideas and mentor the less experienced members of your team who are more likely to get stuck.
11. Refusing to write bad code
It comes a time when deadlines will force you to write terrible code, and that's okay. You've tried warning your client or manager about the consequences, and they insist on sticking to the deadline, so now it's time to code. Or perhaps there's an urgent bug that can't way for you to come up with a clean solution. That's why it's important to be versatile as a programmer and to be able to write poor code very quickly as well as good code.
12. Blaming others
Taking responsibility for your mistakes is a virtue that will make you shine among your peers. Don't be afraid to admit that you've made a mistake. Once you're okay with that, you will be free to focus on learning why you made that mistake, and how to avoid it. But if you don't own up to it, learning becomes impossible.
13. Not sharing with your team what you've learned
Your value as a developer is not only placed on the code you write, but also on what you learn when writing it. Share your experiences, write comments about it, let others know why things are the way they are, and help them learn new things about the project and its intricacies.
14. Being too slow on giving feedback to managers/clients
One of the most valuable character traits of any craftsman is in making sure that everyone is on the same page about the work, as much as possible. The reason for this is not so that your manager call fill spreadsheets. It's for your own gain as well: you will have less insecurities and reduce uncertainty about the lifetime and future of the project.
15. Not using Google enough
Impostor syndrome can make you fearful of opening your browser to look things up. You'll be really missing out, because the best way of solving a complex problem quickly is not having to solve it at all, when someone else already has for you. Of course, you can bother the engineer next to you as well, but rarely will they be able to give a response as detailed as Stack Overflow, not to mention that you'll be interrupting their work as well.
16. Overvaluing your personal style
Always aim to coordinate your working style and environment setup with your team. Ideally, everyone on your team should be working under similar conditions and following the same coding style. Doing things your way can be more fun, but coworkers might not be used to your way and if you write code in an unusual style, it will cause other developers to think twice when reading your code and induce on them an unnecessary cognitive load.
17. Having a personal attachment to your code
When someone comments on your code, don't take it personally. Your code should stand on solid ground, that is, you should be able to explain why you wrote it that way. If it needs improvement, that's only a reflection of the code's correctness, not of yourself.
Writing code
18. Not knowing how to optimize
A good optimization strategy takes some experience to get right. It takes exploration, analysis, and knowing every system involved in a process. Inform yourself about these things. Learn about algorithmic complexity, database query evaluation, protocols and how to measure performance in general.
19. Using the wrong tool for the job
You can only know so much, but the reason why you have to keep learning is that each new problem brings a different context, and requires a different tool, one more applicable to the task at hand. Be open to new libraries and languages, don't make decisions based strictly on what you know.
20. Not bothering with mastering your tools and IDE
Each new hotkey, shortcut or parameter you learn about the tools you use every day, will have a more positive effect on your coding speed than you realize. It's not about saving a few seconds by using a hotkey, it's about reducing the context switching. The more time you spend on each small action, the less time you'll have available to think about why you're doing it and about what comes next. Mastering shortcuts will free your mind.
21. Ignoring error messages
Don't assume that you know what's wrong with your code without even reading an error message, or that you'll figure it out quickly enough. Having more information about a problem is always better, and will save you much time.
22. Romanticizing your developer toolkit
It regularly happens that another editor o command line tool will be more useful for a particular problem than the one you're using. Visual Studio is great for writing IDEs, Sublime is great for dynamic languages, Eclipse is great for Java, and so on. You might love your editor, but that doesn't mean that it's the most fitting one for the task.
23. Hardcoding values instead of making them configurable
Always be thinking about what changes might come and how to deal with them. Technical debt will grow at a great rate if you don't separate the moving pieces from the rest of your work. Use constants and configuration files where appropriate.
24. Reinventing the wheel all the time
Don't write code you don't need to. Perhaps someone else has spent a good deal of time on your problem already, and they might have a well-tested solution that you can reuse. Save yourself some trouble.
25. Blindly copy/pasting code
Try to understand the code first, since it can happen that what the code does is not what it looks like it's doing, or there might be some small detail you're overlooking. You will also learn more about a problem this way, and about programming in general.
26. Not taking the time to learn how things really work
Expand your knowledge by thinking about how things work, and reading about the underlying issues. You might save time by not bothering right now, but what you learn on a project will be more important in the long term than actually getting it done.
27. Having excessive confidence in your own code
It's dangerous to assume that just because you wrote something, it must be great. You learn as you grow and work on new things, so take a look at your old code from time to time and reflect on how you've progressed so far.
28. Not thinking about the trade offs of each design, solution or library
Every product has its fine points that you'll only learn about by using and analyzing it. Seeing a few examples of use for a library will not make you a master of it, nor does it mean that it's the perfect fit for every situation that will come up in your project. Be continually critical of everything you use.
29. Not getting help when stuck
Keeping a short feedback loop will always be less painful for you, even if you make mistakes, than if you let a problem escalate. Asking for help doesn't mean that you're incompetent. The right people will see it as a will to learn, and that's a great virtue to have.
Testing and maintenance
30. Writing tests to pass
Writing tests that you know will pass is necessary. They will make refactoring and reorganizing a project a safe task. On the other hand, you also have to write tests that you know won't pass. They are necessary not only to move the project forward, but also for keeping track of issues.
31. Disregarding performance testing for critical cases
Have an automated performance testing setup ready by the middle point of the development process to make sure you've got that covered and don't have escalating performance problems.
32. Not checking that your build works
It's not often that a build passes but doesn't really work, but it can happen, and it might be troublesome to fix the problem the longer you wait to look into it. Quickly testing every build is an important habit to have.
33. Pushing large changes late, or leaving after making a large push
This is where overconfidence will get you, and it can take getting burned multiple times to learn to avoid this, so take the advice now and make sure you are always there when your build eventually breaks.
34. Disowning code you wrote
Be willing to support code you wrote. You are the most suitable person for dealing with it, and you should strive to make your code so good that you'll be proud of what you made.
35. Ignoring the non-functional requirements
When you're trying to deliver something, it can be easy to forget about some aspects like performance and security. Keep a checklist for those. You don't want them ruining your party by assuming that you will make your deadlines without keeping track of non-functional concerns.
What are your worst programming habits?
As it’s often said, we are creatures of habit. Improving the way you work through habits is a great way to avoid having to think too much about every single situation. Once you’ve assimilated a good way of doing something, it becomes effortless.
Note: this post was originally featured on TechBeacon.
Would you like to know more?
Don't miss my next article; get notified by email!
Great article! I love to code, and I spend a lot of time on it. I pushed my studies into the background and my grades deteriorated. I hope that the service https://www.trustmypaper.com/ helps to fix this situation.
Test Driven Development is not a best practice. It is just a practice. The best practice is to know when to practice it and when not to. Unfortunately the moment you say something like TDD is a best practice you make it mandatory for anyone with a sheep mentality. In fact I made a mistake in saying knowing when I really mean understanding. You can’t just do everything by rote.
Making your code easily testable is something you can call a best practice. It should be easy where possible at minimum to manually test your code. Certain systems will prohibit this but that is quite rare.
Making it easy to test is as much infrastructure as it is software. Your software should be sufficiently configurable for test environments but it should also have test environments, be easily deployable, build quickly, run quickly, etc. A lot of people really under appreciate the importance of optimisation for testing.
TDD can actually happen anywhere in the pipeline in a number of forms. That is if you are talking the basic concept. It might consist of writing manual test cases from requirements before issuing the work. It doesn’t have to happen in software development. It can be an aspect of project management. I think it is nice to have at least some minimal test cases with requirements but it doesn’t need to be a blocker on development.
However you do it TDD adds additional blocking steps before you can develop and deliver a product. There are other ways to achieve what TDD does. It basically an extra cost and that needs to be justified. It can’t be on the basis of simply its a best practice and these people have anecdotal subjectively positive experiences of it in this book. Nor can it be on the basis of its proponents, adoptees, author or fanbase. Additional expenses must always be scrutinised and doing more than required by default on account of mere word on the grapevine is just scamming people for billable hours.
There are interesting things that can be achieved with TDD if applied to the right scenario with the right understanding but neither of those things are commonplace.
In my experience most of the time people say they have TDD it is cargo cult. I have never seen TDD do anything but make matters worse when misapplied or when there is a more fundamental problem such as no competency.
These days TDD tends to just mean nothing goes through code review unless it has unit tests which are also the most expensive way to test software especially when implemented exhaustively rather than opportunistically.
Unit tests when done exhaustively mean you not only double or triple the work but you also end up with far more effort making your software architecture work with unit tests than what it is actually meant to be doing. On top of that it makes a codebase nearly impossible to rework (or refactor, yes you heard me right) and is very bad at detecting bugs that will appear when the system actually runs.
People get automated testing and TDD confused a lot which doesn’t help. Automated testing can achieve interesting things when applied both properly and appropriately but then again what you see out there tends to be more cargo cult of do it because it is best practice rather than founded in understanding.
I would say the one best practice people should really take stock of is that if you are doing anything that’s not strictly necessary and that you either can’t be entirely sure of a tangible benefit or lack the ability to do it properly then don’t.
right to the point! good points, keep up the good work!