In a previous blog post, we mentioned that an algorithm is a recipe that explains to the computer how to get a task done. Sometimes we need to be bossy and tell it exactly how to do its job. Algorithms implemented by components like Decision Trees, are called “procedural”, because we describe the actual procedure and process of how to do things. Other times we can be more liberal and give an overview of the task, leaving the machine decide how to execute it. Those algorithms, implemented by components like Situation Sets and If-Then Rules, are called “declarative”, because we only declare what the task is, and the machine knows how to do the particulars itself.
NLS has both procedural and declarative components which can be used almost interchangeably to achieve the same result. Both styles have their pros and cons; with procedural logic we have much more control over how our questions are asked and the overall user experience of our applications, but procedural algorithms are much harder to maintain and extend. It is much easier to update and extend declarative algorithms, but as a trade off, we hand control of question order and user experience to the NLS engine.
The beauty of NLS is that you can use the two styles together in the same application, and the inference engine knows exactly how to combine them to reach the end goal. This is what we call in the NLS realm “Hybrid Reasoning”.
Since the two styles are equivalent, the question that baffles most Studio users (and in fact, the vast majority of programmers out there) is when to use a procedural component, and when to use a declarative one. We already mentioned a good example of procedural and declarative logics that have almost equivalent semantics; decision trees (procedural) and if-then rules with situation sets (declarative). Recently we added a “hybrid” component called Question Flow that is both declarative and procedural in its own way. Question Flows are similar to decision trees in that the Author has complete control over how and when questions are asked, but they are different in that they still allow NLS to determine the best way to set values for particular variables.
Declarative logic might sound like the answer to everything, but (maybe unfortunately) it isn’t. Letting NLS decide when to ask questions is very convenient when the order in which they are asked does not affect the user experience negatively. For example, suppose we build an NLS application to decide whether our clients are exempt from a particular tax withholding, and we chose to implement the logic using purely declarative components. Depending on how the rules from the Treasury Department are structured and how we chose to implement the corresponding if-then rules in NLS, the behavior of the application at runtime might dramatically change. Assume the rules are very simple:
- If you work in the government, you are exempt
- If you are male and over 65 or under 25, you are exempt
- If you are female and over 60 or under 30, you are exempt
By implementing those as NLS if-then rules, and putting a goal in “exempt”, NLS asks us whether we work in the government before potentially asking about our age and gender. Because we, as human beings, give particular meanings to the variables “work in the government”, “age” and “gender”, we might find it awkward to be asked information about our job before our personal information. Moreover, the runtime experience will be different for users, depending on their particular circumstances. This dynamic nature makes it sometimes harder to train people to use NLS applications.
There really is no recipe for creating the “right” NLS application; simply a few rules of thumb.
The most difficult question to answer is when to use procedural, and when to use declarative logic. There are a few deciding factors we can keep in mind when authoring an NLS application that will simplify the thought process a bit.
Form of knowledge
It’s true that if-then rules and decision trees have (almost) equivalent semantics, but it’s really hard (in computer science, we call it “undecidable”) to decide whether we can turn a set of if-then rules and situations into an equivalent decision tree and vice versa. If the knowledge we want to represent in the NLS application comes in the form of a complex flow chart, a decision tree or a question flow is the obvious way to go. If, on the other hand, the knowledge comes from a government ruling (in which most often the language follows a common pattern of “If condition then action”), then using if-then rules and situation sets is much easier.
While authoring an NLS application it might be possible to identify portions of the knowledge we need to represent that are best implemented in a specific way. In such cases, it is highly recommended to do so, since NLS really favors such “hybrid” designs.
User Experience
As mentioned in the example of the Treasury Department tax ruling above, in many cases it is desired to control the order in which questions are asked, because it makes sense to do so given the meaning we give to each particular variable. This makes the user experience feel much more natural, and the fact that most of the NLS application is deterministic allows us to train people to use the application much easier. These cases are the bread and butter of procedural logic.
Data Collection
For applications targeted at a large audience, it is usually a good practice to gather data for later off-line analysis. Those applications (or at least, a portion of them) need to be deterministic, because we want to make sure we collect the same data for each usage. Hybrid designs, like Question Flows with otherwise variables and if-then rules are ideal for these situations; we can represent the “data collection” part of the application in the procedural logic (Question Flow), and continue with representing the core reasoning with declarative logic.
Personal Taste
Last but surely not least, there always is a matter of personal taste in developing NLS applications. We are all different people who think differently about problems. As a consequence, our brains reach a solution for each problem in a different path. NLS is flexible and dynamic enough to accommodate many different schools of thought with respect to how an algorithm might be expressed.
The (somewhat surprising) conclusion, is that there really does not exist a “recipe for recipes”, a pre-defined, standardized way to develop all NLS applications. It’s just like we all think about problems and their solutions differently or take a different route to the grocery store than the one our spouse takes. The exciting part is that NLS allows this flexibility, so that each Author feels comfortable to enjoy developing NLS applications their own way.