Assume You’re The Idiot

Assume you’re working on a project as a developer. You write code. Maybe you write tests or docs. Maybe you work through requirements with a product owner or with users. Whatever you consider the job of a developer to do, assume you’re doing it and you’re doing the best job one can do at it. And so you’re using nearly 100% of your cognitive capacity (or the capacity remaining to you when you reserve some for having a life outside of work).

Assume someone else is your manager in this scenario. And they’re giving 100% (or nearly) of their cognitive capacity to that job. Whatever you think a manager is or should be responsible for, assume there’s a person doing that job, doing it well, and giving it their all.

Assume someone else is a designer on your project. Whatever your conception of that job, imagine they’re doing all they can to do that it well.

Imagine this about all the roles on a project, whatever they are on whatever project you’re working on. Everybody has a set of responsibilities, everybody’s putting all their available mental energy into their job, and delivering.

Now imagine that somebody on the team appears to do their job badly. But remember, you’re giving nigh-100% of your energy to your development work. So how do you know?

Or they don’t understand something about your job. But remember, they’re giving nigh-100% of their energy to their work. So why should you expect them to know?

So often, we engage with others from a place of presumed superiority. If someone’s trained at a job and responsible for that job and has been doing that job for years, the right way to react to a perceived poor performance is not to scoff and not to correct, but to ask questions. Assume you don’t understand before you assume they don’t understand.

Free Like A Puppy

“Think free as in speech, not as in beer.” – Richard Stallman

“Free as in speech” means no restrictions on your activities. Libre. Liberty, freedom, do as you like.

“Free as in beer” means you don’t have to pay for a thing. Gratis. Free beer, open bar, help yourself.

“Free like a puppy” means you don’t have to pay for a thing, but there’s a cost that comes with having it.

Sure, take the “free” puppy. Now you have to feed it, walk it, and pick up after it.

Referential Transparency

A function is referentially transparent if you can replace a call to it with the result of that call without changing its behavior. Its result depends only on its input.

Pure functions are referentially transparent. An addition function, for example:

let sum = add(5, 6);

The function call’s result can be replaced with its result:

let sum = 11;

Nothing changes in the execution here except the removal of a call to add.

Here’s an example of a function that isn’t referentially transparent:

let today = getCurrentDate();

I’ll replace getCurrentDate with its result:

let today = '02/17/2016'; // or something

But if I call getCurrentDate again tomorrow, I won’t get the same result. I can’t replace the call with the result without changing behavior. So getCurrentDate is not referentially transparent.

Redundancy

Redundancy is doing the same thing twice. Making a copy. Repeating yourself.

We like redundancy for data storage. If my data’s in two places and I accidentally delete it from one, I have the other as a backup. Whew.

We don’t like redundancy in our code. If I have two blocks of code that do the same thing, that’s extra code I need to keep track of. Yuck.

We even have a name for this idea: the DRY principle: Don’t Repeat Yourself.

(IMHO, sometimes redundancy in our code can be okay: If I have two blocks of code that do the same thing but which mean different things, particularly when I expect to them grow in different directions over time, maybe it’s not so bad to have the duplication.)

We also don’t like redundancy in our communication. As a parent of a toddler, I know very well that having to repeat oneself several times can be very frustrating.

And as a professional knowledge worker, I know very well that it isn’t just small children who sometimes need to be told something several times before it sticks. I do. You do, too. We don’t like it, but it is necessary. And we can learn to like it more when we start to understand its value.

Maybe think of it more like data storage: I want this data to be stored in this other person’s brain reliably. Telling them multiple times is a way to increase that reliability.

Ubiquitous Capture

Good ideas sneak up on you.

If an idea worth keeping comes to me while I’m in a meeting, in the shower, or driving down the freeway, I want to grab it before it gets away. I want to stash it somewhere now. I’ll use it later. Hell, I’ll decide if it’s even good later.

I also want to minimize the time between having an idea and recording that idea. Stopping what I’m doing, even for a second, has a cost. In a meeting, for example, any writing or typing I do means I’m doing less listening. I want to minimize the interruption. I want my recording to be automatic, almost robotic.

This is ubiquitous capture: The ability to quickly capture information at any time, then quickly get back to what I was doing. Processing happens later.

