Posted this on the blog as well, but some here might find it useful.
Instead of duplicating code to implement common/middleware functionality, I like to just pass around functions. I usually just have one makeStandardHandler type function that covers most cases. For the special cases, I can easily combine middleware in any order for the desired result.
> Instead of duplicating code to implement common/middleware functionality, I like to just pass around functions.
The problem there is that it doesn't allow you to either:
• Apply the middleware to routers or sub-routers;
• You end up with http.HandleFunc("/", loggingMiddleware(recoveryMiddleware(sessionMiddleware(myHandler)))) - which is no fun, repetitive and prone to errors
• There's no request context - your handlers have no way to communicate between themselves (i.e. passing a CSRF token from middleware to the handler rendering the template or writing to the response header)
It does work for basic applications, but it just doesn't scale beyond more than a (small) handful of routes. I wrote a little function[1] that helps with avoiding the gratuitous function nesting, but you'll need to BYO request context in many cases. This often ends up being map[string]interface{} (so you may want getters/setters to wrap types coming in and out), as the alternative is to rely on structs + methods (ala https://github.com/gocraft/web) which can be a little unwieldy. Horses for courses, as they say!
Goji (https://goji.io/) is a really nice middle ground between bare net/http (and writing your own boilerplate over and over) without any dependency injection, fairly sane middleware chaining and no global request context map (so no need for locks!).
I've been playing around a fair bit with Goji and gocraft/web over the last week and enjoy both their approaches, and may end up porting over a gorilla/* + net/http project to get some sanity out of my middleware and request context.
It's a real shame that TL;DR has now become the norm.
I can't find the link right now but there was an article somewhere stating that the TL;DR is a redundant construct because if you want to summarize your article you should do it at the top, in the first paragraph.
That first paragraph is called an "Introduction".
Funny enough the author of the blog post wrote a good introduction to his article, but chose to tack a TL;DR to it.
Just to throw my 2 cents in, I've had a blast using Martini for the past few weeks working on Hacker News Anchor[0]. It's a pretty minimal product, true, but using Martini I barely noticed the framework. I may be biased since I tend to heavily prefer Sinatra-style frameworks, but Martini didn't disappoint.
Surprised not to see Tigertonic in this, which has a large following on GitHub and puts more emphasis on monitoring and operations: https://github.com/rcrowley/go-tigertonic
Tigertonic has a really nice API, but is also fairly JSON orientated. I think when many people say "web frameworks" they implicitly mean "serving at least some HTML", even if we all know the web != just HTML.
If what you need is something minimal, then why not to use a JSON API server and have your front-end app use your API.
I compose APIs from Go and NodeJS servers and get really good productivity & performance benefits. And this is what I use; http://github.com/azer/atlas
That's pretty much what I'm doing. The clients so far are javascript making calls that return json. I find it better to handle the UI display on the client rather than using a template package on the server.
It's resulted in a very straight forward go server implementation. The only package I use outside of the base go libraries is beego's session package.
I'd disagree having a backend written in Go and a front-end written in another language is being minimal. Plus I think the majority of people attracted to Go are fundamentally opposed to Javascript.
For the routing side of things, HttpRouter[0] seems like a nice alternative when performance matters to you. But as the author of this post referred to, sticking with the basics is a nice way to go. The nice thing about a lot of these frameworks, is that you can use bits and pieces of them if you'd like, you aren't required to use all the functionality.
So the decision is, even though there are many good Go frameworks for web development (they forgot some, like beego), to invent their own micro-framework? I think basically they just re-invented a small aspect of some of the frameworks they dismissed.
I have made similar decisions before, and it is more fun and certainly gives a sense of freedom and less to learn, but I think that is generally an incorrect decision and in this case it is particularly obvious. There are many existing Go web frameworks, and I am sure that some existing Go web frameworks are good enough for Square.
This sort of thing is why I prefer to work alone. Because those types of incorrect decisions are very common. There is always more than one way to do something. It is just surprising to me how often engineers carefully select the ways that are inferior (more work, and/or less sophisticated). Of course, as I said, sometimes I make wrong decisions, but in those cases I can always change my mind. An organization or another individual is harder to change though, and bad design decisions can become solidified.
I don't know why the authors of the article dislike dependency injection, but I think it comes down to how you view your code. Dependency injection sort of hides what goes on in your code and makes it hard to follow.
Developers who are used Rails, Django, Laravel and other large frameworks might not really care, and they might not need to. You develop for and with the framework you picked an understand and accept that stuff works a certain way, because that's what the framework does. If however you're a Go developer and want to do web development Gorilla will seem like a better approach than Martini og Revel, because it's just add the bits you're missing. Picking a larger framework and you get locked in doing stuff their way, and the dependency injection and "magic" makes it hard or impossible to escape the framework, should you want to.
For me, I like to be able to look a just my own code and reason about what it does, without ending in "here I pass a bunch of stuff of the framework and hope it does the right thing". Normally I know what I want and if the framework has these magical bits they more often than not get in the way... I'm looking at you stupid Django Rest Framework.
[+] [-] abtinf|12 years ago|reply
Instead of duplicating code to implement common/middleware functionality, I like to just pass around functions. I usually just have one makeStandardHandler type function that covers most cases. For the special cases, I can easily combine middleware in any order for the desired result.
[+] [-] elithrar|12 years ago|reply
The problem there is that it doesn't allow you to either:
• Apply the middleware to routers or sub-routers;
• You end up with http.HandleFunc("/", loggingMiddleware(recoveryMiddleware(sessionMiddleware(myHandler)))) - which is no fun, repetitive and prone to errors
• There's no request context - your handlers have no way to communicate between themselves (i.e. passing a CSRF token from middleware to the handler rendering the template or writing to the response header)
It does work for basic applications, but it just doesn't scale beyond more than a (small) handful of routes. I wrote a little function[1] that helps with avoiding the gratuitous function nesting, but you'll need to BYO request context in many cases. This often ends up being map[string]interface{} (so you may want getters/setters to wrap types coming in and out), as the alternative is to rely on structs + methods (ala https://github.com/gocraft/web) which can be a little unwieldy. Horses for courses, as they say!
[1]: https://gist.github.com/elithrar/21cb76b8e29398722532
[+] [-] digitaltoad|12 years ago|reply
[+] [-] elithrar|12 years ago|reply
I've been playing around a fair bit with Goji and gocraft/web over the last week and enjoy both their approaches, and may end up porting over a gorilla/* + net/http project to get some sanity out of my middleware and request context.
[+] [-] Yuioup|12 years ago|reply
I can't find the link right now but there was an article somewhere stating that the TL;DR is a redundant construct because if you want to summarize your article you should do it at the top, in the first paragraph.
That first paragraph is called an "Introduction".
Funny enough the author of the blog post wrote a good introduction to his article, but chose to tack a TL;DR to it.
[+] [-] andreif|12 years ago|reply
[+] [-] notduncansmith|12 years ago|reply
[0] http://hidden-bastion-5609.herokuapp.com/
[+] [-] jacquesm|12 years ago|reply
(negroni is another coctail...).
[+] [-] ericflo|12 years ago|reply
[+] [-] elithrar|12 years ago|reply
[+] [-] emocakes|12 years ago|reply
[+] [-] oakaz|12 years ago|reply
I compose APIs from Go and NodeJS servers and get really good productivity & performance benefits. And this is what I use; http://github.com/azer/atlas
[+] [-] forgotAgain|12 years ago|reply
It's resulted in a very straight forward go server implementation. The only package I use outside of the base go libraries is beego's session package.
[+] [-] cheez|12 years ago|reply
That might be OK for some instances but many times, one needs to be able to serve a browser directly.
Your idea of a API is still a good one, you might just change the level at which you create this "backend" API.
[+] [-] phea|12 years ago|reply
[+] [-] chc|12 years ago|reply
[+] [-] thinkpad20|12 years ago|reply
[+] [-] optymizer|12 years ago|reply
[+] [-] kyrra|12 years ago|reply
[0] https://github.com/julienschmidt/httprouter
[+] [-] ilaksh|12 years ago|reply
I have made similar decisions before, and it is more fun and certainly gives a sense of freedom and less to learn, but I think that is generally an incorrect decision and in this case it is particularly obvious. There are many existing Go web frameworks, and I am sure that some existing Go web frameworks are good enough for Square.
This sort of thing is why I prefer to work alone. Because those types of incorrect decisions are very common. There is always more than one way to do something. It is just surprising to me how often engineers carefully select the ways that are inferior (more work, and/or less sophisticated). Of course, as I said, sometimes I make wrong decisions, but in those cases I can always change my mind. An organization or another individual is harder to change though, and bad design decisions can become solidified.
[+] [-] burke|12 years ago|reply
[+] [-] zimbatm|12 years ago|reply
[+] [-] mixologic|12 years ago|reply
What do they have against dependency injection? Why do they think its 'magic' ?
[+] [-] mrweasel|12 years ago|reply
Developers who are used Rails, Django, Laravel and other large frameworks might not really care, and they might not need to. You develop for and with the framework you picked an understand and accept that stuff works a certain way, because that's what the framework does. If however you're a Go developer and want to do web development Gorilla will seem like a better approach than Martini og Revel, because it's just add the bits you're missing. Picking a larger framework and you get locked in doing stuff their way, and the dependency injection and "magic" makes it hard or impossible to escape the framework, should you want to.
For me, I like to be able to look a just my own code and reason about what it does, without ending in "here I pass a bunch of stuff of the framework and hope it does the right thing". Normally I know what I want and if the framework has these magical bits they more often than not get in the way... I'm looking at you stupid Django Rest Framework.
[+] [-] benatkin|12 years ago|reply
[+] [-] unknown|12 years ago|reply
[deleted]
[+] [-] unknown|12 years ago|reply
[deleted]