Anti-pattern: Multiple Frameworks in the same codebase

Published: Thu Jan 13 2022
Updated: Thu Jan 13 2022

The Frameworks vs Libraries debate is evergreen. Just to make things clear, my mental model here is:

  • Framework: Someone else's code is in the drivers seat. Your code gets invoked by someone else's code.
  • Library: You are in the drivers seat. Your code calls external code.

There was a recent post about this I really liked: "Write Libraries, Not Frameworks". The HN discussion is also on-point.

I mostly agree with that post. As a user, I prefer external dependencies that are libraries not frameworks. But there are definitely places where I would like to use a framework — for example, I don't usually want to cobble together every part of a modern web framework from smaller libraries.

If you are using a framework, please follow this rule of thumb though: You can use multiple libraries in a single project, but you're only allowed to have one framework.

Here's why:

  • Frameworks are monolithic and opinionated pieces of code. You have to write your code in a way that works with the framework.

  • Having two (or more!) frameworks in the same application means trouble.

  • The frameworks won't be designed to work well together.

  • Your code will need to be twisted to meet the needs of each framework. Your code will need to serve as a glue layer, just to overcome the impedance mismatch between these frameworks.

  • The end result will be something brittle and harder to maintain.

Let's take a concrete example:

  • Dropwizard is a Java framework that's more minimalistic compared to most JVM frameworks.

  • Out of the box, Dropwizard does not support Dependency Injection12.

  • You might be tempted to put in a dependency injection framework like Guice.

  • By experience, I can say that this is a mistake. You will lose sight of how Dropwizard is meant to work3, and you will have to debug issues caused by integration between Dropwizard & Guice.

  • I've personally wasted time debugging such issues.

    • Examples: Why isn't this resource wired properly? How does scoping of injected objects work? Why does application startup take a long time? How do I hide a route from the application when I'm not ready to launch it?
  • With benefit of hindsight, I would either:

    • Not use dependency injection when using Dropwizard.
    • Or, use a framework like Spring Boot which has built-in support.

This is a simple rule of thumb that I try to follow for all my applications: two frameworks + single codebase = bad idea.

  1. Technically, it uses HK2 internally. But this is not really exposed, and the Dropwizard docs don't mention HK2 at all.
  2. I should really get down to writing my thoughts about dependency injection one day!
  3. The feeling I get whenever I use Dropwizard is that of a simple, minimalistic framework. Something like Flask with Python. Doing magic seems counter to the goals of using a lightweight framework. Dependency injection is magic. If you want more features, why not pick a framework like Spring Boot instead?