MV to the web – Part 1
A lot of BASIC developers still want to get to the web, but they aren’t sure what’s required. Let’s work it out here. This is Part 1 of 3 blog/articles that will help to get you started.
Let’s begin with a quick definition of terms:
- CUI : The Character User Interface is your 80×24 screen accessible through a terminal emulator.
- GUI : Any Graphical User Interface including browser with HTML, browser with Flash or Silverlight, a mobile device, or thick-client application.
- Thick-client : Software installed on a PC or mobile device, written for the specific OS.
- Thin-client : Software deployed at run-time to a client, usually through a browser. A client is “thin” if it is merely intended to accept input and render output while leaving most or all processing to a remote server.
- BUI : I coined this term for a Browser UI to easily distinguish thick from thin apps and to further separate browser apps from other GUIs, including web services and now mobile apps (which can be thick or thin).
- API : An Application Program Interface is a defined set of functions which makes software accessible to an unknown client for as-yet unknown purposes.
- Web Service : This is a set of back-end rules and a middle-tier to access them. There is no User Interface, only an API and now a means to access that API.
- Business Rule : This is a segment of BASIC code that accepts input values, processes them in conjunction with other data in the DBMS, and returns simple or complex output values. In other environments this is also called a Stored Procedure.
Let’s also establish up-front the premise that tools are irrelevant. This includes languages, frameworks, vendor-provided connectivity libraries, and third-party “Integrated Development Environments” (IDE). All of the tools we’ve seen in this market do exactly the same thing. There is a server component, a middle-tier, and a client component. The tool providers place varying degrees of emphasis on each side. Some tools are better in some areas, worse in others. They have varying pricing models, and it’s up to the consumer/developer to decide if the new convenience is worth the price. What I want to talk about here is not what these products do, but the basic functions that need to be done. From here people can decide what they can do on their own, what they want to buy, and what DBMS tools are adequate for specific jobs.
What’s so different about code for CUI and GUI?
The first important concept to understand about the difference between CUI and GUI code is the basic mode of input and output.
The CUI accepts input from the keyboard in a terminal emulator. Each key is sent to the server and processed by one or more INPUT statements which may accept all characters, or a limited number of characters. As keystrokes are processed they are usually echoed back to the client. There is a round-trip on every keystroke. For output using a CRT statement, the @() functions convert column/row specs to an escape sequence for the specific emulation in use by the client. The emulator accepts the stream of characters and takes action to position the cursor at a specific location.
As indicated in the definitions above, there are many kinds of GUI. Some accept and render data via HTML. Others not. In a first attempt, one is tempted to strip out the INPUT and CRT statements, and then to customize BASIC code to work with specific client types. For example, a customer master inquiry program might be modified to parse an ID from an HTML Input tag, and to return data wrapped in HTML tags. Unfortunately that means another effort is required to re-purpose the code for a different GUI.
The better approach is simply to create a single code set that is completely client-agnostic, where the input and output mechanisms are unknown. In this pattern, all data is expected to come in through variables which are themselves populated by unknown entities. If you think about it, the only custom code you want is the code that parses and renders data, not the code that processes and returns data.
So the goal for all of your code is two-fold: To strip out the CRT and INPUT statements, and to modularize the code so that source data comes from outside and results are returned back to whatever called your code. This isn’t tough because you’ve probably written routines that are intended to be run by a Phantom process where there is no UI. These background processes get their data from “somewhere”, they do what’s necessary, and they return results by writing to a file or generating a report to a printer. Except for diagnostic code these routines should never have CRT or INPUT statements – and this applies to your GUI code as well.
“I have a Lot of code, where do I start?”
The first step is to identify which processes should be GUI-enabled, and when. In many cases only the CFO or other decision makers will actually be seeing a GUI, so the only target may be management reports. In other cases management wants all inquiry programs to be in GUI, but they understand that data entry done in-house can be done much faster in a character interface. The rule is to not “throw out the baby with the bath water” – don’t put a new user interface on screens that no one will use. Sometimes the goal is in fact to GUI-enable all screens, but reasonable, phased deployment schedules must be planned.
I have a program in front of me. What do I do with it?
I’m going to describe this in a pattern which works outward from specific detailed functions, to subroutine items that contain them, to a larger system of subroutines. In another article I’ll talk about connecting to your now GUI-ready code from outside – though really this has been the ongoing theme for this blog for a few years, so anything I have to say on this topic now won’t be new.
The next step to putting a GUI on an application is to modularize the code. Most Pick BASIC code is procedural code – that is, the code is written in the order that processes are expected to happen. For example:
CRT @(0,10) : "Enter Country ": @(-4) :
READ C.REC FROM F.COUNTRIES,COUNTRY.ID ELSE
CRT @(0,23): "Invalid, try again":
CRT @(30,10) : C.REC<1> ; * Show the country name
GET.PHONE: * …
Let’s go back to the fundamental difference between CUI and GUI. The CRT statement immediately sends output to a terminal emulator. We don’t leave this program to do that output. The next INPUT statement also assumes a direct in-line bond with the UI. This is not the case with GUI. For real GUI applications, you never hold a program open for execution while the user is operating on data. The CRT and INPUT statements are related to I/O and the READ statement is considered a Business Rule. I/O and rules never flow like that in a GUI. Each of those functions, Input, Rules, and Output, are processed as separate and unrelated events by different code. So the structure of this code must be modified. For example:
VALIDATE.COUNTRY: * Subroutine assumes ID value is already available
COUNTRY.NAME = ""
ERR = ""
READ C.REC FROM F.COUNTRIES,COUNTRY.ID THEN
COUNTRY.NAME = C.REC<1>
ERR = "Invalid Country ID, try again":
VALIDATE.PHONE: * …
Now, the job of this business rule is to return the name of the country, given an ID, or to return an error message. The user interface has no idea how the data is being validated, but it knows that it will get either data or an error message. It is the job of the UI to accept the input and to render the result. This is no longer the job of the BASIC code on the back-end. This business rule has no idea what kind of client is invoking its functionality, where that client is, or what languages were used to create the client.
Once your code is modularized in this way, you can use it with any GUI, Web Service, device, or even a CUI. Your first step in moving to a new paradigm should not be to look for tools. It should be to modularize the code that you have so that you can use it with any tool. For this, no purchases are required. No skills are required beyond those you already possess. You don’t need to learn a new language or hire a new programmer. No new connectivity is required.
In my next article in this series, I’ll discuss how to setup your now modular subroutines with an API so that they can be used in a multi-tier environment, accessible from any client, using any connectivity tools or technology.