About me

Michael L Perry

Improving Enterprises

Principal Consultant

@michaellperry

User login

Approaching an ideal from two directions

The ideal specification is unambiguous. After reading such a specification, the consumer should have no question as to the correct behavior of the system described.

The ideal code is not extraneous. There are no implementation details written in the code that were not part of the problem domain. Such details would not have been described in the specification, and could therefore not be verified as correct. If they can’t be verified as correct, then they must be arbitrary. If more than one arbitrary implementation choice could lead to a correct program, then why must the programmer make the decision? And why must he express that decision in code? The computer could figure it out.

As specifications approach their ideal lack of ambiguity, they remain firmly in the state of having no extraneous parts. The specification doesn’t contain implementation details. The customer doesn’t care how it is implemented. They just want it to be correct, and optimized for cost and speed.

As code approaches its ideal brevity, it remains firmly unambiguous. Since code is executed by a deterministic computer, the computer knows at any point what the program will do. There is no question.

Specification, in trying to become unambiguous, is approaching code. Code, in removing extraneous details, is trying to become specification.

Example: a checkbook ledger

If we were to write ideal specifications for a checkbook ledger, we would use only terms from the problem domain. We would define a transaction. We would say what a user could do with a transaction. And we would describe the reaction of the system to those operations. These statements would leave no doubt as to the correct behavior of the system. For example, we could write:

  • A transaction is a named, dated event that either increases or decreases the balance of an account by some positive amount.
  • A user can create a transaction, giving the name, date, and amount of increase or decrease.
  • A user can change the name, date, or amount of a transaction.
  • A user can void a transaction.
  • The system displays transactions in chronological order.
  • The system displays the running account balance of each transaction, that being the previous transaction’s running account balance plus the current transaction’s increase or minus its decrease.
    • The chronologically first transaction, having no previous transaction, assumes a prior balance of zero.
    • A voided transaction does not increase or decrease the prior balance.

If we were to write ideal code for a checkbook ledger, we would only solve the business problem. Storage, communications, and representation details would be handled by our chosen frameworks. We wouldn’t have to describe how a transaction is turned into bits on the network, nor would we have to generate SQL statements to persist or query them. For example, we might write this code:

Transaction(BelongingTo: Account) {
    Name: string
    Effective: date
    Change: [Increase, Decrease]
    Amount: decimal {Amount > 0.0}
}

Void(Voided: Transaction) { }

Account {
    Transactions {
        Transaction t : t.BelongingTo = this
        where not exists Void v : v.Voided = t
        order by t.Effective
        select {
            t,
            RunningBalance = (prior.RunningBalance ?? 0.0) +
                (t.Change = Increase) ? t.Amount : -t.Amount
        }
    }
}

The code verifiably satisfies the specifications, because it says no more and no less than the specifications do. In fact, besides the syntax, the code is the specification. The two artifacts, each evolving toward its own ideal, have ended up in the same place.

Programming languages of the future

No programming language yet developed is as concise as the above code. But we are getting closer. Modern frameworks raise the level of abstraction to remove implementation details from application code. Languages are moving away from the imperative style and adopting declarative and functional styles.

Today, programs are be specified by a Business Analyst, who is skilled in decomposing and unambiguously describing business processes. And programs are written by developers, who are skilled in constructing solutions from technical components at all levels of abstraction. But when programming languages finally do reach this level of brevity, a new discipline will emerge. Neither skill set will be sufficient to solve business problems with software. One person will create this artifact, an executable specification, using a mix of these two skill sets. This person will possess the mind of a mathematician.