Computer software deals with two kinds of information:

  1. data
  2. control.


Separation of Concerns

See S/SL (in References) for an example of a data-less language.

Locality of Reference

Information leaks are currently called “dependencies”[^locality].

An insidious form of information leak is the use of functions!

Scoping (Nesting)

In computer science, it has often been the case that problems have been solved through the use of nesting - aka scoping.

Structured Programming

Structured programming prescribes nesting of control-flow as a solution to the problem of spaghetti control-flow.

Global Variables

The problem of global variables was solved using nesting.

The “real” problem is one of spaghetti dependencies. How to stop programs from becoming “too large”?

Object Oriented Programming

OOP is a solution for structuring data and divorcing data from implementation details.

Inheritance is a useful way to organize data.

Inheritance is a poor way to organize code.


Syntax is, currently, used for dealing with control-flow descriptions.

Two languages for any program -

  1. a data description language
  2. a control-flow description language

Pattern Matching

The trend in FP is to use pattern matching to separate control information from data information.

Pattern matching is well-understood, albeit under a different name - “parsing”.

Denotational Semantics

Denotational Semantics is the field of describing programming languages using functional notation.

Control-flow, in Denotational Semantics, is most often handled through the use of GOTOs (rebranded as CPS, first-class-functions, continuations, etc.).

Data Flow

“Data flow” refers to a style of control-flow, not to data structuring.

FP requires that all inputs arrive at a component (a function) at the same time. FP assumes that there is a single happy path.

Control Flow

The current model for control-flow - syntax - is based on assumptions related to 1950’s computer hardware - e.g. a single CPU[^cpu] and expensive memory.

Deep Recursion, Long-Running Loops


Programmers conflate the various uses of state and lump them together.

I discuss this further in,-Analysis-of.html.


I discuss StateCharts further in and

Note that many “successes” in programming have been built on top of the state paradigm, e.g. operating systems, YACC, LEX, REGEXP, etc.


Threads are more like assembly-level operations provided on a single CPU than a high-level concept useful for programming distributed systems.


See the References section for S/SL - a dataless language that was, ostensibly, used for constructing compilers (aka “big” programs).


The problem with GOTOs was not the GOTOs themselves, but the unstructured use of GOTOs.


Components are scalable only if they are not inter-related.

Scalable components cannot have dependencies on one another.

Type Checking

Currently, most PLs provide a handful of hard-wired types and a way for programmers to define further types.



Input Validation


The fact that three forms of type checking exist is a tell that the concepts of type checking are non-uniform.

Absolute Naming

Most PLs create names that are absolute and global to the whole application.



At present, I believe that dependencies are the first-order problem.

dependency debt.

Visualizing Dependencies

I believe that diagrams show dependencies more readily than textual code.

Little Things

The Little Things matter.

Asynchronous Components

Software components are asynchronous by default.

Synchronous components are the exception, not the rule.


Software components “live forever” (like web servers).


Software components can be supplied inputs at different points in their lifetimes.


Software components can produce outputs at various points in their lifetimes.


Exceptions are not exceptional.

Exceptions produced by components are the same as all other outcomes produced by components.

The problems and the solutions dictate which outcomes are considered to be erroneous. Software Architects design solutions that produce the desired outcomes, picking from a multitude of choices. Few problems have exactly one solution - it is the Architects’ responsibility to make vaarious trade-offs and to make the design clear to readers.


Software components have input and output ports.

Most current PLs have APIs that imply synchronous operation.

One Universal Type

Components are plugged together port-to-port where ports have a single, universal, simple type, e.g. a message.

Types checking is done in a pipeline, from simple to more complex.

Not all software components need to fit this simple - one-in-two-out - model.


Components are built in layers.

No layer contains more units than can be comprehended, e.g. 7±2.

Components can, themselves, contain layers, recursively.


Long running loops and deep recursion are not allowed.


Diagrams are a way to visualize multiple outcomes.

Diagrams are a way to show nesting and locality of reference.

Diagrams can visualize information leakage.

Diagrams make it difficult to draw leaky components, especially when everything (e.g. function calls) is made explicit.

Example Diagram Scenario

A software component is represented as a box.

Software components are asynchronous.

Lines represent message flow paths.

Software components contain input and output ports.

Input ports are small green circles.

Output ports are small yellow circles.

A Dispatcher routine invokes ready components in a random order.

Relative Naming

All names are relative to components.


Components have 5 namespaces:

  1. inputs

  2. ouputs

  3. contained components

  4. connections between components

  5. other


A component refers to a component that is contained in it by using a name (e.g. “inner”) or and index (1, 2, 3, …), for example:


Likewise, it can refer to a named input “in” as, for example:


See Also

Table of Contents