Common models can be didactically useful even if they are, basically, not correct. That’s how I feel about Lehman’s “Programs, Life Cycles, and Laws of Software Evolution,” published in IEEE Vol. 68, 1980. The “laws” themselves — reinterpreted to death1 — are neither surprising nor axiomatic today.
One of the models Lehman uses to construct his laws, on the other hand, is a didactic gem: his hierarchy of program complexities (S-, P-, and E-programs).2
Here’s a very condensed version of those concepts:
Class | Characteristic | Example | Characteristics |
---|---|---|---|
S | Specified | Solution to the classical travelling salesman problem | “Programs whose function is formally defined by and derivable from a specification.” |
P | Abstract | Simulation game where the player directs virtual salespeople | “It is a model of an abstraction of a real-world situation, containing uncertainties, unknowns, arbitrary criteria, continuous variables.” |
E | Reflexive | Program for managing real salespeople | “The program has become a part of the world it models, it is embedded in it.” |
Section II of the Lehman paper — “Programs as Models” — includes extended examples of each category. Of course, the categories aren’t unrelated! Basically “all large programs (software systems) will be constructed as structures of S-programs,” Lehman explains.3 There’s an analogous compositional relationship between P and E:
At the complex end, we aren’t typically cobbling several independent P-programs together to form E-programs. Instead, think of E-programs as P-programs in the real world. For example,
As a product with users: through use, it generates new problems, desires, and requirements in the market it addresses. In other words, organizational composition.
As an evolving system: it reflexively influences its own progress from P0 → P1 → ⋯ → Pn because each version encourages or discourages subsequent versions. In other words, temporal composition.
In the second sense, technical debt is a self-contained E-program problem: the code you write today impacts your program’s viscosity — its resistance to change — but also determines the nature and urgency of future changes. Managing tech debt well requires foresight.
Almost by definition, useful software engineering contributes at least indirectly to some E-program, “mechanize[s] a human or societal activity.”4 Even really simple programs — basic Unix commands, for example — are E-programs by nature of their widespread use.
In fact, E-program-style problems are so ubiquitous we should question Lehman’s trichotomy. Are they really a distinct kind of program? Or should we focus on E-programming as a verb instead, a way of forecasting-despite-reflexivity in S- and P-programs?
E-program skills are not underrated, but they are under-discussed.
Randall Koutnik suggests we replace traditional SWE levels with terms for the kind of work we do. In this model, we develop autonomy rather than seniority. You started as an “implementer” of concrete specs, became a “solver” of more loosely-defined problems, and finally grew to be a “finder” of problems to solve. Sounds familiar? That three-stage development corresponds to the kinds of thinking required by each of Lehman’s program classes.
Koutnik level5 | Koutnik role | Lehman program class |
---|---|---|
Junior | Implementer | S-programs |
Regular | Solver | P-programs |
Senior | Finder | E-programs |
You can think of promotion between the Koutnik roles as the combination of two things:
For example, promotion from “Implementer” to “Solver” requires that you can decompose P-programs into S-programs — complex problems into simple behaviors — and that you can effectively implement those decomposed elements. Per the diagram above, “decompose” typically means functional decomposition.
Promotion from “Solver” to “Finder” requires breaking E-programs down into P-programs, preferably for delegation. The two kinds of E → P composition I described have inverses:
Temporal decomposition
Organizational decomposition
Setting aside my specific examples, decomposition from E- to P-programs means determining what problems to solve in a reflexive E-program environment, where the problem you solve today determines what new problem you’ll want to solve tomorrow.
“Temporal” and “organizational” aren’t an exhaustive list of E-program (de)compositions — shoot me an email if you think of another. No matter what source of program-reflexivity you focus on, you’re likely to wind up with a focus area more actionable than the typical Regular-to-Senior values (e.g. unspecific “leadership”).
To engineers: your workplace might encourage you to cede exercising foresight to your Product or Engineering Manager. Don’t! These are important aspects of your craft; engage them, even if you don’t have the autonomy to act on your own predictions. Engage them out of self-respect if nothing else.
In the early stages, earning engineering autonomy means writing the P-program you need today. Later, it’s about navigating the E-program you’re building indefinitely. Don’t miss the forest for the trees.