Tuesday, April 13, 2010

Inside-out design : Parts I and II



The topic of bottom-up vs. top-down design has accumulated a lot of baggage since both descriptions of system design were first introduced (1970s). Both are perhaps well understood, or many may assume they understand both. This series of articles introduces the terms inside-out and outside-in to help readers visualize a three-dimensional design (an onion’s layers would be a good example) rather than a two-dimensional design similar to tree rings.

Business software is discovered, not invented. Arguments that computer technology has fundamentally changed business, or even invented it, are exaggerated. The business of banking remains much the same as it was 150 years ago, deposits and loans. Insurance remains much the same, pay smaller amounts now for the promise to cover expenses later. Retailing, logistics, and drafting are also mostly unchanged.

If computers haven’t invented these businesses what can we truthfully assert they have done? We can assert that they’ve helped make humans, both individually and collectively, super human. The way in which software has incrementally accomplished this feat can be described as from the inside-out. This article will elaborate on what inside-out design is, use it as a model for how new software projects should be designed and developed, and describe how inside-out design (IOD) avoids the many shortcomings of alternative approaches.

“We can make him better than he was before. Better, stronger, faster.” 
Introduction to The Six Million Dollar Man

Though banking may be a complicated business, its basic activities are simple. Customers “deposit” money at the bank and are paid interest. Banks pay a lower interest rate on deposits than they earn lending money to other customers.

Perfect Memory

Our first step at creating a super-human banker is to improve their memory—regardless of age. How many customers, account balances, and interest rates for each can a human remember perfectly on their own? Whatever that number is a banker that can remember 100 times more will be more profitable. The banker that can remember 100 times more than that even more profitable. A banker with perfect memory is limited only by his productivity and efficiency—but we’ll address that later.

Perfect memory is what databases provide the banker. A database is capable of remembering, perfectly, the name of every customer, their address, phone number, accounts, account balances, transaction history, and even their relationships to other customers and their accounts.

This is the core of our inside-out design. The business already existed—all we did was discover and record the banking schema into a database.

If nothing else is done, our banker may be better off than they were before. Without any additional features the possibilities are nearly endless. Anything that can be stored in the database can be done so perfectly. Any number or type of account and any number or type of transaction can be perfectly stored and perfectly retrieved.

Much more can be written of the benefits of relational databases, and indeed much already has. Not the least of which include RDB’s basis in relational set theory, referential integrity, and normalization.

But even with mathematically provably correct data, perfect memory can still be tarnished with imperfect manipulation. The next layer will enhance the first with perfect execution.

Perfect Execution

With perfect memory our banker will never forget your name or account balance. They simply record each of your transactions in their database.
If this were a relational database our banker could use SQL. Using SQL they can find your account number using your name or phone number:

SELECT @ACCOUNT_NUMBER = ACOUNT_NUMBER
 FROM CUSTOMER
 JOIN ACCOUNT 
   ON ACCOUNT.OWNER_KEY = CUSTOMER.CUSTOMER_KEY

WHERE CUSTOMER.PHONE_NUMBER = "248 555 2960"

Once they have your account number they can enter the transaction

INSERT INTO TRAN_HISTORY (ACCOUNT_NUMBER, TRANSACTION , AMOUNT)
VALUES (@ACCOUNT_NUMBER, “DEPOSIT”, $100.00)


Depending on how “perfect” their database is, and how many accounts the customer has, or whether they recently bounced a check and must pay an NSF fee, or how accounts feed the general ledger, more SQL will likely be required to keep everything “perfect.”

So even though the banker can remember perfectly what was done they have difficulty remembering how to do it.

Most contemporary relational databases provide a mechanism for building SQL macros or functions called stored procedures. Stored procedures extend the syntax of SQL and a mechanism for storing the function inside the database itself. In this manner an RDB may hide the details of its schema as much for its own benefit as our banker’s. Additionally, invoking stored procedures is simpler than typing all the SQL each time, making it easier for more bankers to use the database even if they must still learn some syntax.

If SQL is the lowest-level language for manipulating relational database tables, or 1st generation language, stored procedures can be thought of as a less low-level or 2nd generation language. Using stored procedures are example above may be simplified.

EXEC ACCOUNT_DEPOSIT(“248 555 2960”, $100.00)

How ACCOUNT_DEPOSIT is implemented is hidden both by virtue and necessity. By virtue because bankers don’t have to remember all the details of an account deposit, and by necessity because such an interface is required to provide perfect execution—the database is always updated consistently no matter who invokes the procedure. Additionally, the procedure is free to change its implementation without affecting bankers as long as the order, type, and number of the procedure’s arguments are unchanged.

The reasons for the procedure’s change are also hidden from the procedure’s users. Its implementation may have changed because of new features or schema change. Regardless the reason, the procedure’s consumers benefit by its improved implementation without needing to change what they already know and the processes they’ve already documented.

It’s worth noting that an RDB that provides stored procedures is very much like an object in a traditional object-oriented point-of-view. Just as objects implement publicly-accessible methods to hide their implementation our banking RDB schema implements publicly-accessible procedures to hide its implementation.

Our banking database’s stored procedures define its Application Programming Interface. Any user can use the stored procedures to affect perfect transactions.

It’s important to pause here and contemplate an important inside-out feature. Any user can use the stored procedures to affect perfect transactions. One banker may be a teller, another may be an ATM, or a Point-of-Service terminal, or still another may be a web page.

Even though our implementation requires applications (tellers, ATMs, POSs, etc.) have access to our database, no other technical hurdle is erected. Any programming language that provides a library to access our RDB is capable of executing perfect transactions. In this sense, the surface area of our system has been increased. We’ve simultaneously improved our system’s integrity while increasing its utility to other languages and applications.

Outside-in designs may approach this differently. It is too commonplace for applications to be designed from the outside-in—designing the user interface first and the supporting infrastructure afterwards. The result, though possibly to the user’s liking, is only as capable as it will ever be. It has only a single interface and its supporting mechanisms implement only that interface's required features. It has little surface area.

So now our banker has perfect memory and perfect execution. In the next article we’ll explore inside-out’s next super-human enhancement—ubiquity.
Follow @TomGagne