For me, this happens with a simple notebook, and with the Notes app on my phone (including with voice capture: “Siri, make a note that says ‘blah blah blah'”).

It’s a pleasure to review the notes. There’s always great stuff.

No True Scotsman

“No True Scotsman” is an argument pattern. It goes like this:

Bob: "No Scotsman wears a blue kilt."
Susan: "William Wallace wore a blue kilt."
Bob: "Hmph. Well, no *true* Scotsman wears a blue kilt."

Bob tries to make a generalization, a broad claim. Susan provides a counterexample. And then rather than admit, “yeah, there are exceptions to my rule”, Bob counters by adding a layer of subjectivity. If Bob decides who’s a true Scotsman, there’s no way for Susan refute him regarding what Scotsmen are like.

This pattern comes up in software development. It comes up when we can’t agree on our terms, and it comes up when we make broad value claims about things. Worst is when we do both at the same time.

“Agile” is the first thing that comes to mind:

Bob: "Agile is great."
Susan: "My last project was agile, and it was terrible because of x, y and z."
Bob: "Oh, agile is supposed to be about a, b and c, not x, y and z. If you understood that, you'd see that *true* agile is great."

Now replace “agile” in that exchange with “functional programming”. Replace it with “object-oriented programming”. Replace it with “continuous integration”. Replace it with “git” or “distributed version control”. Replace it with “React” or “Angular” or “Knockout” or “Backbone”. Replace it with “Ruby” or “Javascript” or “C#”. “Static languages” or “dynamic languages”.

These kinds of claims are made about people, too:

  • Real programmers don’t use IDEs.”
  • “No good programmer would use Visual Basic.”
  • Real programmers understand virtual memory.”
  • Everyone should learn how to code.”

Why do we fall down this hole?

It’s comforting to think that my definition of any of these things is an objective one. It’s tempting to think that people who disagree simply don’t get it. But that’s false comfort. My definition of a term is useless if I’m working with somebody with a different perspective. And my job isn’t to know the term. My job isn’t to build the thing by myself. My job tends to be to work with people to agree on terms and build the right thing together.

It’s comforting to think that a new practice or tool or platform is a magic bullet, the thing to be used in every situation from here on out. A broad class of problems is solved. But that’s false comfort. There will be situations where another tool would be better. And my job isn’t to apply the same technology to every problem. My job is to figure out the right problem to solve and then use an appropriate set of tools to solve it.

Catch yourself saying things like “every”, “all”, “nobody”, “x is great”, “y is terrible”. It means you’re on autopilot, at least a little bit. That isn’t necessarily a bad thing, but it’s something to be aware of.

Flailure

Can I coin a term? Probably not. But I’ll give it a shot anyway.

Flailure: Repeated failure without evaluating and adapting your approach. When you’re not only failing, you’re flailing.

Failure is often good. It can be a great way to learn, and learn quickly. But to learn, you have to pay attention. To what you did, how it turned out, and what you could do differently next time.

Parameters and Arguments

Imagine a function that returns the sum of two numbers:

function add(x, y) {
  return x + y;
}

Now imagine a line of code that uses the function:

let total = add(price, tax);

x and y are parameters. price and tax are arguments.

Parameters are defined as part of a function definition. They’re properties of your function.

Arguments are the things you pass into a function. They’re properties of an invocation of your function.

In practice, this is a nitpicky distinction. You can use these two terms interchangeably and be understood, almost always. (Almost.)

Curried Form In Elm Functions

Here’s a newbie Elm thing that made me stop and think:

In the docs, there’s a Contracts section, where type annotations are discussed. Some examples like this one are eventually given:

longestName : List String -> Int
longestName names =
  List.maximum (List.map String.length names)

That first line annotates the following function, longestName, as a function that takes a List of Strings and returns an Int. Pretty straightforward.

Later, when I started looking at the Elm Architecture tutorial, I came across a function with a type annotation that looked like this:

update : Action -> Model -> Model
update action model =
  case action of
    Increment ->
      model + 1

    Decrement ->
      model - 1

My brain wasn’t quite ready for Action -> Model -> Model. The function has two parameters. So why doesn’t the annotation?

Here’s how to think about it: It’s a function that takes an Action and returns a function. The function it returns takes a Model and returns a Model.

Curried Form

Elm functions are defined in “curried form”. That’s what Action -> Model -> Model is. A function in curried form is expressed as a chain of smaller functions, each of which takes a single argument and returns a function. (Until the last one, which returns the ultimate result.)

Maybe it’s helpful to imagine parentheses here: Action -> (Model -> Model). Better?

By contrast, a seasoned C#/Javascript developer like me is used to something more like (Action, Model) -> Model. Two parameters, one result.

(“Currying”, by the way, is the process of taking a function with multiple parameters – the kind I’m used to – and transforming it into the chain-of-single-parameter-functions form that Elm uses by default.)

Partial Application

If I call the update function but provide only the first argument, Elm returns a new function. E.g., at the REPL:

> update Increment
<function>: Model -> Model

What does this new function do? It does what the update function does, without requiring (or allowing) me to pass in an Action. The Action is already known. So this function always takes a Model and returns a new Model with a value of the argument Model’s value plus one. It always increments.

This is called “partial application”. Because I’ve applied only part of the function, bound only one of the parameters. The result is a new function I can use to send in the rest.

(Note: Curried form makes partial application easy. But partial application does not require curried form.)

Juggling

  • What happens when this piece of code runs.
  • How pieces of code fit together to form modules.
  • How modules fit together to create applications.
  • How applications fit together to create systems.
  • How developers work together to create, deliver and maintain code and modules and applications and systems.
  • How users interact with systems to create outcomes.
  • How developers work with business folks and other knowledge workers to understand desired outcomes.
  • How desired outcomes are likely to change over time.
  • How likely future changes should affect present decisions about how code and modules and applications and systems should fit together.