April 11, 1999 - Jack Harich - Go Back
The UHR Technology Grid can be boiled down to the key behaviors necessary to achieve the vision. These behaviors can be implemented in any manner appropriate to your needs. UHR is language, storage, platform, UI and vendor independent. UHR is an "architecture of concepts", not an off the shelf tool. |
Part Centric Microkernel
The first two phases of the UHR Technology Grid are Part Centric and Microkernel. Once you have reached phase two, your entire approach to UHR revolves around a part centric kernel. This kernel is a Plugpoint Framework that serves as the lowest layer for all other frameworks. The kernel is small but contains lots of UHR behaviors, which are:
Microkernel - The microkernel itself. It's high level responsibilities are part organization, part life cycle management, part collaboration, container management, Message routing and container services. It cannot do anything by itself. Think of the microkernel as what makes other wondeful things possible, such as Innovative Visual Tools, Hyper Assembly and the Dynamic Logic Stage. The microkernel was influenced by the rock solid Linux kernel, one of Linux's strongest features.
Flexible Container - Systems are assembled by organizing parts into a tree of containers and parts. A part may "be" a container. Containers are flexible because they allow their parts to be configured, relationships established, services added, custom classes to use for constructing the container, primordial invocations run, etc. Containers can accomplish amazing things. They behave as a standardized mediator.
Flexible Part - Reuse is accomplished by deploying "parts", which are class instances implementing zero or more interfaces the container knows about. Note we do not require implementing a single interface or extending a class. This would be very inextensible. Instead we take a "many optional interfaces" approach. If a part implements a certain interface, the container will treat it appropriately, such as by providing it with its Declarative Knowledge or Container Services. Thus parts can be any class at all. A part can be just a single class or the entry point to a large subsystem. A part must (we suspect) be in the same language as the kernel, but parts can be wrappers for other languages, remote objects, legacy systems, or even other parts.
Domain Neutral - The kernel is totally ignorant of application specific behavior such as storage, user interface or networking. This is a great example of "Less is More". The smaller and dumber the kernel is, the better.
Continuous Evolution - The kernel contains the definition of a system. This definition can be edited while the systems is running or not. Once we have mature visual tools, the norm will be to do nearly all edits while a system is running. This will eliminate the false design/run dichotomy. Gone is the edit, compile, run cycle of old fashioned development. The ultimate goal of Continuous Evolution is "The norm becomes evolving systems as fast as you can decide what to change while the system is running." This is similar to Linux's hot swappable modules, except we get into detailed configuration.
No Code To Assemble Parts - There should be absolutely no code necessary to assemble a system from parts. The one exception we've found so far is the system marker class, which is trivial. The reason we must eliminate code in system assembly is to completely break the chains of bondage that code entails, and graduate to snapping together parts to build a system just like kids do with Legos, an analogy discovered by Michael Ivey.
Declarative Knowldge - This is the most important UHR characteristic. It's crucial to separate systems into "what to do" and "how to do it". Also known as "Parameter Driven", Declarative Knowledge (DK) is the "what to do" and parts are the "how to do it". DK is similar to the role DNA plays in determining a life form's inate behavior.
Parts are reused by configuring them with DK to behave appropriately for that system. The approach taken to DK must be storable, editable, transportable, settable, applyable and standardized, such as wth XML and DTDs. The DK must be passed around inside a system in a manner independent of its storage format, such as the Param object in the BA.
A stored DK structure is a system defnition. A system is that DK plus a kernel and the parts referenced by the DK.
Anonymous Collaboration - The more loosely coupled parts are, the more they can be reused. The principle of Anonymous Collaboration must be supported. In the BA this is done by letting the kernel establish part relationships, letting parts collaborate via Messages and passing only Datatrons between parts.
Infinite Extensibility - The kernel and the systems built with it must be "infinitely extendable" or we will continue to see short system lives, frustrated users who cannot build or customize their own systems and way too many legacy systems. This boils down to you can change nearly anything fairly easily without breaking existing systems. In the BA we accomplish this with Anonymous Collaboration, Declarative Knowledge, a well architected microkernel, and the abiility to customize that microkernel on a per container basis. See Infinite Extensibility.
Note complete infinite extensibility is impossible. We are just trying for 99.99%. Once the visual tools are mature and we have lots of parts, your major system investment is in DK. Well designed DK is part and kernel independent, allowing you to throw your entire toolset away and start on another iteration, without losing your investment in DK.
Replacable Part - While a system is running, it should be easy to replace an existing part with a new part. For example you may want to replace a SocketServer with it's latest version. In the case of the BA this could be done by using ReplacablePart and ReplacablePartClient iterfaces, with a "two phase commit" style replacement. It's possible a kernel modification will be necessary to make this transparent.
Container Services - Containers must offer Object and Message Services. This allows parts to use other parts that are shared so widely they should be architected as services. The services should be somewhat near the top of the hierarchy. When a service is requested, if it's not in that container the parent container is searched, etc, all the way up to the system root. This allows super easy implementation of the Service Architecture Pattern. Note it also allows shadowing.
An Object Service returns a named object on request, much like a Naming service. A Message Service processes a named Message, and is preferred to an Object service due to lower coupling. Both are parts themselves. Remember, in UHR everything is a part. Even the kernel is a collection of parts with a default provided.
Internet Deployable - As software becomes network based, systems need to be able to deploy themselves incrementally and transparently. For example a client needs to be able to launch and run a system via a brower or a bootstrap entry point program. In the BA this is done via the class loader mechanism for parts and Class.getResourceAsStream() for DK. BA systems can be server based and transparently used by TCP/IP clients.
Ease of Use
To achieve the third phase of UHR, Ease of Use, requires fabulous Innovative Visual Tools. Building these requires at least ten times (surprise!) as much work as it takes to build a microkernel, because they are so many, vast, varied and powerful. We must reach Ease of Use to achieve the Conceptual Model of the BA. Sit down and memorize this model to understand UHR from the user's point of view. We are including Parts Management in Ease of Use to simplify this document.
Really good visual tools let users "mentally merge" with a system, just like a muscian becomes the melody and leaves the sheet music behind....
Look and Choose - This means the user can look around and choose what to do. They do not have to memorize anything, unlike the command line, data entry or text mindset that characterizes many less mature tools. "Look and Choose" is called "Explorable" by Microsoft, and was one of the design requirements of Windows 95. For example instead of entering a value you choose it from a dropdown list. The user should never have to enter complex raw data. The user should never have to enter something if a gesture could do it instead. Any mutations they do should be instantly validated. System use should be so intuitive and "learnable" that little or no documentation or training is required.
Hierarchial Composition - User studies have concluded that for high ease of use, the user must quickly develop an intuitive, comfortable "Conceptual Model" of what they are using and doing. For system assembly from parts, we have found a visual "System Tree" approach the best way to represent a system definition. Note the underlying implementation should also use a tree. Hierarchial Composition supports one of the principles of Structured Assembly.
System Tree - This implements Hierarchial Composition and allows the user to transparently manage the underlying storage of the system definition, such as databases and file structures. It should support context menus per part, quick part assembly, visual cues about a system's status, and work closely with the other visual tools. The System Tree is the foundational visual tool.
DK Editor - Most of the user's time will be editing the Declarative Knowledge for parts. It needs to be a smooth, slick, powerful, incredibly easy to use visual tool. It should completely hide the underlying DK implementation, such as the parex format or XML/DTD. It must have Look and Choose, validation as you go, intelligent defaults, undo/redo, drag and drop, online help, DK examples, and the ability to handle thousands of key/values for a single DK bundle. Custom DK Editors per part should be supported. It should allow edits to be applied to the part while the system is running with no more effort than a birthday smile. :-)
Inspector - For fiddling around with a live system, you need to be able to "inspect" any part and see what it can do, what it's state is, and how it collaborates with other parts. The user needs to see and change part properties or invoke any method, even those requiring arguments that are other parts. They need to be able to "explore" a part's objects. This lets the user "look into the system", giving them the feeling they know what's going on. A knowledgeable user is a happy user.
Part Shop - Since the average user will need a minimum of 2,000 parts to create and improve systems, sophisticated Part Shops become necessary. We expect these to be internet based and support inventories of over 250,000 parts. Users should be able to customize their selection of frequently used parts.
Drag and Drop System Assembly - The user must be able to quickly drag and drop parts from the Part Shop to the System Tree, as well as copy and paste containers and parts within or between System Trees. This is how systems are composed, and is the way users think.
Datatrons - A datatron is like an electron. In electronics we have devices assembled on circuit boards, connected by wires. All devices communicate with one thing - electrictiy, which is electrons with a varying signal. A datatron is a pure data carrier with no behavior. All part collaboration can be expressed by parts communicating with one thing - datatrons. These datatrons are standardized data structrures such as tree, rowset, row, stream or array. Think of datatrons as standardized mobile parts.
A Message is a type of datatron. A datatron carries only primitaives, strings or other datatrons. We believe it's possible to specify a small number of datatrons, less than ten, that will suffice for nearly all systems. Datatrons can have events, allowing them to serve as models. If a listener is a schema, we can help achieve "All data structures must be self validating."
Configurable Logic - Declarative Knowledge is "configurable state". As the UHR technology Grid shows, we need to achieve "Configurable Logic" to make the Dynamic Logic Stage possible. Configurable Logic means we can express "how to do it" in a part with DK rather than code.
We have good news here. In April 1999 we achieved the beginning of this goal 2 years ahead of schedule by using simple "commands" in the Modular Screen Subsystem and AutoTest. We can already demonstrate configuring actual logic while the system is running. This is a milestone in the history of UHR.
Other Visual Tools - The above are the core tools and concepts for a minimal first round. After that we will need more, such as wizards, drag and drop GUI builders, personal assistants and modelers. The last is sorely needed. Otherwise you have to buy a third party tool (such as Rational Rose or Visio) and go back and forth from it to your UHR tools. Much better is a integrated modeler for the basic model views of frameworks and systems. Innovation will be required here, because our needs are far different from stand alone, code centric modeling tools.
Living Systems - The idea is that once a system is started it's never stopped, behaving as a life form. The user makes all changes to the system while it's alive, including part replacements. Systems can be put asleep and awakened, allowing easy hardware shutdown and "instant on". Systems can be migrated to another CPU while staying alive. Systesm can have offspring via cloning, which is where many new systems with interesting attributes come from. Living sytsems are composed of living parts that can be moved or cloned from system to system, or Part Shop to system., or system to Part Shop. Visual editors can be included in all this, so that the user's world is completely intact when they return to another session. While this is wonderfully user centric, it's system centric too, and paves the way for the Dynamic Logic Stage which can culminate in systems that emulate learning, growth and life as we know it.
Building Your Own UHR Implementation
Once you understand the UHR Vision, you can start from the Bean Assembler (BA) microkernel, libraries and visual tools, or build your own in the language of your choice. UHR contains lots of subtle concepts. We have tried to document them, but to fully understand them you should closely examine the first iteration, the Bean Assembler. We encourage people to treat this as merely a first iteration example, and surpass it by improving it or doing their own implementations.
Those doing a UHR implementation should probably build the kernel first, and then use it for all further work, including the visual tools. This is much like a compiler that compiles itself. It shakes out your design and implementation quickly, giving you early validation and experience. After all, if the kernel is not the best foundation for your other tools, how good can it be?
You should also pick your implementation language(s) carefully. UHR cannot be done easily without these implementation language features:
- Platform independence.
- Object Oriented.
- Dynamic class loading from any source, including the internet.
- Clean extendable multiple interfaces.
You could consider doing a UHR subset for some situations. Such systems would need a part wrapper to collaborate with full UHR systems.
This document is not complete, because the subject is too large. But is should get you started. Have fun!