Invariant 3: Don't Build Without a Plan

software development Jan 25, 2024

This post was originally published on https://tftc.io by Will Cole.

Read original post

Invariant 3: Don't Build Without a Plan

Mark is "wired in". It may seem corny, but it's a powerfully real thing.

In Invariant 2: Don’t Design Without a Strategy, we ended up with a spec and schedule. We could have ended up with a number of other artifacts, but we at the very least ended up with a spec and schedule. That spec and schedule means you have a PLAN, and if you have a PLAN, you can write code. That leads us to Invariant 3: Don’t Build Without a Plan.

When I was at Stack Overflow, we were a bit more on the nose in how we described Invariant 3. The incantation for the product team was: NO CODE WITHOUT A SPEC AND A SCHEDULE. We believed this so much that there was a recording of Joel Spolsky, with major Auggie Garrido energy, repeating the line over and over. No code without a spec and a schedule. Don’t Build Without a Plan. 

If you’ve spent your career working in startups, this invariant may seem sacrilegious. If you’ve spent your career working in mid-to-large sized companies, this Invariant may strike you as the most necessary. And this makes sense. If you’re a small startup, under 10 people, the fact that the plan can take longer than the coding could cause your early dev team to have dreams of mutiny. You may not have anyone on the team that has ever written a spec, and the 26 year old CTO may have never had the discipline to sit down and figure out an engineering schedule. You convince yourself it’s not worth it, and at this size, you’ll sometimes get away with it. With fewer than 10 people, you can essentially rely on telepathy. Until you can’t. Then you’re in a seriously bad place. Best you do a good job of this before the telepathy bandwidth runs out. 

Don’t Build Without a Plan lines up with our Build atomic unit. The one that states: Actually implement the thing you designed in the discovery phase with lines of code. This should be the easy part. I say this should be the easy part because for many teams who don’t build software in an opinionated way, this is the hard part. The reason this is the easy part on my teams is because we are following the most important concept in understanding the invariants, which is to solve problems at higher levels of abstraction before we move to problems at lower levels of abstraction. This is not to trivialize the complexities of writing code, only to show that it’s relatively easier to write good code if you have a strategy, a spec, and a schedule in place. 

What is Everyone Else Doing During Build?

If the Build phase is all about writing code, then what exactly is everyone else doing? Let’s start with what they’re not doing. What they’re not doing is:

  • Bothering their engineering team
  • Waiting on the developers to finish
  • Bothering their engineering team
  • Changing a bunch of stuff in the spec just because
  • Bothering their engineering team

You know that scene in the The Social Network, where the guy who plays Mark Zuckerberg is speaking to Justin Timberlake who is pretending to be some other guy, and the guy playing Zuckerberg keeps telling people not to bother one of his developers because he’s “wired in”. I remember that scene coming off as corny, but it’s a powerfully real thing. 

If you’re not a programmer, or are like me and haven’t programmed professionally in a very long time, it may strike you as odd that interrupting a programmer is such a taboo. If you were a novelist, or did some other form of deep writing it would seem intuitive. When someone is programming, oftentimes the time spent on the problem is the most important part of making progress. And that time gets progressively more valuable when it comes in chunks of uninterrupted focus. A programmer is more productive working on a problem after 30 minutes, than they were in the first 5 minutes, and after an hour and a half of uninterrupted time, they can see the matrix in its entirety. Time on target matters because programmers are using RAM in their brain that takes time to fill up with the useful stuff. This stuff helps them navigate the complexities of the codebase: changing stuff here has affects over there, this test needs to be amended to cover my new thing here, and let me build a firewall around this ungodly regex that if I touch, could shut down the county substation for some reason. This could build up to dozens or hundreds of files and linkages in some cases. When the programmer is interrupted (even a simple tap on the shoulder), the risk is that all that RAM gets dumped and the programmer has to build it up again from scratch.

The point is, don’t sit around doing nothing, and for the love of god don’t bother your engineering team. They’re wired in.

Pipelining

