A Case for Procrastination

A linup of Model T Fords

The most valu­able, unique as­pect of soft­ware de­vel­op­ment is the speed at which we can it­er­ate. Soft­ware pro­jects that don’t it­er­ate quickly and fre­quently usu­ally stag­nate and fail, while pro­jects that work with user feed­back on an al­most real-time ba­sis are the most suc­cess­ful. I’ve no­ticed the dif­fer­ence per­son­ally, with my work at Archytas Automation. Most re­cently, I’ve read The Lean Startup, Zen and the Art of Motorcycle Maintenance and The Pragmatic Programmer. While each uses their own ter­mi­nol­ogy, both go into depth on the depth on the topic of fast it­er­a­tion cy­cles.

Lean Manufacturing and Lean Thinking

Lean man­u­fac­tur­ing, as ex­plained in The Lean Startup is a pro­duc­tion method­ol­ogy fo­cused on avoid­ing waste. The book’s pri­mary ex­am­ple is the Toyota Production System.

In the mid 1930s, the world’s largest car man­u­fac­turer was Ford. Ford’s fac­to­ries pro­duced thou­sands of unique parts, which to­gether could form a car. They pro­duced these parts in bulk, and each dis­tinct part had an en­tire ma­chine ded­i­cated to pro­duc­ing it. There was a ma­chine that made springs, a ma­chine that made nuts, and a ma­chine that made bolts. No ma­chine could make any part other than the one it was de­signed for.

This was great: it meant that cars would be cheaper than ever, and more peo­ple could ex­pe­ri­ence car own­er­ship.

Around this time, Toyota en­tered the au­to­mo­tive in­dus­try. How­ever, they did not have the time, nor the money to de­sign and build the same kind of hy­per-spe­cific man­u­fac­tur­ing ma­chines that Ford used. In­stead, they chose to pur­chase com­par­a­tively few hy­per-gen­er­al­ized ma­chines. Their strat­egy was to build one car at time, and sell it as soon as pos­si­ble (ideally the mo­ment it rolled off of the fac­tory floor). This way, if there is an is­sue with the ve­hi­cle, the de­sign can be mod­i­fied be­fore too many faulty cars are as­sem­bled.

The Toyota Production System em­pha­sized flex­i­bil­ity over ef­fi­ciency. By stay­ing flex­i­ble, Toyota gave it­self the abil­ity to op­ti­mize all as­pects of the busi­ness in the mid­dle of a pro­duc­tion run.

On one hand, the Ford process looked like this:

  • Get ma­te­ri­als for one hun­dred cars.
  • Fabricate over a thou­sand dis­tinct parts re­quired for each car (likely more than a hun­dred thou­sand to­tal parts).
  • Assemble one hun­dred cars .
  • Sell one hun­dred cars.
  • Receive feed­back on ve­hi­cle and pro­duc­tion process.
  • Perform all pos­si­ble changes to the ve­hi­cle’s de­sign and pro­duc­tion process (which would be very lit­tle).

With this many steps, each tak­ing place over a com­par­a­tively long time, the it­er­a­tion cy­cles are few and far be­tween. On the other hand, the Toyota Production System looked like this:

  • Get ma­te­ri­als for one car
  • Fabricate the rel­a­tively few dis­tinct parts re­quired for the car
  • If there is an is­sue with the pro­duc­tion process (a ma­chine breaks, some­one gets hurt, etc.). Stop the whole process and fix the is­sue, so it will not af­fect fu­ture cars.
  • Assemble one car.
  • Sell one car.
  • Receive feed­back on ve­hi­cle and pro­duc­tion process.
  • Perform all pos­si­ble changes to the ve­hi­cle’s de­sign and pro­duc­tion process (which could be quite a lot, given the flex­i­bil­ity of both).

Counterintuitively, per­form­ing each step with a batch size of one ac­tu­ally ended up be­ing more ef­fi­cient. Even though Ford ex­pe­ri­enced a higher level of ef­fi­cient within each batch, their process led to many more wasted parts be­ing man­u­fac­tured, as well as a lack of com­mu­ni­ca­tion be­tween steps, which dra­mat­i­cally in­creased the amount of wasted ef­fort. Ad­di­tion­ally, be­cause the Toyota Production System al­lowed com­par­a­tively rapid it­er­a­tion, Toyota ve­hi­cles were sim­ply bet­ter: more durable, and more use­ful to their cus­tomers.

Lean Thinking In Software

In soft­ware de­vel­op­ment, it can be tempt­ing to go the Ford route: cre­ate a de­tailed plan of all the fea­tures you wish to add to your ser­vice, then, de­velop the fea­tures, and de­liver them all at once. Only then do you ac­cept feed­back and eval­u­ate the use­ful­ness of each fea­ture.

In The Lean Startup how­ever, Eric Ries sug­gests an al­ter­na­tive method­ol­ogy, in­spired by the Toyota Production System. Before de­cid­ing on which fea­tures to in­clude in your ser­vice in an all-at-once, shot-in-the-dark man­ner, per­form ex­per­i­ments. Cre­ate an ab­solutely min­i­mal pro­to­type of the fea­ture, give to a cus­tomer, and ob­serve how they use it. It is pos­si­ble they find the fea­ture un­help­ful, or they use it in a way you did­n’t ex­pect. By run­ning the ex­per­i­ment early on, there are far fewer un­help­ful fea­tures in­tro­duced, and the cus­tomer gets a prod­uct more closely tied to their needs.

