The Three Stonecutters

An old story tells of three stonecutters who were asked what they were doing. The first replied, “I am making a living”. The second kept on hammering while he said, “I am doing the best job of stonecutting in the entire country.” The third one looked up with a visionary gleam in his eyes and said, “I am building a cathedral.”

It is the second man that is the problem. Workmanship is essential […] but there is always a danger that the true workman, the true professional, will believe that he is accomplishing something when, in effect, he is just polishing stones or collecting footnotes.

The functional work becomes an end in itself. In far too many instances [they] no longer measure their performance by its contribution to the enterprise but only by professional criteria of workmanship.

Source: Drucker, “Management” (emphasis mine)

Notes on Drive

Drive

I told myself that I’d read Drive after finishing The Mythical Man-Month, but I lost interest in the latter pretty quickly. Drive’s “surprising” truth isn’t all that surprising to those of us who are fortunate enough to be creative workers in a frothy tech industry: after a certain point, material compensation isn’t as important to us as the joy we get from doing our work.

I discovered when I reached the end of the book that taking notes on Drive was superfluous; the end of the book is packed with helpful reference material, including an executive summary. Nevertheless, these may come in useful:

  • Motivation has changed through the ages
    • Food, and not being killed
    • Basic needs are met, seek reward and avoid punishment more broadly
    • Motivation 2.1: Loosened dress codes, more flexible hours
    • Motivation 3.0: autonomy, mastery, purpose
  • Problems with carrots and sticks
    • They can extinguish intrinsic motivation
    • They can diminish performance
    • They can crush creativity
    • They can crowd out good behavior
    • They can encourage cheating, shortcuts, and unethical behavior
    • They can become addictive
    • They can foster short-term thinking
  • Carrots work if the task is dull, but you have to acknowledge that it’s boring and necessary, then let people complete the task in their own way.
  • Friedman’s two types of people
    • Type A: Excessive competition drive, aggressiveness, impatience, and a harrying sense of time urgency. Significantly more likely to develop heart disease.
    • Type B: Just as intelligent as ambitious as Type A, but their ambition steadies them, and gives them confidence and security.
  • McGregor’s two outlooks on employees
    • Theory X: People dislike work, fear responsibility, crave security, and badly need direction.
    • Theory Y: Work is as natural as play or rest. People are creative and ingenious, and they will seek responsibility under proper conditions.
  • Pink’s two types of people
    • Type X: fueled by extrinsic desires, concerned about the rewards that activities lead to, rather than the inherent satisfaction of the activity itself.
    • Type I: fueled by intrinsic desires, concerned about the inherent satisfaction of the activity, rather than the rewards that it leads to.
    • Type I’s almost always outperform Type X’s in the long run.
    • Type I’s don’t disdain money or recognition. Employee compensation must hit a baseline or their motivation will crater regardless of their type.
    • Pay a Type I enough and you’ll take money off the table, allowing them to focus on their work. For a Type X, money is the table.
    • Type I’s are physically and psychologically healthier.
    • Humans are, by default, Type I.
  • Autonomy
    • Autonomy is the most important of the three basic human needs.
    • Empowerment is not autonomy. It is simply a more civilized form of control.
    • Type I behavior emerges when people have autonomy over the four T’s:
      • Task. The “20% time” that companies like Google, Atlassian, and DOW give their employees results in many new products.
      • Time. Lawyers are universally sullen because they bill by the hour, and law is a zero-sum game.
      • Technique
      • Team
  • Mastery
    • A mental state of Flow is how people achieve mastery.
    • In Flow, the relationship between what someone has to do and what they can do is perfect.
    • There are two things companies can do to help employees achieve mastery:
      • Give them “Goldilocks Tasks” — challenges that are not too challenging but not too simple.
      • Trigger the positive side of the Sawyer Effect, and turn work into play.
    • Achieving mastery is painful. Therefore, grit is essential to mastery. In fact, it is as essential as talent.

Fees and Credits In Shared Upside Transactions

Marketplace startups are challenging to run because sellers, buyers, and operators of a marketplace have conflicting goals. Sellers want to sell their goods for as much as possible. Buyers want to pay as little as possible. The operators of the marketplace want to reach liquidity as quickly as possible. Each group uses the platform for their own benefit.

Sharing the upside of a transaction is one way to build trust between two parties. For example, realtors typically get a percentage of the final sale price of a house. This incentivizes them to sell the house for a high price, and incentivizes the owner of the home to flexible with open house schedules. To increase profitability, marketplaces use fees and credits to incentivize or punish behaviors.

