In this essay, I discuss recursive design — an extreme form of divide and conquer in terms of knowns and unknowns.
In my opinion, recursive design — divide and conquer — continues to iterate and never stops.
At some point, the design becomes so stable that it can be shipped.
[This is much like songwriting. One never stops tweaking a song, although committing it to a recording tends to slow down the tweaking. Performing songwriters often perform a song differently than it was recorded.]
unkown |
unknown |
brainstorm |
unknown |
known |
|
known |
unknown |
attack early |
known |
known |
implement |
You cannot know what you don't know (unknown unknown).
Iterate and implement.
As design proceeds, you might encounter new sub-problems. Iterate.
Keep iterating until all unknowns are broken down into knowns, or, the solution is complete.
[Break the problem down into the other 3 categories]
High risk.
Fail early.
If you know how to solve a sub-problem:
Brainstorming is a technique of looking for new unknowns — and then iterating them.
Brainstorming is most often associated with the arts, e.g. songwriting.
Much of current programming is art — creativity that has not (can not) been formalized.
The more you know, the more creative you can be[1].
Implementing is a way to know more about a specific domain.
Static typing is a way to know more about a specific domain.
Coding, currently, involves two activities:
Static typing is, actually, a form of implementation — coding up the types, without coding up the implementation[2].
Haskell, Agda, etc. break implementation down into two sub-components
Some people have a eureka moment when using statically-typed languages — they code up the type system, and, when it passes automatic checking, they write code underneath the type system and "it just works".
Coding, currently, involves two activities:
Writing and checking types is the "thinking" part.
Using type-checking to brainstorm the thinking part is just "divide and conquer". Coding is deferred until the type system has been automatically checked.
The essence of recursive design is to break problems down into smaller sub-problems.
Each sub-problem is broken down — over and over — until all sub-problems can be easily understood and implemented.
The hard part of a problem is the thinking part. The easy part of a problem is writing code after the thinking has been completed.
If a problem seems hard, the problem needs to be sub-divided.
If a problem seems hard, one might be trying to use the wrong paradigm to solve it in.
For example, we currently think that multi-tasking is hard, but most people (not programmers) already know how to deal with multitasking, e.g. music scores, cooking recipes, etc. Are we using the wrong paradigm to think about multi-tasking? The functional approach is useful for one-in-one-out problems[3]. Is multitasking a one-in-one-out style of problem? I find that StateCharts[4] and asynchronous ideas, e.g. SonicPi,[5] FBP,[6] Arrowgrams,[7] etc., make it easier to think about multitasking.
FBP
Sonic Pi
Arrowgrams / Components
https://guitarvydas.github.io/2021/03/16/component-diagrams.html
https://guitarvydas.github.io/2021/03/06/Components-(again).html
https://guitarvydas.github.io/2021/01/16/HTML-Components-Arrowgrams.html
https://guitarvydas.github.io/2020/12/10/5-Whys-of-Software-Components.html
https://guitarvydas.github.io/2020/12/09/HTML-Components-Arrowgrams.html
https://guitarvydas.github.io/2020/12/09/HTML-Components-Handling-Callback-Logic-Explicitly.html
https://guitarvydas.github.io/2020/12/09/Box-and-Arrow-DSL-For-Concurrency.html
[1] Pat Pattison
[2] Divide and Conquer, again. Implementation can be broken down into 2 things - (1) type system, (2) code.
[3] I call this class of problem a "calculator".
[4] https://guitarvydas.github.io/2021/02/25/statecharts-(again).html, https://guitarvydas.github.io/2020/12/09/StateCharts.html
[5] See appendix
[6] See appendix
[7] See appendix