1/27/00
| Here we present a logical train of reasoning that leads to the core architecture. This is known as rationale, but somehow it seems more profound and personal than that, so we call it philosophy. |
The goal of any artificial system is to provide desired functionality. The goal of UHR is to make that as easy as possible. Put another way, the goal of UHR is to minimize the effort to express systems. Here the word "express" means "to communicate what's necessary to create" a system.
The question immediately arises, what's the best way to do this? Our strategy is:
1. Keep the solution domain independent, so it can apply to any type of system.
2. Allow developers, end users, or systems to express systems.
3. Keep the solution as small and simple as possible.
4. Use reuse as the driver for efficiency.
For clarity and generality, consider a system to be a working universe. The absolute minimum needed to define a universe is:
1. What's in it.
2. How what's in it behaves.
We use Declarative Knowledge (DK) to define "What's in it." We use black boxes full of procedures, aka parts, to define "How what's in it behaves." Parts have state and behavior. DK has only state. It's that simple. The minimum to define an artificial universe (aka system) is DK and parts. So we define a universe by:
DK - What's in it. Declarative Knowledge.
Parts - How what's in it behaves. Procedural Knowledge.
A subtle notion is what governs the laws of behavior for this universe? We see this must be parts, so we introduce some primordial parts that control the behavior of all other parts. In UHR these are called "core parts". For example one core part may know how to read DK and create parts from it. Another core part may handle part bonding, just like the laws of Physics handle molecular bonds. The non-core parts are "domain parts". Since the core parts themselves are part of their universe, subject to the same laws of all parts, we have a self-referential universe of parts.
Just as atoms interact with other atoms via forces that follow laws of nature, so must our parts. Rather than four different forces as in nature, we use a single force for parts - Attractors. Each part has zero or more services and zero or more needs. Each service and need has an attractor. Service attractors attract need attractors. If the attraction is strong enough, bonding will occur, resulting in a link. Once a link is formed, a part with a need can call a part with the linked service. In this manner parts interact with other parts, just as atoms interact with other atoms.
For our universe this gives us:
DK - What's in it. Declarative Knowledge.
Parts - How what's in it behaves. Procedural Knowledge.
Links - The channels that parts use to collaborate.
What moves along those channels? Since we are the creators of this universe, we get to foolishly play God and choose what would lead to the best of all possible worlds. Following Occam's Razor ("Entities are not to be multiplied beyond necessity") we do not introduce a new abstraction. Instead we reuse what we have, DK and Parts. What moves along the links in our little universe? Mobile DK and Parts, which we call Datatrons and Logitrons in honor of electrons, which are what move along circuits. Datatrons are mobile units containing data. Logitrons are mobile units containing logic, aka procedures. By agreement on a small number of Datatrons and Logitrons, a universe achieves great simplicity and Anonymous Collaboration, resulting in high reuse.
Our universe is growing, and now has:
Declarative Knowledge
DK - Stationary
Datatrons - Mobile
Procedural Knowledge
Parts - Stationary
Logitrons - Mobile
Links - The channels that parts use to collaborate and mobile elements travel on.
We're almost there. Study of the universe we all call ours shows it to be heterogeneous rather than a homogenous ball of matter. The matter is highly organized into galaxies, solar systems, planets, etc. Only by first recognizing these groupings and putting them into a logical classification were we able to understand the real universe. Thus we must provide organization for our little hypothetical universe. It should be flexible, domain independent, scalable and navigatible. We avoid reinventing the wheel once again by choosing a physical hierarchy, the same organization that can be applied to any physical universe or collection.
We define the hierarcy in the traditional manner as a tree of nodes. Each node is a containers or leaf. A container can hold other nodes, which are containers and/or leafs. A leaf cannot hold other nodes. Each container has a parent container, except the root container has no parent. There's only one root per hierarchy. The root is a common system entry point.
All stationary entities must have a place in the hierarchy. We have two stationary entity types, DK and Parts. Where should they go? A traditional hierarchy has only containers and leafs, with no obvious place to put DK and parts, unless we do something odd like having both a Part and DK on each node. Since this is not done in the real universe, we avoid doing it in our artificial universe, and so use the rule that each part has it's own optional DK. Now we can say that each node has a part, which is a container part or leaf part. This further divides DK into Container DK and Leaf DK.
Looking closer, a tree is just a set of parent container relationships, while links are part relationships. Thus we have two types of fundamental part relationships, parent and link.
At this point we must allow parts to be reusable, just as molecules can be identical but appear more than once in a system. Since we are pairing DK with parts, and DK is knowledge, we say that DK is the policy a part should follow in a reuse case. Container DK will focus on what's in a container and bonds. Leaf DK will vary per type of part.
We can now say our artificial universe consists of a tree of parts, with the mission of each part optionally determined by its DK. The parts communicate through links formed by attractors and bonding. Datatrons and Logitrons pass over those links. Since our universe is a system, we call the hierarchy a System Tree. Our universe now consists of:
Declarative Knowledge
DK - Stationary. The policy for each reusable part to follow in a particular reuse case.
Datatrons - Mobile. Very standardized.
Procedural Knowledge
Parts - Stationary. Occupies a node in the System Tree.
Logitrons - Mobile. Also very standardized.
Relationships
Links - The channels parts use to collaborate and mobile elements travel on.
System Tree - The hierarchy of container parts making up a system.
This is fine, but to implement it we have language considerations. For example in Java, Datatrons are over 100 times as slow as method calls for part collaboration. We may be able to improve on this, but meanwhile we must introduce one more element to complete our universe, Unifaces and Multifaces. A Uniface is a domain independent single method interface such as:
public interface UF_void_String_int {
public void act(String arg1, int arg2);
}
A Multiface is the same thing with multiple methods. A Uniface is a special case of the Multiface concept. The use of Unifaces and Multifaces allows a large inventory of reusable parts to collaborate anonymously at high speed, with strong typing and concise, clear code level calls. These are strong advantages over Datatrons. Then again, Message Datatrons have the advantage of multicasting, filtering, dynamic routing, etc. We hope to someday get the best of both worlds, but for now we lean towards Unifaces and Multifaces for collaboration.
Which is preferable, Unifaces or Multifaces? We don't know yet from experience, but speculate that Unifaces are, because they allow more atomic rearrangement of a system and part inventory, have a very simple naming pattern, bring services down to the simplest level possible, etc. It's a guess. But one size seldom fits all, so we allow either, and even allow any kind of type such classes. Hereafter we use the term Multiface, even though in the Gen2 core only Unifaces are used.
As a bonus, Multifaces can pass Datatrons, when that is preferred. A good time for the part designer to use a Datatron is when a large number of attributes must be passed at one time. The best example of this by far is DK itself, which can have thousands of nested key values.
Our tidy artificial universe is now complete with:
Declarative Knowledge
DK - Stationary. The policy for each reusable part to follow in a particular reuse case.
Datatrons - Mobile. Very standardized.
Procedural Knowledge
Parts - Stationary. Occupies a node in the System Tree.
Logitrons - Mobile. Also very standardized.
Relationships
Multiface Links - The channels for part collaboration and mobile element travel.
System Tree - The hierarchy of container parts making up a system.
All this implies that all the UHR core has to do is:
1. Provide a plugpoint structure in the form of the System Tree.
2. Allow containers to be defined with Container DK.
3. Allow leaf parts to receive their DK automatically.
4. Do automatic bonding which can be overridden by manual bonds in Container DK.Plus a few more responsibilities based on things we didn't discuss:
5. Provide part lifecycle management services. Otherwise a system can' t be started or dynamically grow.
6. Provide various "hooks" for tools and advanced parts, such as container events.
And that's all. This keeps the core as small and simple as rationally possible.
We are just getting our arms around these, and hope to eventually have a solid mathematical and logical model. Until then, we can offer this list of rules:
- All parts look the same on the outside.
- All parts are treated as black boxes.
- Parts must preserve Anonymous Collaboration via Multifaces, Datatrons and Logitrons.
- Core parts follow the same rules as domain parts.
- Vary reusable part behavior with DK, not inheritance when possible.
There is a certain intrinsic beauty in our artificial universe. We have reduced the problem of system creation to one of knowledge description and reusable procedures, since relationships are defined by DK or Parts. To compose a system, you need these things:
1. The UHR Core, which is a small collection of "primordial" core parts.
2. An inventory of domain parts.
3. Container DK for the root and other containers.
4. Leaf DK for the leaf parts.
5. A pointer to the root container DK, such as a "marker class" or url.
The last is trivial. The first is already done. The second you only have to do once. Thus all one has to do to describe a universe of parts is 3 and 4, Container and Part DK.
Container DK is far, far simpler than code. It has no loops or decision. It has sequence, but only rarely is this important. What little sequence Container DK has is for ordering the parts in a container per the designer's preference, so they can better conceprualize the system of parts. Sequence is also sometimes used for ordering part commands, but this is irrelevant if only one command per container is used.
Leaf DK is just as simple, but varies from part to part. Lets examine four popular system partitions. For UI parts Leaf DK is the most compact known way to describe the UI, with html as the best example. For Business Logic parts Leaf DK is mostly your business policies. For Persistence parts Leaf DK mostly describes the knowledge structure of the application or enterprise. For Inter-System parts Leaf DK describes protocols, locations and policies that allow entire systems to collaborate.
For the two Generation One UHR systems, we saw a ratio of over 50 to 1 for code to DK, excluding the Java class libraries but including the part inventory. This was very good news.
Example - For those not expert in DK, here's an example. Suppose in a dye factory a mixing vat needs to mix a certain percentage of certain ingredents for a certain amount of time at a staged number of temperatures. The Declarative Knowledge consists of the percentages, ingredent names, time, stages and temperatures. The Procedureal Knowledge consists of how to find an ingredent, put it into the vat, raise the termperature, lower the temparature, what to do when a cycle starts or stops, how to mix evenly, etc. The Procedural Knowledge (PK) obviously takes lots of code and/or people skills to do, while by contrast the DK can be listed in half a page. In this case, the ratio of DK to PK might be in the neighborhood of 1 to 1000. The point of this example is to illustrate that splitting knowledge into DK and PK allows the PK to be very effieicntly reused by varying just a tiny bit of DK. This gives systems composed of DK and PK great leverage. The software industry is just now discovering this, as the arrival of XML shows.
Consider that for decades studies have shown the average productivity per developer to be 10 to 30 lines of "code" per day, independent of language used. What do you suppose will happen when for most systems, most parts (this is PK) are already created, Container DK is wonderfully short, and Leaf DK is a piece of cake to create because of the power of Visual Tools?
We've saved some good news for last. Late in implementation of the Gen2 Core we discovered. the possibity of "automatic bonding". It turned out to work. Wow! Basically what happens is parts supply Match Policy for each need. Using that policy, the core checks the container for matching services, and if not found searches elsewhere for a match until found or the search area is exhausted. In this manner parts can define nearly all of their own bonds, rather than that info having to be in Container DK. This greatly reduces the size of Container DK, which reduces the number of lines of "code" a developer must produce per day when working with UHR systems. The result is much greater productifity and lower defects.
Automatic bonding is not a trick, but merely the emergent result of mimicking the real universe, where automatic bonding is the norm. All we've done is introduce the correct abstractions - Attractors, Parts, Services and Needs - to make this happen as easily, fast, correctly and productively as in Mother Nature.
The sudden appearance of Automatic Bonding was a pleasant surprise, and hopefully a confirmation of the correctness of the above design philosophy.