October 25, 2006

...Learn TDD with Codemanship

Strict vs. Pseudo-Evolutionary Design

From both a theoretical and a practical perspective, I find it useful to draw a distinction between strict evolutionary design and pseudo-evolutionary design processes.

As a design strategy, one of the limitations of evolution is that it doesn't work for end products that are irreducibly complex. A toaster oven works as it is. If we remove a key component, it stops working, for example. Functionally, we could not evolve useful precursors to a toaster oven that are "almost toaster oven-y", or "slightly more toaster oven-y than the last one".

And functionally, software either works or it doesn't. A function that adds 2 + 2 either returns 4 or it doesn't. If it returns 3, we don't say it's 75% correct. It's 100% wrong. And in that sense, we need to ask ourselves if "evolutionary software design" really is evolutionary, strictly speaking.

We could apply strict evolution to a fuzzy design variable, like - just off the top of my head - Normalised Distance from the Main Sequence (D').

Given a design where classes are distributed among three packages, we can calculate the abstractness and instability of each package, and therefore the balance of the two variables for each package. D' is a number between 0 and 1, where 0 is best and 1 is worst, and 0.50 would be slightly worse than 0.49.

Design Generation #1

We can move classes between packages randomly (mutation) and recalculate D'. If D' is lower, we keep that class where it is, otherwise we move it back to where it was (selection). Then we use the existing design as the base for the next generation (reproduction) and randomly move another class. If we repeat this cycle enough times, we may well discover the optimum value of D' across all 3 packages, which is incredibly difficult to do by hand, even with just 3 packages. (Of course, we might also stumble across a sub-optimal local minimum, but that's another story.)

Design Generation #2 - Average D' has decreased because of the random move of class G from package P3 to P2

We might then apply the same evolutionary process of design optimisation to multiple design quality variables, and on a larger scale. But the process would be essentially the same.

In a process of pseudo-evolutionary design, such as Test-driven Development, we still move through a solution space which - in this case - is defined by the programming language as the set of all possible programs that can be written in that language. We make small additions and changes to the code, and the complexity of the solution grows as we seek feedback with each small adaptation we make. What distingushes the process from strict evolution is that there isn't a continuum of "better" or "worse" that we can use to compare two solutions to each other - not functionally, at least. It either does what's required or it doesn't. But pseudo-evolution tends to succeed for much the same reasons that strict evolutionary design does - in so much as it breaks highly improbable solutions down into much more probable chunks, and for that reason it deserves the moniker "evolutionary design".

But I think it helps me to make a distinction when I'm thinking about functional vs. non-functional requirements.
Posted 14 years, 2 months ago on October 25, 2006