I read a thing claiming that containers are “light weight.” But that’s only compared to a hardware virtual machine! Containers seem light only through the historical accident of their path to popularity. They are nearly at the end-point of heavyweight distribution methods.
Once upon a time, we programmers were able to handle a bit of version skew. We’d use libraries like GTK+ which maintained backward compatibility—at the ABI level, even—so that code compiled against 2.4.x would run against 2.4.x or later 2.x releases, without changes. We’d install something like Smarty to the global PHP include path, and use a single copy of it from all our projects, for space efficiency. Nothing was vendored!
(We could semi-vendor things in scripting languages by playing with the include path. Install a major upgrade to, say, “lib-v4”, then in the v4-aware application, prepend the “lib-v4” directory to the include path at runtime. When all the applications were converted, remove the old version from the global path, move the v4 code there, and remove the include-path code from the apps again. It’s a lot like gradually updating a database column. It wasn’t a great approach for C code, though.)
Portability across operating systems, even in “POSIX” land, was a mess, but we all learned how to do it. Virtually all open-source code dealt with it, so we had plenty of examples, and we largely respected the user’s choice of platform to run on. Even if it were Solaris…
This also produced a pressure for minimal dependencies; the less we required of a user, then the more likely they were to run our code. I still think that Java largely failed on Linux because every user had to fetch the JRE from Sun’s atrocious website themselves. (Blackdown and later OpenJDK would change this, long after the ship had sailed. The Apache Foundation’s Java-based projects are a notable exception from the general attitude, but they are also not desktop software.)
Today’s environment is the complete antithesis. We pack entire OS distributions, possibly a language interpreter, all of our libraries, and our application code into a gigabyte-plus wrapping (partially shared, but still a minimum). Then, we call it “lightweight” because it doesn’t have a guest kernel in there.
The old times weren’t perfect; it was an incredibly painful experience to make Linux binaries that worked across distributions, because of variance in the filesystem layout and the need to rely on old libraries to cover the older systems people might run the binary on. And sometimes, there was no choice but to make multiple builds, because distributions might only package one of incompatible library versions. But largely, to support an app of a few megs, we shipped a few megs, not a few hundred, and we certainly didn’t call “a near-complete disk image” lightweight.