The First Thing To Know About Programming

If I were put in charge of teaching you how to program, the very first thing we’d cover is a simple principle: Code is for humans.

Code is for humans, far more than for machines. Sure, the machine executes the code. The machine is a wonderful thing. But the human telling the machine what to do is even more wonderful. The capacity that code gives us to collaboratively create elaborate, elegant, executable structured meaning is more wonderful still.

When programmers don’t remember that code is for humans, we write code that’s hard for a human to read. And of course, code that’s hard for a human to read tends to be hard for a human to change. We make our colleagues’ jobs more difficult. We make our own jobs more difficult.

A lot follows from this little principle. It’s not easy. Naming things well is hard. Structuring things sensibly is hard. There’s often not a clear best answer. But there is often a better answer than your first pass. Even a little bit of consideration for the humans goes a long way.

(But you should give a lot.)

First Principles

To teach someone something, you want to meet them where they are on the road and then help them along for the next few steps.

That’s two hard things: understanding where they are and then teaching them the next thing. We understand that the teaching part is hard. That’s what we tend to work on. But the meeting-them-where-they-are part has its own set of problems.

When I try to write about something technical, I constantly find myself asking: What if the reader doesn’t don’t know about this yet? I can’t define thing C in terms of thing A and thing B if the reader doesn’t know about thing B yet.

“If you wish to make an apple pie from scratch, you must first invent the universe.” – Carl Sagan

Of course, you have to start somewhere. And your audience will quickly lose interest if you start several levels of abstraction beneath what they’re actually interested in.

But I find it helpful for my own understanding to keep asking myself this question. Questioning my understanding often shows me the gaps in it. Trying to write about very basic stuff nearly always turns out to be harder than I expect. Sometimes I learn things I’ve missed or forgotten. Sometimes I turn my intuitive knowledge into knowledge that’s more concrete and communicable.

Scrum For Body Shops

If you apply the two most conspicuous Scrum practices, stand-ups and iterations, and do nothing else, what you’ll have is a pretty effective way to micromanage a low-skilled team. Management can closely manage what they do and steer their work at a very detailed level.

The other way is to build a team of skilled folks. Don’t treat knowledge workers like replaceable cogs, and create an environment where skilled people are trusted and enabled to do good work. In that kind of environment, there’s still a place for agile practices, but their intent won’t be to ensure that progress is being made every day. They’ll be there to provide a structure to what’s being produced and a cycle of collaborative evaluation that enables rapid feedback and a change of direction.

In other words, the other way is to actually value individuals and interactions over processes and tools, like the Agile Manifesto suggests.

Toddlers Try

My son is fifteen months old. He likes to dance. He’ll push the same button on the same musical toy a dozen times, swaying back and forth to the music. It reminds me of middle- and high-school dances, how I wasn’t any better a dancer at fourteen than he is now. (Or at thirty-four, for that matter.)

My kid’s not better than me at a lot of things (yet), but there’s one thing he’s way, way better than me at: Trying. This seems to me to be the thing that kids are best at. Trying to walk, falling down, getting up, trying again. Trying to stab a piece of fruit with a fork, pushing it off the tray, trying again with the next piece.

Adults are terrible at trying. We make excuses, we procrastinate, we fear failure. We have a lot more experience not trying. We get really good at not trying.

The Principal-Agent Problem

I hired a plumber to fix a slow-draining bathtub recently. It was a fantastic experience. I plan to be a customer of that particular plumber for a long time.

Here’s why: The guy took a good look at my problem, asked a few questions, and then proceeded to explain what was going on to me in terms I could understand. He showed me why my efforts at snaking were fruitless, told me what he could do about it, and recommended I point out a particular quirk about the situation to future plumbers, if the problem came up again.

Usually when I have to hire somebody to do work like this, work I don’t understand, I find it stressful. And it’s not an infrequent scenario: It happens when I hire someone to fix my car, file my taxes, treat my lawn, manage my investments, treat my illness, and on and on.

When you shop for a service to do work and you’re not able to assess the quality of that work, trust has to come into play. You have to trust their expertise and then you have to trust that they’re not screwing you over on price and/or quality.

This is known as the “Principal-Agent Problem”. In all these cases, I’m the principal, and I’m hiring an agent to do some work on my behalf. The problem comes when their incentives don’t align with mine.

For instance, as soon as I pay my plumber by the hour, he has a small, direct, financial incentive to take more time to do his work. And I have no way of judging whether he could’ve done the job in four hours instead of five. I have to trust him.

