Live data from Hacker News

Some Go web dev notes

jvns.ca

101–110 of 154 posts

Re: Some Go web dev notes

#101
post #20

> I learned the hard way that if I don’t do this then I’ll get SQLITE_BUSY errors from two threads trying to write to the db at the same time. 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: http…

OK, a bunch of the replies here seem to be misunderstanding #1. In particular, the assumption is that the only reason a transaction might fail is that the database is too busy.

I come from the field of operating systems, and specifically Xen, where we extensively use lockless concurrency primitives. One prime example is a "compare-exchange loop", where you do something like this:

    y = shared_state_var;
    do {
        oldx = y;
        newx = f(oldx); // f may be arbitrarily complicated
    } while((y = cmpxchg(&shared_state_var, oldx, newx)) != oldx);
Basically this reads oldx, mutates it into newx (using perhaps a quite complicated set of logic). Then the compare exchange will atomically:

- Read shared_state_var

- If and only if this value if equal to oldx, set it to newx

- In any case, return oldx

In the common case, when there's no contention, you read the old value, see that it hasn't changed, and then write the new value. In the uncommon case, you notice that someone else has changed the value, and so you'd better re-run the calculations.

From my perspective, database transactions are the same thing: You start a transaction, read some old values, you make some changes on those values. When you commit the transaction, if some of the the thing's you've read have been changed in the meantime, the transaction will fail and you start over again.

That's what I mean when I say "database transactions are designed to fail". Of course the transaction may fail because you have a connection issue, or a disk issue, or something like that; that's not really what I'm talking about. I'm saying specifically that there may be a data race due to concurrent accesses. Whenever there are more than one thing accessing the database, there is always the chance of this happening, regardless of how busy the system is -- even if in an entire week you only have two transactions, there's still a chance (no matter how small) that they'll be interleaved such that one transaction reads something which is then written to before the transaction is done.

Now SQLite can't actually have this sort of conflict, because it's always single-writer. But essentially what that means is that there's a conflict every time where there are two writes, not only when some data was overwritten by another process. Something that happens at a very very low rate when you're using a proper RDBMS like Postgres, now happens all the time. But the problem isn't with SQLite, it's with your code, which has assumed that transactions will never fail do to concurrency issues.

Re: Some Go web dev notes

#102

Earlier quoted context omitted.

