The "Countries" example does not look correct to me. Go maps aren't safe for concurrent use (such as parallel REST API requests in this case) and need to be protected with a sync.RWMutex or similar, although it might work safely in some special cases (I'm not sure).
You're right, the example does have a glaring bug - and I completely agree with you, examples should not include incorrect code.
Just to clarify, maps can be read concurrently without locking as long as you're not writing to them. As soon as any concurrent operation might make changes to the map (as the example does) you need locking, preferably a sync.RWMutex (a sync.Mutex will also work but will be way less efficient for no good reason).
I'm pretty sure the map here is not the important part. The example demonstrates how to use the rest interface to talk with a store. The actual implementation of the store is up to you.
Absolutely! Example code affects programming style and teaches people. It should be correct (and in good style), this is probably very much underrated.
Fair point, examples should be correct even on the part that is not the primary focus of the example. I’ve added a RWMutex to the "users" example, other examples improvements will come soon. https://github.com/ant0ine/go-json-rest-examples/commit/6983...
Many gophers hate magic. ORMs are specifically magic, and therefore not very popular with many gophers.
Many gophers have a lot of experience in other languages with ORMs and have been burned by them on many occasions.
I like to say - ORMs make the easy stuff easier, and the hard stuff harder. If you're only doing really simple object storage and your data model easily fits with the model the ORM expects, then it's not too bad. If you EVER want to deviate from that model (and you'll ALWAYS end up wanting to deviate from that model), then you are gonna have a bad time.
Many gophers prefer their code to be more obvious and more under their control. Writing a little SQL never hurt anyone, and Go's SQL package is pretty good. Personally, I like http://github.com/jmoiron/sqlx - you have to write SQL statements still (I consider that a good thing), but it removes the boilerplate of getting data in and out of structs.
Well said. My biggest problem with ORMs in the past boils down to them being "leaky abstractions". They work fine for simple create/update/deletes, but get into trouble with foreign keys, indexes, "group by", advanced queries, etc.
We're using an internally developed ORM in Go and it saves us a lot of time.
Pros:
- Less typing, which means less bugs.
- Type-checked queries, although this is technically not part of the ORM. We have a custom tool which statically examines the code creating ORM queries, checks the types of the output and lets you know of potential errors (e.g. the field you're querying on does not exist anymore). Writing the same tool for SQL would be incredibly difficult.
- No need for long ugly SQL strings in code (well, except for the ORM implementation itself).
- Easier refactoring. If we make changes to a model, the ORM makes the schema modifications for us (with some limitations - e.g. if you rename a field you have to tell the ORM the old name, so it renames the field in the table instead of creating a new one). Coupled with type-checking this is god-send.
- Complete SQL database abstraction (database/sql does not provide that - placeholders, quotes, etc... vary by database driver).
- SQL / NoSQL / KV-store / whatever transparency. We have SQL drivers for sqlite, postgres and mysql, as well as drivers for mongodb, the GAE datastore and redis. Of course, some drivers have limitations, like the NoSQL ones can't perform JOINs, but we still get incredible flexibility. We had one app running on GAE with a data model which was a good fit for the datastore. Some months later, a few requirements were added and moving to a relation database was the best solution. So we spun off a Google Cloud SQL instance, migrated the data and started using JOINs for the new features, while the previous code continued to work unchanged.
- App Engine / vanilla Go cross platform (well, you'd also need our full web framework for that, but the ORM is one of the key components). We have some applications running in GAE. If they ever get too costly to run on GAE we can just execute three of commands and deploy it to our own servers (and by "three" I mean the exact number: one command to move the ORM data from the datastore to the new database, another one to move the stored blobs from the GAE blobstore to S3/GCS/filesystem and another one to deploy the app to the new server).
Cons:
- Overhead. Negligible in most cases, but when it matters we can drop down to raw queries.
At the end of the day, I think using an ORM or raw database queries is just an engineering decision you have to make depending on your project constraints, not on the language you're using.
One reason might be that there weren't any ORMs around that would qualified to be called such for other languages, last time I checked. https://github.com/jinzhu/gorm is probably still the most popular choice.
Though as jmoiron points out http://jmoiron.net/blog/gos-database-sql/ if you're looking for a Go version of ActiveRecord it isn't going to be achievable any time soon.
Go has a ton of things going for it! I suggest Googling for more info, but a couple of my favorite features:
* I can use go fmt to format my code and it'll look nice. So many people use go fmt that most code bases are very easy to dive into. They all follow the standard!
* No magic! You write what you want and the whole formality of the thing forces you to write better code. May be a placebo effect, but I find myself writing less buggy code in Go.
* Compile to static binary you can just drop and run -anywhere-. No rvm gemsets, no rbenv, no bla bla bla - you want your code running, period.
Clearly you have never run across the same program, first in Perl, and then in Python, and felt the tangible differences in maintainability between the two implementations.