As long as there have been programmable computers, there has been a form of application packaging, and it has taken many shapes in the past and has at least as many that coexist today. Here’s a brief run-through of some of these followed by a couple of conclusions.
punch card boxes
1950’s and 1960’s
For the early computer systems the format and packaging for individual programs wholly depended on what the system was. Programs were either entered manually directly into the mainframe through a programming interface or stored on punchcards organized into stacks that were then fed to the system to either run in realtime or to load them into the program memory and then run from there. This was most likely the earliest form of application packaging – a literal box (or just a stack) of cards.
Typical application: a box of cards.
- Simplicity: It’s a box of cards
- Many times authentic hand-drawn labels and cover art
- Very limited storage
- Don’t ever lose a single card or nothing works
Cassette and floppy
1970’s and early 1980’s
As computers started invading homes, two types of data storage became widely available: magnetic cassettes and floppies (first 5 1/4 “, then 3.5”). It became popular to distribute an application on one or multiple floppies, or on a cassette. It was usually loaded from it into memory and then run. In some cases this meant just going to the physical beginning of the tape or the first sector of a floppy and reading data linearly into the program memory.
Typical application: one cassette tape or one floppy with a pretty label.
- Huge leap in application availability for an average home (from none to a lot)
- Tapes, floppies, real physical things with neat (or hand drawn) labels on them
- Failures after extensive use
- Often very long loading times
FILES, FOLDERS, ICONS
Late 1980’s into the 1990’s
Graphical user interfaces brought a new challenge: applications needed icons. In many cases, this also was the time when developers had to choose between bundling everything into the application file – or start storing data files separate from the application. At this point most applications also had to adhere to a file system, so file names and sometimes file extensions were needed. Folders (or directories) were a new thing so many times they weren’t even used.
The GUI would then choose what to show. For example, early Macintosh and Amiga computers would just show the files that had visual data attached to them (a separate icon file / metadata entry). First versions of Windows were basically file explorer applications that showed all content (with the later luxury of having shortcut files) and you had to determine by the extension if a program was runnable.
Typical application: 1 executable file, 1 icon file, 1+ data files in a flat folder.
That weird era when everything was on CD-ROMs
CD-ROMs became a thing so there was a way to store a lot of information along with the applications – but at the same time they were too large to be copied onto the hard drive. This brought a very special of CD-ROM discs that had executables and their data on them while user data was to be written out to the hard drive.
Typical application: 1 physical CD-ROM disc
- A LOT more data than ever before
- Beginning of “Multimedia” and the first time real video assets could be used
- Media easily destroyed by a single scratch
application packaging today
Hard drives became common and people would no longer need to constantly feed their computers with floppies. Now it was the operating system’s responsibility to guide the user to organize their programs into appropriate locations.
What now follows is a comparison of some of the currently used application packaging methods by their platform.
Windows 95, 98, 2000, XP, VISTA, 7, 8
Windows 95 marked the birth of the Program Files folder and the Start Menu. It meant that an application was always divided between – at minimum – two locations. Program Files would have a folder for each program and Start Menu would host the metadata file to tie together the program name, icon and executable path. It also meant that a developer would need to consider this when writing an installer and uninstaller – another two things that became instantly necessary. In order for the computer to know about the uninstallers, a registry entry was also needed.
- Fast structured listing of available applications
- Lots of extra work for the developer due to needing installers and uninstallers
- Extremely volatile: A user could delete any 1 piece of information and make the application either invisible or dysfunctional
- Cleanup is difficult and often requires extra tools to get all the pieces off your computer
Although not directly an Apple invention (this was inherited from NEXTStep) MacOS began using a bundle approach to applications. On the file system level, this was basically a folder with a fancy name, but it did quite a few nice things in the way of standardization: A developer would always provide an app bundle with a consistent structure. Also, it meant that the OS would always know where to go for the application icon and a presentable (or even translated) name to show. In many cases just copying the bundle into the /Applications folder would equal to installing and deleting to uninstalling the application. This is still used by OS X today and was also adopted into iOS almost as-is with the addition of an outer .IPA container that is then compressed.
- Fast listing of applications
- “Zero install” possible – usually nothing else than copying the bundle is needed
- Limited hardware – only available on Apple devices
Linux had almost a completely opposite approach to application bundling in comparison to MacOS and DOS/Windows: every piece of an application would be stored in a context by their type rather than together in a single entity. A package manager would be responsible for keeping these pieces together. Binaries would typically go under /usr/bin, data files under /usr/share, dynamic libraries under /usr/lib and configuration under /etc.
- Due to different locations of data types, appropriate storage medium can be chosen for each, leading to better performance in some cases
- Shared locations for libraries means not all applications need to bring all of their own libraries, saving disk space and memory resources
- Shared locations for libraries often means applications need to be constantly rebuilt and repackaged to conform to latest library versions to avoid conflicts with other applications
- Packaging is convoluted and usually involves manually writing scripts and metadata files to give all the necessary information to the package manager
- Need to support different package managers due to the huge variety of distributions
A newer approach in app packaging for Linux are AppImages. They combine all the data and executable files needed for an app into a single compressed file that can then be run as-is.
- Almost completely compatible across different Linux distributions
- No superuser rights needed for installing an application (unless an SRP is in effect)
- No standardized way to supply icons – each appimage is left to figure this out and there are many approaches
- A bit more than just downloading is involved – the executable bit needs to be set for each appimage
- A slight performance hit due to compression
Windows 8 / 10 (.appx)
Windows store provided a more user-friendly way of installing applications. Applications would be bundled in .appx package files with a very specific set of instructions. When run, the package would then follow its instructions and drop all the files in their appropriate locations, under Program Files, Start Menu, Registry and so on.
- A standard installer / uninstaller architecture (compared to earlier ways of packaging for Windows)
- Easier or more consistent cleanup due to the standard
- Not particularly friendly towards a developer (amount of documentation, different pieces of metadata needed, still a very installer-like mechanism)
Android utilizes a package format APK that’s based on JAR (Java Archive) packages. It is at its core a zip file with a specific structure and metadata, very much like an AppImage on Linux.
- In many cases cross-compatible across hardware (unless containing binaries)
- Compressed, slight performance hit
- For performance must contain multiple binaries for the different hardware classes
Some platforms have clearly done better in this than others, but as usual the developer always loses: If you want to reach the highest number of people as possible with your application, you’ll end up packaging your application in at least a few different ways.
If you’re using a cross-platform development platform from the beginning to the end you might be spared from some trouble but it’s still good to keep in mind how the various platforms handle their data. Here’s a few things that may help you:
- Always structure your projects well. If there are platform-specific parts, decide early on if you’re separating them by their type, context or platform and stick to that.
- Incorporate packaging early on. Sometimes this might still influence the way you organize the project so it’s better to do that before you need extensive refactoring.
- Try to include all your target platforms early instead of choosing one and adding the others as an afterthought. Develop cross-platform from the get-go instead of “porting” your app. This will spare you from a lot of trouble when making new versions.
- Even when writing to platforms that seemingly let you put your files wherever you want (Windows, Linux) there still is a standard to follow and it’s usually there for a good reason.