What you should be doing is pipelining. You’re always somewhere in the flow of the 5 atomic units. Most of the time, we want to be in a rapid loop of Discovery, Build, and Delivery. With that said, not everybody on the team has the same amount of work to do in each phase. Without being too precise about it, the following table is a rough approximation of how much time people on each team spend on each phase:

Stage

Developers

PMs

Marketing

DevOps

Designers

Discovery

20%

80%

10%

5%

30%

Build

70%

10%

10%

20%

50%

Delivery

10%

10%

80%

75%

20%

If the entire team works in lockstep, strictly doing discovery together, then build together, then delivery together, you get these very quiet periods for developers who are sitting around waiting for specs to arrive, after which you get these very quiet periods for PMs who have given their specs to developers and are waiting for the code to get built etc… Since we don’t want our highly paid tech team sitting around waiting for eachother, it benefits us to be able to build a system where all of these things are happening simultaneously.

Pipelining allows individual team members to spend their time where they are most impactful. Sometimes, that means while engineers are building, PMs are working on entirely different features or products, prepping for another build cycle. Sometimes that means that marketers have 90% of the assets they need to train their sales team, and build their go-to-market plan on the current project, and don’t need to wait for Build to complete to finish prep for Delivery

The DevOps team realizes that once this thing is ready, they’re going to need a beefier server, and can get ahead and set it up now.

While there’s nothing particularly revolutionary about pipelining in this fashion, there is a price to pay– a coordination price. So while the PM may have work to do on delivery for this feature, or discovery on an entirely different feature, they’re still on the hook for keeping everyone informed with information and for deploying effort efficiently so no one is waiting around. This isn’t the 90’s where we all take coffee breaks while we write code and wait for it to compile. We’re doing lots of stuff here, just not bothering the people who need absolute focus.

Now about those people we’re not bothering…

Please Product Guy, Tell Me How to Code Better

Touché. We are at a point where I have less advice because I’m one of those guys buzzing off to another phase in the process while the code is being written. However, I have worked with hundreds of programmers at this point, so indulge me just a bit on how you, Mr. Programmer, can do a great job in the Build phase while working with someone like me.

So let’s take for granted that you’re working with me, and I know how to leave you alone. This doesn’t mean you get to disappear for three weeks. Here are some things that you should always be doing, and sometimes be doing, when you’re not wired in during Build:

  • Always set up time to demo progress with PMs, Designers and Engineering managers (and other peers depending on the project). Yes, even on the small stuff. These people need to see the work, finished or not, in order to keep things on schedule and prepare for the next phase. You need some sort of ceremony that is consistent. This helps them, but it also helps you not get interrupted, because in a few days they all get to talk to you anyway.
  • Sometimes pair program – if you’re new to the codebase, or a subsection, or are working in a complicated area that someone else has excelled in, or you’re just in a rut and need someone around to get on the right track. I say sometimes because I’ve found the practice of always pairing to be quite an insane waste of good people’s time. 
  • Always yell fire as soon as the schedule you set is veering off track. Good PMs will have your back and move mountains while you’re focusing. Just give them the information they need to do so.
  • Sometimes do the wrong thing for the right reasons. Like write code you know you’ll refactor in four months, or will be obsoleted by a feature you know is coming down the pipeline. As long as everyone on the team, not just you, knows why this is happening, it can be a healthy thing to occasionally do.
  • Always share those things that only programmers can discover. That you found a 3x more performant solution than we set out to achieve. That you found an inefficiency in the UX that the designer hadn’t noticed and have a suggestion to make it better. Or that thing we dropped in Discovery because we thought it would take seven weeks–the one everyone loved but we just couldn’t justify–you found a way to get it in the current schedule, while you were deep in the code. 
  • Always get code reviewed and have a process for which reviewers are accountable to you.
  • Sometimes break all of these rules and ask forgiveness later, but don’t get a reputation for doing so often.

So yeah, I have no grand advice to make you a better programmer. You can do that on your own. But what I have given you to this point is a major voice in all the thinking that goes on before we write code–a fabulous spec, a schedule you set yourself, and some peace and fucking quiet to do your work. You’re welcome.

Iterating vs. Incrementing

