Good Enough

“Good enough”: Know it. Reach it. Stop when you reach it.

Some folks chronically don’t do enough. Some folks chronically do way more than enough. Some folks have both problems, in different domains.

The point is to know your goal. Knowing the problem you’re trying to solve means you’ll know when you’ve solved it.

A lot of the time, knowing isn’t enough. Remembering is the challenge.

Can you do more? Maybe. Probably. Should you do more? Maybe. Stop and think about it, at least. Evaluate. Should you do more now? Should you do more instead of everything else you could be doing now?

If you don’t do more, will it hurt? If you do do more, will it hurt?

Fixed Mindset, Growth Mindset

Fixed mindset says my talents are innate. This is what I’ve got. These are my God-given or nature-given talents, and they’re what I’m stuck with. I’m bad at math but good at English. I’m great at hockey but bad at tennis. I’m bad with people but good with computers. The rough shape of who I am is a fixed thing.

Growth mindset says I can get better. Yeah, I’ve got what I’ve got, but with effort I can grow. If I practice my math, practice my backhand, practice my social skills, they can be better. I can be better. Over time, I can change the rough shape of who I am.

I believe in trying to maintain a growth mindset. When you struggle, recognize it, make a plan for growth, and execute that plan.

“let” Is The New “var”

ECMAScript 2015 introduced a new way to declare a variable: let.

var foo = 'bar'; // ye olde variable declaration
let herp = 'derp' // new hotness (hot newness?)

Why did we need a new way to declare variables? This seems really strange until you know the reason, at which point you’ll probably never want to use var again.

The reason is that Javascript variable scope was weird: When you declare a variable with var, its scope is the enclosing function, not the enclosing block.

An example can help:

function getCustomerNames(customers) {
  var names = [];

  for (var c = 0; c < customers.length; c++) {
    var fullName = c.firstName + ' ' + c.lastName;
    names.push(fullName);
  }

  return names;
}

The scope of the variables c and fullName here is the function getCustomerNames, not the blocks in which those things are contained. Those variables can be seen outside of the for loop in which they’re defined. They enter scope before the loop even runs!

The function really runs as if I had written things this way:

function getCustomerNames(customers) {
  var names = [],
      c,
      fullName;

  for (c = 0; c < customers.length; c++) {
    fullName = c.firstName + ' ' + c.lastName;
    names.push(fullName);
  }

  return names;
}

Function scope can create some sneaky bugs, especially for experienced programmers who’re new to JS. Those folks would be inclined to assume that JS scoping is block-centric, like C/C++/C#/Java.

In fact, some Javascript folks recommended writing all your var declarations at the top of a function, to reflect their actual scope.

let introduces block scoping to Javascript. If I change the var statements to let statements in my original example:

function getCustomerNames(customers) {
  let names = [];

  for (let c = 0; c < customers.length; c++) {
    let fullName = c.firstName + ' ' + c.lastName;
    names.push(fullName);
  }

  return names;
}

The scopes of c and fullName are now their containing blocks, not the whole function. Those variables aren’t visible outside the for loop. The code operates as a C-family programmer would likely expect it to.

But why did we need a new thing? Why not just fix var? Because changing how var works would break a lot of existing code. Introducing let as an alternative allows new code to use block-scoped variables while leaving legacy code working as it has.

Memoization

Short version: Memoization is per-input-set caching of a function’s outputs.

Long version:

Imagine I have a function that’s expensive, used a lot, and referentially transparent. Maybe a function getPrime(n) that gives me the nth prime number.

Remember that the output of a referentially transparent function depends only on its inputs. If my function is expensive, and I expect to call it a bunch of times with the same input, it might be helpful for me to remember the result the first time I call it with that input, and simply return that result on subsequent calls, rather than doing the expensive calculation again.

That remembering is memoization.

As usual, an example will help. Happily, I can easily steal a good one from underscore.js instead of writing my own.

_.memoize = function(func, hasher) {
    var memoize = function(key) {
      var cache = memoize.cache;
      var address = '' + (hasher ? hasher.apply(this, arguments) : key);
      if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
      return cache[address];
    };
    memoize.cache = {};
    return memoize;
  };

Does this make sense?

_.memoize is the function declared. It’s a higher-order function, taking a function func and a hash function hasher, and returning a new function, the memoized version of func.

_.memoize returns a wrapper around func with a cache and some extra logic added. The wrapper is the memoized version of func.

