8.3.0.5

Lecture 3: Analysis and Design Principles

Today

Lecture

In this course, we will practice the most fundamental aspects of software development, borrowed from across the spectrum of ideas.

The Abstract Idea

If these principles bring back memories of the design recipe for programs, especially the one for interactive programs, you are a reflective programmer and on your way to growing into a sw architect.

Step 1 Understand the system: its elements and its context.

Start from a thesis and formulate it as a concise phrase. Collect ideas around this phrase, going further and further away from the core, until you know that every extension of this "spiral" points to elements that are way beyond the desired software system.

Now you have a complete picture of the elements of the desired software system and its context.

Draw a boundary between the context and all the pieces that belong to the system as a whole.

Step 2 Find the stimuli and determine appropriate responses.

Software systems are inert. Some event activates it. You know some examples: left swipes, right swipes, mouse movements, key strokes, temperature readings, changes to a camera’s lens, etc.

The event takes place in the context and a “message” about event crosses the boundary between the context and the system. Once stimulated, the system computes. The goal of the computation is to compute a response. Sw Devs call the path from the stimulating event to the effect of the response on the context a use case. (They also speak of a stimulus-response system.)

Your job is to find all—or at least all critical—use cases.

Step 3a Identify software components and their possible interactions along use cases.

Every use case relies on some forms of data and consists of distinct computational steps. The two aspects give us insight on what the key components of the software system are and how they interact. Distinct use cases may use the same component, sometimes in the same way, sometimes in other ways.

A component encapsulates knowledge; interactions between components are about knowledge exchanges, as in, one components “knows” some information that another one needs to make progress.

The word “interface” here is not to be confused with Java’s interface; there is only a loose connection. You will represent knowledge as data. The demand for interactions dictates the shape of the interfaces of the components.

Step 3b Identify different computational concerns.

The components for one and the same use case address different concerns. Separating out different concerns is important because each of them may evolve in different ways over a system’s lifetime.

To identify different concerns, inspect the interactions among the various components:
  • Some interaction can be incidental, meaning if they fail the system will serve its primary purpose.

  • Some interactions rely on whimsically chosen forms of data; this is especially true for distributed components.

  • Similarly, distributed interactions must settle on some protocols, but the logic of the communication remains completely unrelated to the protocol.

There are other concerns (security, privacy) that may show up in a system design, but for an abstract discussion, the above should suffice.

Step 4 Order the use cases according to importance.

Some uses cases are essential. Others are cosmetic. And the rest of them exists somewhere in between. The ordering should take into account the different concerns; logical concerns should trump communication concerns.

Build the components for the most important uses cases first. Remember to build the components in a bottom-up manner. That is, start with those that can be tested independently, then build the components that rely on the first batch and so on.

Step 5 Iteratively refine the prototype.

Once a prototype can be demoed and satisfies “customers” (your boss, actual customers, focus groups, etc), it is time to deal with additional concerns for existing test cases or additional use cases.

Example: Grocery Store

Imagine a small grocery store that wants to deploy an “information management system” to improve the efficiency of its operation.

This problem is old, basically solved (though improvements will come). Over the past three decades, sw devs have injected software for “points of sale” stations (cash registers), inventory management, accounting, etc. You have been to grocery stores and have interacted with some of that kind of software. Now let your imagination roam.

Here are some things to consider from the original store:

  customers

  customers enter

  customers exist

  customers pay

  

  cash-register personnel (incl. baggers)

  cash register

  prices for items

  payments,

  receipts,

  transfer of money to banks

  (possibly automated) bank teller

  bank accounts

  

  shelvers

  shelves and shelving

  pricing of items

  

  shelvers

  storage room

  transfer of goods to shelves

  

  truckers

  trucks that carry groceries

  transfer of good to storage room

  

  managers

  inventory inspection

  low-inventory alert

  ordering

  contact to whole sellers

  whole sellers

  

  accountants

  accounting

  -- customer accounting

  -- bank accounting

  -- whole-seller accounting

  -- employee payment

So now we can identify a bunch of use cases:

  use cases:

   customer wishes to pay for a cart of purchases

   inventory manager must check status of goods and re-order (if necessary)

   accountant needs to balance books and pay bills

   ...

  customer service is most visible; speeds up checkout (perhaps)

  ... connect to accountant

  ==> two important classes of "clients"

Let’s study cash register use case:

  customer -> PoS -> Debit Card -> bank -> ackn

                  -> Printer -> receipt

                  -> Inventory -> alert

Each of these pieces needs interface capability to serve this use case.

  Debit Card:  check (connect to bank) -> acknowledge sufficient funds

               transfer funds -> acknowledge payment

  

  Inventory:   removed goods from shelves

  Printer:     list of goods bought, total, receipt of funds

Example: Game System

Probably skip

Imagine a small circle of hacker friends who play the Take 5 game. They have decided to automate it so that they compare their AI hacking skills. They settle on some programming language and decide to implement a framework into which they can plug their AI players and run games and entire tournaments.

Then they decide that they actually hate the chosen language. Nobody wants to program a player in it. They are okay with writing whatever software is needed to make it all work out. Otherwise they will use TCP to connect independent processes to run their players and communicate with each other. While they are at it, they decide that they are going for a distributed version, allowing them to connect their players from home without leaving the comfort of the great indoors.

  elements:

  

  referee

  players

  cards -> points, bull points

  rounds

   game

    initial setup

    turns

  simplest use case consists of 2 steps:

   everything needed to set up a game and play a turn

   - ref hands cards to players

   - every player returns one card

   - when the ref as a card per player, it flips it

  

   ref requests card from player , plus optional positioning

   - executes the stack manipulation:

     - player may receive a stack of cards

  

  Player:

   receive initial hand

   decide on which card for initial stack

   take turn

What does it take to describe the interface.

  take turn -> current stacks

            <- one of: card with position or card (accept bull points)