|« Everything I needed to know about SOA, I learned it at the gas station||How to Run a Chorus.js Orchestration on a Raspberry Pi? »|
There have been a lot of talks in our industry about what software engineering is and how it should be done. For those who don't know, the foundation of Computer Science, and unfortunately Software Engineering, is λ-calculus. If you are not familiar with it, it's an algebra that defines formally how "computations" are performed:
- a variable, , is itself a valid lambda term
- if is a lambda term, and is a variable, then is a lambda term (called a lambda abstraction);
- if and are lambda terms, then is a lambda term (called an application).
If this is not clear enough, here are how lambda expressions are defined and computed (again from Wikipedia's article):
A lambda abstraction is a definition of an anonymous function that is capable of taking a single input and substituting it into the expression . It thus defines an anonymous function that takes x and returns t. For example is a lambda abstraction for the function using the term for t. The definition of a function with a lambda abstraction merely "sets up" the function but does not invoke it. The abstraction binds the variable in the term .
An application represents the application of a function to an input , that is, it represents the act of calling function t on input s to produce .
There is no concept in lambda calculus of variable declaration. In a definition such as (i.e. ), the lambda calculus treats y as a variable that is not yet defined. The lambda abstraction is syntactically valid, and represents a function that adds its input to the yet-unknown y.
Bracketing may be used and may be needed to disambiguate terms. For example, and denote different terms.
λ-calculus comes from a time where the main value proposition of "computers" was to compute ballistic trajectories, decode encrypted message and occasionally crunch a few profit reports.
Times have changed, we now use "computers" for a bunch of other stuff. Anybody who has had to write some code has probably noticed that we typically wrestle with four concepts:
These concepts form an interesting symmetry that spans across four views: physical/conceptual and static/dynamic. The very problem introduced by λ-calculus is that a variable, , is used interchangeably to deal with a type, a relationship or a state, but types, relationships and states are fundamentally different from one another. Great developers will natively sort them out, others will at best create a maze.
Object Orientation, for instance, is just a bunch of actions and types. There is no way to express directly states and relationships. States are systematically reified behind type properties and relationships behind type composition mechanisms (a.k.a. containment). Even in SQL, where relationality is the norm, relationships are "coded" as an attribute of a type. Conceptual frameworks like UML have tried to correct this myopic behavior by adding a layer of higher semantics, but again if you look at the structure of UML, i.e. MOF, it is "essentially" physical (actions ant types).
One could actually argue that the adoption of OO has been so wide spread precisely because it enables to code "what you see" (the physical view). You see a "customer", hence, you code a customer class... right?
Depending on the domain, relationships and states will be more or less important/trivial which will make traditional λ-calculus based software engineering paradigms more or less effective, but thinking that you can translate reliably and consistently state and relationship semantics into actions and types is the biggest fallacy of software engineering and the root cause of pretty much any problem you see today.
Thinking that one can fix software engineering without changing its foundation, or simply by developing higher semantics that suffer from the same myopy, it a bit like a doctor trying to treat a fever with a couple of TUMs.