Common Programming Pitfalls

or: Common errors in any language

Introduction

Programming is a process mostly done by humans. Humans make errors. We want to highlight some of the most frequent mistakes made by developers across various programming languages. By learning about these pitfalls and how to avoid them, you can produce better code with fewer errors and ensure a more efficient development process.

  • Indentation Errors
  • Name Errors
  • Index Errors
  • Key Errors
  • Type Errors
  • Attribute Errors
  • Syntax Errors
  • Logic Errors

Not following coding conventions

No matter if it is a random open source project you are working on, or if it is the code you write at work. Any decent software project should have defined coding conventions and style guides, so that all contributing developers can comply with them. In the end, this results in a well readable and comprehensible code base making it easier for anyone to maintain and understand it. To help the developer follow the set guidelines, there are tools for static code analysis such as linters. See more in the Tools section!

Using bad naming

This one is a classic. Bad names for variables, functions, classes or modules will drive anyone reading your code nuts. Even you yourself will eventually get lost between badly named variables. Especially if you come back to code you wrote a long time ago. What was that variable again? What does this function do? It looks like magic. No idea what it is doing.

Not handling exceptions

Senior developers know what can cause exceptions and they anticipate where they will be thrown. They know: If your code throws an exception and you don't handle it properly, your program will crash. So you should make sure to handle all exceptions that your code can throw.

Using too many global variables

Any software developer has heard it: Avoid global variables where possible. The reason is that too many (or using only) global variables result in code where the boundaries between different parts and modules are not clearly defined anymore. This can lead to potential bugs and makes the flow of the code harder to follow.

Instead, try to scope the variables so that they are only used inside of one module. If there are rare cases of variables that are needed by all modules, it is totally fine to have these as global variables. But usually, you can also put them in their own module and call it 'shared' or something similar.

Wrong or no logging

Often, developers tend to use print()-based logging to output something at random locations in the code where they need it. This mostly applies to junior developers that are just starting to learn how to write software. However, neglecting to implement proper logging and debugging mechanisms makes it difficult to troubleshoot and diagnose issues later on. You should follow a proper strategy on how to implement logging throughout the application and keep this consistent. A starting point could be this:
1. Decide what logging framework to use. For example in Python, there is the logging module.
2. Correctly configure the logging module once in the main configuration of your application. This means
- setting the log level
- defining the format string, such as '[datetime] [module] [level] [message]'
- configuring the output. This can usually be configured to the stdout stream or a logfile.
3. Make use of the different logging levels any logging package provides. Use debug logging where it is helpful to follow the flow of the application. Use info logging when something important happens which should be printed to the log even when running in production. Use warn logging when something unusual happens. Use error logging if a real problem occurred, such as a connection loss or invalid data as input.

Not properly formatting bash commands

Quite often, developers need to write down long bash commands with many parameters. Either for documentation purposes, or because the command is needed in a script such as a Dockerfile. You should avoid to just write the command with all configuration switches and options one after another. Instead, introduce a backslash after a unit of meaning, so that the lines don't become too long and the command is readable at first glance. This helps others and avoids headaches. No one wants to maintain 5 lines of ugly shell code.

Not doing proper input validation

Another pitfall mostly junior developers step into is improper handling of user input in critical applications. This mostly applies to web applications. As a rule of thumb: You should never trust anything in your application that is coming from the user. Do proper input validation and sanitization. This avoids security vulnerabilities such as code injection attacks.

Not writing software tests

Some developers make fun of them, some don't write them on purpose, and others love them. Software tests are hard, but useful. And they can make your life so much easier. Neglecting to write unit tests or not providing sufficient test coverage can result in too much untested or brittle code.

This is why you should learn to love unit tests. There is no reason to avoid them. The beginning is hard, but once you have learned the basics and are in the flow, tests are your partner in crime. Imagine if you can change the code anywhere you want and when you are done, you just run the tests and they tell you if the code still does at least the same thing as before. How cool is that.

Of course, this also entails certain inconveniences. When you change the core of a function that is being tested, you also have to change the unit test. But believe me, usually it is still worth writing tests.