Nothing prevents a programmer from implementing a coupled and ineffective solution, maybe without even knowing it, and just like with the more famous design patterns recognizing what he has built only at completion. These counterproductive solutions can be identified as standard bad practices: they are called anti-patterns. Moreover, while design patterns usually are focused on design and coding, anti-patterns can be observed in many different fields of software engineering such as the organization and management levels.
Let's see an example focused on software design. Suppose you have a small application which a narrow set of features and you are in a rush to implement new ones. In the worst case, these features will be hacked in without respect for the design of the application, whose architecture is not even formally defined or cannot scale while the size increases. What you obtain is a large system composed of highly coupled parts you cannot change, with duplication in business logic spreaded troughout the classes and in which different components break after a change in unrelated ones. This is called a Big ball of mud.
The requirements for an anti-pattern to exist are simple: a repeated behavior that may appear beneficial in the short-term, but causes pain in the long run while a standard good solution exists. In the case of an object-oriented Big ball of mud, the solution is unit testing and dependency injection.
We are most interested in object-oriented and general programming anti-patterns, and they are the subject of this post. Here are listed the most important and (in)famous, and maybe you have already heard their names. You can consult the wikipedia category for more examples. I guess you will recognize also why most of these anti-patterns are considered bad practices.
- Anemic Domain Model: use of a domain model layer where business logic is not incorporated with data, for instance a big group of entities without any method different from a getter or setter.
- God object: an object from a class that have many responsibilities instead of a single one.
- Sequential coupling: an object requires the client to call its methods in a particular order.
- Circular dependency: mutual dependencies between classes, object or packages. A circular dependency makes two or more code entities inseparable, increasing coupling and killing reusability of both. Mutual dependencies should be break with interfaces, like in the Observer pattern.
- Object orgy: free access to object properties by collaborators, also by setters and getters overusage. Encapsulation should be preferred to prevent changes in a component to affect the other ones.
- Interface bloat: an interface that has grown so much and has to do so many things that it is too difficult to implement, resulting in only the first and official implementation being available. Small and focused interfaces should be preferred.
- Magic pushbutton: inserting domain logic in the user interface only. The name derives from writing code in the generated event-handling routines of buttons. This practice should be replaced with delegation to the domain layer.
- Action at a distance: unexpected interaction between different components. Global state and singletons are typically an example of this anti-pattern, which reveals its Api problems during unit testing.
I think learning from errors is fundamental in every profession, and I considered lucky who can learn from others' mistakes. If we learn what are the wrong choices, we feel confident to apply the best practices of this industry as we can see why they are valid.
Sorry for the late post but it's my ISP fault. Feel free to add anti-patterns that you perceive as diffused in the comments.