There are "programming antipatterns" that can be intentionally used to create unmaintainable code bases... like magic numbers/ strings, obfuscated spaghetti program flows, etc.
But there are more unintentional ways of making your code base less maintable:
- Lack of consistency: Avoid using multiple different words to describe the same thing.
- Mix everything together: This happens when instead of having a dedicated piece of code for each purpose, the code contains functions that tries to do everything at the same time.
- Cyclomatic complexity: This happens when a function can have many different unique outcomes, making it hard to understand and test. Long functions usually fall into this category.
- Implicitness: Being implicit can make it very hard to figure out what is going on. Abbreviations and acronyms fall into this category as well. Bonus points if you excessively use operator overloading, reflection or anything that can be used to have a layer of magic happening.
- Messy concurrency: If you are going to be using concurrency primitives, you better have zero tolerance with messy code... otherwise, you'll be living in a multithreaded hell made out of spaghetti involving mutexes, condition variables, semaphores where things break and you have no idea why.
- Memoirs about journeys to nowhere: This happens when instead of writing a comment explaining what something does leaving out irrelevant details, you write a longer comment that reads like a monologue with many irrelevant details where the central point is you rather than the code being documented, and reads in a complicated, non-linear way... like: "I thought this did A, but then because of B, C happens this does D. Right? TODO: find out more about E". Some people think this makes them look clever.
- Interleaved levels of detail: Instead of having layered levels of detail that do not mix, write code that deals with high level things and very low level things at the same time.
But there are more unintentional ways of making your code base less maintable:
- Lack of consistency: Avoid using multiple different words to describe the same thing.
- Mix everything together: This happens when instead of having a dedicated piece of code for each purpose, the code contains functions that tries to do everything at the same time.
- Cyclomatic complexity: This happens when a function can have many different unique outcomes, making it hard to understand and test. Long functions usually fall into this category.
- Implicitness: Being implicit can make it very hard to figure out what is going on. Abbreviations and acronyms fall into this category as well. Bonus points if you excessively use operator overloading, reflection or anything that can be used to have a layer of magic happening.
- Messy concurrency: If you are going to be using concurrency primitives, you better have zero tolerance with messy code... otherwise, you'll be living in a multithreaded hell made out of spaghetti involving mutexes, condition variables, semaphores where things break and you have no idea why.
- Memoirs about journeys to nowhere: This happens when instead of writing a comment explaining what something does leaving out irrelevant details, you write a longer comment that reads like a monologue with many irrelevant details where the central point is you rather than the code being documented, and reads in a complicated, non-linear way... like: "I thought this did A, but then because of B, C happens this does D. Right? TODO: find out more about E". Some people think this makes them look clever.
- Interleaved levels of detail: Instead of having layered levels of detail that do not mix, write code that deals with high level things and very low level things at the same time.