How To Write a Programming Book
If you read Programming books, then your goal is to learn. If you write Programming books then your goal is to teach. When I wrote my book Functional Programming Made Easier, I tried to apply everything that’s chronicled in this article.
So to write a Programming book you need to understand how to teach someone about a subject you understand well without being around to answer any of their questions.
That’s a tall order. I cannot tell you how many Programming books I’ve bought, started reading and abandoned because the book failed me.
Before we learn what to do when writing a Programming book, we should first learn what NOT to do, since we learn so much more from failures than we do from successes.
How Not to Write a Programming Book
Too many Programming books follow the pattern A, B, C, X, Y, Z. This kind of book starts off pretty easy. Each chapter makes sense and builds on the previous nicely. And you’re excited to be learning with relatively low effort.
Then there’s that fateful page turn. You know the one. The one that propels you into a world of complexity long before you’re ready to embark on such a journey.
It’s like, Chapter 1: Learning Your A,B,Cs. Chapter 2: Learning Your 1,2,3s. Chapter 3: Differential Calculus!
You flip back to the previous page in disbelief hoping to find the part that you missed to bridge this massive gap but to no avail.
The reason authors make this mistake is most likely because it’s easy to talk about the easy stuff (for obvious reasons). And it’s easy to talk about the hard stuff because that’s what really interests the author.
It’s that middle ground, the bridge from the beginner material to the advanced, that’s so difficult. And nearly every technical book gets this wrong. The same could easily be said with articles and blog posts.
Another problem with technical books are the exercises. Math books are the worst of all offenders with their odd-answers-only section in the back of the book with zero information on how the answers were obtained.
And in those rare occasions where the author works out a problem, those problems are typically only the easiest of examples. Come the hard ones and they typically leave them as “an exercise for the reader”.
Seems like a huge cop-out to me. The author is just being lazy. It’s not like I can just phone them up or text them when I get stuck and they’ll drop everything to come to my aid.
A book should contain as much information as possible so that most readers can independently learn its subject matter. The reader shouldn’t have to search the web to fill in the blanks of a book.
Finally, don’t skip steps. It’s so easy for someone skilled in a subject to make broad leaps from point A to Z. Many times, they don’t even know how they do what they do. At this point of the game, they just do it.
When you’re trying to learn from them, that’s the worst thing in the world. There’s no way that you can read minds. And if the author hasn’t taken the time to slow down their thinking and explain what they’re thinking each step of the way, there’s no way for the student to fill in these missing pieces on their own.
For example, here’s a simple Algebra problem to solve for x:
2x + 10 = 20
2x = 10
x = 5
Now, there are all of the steps and if you don’t understand how to solve this on your own, you’re pretty lost with only these 3 simple lines.
Contrast that with:
2x + 10 = 20 (given)We want to isolate x from the numbers, so we're going to subtract 10 from both sides of the equation.2x + 10 = 20
- 10 = -10
2x = 10Now that x is isolated on one side of the equation, we want to reduce 2x to only x, which will leave us with x on one side of the equal sign and the value for x on the other.We'll do this by dividing both sides by 2. This will cancel the 2 in 2x leaving us with x.2x = 10
2 2x = 5
Since most of us have had Algebra before, we can pretty much do this problem in our heads without even having to write down the simple 3-step version.
But for someone just learning these concepts, seeing each step in gory detail with the strategy explained before each step is critical to gaining understanding.
Notice how I first explained what my strategy was and then I explained what tactic I was going to use to accomplish my goal. This was done before each step.
This is like being able to peer into the mind of the Mathematician. And in Programming, we do these 2 mental steps between every line of code we write.
I’ve yet to encounter a Math or Programming book that takes this approach. It doesn’t mean that they don’t exist. It just means that if they do, they’re a rare breed indeed.
How to Teach
Writing a Programming book is writing a book to teach people how to program. That means that it’s mostly a teaching book and to write such a book, you really need to know how to teach.
I’ve never been a big fan of how subjects are taught in school or in books. I always thought that I’d do a far better job teaching since I’ve had tons of experience tutoring students my whole life. Was I ever wrong.
When I first began teaching my daughter to program, I was amazed at how terrible I was at it. I’d been programming for over 30 years at the time. And to be honest, I’m pretty damn good at it.
But to teach it. Wow. That really was far more difficult than I could’ve imagined. I had taught people who already knew a bit about programming with ease.
But teaching someone something from the very beginning was very difficult. She probably taught me as much about teaching and learning as I taught her about programming.
Now, it’s not like I hadn’t been thinking about teaching or learning my whole life. I had some pretty good ideas about what I thought was important when teaching someone.
But I really honed my model of teaching trying to explaining how a computer works and, subsequently, how to program a computer to someone who was born into a world where computers were as commonplace as a toaster.
Here are some of my most important teaching rules:
- Always start where the student is an expert.
- Take the student from where they are to where you want to take them one micro-baby step at a time for the whole trip explaining yourself before each and every step while never skipping a single step or leaving anything out.
- Never give a student a solution to a problem they don’t have.
- Simulate discovery whenever possible.
- Concrete models are far more powerful than Abstract ones.
Always Start Where the Student is an Expert
This should be so obvious but it’s not. Before I embarked on teaching my daughter about how computers worked, I opened up my work PC and had her TOUCH each and every part of the system.
I knew she was an “expert” at using a computer because she had done so since she was in the first grade. And this is where I started. I wanted to dispel any mystery about the computer.
I had her touch the CPU chip. As she did this, I told her how this chip is where the circuitry was that did things like simple math and basic logic. I told her that all the programs she had ever run are interpreted and executed inside of this chip.
Then I had her touch the memory cards. I explained how all of her open programs are all stored here and when she turns off the computer, they’re all gone. I also explained that these were tiny circuitboards that fit into slots so that we could add more memory if we wanted to.
I next had her follow the ribbon cable from the motherboard to the disk drive. I then explained that her programs were installed here and that they would last even after she turned off the computer.
I also explained that all of her files were here too and how the disk was made up of platters that spun at a very fast rate so we could get data from them quickly and that it was made of a magnetic material that we used to store information on.
This experience didn’t make her a hardware expert but it gave her a concrete model of what the computer was and an experience that grounded her and was the basis that I built all of her subsequent knowledge upon.
This proved so successful that she went out and got a book on how computers worked, which did a far better job at explaining in detail than what I had done.
My goal was to make sure that when we made up our own little Assembly Language for a fictitious machine and I drew a square marked CPU that it wouldn’t be an abstract concept.
Instead, everything I said about the CPU got related to that experience of touching the chip. When I talked about the Data Bus running between memory, another rectangle on the page, and the CPU, this had some sort of meaning to her since she remembers them living so close to one another on the motherboard.
This is one of the biggest problems with teachers. They suffer from knowing too much and for too long. This was my problem when my daughter asked me why we use functions and I looked at her as if she asked why do we use cups to drink from.
Too many teachers blame the student for not keeping up. They can justify this position by pointing to a student or two in the class that is keeping up just fine, not taking into account that many times those students have already learned the subject outside of the classroom.
In school, this is a huge problem. And a professional teacher can, hopefully, learn to recognize when they’re going too fast or when they’re skipping steps that is causing trouble for many of their students.
But a book author has no such hope. They write their book and move on. Most readers blame themselves for being “too stupid” for not being able to understand the material.
But this is just hogwash. The burden is on the author not the reader. By writing a book, an author is saying to the world, “Hey, I’m an expert on this subject that you’re interested in learning and I know it so well that I can teach you to understand it too”.
Well, if that’s what you are saying to the world then you have a pretty high bar to clear. And most don’t even come close. I personally have encountered hundreds, if not thousands, of times when I was reading technical material trying to understand something where the author just made a leap and left me behind.
I have an analogy that I created to help visualize this dilemma.
Imagine that you live in the country and your home and school are separated by a raging river.
Now, there’s a nice bridge that you could use to cross this river but it would add 20 minutes to your walk to school. So for the last 10 years, you’ve been crossing the river by way of a bunch of slippery rocks that make their way from shore to shore.
One day, a new kid moves into your neighborhood and you become fast friends and start walking to school together. That is, right up until you come to the raging river and its slippery path of rocks.
You cross it with ease and look back at your newly acquired friend in disbelief at their hesitation. You tell them that it’s easy and that all they have to do is just walk briskly across the rocks and they’ll make it to the other side safely.
These words do nothing to boost their confidence. Realizing that telling them what to do isn’t enough, you decide to show them. So, you scurry back to the other side of the river and tell them to pay close attention to how you cross.
You then proceed to cross just like you did before. Your friend is still not convinced that they are skilled enough to make it. So you cross back once again and speak very slowly, explaining what you’re doing as you more slowly cross across the rocks.
After this last explanation and demonstration, your student is none the wiser and decides to walk to the bridge instead. You conclude that your new friend is nice enough but not a very good student and you make your way alone to school.
The problem with the teacher in this story is that they forgot what it was like to not know how to cross the river. They’ve been doing it for so long that they cannot remember how they first felt not being able to do it.
Try to think back before you could tie your shoe. Try to feel what it was like to struggle to make the loops and push and pull the laces into the right configuration. I’d bet a million dollars you cannot image how that feels.
Now try to imagine that you cannot read. Equally difficult. This is because we’ve been doing it so long that we don’t think consciously about it anymore and that’s what students have to do.
It takes a lot of conscious mental energy to think about reading or tying your shoe when you don’t know how to do it. No amount of showing someone how to drive will make it easier for them to drive.
And with our river-crossing story, showing the new kid how to cross the river and explaining it with words slowly doesn’t help. So what should have been done?
This is where baby steps comes in. The new kid should have kept one foot firmly on the shore. This is where they’re an expert and highly confident. Then they should reach their foot out to the closest rock and very slowly apply some of their weight to the rock.
Once they reach this position, they need time to build up confidence that they will not lose their footing. We cannot rush them to put their other foot onto the rock.
Once they feel ready, then they should place their other foot on the SAME rock. Not the next rock. That’s too advanced. They need feel comfortable with this rock and so that’s the next rock for their other foot.
Once again, they stand there until they feel confident that they will not fall and then the repeat this process, however slowly as they need, to finally cross the river.
Over time, they will begin to tire of this pace and they will look to skip planting both feet onto each and every rock. But only after repeating this process dozens and dozens of times.
Remember, you’ve been crossing that river for 10 years. It’s like tying your shoe. You don’t have to think about it anymore. But your friend needs their full attention to be highly focused just to move inches.
This is why skipping steps is easy for the expert, i.e. the teacher, and not for the student. Teachers have forgotten what it’s like not to be able to do what they’re teaching like we all cannot remember what it was like not to be able to tie our shoes.
This amnesia is why this rule is so important. When teaching, no steps should ever be left out.
Never Give a Student a Solution to a Problem They Don’t Have
I remember in math class when we were told that Chapter 10 is about Logarithms and we needed to learn about them for the test next week.
No mention as to why we should care about these Logarithms. Just that there were these things called Logarithms and we needed to know all about them so we could pass some test in our not too distant future.
I hated this. And I wasn’t alone. I can remember more that one occasion when a student would ask the teacher when we’d use whatever they were trying to teach us in the real world.
The answers were always dubious and never satisfying. But imagine you understood why you needed this magical new idea. What better way than having this new subject solve a problem that you have.
And there’s no better way to make that happen than to give that problem to your students. I have a favorite example.
Imagine you’re a music teacher and you want to teach your classroom about Music Notation. Where would you start? Maybe talking about the history of notation and how we got here would be nice.
But that wouldn’t inform the students about how to read or write music. Instead, it would be best to have the students make up a very simple tune. Or they can think of a simple tune, e.g. Twinkle, Twinkle Little Star, if they don’t want to try to make one up.
Then give them time to bang on a piano or synth keyboard until they can figure out all of the correct notes to play.
Now, have them write down which keys to press on the piano to play this simple tune. But they must keep the tune a secret. Then when they’re done, they can come up to you and hand you their piece of paper for you to play on the keyboard.
So imagine you get a piece of paper with just 3 notes from a student, A, B and C. You play the A for a really, really long time. And then you play the B and C very quickly thereafter.
Then you ask the student if that was their song. Clearly, it’s not and they would proclaim that you played it wrong. When asked how you played it wrong, they’d explain that you played the A too long and the B and the C much too fast.
To this, you reply that there was no mentioning of how long to play each note, just that there were these notes, A, B and C. It’s at this point that you’d instruct the student to create some way to specify “how long”.
Then when the next student comes up, you repeat this over and over. And when each student gets their own syntax for specifying note duration, you play their song wrong again by playing some of the notes really, really quietly and others super forcefully.
The student will rightfully object to your terrible interpretation of their masterpiece to which you will point out that there is no information regarding how loud to play the notes.
The next lesson you teach them is by playing a very low A then a very high B and then middle C. One would expect the student to once again object to such a terrible performance of the material.
You then explain that they didn’t tell you which A to play so you picked one to your liking. Once again, the student returns to their desk to improve their notation system further.
Now, once all of the students have had time to hone their notation systems, you have a few volunteers come to the front and explain their notation to you and then you play it.
Most likely, you’ll play it pretty good and many of the students may even be able to guess that you just played the first part of Row, Row, Row Your Boat.
It’s at this point where you ask the students to trade papers with their neighbors and then ask for volunteers to come up to the piano and play their neighbors compositions.
Hopefully after the reluctance of the students to volunteer or the abject performance attempts of those brave enough to try, the class would understand why having a standard system for Music Notation is so important.
Now, every student has the problem of trying to convey their personal musical notation to someone else who is going to play their compositions. And now that they have the problem, they are perfectly prepared and far more interested in the solution that you have for them.
Humans have been inventing things to solve problems for as long as we’ve been human. And the guy who invents something really understands what he’s invented because he understands the problem it solves.
When my daughter asked me why we use functions in programming, I was ill-prepared. But many months later, when I came to her with a well-thought-out response, she dismissed the question as being obvious. She was appalled that she even questioned it saying that “we use functions for everything”.
Even in her early days of learning programming, she was experienced enough to see the benefit of functions. So much so, that she couldn’t believe anyone would ever question it.
This is the same problem that faces many students about complex abstract concepts. They guy who invented them understands them because he had a problem to solve and that’s why giving students a problem before giving them the solution is so powerful.
But what can make that even better is if you don’t tell them the solution to the problem you just foisted upon them but instead take them through a process of inventing or discovering a solution.
We can never truly discover a solution in a teaching environment due to time constraints. Some subjects took decades or centuries to mature. But we can simulate a path to discovery. As someone who knows the path, you can guide your students to come to the conclusion that you want them to.
I do this when I explain Monads to programmers who want to understand Functional Programming. I give them the problem of doing effects in a Purely Functional Programming Language and then have them try to work with Pure and Effectful Functions until they run into problems.
Then we create solutions one by one for each problem case and when we’re done, we’ve actually created the Monad. When we take the solutions that we created, not knowing about the Monad, and compare them to Monads in languages like Haskell or PureScript, we can see that the two solutions are identical to one another.
Now they too have invented the Monad and therefore have a much deeper understanding of how this new complex abstraction fits into their programming world.
Concrete Models Over Abstract Ones
When you first learned about Positive Numbers, you were probably very little. In fact, it was never explained to you that you were learning Positive Numbers. Your teachers just called them Numbers.
And when they explained them to you, they probably used blocks or coins or balls or some set of objects in your world to build an intuition about counting and numbers.
This was a great concrete model. They started where you were an expert by choosing objects that you were familiar with. And I can’t say I’ve ever met anyone who had trouble learning how to count. So this method has quite a proven track record.
Now, I want you to think back to how to you learned about Negative Numbers. How were they first explained to you? Take a minute to really try to remember how they were first explained to you and your fellow students.
Before I tell you how most people are introduced to Negative Numbers, I want you to think about all the kids in school, one of which may very well be you, who initially struggled with Negative Numbers. You may even know a kid or two who never really understood them and just gave up.
It will be clear why this is this case when you realize that most kids are taught Negative Numbers using the Number Line, a 300 year-old Abstract Model for Numbers.
Have you ever seen a Number Line in nature? Had you ever seen one before that fateful Math class? I doubt any of us had. I know I hadn’t.
The difference between our ease of understand these two concepts is the model that was used to initially introduce them to us. Positive Numbers were introduced to us using a Concrete Model, i.e. physical objects in our universe that we were very familiar with.
In contrast, Negative Numbers were introduced to us using an Abstraction known as the Number Line. This model forced us to learn a whole new way of adding and subtracting using this Number Line thing that we just learned.
The problem is that humans don’t learn well from abstractions. We need concrete examples and lots of them before we can build a set of rules to help us reduce the complexity of the subject. This set of rules is our model. And that model is an Abstraction.
Abstract models come after we understand not before.
Here’s an example I like to use to explain the difference.
You’re four years old and walking with your mother when you encounter a strange blue creature that you’ve never seen before making a loud sound that frightens you.
You hide behind your mother and say, “Mommy, Mommy, what is that?” She calmly explains that it’s a dog to which you query, “What’s that sound it making?”.
She says that it’s barking and that’s a dog’s way of talking. You calm down and peer from behind your mothers legs and make a mental note that there are these blue creatures called dogs that make a sound with their mouth called barking.
Two weeks later, you and you mother encounter another dog except that this one is red and when it barks you say, “Mommy, Mommy, what is that?” To which she explains that it’s a dog.
“I thought dogs were blue.” you reasonable reply. “Some dogs are blue but then some are also red”, she explains. With this new experience, you modify your model of these things called dogs to note that they also come in red.
Two weeks go by and you and your mother are out walking again when you encounter a green dog that’s moving its mouth as if to bark but no sound is coming out.
“Mommy, Mommy, what is that?”, you rightfully ask to which your mother explains that it’s a dog. “But, why isn’t it making any sound?” is your next logical question. She explains that green dogs cannot bark.
Once again you modify your model of a dog to be a creature that comes in three colors, red, green and blue. Also, dogs make a sound with their mouth called barking except for green ones. Not a bad model constructed by a four- year-old in as little as four weeks.
Now, imagine we go back in time before you encountered your first dog. And instead of that event on that fateful walk, you come across a school teacher whom your mother knows.
They get to talking and they mention a dog in their conversation. So, being the ever curious child that you are, you ask, “What’s a dog?” The teacher chimes in with, “Dogs are animals that come in the colors red, green and blue and they make a barking sound from their mouths except for the green ones.”
In this latter case, your model of a dog is pretty non-existent. The explanation for your question is pretty incomprehensible due to the fact that you were only given the model for a dog instead of allowed to build it slowly from concrete encounters with dogs.
This is the equivalent of you asking me what a napnap is and I explain that it’s a moople that comes in three colors red, green and blue and that it humbats with it’s mouth except for the green ones.
But, unfortunately, this is how nearly all ideas are conveyed. First, you’re given the Abstract Model, which at first has zero meaning and only after getting to see example after example do you get to finally understand what your mother’s friend was talking about all along.
And if you don’t encounter a dog until you’re 5, no amount of telling before that will match the power of the Concrete Model of a real dog.
Returning to our discussion regarding the abstractness of the Number Line, you may be wondering what would be a Concrete Model that would be a far better teaching tool.
When I first asked this question, it took me a long while to come up with one, but I finally did.
Imagine a plot of land. It’s just dirt. This empty plot of land represents the number 0. Now, I take 2 Buckets of dirt and place them on this plot. This represents the number 2.
Now, I ask you to Subtract 1 Bucket of dirt from the land. You promptly walk on the plot, pick up one of the Buckets and walk off. Now the plot of land has 1 Bucket of dirt. This represents the operation 2 - 1 = 1.
I then ask you to do it again and you remove yet another Bucket leaving me with an empty plot of land. This is equivalent to 1 - 1 = 0.
Now, I ask you to do it one more time. What do you do?
Think about it?
Well, it’s easy. You pick up a hand shovel that just happens to be serendipitously lying about and an empty Bucket and you dig a Hole and fill the Bucket.
Then you remove it from the plot of land. Now, my beautiful plot of land has a Hole in it. This represents the operation 0 - 1 = -1.
So, in this concrete model, we have Buckets as representing +1 and Holes representing -1. We can teach this model to Kindergartner’s since they are already experts at playing in the sandbox.
And if I say to you or anyone who understands this Concrete Model, you have a plot of land with 2 Buckets and 3 Holes and I ask you what that represents, you can very quickly and easily tell me -1.
Conceptually, this is lightyears ahead of the Number Line. Kids can learn Negative Numbers many years before they’re currently taught and master it as well as they have Positive Numbers.
Money Where My Mouth Is
All of these ideas sound great in theory but I’ve actually applied them in practice. I’ve taken these ideas and many others in my book called Functional Programming Made Easier: A Step-by-step Guide.
This books starts where the reader is an expert, i.e. programming Imperative Languages. The least experienced reader that I imagined writing this book for was someone who is a professional developer for at least 2 years.
I assume zero Functional Programming experience and start very slowly from there. The first 200+ pages is just beginner stuff. Including coding many functions.
The exercises are 100% answered. After I ask the reader to code the function, I code it ONE LINE AT A TIME. This adds tons of bulk to the book and greatly increases the page count, which, frankly, may frighten some people away but it’s exactly what’s needed when you want to understand how to go from a blank page to working code.
I have NOT found a single book in the programming universe that does this. When a new developer sits in front of their editor with their fingers on the home row staring at an empty file, they soon learn that the book they just finished reading has NOT prepared them properly to move forward from nothing to working code.
In my book, there are times we prove that our implementations are law abiding, e.g. that our Functor implementation follows the Functor laws. In those proofs, not a single step is skipped even though the Math involved is from Junior High School.
Just because you understand Algebraic Substitution doesn’t mean that you can follow my line of thinking. That’s why no steps are skipped. No hands are waved. And, hopefully, no reader is left behind.
The one dreaded subject in Functional Programming is the Monad. There are jokes about how once you understand the Monad, two things happen simultaneously. First, you feel compelled to write a Monad Tutorial and second you lose all capability to explain the Monad.
When I introduce this subject, I give the student the problem that the Monad solves FIRST. Then we Simulate the Discovery by slowly and naively developing our own solutions to each problem as we encounter them until we’ve “accidentally” invented the Monad.
The Concrete Problem is first introduced then we work out a very specific solution and then we generalize it into an Abstraction. I will admit sometimes I introduce an Abstraction before I give any Concrete examples but in these cases, the Abstractions are pretty simple and the Concrete examples are hot on their heels
The Monad is no such case. Students struggle with this concept and I remember my difficulties not too many years ago. And that’s what made the timing of this book for me and my journey in Functional Programming so well timed.
I’ve only been doing Functional Programming for the last 5 years of my 40 year career. I know enough about programming such that it would be a huge struggle to write a complete-beginner book since I’ve forgotten what it’s like to know absolutely nothing about programming.
But I remember all of the pain points of learning Functional Programming since it wasn’t that long ago for me. Had I tried to write a beginner programming book early in my career, I’d lack the experience that I now have that enabled me to provide real-world advise the reader of this book.
A few more years of programming in Haskell and PureScript and my ability to teach these subjects would have surely diminished as the pain of understanding the subject would have faded away.
Finally, the one thing I did in this book was to not just present theory. So many times you read a book and think you understand how to apply your new found knowledge to your work only to quickly realize that you don’t.
You understood it while you were reading it but when you went to apply it, you froze. Understanding Functional Programming concepts is great in a classroom situation but in the real world, you need to know how to apply these new concepts to building real software.
When the reader is finished with the book, they know exactly how to solve dozens and dozens of problems that they will encounter in developing real-world code that most of us develop on a regular basis.
And with that experience, they can easily extrapolate to other types of programs, e.g. a Command Line program or a Desktop Application.
It took me my whole life to be ready to write this book and I’ve been actively working on the material for about 2 years. It’s been road tested by programmers at my company who used it to learn more advanced Functional Programming just before needing to work on a customer project.
The team used to program in Elm, a beginner Functional Language for Web front-ends. I used my book in a training class to upgrade their skills to Haskell and PureScript.
This is some proof that my unorthodox methods work well. Hopefully, you can steal from this article and possibly the best parts of my book if you happen to buy it.
And if and when you write your own book or even a small blog post, I hope you will be able to apply some of the rules for teaching that I’ve discovered to help you better explain what comes so naturally to you and is so foreign to your reader.