Further, it is pos­si­ble that your un­der­stand­ing of the prob­lem do­main is mis­in­formed. Plan­ning out the en­tire prod­uct re­lease months in ad­vance is prob­lem­atic when the re­quire­ments of the pro­ject change (and they will, of­ten).

Why Interpreted Languages Can Be So Productive

Interpreted pro­gram­ming lan­guages are al­most laugh­ably per­va­sive. Of the top ten most pop­u­lar pro­gram­ming lan­guages on the 2023 StackOverflow Developer sur­vey, six were in­ter­preted. That count does not in­clude TypeScript, which can be used in a semi-in­ter­preted man­ner. In­ter­preted lan­guage pop­u­lar­ity is of­ten chalked up to their ease-of-use, ab­strac­tion, and sim­ple, English-like syn­tax. How­ever, I be­lieve there is an ad­di­tional rea­son: they al­low one to it­er­ate much, much faster.

Micro-iterations

Iterations can hap­pen on any timescale. Micro-iterations oc­cur hap­pen over the short­est time scale. These are small, in­cre­men­tal changes that oc­cur (usually) when de­bug­ging or op­ti­miz­ing code. It is the amount of time (and by ex­ten­sion, men­tal over­head) that re­sults from a change. The longer it takes for tests to com­pile and run, the longer it takes to de­bug.

I be­lieve you can model it like so:

time to de­bug=(time to test)2text edit­ing\text{time to de­bug} = (\text{time to test})^2 * \text{text edit­ing}

This is not an ex­act, rep­re­sen­ta­tive equa­tion, merely an ab­strac­tion to il­lus­trate my point, based on per­sonal ex­pe­ri­ence.

In other words, the to­tal de­bug­ging time in­creases su­per-lin­early as the time it takes to test a change to the pro­gram in­creases. No­tice how, as the time to test in­creases, the ac­tual amount of time text editing falls to a neg­li­gi­ble ra­tio of the to­tal. I be­lieve this comes from the fact that as com­pi­la­tion time in­creases, the amount of in­for­ma­tion gleaned per mi­cro-it­er­a­tion tends to de­crease.

JIT Compilation and Hot Reload

This is where we get to the ti­tle of the ar­ti­cle.

The con­cepts of lean think­ing ex­tend into com­piler tech­nol­ogy. The Toyota Production System in­cludes the con­cept of Just-in-time”, mean­ing, “to only pro­duce ex­actly what is needed for the prod­uct, ex­actly when in the process it is re­quired.” Avoid plan­ning re­source re­quire­ments ahead of time and build sys­tems that only pro­duce what is ac­tu­ally needed.

While the mean­ing of Just-in-time” is dif­fer­ent when we re­fer to com­pil­ers, the line of think­ing is ul­ti­mately the same. In­stead of wast­ing valu­able, hu­man-scale time on com­pi­la­tion and op­ti­miza­tion of ir­rel­e­vant code, just com­pile the code you need, when you need it. This dras­ti­cally re­duces the amount of time to test, and ul­ti­mately, the time to de­bug.

Further, tech­nolo­gies like React and Flutter’s Hot Reload make it pos­si­ble to com­plete these mi­cro-it­er­a­tions with­out hav­ing to restart your pro­gram. I be­lieve this is partly why in­ter­preted lan­guages are so be­gin­ner-friendly (other than the high level of ab­strac­tion they typ­i­cally pro­vide). New­com­ers to pro­gram­ming spend most of their time on syn­tac­tic is­sues and sim­ple run­time er­rors. By mak­ing mi­cro-it­er­a­tions hap­pen as fast as pos­si­ble, you make these is­sues less an­noy­ing to deal with.

Procrastination

If you are in uni­ver­sity (like I cur­rently am), or any other level of ed­u­ca­tion, it can ac­tu­ally be ben­e­fi­cial to hold off on do­ing your home­work. It is not un­com­mon (at least in my ex­pe­ri­ence) for the pro­ject or pa­per re­quire­ments to change at the last minute. Some of your peers may choose to com­plete the pro­ject or pa­per as soon as pos­si­ble. If this is the case, you may ben­e­fit from their ex­pe­ri­ence. If a cer­tain chain of logic or analy­sis is con­fus­ing or mis­lead­ing, they can warn you to avoid los­ing time. As­sum­ing they are will­ing, they can also pro­vide in­sight­ful feed­back on your work mid-way through your writ­ing or study process.

Conclusion

Iteration is in­cred­i­bly im­por­tant to any de­sign and de­vel­op­ment cy­cle, es­pe­cially in soft­ware. Since I have em­braced it­er­a­tion, I’ve seen a dra­matic im­prove­ment in my pro­duc­tiv­ity and ef­fec­tive­ness. So I en­cour­age you: if your build process takes 30 min­utes, spend some time on im­prov­ing it. If you are work­ing on a pro­ject that has­n’t been put in front of a cus­tomer, try show­ing it to a fam­ily mem­ber or non-tech­ni­cal friend. Ask them for bru­tal hon­esty, and your pro­ject will be much bet­ter off.