Based on the number of requests I received for this article, I have decided to post it. It was written for Object Magazine and published in the March-April issue. It was written in an informal style in keeping with the tone of the magazine, and it assumes an audience more familiar with object-oriented programming than with knowledge base technology. Object Magazine is published by SIGS publications and can be reached at 588 Broadway, New York, NY 10012, USA. Their FAX number is 212/807-9111. ---------------------------------------- INTEGRATING OBJECTS WITH KNOWLEDGE BASES Object and Knowledge Base (KB) are two powerful application development technologies, each solving a different piece of the application puzzle. This article shows the strengths of each technology by looking at their respective origins, the synergy and tension between the two, and how they can be combined for the applictions of the future. Object technology makes it easier to develop, maintain and reuse a wide range of applications. The applications it is suited for are, like most applications, concerned with the processing of data. Object-oriented programming (OOP) provides a better way of defining data and process. Knowledge Base technology also makes it easier to develop, maintain and reuse applications, but KB applications, unlike most applications, are not about applying procedures to data. Instead, KB applications are about dynamically applying decision-making reasoning based on data. Many applications have a need for both, and the dynamic decision-making of KB combined with easy to maintain objects can be a very a powerful combination. To understand better where each is applicable, it helps to go back and look at the types of problems that researchers were trying to solve when they invented both objects and KBs. OBJECTS FROM SIMULATION Objects came from the folks in the simulation labs. They were trying to model real-world stuff, like the flow of materials through a manufacturing plant, or trucks delivering things around the country. To model either a machine on a factory floor, or a truck driving around, requires both data to model specifications, and chunks of procedural code to model behavior. Using conventional programming techniques, the data definition was in one place and the procedural code that modeled behavior was in another. As the complexity of a simulation grew, the difficulty of dispatching the right chunk of process code to interact with the right data at the right time became overwhelming. Good software engineering required better binding of the data and process code that described the objects of the simulation. The result was object-oriented programming (OOP), with its now familiar encapsulated attributes and procedures (methods). Imagine how much easier OOP makes it to build an application that simulates a number of interdependent factories, making and shipping materials between them. Each factory would be an object with its attributes and behaviors (methods) encapsulated within. Its methods would refer to other objects representing the processes on the factory floor. The trucks are also represented as objects, as are the materials they are shipping. With objects, the programmer trying to simulate sending a truck from Chicago to Detroit doesn't have to worry about dispatching the right code that manipulates the right data; he or she simply sends a message to the truck object, saying "Go to Detroit," and the truck object does the right thing. As it turns out, many software applications are very similar to simulations, and, because of this, object technology is a powerful technique for developing them. For example, systems software with its control blocks and processes that manipulate them is a perfect candidate for objects. Accounting software with the flow of control of financial data through accounts is another good example. However, as with most programming technologies, OOP is procedural programming. It is, many would argue, a better way to do procedural programming, but it is still procedural programming, concerned with process and data. KNOWLEDGE BASE FROM ARTIFICIAL INTELLIGENCE Rules Knowledge base came from the folks in the artificial intelligence (AI) labs, who were trying to solve problems that were not easily expressed in process code. They were trying to write programs that mimicked human intelligence. Just as the simulation folks did, they invented different ways to program to overcome the limitations of conventional languages. Of these, the one that has had the widest commercial success is rule-based programming. It is at the heart of all knowledge base technology. Rules are useful for expressing some portion of human knowledge in the form If this situation exists Then take these actions These are called pattern-matching rules. Based on some sensory input, we draw some conclusions or take some actions. Consider the various types of rules like this we all carry around in our heads. If planning to buy cookies in the mid-afternoon, then make sure you get change for the junk-food machine when you buy lunch. If it is raining, then bring an umbrella. If it is snowing, then wear boots. If the keys are locked in the car, then consider using a hanger. If the keys are locked in the car and it's a newer car, then forget the hanger and either call a locksmith or a car thief. If the work is due tomorrow, then plan to stay late. If planning to stay late, then eat more cookies in the mid-afternoon. A rule, such as the one about keys locked in the car, is in each of our heads all of the time, yet it is dormant most of the time. It is only triggered when the situation, or data available to our senses, changes. The rules do not follow any set procedure, rather they are dynamically applied, in the appropriate sequence, based on the available data. To write a program that behaves like a human (at least as far as thinking using just pattern-matching rules) is extremely difficult with a procedural programming tool. Each rule has to be checked each time and all the dependencies have to be checked and the sequence has to be just right and, in the end, you wind up with an unmaintainable pile of "spaghetti code." The problem with writing this type of program is the computer itself. It is designed to do one thing at a time. It is not designed to dynamically respond to data as a human does. The solution? Invent a computer that can respond dynamically. Well, this is difficult, but the next best thing is to build a software simulation of a computer that behaves as we want. This is a piece of software called an inference engine. It does not execute code sequentially. Rather it assumes that a program is made up of a set of independent rules. It looks at the data available and, based on that data, dynamically chooses the rules that should be activated. (It does this using pattern-matching algorithms and sophisticated index structures. The inference engine is, of course, a piece of systems software and, as such, is a good candidate for implementation with objects, but this is not an article about implementing inference engines.) Once a rule is activated, it takes some actions or draws some conclusions that change the known situation and known data. The inference engine then uses this new information to see if any other rules should be activated, and activates them if so. The process continues until stopped or when no more rules can be activated. This cycling behavior simulates, to some small degree, the human reasoning process. Running an inference engine with the rules listed above will result in behavior somewhat like human behavior. For example, the rule about locked keys in the car will remain dormant unless the data indicates the keys have been locked in the car. Also, chains of implications are handled dynamically and correctly, no matter what sequence the programmer coded the rules. In the sample rules, the fact that work is due tomorrow implies staying late, which implies buying cookies, which implies making sure you get enough change at lunch time. An inference engine processing the rules would draw all of these conclusions and present them to the user of the program. Rule-based programming has found commercial success because, besides the sample program that provides advice on weather, keys and cookies, there are many practical applications that can be built with it. For example, a production scheduler routinely makes decisions on the best way to schedule manufacturing based on patterns in changing data about plant capacity and resources, orders, inventory, and changing market conditions. This decision-making process can, and often has been, successfully implemented using rules and an inference engine. Similarly, assessing risk, such as in insurance underwriting or loan and credit approval, is another task that involves recognizing patterns in information and responding to them. Diagnosis of failed equipment, customer service, and help desks are other areas that involve decision making that can be expressed in rules. Frame Data Structures Looking at the sample rules again, you will notice that the rules cannot exist in a vacuum. They all refer to data. The data is used to model the problem domain; the data is used by the inference engine to decide which rules to activate; the data is manipulated by the THEN, or action sides of the rules to represent actions or conclusions. For example, in a scheduling application, the data is used to model the production environment, the resources available, and the order information. In a credit authorization application the data is used to model the applicant's financial situation. In a configuration application the data is used to model the order and part information. It does not take much to realize that the expressive power of a rule-based programming language depends to a large degree on the expressiveness of the way the data is represented. The AI folks figured this out and started developing more and more sophisticated structures for data modeling. They arranged the data in hierarchies. They included triggers with the data that automatically fired off bits of process code associated with the data. They called their data model frames. Frames are in many ways similar to objects-both have hierarchies and both have procedures associated with the data. But the procedures of frames are not directly activated by the programmer, rather they are activated by the situation. Procedural attachments might be defined that automatically perform certain tasks, such as finding an attribute value when none exists, or making sure related attributes are kept in sync when one or the other is updated. This is in contrast to the methods of OOP that are directly activated by the programmer using send commands. Frames also differ from objects in their openness. They are designed to work with rules, and their attributes are always open for interaction with any and all pattern-matching rules. This is in contrast to pure objects in which the attributes and methods are so tightly encapsulated, you cannot tell which is which from the outside. Frames were close enough to objects that most people working with knowledge base began to use the two terms interchangeably, thereby causing great confusion. Pattern-Matching Rules and Objects Still, it seems as if objects, as opposed to frames, and rules are made for each other. Objects are the best way to simulate or model a problem domain. Rules are designed to capture and encode human expertise that is applied to a problem domain. Why not use objects for modeling the domain and rules to represent decision-making applied to the domain? Further, rules and frames were designed for pure decision- making applications. They are not good for building straight- ahead procedural applications, just as objects and other procedural technologies are not good for building decision- making applications. (Rules can be used to encode procedures, and procedures can be used to encode rules, it's just that it becomes impractical after a certain degree of complexity.) Integrating rules and objects in a single environment means a developer can easily encode both the decision making and the procedural components of an application. Well it is a good idea, and that is exactly what the leading vendors of knowledge base tools are doing, but there are some fundamental difficulties in integrating objects and knowledge base that must be addressed. Lets look at some of the key characteristics of each. Objects are a full programming system, designed as much for encoding procedures as data. KB objects (frames) were never designed to be a full programming system by themselves; they were more data- oriented, designed to work with rules and an inference engine to form a complete programming system. Information hiding is a key for objects, and the source of much of the maintainability of object-oriented applications. KB objects (frames) have to be open to the inference engine, so whenever any data changes, it knows what rules to activate. This last point bears a little more explanation, related to the implementation of an inference engine for pattern-matching rules. A naive implementation would check all of the patterns of all of the rules on each cycle of the inference engine. This would be extremely inefficient. A practical implementation requires the building of a sophisticated index structure, called a Rete network, that ties elements of patterns directly to the rules. Whenever a data element changes, it is used as an index into the Rete network to see which rules are made ready to be activated. This means the data elements have to be active, in the sense that any changed values automatically trigger the Rete network. This means, the object portion of an integrated system must be able to support object attributes that are visible to the inference engine. This, of course, means the developer loses some of the strict control over those attrbutes that good object-oriented design dictates. An implementation that supports both KB and objects must be loose enough to allow the developer the flexibility to use the appropriate technology at the appropriate time and still have them work well together. EXAMPLES Let's consider two different example application areas to better understand the relationship between objects and KB. One is taxes and the other is order processing. Taxes A tax calculation follows a definite procedure, and, as such, is a good candidate for being automated using procedural programming tools. Conventionally, there would be data definitions for the lines of the tax forms and other quantities of interest and there would be procedures and subprocedures for filling in the different forms. An object-oriented approach would improve on this design by creating a class hierarchy for forms. The form object would not only contain the data for the form, but the processing necessary for filling in the form. This would lead to a cleaner, more maintainable way of implementing a tax program, but the program is definitely procedural. On the other hand, consider tax advice. A human tax advisor responds to a wide variety of information to make recommendations for a particular situation. The tax advisor draws on a knowledge of tax law, and knowledge of the client's financial goals and situation. The good way to implement a program that gives tax advice is to use rules that look for patterns in the client information, financial situation, tax calculations, and financial goals. Because the rules are not embedded in procedural code, they are easy to write and easy to maintain. This is a different architecture than is used for the object-oriented tax calculation program. What if we wanted to build an integrated tax program? An architecture that tied objects and rules would be perfect. Because tax advice sets the strategy for calculating the taxes, the rule-based portion of the program would be at a higher level in this application. It would gather information from the client and start to decide on the best strategy. Some of the rules would send messages to the form objects to get calculations. For example one of the rules might give the guidelines for deciding whether it is worthwhile to itemize deductions on schedule A. If you own a home, then send get bottom line to schedule A. Other rules would relate to home business issues, and how to handle inventory and expenses, and what to depreciate and how based on situation and goals, and how to deal with business use of a car, and on and on. All of these would be expressed in pattern-matching rules. On the other hand, the work of dealing with the tax forms would be cleanly handled by sending messages to the form objects. One such message might direct the depreciation form to add another item using a certain depreciation scheme. Together, the rules containing advice and the objects describing the tax calculation process would form an elegant system with the best of both worlds. Order Processing Another example to consider is order processing. The entering and processing of orders is procedural and has been automated many times. Objects are good for building this application as orders and items become objects with the procedures that describe their behaviors encapsulated with them. Further, order processing needs to be integrated with inventory, which is quite naturally represented as a hierarchy of parts objects. Consider order configuration, which is not procedural. A person configuring an order responds to patterns in the order based on inventory and the goals of the purchaser. Configuration is best represented by a series of pattern- matching rules that ensure an order is complete. How many people went to computer stores and bought printers for their PC ATs and got home and found the cable didn't fit and needed to make a second trip to get a 9-pin adapter? An order configuration advisor would have rules that ensured these types of mistakes do not happen. Consider also pricing. Many organizations have complex pricing rules that are based on quantities ordered, past history of orders, payment of bills, seasonal specials, etc. etc. This too is better written using pattern-matching rules. So an integrated application would use classes of objects to represent orders and items and parts in inventory. The classes contain methods describing all of the procedural knowledge for maintaining inventory and processing orders. The knowledge of how to configure and the knowledge of how to price are stored in two different packets of rules. The rules match patterns in the attributes of the objects and make decisions on how to add items to orders, and how to price those items. Some of the rules from this system might be as follows. If ordered item = printer then send add item cable to order. If ordered item = cable and machine is AT then send add item 9-pin adapter to order. If ordered item = 9-pin adapter and new customer then don't charge for adapter. SUMMARY There is an obvious synergy between objects and KB, but it must be made clear that object technology is procedural and the dynamic pattern-matching of rules is not. There are some compromises that must be made for objects to work cleanly with KB. The developer needs to be aware of the strengths and limitations of both technologies and use them together to build smarter, more robust applications. BIO Dennis Merritt is the author of Building Expert Systems in Prolog (Springer-Verlag) and a principle of Amziod in Stow, Massachusetts, specializing in Prolog and expert system tools, training, and consulting. He can be reached at amziod@world.std.com