Revel was the most promising Go web framework that I saw though very immature.
Go ORMs aren't ORMs. They are object persistence frameworks (at best). None of them really provide the "R" in ORM. Most of them basically do "SELECT * FROM table WHERE id=12" and dump that into a struct. There goes the "M" as well.
The Go language itself is very nice to work with though. It's a great language. Give it 2-3 more years and a truly usable ORM and web framework will crop up.
Re relational versus non-relational, they're really suitable for different kinds of data, and it's disingenuous to suggest that one is the future and one is the past.
Ruby's ActiveRecord is a much better choice. It has an excellent balance between SQL and OO. It doesn't pretend that SQL doesn't exist; on the contrary, it encourgaes SQL use, and merely maps tables to objects, adds a bunch of useful features (data validation, change management, automatic joins, declarative migrations) and gets out of your way most of the time.
For example:
users = User.where("created_at > ?", Time.now - 1.year).
order('name').limit(10)
Results are lazily loaded and composable, so you can do: users = User.where("created_at > ?", Time.now - 1.year)
if (page = params[:page])
users = users.offset((page - 1) * 10).limit(10)
end
Joining is easy: users = Users.joins(:accounts).
where(accounts: {type: 'facebook')).first
becomes something like: select users.*
from users
join accounts on accounts.id = users.account_id
where accounts.type = 'facebook'
limit 1So now I've gone fully circle: from SQL to ORM and back to SQL.
You can write migrations either in plain SQL (my preferred method) or in go.
Aside from goroutine scheduling issues, what would be the main reasons to run multiple Go processes, instead of just running a single multi-threaded process?
It's probably possible to have most of that logic in a single Go process which runs a bunch of sub-processes for serving requests, but then you're also pretty much writing a load-balancer as well as your app each time. Perhaps better to separate out those tasks and put them into a separate process manager which runs a pool of processes, as on other platforms like Ruby with Unicorn or Passenger? Those platforms have other reasons of course for scaling with processes and not threads, which don't apply to Go.
Not sure how hard or efficient this would be (just using one process) as I haven't tried an app in this style in go, have only been playing with it so far. I would be really interested to see a Go server implementation that managed a bunch of goroutines to serve requests, are there any examples out there?
I'm slightly confused by this question, because that's what the standard library does. If you've ever used net/rpc, or net/http, then it spawns goroutines for each request (or connection, respectively).
If you meant to say spawn a bunch of _processes_ to serve requests, then no, I don't think anyone has done it. I don't think it makes a whole lot of sense for anyone to write code to do this in Go, tbh.
> redundancy in case a process does hang
If you're talking about deadlocks, then only the deadlocked goroutines will be blocked. The rest will make progress, just as if you had multiple processes.
> rolling restarts to switch out to a newer version of the code seamlessly by starting multiple processes to handle requests before killing the old one
You can do this with only 2 processes, old and new. You can spawn the new one, tell your LB to add the new to the pool, wait 30 seconds, remove old from pool, wait 60 seconds, kill old one. You don't need an LB, you could, of course, use an nginx frontend or something instead. There's also some neat ways to do nginx-style zero downtime restarts that I've never tried, but heard good things about.
> I suspect you'd hit some limits of the scheduler
AFAIK, limits of the scheduler tend to be hit when you increase GOMAXPROCS to something above 8. At this point, you'll spend a lot of your time in the runtime managing goroutines. My solution is just to run multiple processes with GOMAXPROCS=8 and point your LB at both of them. Again, you can just use nginx.
Feel free to experiment with the model you proposed, but this is relatively non-idiomatic, and the context-switching cost will start to mislead you as to Go's actual potential. The advantage, btw, that you get when you use the model I spoke of is that in memory caching, connection pooling, context switch time are all close to optimal, and you have fewer processes to monitor/restart/update.
You can do this with only 2 processes, old and new. You can spawn the new one, tell your LB to add the new to the pool, wait 30 seconds, remove old from pool, wait 60 seconds, kill old one.
You still need a LB to do this, though I take your point that you could use nginx, might experiment with that.
* Lack of an ORM (there are many, almost all incomplete, and lacking in some way)
* Immature or incomplete db interface libraries
* No db migrations (would love to see a simple sql-only solution here)
* Package management is simple and elegant but without explicit versioning, so forking is the end result to ensure stability
* No process pool management for running Go behind something like Apache or nginx.
This goagain tool looks interesting for the last point though:
https://github.com/rcrowley/goagain
and the routing I found pretty straightforward with something like github.com/gorilla/mux so there are solutions, they're just not always as fully baked or as mature as you'd find in other ecosystems. One place Go shines though is the great built in web server which really simplifies getting up and running and testing, and which I see they've built on here.
Given how easy and pleasurable it is to work with, and the focus on practicality rather than language features, I'm quite confident that Go will reach it's stated aim of becoming a popular server-side language quite soon. For those new to the philosophy behind the language, I found this informative - http://talks.golang.org/2012/splash.article