Managerial accounting of fees and credits in shared upside transactions isn’t as straightforward as I expected. The goal of managerial accounting is to interpret the financials of a company in a way that supports strategic decision making. Here’s an example based on my experience.


GizmoCorp is a hot new startup that buys gently used Gizmos from people in America and ships them overseas to China, where used Gizmos are in high demand because new Gizmos cost an exorbitant amount of money.

Jane, the founder of GizmoCorp, came up with the original idea in the shower and decided to try out the business model. That weekend, Jane convinced her childhood friend Dana to give her Gizmo-for-cash idea a try. When Jane arrived at Dana’s house in Oakland, she noticed that Dana’s Gizmo was rather dirty, and needed professional cleaning before it could be sold. Jane guaranteed Dana at least $15,000 for her Gizmo, and promised to split the difference if the Gizmo sold for anything more than that. Dana agreed, and Jane trucked the Gizmo to the port of Oakland, where it was cleaned, loaded onto a container ship, and sent off to China. Jane has a business partner in China that takes care of selling the Gizmos once they arrive in China. Her business partner charges a flat $1,000 fee per Gizmo sold. A few weeks later, the Gizmo sold for $20,000, and Jane received a wire transfer from her partner in China for $19,000. Thrilled, Jane sent Dana a cheque for $17,500, a thank you card for being GizmoCorp’s first customer, and this receipt:

Dana
Guaranteed Price $15,000
Actual Sale Price $20,000
GizmoCorp Commission -$2,500 ($20,000-$15,000) x 50%
Final Payment $17,500

Jane Goes To Sand Hill Road

Fast forward a year, and Jane is selling tens of Gizmos a day. Jane goes to Capital Partners, a top venture capital firm, and pitches GizmoCorp to them. They decide to invest, but set very aggressive goals for Jane. Jane is only making an average of $2,000 per Gizmo sold right now. The investors are pushing her to make at least $3,000 per Gizmo. Jane is confident that she’ll hit that goal, and takes the money. Jane heads back to GizmoCorp with the good news, explains the new goal for the business, and takes the team out for a happy hour. As the bar is closing, Jane surprises the team by giving them the rest of the week off, and tells everyone to come back on Monday refreshed and ready to go.

The $500 Cleaning Fee

The GizmoCorp executive team gets together on Monday morning to figure out how to make more money per Gizmo. They analyze their past transactions and figure out that they’ve been spending about $500 per Gizmo on cleaning costs. Jane proposes that they pass the cleaning cost on to their customers: they’ll deduct $500 from the usual guaranteed price if a Gizmo needs cleaning. Everyone nods their heads in agreement. They call this the $500 Cleaning Fee.

That day, two customers with identical Gizmos contact GizmoCorp. Ariel’s Gizmo is in pristine condition, and doesn’t need any cleaning. Becky’s Gizmo has been sitting outside for years and needs to be professionally cleaned. Both Gizmos are sold for $20,000. Here are the receipts that were sent out.

Ariel (Without Cleaning Fee)
Guaranteed Price $15,000
Actual Sale Price $20,000
GizmoCorp Commission -$2,500 ($20,000-$15,000) x 50%
Final Payment $17,500
Becky (With Cleaning Fee)
Guaranteed Price $14,500 $15,000-$500
Actual Sale Price $20,000
GizmoCorp Commission -$2,750 ($20,000-$14,500) x 50%
Final Payment $17,250

Problems With The $500 Cleaning Fee

A month later, the executive team meets to discuss the results of the Cleaning Fee. Things are off to a good start! 60% of customers are opting to clean their Gizmos prior to pick-up themselves, up from 30% the previous month. However, there are two unexpected problems.

Firstly, GizmoCorp notices that they’ve had fewer customers than usual this month. The executive team theorizes that it’s because the Cleaning Fee sounds really bad in a pitch. People don’t like fees, because that sounds like money is being taken away from them.

Secondly, Jane pointed out that even though the Cleaning Fee is $500, GizmoCorp is only saving $250 whenever someone cleans their Gizmo themselves. The executives compare Ariel and Becky’s receipts and convince themselves that this is indeed true: their final payments only differ by $250.

The $500 Cleaning Credit

The executive team comes up with a brilliant solution: they’ll implement the Cleaning Fee as a credit instead. They’ll give everyone a guaranteed price that’s $500 lower than usual, but offer a $500 credit if they clean their Gizmos themselves.

