Anti-Patterns in Software Development That You Should Avoid

Thanh Le
Geek Culture
Published in
8 min readOct 21, 2020

--

Photo by Free To Use Sounds on Unsplash

Context

Software development is a chaotic activity. So, applying design patterns wisely will help you to speed up the development process by providing well-proven design paradigms. Basically, design patterns provide reusable solutions for common problems/issues. Besides that, if you use design patterns in your solutions, your source codes will become more flexible, reusable and maintainable.

Anti-patterns are on the opposite side of the design pattern and undesirable. There is another term for Anti-pattern that people usually use called Design Smell.

What are they?

Note: The list below might be not exhaustive. They are just from my point of view. Feel free to add more based on your experience :)

Silver Bullet (Golden hammer)

Photo by Will Porada on Unsplash

Golden Hammer is an anti-pattern that you easily to find a sample not only in software development but also in every aspect of life. Some people tend to have their solution ready before understanding the problem like a doctor prescribing while the patient still telling about the symptoms or like a developer trying to use modern UI/UX frameworks to build a simple feedback form with 4 text fields…

In software development, each design pattern, each framework or even each programming language is suitable to the typical problem. However, some people obsessively use the same one for every problem that they have to resolve.

As a result, the Golden hammer leads to…

  • Poorly performing code: the chosen one is not an efficient solution to the problem.
  • Overly complicated code: in the sample above, instead of using some simple line of HTML codes the developer used a modern framework like Angular it leads to hard to maintain and even hit directly to performance.
  • Redundant code: the chosen one not only adds no benefit but also brings so many useless codes.

How to avoid this anti-pattern?

  • If you working in a team (especially a leader), you should learn to listen to other people first — don’t be narrow-minded.
  • Always have at least 2 solutions for one problem and benchmark them. List down all PROS and CONS of each solution then choose the better one.

God Class

Photo by Rick Mason on Unsplash

A typical God class will control many other classes, take many responsibilities as well as lots of dependencies. This anti-pattern directly violates the “Single Responsibility” principle.

God classes are hard to unit test, debug and document. By the time, they will grow up together with your application and become the maintenance nightmare even untouchable.

Your application could be well designed at the beginning and there were no God classes at all. However, the requirements and development team size will grow day by day. As a result, single clearly-defined classes will turn into God classes at some point.

Here is a sample of God Class:

figure 1: God Class

In order to refactor the God class above, we should divide functionalities into different classes and interfaces as below:

Import/Export function and Interface:

figure 2: Import/Export function

Database Integration

figure 3: database integration

Validation

figure 4: validation

How to avoid this anti-pattern?

  • The development team should follow the “Single Responsibility” and “Interface Segregation” principle.
  • Do code review and detect technical debts frequently.
  • Classes should be well documented.

Big ball of mud

Photo by Gabriel Sanchez on Unsplash

“Weeks of coding will save you hours of planning.” — Unknow

Big ball of mud is a very common anti-pattern that happens when your solution/application lacks a perceivable, flexible, suitable architecture. If your application has the following symptoms then could be considered as “Big ball of mud”.

  • Haphazardly and sloppy structure without coding comments.
  • Containing many God classes with more than 6000 lines of code.
  • Static variables/functions everywhere.
  • Methods being overloaded several times.
  • Don’t have the coding convention.
  • Duplicated codes everywhere.

This anti-pattern is very dangerous, because, we don’t realize that our application becoming “Big ball of mud” until we can’t refactor it anymore and have to decide to rewrite. The reason why we can’t realize earlier might come from different reasons like requirements changes, the deadline is near, adopting new developers, or even we’re too confident with initial design architecture….

How to avoid this anti-pattern?

In general, we rarely can detect the issue when it’s occurring, so every action should be applied at the beginning of the project. In case we can detect the issue then options to mitigate are very limited and costly.

  • We should have a discovery phase to design the to-be system and choose the most appropriate design to apply before the development phase. (In some projects, to save the cost we usually by-pass this phase).
  • Do code review frequently in order to detect issues as soon as possible.
  • At some point, if your architecture can’t catch up requirements then you should take action intermediately, don't wait until too late.

Error hiding and Exception swallowing

