Paul Hammant's Blog: The Principles of Containment
Claim: The thing doing the containing can see the component it is containing. The latter really only suspects it is contained, and cannot casually reach the container to interact with it explicitly, unless the container configured it to do so. Thus, there is an implicit sandboxing at each container/contained boundary. When I say each container/contained boundary I suggest that these should be nestable and each contained item be further restricted without knowledge of its nesting depth.
I have four exhibits I can think of:
Exhibit 1 - Dependency Injection
With friends, I wrote PicoContainer in 2003. It was the first constructor injection container for Java. I’d been a junior contributor to Apache’s now defunct Avalon container for a couple of years before. Avalon introduced “Inversion of Control” (IoC). I hate the word ‘framework’ in conjunction with DI. That’s because you could instantiate as many wholly separate containers as needed, register components (or other containers) into them, and by default, none of those contained things had references to the container that contained it.
Dependency Injection is a more of a thing for Java and C# than it is for Ruby or Python. Of course Java runs in a Java virtual machine, which is a process on an OS, and we historically had container concepts with EAR and WAR file deployments, that were a massive mistake for Sun in the opinion of many.
Note that JavaScript has DI too, first introduced by AngularJS. Not quite the same as the DOM is wide open to lots of hackery. At least, inside the “same origin” policy.
Exhibit 2 - Virtual Machines
Think VMWare, Amazon EC2 instances, or the equivalent Digital Ocean (etc) things. Each needs a wholly-separate Operating System, and shares CPU, RAM and networking infrastructure with sibling VMs, but can’t casually discover the siblings, or reach into innards of the containing host operating system. The technology on the host that manages the guest VMs may expose/configure file mounts, incoming ports/sockets, and graphical resources, but the directionality is clear. Each VM can host a number of processes as a normal machine installed OS would have. VMs don’t normally configure/restrict outgoing IP addresses/ports, but they should be able to.
Exhibit 3 - Docker style containers
[ I was as the CoreOS sponsored Tectonic Summit in NYC Monday and Tuesday this week ]
Not to be confused with VMware style VMs, though they often go together. A host machine (physical or virtual) mounts a container with minimal (shared) operating system resources. It feels like a regular operating system, but conventions apply, and the contained is limited to a single application/service. Typically, that is a limit on the number of larger processes running. Say one ideally, though again that is really only a convention. As before, the container knows about the contained, and the contained is limited in what it can connect to (files/dirs, incoming and outgoing network connections). Deployments focusing on this style of container, always use less resources that deployments resting on VM solutions (above).
Exhibit 4 - UIs
It is less obvious here, but a visual rectangle of a UI that contains many smaller rectangles most likely guides the layout more than the contained guide the layout of the container. Maybe the container queries the contained about preferred size and all that. This is all about the ‘V’ in MVC (Model View Controller), and the M and C aspects are entirely different programmatic constructs. As you’d expect, all bets are off if there is absolute positioning going on.
There are strong component models like Java’s Swing framework (which Netscape donated to Sun in 1997 or thereabouts). The principles of containment are almost never fully realised though, as the view assembly code can navigate casually to its own container and tinker with it, or sibling components/containers.
Even for Flash applications in web-apps (seemingly a rectangle in a rectangle), the principle of containment was weak as a technology called LiveConnect allowed the Flash doohickey to reach back out into DOM of the container, although maybe the same origin applied. Flash is dead anyway, and nothing programmatic has assumed its place in the world of browser plugins.
4.1: The web specifically
What a disaster. As with fat UIs the components in a browser tab can interfere with each other, regardless of the visual containment intentions. This is so bad today that you can’t have rectangles from modern web microframeworks (say AngularJS, Angular(2), EmberJS, and React) share space on the same page and have easy isolation. It just breaks as the monkey-patching of bits of pieces of the DOM to get things working destabilises things. Say AngularJS inadvertently disables EmberJS, or vice versa, or each effectively kills the other. You have to revert to Iframes to guarantee isolation, and that is quite heavy with big aesthetic downsides.
I say disaster because it is 2016 and we are 25+ years into the web and this should have been solved many years before. <div isolate>..</div> is what we needed, as well as a mechanism to declare inputs and outputs of the contained, and wide support for a HTML-import. Note: <iframe> specifically has had a ‘sandbox’ feature since HTML v5 and in mainstream compatibility since 2014.
Circling back to Dependency Injection - this pattern/practice simplified the construction of non-visual parts of the UI. It is a trick though, as the IoC can be subverted within the DOM. Components/Services/Directives can gain a reference to their implicit containers after a few lines of JavaScript.
Maybe in another decade the DOM will become a better container/contained facilitator.
Exhibit 5 - Java Virtual Machines
(added in April 2021, previously hinted at in the diagram above)
The JVM has the ability to carve up classloaders into hierarchies and within that attach different security managers allowing for:
- implementation hiding
- different permissions files, outgoing site access, incoming socket listening, etc.
Classically, big server technologies like J2EE servers used this to allow some form of multi-tenant capability. Such servers could host multiple apps and protect them from each other in terms of data/method access. Those servers couldn’t so easily protect each app from others in terms of CPU or RAM limits and that would also speak to the principles of containment.