The Problem With Package Managers

As Linux moves farther away from its UNIX roots, and more towards being yet another appliance for the drooling masses (the same drooling masses who just five years ago couldn’t grok the difference between a CD-ROM tray and a cup holder), our once great proliferation of usable choices has dwindled due to a tendency on the part of developers to target only Debian- or Red Hat-based distributions, with a strong bias towards Ubuntu on the Debian side, while few of the more generous developers will also target SuSE, and even fewer will distribute software as a distribution-agnostic tarball. This situation leaves users of other distributions in a precarious position, especially in the case of those of us who–like the author of this article–believe that systemd is a baroque, labyrinthine monument to bogosity (how Lennart Poettering manages to get hired by any reputable software development firm is an atrocity that boggles the mind–his other big “hit” is a three-coil, peanut-laden steamer of a solution-looking-for-a-problem called PulseAudio), and would seek one of the increasingly rare sysvinit based distributions to get away from it.

This is a problem mostly due to package managers. If you’re on a Debian-based system, you get apt. Red Hat, yum. SuSE, zypper. These utilities should need no introduction, and are often praised by Linux users: a single command will install a package and all of its required shared libraries and dependencies, and another command will upgrade packages to the latest and greatest versions, all from a centralized, cloud-based repository or list of repositories. They do provide some convenience, but at a cost: the days of reliably being able to find a simple tarball that will work with the incantation of ./configure; make; make install seem to be numbered. This was a nice, cross-platform solution, and had the added benefit of producing binaries that were well-optimized for your particular machine.

One bright light in all this darkness is the pkgsrc tool in NetBSD: you check out a full source tree from a CVS repository, and this creates a directory structure of categories (editors, databases, utilities, etc.) into which are further subdirectories representing packages. All you need to do is descend into the desired subdirectory and type an appropriate make incantation to download the package and its dependencies, build them, and install them to your system. Updates are similar: fetch the latest updates from the CVS repo, and repeat the process.

However, not even pkgsrc has solved the other big problem with most package managers, and that is the politics of getting new packages into the repositories. The Node.js package manager, npm, is the only one that does this correctly (in the FOSS sense) in any way: you go to the npmjs.org website, create an account, choose a package name (and hope it hasn’t already been taken by another developer), and you are in charge of that little corner of the npm world. You manage your dependencies, your release schedule, your version scheme, the whole nine yards. With Linux distributions, it seems that only a blood sacrifice to the gatekeepers will allow you to contribute your own packages, and even when you get past their arcane requirements, it is still a mass of red tape just to publish patches and updated versions of your software. Node.js, for instance, has not been updated in the mainline distribution repositories since v0.10, which is by all measures an antique.

In order to meet my standards, there are three solutions, that should be employed together:

  • Publicly and brutally shame developers who release only deb and rpm packages but no ./configure; make; make install tarball until they are so insecure that they cry into their chocolate milk and do the right thing (or strengthen the developer gene pool by quitting altogether and opting for a job wiping viruses for drooling PC users with The Geek Squad)
  • Push the Linux distributions to abandon the brain-dead cathedral approach to repo management and opt for a more bazaar-like egalitarian approach like npm
  • Make countless, humiliating memes of Lennart Poettering in embarrassing and compromising contexts (this bit is more for the health of UNIX as a whole than for package managers, but it’s the duty of every good UNIX citizen)

 

Advertisements

What an object-oriented MUMPS could look like, without breaking existing code

A little idiomatic support for the OO paradigm is something I’d love to see MUMPS embrace in the future. This is not to say that you can’t write OO code in MUMPS ’95–you can even write OO code in assembly language–but, the syntactic sugar would be nice, as well as the scoping protection and encapsulation this would give. The introduction of the dot-notation paradigm would lend itself very well to creating clean new API libraries. Some of you may not know, but the dot-notation API is used by some MUMPS vendors for calling out to external (non-MUMPS) routines.

We’d add a few new things:

  1. Overloading the NEW command so that it can also be a unary operator. This will allow operations such as:
    set myCar=new $$Car()
  2. Adding a $OBJECT() intrinsic, which would take two parameters: a variable name and a type name.
    $OBJECT(variable,type)

    would return a true value if the node referenced by variable (which can be a global variable or a local, either could include subscripts) matches the type defined by type.

  3. Adding a this keyword, which would return the entire current object.
  4. Adding conventions to the language. Any NEW commands at the top level of a routine would define instance variables, and the top-level routine without any tag specified becomes the default constructor for an object.

The main thing I’d like to see, though, is the ability (shown in the hypothetical sample below) to store entire object instances in MUMPS globals and retrieve them later:

;; when tag and routine are same, use the default constructor
Car
 new color,doors,started 
 set color="",doors=0,started=0
 quit
;; overloaded constructor (limitation: 
;; you could only overload the constructor once)
Car.Car(color,doors) 
 set this.color=color,this.doors=doors
 quit this
;; procedure method
Car.Start 
 set this.started=1
 write "Car started",!
 quit
;; procedure method
Car.Stop 
 set this.started=0
 write "Car stopped",!
 quit
;; extrinsic function method
Car.Color() 
 quit this.color
;; extrinsic function method
Car.Doors() 
 quit this.doors
;; extrinsic function method
Car.Started() 
 quit this.started

TestCar
 ;; new as a unary operator as well as a command
 new wifeCar
 set wifeCar=new $$Car("blue",5)
 new myCar
 set myCar=new $$Car("silver",4)
 ;; we're now going to store myCar and wifeCar in subscripts 
 ;; of the ^persistentCars global
 set ^persistentCars("John")=myCar 
 set ^persistentCars("Miri")=wifeCar
 ;; $object(variable,object) would return null if "variable"
 ;; is not of type "object"
 new memCar
 if $object(^persistentCars("Miri"),Car) do 
 . ; this use of the new operator will fail 
 . ; if ^persistentCars("Miri") is not a Car
 . set memCar=new $object(^persistentCars("Miri"),Car) 
 . ; we can now access Car's methods from memCar
 . do memCar.Start 
 . if $$memCar.Doors()>2 write "family car!",! else write "coupe!",!
 . set ^otherPersistentCars("Miri")=memCar
 else write "The global did not contain a valid Car",!
 quit