Controversial coding opinions, Part I: Web Server Frameworks are Evil
Web frameworks are sneaky. They lure you in with their promises of just overriding one method, and (voila!) you have a web or API server.
But then time passes.
Suddenly you want to change something that the framework doesn’t make extensible. Or you spend hours debugging something deep in the bowels of the framework you’re using. Suddenly your framework is your enemy.
In fact, I’d argue the eventual frustrations from using a given web framework are directly proportional to the amount of magic it wows you with up front.
Reusing code of any kind involves a tradeoff between having control and moving faster. This is almost always worthwhile with libraries, which are easy to swap out over time. But web frameworks, even when pluggable, usually involve a magic abstraction over routing HTTP requests and finite points of extensibility. The tradeoff isn’t worth it in the long run. Sometimes it feels like the goal is “write as little code as possible,” when it should be “make this code as easy to write and maintain as possible” — declarative abstractions are not inherently better just because they’re aren’t code. It only takes a small amount of boilerplate application code and some libraries to make something just as functional as and much more versatile than a pre-built framework.
It’s based on code I used to build Answerbox and Spatula, but its real origins are in the way we structured the API code at Foursquare. That codebase grew beautifully over many years: as our needs changed, we refactored; when we had time, we used Scala features to improve its type-safety; when new employees started, they could immediately grok what was going on because at its heart it was a series of switch statements or map lookups that looked just like any other code. There were no gotchas.
You might argue unframework is just another framework, but that’s missing the point. I’m not asking you to take this as a .jar and be just like me. I’m asking you to copy this source code and change every line of it to fit your particular requirements. It’s a macro version of taking code off of Stack Overflow.
There are three advantages to this approach.
1. Flexibility. I can change anything I want! My templating engine is no longer coupled to my routing code. My ORM is no longer tied to my authentication. Even compared to pluggable frameworks, I still have more freedom. I can replace the HTTP Request and Response abstractions with richer objects of my choosing. I can send some types of requests down a totally different cascade of processing than other types of requests within the same binary.
2. Introspectibility. I no longer encounter bugs that require trying to step through endless abstract framework code trying to understand where it went wrong. If you’ve ever spent an hour or two trying to figure out why your call to http://myserver/foo was not being routed to fooMethod the way it should be, you know exactly what I’m talking about. Writing code that calls fooMethod if it sees foo in the path is SO SIMPLE, but we keep insisting on complicating it because declarative routing is cute. It’s just not worth it. Let’s make code you can debug without going insane.
3. Learnability. The more abstract your framework, the more that new hires will need to ramp up on. In the beginning this isn’t so bad, since your codebase is simple. But as it grows, you’re forced to use cutsier tricks to bend the framework to your will, each of which require explaining. In contrast, straight-line code can be understood just by reading it.
Sure, there are some downsides to not using a framework. Maybe the code feels more “boilerplate”-y. Maybe you miss getting little quirks fixed for free when your framework updates. Maybe you miss the ease of just getting going on something new.
But after working this way, I’ve found it hard to go back to frameworks on anything other than the smallest projects. Life’s too short for wrestling with your tools.