Summary:
Cory Foy uses more than a decade of experience with agile and lean development to help developers create cleaner code, and also be able to know—or "hear"—when their code is unhappy. In this interview, Cory shows why constantly learning and evolving your language skills is so important.
Noel: I love that your upcoming session is titled "When Code Cries: Listening to Code." What in the world makes code cry, and what does crying code sound like?
Cory: The talk started off from an insight while teaching a junior developer. A key insight from test-driven development is that it isn't about the tests, but about the design that the tests enable to emerge. But I found that junior developers were struggling to get that clean code to emerge from the tests. What I struggled with was why that was. The code was clearly telling them what it wanted to do....
And then it hit me. The code was talking to us, but they couldn't hear it. Not from lack of trying, but because they couldn't understand the subtlety of the language. And I imagined this piece of code trying desperately to tell us what it needed to do but not being able to. And that picture was very sad in my mind.
So crying code looks like a mess. Because we couldn't hear what it was trying to tell us it needed.
Noel: In what other ways does code talk to us? If it's not "crying," what else can our code tell us?
Cory: Like many others, my initial exposure to the idea of design patterns was from the "Gang of Four" book. But I was lucky enough to work alongside of Alan Shalloway, who has a different view of design patterns than many others I had worked with. He went back to the seminal text on patterns: Christopher Alexander's The Timeless Way of Building. Alexander refers to the idea that things can be "alive" based on how they respond to the pressure (or forces) put upon them. So the patterns are solutions to recurring problems within the context of these pressures.
In other words, design patterns aren't mere recipes that we implement, but inherent in the problem we are trying to solve, and the pressures of that solution. We don't put them in—we get out of their way so they can come out.
Ultimately, programming is about communication—which is why we call them programming languages. But part of that communication is staying out of the way of the emergent design inherent in the things we build. So, if we're listening to our code, we can tell that something isn't right—that we're doing the wrong thing. We often call this "intuition," but I think a large chunk of intuition comes from practice of hearing what the code is saying.
Noel: I also really liked where in the abstract for this session, you say that you can "help code to come alive by naturally resolving the forces that are present in the problems you are working to solve." How is this done?
Cory: As I mentioned above, Alexander talks about the idea of things being "alive"—that is, how well something resolves all of the forces and pressures at play. Let's imagine we have a collection of objects and we need to loop over them. One way would be to use a traditional for loop:
collection = [Coke, Pepsi, Dr. Pepper]
for(i = 0; i < collection.length; i++) {
print collection[i];
}
This code sets up a variable ("i"), initializes it to 0, and then loops while i is less than the length of the collection. During each loop, we get the item in the collection that corresponds to the current position and print it out.
Now, look at this code:
collection = [Coke, Pepsi, Dr. Pepper]
collection.each do |item|
print item
end
I don't have to explain what this does. For each item in the collection, we print it.
Both snippets of code work. They loop over the collection and print it out. And, in that sense, they are both good code. But if we consider the other pressures at play—communicating with other developers, seeing duplication, understanding the domain—the latter code clearly wins. It "feels" better because it resolves the pressures for us better. This is the idea of code that is alive.
Noel: I recently read some really great tips in regards to design patterns. Jim Bird suggests things like don't use patterns you don't need or don't fully understand, and don't expect them to be recognized and understood by future developers. I was curious if you had any other tips when using design patterns, especially with the goal of keeping your code happy.
Cory: I don't say I agree with Jim's post. As I mentioned above, patterns aren't something you apply, but instead recognize within the solution. So they are there, whether we explicitly code them or not. If I do something like this:
print "Hello, World!"
I theoretically have the world's smallest model-view-controller. The model is the string "Hello, World!" The view is whatever we are printing to with the command "print." And the controller is the program which houses that statement. What Jim is referring to would be someone taking the canonical pattern of MVC and creating a 12-class monstrosity just to print "Hello, World!"
In that context, the best thing we can do as developers is keep learning and evolving our language skills. My Foy-Z model talks about how we evolve those skills. But even once we have the ability to handle code in a cognitively demanding-reduced context, we still have to work on understanding nuances.
To summarize: Design patterns aren't a panacea. They are a guidepost while we learn what is going on. Or, as Alexander says, "At this final stage, the patterns are no longer important; the patterns have taught you to be receptive to what is real."
Noel: What do you hope those who attend your session are able to take back to their own projects and teams? What's something that should be able to be implemented quickly upon returning to work?
Cory: There are two key points I want attendees to take away. The first is that code is merely a bridge for us to scrub away the problem and find a way to have the computer do what the problem is telling us we need to do. The second is that we can use this knowledge to fundamentally alter how we teach people and our own teams programming. We have to think about programming the same way we think about teaching language: that we start with cognitively undemanding, high-context work and slowly move away from that. But that also means that in order to get better at programming, we have to find ways to immerse ourselves in cognitively demanding, low-context code so that we know how not to write code like that.
A passionate technical executive, developer, blogger, and speaker, Cory Foy has more than sixteen years of software and technology experience and ten years of agile and lean methods experience. His background includes work in the health care, financial, and technology sectors, serving as a Premier Field Engineer and Team System Ranger for Microsoft; consulting with DirecTV, Stratos Global, and Invensys as a senior consultant for Net Objectives; and architecting solutions for organizations such as MIT's College of Engineering while at 8th Light.