This feels like as good a place as any to center ourselves on a very important modality. Are we iterating or are we incrementing through a problem? The answer will have an effect on both Discovery and Build, but the dynamic in Build is so vastly different if you’re incrementing vs iterating that I feel it’s best served to discuss here.

In Invariant 1: Think, Then Do, the title image was from Jeff Patton’s extraordinary post from 2008, Don’t Know What I Want, But I Know How to Get It. In the post, he defines iterative and incremental development as:

“By incremental development, I mean to incrementally add software a time (sic). Each increment adds more software – sorta like adding bricks to a wall. After lots of increments, you’ve got a big wall.

By iterative development, I mean that we build something, then evaluate whether it’ll work for us, then we make changes to it. We build expecting to change it. We never expected it to be right. If it was, it’s a happy accident. Because we don’t expect it to be right, we often build the least we have to to then validate whether it was the right thing to build.”

Both modes of working are completely valid. However, it’s vitally important that you know what mode you’re employing well before you exit Discovery. Why you ask?

Incremental Development

  • Specifications and schedules are really locked in.
    • Which means work on Delivery is going to be pipelined with the Build phase.
    • Which means changes in the spec or schedule are bad.
    • Which means people, yeah you PM, really need to leave programmers alone during Build.

Iterative Development

  • Specifications exist (no, you don’t get a pass, you still need to write specs) but we anticipate they will change and evolve as we write code
    • Which means pipelining suffers. Not as much is known for people to do their work in Delivery.
    • Which means PMs and designers and programmers need to communicate during Build and cycle back to Discovery very quickly.

Iterative development is not without structure and doesn’t live outside of the Invariants or the five atomic units. It just necessitates more communication and cycles between Discovery and Build. Incremental and Iterative development are not good or bad. They are both useful if you recognize what mode you’re in on any project. So how can you know what mode you’re supposed to be in?

Incremental Development

  • The spec writer has a strong opinion on what the end result of a feature/product should look like.
  • You’re doing something without a lot of moving parts or dependencies.
  • You have excellent visibility into customer wants/needs.
  • You have immovable deadlines .
  • As Jeff Patton puts it: “We release incrementally so that we actually get the business value we’re chasing.”

Iterative Development

  • The spec writer, and therefore the team, knows some - even many - things about a feature or product, but are still searching for the right overall solution.
  • The team is convinced that if they start building, they’ll find the gaps.
  • You’re doing something complex, potentially with lots of dependencies.
  • You’re inventing something new with no comparables.
  • You have loose deadlines.

The Invariants are of course methodology-neutral and are flexible enough to deal with changes in working style like Iterative vs Incremental development. However, the expectations of how Build and Discovery play out are dependent on the software team coming to an agreement before Build begins on whether you are Incrementing or Iterating. 

Validating Build

So how do we know Build is “done”? We know it’s done when a programmer or team rings a bell, @here’s a Slack channel, or stands up and triumphantly announces: “Finished”. I’m not kidding though, it’s done whenever the programmer says it’s done. 

As far as validation goes, once the feature or product is done, we want to check our engineering schedule and see how we did. Right on time? Early (hey, it’s happened .05% of the time in my experience)? Or Late? This is good information to have when the team does a retrospective or something similar in the future. Keep score and you’ll get better at setting schedules.

As far as accountability goes, we have an Invariant just for checking our work in Discovery and Build. It’s called QA, and everyone should do it all the time. However, really good programmers and product people stack the deck in their favor before QA starts. PMs, designers, and programmers will secretly test their own work, making sure it meets all the requirements as well as looks and performs the way they anticipated. They do this because it would be super embarrassing if the spec said that a button should be green, labeled “Submit”, and saves profile updates but instead was blue, labeled “Enter”, and didn’t save any changes. Whether you have dedicated QA people or not, the process of QA should be more challenging than that. Speaking of…

Code’s Done, Ship It?

We’re close, so close. But before we do, we need to follow Invariant 4: Do What You Said You’d Do, coming soon. 

Originally published in The Tools of Ignorance

Tags

Scrib

scrib enables you to accept bitcoin on the web with any bitcoin payment processor you prefer. available to @Ghost users now. more to come. a @TFTC21 company.