That day, two customers with identical Gizmos contact GizmoCorp. Abby’s Gizmo is in pristine condition, and doesn’t need any cleaning. Bernie’s Gizmo has been sitting outside for years and needs to be professionally cleaned. Both Gizmos are sold for $20,000. Here are the receipts that were sent to Abby and Bernie:

Abby (With Cleaning Credit)
Guaranteed Price $14,500
Actual Sale Price $20,000
GizmoCorp Commission -$2,750 ($20,000-$14,500) x 50%
Cleaning Credit $500
Final Payment $17,750
Bernie (Without Cleaning Credit)
Guaranteed Price $14,500
Actual Sale Price $20,000
GizmoCorp Commission -$2,750 ($20,000-$14,500) x 50%
Cleaning Credit $0
Final Payment $17,250

Problems With The $500 Cleaning Credit

A month later, the executives meet up again to discuss the results of the Cleaning Credit. GizmoCorp’s monthly customer count is back to normal. It seems like positioning the fee as a credit has helped. 80% of customers are opting to clean their Gizmos themselves, up from 60% last month. The executives laid out all five receipts next to each other, and added new “breakdown” rows to figure out how much more money GizmoCorp made as a result of the Cleaning Fee and the Cleaning Credit. Here are the formulas they used:

Commission Revenue = (Actual Sale Price - Guaranteed Price) / 2  
Cleaning Fee Revenue = IF clean THEN $0 ELSE $250  
Cleaning Credit Revenue = IF clean THEN $0 ELSE $500  

Comparing Abby’s and Bernie’s final payments, the executives are convinced that they’re now saving $500 whenever a customer cleans their Gizmos themselves.

Jane
(The Original Customer)
Ariel
(Without Cleaning Fee)
Becky
(With Cleaning Fee)
Abby
(With Cleaning Credit)
Bernie
(Without Cleaning Credit)
Guaranteed Price $15,000 $15,000 $14,500 $14,500 $14,500
Actual Sale Price $20,000 $20,000 $20,000 $20,000 $20,000
GizmoCorp Commission -$2,500 -$2,500 -$2,750 -$2,750 -$2,750
Cleaning Credit N/A N/A N/A $500 $0
Final Payment $17,500 $17,500 $17,250 $17,750 $17,250
Commission Revenue $2,500 $2,500 $2,750 $2,750 $2,750
Cleaning Fee Revenue N/A $0 $250 N/A N/A
Cleaning Credit Revenue N/A N/A N/A $0 $500

Jane notices that something is wrong. She adds two more rows.

Dana
(The Original Customer)
Ariel
(Without Cleaning Fee)
Becky
(With Cleaning Fee)
Abby
(With Cleaning Credit)
Bernie
(Without Cleaning Credit)
Guaranteed Price $15,000 $15,000 $14,500 $14,500 $14,500
Actual Sale Price $20,000 $20,000 $20,000 $20,000 $20,000
GizmoCorp Commission -$2,500 -$2,500 -$2,750 -$2,750 -$2,750
Cleaning Credit N/A N/A N/A $500 $0
Final Payment $17,500 $17,500 $17,250 $17,750 $17,250
Commission Revenue $2,500 $2,500 $2,750 $2,750 $2,750
Cleaning Fee Revenue N/A $0 $250 N/A N/A
Cleaning Credit Revenue N/A N/A N/A $0 $500
Revenue Breakdown Total $2,500 $2,500 $3,000 $2,750 $3,250
Actual Revenue $2,500 $2,500 $2,750 $2,250 $2,750

The breakdown rows can’t be correct because they don’t always sum up to the actual revenue for each deal! Jane thinks hard and realizes what the problem is: When a fee is implemented as a credit in a shared upside deal, the commission revenue is increased by a constant amount equal to half the value of the credit, regardless of whether it was applied or not. This constant amount will be double counted unless it is removed from the commission revenue.

Therefore, these are the correct formulas

For Cleaning Fee deals:

Commission Revenue =  
  IF clean
  THEN (Actual Sale Price - Guaranteed Price) / 2
  ELSE (Actual Sale Price - Guaranteed Price) / 2 - $250
Cleaning Fee Revenue = IF clean THEN $0 ELSE $250

For Cleaning Credit deals:

Commission Revenue = (Actual Sale Price - Guaranteed Price) / 2 - $250  
Cleaning Credit Revenue = IF clean THEN -$250 ELSE $250  

And they result in this table:

