(If you’d like to see the video, click here)
Earlier this year I was invited to be a speaker at SCNA 2012. At the time I was thinking a lot about quality and about the learning and growth process of developers. Back in March I helped launch the Florida arm of 8th Light, and now had several apprentices and craftsman under my mentorship. I noticed that when we did exercises where we let the code build incrementally – such as using Test-Driven Development – it ended up quite a mess during the process. Why was that? The code was clearly telling them what…
And then it hit me. The code was talking to them, but they couldn’t hear it. Or understand it.
The idea of code talking had been planted in my brain by Scott Bain and Alan Shalloway of Net Objectives. They introduced me to the patterns work of Christopher Alexander which stated that patterns aren’t recipes to be applied, but rather inherent in the problem itself based on the forces at play. For example – what’s the difference between an Adapter and a Façade? An Adapter is when you need an external class to be an explicit part of an existing class hierarchy. A Façade is used to simplify an interface your system has to work with. They both are implemented in similar ways – by wrapping an existing class – but the forces they resolve are quite different. As such, Adapting a class whose interface you need to simplify may be a sign that things aren’t quite as you think they should be.
But this idea that patterns are inherent in the problem itself – how do you teach that to beginning developers? That question led me to look into the way that we teach people programming languages as a whole. If you look at most any book, tutorial or webcast about a language, the writers tend to start with syntax – “Here’s what a loop looks like. Here’s how we do closures and lambdas”. Outside of “Hello, World” you have to muddle your way through syntax first, and then try to think through how to apply it to your real world situation.
Second Language Acquisition
Through lots of reading and research, I came across a model which seemed to explain why the above approach to learning programming was not ideal. And it came from a not-so-unlikely source: second language acquisition. It turns out that when we want to learn a second natural language – like German, Japanese or English – we don’t start by asking what nouns and prepositions are, and how to conjugate verbs. We start by transference – applying knowledge about existing situations to learn how they are expressed in the new language. For example, when I travel internationally I make sure to learn how to say 5 things in the native language – “Hello”, “Goodbye”, “Please”, “Thank You” and, most importantly, “Do you speak English?”. When we went to Germany for three weeks several years ago, I extended that by learning conversational situations such as being in an airport, asking where a potty was, etc.
This way of learning is captured in a model called the BICS/CALP model. This model lays out two key stepping stones for language acquisition. The first, Basic Interpersonal Communication Skills, establishes the skills necessary for social interactions. The second, Cognitive/Academic Language Proficiency, covers the skills necessary to succeed in academic or cognitively challenging situations. These skills, along with examples, can be seen in the chart below:
Another interesting thing came out of thinking about acquisition of development skills in the same way we look at acquiring a second language. Specifically the idea of dialects. Even if one does learn “English” or “Spanish” there are lots of local dialects and slang which can still trip up a non-native speaker. Similarly, in programming we create our own dialects. We tend to codify these through documents like Coding Standards, but also can be the mindset and approach to the task at hand. For example, taking a language designed around an imperative programming paradigm – such as Ruby – and applying principles and ideals from a different paradigm – such as logic or functional programming – we end up with a hybrid approach which may not fit the specifics of “by the book” teaching.
But thinking about dialects exposes the root of the problem of starting with syntax – even if one does learn the syntax, there is no guarantee that’s going to be the right one for the team or project they are working on. We need a different approach to bringing people up to speed. Luckily, we already have the tools, and we have a model we can use, so let’s put it all together.
The Foy-Z Model
One thing that really struck me about the BICS/CALP model was the idea of multiple baselines. We tend to give developers the ideal that if they have a REPL and 10,000 hours, they’ll be experts. And while 10,000 hours is an important metric (even if it seemed like I said it wasn’t in my video of the talk – it was a bad segue into the ‘C++ in 24 hours’ slide), it doesn’t give us enough information. Specifically – at what point can we begin introducing a developer to production code on a project? How do we help her get up to speed as quickly as possible?
I began thinking about what would establish a “Basic” baseline and an “Advanced” baseline given the constraints of the BICS/CALP model – specifically – how do we start with something that is cognitively unchallenging and provides a lot of context? Once that is mastered, what would be the next step of providing reduced context but still not being cognitively challenging? This led to the creation of the following model:
In this model, we start with Katas. Katas are exercised which are designed not to be challenging to solve, but to provide a test-bed to practice tools and techniques. They are the perfect fit since we have a lot of context (we understand the problem innately) and they aren’t cognitively challenging. We can simply say, “I know this is how I would approach the problem – how do I express that in this language or this dialect?”
For example, if we wanted to print “Hello, World” to the computer screen, the thought process could look like this:
- English: “I need to tell the computer to print the words ‘Hello, World’ to the screen”
- Ruby: “I can print to the screen using
putsand specify a string by putting it in quotes, so
puts ‘Hello, World’”
- Java: “I can print to the screen using
System.out.printlnand I have to pass to it a string to print. I can specify strings by putting the words in quotes, so
System.out.println(‘Hello, World’). Oh, I guess I have to end every statement with a semicolon, so
Once we have a grasp on transferring situations we already understand to the language, we can move to Koans. These provide an understanding of the Syntax of the language. For example, the Ruby Koans specify things like “about_hashes” and “about_nil”. We aren’t being cognitively challenged, since we are just following the guidelines in small steps, but we don’t have as much context because we may not completely understand nil.
Working through Katas and Koans establishes a baseline of knowledge for the language or dialect. At this point, we can begin to introduce more cognitively challenging situations, but provide them with a lot of context. This would typically be pairing on a new feature, or pairing on providing production support for an application. The developer is now having to really think through the application of the language, but has the context to see how other people have done it in that project.
Finally, they can begin to understand and listen to what the code is saying. This requires cognitively challenging work with little context. After all, if something is telling you to extract it as a method because it would resolve a force at play – you have to have a lot of inferred context and thought in your head to pick that out.
Over the next couple of weeks, I’m going to be publishing some additional articles on the implications of this method, how things break down in the lines, and diving deeper into some of the concepts like intermediate katas and listening skills for code. In the meantime, your feedback is more than welcome and encouraged!