While Design patterns are recurring solutions to problems often encountered in software applications, anti-patterns are exactly the opposite — these are recurring programming practices that create problems instead of solving them. These evolve out of over engineering, wrong implementation of design patterns, not following the recommended practices, etc. I would like to present a discussion on anti-patterns in this post.
Selecting the Right Combination
The choice of which patterns, frameworks and platforms to use in an application depends largely on an objective observation of the functional and non-functional requirements. You shouldn't select a design pattern because you saw someone use it somewhere or someone told you that there is no harm in using it. You should decide whether or not it is the right pattern to use based on what your problem statement is and what solutions are available for you to achieve the stated goal.
Let's discuss a few programming anti-patterns. Single Responsibility Principle is one of the most important of the SOLID principles in software engineering. The SOLID principles include: single responsibility principle, open/closed principle, Liskov substitution principle, Interface segregation principle and dependency inversion principle. SOLID principles, if followed properly help you to build types that are easier to manage, test and maintain. The Single Responsibility Principle states that an object should perform one, and only one, task.
It is a bad design if you have too many operations in your class. If you have a class that performs, or is intended to perform, too many tasks, it violates the Single Responsibility Principle. This anti-pattern is characterized by a single class that contains many different operations — many responsibilities are allocated to this class. Instances of such classes that perform too many tasks are known as God objects. Such classes are difficult to test, manage and maintain.
Spaghetti code is another example of an anti-pattern — such code is difficult to maintain and is not reusable. Spaghetti code is a result of developers writing code without a proper design and code review. The relationship between objects are a bare minimum and you would need to write many integration tests before you could deploy your application to production. Testing of Spaghetti code is difficult, such code doesn't leverage the benefits of object oriented programming and most importantly, the flow of execution is dictated by the objects and not the consumers.
Constructor injection becomes an anti-pattern if one or more of the arguments to the constructor is not a class dependency. In essence, imagine that you have a class with an argument constructor and the argument(s) in your constructor is not always needed. You are still constrained to pass the arguments in the order in which they have been declared just to satisfy the method (the constructor in this example) call. This is an example of a code smell — you are injecting dependencies that are not always needed using a constructor. Implementing design patterns to solve the design problems encountered is definitely a good idea. However, you should not overuse patterns. If design patterns are not used the proper way, your code would become difficult to understand and maintain and become an anti-pattern.
There are many other anti-patterns such as service locator, singleton, generic repository and the dispose pattern. Such anti-patterns are an example of using these patterns the wrong way. These patterns do have some useful applications but if not used properly will result in code smells and hence an anti-pattern. I will discuss regarding these patterns and how they might tend to become an anti-pattern in future articles with code examples and the best practices to avoid code smells when using design patterns in your code. Happy reading!
Adaptive Code via C# by Gary McLean Hall