Dana
(The Original Customer)
Ariel
(Without Cleaning Fee)
Becky
(With Cleaning Fee)
Abby
(With Cleaning Credit)
Bernie
(Without Cleaning Credit)
Guaranteed Price $15,000 $15,000 $14,500 $14,500 $14,500
Actual Sale Price $20,000 $20,000 $20,000 $20,000 $20,000
GizmoCorp Commission -$2,500 -$2,500 -$2,750 -$2,750 -$2,750
Cleaning Credit N/A N/A N/A $500 $0
Final Payment $17,500 $17,500 $17,250 $17,750 $17,250
Commission Revenue $2,500 $2,500 $2,500 $2,500 $2,500
Cleaning Fee Revenue N/A $0 $250 N/A N/A
Cleaning Credit Revenue N/A N/A N/A -$250 $250
Revenue Breakdown Total $2,500 $2,500 $2,750 $2,250 $2,750
Actual Revenue $2,500 $2,500 $2,750 $2,250 $2,750

Much better! Now the revenue breakdown matches the actual revenue. The last thing to do is replace the now redundant “Revenue Breakdown Total” row with something more useful: Profit.

Profit = Revenue - Cleaning Cost - Chinese Partner's $1000 Fee  
Dana
(The Original Customer)
Ariel
(Without Cleaning Fee)
Becky
(With Cleaning Fee)
Abby
(With Cleaning Credit)
Bernie
(Without Cleaning Credit)
Guaranteed Price $15,000 $15,000 $14,500 $14,500 $14,500
Actual Sale Price $20,000 $20,000 $20,000 $20,000 $20,000
GizmoCorp Commission -$2,500 -$2,500 -$2,750 -$2,750 -$2,750
Cleaning Credit N/A N/A N/A $500 $0
Final Payment $17,500 $17,500 $17,250 $17,750 $17,250
Commission Revenue $2,500 $2,500 $2,500 $2,500 $2,500
Cleaning Fee Revenue N/A $0 $250 N/A N/A
Cleaning Credit Revenue N/A N/A N/A -$250 $250
Revenue $2,500 $2,500 $2,750 $2,250 $2,750
Cleaning Cost -$500 $0 -$500 $0 -$500
Chinese Partner’s Fee -$1000 -$1000 -$1000 -$1000 -$1000
Profit $1,000 $1,500 $1,250 $1,250 $1,250

From this table, we immediately notice two things:

  1. GizmoCorp is making a constant amount of profit, equal to half the value of the Cleaning Credit, regardless of whether the customer decided to clean their Gizmo themselves or not.
  2. The Cleaning Fee, in the best case, actually led to more profit than the Cleaning Credit. In the worst case, it made just as much. The executives had intuitively expected to make more from the credit than the fee.

Going Negative

How about the case where the Gizmo unexpectedly sells for less than the guaranteed price, and there is no upside? Here’s the same table, except that the Actual Sale Price has been lowered to $10,000.

Dana
(The Original Customer)
Ariel
(Without Cleaning Fee)
Becky
(With Cleaning Fee)
Abby
(With Cleaning Credit)
Bernie
(Without Cleaning Credit)
Guaranteed Price $15,000 $15,000 $14,500 $14,500 $14,500
Actual Sale Price $10,000 $10,000 $10,000 $10,000 $10,000
GizmoCorp Commission $0 $0 $0 $0 $0
Cleaning Credit N/A N/A N/A $500 $0
Final Payment $15,000 $15,000 $14,500 $15,000 $14,500
Commission Revenue -$5000 -$5000 -$5000 -$5000 -$5000
Cleaning Fee Revenue N/A $0 $500 N/A N/A
Cleaning Credit Revenue N/A N/A N/A $0 $500
Revenue -$5000 -$5000 -$4500 -$5000 -$4500
Cleaning Cost -$500 $0 -$500 $0 -$500
Chinese Partner’s Fee -$1000 -$1000 -$1000 -$1000 -$1000
Profit -$6,500 -$6,000 -$6,000 -$6,000 -$6,000

Like the earlier examples we hold Commission Revenue constant in order to make apples-to-apples comparisons. Here we see that Cleaning Fee Revenue and Cleaning Credit Revenue are identical, and when not zero, are equal to the full amount of the credit or fee: $500. Not only that, but Profit is identical across both the Cleaning Fee and Cleaning Credit. The conclusion: in the case where a Gizmo sells for less than the guaranteed price, the Cleaning Fee or Cleaning Credit will reduce losses by $500 regardless of whether the Gizmo was clean.

