The lack of example code in the security section should be a worry to all.
It isn't hard to prevent SQL injection if you use parameterized SQL statement rather than using string concat, and whilst examples of this are trivial they shouldn't be skipped.
In the XSS section it mentions filtering and checking inputs, but does not mention sanitization and does not give any examples. In the aversion to use any non-standard package it also does not mention https://github.com/microcosm-cc/bluemonday or anything similar (I am the author of bluemonday - a HTML sanitizer in the same vein as the OWASP Java HTML Sanitizer).
There is some sample code, in the Filtering section, but this only demonstrates the use of a fixed range of inputs in determining a filter, and then a regexp to check the input matches a format.
Beyond the security, where the theory is at least known even if a demonstration on how to implement it is lacking... the entire guide misses out on demonstrating templates to their fullest, and specifically using a map of functions to provide the equivalent of Django's TemplateTags.
In fact, the missing link for most Go developers who are building web apps, and for those coming from outside Go, are template tags. Most Go devs I know (who seem more systems focused) don't even realise that this stuff exists: https://golang.org/src/text/template/examplefunc_test.go
Using string-based templating in general is a really bad practice, as it leaves the door wide open for XSS, SQL injection, etc. Sanitizing inputs, while often cited as the proper thing to do, isn't addressing the root problem: that we're using templating systems that don't use proper data types and thus can't automatically DTRT when rendering.
Interestingly, html/template does actually handle some stuff like this. Pass html in a string as a field into html/template, and it'll escape all the html automatically. In order to get the html to actually render, you have to pass it in as a `template.HTML`. There are variants of the `HTML` type for different places, including html attributes and javascript code.
Templates are definitely the most lacking aspect of Go in my experience. Templating exists and works but in my usage at least has felt very clunky.
It could be that I just haven't come across any resources that do a good job of explaining their strengths. I see so many comments from people who seem genuinely excited about Go's built in templates that my assumption is always that I'm doing something very wrong.
Well, that perhaps isn't fair... fairer would be to say that there isn't an authoritative set of examples showing how people can achieve things similar to something like Django templating or Rails templating. It is actually fairly effortless to nest templates, extend them with custom functions, and all of the things one would need to do.
That isn't too bad at all, but the snippets and examples are so small that it's hard to really see what the value is and how it all glues together to create nice readable templates.
Anyhow, the key place to look at template tags would be:
Those three things, viewed as one, should allow any Go dev to extend templates to do whatever you want them to do.
Hugo have been very "functional" in their choice of template tags, but there's huge scope for new packages to deliver more aesthetic tags, or tags for localization, to humanise time and plurals, basically to provide a core resource of tags similar to https://docs.djangoproject.com/en/1.9/ref/templates/builtins... so that each dev doesn't implement their own.
I agree it is much nicer to have a layout template which includes your view templates (ala rails and many other systems), rather than including header/footer in each template. Yes you can do this, I handle this by having a layout template which includes a key for content, and rendering each view into its own template (without header/footer) which then goes into the content key of the layout. This is pretty straightforward to do though apparently not a usage they anticipated.
They've recently introduced the concept of blocks too which is an attempt to solve this though it looked pretty clunky to me last time I looked. See this discussion from author of hugo asking how to use it (always a bad sign!):
Also, it talks about salting, but it's NOT a salt, or at least it's a horrible salt. A true salt should not be reused at all, it should be unique to each password hash. Generally you see something like '<storedhash> = salt + hash(salt + password)' so you can recover the salt automatically.
A global salt for all your stores passwords at least prevents generic rainbow tables from being used against a stolen password database. Salts per password prevents the same password from having the same hash result in your database.
There's really no reason to ever use a global salt, it's not like it's hard to generate a random one for each user. If you're already putting in the effort to use salts, might as well go all the way instead of saying "well it's better than nothing ¯\_(ツ)_/¯" (I'm not directing this at you in particular, just at anyone who intentionally takes half-measures when it comes to security)
Last pass used both: a global salt and a per-password salt. The idea was that the global salt isn't stored in the database so if the attacker doesn't have access to the application server, they cant find what that salt is at all.
Not sure where the line is drawn, but it's definitely inclusive of the more secure option when it can be implemented in <10 LoCs of code simple enough 99% of the professional dev community can write it.
Even worse, using an actual password hashing lib, i.e. golang.org/x/crypto/bcrypt, is usually going to take care of it for you. 2 lines of code, 1 to make the hash when the password changes, 1 to check if the password matches the hash, and you are done!(as the library already generates and includes random salts in the hash for you)
The security section, specifically on encryption, is dangerously misleading. It really needs an overhaul.
To start with - DES is broken, you cannot use it. It also totally blasts over important details like -not re-using the same IV- for AES. Really, it should be updated to use a better higher-level general purpose encrypt/decrypt library, which handles all the happy primitives in a way that you can't shoot yourself in the foot.
As for 'base64' being a good encryption algorithm? All the nopes & I can't evens.
The password stuff is pretty bad too. IDK, needs a re-write.
I disagree—the guide is Beego centric, and Beego does some peculiar things[1]. I feel like I'm ragging on someone's hard work here, but I take web security seriously, and I want to make sure frameworks (which are attractive to newbies) are doing sane things.
Really impressed by your patience and the thoroughness of your answers. Although the outcome is disappointing, you did an excellent job communicating not only what should change, but why and with references.
What's the hip solution for keeping a session-scoped, server-side data store? Recently dove into that for Hapi.js, found out that many people encrypt these and stuff them into cookies, ASP style - with all the same patterns of fail.
Also - the developers claim this is a feature (after all, you don't have to worry about load balancing or distributing your state information on the backend. sigh )
gorilla/sessions (for which I became a maintainer last year) has Redis/BoltDB/Postgres/etc. backends: the cookie stores an opaque ID, and all the data is in the server side store (allowing you forced expiration, etc).
Cookies are also supported, and everything is HMAC'ed at a minimum. You can optionally encrypt, but since you should only be transmitting over TLS, doing so can be redundant.
I wonder how long it'll take before we get usable TLS-based sessions again. AFIK the only way to do that now, is via client certificates, and the UI for that (on the browser end) is still so bad it's practically unusable.
I think it's perfectly valid (in an imperfect world) to use a (secure) cookie as a session token a la kerberos over http(s) -- and with authenticated encryption wrapped around the cookie I don't see much problem "storing" some session state in there (opaque to the user agent/user).
Still somewhat unclear what that actually buys you in terms of scalability/simplicity -- all communication should be over TLS anyway, which means there will be a session context between the user agent and the TLS terminating server/load balancer (or if you have none, between the ua and the web server).
I suppose it allows you to separate the user session from the TLS session -- which might be "fine" from a system level view, but I don't think it's really a security "win".
Anyway, I'm happy people like you take the time to maintain stuff like gorilla/sessions -- it's part of what makes modern languages/frameworks so easy to use to get stuff done (and get them done in a sane way...).
Very cool, I'll have to take a look at the gorilla/sessions work.
As for the cookie mode, I'd make encrypt + HMAC [along with the nonce + timestamping & expire goodies] the default. There are a lot of reasons you shouldn't show a user what's in their 'internal state' - and users of your library may not understand that.
If you're HMAC'n you're already using a secret key, so - no great shakes to default to the encrypted mode.
I'm so conflicted by Go. If I want to write a website quickly, I'd use Python. If I were concerned about performance, I have Java. I write my systems stuff in C++ (Rust now). Is there a compelling reason for me to even learn Go? Is it better than Java in some measurable way? Should I take the time to learn it? Honestly curious.
I wrote The Little Go book [free], my first Go blog post was in 2011, and a few of my Go libraries are used by people other than just me.
But Go's not my goto language. I'm a staunch believer in the productivity of dynamic languages. In my opinion, Go's less than stellar type system and weak reflection capabilities exasperate this gap, even moreso for most websites / apis (which deal with impedance mismatch at two boundaries).
But, to answer your question. Consider first that Go's very simple to pick up. So the investment is small. Second, where I differ from you is on your second point: Java. I dislike it. It's complicated and verbose and gets in my way. Rust and Go are both proof that we know how to build better languages now. So, when I need to share memory across multiple cores and performance is a concern, I switch to Go because it's fast and simple.
Rust and Go are so completely different that I don't see how they're similar. OTOH, I write most of my code in Java, and a little bit in Go, and can hardly tell the difference between the two (their goals, design philosophy and levels of abstraction are nearly identical). I use Go for small command-line apps, where it shines, and Java for more serious server-side software, where I can't do without its unparalleled monitoring and tooling and more, uhm, grownup approach towards dependencies and project management (unless you work like Google). I know some people don't like Java, but I'm puzzled when the same people like Go (I can understand how you can like neither, or, like me, both). I agree that the onboarding experience for Go is better and more familiar to people coming over from Python (perhaps to the point that to people coming from Python, Java and Go appear very different), but if you're used to Java, Go feels like Java-lite. You use it when you need something more quick-and-dirty (or for command-line apps; Go is a much better fit than Java for those), but you stick with the "full" version for the serious stuff.
The only reason I will stick with Java is because business applications are in Java and there is no reason to use any other language.
> their goals, design philosophy and levels of abstraction are nearly identical
I think it could not be more different. Java APIs (including libs by Sun/IBM/Oracle) is a manifestation of more is less which is exactly opposite of Go.
> Java for more serious server-side software
The seriousness part is only because serious folks (the one who fund projects) prefer Java. I too think this is very important if not the most important part.
> unparalleled monitoring and tooling and more,
I too would need lot of monitoring and tooling if Oracle/OpenJDK GC keeps crapping out for just 10-20GB heaps which is currently the case for us.
> Java APIs (including libs by Sun/IBM/Oracle) is a manifestation of more is less which is exactly opposite of Go.
For example?
> The seriousness part is only because serious folks (the one who fund projects) prefer Java.
I disagree. There are plenty of design decisions in Go that make it less optimal for very large projects (e.g. dependencies, error handling, generics), but most of all lack of hackability. Go is one of the least hackable languages I've ever encountered, i.e. the only escape-hatch you have when you realize, 5 years into the project, that you need to circumvent some runtime semantics are either source-code instrumentation or hacking on the runtime itself.
> Oracle/OpenJDK GC keeps crapping out for just 10-20GB heaps which is currently the case for us.
There is no way Go's GC wouldn't crap out on you sooner (except maybe in the circumstances that are now addressed as part of Valhalla).
Having said that, I think Go is great, and is a natural fit for anyone who likes the Java philosophy (which is also the Go philosophy)[1]. Some design decisions and some implementation circumstances just make it less suitable for really big stuff.
[1]: Namely, reading comes before writing, no too-clever tricks, and no cutting-edge PL ideas; a "blue collar" language, as Gosling referred to it.
> I use Go for small command-line apps, where it shines
I'm curious. Is there empirical evidence proving that Go is better than Java for small command-line apps, or did you just use your personal judgement to reach this conclusion?
> Is there empirical evidence proving that Go is better than Java for small command-line apps
Sure. It doesn't require warmup, it's a little easier to deploy as a standalone executable, and performance is comparable to compiled Java code in programs of this size (you can easily confirm all three claims); those are pretty much the relevant requirements from many command line programs. It's not a property of the language but of its implementation choices (AOT compilation, statically linked runtime), which match the requirements of those kinds of applications better.
I actually think Go's simplicity is a weakness because it will only get you so far. Take web development for example, all the tutorials show json.Unmarshall, but this one stackoverflow post says I should use json.Decode. Oh shoot now I'm having all sorts of problems because I don't really understand json.Decode.
Furthermore I think most people reach for Golang in the beginning because they want performance. However I've found it incredibly easy to write unperformant Go.
I think Golang will ultimately be a very important stepping stone in language development in terms of concurrency, type systems, standard libraries, deployability, and many other categories. I think a lot of important programs will be written in it. And ultimately I look forward to how future languages draw from it.
> I think Golang will ultimately be a very important stepping stone in language development in terms of concurrency, type systems
"stepping stone" usually implies progress and Golang was a regression on both fronts, and while its deployment story is ok that's in no small part because it just opts to statically link everything by default, which the field has been going back and forth on basically since the beginning.
"Take web development for example, all the tutorials show json.Unmarshall, but this one stackoverflow post says I should use json.Decode."
Plenty of JSON libraries in plenty of languages have both a function to decode JSON and an object that allows you to decode JSON with some settings. That's not really a Go-specific issue.
Lack of generics (stick, meet dead horse) is at the forefront.
Lack of very basic functions (map, filter, reduce) against slices.
map[string]interface{} is pain to work with (one of the moderately popular libraries I mentioned helps: https://github.com/karlseguin/typed)
Lack of immutability.
I don't want to get into errors vs exceptions, but I've never heard a pro-errors argument that wasn't hand waving. I think the decision makes sense given Go's genesis (system programming), but given how Go's actually being used, it's a step backwards.
What I struggle to understand is: If that functionality is considered useful or even impeding the development process for those developing in Go, why has nobody forked the language to add them?
Many of the points you mention are fairly low hanging fruit for inclusion if you are willing to accept the tradeoffs that official Go maintainers are not willing to.
I think the trouble there is just that many other modern languages haven't taken the extreme stance on typing that Go has. It's much easier to learn say, Rust or Scala, than it is to fork and maintain a branch of Go, and there's certainly nothing so special or attractive about Go to tip the balance in the latter's favor.
The issue with that is that anyone invested in Rust or Scala have no reason to want a better type system in Go. Fixing Go is as important to them as fixing COBOL, and I don't see HN full of threads on what needs to change in COBOL.
What we have here is people who are already heavily invested in Go to the point where its type system is a real problem for them, yet they do not want to fix the problems, even in light of the relative ease at which at least some the problems can be solved (again, if you are willing to accept the tradeoffs).
It is rather surprising if not outright shocking that experienced developer get heavily invested in a language when other mature/ better alternatives are there.
> What I struggle to understand is: If that functionality is considered useful or even impeding the development process for those developing in Go, why has nobody forked the language to add them?
The group of people who are able to fork, change and maintain their own Go variant are usually not the people who would ever consider using Go in the first place.
Have a look how long it took PHP to get an AST (instead of the broken mess of reading&executing). Those who are able aren't those who would ever deal with PHP.
I've sometimes wondered a bit about this myself. But consider what you'd end up with if you wanted to keep most of go's benefits, but add on such bits. And consider that you could just use Ada, Nim or OCaml. Or maybe Rust (I really like Rust, I'm not sure how much overlap there is in any subjective list of "Go the good parts" and "Rust the good parts" though).
I think some of the best parts of Go is the central model: "go get", "go fmt" along with the standard library - if you fork, the burden falls on the fork keep all that stuff working in a sensible way too.
- OCaml is great but parallelism is still limited by its "Global Interpreter Lock" (like Python or Ruby).
- Rust is great but ownership/borrowing is not for everyone and people sometimes prefer relying on a good garbage collector.
- Nim is great but it's a "small" project compared to Go and most people prefer relying on a large ecosystem like the one offered by Go.
- Ada was a major milestone in the history of programming languages, but it's considered by most as an "old" language, compared to Go/Rust/OCaml/Haskell/Scala/etc.
Thanks. Right, generics is a big one. But isn't Go actually being used for system programming? At least that what I think of when I think of Golang. Maybe the scales have tipped and writing api/microservices is the larger use case now?
I don't know. All I know is this [possibly dated] quote from Rob Pike:
"Although we expected C++ programmers to see Go as an alternative, instead most Go programmers come from languages like Python and Ruby. Very few come from C++"
Maybe Python and Ruby programmers are adopting Go to do system programming, but that isn't my impression.
While this may not be a popular opinion, I find Go's type system to mainly benefit the compiler in optimization and be of minimal benefit to the safety or correctness of the program.
Any non-trivial Go project will have interface{} sprinkled all over [1], which effectively gives you the guarantees of a dynamic language with the syntactic overhead of a typed language. Truly the worst of both worlds. While I realize it's a tired argument, Go desperately needs generics in some form or another. It would remove most criticism from the language while substantially improving the correctness of programs.
Go has concurrency features that the other languages you mentioned don't have. The select construct is a very nice language feature and allows a surprising amount of power.
Go's compiler is very fast, which saves a lot of time in aggregate.
Go exhibits good design in many areas, including the core language, the compiler toolchain, and the standard library. You can write a complete server-side web application using only the standard library, and it won't be terrible.
Go is generally easier to learn than C++ or Java, and requires fewer concepts and fewer steps to produce a working program. A person who has written programs in Java or C can probably learn Go in about a day. Go's spec can be read in one or two sittings. The way to write "good" code in Go is usually obvious.
I've spoken to some detractors of Go and can understand where they're coming from. Erlang and Elixir users tend to not find Go's concurrency features compelling. Functional programmers will not find that Go provides much in the way of expressive power. Java programmers have expressed concerns about the Go garbage collector, although I think a lot of those concerns are now at rest.
For those that enjoy the set of tradeoffs that Go makes, it's a nice way to engineer software.
A person who has written programs in Java or C can probably learn Go in about a day.
I really wish people would stop saying this. There is more to Go than just the syntax. I'm a Go dev on a team of php and Java devs, and just the opinionated philosophy of Go is hard to get across to them. They bypass the Go interview only to create the mess interviews intend to prevent. They are junior/mid devs again, except that because everyone keeps saying Go can be learnt in a day they think they've already mastered it. Go is easy to get started, but there is somewhat more than a day's worth of learning, I see this daily.
I don't think a day is reasonable either, but 2 weeks is. You get to a point where you just sort of run out of concepts to learn... it's a weird feeling at first, to be honest with you.
I don't agree. After two weeks people are still unaware of lint, vet, -race, haven't even begun exploring how error values can be managed, ... Interviewees with 6 months of Go are regularly rejected - how is that possible if it's so quick and easy to learn?
If they have the fundamentals down and are creating a "mess" that sounds like a failure of the existing project leads. A little code review and direction goes a long way.. It doesn't take long to run lint, vet, -race by someone. Establishing best practices and engineering principles for the project/team can help tremendously with on-boarding too.
I did a simple port of Python program to go a while back.
The python program is web backend for JQuery+html Single page web app for front end. It built its own database in the backend on top of SQlite.
It is not that hard to part a few features over, ~1-2 weeks including learning time. There are lot of examples on how to do most of typical web programs with REST/AJAX for golang.
The REST/JSON in golang is a lot of verbose than python. Go need to define all JSON fields via marshalling which is none-trivial amount of boiler place template code code. It does very strict type check on all incoming JSON structures. I have full functional regression test coverage from my frontend code to the all the python REST APIs /JSON structures. The more stricter type check in REST/JSON in the Golang requires a lot of work while provide little value for me.
The error handling the go compare to pyhon is an "acquire taste". (I have to acquire that taste yet.)
I was used to the code style of raise/catch exceptions. Python provides extremely good stack trace feedbacks on those error cases. Recover from exceptions in python are trivial.
My python code needs to build/handle 10-25 GBytes database. I spent non-trivial amount of time in the low level API of python/C code to optimized/debug memory related issue at that scale. All the issues in python backend were worked out already. The backend python all used very little memory in building and using 20+GB of DB.
For Golang, I can not get pass that barrier. Building a DB of about 2-4GB cause the golang app to completely slow down. (Most likely GC kick in, memory hogs on system level.) I spent a few more weeks on golang and can't get enough info to fixed that issue and put that porting from python->Golang project on the shelf. In python I can force a GC operations in certain point of my app to see the memory usage clearly drop down. I can't find a way to do that in golang. There were documented API in golang that supposes to do that. But it just doesn't works for me.
Java programmers also know a thing or two about java.util.concurrent, parallel streams, futures and Quasar.
The only thing Go concurrency has over them is that it is easier to start with, but it isn't easier to use any other pattern, because Go doesn't allow library code to be first class in the type system.
Well, the thing about Go concurrency is that it has been with the language since the beginning. How much library code is compatible with concurrent or streams or futures or Quasar? If you choose one over the others, are you limiting yourself to only libraries compatible with others that made the same choice as you? How much of the standard library is compatible with each of those?
The same thing goes for value types. In Go, everything uses value types. The standard library is littered with them. Will it be the same for Java? It seems unlikely, given that they have to keep backwards compatibility.
Granted, this is all from the point of view of an outsider who only dabbled in Java, so I may be way off base.
The java.util.concurrent was introduced with Java 1.5, so 2004.
And there were alternatives available before for Java 1.4.
Which means most Java libraries had lots of time to adapt to it.
Also threads and concurrent queues are there since the early days.
Java already has a kind of pseudo-value types, but it is JVM specific. Some JIT and AOT compilers do convert final classes with only accessors (think Point) to value types.
But yeah, it is a JDK vendor specific optimization that one cannot control.
Likewise you cannot control if a value type in Go gets stack or heap allocated, if I remember correctly. Hence why the compiler options to debug how the compiler decided to do it.
Java value types will take time to get adopted surely, but in many type of applications it doesn't really matter that much.
The use cases driving value type's adoption are related to HPC and HPT, many of which are trying to move away from C++ into Java, but still find themselves have to make use of com.sun.unsafe for that last mile.
At least as presented by IBM and Azul on their talks about their approaches to value types in Java.
Assuming a JIT/AOT compiler that doesn't do escape analysis, which varies across JVM vendors.
Also Go's advantage in using value types will vanish when Java finally gets to have them, although we still need to wait for Java 10 for them, while Go is available now. So Go does have a few more years to gain developer mindshare.
Still Java isn't the only game in town, and there are other alternatives with GC, value types, more expressive type systems and battle tested concurrency frameworks.
> It would remove most criticism from the language while substantially improving the correctness of programs.
How the mighty have fallen. A language with more than decade over Go and billions in investment by top tech companies and literal monopoly over enterprise usage need to even think of user share of a marginal language.
Except you are off base giving too much value to Go.
What is driving value types in Java is HPC and HPT companies in places like stock exchanges and biology research that want to move away from C++ into JVM land, but still need to keep some C++ around due to value types or make use of com.sun.unsafe tricks.
Go uses a lot less memory than Java, according to most comparisons. There's a lot of work going on in the cloud space with Go applications (docker, kubernetes, etc), so there's a lot of new libraries for networked webservers getting written.
But mostly, you may find you just enjoy writing Go more than Java. It writes a lot like python... I switched from mainly writing C# to almost exclusively writing Go, and whoo boy, I'm not going back. No more huge class hierarchies, no more "everything has to be in a class"... no more "anything I call may throw and jump me out of my function in the middle and I have no idea if it will or not".
There's just a lot of niceties of writing Go that don't exist in Java. Sure, there's a ton you can do in Java that you can't do in Go, but once you stop focusing on what Go can't do, you realize, it still can do pretty much whatever you want.
Yes, but the rewrite would have happened ever sooner if the original code had been written in Java instead of Go. The Dropbox case is really very specific and very low-level.
And nearly anything you can call in any language could theoretically exit(3). The difference is that exceptions are a normal control structure in C#, Java, or even C++, while the use of panic should be exceptional. It's not considered the regular way to report an error.
Of course, if you have checked exceptions (which are for some unfathomable reason considered bad nowadays), nothing just throws an exception. Moreover, you don't know for sure whether a Go library correctly handles errors, because it's so easy to ignore them.
The problem with checked exceptions is that your code trends towards having every method marked as 'throws Exception' (or whatever your application's top level exception is). Any time a low level method changes to throw a new exception, every method that calls it has to update their exception spec... or they need to have their catch clauses updated to catch the additional exception and either deal with it - unlikely - or wrap it and rethrow it as one of their other expected exceptions.... or they're already catching Exception, which is also bad.
At my last job, very few methods in the application ended up throwing a specific list of exceptions, except the most leaf-ward modules. Anything anywhere near the application logic just threw our top level generic exception, because there was too much below them that could throw a variety of exceptions, and there generally was nothing the middle-tier code could do about it if they failed.
It's really not that easy to ignore errors in Go in practice... and you might as well worry that a library correctly handles the result of string.Split() incorrectly. Either one is a bug. Hopefully your tests would find either one, and there are tools to detect errors you didn't handle.
Any time a low level method changes to throw a new exception,
You don't do that in API-stable code, period. If you are working with API-unstable code - that's the point of static typing. The code won't compile because the intention is exactly to signal that something has changed.
If you change the return type of a low-level Go function, you will have to modify its callers as well.
Anything anywhere near the application logic just threw our top level generic exception,
Bad codebase = bad. Sure. I never encountered that problem in the Java codebases I worked on at various employers. (And I'd be quite happy to complain about Java, I don't like it.)
It's really not that easy to ignore errors in Go in practice...
It is. The compiler will not emit a warning when you ignore the return value of a function/method. Here:
fmt.Println("Hello world")
I have just ignored an error. The compiler is happy. There are quite some Go packages in the wild that do not deal with errors when they need to.
As others have said, it is highly discouraged by the community to use panics as control flow. Generally a panic means there's a serious bug somewhere - not just that unexpected stuff happened, but the programmer actively is doing something wrong.
Any library that panics for reasons other than a programmer bug would never be used by the community. I read a lot of Go code and look at a lot of Go libraries, and I've never seen one that said it purposely panics in my 3.5 years of writing Go.
Compared to Java, C#, Python, C++ etc... where declaring your code panics is a perfectly normal and expected way to report errors.
It's a language that when compared to other languages it's the 2nd best at so many features that it gets the title of the most well balanced language.
For the most part, it seems to have gained traction in the Ruby/Python/PHP world as a backend optimization language. IMHO that's where it currently fits best for most people.
I wouldn't personally compare it to Java, having written it for some time. I too am not too fond of writing web apps in Go. It's doable, and you can do things to make it easier, but it can be painful. It took me some time to get in to the groove.
I see it being used for system tools, to some degree, because it requires no runtime at all (static binary). It also seems to be pretty popular for different newer data stores. Again, if it's pure Go it'll run anywhere... so it makes development (and portability) much easier.
I like its concurrency model, to a point. That said, I hope they really improve some things about in Go 2 (like working with channels and goroutines). I'm not sure when that will be.
I use Go for a lot of things, most of which are command line applications. Whether it be interfacing with some sort of REST API, taking actions on the local system, or some sort of network client for devices on my LAN. It works well for quite a few cases.
It seems to fit well with my mental model quite often, so I use it. And it's a simple language, so it was easy to get started with it. At the end of the day, it's a tool like many others. I think it's up to the creator to choose the tool that feels best to them.
> I see it being used for system tools, to some degree, because it requires no runtime at all (static binary).
This is something I haven't seen discussed much recently.
Do people generally think static linking is a good idea for things other than self-contained system-level daemons? (Where that daemon and supporting libraries might be the only thing you deploy to a server/vm/container)?
As I recently read in a (rather poor microbenchmark article) [1]: "The C assembly code I got with the following command is just 40 lines long. (...) The Go assembly code is 161.021 lines long which must be due to the static linking of Go.".
As everyone (should) know(s) any kind of language that lets you write a useful program in a page or two of code, will include a runtime of some sort (or be depressingly machine- and kernel-specific assembly code, and probably slower than anything a modern half-decent compiler produce). But I don't see a lot of discussion on how you make sure all your go daemons get updated with a new TLS/SSL/GZIP/PNG/XML-library when there's new serious bug found.
[1] Just included for reference, I don't really mean to pick on the author, but it's rather standard fare in the "quickly do a microbenchark; prove only that I'm wrong"-vein:
>But I don't see a lot of discussion on how you make sure all your go daemons get updated with a new TLS/SSL/GZIP/PNG/XML-library when there's new serious bug found.
Yeah, I think it may be because it's situation dependent. For me, it always consisted of recompile all binaries and deploy them. And even then, I'm not sure people would enjoy a blog post just telling you to recompile all the things. It's not very sexy, honestly.
In my situation, it wasn't that big of a pain to do so. A lot of these libraries are within stdlib, so a security bug would incur a new release of Go. So an update should be pretty easy.
If's an external library (i.e., one picked up from GitHub for example), it's pretty much the same. Get new source, recompile binary with patched library, ship to all the things.
There are tradeoffs, absolutely. The alternative would be to write something in an interpreted language. That means we need to push a runtime environment up to the node, and that may include managing any libraries that are needed (think Rubygems). Managing these kinds of setups can be a pain, especially if a node has multiple projects with different dependencies. I found that shipping a single binary was often easier for me.
But it goes back to it being an item in the toolbox, depends on what you need and how your systems are built.
Well, i personally really like the Static linking, but that is because of the limitations on our network. To get onto a server, I have to use a VDI session -> Citrix -> SSH Jump host -> ssh jump host -> server.
The servers dont have internet access and to get files onto them i have to do the same story as above (using sftp). So having 1 static binary that i copy over without having to worry about the dependencies is great.
It's not better than any of the languages you described, but it's certainly different. Go was created in order to build large-scale distributed systems (like the largest search engine in the world), and the problems that Go makes easier to solve may not be the ones that you have. Unlike Rust, Go wasn't created to replace an existing language...it was created to replace an existing way of going about doing things. Unlike Python, Go wasn't created to make code easier to read in general, it was created to make incredibly complex code less ugly.
So no, you shouldn't learn Go unless Go solves the problems that you need to solve. That said, as others have mentioned it's a pretty simple language and I found it quite easy to pick up and start writing programs in.
If you (and your team, if applicable) already know that set of languages, then there's no reason for you to learn Go.
Indeed, if you already know Java, the only reason to learn Go would be if you had a burning need to produce self-contained statically linked binaries. For example, at my company, we have a habit of producing command-line clients for our services, and Go is a good choice for that.
Go has been most useful for people who know a dynamic language like Ruby or Python, but who are encountering problems where they need more performance, better concurrency, or stronger static guarantees. Go improves over dynamic languages in those respects, and it's pretty easy to learn, so it's a great addition to their toolbox.
> If you (and your team, if applicable) already know that set of languages, then there's no reason for you to learn Go.
Google is the perfect counter-example to your argument. C++, Java and Python were the 3 main programming languages in use at Google, and despite that, they designed Go and started using it instead of C++/Java/Python in some projects.
Go can be used instead of C++ when you need and can tolerate a garbage collector, and you don't need things like a custom memory allocator.
Go can be used instead of Java when you need a native executable, statically linked (like you wrote), when you need a better control over memory layout (especially to reduce pressure on the garbage collector), and when you need async IO without callbacks/promises/futures.
Well one reason [1] Google made go was because of how many junior engineers they had who couldn't be trusted with java/python/etc. Instead of letting them struggle, they created go as a more simple and easy to use language.
Some people think Java is icky and other people think the JVM brings too much baggage for their comfort.
Warranted or not, it usually fills the space where fast microservices are necessary.
Personally I think Go's closest competitor is Scala.
Coming from Python, Ruby, and TypeScript -- Go is a fair bit more verbose, and Java takes that a step further. So Go is a nice go-between from scripted environments to compiled.
The only thing I hate it the extra symbols. How to they justify using :
val companyName: String = "JetBrains".
Instead of string companyName = "Jetbrains" ?
It's good for when you want to write something quickly and you're also concerned about performance. It's a deliberately simple language, it's designed so the most naive simple choice is often the best choice, and you can learn enough in one day to start developing productively.
I've never tried to make a whole web app with it, but it's great for making microservices.
Should you take the time to learn it? Yes. It is a very small language, so learning will not take long. Go is a nice tradeoff in development time and performance that is only slightly slower to write than Python (for web servers) but comes with good performance out of the box.
At least for the Web, Go will match the conciseness of Python with the performance (almost) of Java. It takes a lot of cajoling to make Python a great backend for the Web.
Since confounding downvotes, a tldr: closer to Python than Java.
Go's JSON marshaling can be heavy if you tie it to a strict struct versus, say, an interface. You can make it light, but yes, sometimes some reflection is necessary to utilize that data.
For most web applications, JSON in or out is of a known schema, so this generally impacts other servers moreso than web applications.
I guess I was trying to call out that, depending on the API you are supporting, it can get hairy. If you are designing it from scratch, when starting the Go project, you can structure your JSON in a way that's easy to work with.
If you're coming in to something that was easy to use in a language like Python, it may not be that easy in Go.
Go is not concise, it is more verbose even than C++. Compare Python's list comprehensions to Go's for loops, or Python's sort() vs implementing Go's Sort interface, or Python's ternary operator vs Go's five-line if-else statement, or `if err != nil...`
My strategy is to write very modular web app in python and when performance needed replace a module with go. Not only at that time specifications are mostly final, but most bugs are also covered. That way I get speed up the development of dynamic language and when needs a raise, use running speed of go language.
> Is there a compelling reason for me to even learn Go? ... Should I take the time to learn it?
One thing to consider is that the language is purposefully small, and you can learn the basics very quickly. Spend a day with it, and you'll get a feel for the language syntax and maybe some exposure to the standard library. You'll have a sense then whether you want to pursue it further.
So if you're curious, the compelling reason is that you can satisfy your curiosity without much effort, and that will ultimately be more satisfying than asking strangers to convince you one way or the other.
There is - Go is a terribly fun language in the domains that it's good at. Like some other fun languages, if you take the time to get into 'the go way' of doing things, you'll get a new perspective on some kinds of programming that'll help you in general.
Go is drastically less bloated than Java. Stupidly fast compilation and running lets you use it almost (but not quite) like you might Python for some things.
A recent example for me: Writing a quick & dirty server that talked to a device that was spouting a stupid binary serial-over-TCP protocol. Goroutines made handling the bidirectional communication trivial, and go being a bit on the low-level side makes it easy to cope with binary protocols without worrying that your chars and bytes and unicode characters are getting all mixed up. You can do all this in Java - but it's so clean in Go.
My current playbook looks something like:
Network servers: Go. Go go go and more go. Things that talk to lots of other things and involve interesting communication are a natural match. I rewrote my pi searcher in Go a year or so ago, for example - http://da-data.blogspot.com/2013/05/improving-pi-searchers-s... - and this year was able to run the thing through Pi day on only a single (larger) AWS instance. Woot. We use it for research, such as writing Paxos derivates. Great stuff.
Go's also pretty amazing for little utilities if you want them to be faster than Python -- particularly if you want the launch time to be faster than Python. Which can be great for utilities you build to use in loops in shell scripts, etc. The fact that they're purely statically linked makes a lot of otherwise hairy cross-platform nastiness just go away.
The fact that it's statically typed and includes great, easy-to-use parsing support for itself also makes it much better for refactoring than Python is. The tools aren't as mature as those for Java, but the language is well-designed to support it (think "go fix" -- which can automatically port forward much old code to newer versions of the language). The tooling for this kind of thing is great for Java, good for C and Go, and absolutely horrible for Python. As a consequence, Go can more roubustly handle being worked on in very large codebases and teams. What would be a slightly scary regexp replace in Python can be a much more syntactically and semantically safe change in Go (at the cost of a little more writing of the replacement code).
Tensorflow (and most things numeric): Python. Because it was pre-decided. :) But, more seriously, Go's lack of generics hurt it here (you can't express matrix/tensor manipulation natively, and saying A * x is about as right as it gets when you're talking math). The ML community has adopted Python to a pretty strong degree, particularly because of NumPy, and so it fits in really well there. I still get grumpy about it -- I've lost count of the number of times I've messed things up that static checking could have caught, requiring quite a long time for tests/running it to finally do so. But I do like Python, to the point of:
Beginners: Python. I pushed hard to switch CMU's intro course for non-majors to it, and succeeded with a lot of help from others. It's awesome seeing what a bunch of motivated, smart first-years can accomplish in Python in one semester. Damn. And they can 'take it with them' -- scientists/engineers and numpy are a pretty good match, for example.
Fast as hell: C++, light on the ++, heavy on the C. A lot of our research code is very low-level. I'm still finding Rust incredibly annoying, but I may just be a slow learner, and it's on my list to take a really serious look at it after I'm back from Google.
(You'll note that nothing that I do involves a UI. I'm a unix & systems person through and through, which helps explain the utter lack of Java, C#, Swift, etc. in my life.)
Tensorflow (and most things numeric): Python. Because it was pre-decided. :)
Tensorflow has a minimalistic, but good-enough C API for running graphs. So, once you've built/trained a graph in Python, you can run it from Go without much trouble.
(Source: did that last week.)
still get grumpy about it -- I've lost count of the number of times I've messed things up that static checking could have caught,
For basic numpy-like functionality Armadillo and Eigen also work fine. I agree, I highly dislike numeric Python for the lack of type checking. Combined with the relatively long compile times of e.g. Theano it's a disaster (yes, I know 'fastrun').
I'm still finding Rust incredibly annoying, but I may just be a slow learner,
I'd encourage you to continue. I am also a beginner, but wrote some small crates. Once you get the hang off it, it combines the strengths of most things out there - C++-like memory control and performance, the terseness of Python/Haskell (though map/fold/etc.), and safety. It's a truly fun language to program in. Unfortunately, the library ecosystem is still rough.
> I'm still finding Rust incredibly annoying, but I may just be a slow learner
You are writing most of your code in Go, so you don't really have practical knowledge of Rust. I recommend you to try start some project (or tool) in Rust, keep patience first month or two and then you'll love Rust. It's how came to Rust, now I'm in the "honeymoon" period with Rust and I love everything I do with it. Before Rust, I started thinking I'm losing joy in programming, by doing stupid and boring things every day.
Completely agreed. I'm mostly getting hung up on the ecosystem issues the previous person alluded to -- I gave up at some point this weekend after fighting with getting the GMP bindings working properly on my mac with libraries installed in /opt/local instead of /usr/lib, for example. (The previous "ugh" was with the built-in bigint package). That's not about the core language, per se, just about the library and tooling maturity. As I said - once I have a bit more time to throw at it, I'll give it a real shot.
It's possible to write non-GUI command-line Swift programs that run on Linux (and certain other platforms). In terms of 'close to the metal', Swift is probably much closer to Rust or C++ than C# or Java, and is at least at the same level as Go.
Is your 'close to the metal' claim based on any concrete experience with Swift? I like Swift as a language but I found its String/unicode support way too slow for the text processing stuff I do on the server side. I also tried using arrays instead, but in my text parsing micro benchmarks Swift is always four times slower than Go, Java, C++ and even two times slower than JavaScript/V8.
I don't really see a reason why this should be the case, so I hope it will improve over time.
But using mandatory reference counting does limit the sort of tasks for which Swift will ultimately be suitable. I wouldn't put it in the same category as C++ and Rust for that reason.
My (highly speculative) guess is that your String issues were due to either/both:
- Swift performance issues involving working with strings, some of which have been ameliorated by later releases;
- 'Hidden' bridging between NSString and String, which can be expensive and might have something to do with some of String's APIs actually being Foundation APIs in disguise.
There is much to be done with regards to Swift performance, though. If you have any sample benchmarks I would be interested in writing/running them myself, just for personal edification.
In terms of 'close to the metal', I freely admit this is a ill-defined term I am using for my own benefit. Swift code doesn't execute on something akin to the JVM or CLR; it still requires a heavier runtime than (e.g.) Rust. It is AOT-compiled to machine code. (But then again, this is possible to some degree for Java as far as I can tell, although it is certainly not the most popular way to run Java code.)
I agree that mandatory RC for classes and boxed types makes Swift impractical for a certain definition of 'systems software' typically written in C++ and occasionally Rust. For a different definition, one that encompasses the garbage-collected Go, Swift is theoretically suitable. The language designer has mentioned that he would personally like to see Swift gain some form of borrowing/lifetimes, although even if that did happen Swift would not get it for years to come.
I tried to avoid bridging as far as possible and I'm working directly with UTF-16 because that's the fastest view by far. I'm using the latest release version of Xcode on a Mac.
The simplest benchmark I used is a function that does the equivalent of
str.split(/\s*,\s*/)
So it splits a string around a separator and removes any whitespace around the items. For a million strings the numbers I get are as follows:
Swift: 3.5 seconds
Java: 0.31 seconds (after warmup)
So that makes Java more than 10 times as fast as Swift.
Here's the source code. I would be more than happy if you could tell me that I'm doing something horribly wrong (which I frequently do):
import Foundation
let N = 1000000
func generateTestData() -> [String] {
var a = [String]()
for _ in 0..<N {
a.append(",,abc, 123 ,x, , more more more,\u{A0}and yet more, ")
}
return a
}
func splitAndTrim(s: String, sep: UInt16) -> [String] {
var result = [String]()
result.reserveCapacity(10)
let space = NSCharacterSet.whitespaceAndNewlineCharacterSet()
let cs = s.utf16
let eos = cs.endIndex
var begin = eos
var end = eos
for i in cs.startIndex..<eos {
let c = cs[i]
if c == sep {
result.append(begin == eos ? "" : String(cs[begin..<end.successor()]))
begin = eos
end = eos
} else if !space.characterIsMember(c) {
if begin == eos {
begin = i
}
end = i
}
}
result.append(begin == eos ? "" : String(cs[begin..<end.successor()]))
return result
}
func doSplits(data: [String]) -> Int {
var count = 0
let sep = ",".utf16.first!
for s in data {
let parts = splitAndTrim(s, sep: sep)
count += parts.count
}
return count
}
let data = generateTestData()
let start = NSDate()
let sum = doSplits(data)
print("elapsed: \(NSDate().timeIntervalSinceDate(start))")
print("sum: \(sum)")
And here's the Java code:
import java.util.List;
import java.util.ArrayList;
public class ParseTest {
static int N = 1000000;
public static void main(String[] args) {
List<String> data = generateTestData();
for (int i = 0; i < 3; ++i) {
long start = System.currentTimeMillis();
int sum = doSplits(data);
System.out.println("elapsed: " +
((System.currentTimeMillis() - start) / 1000.0 + " seconds"));
System.out.println("sum: " + sum);
}
}
static int doSplits(List<String> a) {
int count = 0;
for (String s : a) {
List<String> parts = splitAndTrim(s, ',');
count += parts.size();
}
return count;
}
static List<String> splitAndTrim(String s, char sep) {
List<String> result = new ArrayList<>(10);
int eos = s.length();
int begin = eos;
int end = eos;
for (int i = 0; i != eos; ++i) {
char c = s.charAt(i);
if (c == sep) {
result.add(begin == eos ? "" : s.substring(begin, end + 1));
begin = eos;
end = eos;
} else if (!Character.isSpaceChar(c)) {
if (begin == eos) {
begin = i;
}
end = i;
}
}
result.add(begin == eos ? "" : s.substring(begin, end + 1));
return result;
}
static List<String> generateTestData() {
List<String> a = new ArrayList<>();
for (int i = 0; i < N; i++) {
a.add(",,abc, 123 ,x, , more more more,\u00A0and yet more, ");
}
return a;
}
}
Can this headless Swift be compiled to a simple, self-contained, statically-linked, no-runtime-required binary like Go? (A real question, not some sort of advocacy.)
There used to exist GCJ, but its development died when the main developers joined OpenJDK development or moved elsewhere, back in 2009.
There is still the RoboVM version before it got acquired by Xamarin.
There are also Avian and JikesRVM, but it depends a bit what features you are using.
The problem with Java non-comercial AOT compilers is that the majority of the Java shops that really care about AOT compilation don't mind to pay for it, so there isn't a real effort to invest on a free AOT compiler.
The lack of community support for RoboVM was a good example of it.
Even the upcoming AOT compiler in the official JDK will be a commercial feature, at least it was announced as such.
I actually find web applications a fairly weak use case for Go, it's never incredibly pleasant to do. Network services in general are very compelling, mainly because of the strong standard library.
I'm totally ok with building services and cli tools using Go but it's not gonna work for web apps - situation is dire and that's ideological position - i.e. don't expect changes there :/
Basically DIY everything outside standard library ( e.g. section 9.1 building CSRF)
Personally switched to http://www.phoenixframework.org/ for json apis/web apps
I'd say go is just slightly harder to write than python and as fast as (or faster?) than Java. It takes a lot of less memory than Java and Python for sure. Easier to read than both.
Over the previous few weeks, I've seen multiple projects including one internal project drop Go. There was the widely publicized story [1] where Dropbox was switching from Go to Rust. More recently one of our backend engineers who built a prototype in Go told us that they pulled all of the GoLang code out in favor of C++/Python citing a huge overhead (I don't remember if it's CPU or Memory footprint). I know a lot of people are touting the concurrency model, but I've seen so many technical analysis of unfavorable technical analysis of Go that I'm starting to question whether I should learn Go or invest my time learning something else?
While the concurrency model is nice (especially waiting on multiple channels - I haven't found a way to do that nicely in C++), I think there are other bigger advantages to Go:
* The standard library is really nice. It has almost everything you want and it's written in a clean non-enterprisey way
* It generates a single statically linked binary. Doing this is very difficult in most other languages.
* It's really really easy to cross-compile. Again, often very difficult in other languages (you might even have to compile your own compiler).
* It comes with a built in battle tested HTTP2 server, and a sane TLS library.
* It's a very simple language so it is easy for beginners to pick up, and also easy to read other people's code. Don't underestimate the importance of this - there's nothing worse than writing something awesome in a language that your coworkers find difficult, and then perpetually having to support it.
* The tooling is pretty good.
* Performance is good, and they've done really good work on minimising GC pause lengths.
Of course I wouldn't pretend there aren't downsides (cough generics), but they're mostly minor and certainly no worse than you'd have in any other system (C++/Python sounds like it would have more than its fair share of issues!).
Edit: Aside from generics, my biggest complaint is the impossibility of RAII. It's too easy to forget to `close()` things. Most languages suffer from this though, and at least Go makes some attempt to improve matters with `defer`.
> it generates a single statically linked binary. Doing this is very difficult in most other languages.
For AOT platforms it's difficult mostly due to glibc. e.g. on FreeBSD and Linux musl it's trivial to build fully static binaries.
Otherwise all valid statements and Golang is an improvement over other mainstream languages. So here's some future items for improvement that would make it even better and well suited for wider use:
* a nicer error handling mechanism, though this may be hard
* dead code elimination. Golang's static binaries are huge compared to fully statically compiled executables for other languages. I suppose the new compiler passes and backend might provide a basis to solve this.
* restore compile speed, which of course was mostly due to previously missing optimizations and simple compiler passes, which were added now and made it slower. Still the Wirth'ian language design allows for much faster compile times than C or C++.
And don't forget: no makefiles! All the building and rebuilding is entirely handled by the compiler. Which is very nice for simplifying project building.
The Dropbox project where they switched from Go to Rust is very low-level, and the constraints regarding memory usage where not typical of the average project, and the developers recognize they continue to use Go and Python in most other projects at Dropbox.
Ah thanks for clearing that up. The project that my colleague switched from Go was also a low level project. It seems like Go isn't fantastic for lower-level projects yet.
About your colleague, what exactly made him/her switch?
To define a bit more what I mean by "low-level":
- I think that Go is "lower" level than Java because Go is compiled to a native executable (no virtual machine) and Go gives you control over memory layout (not everything is a reference like in Java).
- I think that C/C++/Rust are lower level than Go because you control memory allocation and deallocation (no garbage collector) and you can even customize the memory allocator if you need. It's also more efficient to interface with C libraries because the calling conventions are identical.
Unfortunately, I'm under an NDA, but I just went back in slack to see what the issue was. Seems to be that we didn't have the build process and tooling to support Go and our system is under extreme resource constraints so supporting anything outside of our existing tools is a no-go (no pun intended).
In terms of the other languages you've mentioned, I went to school and all they thought us was C++ so I'm fairly comfortable there. I still haven't used Rust, but I've touched a ton of other languages. The language I've been experimenting with the most recently is Swift since I'm an iOS developer.
This is incorrect. Dropbox replaced their most performance-intensive section with Rust to squeeze out every last drop. They're still very much so a Go and Python shop.
Go isn't right for all projects. There has never been a language or platform that's right for all projects. It's quite a successful language, however, if it's at the point where there are now projects that realize that and are making the move to other languages.
However posts that, in 2016, seriously posit "I'm trying to figure out if it's worth learning" I don't believe are being sincere. They're usually saying "I haven't, and still don't want to, and here's my current justifications". And that's okay. I don't know Rust. I haven't bothered with Swift yet. One day.
Go's concurrency is great as easy starting point, but as soon as you want to use another model you need to move out to libraries.
And when you need third party libraries, then other languages have much more mature libraries[1], and thanks to more powerful type systems, those libraries get to be used almost as built in types.
Looks like a great contribution to the community. Major props for freely releasing it.
Most of the Go references that I tend to come across tend to focus on code, concurrency and API's without much attention to the full stack web app side. This definitely helps to fill that gap in the community.
Just flipping through the contents and skimming the chapters, the IDE section alone is really impressive.
Sad to see things haven't changed much on the sql front. Many web apps don't care about performance for the language, since the cost of querying the db will be orders of magnitudes higher anyway. What they want is a simple one liner to persist object graphs into a DB, because 90% of the code will be glue code around insert from json, and select to json types of features ( i'm talking list & forms types of web apps, not the fancy video chat over webrtc demo).
The fact that this books advertize "build your own orm" solution, with the one given not even able to select 1-many objects makes me really wonder how in the world one could recommend go for web apps.
Ps: to get a benchmark on what is the current level of productivity expected today for enterprise-like web apps, just have a look at a loopback.io demo. Yes, it's node.js which sucks, but you have to admit that we're pretty far away from manually mapping result columns to struct properties.
I find Go to be a concise and productive language for computing infrastructure applications, but struggle to apply it to problems with complex domains in business and industry.
For those, other languages like Java and C# that better support encapsulation and data/information hiding for the modeling of real-world concepts remain suited.
I think the problem with a lot of language discussions is really about the need for many to find the "one true ring" that can be learned and applied everywhere.
Instead, a polyglot approach surely is the best one?
I think it serves as a good example of how one can use go for webapp development.
With that said, after a year+ of writing go in my day to day job, I still gravitate towards dynamic languages for web application development and leave go for most systems programming tasks.
I'm not trolling. It seriously is easy enough to crank out a basic web app in less than a hundred lines of code that runs very well with just the standard library.
While I completely agree that the standard library is all you need in quite a lot of cases, the parent seems to be asking from more of a "how do I structure my application" perspective. A tool that generates the boilerplate necessary to use the standard library effectively in a complete application. Not just http handlers, but think of the persistence layer, for example. The standard library does not assist much with the engineering aspect of the job.
I wrote my own reverse proxy in Go to route stuff to other Go processes based on hostnames, and made it so I could listen to port 80 without root. At first, that was via `setcap 'cap_net_bind_service=+ep'`, but that was a little fragile, as I'd have to remember to do that on every recompile, so I switched to just listening to port 8080 and using iptables to forward 80 to that.
Like Vendan, I run my Go webapps on port 8080 (so I don't need root) and then have a very simple HAProxy setup that forwards port 80 to port 8080. Then I write a simple service for my Go app so I can control it with systemctl.
I like to use https://caddyserver.com/ as reverse proxy for the easy setup and buildin Let's Encrypt support. You can also use Apache or Ngixn if you want.
But you can also bind directly to port 80 if it's a simple app.
There's so much good content here, but it's also very surprising how much of it is truly a "roll-your-own and hope you get it right" approach.
If you have to write explicit code in each of your postbacks to check a CSRF token, it's going to happen that not all your posts will end up being protected. If you have to hand-build SQL queries, it's going to happen that you'll have injection vulnerabilities. If you are manually generating and signing cookies, and having to write explicit code to sign them and check signatures... These are all features that should be done in a core library which makes sure these things happen all the time, not just when you remember to, what, copy/paste the code into each of your functions to do it?
There's the overall structure of the code, which seems like it would quickly devolve into chaos. Looking at Section 4.4 there's a 'login' function which handles rendering the GET as well as processing the POST just by if/else on r.Method. You wouldn't want to actually structure a code-base like this, right? Later on, they do show a 'Beego' based router, which seems a bit more sane, but I'm really not a fan of 'showing the wrong way first' as a learning tool.
The particular techniques being used seem very home-grown and not particularly best practice. To prevent double-submit they add a hidden field with token=MD5(time.Now) and also save it to "a session cookie on the server side"? Not quite sure what that means, but I think it's trying to say save the token on the back-end linked to the session, and then verify a POST, from that page, on that session, has that token. And then presumably clean up the storage... The majority of which is not actually coded in the example, making it just a high level roadmap of what you could do, not a practical working starting point. But anyway, if your goal is to prevent multiple POSTs per GET, and you already have a transactional session state for the user, then you do it with a server-side counter, not a hidden field, and certainly not a "obfuscated" MD5(time.Now). Even if you have no session state, then the simple answer is to create session state, not to create another token which does exactly the same thing as session state, but in a completely insecure manor.
So overall I have a ton of respect for the work that was put into this document, it tries to cover a lot of material and is very easy to read. But I think the details also matter and 1) I can't believe this is idiomatic Go for how to actually route and manage requests, and 2) the entire proposed tool-set for actual secure processing of Sessions, SQL, CSRF, XSS, etc. seems to be totally home-grown and not at all production ready.
Note, in the IDE section: LiteIDE has gocode bundled, and in most cases, you can leave the GOROOT and such alone. I have yet to need to change it on either linux or windows.
I've got to be honest, when these language shootouts come up (and it feels like I've read a lot of them this week), it reminds me why I'm pretty happy working in C#. I've got great tooling, generally good libraries, a pretty decent core language, and generally, shit just works so I can get shit done.
Is it super sexy, no. Does it win me Internet Geek Points™, no. It's pretty much still Windows-only, but fine, that's the world I live in. The foot-guns are relatively small-caliber, and I've learned enough to avoid pointing most of them. I can do OOP, I can do functional (maybe not super pure ivory-tower monad/ADT/pattern-matching sorcery, but whatever - still have F# on my todo-list...), I can write straight procedural code if I really wanted to. I've even got a REPL and can use it as a scripting language.
Honest question - what is the point of this comment?
While I understand that HN has quite a population of .NET platform devs these days, traditionally this sort of noisy comments would be quickly rendered transparent (this one even claims to justify itself relative to a "language shootout"....only it's just a page talking about Go best practices, so it is off the mark). And the "Internet Geek Points™" thing is just nonsensical, and has become another defensive .NET talking point (e.g. "We're not trend chasers...now let me tell you how we also incorporate all trends").
I would have ignored it, but the above "language partisan" comment, having utterly nothing of value to add to the comments, or this story, and being completely out of context, has been floating on the top, betraying a pretty profound twist in the saga of HN.
Combine a momentum oriented society with an up/down vote button on everything and this is what you get.
Voting based on insightfulness or relevance simply cannot work when only a small minority can ever be expected to stick to it. We are being conditioned on picking a side and then boosting that side no matter what.
Voting up a comment that is in disagreement with your own opinion makes it look like you are losing the debate if being upvoted is generally associated with being right. So most people won't do it.
I believe the only way to prevent this in a community is to force people to use only words to express opinions. In my view, voting has no place in debates. And yes it means that we're not going to get our debates filtered and ranked according to insightfulness. But at least we're not getting any false signals based on perverse incentives either.
> I believe the only way to prevent this in a community is to force people to use only words to express opinions. In my view, voting has no place in debates. And yes it means that we're not going to get our debates filtered and ranked according to insightfulness. But at least we're not getting any false signals based on perverse incentives either.
And yet, I just upvoted your comment because it seemed much easier than typing a reply to say that your comment was of interest to me and I enjoyed reading it. But now I've said that as well.
I like having the flexibility to do both, but I recognize the compelling arguments you've made about the problems with having voting available everywhere. On HN in particular, I feel the downvote capability should be further constrained than it is presently (I think it opens at 500 karma presently).
Perhaps the downvote button should be changed to a flag (essentially how I use it) which might discourage using it for disagreement. I only downvote a comment when it is abusive, belligerent, blatantly condescending, or clearly nonsensical and unwilling to actually converse.
Ideally upvote would only be used for well-stated well-reasoned arguments with a plausible basis, regardless of the actual position, but I sometimes find myself upvoting a comment because I agree with it's conclusion. I think the agree-upvote is lamentable, but unavoidable in general.
Some UI changes might be able to fix the disagree-downvote (i.e. change to 'flag'), but I feel that the agree-upvote is too much a part of human nature to have an easy fix.
I believe the author's tone is what is getting you here. They really should have phrased the comment like "I'm really happy with a C# .NET backend because of a,b,c. What advantages would Go have over this backend to make it worthwhile for me to investigate?" This would have been a more useful comment.
People invest time in their languages so it's easy to subtly inject emotions into comments that come off snarky and unproductive. Then other supporters of the language just defensively click the up arrow.
There was a lot of this in the WASM articles where they were saying it will kill off Javascript.
Even though such a question would be more useful, I'm glad they didn't go that route as it would be dishonest: Too often we see the "why should I learn this?" questions that are really transparent "Why I haven't and won't bother -- my mind is firmly made up -- and here's how I pretend that I'm just being open minded in critiquing it" posts.
Many of us are happy in our niche, and learning new things is often a PITA. We're happy with what we do and how we do it, with the tools and things that we're used to. And that's okay. The truth is that the language evolution is something that we can mostly just ignore, and if eventually something is truly dominant for a use case, we can easily adopt it with no real handicap over people who ground with it from the ugly beginnings (and many of those advantages will percolate to other platforms anyways. node.js is just layers and layers of compromises and problems, but it had a profound impact on other platforms, and truly changed the web serving game).
And that's okay. But traditionally if someone posts resources for a particular language, it is bad form to engage in language wars, gloating, holier than thou (which the whole scarequote "maybe it isn't `trendy'" sorts of posts really are), etc, in the discussions. They're boring, we've had them literally thousands of times, and they are a distraction from discussing the actual contents of the post.
I've noticed this particularly afflicts Go discussions. Python, Rust, D, Swift...all can be discussed rationally and productively. But if Go appears, it seems to be just threatening enough that it draws out people concerned about things they don't know.
> I've noticed this particularly afflicts Go discussions. Python, Rust, D, Swift...all can be discussed rationally and productively. But if Go appears, it seems to be just threatening enough that it draws out people concerned about things they don't know.
I totally agree with that. Apart from Swift which is by fiat, Go is the only language in top 15 or so which is used for serious work by developers who are not PL enthusiasts/theorists. This is putting serious, though I think unfair, demands on Go developers to justify their choice. So users of languages as diverse Haskell, Elixir, Java, Rust, Scala and many more keep beating Go with their favorite feature of preferred language. Somehow Rust specially stands out as its users/developers seems 100 times more interested in Go related discussions than vice versa. It is similar to politics saying: "You may not be interested in politics but it doesn't means politics is not interested in you"
It also doesn't help that Go users tend to deny weaknesses in Go. The typical line is 'you don't understand it because you have not used it long enough'.
I have written Go intensively and less intensively over the course of last four years. Not surprisingly, most of the criticism are true.
I think criticism is all fine even by non-users. What I do not like is justifying to others who have no stake in project that why I used Go in place of lang of their choice.
Having used Go for some time now, and suspect that this attitude is a reflection of 'The Go Authors' and documentation.
Although it's described as a systems language, it glosses over many low level details. The 'atomic' package says 'These functions require great care to be used correctly.' In attempting to find out what care is required, I ultimately discovered that the authors couldn't agree on how to express how to define its operation.
When used for applications and running into shortcomings, the response is that it's not meant for that. The takeaway is that Go hits a spot between low-level systems programming and applications.
Probably this should have gone underneath the comment that's next down the page (echelon's "I'm so conflicted by Go...") instead of top-level. It was late.
Honestly comments like these further discredit the Windows-development-community in my view.
First, a quick rant.
You talk about "great tooling," and by this (I fear) you mean Visual Studio? Good libraries, by this you mean things like System.Foo.Bar.BazQux()? A "decent core language," by that you mean a pretty blatant knock-off of Java (which is an overly-bloated language in its own right)? And by "can do OOP" you mean must do, since the language forces you to embrace the paradigm? "Functional?" Without real first-class functions: without closures?
Generics? Fair point. Golang is lacking in that regard, at least for now.
But let me address the key misconception in your comment. You mention "sexiness," which in your mind is some sort of pointless quality. Here's what you're missing: biologically, we interpret sexiness as an indication of fertility. Good tools and languages aren't good because they're sexy, they're sexy because they're good. The ability to perceive, expect and demand this sexiness from tools is nothing more than a veiled desire to work in the most effective possible way. That's why people love Unix and hate Windows. That's why they leave languages like Java, C#, and C++ for Python and Go; and some (who I admire) use Haskell. It's not about elitism, the elitism is merely a by-product: the fundamental issue here is greediness, and the strength of one's desire to be as efficient as possible.
Did OOP kill your father, kick your dog, and sleep with your wife? If you stick your fingers in your ears and sing "module! module! module!" as you do it, you could probably live with the fact that C# coerces you into putting your static functions in a class. Since 2007 there have been LINQ, lambdas, closures, and a whole host of functional features added to the language.
With regard to sexiness, as an old Quebecois logging foreman once told me, "Sometimes you want the supermodel wife, and sometimes you want the one who can carry the canoe." If you can get both, great, but I got a lot of canoes to carry.
> Honestly comments like these further discredit the Windows-development-community in my view.
I'm just an asshole with an opinion on the internet, and I seem to have misplaced my official Windows-development-community membership card...
Please don't post unsubstantive comments to Hacker News.
Programming language flamewars are bad for this site. They're tornados of tedium that pick up entire threads and deposit them miles away in an intellectual desert. Please let's keep them off HN.
C# or Java are enterprisey, established languages used by millions of developers. They aren't going away because of Go, Elixir, or Node.js ...
And C# is sexy, it's the best object oriented language out there. So don't worry. C# doesn't need yet another guide for web apps, there are thousands of books and tutorials about the subject already. You don't need to try selling C# to anyone. People who need it already use it.
C# is an amazing language. The .NET framework is equally amazing and probably the most productive framework created so far.
In the next 12 months with the release of .NET Core, even the Windows requirement will go away. It should be at the top of the list for just about any project these days.
"Need" is a funny way of framing your counter. Of course any one who "needs" it, need meaning they can't use something else, would be using it. However there are many who would very much LIKE to use it but can't because the Core stuff is not quite ready for them; I NEED for it to work on OSX and linux but as of the latest dotnet deb package I can't use the AWSSDK with it.
Why not? I'm not selling anything. I just listed some reasons why C# is a great language with a great framework that can be more productive than most other environments.
By the way, it's probably one of the most commonly used languages ever when looking at the entire amount of software that's written in the world. Basically the entire Fortune 500 runs software written with .NET/C#.
Yeah, well, I've been hearing the "one-day we'll be on Linux" claims long enough to grow tired and move on. Developing on Windows, after having had some experience developing in a Linux/Mac environment, feels like second class citizenry. That's without even talking about nuget, etc...
.NET has been available on Linux for years via Mono (with various compatibility issues but it works). And the next official version with cross platform support already has a Go Live license which means Microsoft will support any production app.
Yes, Mono had issues as I said but it did/does work if you can work around it. Granted the windows licenses are cheaper than the dev effort to fix any potential issues so it's not the best situation.
But .NET Core can be used today and it works fine with the framework rapidly being developed. Several major libraries are also in or have completed the migration and we're just waiting on some other dependencies but we do have smaller apps running today.
Ecosystem for the code is the same (and as vast) as it's ever been, that's the strength of the CLR/framework. Mono/.net on linux does have a community but it's growing quickly now with Core.
We have some smaller backend stuff running today (messaging, logging, etc). Bigger apps have dependencies that are still waiting to be compatible with .NET Core.
Isn't the biggest problem of .NET/C# that Java and the JVM are just too similar? Sure, some things are nicer in .NET-land, but is it worth the switch, which kinda locks you, or at least moves you towards Windows too?
It doesn't take "balls" to say anything anonymously on an online forum. Nobody's angry he likes C#; there simply is no reason for this comment to exist on a thread about Go.
I've done C# development for many years. C#, while elegant, is far from being a productive language, mostly because of its ecosystem and community. Making a simple API web server using proprietary Microsoft libraries is way harder than it needs to be. Documentation is also piss-poor on most of these tools, and many developers just resort to reading opinionated online web blogs which give all kinds of terrible advice. You can use open-source libraries like Nancy instead, but they're usually error-prone and updates have been known to break production deployments.
Visual Studio still crashes all the time and compilation on bigger projects is usually slow and painful. I've had to work on full fledged projects with infamous Entity Framework data-access layers and these things are a nightmare to work with. I've seen entire projects generated using T4 text templates...
As feature-rich as the language may be, the way developers use it lead to huge problems. Now that Microsoft is introducing ASP.NET Core the fragmentation in the community is only getting worse. Couple this with the fact that .NET is used in all sorts of dysfunctional development teams, and you've got a recipe for disaster every time.
For me the few positive things is that Go is a kind of second coming of Oberon-2 with C like syntax and now many Hipsters are using it instead of C (why I re-wrote X in Go kind), which eventually leads to less exploit-friendly code being written.
It isn't hard to prevent SQL injection if you use parameterized SQL statement rather than using string concat, and whilst examples of this are trivial they shouldn't be skipped.
In the XSS section it mentions filtering and checking inputs, but does not mention sanitization and does not give any examples. In the aversion to use any non-standard package it also does not mention https://github.com/microcosm-cc/bluemonday or anything similar (I am the author of bluemonday - a HTML sanitizer in the same vein as the OWASP Java HTML Sanitizer).
There is some sample code, in the Filtering section, but this only demonstrates the use of a fixed range of inputs in determining a filter, and then a regexp to check the input matches a format.
Beyond the security, where the theory is at least known even if a demonstration on how to implement it is lacking... the entire guide misses out on demonstrating templates to their fullest, and specifically using a map of functions to provide the equivalent of Django's TemplateTags.
In fact, the missing link for most Go developers who are building web apps, and for those coming from outside Go, are template tags. Most Go devs I know (who seem more systems focused) don't even realise that this stuff exists: https://golang.org/src/text/template/examplefunc_test.go