I like Go for this reason as well. In Python I found the Flask framework to be suitably unobtrusive enough to be nice to use (never liked Django), but deploying python is a hassle. Go is much better in that area. The error handling never bothered me either. I think if Go shipped better support for auth/sessions in the standard library more people would use it. Having to write that code yourself (actually not very har…

I'm curious in what sense you find Python difficult to deploy? My company has tons of Python APIs internally and we never have much trouble with them. They are all pretty lightly used services so it it something about doing it on a larger scale?

Forcing something like WSGI and distributed computing is the biggest thing architecturally.

I'm currently moving 4 python microservices into a single go binary. The only reason they were ever microservices was because of WSGI and how that model works.

In any conventional language those are just different threads in the same monolith but I didn't have that choice. So instead of deploying a single binary I had to deploy microservices and a gateway and a reverse proxy and a redis instance, for an internal tool that sees maybe 5 users...

It was the wrong tool for the job.

Re: Some Go web dev notes

#103

I've been using go for a month now in a new job and hate it. It feels like they learned nothing from the past 20 years of language development. 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…

I don't think your example is very compelling but I completely agree with your general point.

I read the Go book by Donovan and Kernighan and I have been working full-time in Go for the last year (my work is otherwise interesting so this is tolerable). It is painfully obvious that the authors are stuck in 1986 in terms of language design. Go is C with modernized tooling (in some ways it's worse...).

It's a horrible idea that has been extremely well executed. And the idea is essentially to make a language as easy as possible for people with imperative language brain damage to learn, make it as simple as possible and then make it simpler than that.

A good example is that despite taking almost everything verbatim from C, the authors decided that the ability to specify that some variable is read-only (i.e. `const`) is "not useful", so one of the few redeeming qualities of C is simply absent from Go.

Re: Some Go web dev notes

#104
post #7

Earlier quoted context omitted.

I agree but those first 5 days are going to be a mixed bag as you pick through libraries for logging, database drivers, migrations, as well as project organization, dependency injection patterns for testing, organize your testing structure, and more. If you have a template to derive from or sufficient Go experience you'll be fine, but selecting from a grab bag of small libraries early on in a project can be a distrac…

I would also say library quality can be generally low. E.g. there are numerous flag parsing libraries but not a single one comes even close to clap in rust.

spf13/cobra and urfave/cli are fine, I think. As sibling said, you can't expect Go to have something like Rust's clap because the metaprogramming capabilities are so different.

On the other hand, I find it sad how terrible stdlib's flag library is. I'd love to have something like Python's argparse, which is not perfect but enough for most of the time. Go's flag doesn't even work well for small programs. It should've been more like spf13/pflag, but as we've often seen with Go, they went "screw decades-old conventions" and did something strictly worse.

Re: Some Go web dev notes

#105
post #7

Earlier quoted context omitted.

I agree but those first 5 days are going to be a mixed bag as you pick through libraries for logging, database drivers, migrations, as well as project organization, dependency injection patterns for testing, organize your testing structure, and more. If you have a template to derive from or sufficient Go experience you'll be fine, but selecting from a grab bag of small libraries early on in a project can be a distrac…

> I agree but those first 5 days are going to be a mixed bag as you pick through libraries for logging, database drivers, migrations, as well as project organization, dependency injection patterns for testing, organize your testing structure, and more. So the same as every other language that lacks these in the standard lib?

C++ comes to mind. Probably the worst language that's used significantly in the industry in terms of tooling and dependency management. The committee is trying to fix this, but almost no one can update to the newer standards.

Re: Some Go web dev notes

#106
post #7

Earlier quoted context omitted.

I agree but those first 5 days are going to be a mixed bag as you pick through libraries for logging, database drivers, migrations, as well as project organization, dependency injection patterns for testing, organize your testing structure, and more. If you have a template to derive from or sufficient Go experience you'll be fine, but selecting from a grab bag of small libraries early on in a project can be a distrac…

I stumbled on this Go starter project that has enough batteries included to get you started I think. You might find it useful https://github.com/mikestefanello/pagoda

I'd suggest starting with the standard library instead. All other libraries come and go, standard will be there as long as Go is alive.

Re: Some Go web dev notes

#107

Earlier quoted context omitted.

I would also say library quality can be generally low. E.g. there are numerous flag parsing libraries but not a single one comes even close to clap in rust.

spf13/cobra and urfave/cli are fine, I think. As sibling said, you can't expect Go to have something like Rust's clap because the metaprogramming capabilities are so different. On the other hand, I find it sad how terrible stdlib's flag library is. I'd love to have something like Python's argparse, which is not perfect but enough for most of the time. Go's flag doesn't even work well for small programs. It should've…

As far as I understand, they respected decades-old conventions. Just not the ones we needed (Plan9 instead of POSIX/GNU getopt).

Re: Some Go web dev notes

#108
post #13

It's sad https://pkg.go.dev/embed was not mentioned in a post about web development in Go :-) Having a true single binary bundling your static resources is so convenient.

Massively underrated. It's actually used to build the pkg.go.dev website itself.

https://github.com/golang/pkgsite

Re: Some Go web dev notes

#109
post #93

Earlier quoted context omitted.

Nice new feature, would actually make me want to use Go without Gin.

I've grown to prefer go-chi over Gin (or Echo), since it's just the standard library with some QoL features on top.

I like it, but with the new http.ServeMux rolled out in Go 1.22, is there any use for Chi anymore?

Re: Some Go web dev notes

#110
post #59
post #2

> In general everything about it feels like it makes projects easy to work on for 5 days, abandon for 2 years, and then get back into writing code without a lot of problems. 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.

I've picked up some Go projects after no development for years, including some I didn't write myself as a contractor. It's typically been a fairly painless experience. Typically dependencies go from "1.3.1" to "1.7.5" or something, and generally it's a "read changelogs, nothing interesting, updating just works"-type experience. On the frontend side it's typically been much more difficult. There are tons of dependenci…

Arguably it's just the frontend. You can use old node in backend as much as you please. Frontend UI expectations evolve so quickly while APIs & backend can just stay the same, if it works it works.
Post reply on HN