Model-view-controller for chatbot
By: Sean Wu
Tags: Chatbot, Conversational UI

It seems that we have figured out how to build applications with a graphical user interface (GUI). We can churn out GUI apps for different platforms, in different languages overnight. It does not cost that much, even the smaller business can afford to build something respectable. But the same can not be said for conversational user interface applications, or chatbots. The number of usable chatbots is embarrassingly small, particularly given the enormous public interest in chatbots for so long. It clearly costs a lot more to build the conversational user interface (CUI) application than to build its GUI counterpart, so only the businesses with deep pockets can really afford to build some usable one.

But why is it expensive to build a chatbot? It has been argued that missing a high-level design language can be a major reason, since we lost the opportunity to capture the potential issues during the design phase, ended up spending time and effort to build the wrong thing. But that is not the only best practice we forget.

Virtually all GUI applications are directly or indirectly based on a software design pattern called model-view-controller (MVC). Model-view-controller is commonly used for developing user interface application that divides the related program logic into three interconnected elements. It separates internal representations of information and service (model) from the ways the result is presented to (view) and input accepted from (controller) the users. The natural boundary induced by MVC often serves as the basis of the division of labor. The work is now divided into the back-end, the front-end, and UI/UX, with each task performed by people with special skills. This alone already implies greater productivity, but it also produces plenty of other more significant cost-saving opportunities, as we can see later.

A chatbot is also a UI application, so in theory, one can apply MVC to it as well. But in practice, we rarely hear this effective UI idea talked about when we build a chatbot. So it is thus interesting to see what cost-saving opportunities we really missed by not following the tried and true best practice, and how we can apply a similar idea in building CUI applications.

Model, service, or back-end first

Since we moved to the web, the model is often referred to as back-end (and I will use them interchangeably), with view and controller classified as front-end. And today GUI apps are strictly built with separation of the front-end and back-end. The back-end is the central component of any UI application, it directly manages the data and logic of the application. It provides service: functionality or information that can help users. The front-end mainly manages the user interaction, including collecting user requests and rendering the response from the back-end service. And front-end and back-end communicate through well-defined APIs, which allow both sides to develop independently.

Since the back-end mainly models the business data structure and logic, and these usually stay the same regardless of which platform the user accesses your service from. This observation opens up another huge cost-saving: now the same back-end can be used to serve different front-ends, one only need to create the UI part of the applications for different scenarios. This is why your favorite applications are often accessible everywhere: web, android, and ios, you name it. It does not cost that much more once the back-end is in place.

There is thus no surprise that GUI applications are designed and implemented in a back-end APIs first approach. We first figure out what service we want to provide to users and specify the API schema needed to provide these services, then we figure out what front end works best for these APIs. Without the service model in terms of schema, working on the front-ends is simply a waste of time.

Chatbots are initially designed to answer simple information-seeking questions, back-end often does not come up in design discussion then. But even when we extended chatbot’s responsibility to directly provide service, we still rarely practice the back-end service first strategy. This is wasteful because without the service provided by backend APIs, understanding users well alone does not help users much.

Instead of thinking of chatbots as magical conversational AI, we should be more practical, and treat chatbots as just applications with conversational UI. This line of thinking naturally suggests that we take a schema-driven approach for chatbot design and implementation: specify what service we want to expose first in form of its schema, then figure out how a user can access them via conversational interactions. Users do not come to the barbershop for cookies, simply bring the conversation back to the services that we do offer does not hurt the user experience much.

Extracting UI from View

In GUI applications, the view is responsible for rendering the information collecting page and final service result page so that users can engage in the interaction until they get what they want. Through trial and error, people figured out it is advantageous to separate the look and feel (generally known as user experience) from interaction logic. This separation allows the developer to develop interaction logic for different countries (speaking different languages) and demographic market (prefer different theme) in one shot; UI/UX people can design the look and feel, localization team customizes the message for each market segment. By reusing the interaction logic, the cost of bringing the GUI application out to different countries is greatly reduced.

Clearly, it is also desirable for us to build a chatbot that can be deployed to different countries with minimal additional cost. Luckily, simply by separating the script (what we say to users) from interaction logic, both during the conversation and delivering the final result, we can too build a chatbot that shares the same logic but serving the different market in a cost-effective manner. This can be done by abstracting the language-dependent part out from the rest of the front-end, so we can easily fill these parts with script in a new language for a new market.

Separating perception from Controller

The controller is responsible for extracting structured events from user interaction with the application. To make GUI applications serve users in different languages, we define some language-independent events. The same interaction logic can be used to react to these events, if we know the user wants to do something, how he/she express that intention does not matter anymore. The conversion from user interaction to events defined this way is typically handled by some UI library, developers do not need worry where the user clicked, and what does such clicking actually mean.

To share the same interaction logic for a chatbot is a bit trickier. The main challenge is at the preception module that converts user utterance in different language into the same event when they mean the same thing. By separating the understanding part out from the rest of the interaction logic, we can use different language understanding module to convert user utterances in different language into this structured intermediate format. Then we can share the same interaction logic and application logic. We note this preception module requires expertise in natural language understanding, and also machine learning, but there are ways that we can reduce the reliance on this, that we can cover in another log.

For business, building chatbot is an expense that they expect returns. So cost-benefit analysis is always at the core of deciding whether they want to build something. While the benefit of the conversational user interface is undeniable, without greatly bringing down the cost of building chatbots, it will be difficult for many business owners, particularly of these small and medium-sized companies, to justify the expense. If we follow these same engineering principles in building chatbots, we can greatly reduce the time and effort needed to produce a good usable conversational experience, by first enjoying the high productivity due to the division of labor, and then more importantly reusing both backend services and interaction logic.