Some Go web dev notes
Julia Evans discusses her experiences with Go, highlighting improvements in routing, the sqlc tool for database interactions, SQLite optimization tips, and the benefits of Go's simplicity and memory management features.
Read original articleJulia Evans shares her experiences and insights gained while developing a website using Go. She highlights improvements in Go 1.22, particularly in routing, which now allows for more streamlined code compared to manual routing. She encountered issues with the built-in router, specifically with redirects involving trailing slashes, which she resolved by adopting a more conventional API design. Evans also discovered sqlc, a tool that generates Go code from SQL queries, which simplifies database interactions without the need for an ORM. She provides tips for optimizing SQLite, such as using separate database objects for reading and writing to avoid SQLITE_BUSY errors. Additionally, she discusses the introduction of a garbage collection memory limit in Go 1.19, which helped mitigate out-of-memory issues in her applications. Evans appreciates Go for its simplicity, ease of deployment, and the ability to quickly resume work on projects after long breaks. She contrasts her experiences with Go to her challenges in using Rails, emphasizing the clarity and accessibility of Go's structure. Overall, she expresses enthusiasm for the new features in Go and encourages developers to stay updated with release notes.
- Go 1.22 improves routing capabilities, allowing for cleaner code.
- sqlc generates Go code from SQL queries, reducing boilerplate.
- Optimizing SQLite involves using dedicated database objects for reading and writing.
- Go 1.19 introduced a memory limit for garbage collection to prevent OOM issues.
- Evans prefers Go for its simplicity and ease of resuming projects after breaks.
Related
First impressions of Go 1.23's range-over-func feature
The author shares positive experiences with Go 1.23's range-over-func feature, initially skeptical but finding it easy to use. Successful adaptation in their project Kivik disproved initial concerns, highlighting benefits for codebase improvement.
An unordered list of things I miss in Go
The blog post highlights features missing in Go, such as ordered maps, default arguments, and improved nullability, suggesting these enhancements could benefit the language despite requiring significant revisions.
A Love Letter to Go
The author reflects on 12 years with Go, praising its simplicity, performance, and concurrency, while suggesting improvements in data structure handling and broader use in data science and machine learning.
Writing an HTTP Server in Go from Scratch: Part 1
The author built an HTTP server in Go for a CodeCrafters challenge, implementing features like request handling, concurrency, and routing, while enhancing code modularity and planning to pursue more challenges.
Some Go Web Dev Notes
Julia Evans discusses her experience with Go, highlighting improvements in routing, the sqlc tool for SQL queries, SQLite optimization tips, and Go's memory management, praising its simplicity and ease of use.
- Many users appreciate Go's simplicity, memory management, and the ease of returning to projects after long breaks.
- Some users express frustration with Go's handling of null values and verbosity in error checking, comparing it unfavorably to other languages.
- There are discussions about the limitations of the sqlc tool for database interactions, with some users preferring manual approaches.
- Several comments mention the convenience of bundling static resources in Go applications and the importance of proper database transaction handling.
- Users share tips and resources for optimizing SQLite usage and improving concurrency in Go applications.
To me this is one of the most underrated qualities of go code.
Go is a language that I started learning years ago, but did't change dramatically. So my knowledge is still useful, even almost ten years later.
Having a true single binary bundling your static resources is so convenient.
As for sqlc, I really wanted to like it, but it had some major limitations and minor annoyances last time I tried it a few months ago. You might want to go through its list of issues[1] before adopting it.
Things like no support for dynamic queries[2], one-to-many relationships[3], embedded CTEs[4], composite types[5], etc.
It might work fine if you only have simple needs, but if you ever want to do something slightly sophisticated, you'll have to fallback to the manual approach. It's partly understandable, though. It cannot realistically support every feature of every DBMS, and it's explicitly not an ORM. But I still decided to stick to the manual approach for everything, instead of wondering whether something is or isn't supported by sqlc.
One tip/gotcha I recently ran into: if you run Go within containers, you should set GOMAXPROCS appropriately to avoid CPU throttling. Good explanation here[6], and solution here[7].
[1]: https://github.com/sqlc-dev/sqlc/issues/
[2]: https://github.com/sqlc-dev/sqlc/issues/3414
[3]: https://github.com/sqlc-dev/sqlc/issues/3394
[4]: https://github.com/sqlc-dev/sqlc/issues/3128
[5]: https://github.com/sqlc-dev/sqlc/issues/2760
[6]: https://kanishk.io/posts/cpu-throttling-in-containerized-go-...
OK, here's a potentially controversial opinion from someone coming into the web + DB field from writing operating systems:
1. Database transactions are designed to fail
Therefore
2. All database transactions should done in a transaction loop
Basically something like this:
https://gitlab.com/martyros/sqlutil/-/blob/master/txutil/txu...
That loop function should really have a Context so it can be cancelled; that's future work. But the idea stands -- it should be considered normal for transactions to fail, so you should always have a retry loop around them.
Sooner or later you will hit html/template, and realize it's actually very weird and has a lot of weird issues.
Don't use html/template.
I grew to like Templ instead
I personally love "library over framework" mindset and I found Go to do that best.
Also, whether you want to build a web app or cli tool, Go wins there (for me at least). And I work a lot with PHP and .NET as well and love all 3 overall.
Not to mention how easy was it for someone like me who never wrote Go before to get up and running with it quickly. Oh did I mention that I personally love the explicit error handling which gets a lot of hate (Never understood why). I can do if err != nil all day.
A big Go fan.
- go-chi for routing - pgx for Postgres driver - pressly/goose for migrations (I like how it can embed migrations into the binary as long as they are in SQL/not Go) - go-jet (for type-safe SQL; sort of - it lets you write 100% Go that looks like 98% SQL) - templ - htmx (not Go-specific, but feels like a match made in heaven for templ) - authboss for auth
I'm very happy with all of these choices, except maybe authboss - it's a powerful auth framework, but it took a bit of figuring out since the documentation is not very comprehensive; but it worked out in the end.
Also sometimes if I have two tables where I know I’ll never need to do a JOIN between them, I’ll just put them in separate databases so that I can connect to them independently.
If this data belongs together and you're just doing this to improve concurrency, this may be a case where BEGIN CONCURRENT helps: https://sqlite.org/src/doc/begin-concurrent/doc/begin_concur...
If you want to experiment with BEGIN CONCURRENT in Go you could do worse than try my SQLite driver: https://github.com/ncruces/go-sqlite3
Import this package to get the version with BEGIN CONCURRENT: https://github.com/ncruces/go-sqlite3/tree/main/embed/bcw2
go build ./... Goes where ?
What makes me happy is that lots of critical infrastructure tooling is also in Go from datbases to web servers and cluster orchestrators.
Just one huge problem is that they REPEATED Java's million/billion dollar mistake with nulls. The usual way to get HTTP Headers using Go cannot distinguish between an empty header value and no header at all because the method returns "nil" for both these cases. They could've adopted option types but instead we are back to this 90s bullshit of conflating error types with valid values. If you're programming defensively, every single object reference anywhere has to be checked for nil or risk panicking now.. like why, after we literally named this a billion dollar mistake in Java, why would anyone fucking do this again?
We have helper methods in our codebase just do to this:
fn checkThingIsA(ctx) {
thing := ctx.get(thing)
if thing == nil || thing != Thing.A {
return false
}
return true
}
In any sane language this is one line: ctx.get(thing).map(|x| x == Thing.A).unwrap_or(false)
In Go, we have to make helper methods for the simplest things because the simplest 1-liner becomes 4 lines with the nil/error check after. We have 100 helpers that do some variation of that because everything is so verbose that could would become unreadable without it.I hate that they made and popularized this backwards dumpster fire of a language when we should know much better by now.
Related
First impressions of Go 1.23's range-over-func feature
The author shares positive experiences with Go 1.23's range-over-func feature, initially skeptical but finding it easy to use. Successful adaptation in their project Kivik disproved initial concerns, highlighting benefits for codebase improvement.
An unordered list of things I miss in Go
The blog post highlights features missing in Go, such as ordered maps, default arguments, and improved nullability, suggesting these enhancements could benefit the language despite requiring significant revisions.
A Love Letter to Go
The author reflects on 12 years with Go, praising its simplicity, performance, and concurrency, while suggesting improvements in data structure handling and broader use in data science and machine learning.
Writing an HTTP Server in Go from Scratch: Part 1
The author built an HTTP server in Go for a CodeCrafters challenge, implementing features like request handling, concurrency, and routing, while enhancing code modularity and planning to pursue more challenges.
Some Go Web Dev Notes
Julia Evans discusses her experience with Go, highlighting improvements in routing, the sqlc tool for SQL queries, SQLite optimization tips, and Go's memory management, praising its simplicity and ease of use.