When the memoized function is called, it first uses the hash function on the arguments to create an address. The address is a single value that’s used as a cache key used for those arguments.

The function then checks whether there’s an entry in the cache for that address. If there isn’t, it runs the original function and adds the result to the cache. If there is, it skips the running of the original function, because it already has the result.

Finally, the function returns the cache entry for the address.

A simple object {} is attached to the memoized function and used as its cache. It’s defined as a property of the function, rather than inside it, so it persists across calls to that function.

And with this, I can memoize getPrime(n):

let getPrimeMemoized = _.memoize(getPrime);

One last note: Think about what happens if I memoize a function that has side effects. The original function will only be called the first time I call the memoized version. So the side effects won’t happen on subsequent calls.

Expressing A Function In Terms Of Another

Imagine an addition function. This is trivial, right? A function that takes two parameters and returns a single value, the sum of those two inputs.

Imagine an incrementation function. Also trivial: a function that takes one parameter and returns a single value, the result of adding one to the input parameter.

You could write these two functions independently. But you could also choose to write the incrementation function in terms of the addition function!

Independent:

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

function increment(x) {
  return x + 1;
}

Expressing incrementation in terms of addition:

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

function increment(x) {
  return add(x, 1);
}

(Extra credit: Can you express addition in terms of incrementation? What challenges does that pose?)

Little Wins

Little wins keep you going. Little wins keep morale up, especially in the face of big setbacks.

You can choose to structure your work in a way that recognizes small progress points. Those are little wins. Just paying some attention to them will help keep you going when you hit hurdles.

You can break a large project down into small milestones on the path to finishing the bigger thing. Each one represents progress, a small victory, a reason to keep going.

If you don’t have a goal in mind, merely a direction, you can still use this. You won’t be breaking a big project down into smaller pieces of work, but taking steps in a concrete direction and evaluating their results. Learning is progress, too.

Test The Interface

A module’s public interface is its contract with the world. Its privates are nobody’s business. (That’s why they’re called “private”.)

When you write unit tests for a module, test only the public interface. (In fact, the tests should read like documentation for the module’s public interface.)

If you find yourself caring about the module’s privates when writing tests, you’re probably going down a path you’ll regret. Stop and think about your design.

If you find yourself making things public just for the tests, that’s another bad sign. Stop and think.

The code calling a module is its client. When the client calls something on the public interface, what’s the expected result from the client’s perspective? Questions like that should shape your module’s public interface, and furthermore should shape how you separate your code into modules to begin with.

Inertia

Tax preparation software companies have a strong interest in the tax code continuing to be complicated. Because they’ve built a product that addresses that problem for people.

When someone comes along with a plan to make the tax code simpler, that’s a threat to their existence. You can be damn sure they’ll put up a fight.

“Institutions will try to preserve the problem to which they are the solution.” – Clay Shirky

We think about this more often within markets, across companies. Like when big behemoths buy up small, agile startups who start to eat their lunch. But it happens within the big behemoths, too.

A big company puts together a new team to develop a next-gen product. Something intended to be a newer, better version of the company’s flagship product.

How do you think the folks in charge of the old product will treat the folks in charge of the new one?

They’ll fight it.

They’re comfortable with the current system. Small change is what you can sell them. Large change will make them nervous. Wholesale change is an existential threat.

You Teach People How To Interact With You

If you start asking about code coverage in every code review you participate in, you’ll teach people to expect the question, and they’ll start thinking about code coverage so they have a good answer for you.

If you rarely respond to emails but always respond immediately to IMs or to somebody showing up at your desk with a question, you’ll teach people that they need to show up in your face to get information from you. They’ll start skipping the emails.

If you teach people what what you won’t tolerate by not tolerating it, they’ll anticipate that and adapt accordingly.

If you teach people what you will tolerate, by putting up with it, they’ll anticipate that.

This happens whether you pay attention to it or not.

Provocations

Stupid questions are provocations.

Questions about assumptions are provocations. (Sometimes these sound like stupid questions.)

Provocations yank us off of autopilot. They prompt us to consider change. Dwelling on a question can be really valuable.

Provocations shouldn’t prompt kneejerk negative reactions. Humble, introspective response to provocation should be our default. This is a thing to practice, a goal to work toward, a direction to move in.

The people who provoke you probably drive you nuts. But maybe they also prompt you to grow.