Photo by MIKHAIL VASILYEV on Unsplash

Effective error and exception handling in every application are very important in every application. They help to provide a pleasant experience to the user, as well as support developer can easily debug the issue and fix, when unexpected failures occur.

Wait… we’re not talking about design pattern or best practice here!

In computer programming, error hiding (or error swallowing) is the practice of catching an error or exception, and then continuing without logging, processing or reporting the error to other parts of the software. Handling errors in this manner is considered bad practice and an anti-pattern in computer programming. In languages with exception handling support, this practice is called exception swallowing. — Wikipedia.

With errors are swallowed, the developer will not have any idea about the root cause of the problem. As a result, it’s very hard to figure out what is going wrong or how to resolve it.

Here are some Exception Swallowing samples:

  • Re-throwing an Exception: We can re-throw an exception from the “catch” block to pass on to the caller and let the caller handle it the way they want just to make sure don’t re-throw an exception using exception parameter. Please have a look at the sample as below:
figure 5: re-throw an exception

As you can easily find out there is an exception in “FunctionB” and the “catch” block in “FunctionB” just simply throws that exception using “throw” keyword. By that way, the catched exception from “FunctionB” will be handled in “FunctionA” — we called it “re-throwing”. In this case, the stack trace of the exception will give you the full detail of where exactly this exception occurred.

So, what will happen if you re-throw an exception using exception parameter? The answer is that it will not preserve the original exception and creates a new exception like the sample below:

figure 6: re-throw an exception with parameter

As you can see, exception caught in the Main() method will display stack trace from FunctionA and Main method. It will not display Method1 in stack trace as we re-throw exception in Function using throw ex. So, never throw an exception using throw <exception parameter>.

  • Catching non-specific type exceptions: We should catch only the exception types you expect to happen because we hide bugs in your code otherwise.

Don’t do this

figure 7: catching non-specific type exception

Should do this

figure 8: catching specific type exception
  • Baseball Exception Handling: You shouldn’t use exceptions as a substitute for normal flow control constructs like if-else statements and for-each loops.

Don’t do this:

figure 9: baseball exception handling — don’t

Should do this:

figure 9: baseball exception handling —should

Note: I also have another article regards to logging in Microservices architecture here: https://medium.com/@letienthanh0212/building-logging-system-in-microservice-architecture-with-elk-stack-and-serilog-net-core-part-1-8fe2dfcf9e6f

Copy-and-paste programming

image source: Pinterest

Copy-and-paste programming, sometimes referred to as just pasting, is the production of highly repetitive computer programming code, as produced by copy and paste operations. It is primarily a pejorative term; those who use the term are often implying a lack of programming competence. It may also be the result of technology limitations (e.g., an insufficiently expressive development environment) as subroutines or libraries would normally be used instead. — Wikipedia.

We can easily find an example of this anti-pattern when do code reviewing for a junior developer or an intern who doesn’t have too much experience and difficult to build and deliver a function/task from scratch. They tend to search and apply the code that they can find from the internet like Stackoverflow or Github or even from co-workers without fully testing and impact analysis.

In the worst case, this anti-pattern can create is an infection of your source code with bugs from the source material. It acts like a virus and you will have to fix the bug and change the code everywhere the code was copied.

Beside junior developers and interns who easily become the victim of this anti-pattern, poor understanding of features common in computer languages, such as loop structures, functions and subroutines might also lead to this anti-pattern.

How to avoid this anti-pattern?

  • Like other anti-patterns, the best way to avoid this anti-pattern is that doing code review frequently and carefully.
  • The code which found from outside your application/solution should be tested and analysed impact area carefully. After that, it should be reviewed and approved by senior members of your team.
  • When you see a code block appearing multiple times, you should do refactoring to abstract each appearance into a single function or method. By that way, if the bug is found you only need to fix at one place.

Conclusions

Making mistakes leads to improvement, so don’t panic if you can find one or more anti-patterns in your current application/solution. Let’s gather the team and try to improve one by one.

Hopefully, you don’t need to rewrite whole application :)

Photo by Wil Stewart on Unsplash

References

--

--

Thanh Le
Geek Culture

A Software Technical Architect — Who code for food and write for fun :)