Separate Test And Implementation Code

separate ways

Photo by Jens Lelie on Unsplash

 

The other day I spotted this programming gem: 

  if (useTheRealMcCoy)
  {
     database = new Database();
  }
  else
  {
     database = new MockDatabase();
  }

Well, it wasn’t quite like this, but similar—I’ve recreated the problem code since I am not in the business of publishing my clients’ proprietary application programming. However, I am in the business of teaching developers to write clearer, more maintainable, and even beautiful code. 

With this example, I spotted a learning opportunity which we will exploit today. 

Why is this code problematic?

As the title of today’s blog post points out, we should not be mixing test code with implementation code.

Why not?

It makes our application more Fragile

Why? Imagine we have a bug in our code causing variable useTheRealMcCoy to be set to false intermittently and instantiating MockDatabase. If we deployed this buggy code to our production environment, then would this cause havoc? Yes, quite likely. We’d expect to see spurious behaviour where data is mysteriously lost instead of being saved to the database.

The code becomes Unnecessarily Complex

When we mix test and implementation code, we make our functions harder to understand for all readers; those who are only interested in the implementation and those who want to browse the testing code. Separate these two responsibilities, and the readability of the program increases. Maintainability increases, and we’re likely to see fewer bugs.

Violation of the SOLID Principles

Coupling concerns meant for the benefit of two different actors, here end-users and programmers, violates the Single Responsibility Principle. Test code helping us programmers should not be mixed in with the parts of the program benefitting the end-user. Furthermore, this dependency on concrete Database instances, Mock or not, goes against the Dependency Inversion Principle. Last but not least, the Open-Closed Principle also comes into play—if we had a design that used an abstraction for the Database whereby we could provide either an instance of a Database or a MockDatabase, then we could extend and alter the behaviour of the code without the original code fragment.

Please avoid mixing test and implementation code. Both fulfill different concerns and should remain separate.

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply