BrickstorOS Engineering Series: Packages Take Too Much Time
In the last post I talked about complexity of package management, the fact that there are a multitude of packaging systems already and one does not rule them all. The thing that is convenient about packaging for a typical user is the fact that he/she can install something, just to try, evaluate, etc. without much effort. In other words, from nothing to a working piece of software the time to delivery so to speak is short. This facilitates rapid prototyping and increases one’s productivity, etc.
One of the problems package management tries to solve, other than dependency hell that is far too common with tools that depend on lots of libraries and such is reduced duplication, i.e. having 10 versions of same thing, each version perhaps different from the other, or not. We don’t want to have 10 applications with each app shipping ALL of the libraries it needs to run, when 90% of them are used by others. Likewise, we don’t want to maintain 10 versions of a library when really, we should have just one.
Things get more complicated when you have package
pkgC all depending on library
libA, and package
pkgA depends on a particular feature of the library, which for some reason is deprecated. Let’s assume the other two packages do not use this feature. Now, you have a working library, at least for two packages, but not for the third. This is a simple, silly example of what could go wrong, and in the open source world where some software follows more stringent rules than other software this is not an uncommon thing. APIs break, often due to a change which perhaps was necessary but not necessarily well communicated to consumers of the API, etc.
When one builds an appliance, one does not worry about having to run lots of different software or the ability to try new things, such as a new Social Media application, a Productivity application, some new development suite, etc. Appliances are more of a fixed type system which does a very specific subset of things in a well-engineered and maintainable way.
What an appliance like one running
BrickstorOS shares with a personal computer, for example, is dependencies on some core libraries which enable various functions on the system. Most appliances are biased towards system code that is there to support the core functions of the appliance, most of which are not interactive, but often use some of the very same building blocks that general compute systems use. So, the benefits of package management on appliances are less obvious.
So, why do most appliance products out there use package management, and did we just get lazy? So, the answer to this question is a bit complicated, but let’s break it down, without offending anyone, hopefully. I think of an OS with package management as a car, which has tens of thousands of moving parts and sub assemblies. They all take time to assemble and are made work with each other. You can build your own car, but most people decide it is easier and faster to just go and buy one. Enthusiasts often choose to buy and just customize the parts they really care about.
What we said early on, before some more in-depth analysis was what most appliance builders opt to do today. They leverage package management to get things done faster and have the benefit of easy updates, but customize some things to suit their interest best in some specific areas. They give-up control, in hopes that package maintainers don’t screw-up. Is this wrong? No, but there is a sacrifice of control, and thereby system reliability.
Yes, you lose control when you implement package management. You now rely on the fact that someone packaging a potentially critical component will do it right, and nothing will go wrong in the process of installation, upgrade, etc. You are also relying on the fact that thorough testing was done to make sure that under millions of possible permutations of package versions this package will install correctly, not conflict with anything and not break anything which may depend on it.
Think about upgrades. Can you predict every possible way in which package upgrades will happen? Let’s imagine someone updates their system just before a few packages were released, someone else updates their system a little after the release. Can you absolutely guarantee that installation of some group of packages is idempotent, in other words order of installation, i.e. sequence has no bearing on final result? If you can, you are living a fantasy. 🙂 So, now you have two systems that no-longer look identical, even if they did at the factory. The permutations are difficult to predict. What if, a customer chooses to only install some, not all updates, etc. This makes it impossible, in practice, to have any two systems that look identical. It also makes it impossible to really reproduce a customer system in a lab, should you have to debug an issue that customer encounters.
Back to the car analogy. Think about stock car racing: Nascar, and how they build systems (race cars). They opt to very explicitly select parts and while they use industry standard specs, and have to comply with various standards, like we do, they finely control the process, and when changes occur, they are very strictly and meticulously validated. This is what we are doing when we build our OS, all from source, no packages. When anything goes wrong in the build process, we know about it, instantly. There is not a chance that a package will work on some system and break on others. There is simply no opportunity for error here. Granted, just like in Nascar things could go wrong, but they go wrong early, not late. Testing a controlled system is far easier, because you know exactly what went into it. Package management obscures critical knowledge of underlying components and their relationship.
So, we chose to always build a complete system and an upgrade, any upgrade is a brand new OS. There is no patching, no replacement of files, no checksum comparisons and storage in a database, hoping nothing will happen with this data and package repository will not get corrupted, etc. We wanted simplicity and robustness. Building every piece of code and treating each update as a new OS release is simpler, more robust, more controlled and more reliable. We are highly specialized and convenience at the cost of control was unacceptable. This is big topic and an interesting one, I hope! So, more to come.