Software Composition in COSA (Under Construction) |
||||||
Visual Software Construction
Visual Software ConstructionOne of the nicer things about a component-based visual development environment is that it affords the software composer with a quick and easy way to identify and navigate through dependencies. If two objects are connected, they obviously share a dependency. Double click on an object and instantly access its specifications. Double click on a connector and learn about its type and purpose. Pre-built components can be stored into a keyword-searchable and browsable repository or can be downloaded from the web. Drop a component into an application under development and it automatically and flawlessly connects itself to any other compatible components. Many painstaking tasks can be automated with smart wizards. These can remove the drudgery out of creating all sorts of useful components, not unlike the way C++ templates are used to create new code from parameterized types. Automated programming not only makes programming more enjoyable and faster, it also limits countless opportunities for mistakes. This allows the software designer to spend his or her time concentrating on the application design requirements rather than the complexities of software construction. Visual software tools have been around for some time but they usually come with some sort of algorithmic scripting language and that is their main flaw. Another flaw is the proliferation of icons. In COSA, there are only a few icons and their types are easy to grasp: synapses, cells (effectors, sensors), components, connectors, pathways, etc... The COSA software construction environment is designed to make software development as painless and easy to understand as possible. No difficult language to learn and no code statements to write. If successful, it will open computer programming to a sector of the population that has heretofore been barred from participating: the average computer user.
ComponentsA component is a container for cells, connectors, data, or other components. Components are primarily for the benefit of the software designer and user. Their main purpose is to serve as a vehicle for organizing, storing and grouping cells and as plug-compatible ensembles for software composition. As mentioned previously, the COSA execution kernel does not handle components or connectors directly. The kernel only sees cells, their synapses and their data. In this light, a component should not be seen as a behaving object in its own right. It is more evocative of a microcosm of a larger system, i.e., an enclosed society of simple individuals that communicate and cooperate with each other while performing simple assigned tasks in an equally enclosed environment. Internally, it is an aggregation of pointers and/or lists of pointers to cells, connectors, synapses and other data structures. Note: all illustrations on this site are preliminary.
Basic CategoriesComponents can be divided into two basic categories, low level and high level. A low level component contains one or more cells, at least two connectors (for input and output) and associated data. A high level component consists of one or more components. In other words, cells are not allowed to exist at the same level as components. A component can be thought of as an inheritance mechanism. Drop a component into another and the receiving component inherits the functionality of the first. The figures below show examples of what a designer may see after double clicking on a component. The naming labels are omitted in the figures due to the reduced size. The small blue and red rectangles are uni-connectors. The dotted rectangles represent multi-connectors. Small blue rectangles are female connectors. Red rectangles are male. Components and cells are shown as circles of various colors. All components are pale green. A small blue circle attached to a cell represents an input synapse. A small red circle is an output synapse. Signals always move from the output synapse (red) of one to the input synapse of another. A dotted rectangle surrounding several connectors means that the connectors together comprise a single multi-connector. The actual layout of objects inside an enclosing component is arbitrary and is left to the discretion of the component designer. Note: The distinction between input and output synapses is used to show the direction of signal flow. In neurobiology, there is only one synapse that connects pre and post-synaptic cells. Internally there is only one synapse that connects two cells.
Loop ComponentThe "while loop" component (above left) is a low-level component because it contains only primitive cells. When started, it repeatedly increments a counter variable (the + cell) and stores indexed data (the 50= cell) in memory until either the not-equal (!=) comparison sensor is satisfied or the effectors have run their course. The dashed-line bracket joining the + and the != cells indicates a sensor-effector association. Remember that all effectors are self-activating and that, once started, they repeat their operations up to a prescribed number of cycles unless stopped. When it fires, the comparison sensor outputs a signal that stops both loop effectors simultaneously. The loop component sends an output signal if the comparison sensor is triggered. The loop effectors too, may send a signal but only if they reach their cycle limit (50 and 100) before the comparison sensor fires. The one-shot assignment effector (top left of the figure) initializes the loop on receipt of a start signal and then activates the two loop effectors. The one-shot effector can be connected to as many loop effectors as needed to accomplish the task. Initializing the loop does not have to be limited to one effector. The start signal may be connected to as many cells as are necessary to perform the initialization. Note that even though the word 'loop' is used to describe the loop component, there really is no signal looping going on. That is, no signal is fed from the output side of any of the cells back to the input side. This is because all effectors are self-activating. Additionally, effecting and sensing take place concurrently during the same cycle. This eliminates a lot of loop-related problems since no actions can be inserted between the increment action and the comparison, as is often the case in algorithmic software. If a sequence of actions have to be performed every pass through the loop, then it is best to use two components, one to count the loop and do the comparison using a one-shot effector, and another to perform the required actions. In such a case there is no way to avoid an actual signal loop. Constructing the loop component consists of the following steps. Use the mouse to drag the desired cells and connectors into the component. Each connector is automatically given an ID. It is up to the designer to accept the default or use an existing ID. Click on the data structure to define the operands and constants for the component. Click on the effectors to open up a property box. This will allow you to specify the operands for each effector. Use the mouse to connect the cells to each other as desired. Finally connect the cells to the connectors. Of course, if you already have a loop component in the repository (which is very likely), it is easier to just copy the existing component and modify it to suit your requirements. Most low-level development in COSA will consist of reusing existing components. ChunkingPsychologists have known for a long time that the brain's short-term memory--the one used for remembering in-use information--has a limited storage capacity, about seven items plus or minus two. This capacity can be expanded by a method known as "chunking." Chunking is a form of information hiding whereby a single unit of information is used to encapsulate a recognizable pattern. For example, the following string of 20 letters is hard to remember because it cannot be easily chunked into recognizable patterns:
Compare the above string with this 20-letter string:
As can be seen, the brain can hold more information in its working memory by encapsulating recognizable patterns into individual chunks. COSA takes advantage of the chunking susceptibility of working memory by hiding the underlying details of a program while exposing its logical structure. It extends the object-oriented concept of information hiding to its extreme, even to the level of elementary operations. This does not mean that hidden operations are inaccessible to the application designer. They can be easily accessed by moving the mouse over a cell. The idea is that, once the designer has gained intimate knowledge of the underlying details of a cell, he or she can subsequently recognize its function just by looking at its label or even its location within a component. Exposing the details would not add to comprehensibility. It would only add to visual clutter, not to mention the waste of expensive screen real estate. COSA encourages chunking. For example, an assignment effector may stand for the following operation:
This information is hidden in COSA. Only the cell's label--if any--may be visible. But just moving the mouse over the effector is enough to trigger a pop-up box that automatically displays the hidden operation. For instance, to get a good idea of what our loop component is doing underneath, one only needs to move the mouse over the four cells. Once the details are understood, the information is chunked and the mere visual appearance of the component is enough for the brain to form a gestalt of the entire component. By exposing logical structure and hiding
implementation details, COSA makes it easy to modify or add to an
existing structure. This is one of the main differences between
composing or designing software on the one hand, and conventional
programming on the other hand. A designer can quickly put a prototype component together
by dragging in a few cells into the work area, labeling them and
connecting them. Once the structural design is in place, the designer
can then go in and specify the underlying details. ReentranceThe loop component provides a perfect example of how potential timing conflicts are resolved in COSA. What would happen if the component receives a second start signal while the loop is still running? During development, COSA enforces the Principle of Motor Coordination or PMC which states that a start signal must not follow another start signal and a stop signal must not follow another stop signal. The PMC enforcer alerts the designer whenever there is timing conflict. In the loop component, a conflict would be flagged if the two loop effectors receive a start signal before they are finished. But even without using the PMC, the loop component would not be adversely affected by an out-of-turn start signal because effectors do not react to out-of-turn start signals if they are already activated. Note that, in the example shown, the PMC enforcer would flag a violation if the 50= effector receives a stop signal after running its course. The reentrancy problems that plague conventional algorithmic software are nonexistent in COSA. For one, component self-reentrancy is impossible. None of the component's outputs can be connected to its input because they have different IDs and are incompatible. Even if the software designer could assign the same ID to all the connectors, it would still be impossible to directly connect the output connector of a component to its input because the connection manager would not allow it. Second, if two or more components require the services of another component simultaneously, they must use a message server. The latter places all request messages in a queue to be processed one at a time. If necessary, especially in time-critical environments, multiple instances of a loop component may be used simultaneously. Note: The above does not mean that a recurrent process cannot be implemented within a component or with the use of two or more components. Reentrance is not the same as recurrence. This will be explained further when the quick sort example (under construction) is posted. Stay tuned. Data SharingHigh-level components do not have data at their level. They are just containers for other components. Most low-level components will have a data structure, the properties of which can be accessed by its cells. Components cannot access each other's data. That is to say, a component's data is always private. The only way a component may access another component's data is through an explicit request message. For example, a quick sort component may receive a request from another component to sort an array of integers. After completing the request, the sorter sends a 'service completed' message back to the service requester. The only data that may be shared between two components is message data. Even then, the destination component only has read permission. The primary reason for the strict rule against data sharing is to prevent misuse. It would be too easy for one component to modify a property in another component without the knowledge of the other. This can potentially lead to incorrect assumptions and ultimately to catastrophic failure. In multi-threaded architectures, it is customary to use semaphores and other techniques to prevent two components from simultaneously accessing a data structure. These techniques are not used in COSA because data sharing is forbidden. ConnectorsWe have already seen one form of a simple connector, the synapse. As you know, synapses are used to connect one primitive cell to another. The high level connector described in this section is a mechanism that enforces and enables safe and automatic connections between compatible components. Internally, like everything else in COSA (with the exception of the kernel), a connector is a simple data structure. It contains various properties needed to connect two cells together. But the internal composition of a connector needs not concern the application designer. He or she will be able to connect cells together simply by clicking the mouse on one cell and drawing a line to another. Connecting components will be even easier. Just drop it into the application in development and it will automatically and instantly connect itself, if possible. Uni-ConnectorsA uni-connector is a mechanism that serves as a one-way conduit for one signal at a time. Every uni-connector must have a unique ID number, a gender (male or female), a visibility level, and one or more associated cells. Some uni-connectors may also have an associated message data structure. Only males can be connected to females and vice versa. Male uni-connectors (also called plugs) are signal senders while female uni-connectors (sockets) are receivers. A male uni-connector and its female counterpart share the same unique ID. A pair of uni-connectors is used to connect one sender cell from a source component to one or more receiver cells in one ore more destination components. All uni-connector pairs are of the one-to-many type. The reason is that an input synapse on a cell can only receive one signal or message at a time. Many-to-one connections are possible in COSA but they are created and managed with the help of a special component called the message server. Multiple messages arriving asynchronously must be placed in a queue and wait their turn to be processed. It follows that, while a male uni-connector may be connected to multiple female uni-connectors, the reverse is not true. That is to say, a female uni-connector cannot not be connected to more than one male connector. However, a female connector may be attached to more than one cell residing in the component it is attached to. Multi-ConnectorsA multi-connector is a group of uni-connectors. It too has a unique ID, a visibility level and can be either male or female. However, gender is used only as a way to ensure compatibility between opposite connectors and not as an indicator of signal direction. A multi-connector can have an unlimited number of male and/or female uni-connectors. A male multi-connector is the complement of a female multi-connector. For every uni-connector in a male there must be a counterpart in the female. Multi-connectors are convenient composition aids because, more often than not, components must make multiple connections with other components, usually in the form of two-pin connectors. The component designer may want to constrain a connection so as to require that all the connectors in a group be connected simultaneously. If any of the uni-connectors fails to connect, the connection manager will not complete the connection. Multi-connectors add compatibility constraints and eliminate opportunities for errors. Unlike uni-connectors which are one-to-many, every multi-connector is a one-to-one connector unless it contains only male connectors. VisibilityAll connectors are created with an initial visibility level. A connector is visible only to other connectors residing at the same containment level or below. In other words, if component A is placed inside component B, A's connectors are visible to all components inside B but invisible to all components outside of B. It is up to the software designer to decide whether or not to increase a connector's visibility level so as to make it visible to components above its current level. Note that increasing a connector's visibility level does not immediately make it visible to outside components. It only means that the connector may be made visible to the outside, if so desired. Visibility levels are somewhat analogous to the public and protected keywords in C++. Construction and DestructionEvery component that requires initialization must use a special female uni-connector for construction and a special male uni-connector to signal when it is are ready. The component manager sends a special construction signal after loading a component into memory. The component designer should use construction connectors to string components together so as to achieve the desired order of initialization. Destruction also requires special male and female uni-connectors. Again, it is up to the component designer to make sure that components are destructed in the desired order. After destruction, the component manager deletes the component from memory. MessagesA message is a structure with various fields of data the content and format of which only compatible sender and receiver components are privy to. A message is an integral part of a uni-connector. In fact, they share a unique ID together. All messages must contain at least two fields, one to hold the length of the message and another to hold the ID proper. Some messages, such as the ones used with the message router component, must have two additional fields: one to hold the address of the sender cell and the other for the destination cell. Sending a message is no different than sending a signal. Of course, the sending component should fill the message structure with pertinent data before signaling the destination component. Note that the data structure that represents the message never moves in memory. This makes for rapid message communication. A component must have either read or write permission to access or modify a message. This is enforced by the development tool. It is up to the receiver to act on the message as quickly as possible and acknowledge receipt so as to free the structure for future messages. This is normally done with a two-way connection between sender and receiver, one for sending and one for acknowledgement. If a receiving component expects to receive multiple messages of a given type from several senders or if the sender cannot afford to wait for delayed acknowledgement, then it is best to use the services of a message server. Normally it is best to use messages for asynchronous communication. Since components can share data, they can communicate synchronously using signals. Unique IDsBoth messages and connectors are assigned unique 16-byte ID numbers on creation. Each ID number represents a unique message or connector type. IDs are universally unique, meaning that no two signal or message types can share a given ID. It does not mean that there is only one connector per ID. An ID registry has to be maintained as part of the component repository for easy access to all developers within an organization. Public IDs and their definitions may have to be kept in a registry maintained by a non-profit organization. There are other issues related to IDs that will have to be resolved. For example, a component designer may decide, for security reasons, to keep some of his or her IDs private by not publishing their meanings or the specifications of their associated messages. Or even the ID itself. This way, the ID essentially serves as an unbreakable 16-byte password. SecurityI am toying with the idea of adding password protection to the connectors themselves. That would be in addition to type ID. Of course, if a component publisher declines to publish the unique IDs of a component's connectors, no one can connect to them. However, sometimes a software designer may want to use a known public component while finding it necessary to restrict access to a few chosen clients. Having the ability to add password protection to individual connectors would solve this problem. One of the nice things about not allowing new executable code into the system is that it eliminates a lot of security problems. This is especially true in the age of the internet with thousands of machines are connected to one another. Data Types and StructuresTo be continued...
ServicesMessage RouterTo be continued... Message ServerTo be continued... Cell ManagerTo be continued... Component ManagerTo be continued... Connection ManagerTo be continued... Application ManagerTo be continued... Other ServicesTo be continued...
Component RepositoryThe component repository is a browsable and keyword searchable SQL database. Its job is to facilitate and encourage reuse. After a component has been tested and documented, it should be dropped in the repository for future reuse. The repository comes with tools that automatically searches a stored component's documentation for pertinent keywords. Software designers should make it a habit of searching the repository before creating a new component. Next: COSA Examples
Final note: This page is under constant revision. Check back often and remember to refresh your browsers.
These pages are under continual revision. Refresh your
browser often.
Last Update: 08/07/2002
Send all comments to: louis.savain@sbcglobal.net
©2002 Louis Savain
|
||||||