> Python, Node and Ruby all have better systems for package management
Maybe they have better tools for managing package dependencies but Go doesn't have to deal with interpreter dependencies, which can be a major headache. Go also doesn't have the problem of conflicting system level packages.
Honestly no matter how good your deployment practices are, if you have to manage an application's deployment long term you're going to have dependency problems of some kind. I'd rather deal with those problems at compile time than hit an edge case during deploy or in prod.
In Python, if you have control over the target system, this is solved with virtualenv. You can install whatever versions of libraries you want in there with pip without causing conflicts with system level packages.
If you intend to ship to end-users, yeah, you are kinda screwed. You are stuck using one of the various "freeze" methods, which, in my experience, kinda blow.
We use Nix which is much nicer than pyenv/virtual environment, but it's still a pain compared to Go. This is mostly due to Python's runtime model, and maybe also the tendency for Python applications to have very tall, broad dependency graphs.
Working with nix is also not very easy; docker might fare better here, but probably just a lateral move. In any case, Go outclasses Python on deployments. Also, my company is looking into compiling Python as a means of code obfuscation; Go compiles by default, which (modulo stripping) is probably enough obfuscation for our purposes.
I've been evaluating Cython for both code obfuscation and for using C based extensions to improve performance. Cython is pretty nice, but shipping binary only Python extensions can be such a pain, especially dealing with 2-byte vs 4-byte unicode representation issues.
Yes it's nice to see this is now fixed. In my case I need to support Python 2.7 though, and for Python 2.7 the only workaround I know of is shipping two binaries (2 byte and 4 byte encoding) then loading the correct module at runtime.
Virtualenv is nice, but lately I've grown to use docker containers instead. You can use the official containers for go, python or ruby, feed it the gemfile or requirements.txt or whether, tag it, push it and you have a permanent snapshoted image.
It's definitely a hack, but for development environments it's quite an effective one. Which is why we actually created a (more user friendly) clone for Go development. It's called Virtualgo, and it's mentioned near the end of the article as well. https://github.com/GetStream/vg
Most of the time pip installs work fine, but once a while after some type of OS upgrade (namely, my experience has been MacOS), you run into odd compiler types of issues.
So it's why a lot of teams will use either Vagrant / Docker to setup local developer environments.
Can confirm that once upgrading macOS required using Docker to be productive, because some C-dep we had stopped working. We have developers using macOS 10.10 to avoid any issues (although they're likely gone by now, it's not worth the effort to figure it out anymore).
I've occasionally had things spontaneously break. Most recently the cryptography package just stopped installing on deployment. Had to add a pip upgrade on deploy, which somehow prevented the AMI I was using from installing some of its requirements. Had to add those packages to my project requirements.
Also some of the data analysis packages don't work with virtualenv.
Most deploy scripts I've seen tend to do this. Which is insane in my opinion, but the python toolset encourage this kind of approach by making it the default easy thing to do.
That's one of the things I prefer about Go: the compiler can cross-compile, so I can compile the entire codebase on my osx machine and produce a single statically linked linux binary that I can just copy over scp to the server. Deployment becomes infinitely simpler.
> Most deploy scripts I've seen tend to do this. Which is insane in my opinion [...]
Also, most programmers don't know a thing about administering servers.
Ubiquity doesn't mean that it's a proper way, as you clearly see yourself.
> [...] the python toolset encourage this kind of approach by making it the default easy thing to do.
It's not quite the fault of Python tooling in particular. It's really the
easiest way in general. Similarly, the easiest way to deploy a unix daemon is
to run it as root user, because the daemon will have automatically access to
all files and directories it needs (data storage, temporary files, sockets,
pidfiles, log files). Anything else that is easier to manage requires to put
a non-zero effort.
> That's one of the things I prefer about Go: [static linking]
Static linking has its own share of administrative problems. It's not all nice
and dandy.
For a number of reasons, I haven't bothered to do a complex build/deploy process. I write in python, I freeze the requirements into requirements.txt, and I type "eb deploy". Anything else is overkill for me.
And then you have different lists of installed packages in your development
environment and in the production and even between two different production
servers (which can silently and/or subtly break your software), and you need
to manually install all the C/C++ libraries and compilers and non-Python tools
and whatnot, and the upgrade process takes a lot of time and can break on
problems with PyPI and/or packages that went missing, and you can't even
sensibly downgrade your software to an earlier version.
Yes, avoiding learning how to properly package and deploy your software is
totally worth this cost.
Python does not really have a "build" step. _That_ is the problem.
I think Heroku also played a role in prolifirating the idea that you can just push your code (from a git repo) to a server, and the server will take care of deploying it. Which usually means the server will install all the dependencies from pip during the process.
When you build a piece of software on many layers of abstractions, something will eventually break and leak all the way up in a nasty way that is difficult to debug or fix.
I don't have specific examples in mind but I've had a lot of frustrations with virtual-env.
For context, you can install opencv, tensorflow, ROS, matplotlib, and the entire scipy stack in a virtualenv, with no external dependencies, using wheels.
This means that you can generate images, train a machine learning algorithm on them, compare the results to conventional CV algorithms, and display them in an ipython notebook all from a venv. There's a huge amount of C++ and even qt integration in that pipeline, all isolated.
It won't be maximally performant (ie for massive training), but for that you'd want distributed docker deploys or similar anyway.
Wheels doesn't completely solve this problem. For example, your example of matplotlib, IIRC, has a dependency on libblas: a C library. This dependency isn't captured in the wheel metadata, and it's up to you to install the right libblas on the host, or somewhere where it will get loaded. (Though honestly, this isn't usually an unmanageable level of complexity. But virtualenvs are not free from external dependencies always.)
IIRC, we also had a problem where a wheel failed to find symbols in a SO it was linked against. It turns out that the wheel worked fine in precise, but failed in trusty, and we ended up having to split our wheel repository because the wheel was specific to the Ubuntu release. (It seemed, at the time, that whatever SO it was linked against appears to have made backwards incompatible changes without changing the major.) There are rare cases like this where the wheel is unique to attributes of the host that the wheel metadata can't capture.
> For example, your example of matplotlib, IIRC, has a dependency on libblas: a C library
And with the wheel packaging, you're free to embed that library in the wheel that depends on it. You can also not do that and rely on the system libraries. The wheel provides you a way to do what you want, but doesn't force you to do it.
The are good reasons for either of those approaches, so I'd say wheel does solve the issue.
As another user mentioned, they do, if the library maintainers take the time to do things correctly. The package I'm describing does not link outside of the virtualenv, the matlplotlib, opencv-python, and tensorflow libraries include all necessary dependencies (although you have to use a non-default renderer in matplotlib, because it doesn't bundle all of them).
What you say is correct, virtualenvs are not free from external dependencies always, but correctly build wheels are. Wheels and virtualenvs aren't the same thing.
Wheels just broke something in our build pipeline. They removed support for Python 2.6 and started tossing errors. I was able to fix it by pinning Wheel which probably should have been done originally by who ever made the build utility, but it would have been a non issue with Go and a binary.
Well, python 2.6 was also EoL'd 4 years ago, so yes, if you're using a no longer supported piece of software and not pinning your versions, I'd argue that you're inviting issues.
Sure. But if the build utility was just some binary, then it wouldn't matter. If Go was abandoned by all maintainers tomorrow or they broke all the packages, the already built binary will still work.
Should someone have changed the Python build tool to be 2.7 or 3? Maybe if they were bored and new it was something that needed work or wanted to be good tech citizen. However, what really happened is that no one even knew what the tool was really doing, just that it was part of a suite of tools in a build process, and no one would have looked twice at it ever again had wheel not removed support for 2.6. /me shrugs.
I mean it totally would if the binary dynamically linked against a file you didn't have on your system, which is exactly what happened with `wheel` (python 2.6 doesn't have OrderedDict, which wheel now uses).
That's a different project, but I also use ros in a virtualenv. Its a bit weird because you end up installing ros both inside and outside of the venv (various ros command line tools only use /opt/ros/... python deps), but your actual nodes run in your virtualenv.
And ros doesn't even need to be a wheel fwiw, its pure python, but its also just a painful thing to deal with for many, so it was worth mentioning.
> Go also doesn't have the problem of conflicting system level packages.
Sure, as long as you're not using CGO and dynamic linking. Otherwise you'll get the exact same problems as the others.
> Go doesn't have to deal with interpreter dependencies
As long as Go is forward compatible this will old true, but I don't think this was the point of the comment.
'go get' is a half-baked package manager and yes it fetch packages and resolve dependencies between packages so that's a package manager. It just doesn't care about versions. Other languages have solved the issue by requiring a third party tool, Ruby even has its own build tool.
There is a reason why some gophers are working on an actual package manager...
> Sure, as long as you're not using CGO and dynamic linking. Otherwise you'll get the exact same problems as the others.
Not even then, to be honest.
I wrote a product that is deployed on many thousands of servers, and all of a sudden a not-insignificant population just started experiencing SIGABRTs on process start.
Turns out Amazon Linux (and some others) had removed a syscall that i386 Go on Linux was relying on (https://github.com/golang/go/issues/14795). We built our product with a manual patch against "src/runtime/sys_linux_386.s" for many months as a result, and it was really a huge headache to help all our customers.
I would be surprised if Python or even Java broke in this way, for example. I was really surprised it even happened in Go to be honest.
There are other runtime problems too, we had a weird interaction with a "cloud OS" based on cgroups (CloudLinux) screwing up our Go processes depending on how many goroutines we ran ...
I think Go is fantastic but its runtime can definitely clash with its environment ... it's not the same as a C program.
Was the system call part of POSIX or the standard Linux interface? Because if so, that sounds like the fault belongs to Amazon, not Go. The same thing could happen to the Python interpreter.
Maybe they have better tools for managing package dependencies but Go doesn't have to deal with interpreter dependencies, which can be a major headache. Go also doesn't have the problem of conflicting system level packages.
Honestly no matter how good your deployment practices are, if you have to manage an application's deployment long term you're going to have dependency problems of some kind. I'd rather deal with those problems at compile time than hit an edge case during deploy or in prod.