This plumber could’ve recommended we tear out these very old pipes and replace them. I would at the very least have given a lot of weight to his suggestion, because I don’t know squat about plumbing.

I’d probably have gotten a second opinion, though. That’s a way to mitigate some risk when putting your trust in an agent. Just the existence of that option means your agent’s incentives are more nuanced than trying to milk you for as much money as possible. An agent needs your trust and will generally act accordingly. One who doesn’t won’t be in business for long.

I think about the principal-agent problem a lot. Not just when I’m hiring agents: As a developer, I’m often the agent myself. I need to build trust and to align my incentives with those of my clients.

It helps to focus on long-term incentives, not just short-term financial ones.

Let Me Think About It

Sometimes your best answer to a question is “let me organize my thoughts on that and we can discuss it later”.

When presented with an important or complex question, answering it off the top of your head might lead the conversation down a path you’ll ultimately be unhappy with. You might commit to something you’ll regret. You might never think to question important assumptions, why the other person thinks that‘s the question they should be asking.

We rarely think we can get away with this. We think we have to have answers, and if we don’t, we’ll be revealed as frauds.

You’re closer to being a fraud when you give unconsidered answers.

A Problem Solver’s Dilemma

There can be a big difference between “I’m upset by x” and “I have problem x”.

When somebody comes to you with a problem, help them solve their problem.

When somebody is upset, a logical response might not be what they need. It might not help. Upset means there’s an emotional component, and you have to deal with that first. If you don’t, you’re likely to be ignored or resisted.

Emotion trumps reason. Not always, but often.

Filter

Filter is a very common higher-order function.

Filter is kind of like map, in that it takes a function and a list and applies the function to all the elements in the list. The difference is the output. Where map uses the function to transform each element in the list, filter uses the function to determine whether an element should be included in the list that it returns.

Here’s a simple example in Python (try it!):

def isEven(x):
    return x % 2 == 0

list = [1, 2, 3, 4, 5]

evens = filter(isEven, list)

print evens

The printed output is [2, 4].

Like map and fold, filter is often used in declarative code where a loop might be used in code that has a more imperative style. And like map and fold, when you get used it, filter can make your code simpler than it might be with a loop.

Fold

Fold is a common higher-order function. You might also see it called “reduce” or “aggregate” or “accumulate”.

Fold is kind of like map, in that it takes a function and a list and applies the function to all the elements in the list. The difference is the output. Fold returns a single value, built up as the elements of the list are processed.

Here’s a simple example in Elm (try it!):

import Graphics.Element exposing (show)
import List exposing (foldl, foldr)

add x y =
    x + y

list = [1, 2, 3, 4, 5]

sum = foldr add 0 list

main =
    show sum

The printed output is 15.

Like map, fold is often used in declarative code where a loop might be used in imperative code. And when you get used to fold, you’ll often be able to write code that’s a little simpler than it might be with a loop.

Fold has another interesting property that map does not: Its result might depend on the order in which the elements of the list are processed.

With the addition function, the order doesn’t matter. Addition is associative. If we want to sum the list [1, 2, 3], we might add 1+2 first, and then that result + 3. We get the same end result that we’d get if we added 2+3 and then 1 + that result.

Parentheses might make this easier to see: (1+2)+3 produces the same result as 1+(2+3).

In plenty of other situations, though, the order in which we process the list elements may matter.

Imagine we have an array of characters and want to fold that list to produce a string. Here’s that example in Elm:

import Graphics.Element exposing (show)
import List exposing (foldl, foldr)

concat x y =
    x ++ y

list = ["a", "b", "c"]

result = foldr concat "" list

main =
    show result

The printed output is "abc".

Now try changing foldr to foldl in this example. This changes the order in which the elements are processed from left-to-right to right-to-left. The printed output will be "cba".

(You can also go back to the first example and change foldr to foldl, and see that this change does not affect the result.)

Your language or library may or may not include fold functions that go in each direction. It’s more important just to understand that the direction can matter for fold operations.

Map

Map is a very common higher-order function.

Map takes a function and a list. It applies the function to each element in the list and returns a new list containing the outputs.

Here’s a simple example in Python (try it!):

def double(x):
    return x * 2

list = [2, 3, 4, 5]

doubles = map(double, list)

print doubles

The printed output is [4, 6, 8, 10].

Map is often used in declarative code where a loop might be used in imperative code. When you get used to map, there are lots of situations where it can make your code a little bit simpler than it would’ve been with a loop.