The Twilight Zone

How about the case where the Gizmo sells for somewhere between the highest and lowest guaranteed price (between $15,000 and $14,500)? Here’s the same table with the actual sale price set to $14,750.

Dana
(The Original Customer)
Ariel
(Without Cleaning Fee)
Becky
(With Cleaning Fee)
Abby
(With Cleaning Credit)
Bernie
(Without Cleaning Credit)
Guaranteed Price $15,000 $15,000 $14,500 $14,500 $14,500
Actual Sale Price $14,750 $14,750 $14,750 $14,750 $14,750
GizmoCorp Commission $0 $0 $125 $125 $125
Cleaning Credit N/A N/A N/A $500 $0
Final Payment $15,000 $15,000 $14,625 $15,125 $14,625
Commission Revenue -$250 -$250 -$250 -$250 -$250
Cleaning Fee Revenue N/A $0 $375 N/A N/A
Cleaning Credit Revenue N/A N/A N/A -$125 $375
Revenue -$250 -$250 $125 -$375 $125
Cleaning Cost -$500 $0 -$500 $0 -$500
Chinese Partner’s Fee -$1000 -$1000 -$1000 -$1000 -$1000
Profit -$1,750 -$1,250 -$1,375 -$1,375 -$1,375

Like the earlier examples we hold Commission Revenue constant in order to make apples-to-apples comparisons, but it’s definitely harder to intuitively explain what’s going on here. Here is what seems to be happening:

Cleaning Fee Revenue = IF clean THEN $0 ELSE $250 + GizmoCorp Commission

Cleaning Credit Revenue = IF clean THEN GizmoCorp Commission - $250 ELSE GizmoCorp Commission + $250  

A Counterintuitive Result

GizmoCorp leadership made these changes because they wanted to increase profit by encouraging customers to clean their Gizmos themselves. The executives were celebrating increases in the percentage of customers who cleaned their Gizmos, because they intuitively thought it was correlated with cost savings. After performing this analysis, it was clear that GizmoCorp was getting extra profit from every customer regardless of whether they clean their Gizmos themselves or not. They didn’t have to wait to know how much extra profit they were going to make from the credit: if we ignored the rare case where a Gizmo sells at a “twilight zone” price, it is simply:

$250 x expected Gizmos sold above guaranteed price + $500 x expected Gizmos sold below guaranteed price

Cleaning Credit 2

This issue can be avoided by lowering the guaranteed price by $1000 instead of $500. We’ll call this “Cleaning Credit 2”. Cleaning Credit 2 Revenue is indeed $500 when cleaning is required, and $0 when cleaning is not required. Here’s how Cleaning Credit 2 compares to Cleaning Credit 1:

Abby
(With Cleaning Credit)
Bernie
(Without Cleaning Credit)
Angela
(With Cleaning Credit 2)
Beatrice
(Without Cleaning Credit 2)
Guaranteed Price $14,500 $14,500 $14,000 $14,000
Actual Sale Price $20,000 $20,000 $20,000 $20,000
GizmoCorp Commission -$2,750 -$2,750 -$3,000 -$3,000
Cleaning Credit $500 $0 $500 $0
Final Payment $17,750 $17,250 $17,500 $17,000
Commission Revenue $2,500 $2,500 $2,500 $2,500
Cleaning Fee Revenue N/A N/A N/A N/A
Cleaning Credit Revenue -$250 $250 N/A N/A
Cleaning Credit 2 Revenue N/A N/A $0 $500
Revenue $2,250 $2,750 $2,500 $3,000
Cleaning Cost $0 -$500 $0 -$500
Chinese Partner’s Fee -$1000 -$1000 -$1000 -$1000
Profit $1,250 $1,250 $1,500 $1,500

Now, GizmoCorp is making $1,500 in profit in either scenario, and the amount of revenue that can be attributed to Cleaning Credit 2 is either $0 or $500. The “Twilight Zone” problem still persists, but it should happen with low enough frequency that we can safely ignore it.

Notes on Gender Equality by Design

What Works Gender Equality By Design Cover.jpg

Iris Bohnet is a Professor of Public Policy at Harvard. Her new book, “What Works: Gender Equality by Design”, is amazing. It’s full of research-backed recommendations for moving the needle on diversity. Here are my notes, but you should really just buy her book.

