My dear friend Markus once said something that resonated with me: “I don’t want to be blocked”. I appreciate framing blockers as a choice because it emphasises progress and places the responsibility of shipping squarely on me.

Virtually all projects eventually run into blockers. Perhaps a different team needs to add a new field to their API response, or the internal synthetic monitoring tool doesn’t support MCP servers yet. Whatever it may be, I find there are three ways to react:

  1. Do nothing and wait for the blocker to be resolved.
  2. Actively help resolve the blocker, for example by opening a pull request to add the necessary API field.
  3. Rescope the project to remove the blocker. Gradual improvement is great, and I prefer shipping an imperfect solution today to a pristine one next quarter.

In the majority of cases, options two and three are both feasible and an excellent way to show colleagues and stakeholders that shipping is a priority. The second option in particular is more appealing than ever because AI agents make it relatively easy to step into uncharted territory to make changes.

An insidious version of this problem occurs in large enterprises where things move slowly and projects commonly cut across teams. In such an environment, those looking hard enough can always find a nearby blocker to dodge the responsibility of shipping. At a small scale, this might manifest as “please wait for my refactor to be done before merging your pull request”, while on a larger scale, it could be “let’s start work on our MCP server in Q4 when the API migration is done”. The issue here is that refactors and migrations are a constant state in enterprises. Come next quarter, some new thing will have emerged to discourage progress.

Shipping requires laser focus, willingness to compromise, and, above all, acknowledging that the responsibility lies with me. I want to make progress, and I don’t want to be blocked.