When I started my career in programming, I levelled up pretty quickly. I chalk this up to late night coding sessions, building out ideas I had. Unfortunately, none of those ideas came to fruition. But that wasn’t really the point. The point was, I just enjoyed building things. I would build out ideas just for the joy of being creative.
In those days, I was using PHP and then Node.js. Languages that felt productive and easy to quickly prototype ideas. Large, Swiss army knife frameworks such as Laravel made it a breeze to quickly get ideas from the editor, to something tangible.
Around 2016, I started learning Go. It was a decision I thank myself for continually, and it has served me well in terms of my career. But I did notice that these late night tinkering sessions became more frustrating. Particularly, Go lacks a direct equivalent to Laravel, for example.
There’s Buffalo, which, at the time of writing this is archived. But even prior to that, I never had a great experience trying to use Buffalo, it felt clunky, and not because of the quality of the codebase itself, with Mark Bates at the helm, a seasoned Gopher. But because the large framework style model doesn’t entirely seem to sit right with the language itself. There are several other frameworks, but they’re more akin to routing libraries than frameworks. Buffalo was the closest I could find to something like Laravel, and I commend the work that went into that project, there are many massively useful libraries that also came out of that project. So, I’m certainly not knocking it. As many folks did find it useful.
Go was written with small, network heavy services in mind, therefor, the full stack web development experience has never felt that great, as that was something the Go community tried to backfill over the years with various libraries and frameworks.
Go was great for my career, because Go is fantastic at many of the types of projects and products I’ve worked on over the years. But it wasn’t a great choice for tinkering with full stack ideas.
But it wasn’t just my choice of language. Back in the PHP days, things were very simple. There was no infrastructure as code, no Terraform, no Serverless, no compute instances, no Kubernetes, none of the weird and wonderful ways in which we get code from our machines into the hands of the users. It was an FTP client, or scp, simply moving files from A to B and spawning a MySQL process in the background. Whilst crude, this was incredibly straight-forward for tinkering with ideas.
The problem is, when an idea springs to mind, you want to create that idea. But that’s only part of the work needed, you need to chose a cloud provider, choose whether you’re going to use some kind of Serverless offering, or some form of container based solution. You need to choose how to deploy your code to that runtime. Even at the code level, you need to write your database layer, which is often a case of manually writing wrappers around SQL queries, that converts input data into SQL and back out again. You need to write some kind of web server, routing, authentication Middlewares, etc.
I found that by the time I’d set up the shell of a project, running on some cloud runtime somewhere, that exposed a single endpoint connected to a database with authentication. I could no longer be bothered to continue with the rest. So ideas would die before they got anywhere near off the ground.
I tried using offerings such as Supabase, but they’re often so opinionated and locked into their way of doing things, that if you stray remotely off track, then you’re in a land of weird work arounds and writing yet more boilerplate just to glue the basic building blocks together.
This all changed recently, I noticed Encore in a Twitter post and the example that person posted looked compelling. I audibly gasped when I saw what encore.dev was as a product offering. It was everything I’d ever wanted in a product. It handles CI/CD, it automatically infers what infrastructure you need from your code alone, and creates it, it creates staging environments, git integration so you can preview you changes, and it keeps its opinions largely to itself.
It also automatically creates your endpoints based off of types and code comments, for example:
//encore:api public
func CreateUser(ctx context.Context, params *CreateUserParams) {
...
}
Becomes $ curl -XPOST http://localhost:4000/users.CreateUser -d '{ "name": "Ewan" }'
You can also create databases, events, caching, and several other common cloud primitives. Amazing.
I quickly span up a service that had authentication (using Clerk, which was a well-documented, and straight-forward set-up), a Postgres database running, and a series of endpoints. From the diagram below, the left most and bottom blocks were just done for me.
The data access boilerplate was still a pain, however. I’ve typically used GORM over the years, just because it seemed like the easiest approach to representing my database schemas in code. But, this meant writing lengthy, tedious repository packages. I had some issues with the migrations and decided to see what else was supported. I found a page in the docs that talked about using sqlc, which seemed to integrate a lot easier than GORM did.
Sqlc was something I’d heard about, but didn’t fully understand the power of until I tried it out. I knew it took a different approach and generated some Go code to interact with your SQL queries, but I was dubious as to how well that could work. So I gave it a go and yet again, there was an audible gasp.
It immediately generated exactly what I wanted from my simple SQL queries, and Encore handled the migrations seamlessly. So that was the data access box of pain taken care of.
Once I’d gotten to grips with this set-up, which took about an hour, I coded away on a project I’d been thinking about, lost track of time and suddenly it was almost 3am. Now, I’m not suggesting people stay up til 3am every night. My point is, it’s been a long time, especially in the Go ecosystem, where I felt so productive on a hobby project, that I just didn’t want to stop. This huge reduction in time spent just setting things up and writing boilerplate allowed me to focus on functionality and the idea itself.
So hats off to Encore on building a hugely impressive product, and I’m sorry to the sqlc maintainers for not trying sqlc out sooner. To be honest, I read about sqlc some time ago, but doubted it could do what it claimed, or imagined there would simply be some kind of catch. There wasn’t, it’s fantastic.