Super Graph is a GraphQL to SQL compiler in Go that I’ve been working on for a while now. Overtime it got a lot of useful features and as the single core contributor some parts of the codebase got away from me. A couple weeks ago I came across a bug in the part of code dealing with nested inserts and updated where we generate SQL to update or insert multiple related tables with a single SQL query. The fix for this was simple enough but somehow I couldn’t get myself to make it since it felt like I’m forcing code where it didn’t belong. When you work on the same codebase for a long while you naturally develop a fine tuned sense about it and code smell is very evident to you and I felt this was not just a smell it stunk.
I didn’t make the fix instead I shut my laptop and went on a long walk as it helps me think. Two packages
qcode made up the core of the compiler,
qcode took the GraphQL and parsed it into an AST called
QCode which was then passed to
psql to generate SQL from. The issue I found was that
QCode was a not rich enough, it didn’t carry with it information about database tables and relationships. This meant that
psql had to do a lot more work and instead of just focusing on generating SQL it had to do the additional work of pulling in database schema information and this made the code more complicated.
The one thing I knew from experience was that generating the SQL was hard enough why make it do more. I decided it was time for a refactor and this required a design rethink. The new design I felt needed to focus on improving readability and simplify complex functions. The best way to simplify code in Go is to extract out concerns into new packages and add more information to structs that are passed around so you don’t have to pull in this information all over the place.
In the new design the core GraphQL parser was extracted out from
qcode into it’s own package. Next up the database schema and relationship discovery code was extracted out from
psql into it’s own package and finally the
QCode AST was made richer. The final result was a codebase much nicer and easier to work with and tons of bugs fixing themselves. Major new features going ahead like support for MySQL seems much easier to reason about.
Refactoring Go code is a breeze the fast compiler makes running tests while making changes almost realtime. I’m just happy with how quickly I could do this and the higher quality codebase that it resulted in. Ask me anything.