A single binary with zero dependancies is so awesome. With a ruby on rails app I need to worry about ruby version, ruby implementation, gem versions, compilation of C based gems, etc etc. With Go i simply copy up the binary and run it.
A single binary with zero dependancies is so awesome. With a ruby on rails app I need to worry about ruby version, ruby implementation, gem versions, compilation of C based gems, etc etc. With Go i simply copy up the binary and run it.
The second reason I switched was RAM consumption and here Go shines compared to Java, although I'll have to let Gogs run for a few days to see what happens.
I gave it a spin and it looks nice. I can see migrating from gitbucket to gogs, mainly for being able to run it on a small VPS. One thing that I didn't like was that the source version can only run from the source code directory. If I copy public and templates directories it should run from anywhere.
But you're right about static resources, they need to be in a directory structure. Fortunately, zip files make them easy to distribute.
What robovm can do is a great example of the joys of toolchains with a well-defined stable intermediate representation. (Or one of the joys, I should say -- the flowering of languages on top of the jvm is another.)
Go's first-class AST work is excellent stuff, but I'd love it even more if they fleshed out a well-defined, stable, portable intermediate format like LLVM's IR and java's bytecode. Making a release of software and knowing it can run on architectures you haven't even thought of yet is liberating. Sure, architectures don't come along "very often" (but they're starting to happen more often!), and sure, you can use a full vm at the bottom layer (but it's slow! It can't do a fraction of the optimizations possible with an IR/bytecode), and sure, you can just pretend the source is an IR (but if some library you use chooses a different build tool chain than you, you're going to have a bad time -- don't laugh, golang is too young to have bifurcated much yet, but give it time, and look at what happened around the go-get mess already; or, consider what happens when someone just adds more tooling like source generation, which has also already happened)... Taking the long view, I think an intermediate representation has proven incredibly useful for the jvm as a platform, and I hope golang also grows to offer such a route sometime in the future.
> sure, you can just pretend the source is an IR (but if some library you use chooses a different build tool chain than you, you're going to have a bad time
In the jvm world right now, for example, I won't touch maven with a ten foot poll. And yet I regularly use libraries produced by people who do. The portable, stable bytecode is a boundary between me and them where the buck stops. Anyone can use any build toolchain they like, and the interface for collaboration is well-defined.
Don't get me wrong, there are many things to love about golang, and there are many things to love about building from source. But I do think it's worth pausing to consider the flexibility that an intermediate representation can unlock.
But I'm inclined to agree that this is one area Go projects have a hard time with. The portability of the executable is great, but if you're doing anything that requires static assets, configuration, or data outside the context of the runtime, you can easily end up with a tough-to-manage mess of configuration.
What we've done for our internal Go projects is wrap them up with an .rpm installer that handles the creation of directories throughout the system, drops init scripts where they're appropriate, and sets up necessary cron jobs and logrotate rules. I don't think this is the best approach, but at the same time I'm not familiar with any good alternatives.
This is mostly a sysadmin/devops issue, since all languages have the same issue.
I solve it through a CM tool (Ansible, in my case) that sets up my directories, rsyncs my templates and TOML config, and uploads my binary. Not having to worry the server running the same env as my dev environment removes a whole class of bugs/frustration.
You're kidding right? I thought that whole "devops" movement (call it what you like) was to get rid of the attitude of "other people's problem".
I live in environments that are (for the most part) regulated and demand by law that there is a strict separation between the people running and developing software, often open to interpretation is the 3rd role of people configuring the software.
The problem is that "I solve it..." just doesn't work. Either people solve it by working cooperatively together or it simply won't ever be deployed.
There's no such thing as a sysadmin problem, devops problem, developer problem. (No go downvote me for the tone of the next sentence) -- For me it's either get your ass moving, stand up, walk over to people and talk to them or get lost!
That's why frameworks exist, or packages like go-bindata or rakyll/statik (https://github.com/rakyll/statik), or CM tools that can wrap it all together.
System configuration I think is a problem independent of the programming language and anything you try will feel as hack. As long as it works, it is ok. :)
Is there anything stopping one from appending a zip archive to the go binary, and having the binary open the executable as a zip file to get at the static assets ?
https://github.com/GeertJohan/go.rice
https://github.com/jteeuwen/go-bindata
EDIT: to add, the Go team is looking to add a generate command in go1.4 to help with this. See: https://groups.google.com/forum/m/#!topic/golang-dev/ZTD1qtp...
You mean, like every single language out there with native code compilers?
A big generation gap must have happened, for static compilation to be touted as awesome feature.
Two decades ago it was the only option in most operating systems.
Not an excuse for the lack of understanding, that static compilation is a standard feature that any language compiler to native code usually provides.
You can build your binary with the netgo build tag, but you must take into consideration that your binary might not behave correctly when running on systems with customised name resolution (NSS) settings, such as nss-ldap etc.
Go developers only distribute their open source software in a way that you only have to take the source, compile it, and run it, without having to worry about dependencies.
I see it all the time in the last 30 years of my career.
Maybe GNU/Linux kids nowadays don't.
Besides C is not the only language with native compiler.
go get -u github.com/go/project
If you're writing native Go code, it doesn't matter if there's 0 or 1000+ dependencies, that one command will take care of everything. So there's no need to fear having extra dependencies, and you are welcome to reuse more code.Go takes the common parts of writing software and abstracts them away. Take any two distinct Go projects, and the only difference will be:
- Import Path
- Actual Code
Everything else works exactly the same no matter what project it is (assuming it follows idiomatic Go package conventions). Docs via godoc.org, standard testing, go vet, http://go-lint.appspot.com/, http://gocover.io/
No need to figure out how to install that particular project/library, how to get docs, how to run tests, etc.
Also their package managers have many issues you don't see with go (because go doesn't have a package manager, rather a source code dependency manager). For example python and ruby have many versions and not everything is available in all versions. What a user will do if he want to run a 2.7 and a 3.x python app? Sometimes they use the system compiler to produce binaries. I have seen it fail occasionally; for example charlock_holmes on a gentoo hardened system. Npm just floods your filesystem with npm_modules directories. I use a package manager so I won't have to install the same thing multiple times at multiple locations. Also it is very difficult to understand its directory structure. I searched the docs for hours in order to find where it stores the programs I install as a user (its path). Go is difficult to understand too in that aspect but it has all this info in one online document. You read it until you understand it.
Finally there are always the questions; should I use pip or easy_install? What does rvm, what gem and what bundle(r)? Why should users learn them? How may I update my current gems and remove old versions? Where is gruntjs and how do I run it?
Probably many more. If `go get` was good enough as you intended to say why do we have `godep, godeps, gom, gondler, goop, vendorize, party, gpm` and many more? Which one should I pick? It's better do GOPATH="_vendor:$GOPATH" go install or use one of them? Also, should I install go with apt/brew/pac or use gvm?
I like go, I use it for fun and work, but really, is getting annoying seeing all this `gophers` totally out of reality.
On the other hand, there isn't a way to not learn about gem, bundle, pip, easy_install, npm when you try to install apps written in their languages. Some times it is easy, as “gem install gollum” and some times it is difficult, as trying to install gitlab.
Haskell I really don't know because any haskell app I ever needed was in my distro's repositories. To be fair most Python packages are too.
Anyway, Go can't produce dynamically linked libraries yet even for Go applications. It really has no choice but to bundle them into one application.
The only package manager (pm) I like, is the pm of the distro I am using. If I am on Fedora, I like yum. When I am on Gentoo I like portage etc. The problem with most web apps is that they have dependencies that don't exist in your distro's pm. I'll take a static binary over a 3rd party pm any day. Let's not forget that one of the most important reasons for the existence of docker is to not have to set up an app in many different systems.
For the later two can calling C functions is cheap. I would assume if you run Go with its default one thread option, it's cheap too. (Switching threads or even processes means context switching is what is usually expensive).
In order to provide efficient lightweight threads, Go allocates only a small amount of memory for each stack, growing it as function calls require it by appending another segment in a linked list. This makes thread creation very cheap.
The problem with segmented stacks is that they can cause "stack thrashing." Suppose a goroutine is right at the boundary between two stacks. It calls a function that exhausts the available segment, forcing the allocation of a new segment, which is then added to the linked list. The function runs, and then frees the segment upon return. If this boundary happens to fall within a tight loop, you'll see a severe drop in performance, to the point that it's completely unacceptable.
Recognizing this, Go relatively recently switched away from segmented stacks. It now uses a strategy called relocatable stacks, or contiguous stacks. See https://docs.google.com/document/d/1wAaf1rYoM4S4gtnPh0zOlGzW... for details. Similar concerns prompted Rust to move away from segmented stacks, but as relocatable stacks require a garbage collector that was not a viable way forward for Rust, so it just dropped the idea completely.
The problem with both approaches is that C has no knowledge or support of either segmented or relocatable stacks. This means that calling out to C in Go involves a completely different calling convention that involves switching to a larger stack, running there, and then switching back--which is very expensive, especially compared to languages like Lua where the C FFI is basically free. That's why Go reimplements glibc by performing its own system calls--to avoid the C FFI.
In conclusion, every language feature--no matter how enticing--has a cost.
Ruby's Nokogiri for example is very very common and I've never found it simple to install.
Python has psycopg, numpy and a variety of others that are often very complex to install.
Node at least differentiates itself in that most of the database drivers have pure JS fallback implementations, so they'll work without the relevant libraries installed, just not as fast.
(test)> pip -q install pillow psycopg2 numpy
pip -q install pillow psycopg2 numpy 9.85s user 5.43s system 44% cpu 34.400 total
That was complex indeed.(it wasn't)
It's not going to get simpler than a single executable.
Same goes for the use of "read-only" mounts and "RAM disks" as opposed to dependence on other, less reliable media.
I hope your comment continues to be upvoted; usually I see downvotes at any mention of static linking. Why, I can never be sure. If static binaries make some power user's life easier why should anyone else care? With reasonably-sized, well-written programs (or the use of a system like Go's), compilation can be quite fast. And easy enough for anyone to do if and when libraries change.