This spring, at the first edition of Codecamp_Festival, we had the pleasure of having Kevlin Henney with us. You may know him as the co-author of A Pattern Language for Distributed Computing and On Patterns and Pattern Languages and editor of 97 Things Every Programmer Should Know and 97 Things Every Java Programmer Should Know, but in this keynote, he talked about his take on what’s essential in software development.
So, without further ado, let’s jump into Kevlin’s countdown:
5. Five orders of ignorance
What is learning? Learning is knowledge acquisition, it’s knowledge communication. There is something that we do in software development that gets classified as knowledge work. It might sound crazy at first, but, at a deeper level it is true that that is what you’re doing in a code base. Quite literally, a code base is a codification of knowledge, it is a codification of the knowledge of the understanding of the domain, of the problem and of the solution and how we can bring the two together. You are constantly learning and you’re constantly trying to communicate through the code and this is done collaboratively, as a team.
In other words, a code base is effectively a collaborative knowledge exercise. So this takes us in a very different direction, thinking about code as just being about solving business problems or code as a kind of a product. It is in fact a collaborative knowledge exercise. Grace Hopper said that programming is more than an important practical art. It is also a gigantic undertaking in the foundations of knowledge, similar to applied philosophy. So if you’re looking for something extra to put on your business card and you’re thinking software engineer or full stack developer is a bit boring, applied philosopher is way cooler.
The five orders of ignorance, written by Philip Armour present an interesting way of thinking about what it is that we do, organizing our knowledge into different zones and classifying the nature of what we know:
- lack of ignorance or the known knowns
- lack of knowledge or the known unknowns
- lack of awareness or the unknown unknowns
- lack of process or the unknowable unknowns
- meta ignorance
Meta ignorance basically means you don’t know about the five orders of ignorance but we are already solving that problem as we speak.
The known knowns are what you know and you can demonstrate. It is a very simple statement. It can be very much like knowing a programming language to a level of competence, or a library, or a domain.
The known unknowns are like how you know you can’t speak a certain foreign language. There are things that we don’t know and we know that there are boundaries. Now, the interesting thing is, we already have a bias at this level, but this is the level we’re comfortable estimating at. We’re kind of comfortable estimating some of the things that we know we don’t know, but we make them a little less important because, if they were important we would already know them.But at least, you’ve acknowledged that you know that you don’t know something, that there will be work that you have to do to achieve that knowledge.
The problem is that most software development does not happen in zero and one. It doesn’t happen just with the known knowns and the known unknowns. This is where we walk into the unknown unknowns. You did not know that you did not know. How do you plan for that?
What we can do is increase the probability that we will discover the unknown unknowns.
This is where things like bugs live. This is where assumptions live. This is where you thought you knew something and then, one day you wake up and realize you were wrong.
Let’s get back to bugs because they will affect a development process. Whether they are
small bugs or larger issues of development, they are very difficult to anticipate. It is like somebody today asks you how long is it going to take you to fix the bugs that you’ve put in the code next month. The whole point about this level of knowledge is that it’s surprising even when you’re expecting it. Assumptions are very curious pieces of knowledge because they are discovered mostly by contradiction. Normally you discover you have an assumption when it’s wrong. You don’t really discover it when it’s right.
The last one, the unknowable unknowns: it means there is nothing that you can do to find out something before it happens, before it can be known.There is no amount of testing or code review that can be done to discover something sooner. How on earth are we supposed to
anticipate the future? Humans struggle with the future that is why we have come up with ideas like road maps. It is a very popular business metaphor and it’s found its way into software development also. We have product road maps, architecture road maps. They are a great idea but you need to understand what a roadmap is, because people are using it wrong. Simply because in practice there is more than one road. Why would you have a road map with only one road? What is the point of a road map with only one road? That’s just an itinerary.
The whole point about the future is that there are many roads. What you need to show people is this is our current thinking, based on our existing assumptions, we’re going to take this path but you know there’s another path here and there’s another possibility.
This also has important implications for the way we prioritize requirements. There is this mantra in the agile community, to prioritize by business value. I have some very bad news for you, it can’t be done. You do not know the business value of something, until it has been built and shipped and used. If you knew the business value of something in advance, that would completely transform the nature of markets over the planet. The future is not knowable before it happens. You cannot prioritize by business value because it violates the laws of physics. You can prioritize by estimated business value, but that’s different. Never confuse an actual with an estimate.
So, in conclusion, what we find out from the five orders of ignorance is that we demand and we’ve been given rigidly defined areas of doubt and uncertainty. These are embedded into the fabric of computer science.There are formally undecidable things, there are things that cannot be determined.
4. The PDSA Cycle
First off, I’m not going to say you must follow this cycle religiously.
As Andy Kinslow pointed out, the design process is an iterative one. It’s a learning cycle. You don’t learn all at once. You are gathering your knowledge through a cycle of expectation and experimentation.
So, the PDSA cycle has four stages:
- Plan: here’s the thing we’re going to do, the thing we want to explore, a hypothesis or set of hypotheses that we want to examine. That’s what we’re doing every time we build a piece of software, or we want to make it faster, or optimize it.
- Do: the problem is historically a lot of plan driven approaches have stopped here. We do a lot of planning and then we do an awful lot of doing, but there’s no cycle
- Study: We should take the feedback. Learning involves a corrective cycle, it involves reflection study
- Act: and then comes the response: here’s what we’re going to do based on what we now know
Now, you may find there are variations of this and you shouldn’t make them rigid. You can do these concurrently, they blur together, but all four of these activities should be present.
What’s difficult is that the Act and Study parts of the diagram are hard to see. It’s very easy for you to see when people are doing planning, planning has an output. Whether we talk about
a plan for how we’re going to build something or a plan in time of who’s going to do what. And you can definitely see a result of doing. But what is the result of studying and acting?
It’s almost invisible, yet so important. It doesn’t have immediate consequences, it has long term
consequences which is why the last two parts of the cycle often get ignored. You learn by finishing things, so this is how you increase the probability that you will find the unknown unknowns.
3. The three questions of Architecture
There’s a lot of different ideas about what we mean by architecture and Martin Fowler captured this quite nicely by saying it’s a term that lots of people try to define with little agreement.
We don’t have a true definition, but Martin observed that architecture has two common elements: One is the highest-level breakdown of a system into its parts, the other, decisions that are hard or expensive to change.
I don’t generally go for the first one, as people will often put up a powerpoint diagram and say this is our architecture. The one thing I can guarantee is that if somebody puts up a diagram and says this is our architecture, then it is not their architecture. It is a view of their architecture, a representation of their architecture but it is not the architecture. It normally involves a bunch of boxes with relationships, it often misses out things like time, it misses out smaller details that are actually going to determine how the system fits together.
The three questions of Architecture are from a book by Paul Dyson and Andy Longshore and they offer this simple idea that an architectural definition is something that answers three questions:
- What are the structural elements of the system?
- How are they related?
- What are the underlying principles and rationale that guide the answers to the previous two questions?
2. The two questions of quality
How do we know that something is good? That depends on the nature of the thing. If it’s food,
then we have a very specific way of describing what we personally, individually find as good.
But if we are dealing with a software structure, we often talk in terms of problems and how to solve it.
The book I got the two questions from is Times we’re building by the late Christopher Alexander. In it, he originated the idea of patterns that eventually made their way into software. The book was actually about buildings but he defined some really interesting ideas about patterns.
We know that every pattern is an instruction of the general form:
Context → Conflicting forces → Configuration
If we’re dealing with code, it might be you’re working in a particular programming language and there are lots of threads. You’re working in Java, it’s a multi-threaded code base, all of the code is in a single executable. That context is very different to when we are running a JVM system where there are multiple languages in use, executing in different processes and we are using HTTP to connect things with a whole load of JSON thrown between them. Both of these are statements of context as well as statements of connection and composition.
Moving on to conflicting forces, it relates to what it is that makes the problem you’re experiencing a problem.What is the difficulty that you’re having.
And then configuration. Do not confuse that with the idea of configuring an application or the
configuration file or anything like that. This means configuration as in what solution structure do you propose to solve the problem that you’ve got.
Alexander said: We say that a pattern is good whenever we show that it meets the following two empirical conditions:
- the problem is real
- The configuration solves the problem
This feels really obvious, painfully childishly obvious, which is why it’s so powerful. Because
this is actually not really about patterns, it’s about design. It doesn’t matter whether it recurs, it doesn’t matter whether this is an idea that we can use elsewhere in different forms, it is an understanding of design. We are solving a problem in a particular situation and we have a particular solution.
The first question would be, is the problem real? Use this as a review question, because sometimes the answer might surprise you. For example, I asked a team I was consulting a few years back, why did they use XML in their project, and their answer was that they didn’t know..everybody else was using it. It was completely inappropriate for the class of software they were dealing with and just because everyone else was using XML and they hadn’t used XML yet, and wanted it on their CV, they ended up not solving a real problem.
We are very good at solving imaginary problems because software development is a creative profession, therefore we have great imaginations and the more creative you are, the more extra stuff you end up solving.
The second question is, does our solution solve the problem? Again, that’s a really simple idea. You have to check if the solution you came up with actually fits the problem. Go Back to the PDSA Cycle. You’ve got to study and then adjust. If we proposed a solution, did it actually work?
Whenever you are making a decision about your practices, your designs, your code and you perceive there’s two different ways to go, ask the simple question: am I solving a real problem here, have I understood it well enough and does the thing that I am suggesting actually solve it.
1. Have more than one idea
Nothing is more dangerous than an idea when you have only one idea. This is not just good for software, this is actually quite a good way of looking at life. Sometimes we get really attached to
a particular design approach and that becomes the only way we see the world.
We need more than one idea to experiment. If you only have one idea, it’s a start, but you need to get to at least two and preferably three. Because then you can evaluate by comparison. You have different hypotheses to entertain. If you can think of only one way of doing something then maybe you haven’t understood the problem enough.
So this this is a really important thing, even if you believe in a particular practice or coding approach very strongly, always take a step back and look for other approaches, see what else is available.
You can check out the entire presentation on our YouTube channel.