Notes

  • When cues about a position’s typical wage range is clear, women are as good as negotiating as men.
  • When employees are prohibited from discussing their salaries with each other, pay discrimination by sex and race is more likely to persist
  • 93% of women do not negotiate their initial offer. 43% of men do this
  • Those who are willing to negotiate advance quicker; performance is not necessarily what gets you promoted
  • Managers have a negative perception of women who ask for a pay increase. The same does not apply to men.
  • Leaning in can backfire. To “lean in safely”, invoke someone else like a supervisor when negotiating. “My team lead suggested that I talk to you about my comp because its not clear to us if its at the top of the pay range”
  • Mentors of women tend to be less senior, have less organizational clout, and they don’t advocate for them as much as mentors of men do for their proteges.
  • Emphasizing meritocracy and merit-based reward practices leads to greater male favoritism
  • Evaluating people sequentially leads to biased conclusions. Comparing people solves this problem.
  • Job postings for male-dominated jobs contain more words like “competence” that signal to women that they don’t belong. This happens in letters of recommendation too.
  • 40% of the gender gap in SAT Math scores can be explained by the unwillingness of women to guess
  • When Asian girls were reminded of their ethnicity, they performed better on Math tests than when they were reminded of their gender
  • Women underestimate themselves, men overestimate themselves
  • When there are only women in the room, women do better at competitions
  • Before 1975, some states still declared men and women adults at different ages
  • Seeing women in leadership positions increases women’s self-confidence and changes both men and women’s beliefs about what an effective leader looks like
  • When there are significantly fewer women than men in senior positions, the senior women are less likely to mentor other women because they see them as competition
  • Men are more likely to support women’s causes when they have daughters
  • Male CEOs who have daughters, especially firstborn ones, are associated with a difference in female employees’ wages
  • The more daughters a male Danish CEO has, the better his employees are paid
  • Start-ups with highly paid women among their first hires were more successful and stayed longer in the market than all-male start-ups
  • People are more willing to accept an unfavorable outcome if they believe the process was fair, but some people don’t believe that quotas are fair
  • The “pipeline problem” is real in some fields like STEM, so quotas might not be realistic
  • Assigning responsibility for diversity to people or groups of people is strongly associated with an increase in workforce diversity

Action Items

  • Invite people to negotiate
  • Be transparent with what is negotiable
  • Have people negotiate on behalf of others
  • Hire & promote in batches, comparing candidates against others in the batch
  • Remove clues that might trigger performance-inhibiting stereotypes
  • Adjust risk when gender differences may bias outcomes
  • Managers should give their reports feedback about their performance, instead of asking them to self-assess
  • Diversify the portraits on your office walls
  • Increase diversity in leadership roles through quotas or other means
  • If you cannot include more than one woman in a team, keep it homogenous so that nobody is a token member
  • Use rankings to motivate people to compete on gender equality
  • Use rules, laws, and codes of conduct to express norms
  • Make specific people responsible for diversity and hold them accountable

Make Reversible Decisions

I recently learnt about the “Rule of Three” from this tweet by Jacob. It says that code should be copied once, and extracted into a procedure only the third time it has to be used. After further thought, I realized that this simple programming rule is a domain-specific manifestation of a more general decision-making guideline.

Lets go back to computing for a brief moment, since many of you reading this are programmers. Abstracting too early is more dangerous than it seems. When abstraction is done too early, it increases the complexity of the product before a complete understanding of the problem has been obtained. As the decision was made with insufficient information, it is more likely to be wrong than right. As more abstractions are layered on top of these bad decisions, it becomes more and more difficult to backtrack as time goes on. Furthermore, as the size of a team grows, it becomes difficult to switch out core infrastructure without stalling the entire team’s progress.

This idea of delaying abstraction can be generalized to all decision making.

In general, decisions that are difficult to reverse should be made as late as possible. Decisions that are easily reversible are great because they are a thinly veiled version of “heads I win, tails you lose”. When you guess correctly, you win, and when you guess wrongly, you get cheap information that can inform your next decision. For example, startups frequently make easily reversible decisions as part of their search for a repeatable business model.

A Framework For Decision Making

  1. If you don’t have to make the decision now, wait
  2. If you have to make a decision now, do something you can undo

The rest of this blog post takes this framework for decision making and applies it to decisions that get progressively more important. I’ll begin with a harmless code quality issue developers can relate to, and end with infrastructure decisions that affect the competitiveness of a business. If you’re not a programmer, I would scroll down to “Decision Making For Managers” and start from there.

Decision Making For Programmers

Functions As Comments

