The code for this project in this article can be found here
Let me ask you one question: What important would you place on things “just working”?
I have long been a fan of dependency injection and inversion of control in general, and if you’ve read my previous articles, you’ll know how big of a proponent I am of it’s use in NestJS. It’s so nice to be able to inject a service into a controller, a logger into a module, or a DB handler into a repository and it “just works” - no need to worry about how. I just want to write business logic, and it’s all just there, ready to be used and injected in by the DI container.
Because of this, I began searching around to see if Go had any DI tooling or libraries to give a similar experience. That’s when I stumbled upon fx, a library created by Uber to provide a full dependency injection framework for Go, and apparently it’s the backbone being almost all of Uber’s Go services (which I assume is a lot given their style guide is the industry defacto). After some time playing around with it, I’ve come out with one persistent observation:
FX makes writing Go programs feel like magic Link to heading
To understand how, we’ll build a very simple document database engine, and we’ll use FX to make managing the dependencies a breeze.
The Project Link to heading
Our simple document database will truly be simple - we’ll he using the filesystem and JSON documents store documents
to collections
(🍃), and use a simple query syntax to find and list those documents, with queries like:
# Create a new collection called "users"
CREATE users
# List all the collections
LIST collections
# Find all documents in the "users" collection
GET users
# Find all documents in the "users" collection with a "name" property equal to "John"
GET users WHERE name = "John"
# Delete all documents in the "users" collection with a "name" property equal to "John"
DELETE users WHERE name = "John"
To do this, we’ll need a few different components:
- A query parsing engine (to parse the query syntax)
- A collection engine (to setup and manage collections)
- A document engine (to read and write documents within collections)
- A storage engine (to read and write documents to disk)
- A logger (to log things, obviously)
- A webserver (to expose the query endpoint, for simplicity we’ll just use a one-endpoint webserver)
The benefits of the DI system will become apparent if we look at the dependency graph:
As you can see, there are a good amount of intermingled dependencies here, and it’s not immediately obvious how to get them all into the right places. Imagine you had a real database engine like WiredTiger, with transaction engines, paging systems, and a whole host of other dependencies to manage!
This is where FX comes in.
The Code Link to heading
This section is still in progress, but you can take a look at the current codebase here