Functions are for defining reusable logic. With very few exceptions, if you are not going to reuse something, don’t make it a function.

Some of you might be wonder why anyone would create a function that only gets called in one place. As a TA for an introductory C++ course who saw this happen quite often, the most common reason I got is that teachers required code to look well organized. Novices then pick up this bad habit of “organizing” code and continue making pointless methods in their own projects and work.

That is how we end up with code that looks like this:

class Car {

public:

Car () {  
  Person owner = createOwner();
  Chassis chassis = createChassis();
  Key key = createKey(chassis);
}

private:

Person createOwner () {  
  return new Person("Jimbo");
}

Chassis createChassis () {  
  return new Chassis("Honda Accord");
}

Key createKey (Chassis chassis) {  
  return new Key(chassis);
}

};

These “do the thing” methods don’t increase the robustness or maintainability of the code, they just slow down the person reading it. This is not abstraction, this is using function names to annotate blocks of code that are usually so simple they don’t need any annotation to begin with.

This is a fairly benign example of knee-jerk decision making. Abstraction for the sake of abstraction is a best, annoying. At worst, it’s a source of bugs.

Recommendation: Unless you get paid per line of code you write, if your function is private and only called in one place, you probably should just use a comment. The “rule of three” is a good guideline here.

Frameworks Are Glaciers

Asynchrony is a powerful way to improve the performance of code. While async APIs are slower by nature, total throughput of the program may be improved because of reduced blocking.

Asynchrony, like multi-threading, is not a silver bullet. It has the potential to introduce insidious bugs, and one that I have been dealing with is attempting to speed up a sync API by doing something asynchronously in it.

I’ve been working with a view system that has gotten just about everything right. It’s modular, has just the right amount of convention without being draconian, and keeps it API lean enough that I hardly ever have to pull up the documentation to do something.

Many months back a small change was made to improve the speed of rendering views: elements were now appended to the DOM in batches using RequestAnimationFrame to stop the browser from locking up when rendering expensive components like long list views.

This addition has caused quite a headache. Render tasks used to have a well defined beginning and end. Now, some components in the view hierarchy may not actually be on-screen when their render method returns. This is an issue in an event-driven system where renders are being triggered all the time. Without knowing when a view is actually done rendering or not, you get weirdness like duplicate components being appended when two render events are triggered in quick succession. There are also more sinister problems, like memory leaks that result from nodes being detached from the DOM while hot code still retains references to them.

Later on, we realized that appending wasn’t even causing the slowdown in the first place. The problem was in parsing large amounts of template code repeatedly, and creating too much DOM at a time. Unfortunately, since we made a bad decision at the framework level, we now had an ecosystem of modules depending on the flawed API, often employing hacks to smooth over the problems bubbling up from the framework.

In hindsight, we should have resisted the pressure to find a quick fix for our users, and taken the time to properly understand the performance issue before we modified a critical piece of our infrastructure. Nevertheless, the lean API will make reverting the bad behavior quite easy, and the bulk of the work will be updating dependents that relied on the misbehaving methods.

Recommendations: Be extra careful when tinkering with lower levels of abstraction, and even more so if there is an ecosystem on top of it. Be as restrictive as possible with your API.

Decision Making For Managers

Organize Your Data

Poor abstraction doesn’t just happen in code. It’s even worse then it happens with data.

Every part of a business is affected by how your data is modeled. Poorly modeled data puts constraints on user interface design, bogs down developers with technical debt, and cripples the ability of the business to take advantage of new opportunities.

Document oriented (noSQL) databases have been growing in popularity lately and for good reason: relational databases are suboptimal for managing semi-structured data. While there are good use cases for a document database, they are being used in situations where a relational database is a much better fit.

The highly abstracted nature of document databases creates an illusion of freedom and speed, and the early stages of a software project will speed by without talk of schemas and migrations. However, from my experience the vast majority of data is relational, and document databases struggle to match the performance and simplicity of an RDBMS when burdened with highly relational data.

Using a document database from the start is therefore a prime example of making a difficult to reverse decision too early. Before core questions like “is our data relational?” have been answered, the developer has already climbed so high up the tower of abstraction that they will encounter significant resistance trying to return to a technology that better fits their needs.

Concretely, the permissiveness of document storage leads to the team accumulating massive amounts of tacit knowledge about their data structure that cannot be easily codified as a schema. This makes moving to an RDBMS later extremely expensive, since they require well defined models and relationships. Furthermore, being able to work directly with plain objects leads to poorly defined or nonexistent interfaces between application code and the database. Since there is no clean interface between the application and the database, a prerequisite for changing the database is defining such an interface and performing a major refactor on the application. For these reasons, starting with a document database can lead to technical debt and switching cost snowballing out of control.

In contrast, it is far simpler to move from a restrictive data model to a more permissive one. Simply turn each row of an SQL database into JSON and throw it into document storage.

Recommendation: Unless you are modeling data that is very well understood and clearly non-relational, resist the temptation to go with a document database, and start with an RDBMS. It is the reversible choice.

Defensive Outsourcing

With the rise of SaaS and module ecosystems it is easier than ever to outsource everything from payroll to server operations. Outsourcing is trading money for time, so it makes sense if you expect to see a net gain in productivity.

Outsourcing comes with its own problems. The goals of your partner are seldom aligned with yours. For example, while you would prefer minimizing switching costs, it is to your partner’s advantage to maximize them. Sometimes, these switching costs are not apparent until you try to break up with a provider.

We were using Cloudant as our database service for a while. To our pleasant surprise, we added a major feature in a few hours by building on top of Cloudant’s integrated search. This came back to haunt us when we grew tired of the terrible performance and excessive downtime.

We went back to self-hosting our database, but this meant figuring out how to implement the search functionality ourselves. Since our app is quite portable, we did not encounter many issues moving it to a different host.

Outsourcing also happens in code. Module ecosystems like npm make it easy for anyone to publish reusable bits of code. It is tempting to rely on someone else’s code, but building on top of someone else’s work without doing your due diligence can come back to haunt you.

When we adopted prova last year as our test runner, we were won over by its beautiful reporting interface. We started building on top of it despite its immaturity, and all was good for a few months. Later we realized that prova had been ignoring and silencing uncaught exceptions. We even caught prova silently skipping entire test cases because of a syntax error! With thousands of assertions already written, it was demoralizing to find out that we couldn’t trust our test runner.

The good news is that prova uses the same unopinionated API that tape uses. Since our test suite is portable, we will be able to switch test frameworks quite painlessly. This wouldn’t have been possible if we started with a very opinionated solution.

Recommendation: Have an exit strategy when building on top of something you’ve outsourced. Keep things portable, so you can undo any bad infrastructure decisions.

Wisdom Is More Valuable Than Reputation

It is not uncommon to see a new technology gain massive adoption. Regardless of the credentials of the body pushing the technology, the risk of adoption is inversely proportional to the age of the technology. This is the same reason why refactors are usually a bad idea: old solutions often look ugly because they have been painstakingly patched to handle edge cases.

In a previous example, I talked about how my experience with Cloudant has been less than ideal. I should mention that Cloudant is an IBM company, a huge name in IT enterprise, and one of the reasons why we trusted them. Another tech behemoth is Microsoft, whose new Windows Azure service has been unreliable enough that companies like K2 are afraid of committing fully. At the same time, K2 has demonstrated some smart decision making by keeping some of its capacity on AWS. This makes the move to Windows Azure an easily reversible decision, should they decide that it fails to meet their needs.

For another example of early adoption gone wrong, here is Khan Academy’s experience as an early adopter of Swift, a promising new technology created by brilliant people under the direction of the well respected Chris Lattner of LLVM fame. 20,000 lines of code later, here is what Andy Matuschak has to say:

In terms of problems, the tooling is not there, and that’s not a dig on the engineers. I happen to think, actually, that the Swift engineering team is one of Apple’s finest engineering teams, but it’s not done yet. It’s full of bugs, it crashes too often. It generates faulty code occasionally. Most critically for us, it’s just really slow. Really, really slow.

Andy Matuschak, A Generation of Lifelong Learners

Since new technology is so unpredictable, it is wise to use a mature solution today, and consider migrating in the future.

Recommendation: Reputation is not a substitute for maturity. Be cautious when adopting new technology, especially if your core competencies as a business depend on them.

Conclusion

Leaning Tower.jpeg

I’ve chosen these examples to show how making reversible decisions can lead to competitive advantage. Like any framework, there are exceptions. Risk usually comes with a commensurate reward; those who made their riches in the early days of the Internet certainly aren’t regretting being early adopters.

Nevertheless, the next time you are faced with a decision, consider the reversibility of your choices, and see if it leads you to a better conclusion. I certainly could have benefited from this thinking a year ago.


Thank you Oscar, Jacob, Matt, Chris, and Dan for reviewing my drafts.