← Back to all field notes
Patterns & practice

When Things Slow to a Crawl

Miscellaneous antipatterns I’ve observed in the wild

Every troubled project I’ve seen had a moment where momentum stopped. Rarely a dramatic failure. A slow, grinding deceleration until shipping anything became hard. The causes are few. The same antipatterns recur across companies, teams, and decades, dressed slightly differently each time. I’ve been guilty of a few of these myself.

What follows is a field guide to the ones I keep meeting. They are grouped by where they originate: architecture, product, planning, people and culture. Each has notes on what I’ve seen work to avoid or recover. None of it is novel. That is the point. These are well-trodden mistakes, and they keep happening because the lessons are hard to internalise before you’ve been burned.


Part one: architecture and technology

Microservice sprawl with no coordinating strategy

The pattern: a new product with no users yet starts life as tens of microservices. Each is owned by someone. Each has its own repository, deployment, sometimes its own datastore and language. No shared plan for how they talk to each other, no contract discipline, no versioning. Within months the team spends more time chasing broken integrations than building features. A change in one service silently breaks three. Nobody can run the whole system on a laptop. Onboarding takes a fortnight.

This usually travels with gratuitous technology diversity: a different language or database or queue for each service, each individually “the best tool for the job.” The Boring Technology Club names the trap. Every new technology you adopt spends a scarce, finite resource, your team’s ability to operate things competently under pressure. Ten technologies, ten failure modes nobody has seen, ten on-call runbooks nobody has written.

Microservices are an organisational technology. They let many teams deploy independently without coordinating. With one team you pay the full operational and cognitive cost of that independence and collect none of the benefit. You have distributed your monolith without earning the right.

What helps: Start with a modular monolith. One deployable unit, firm internal module boundaries enforced by language features (OCaml signatures, TypeScript module exports) or disciplined package structure. You get clean separation without a network call in the middle of every function. Extract a service only under a named pressure: a component with different scaling characteristics, or a second team that needs to deploy on its own cadence. Treat each new technology as a purchase with a price. The default answer to “can we use X” is “no, we already have something that does that.” Stack diversity should be a rare, justified exception.

Event sourcing, event-driven, and distribution for everything, from day one

The pattern: before the product exists, the team decides every state change will be an immutable event in a log (event sourcing), services will communicate only through asynchronous event streams (event-driven), and the whole system will be eventually consistent and distributed. Elegant on the whiteboard. In practice the team debugs across event replays, chases consistency bugs that only appear under load, and cannot answer “what is the current state of order 12345” without consulting three projections. Velocity collapses.

This is often the work of theoreticians who have read deeply and hold strong architectural opinions but have not spent enough time on the front line watching systems debugged, extended, and operated at 3am. Even Martin Fowler, who documented event sourcing carefully and clearly admires it, is plain that it is a demanding pattern with serious costs, not a default.

None of this is a criticism of the patterns themselves. Used where it fits, event sourcing is exceptionally powerful. It was the key enabler behind one of the wins I’m proudest of, at Aether, the AI platform where I was CTO. Event-driven architecture is the same story: decoupling components through events is exactly right for some systems. Both solve specific problems, audit and temporal queries and rebuilding state in new shapes for event sourcing, independent evolution and scaling for event-driven integration. The antipattern is reaching for them before you have those problems. Without them, it is a tax with no return.

What helps: Use a boring, transactional, mutable-state database until something forces you off it. It is well understood, easy to reason about, and “what is the current state” is one query. If you need an audit trail, add an event log for the specific aggregate that needs one, without converting the whole system to a religion. Reach for event-driven messaging, distribution, and asynchrony the same way: per problem, when the problem is in front of you, not as a foundational assumption. Architecture is earned by requirements, not chosen by aesthetics.

Serverless everything

The pattern: the whole backend is functions-as-a-service, sold on no servers to manage and a bill that scales to zero. Then reality arrives. Cold starts add latency on user-facing paths. Local development and debugging become awkward. Per-invocation pricing, fine for short bursty work, turns punishing for anything long-running. The architecture fragments into dozens of tiny functions wired together by cloud configuration nobody can hold in their head. Coordinating them, the orchestration and choreography any non-trivial workflow needs, is usually skipped until it bites. When it is finally addressed, it tends to live in a proprietary, expensive, cloud-specific service (AWS Step Functions and its kin) that locks you in and resists local testing.

I made this mistake myself. In early 2023 I built my first RAG product entirely on SST, which at the time was serverless-only, riding the same infectious enthusiasm. The place it hurts most now is applied AI. An LLM call is dominated by waiting: many seconds, often more, especially with streaming responses where you hold a connection open for the duration. In a serverless model you are billed for that wall-clock waiting time, a premium rate for a function doing nothing but holding a socket. Close to a worst-case fit. FaaS economics and latency were designed for short, stateless, bursty work. A streaming AI workload is none of those. The DBOS team’s talk on serverless past, present, and future traces how the industry arrived here.

What helps: Default to long-lived processes (servers, containers) for steady traffic, long-running requests, or streaming. They are cheaper under sustained load, simpler to debug locally, and do not penalise waiting. Serverless still earns its place for spiky, infrequent, short-lived work: a webhook handler, a nightly job, glue that runs rarely. Pick it as a considered fit for a specific workload, not as a blanket default.

Applied AI with no evaluation framework

The pattern: a team ships an AI-powered feature and improves it by feel. Someone changes a prompt, tries a few examples, decides it looks better, ships. No systematic measurement. When a stakeholder asks “is the new model actually better,” the answer is a shrug dressed up as confidence. Worse, regressions are invisible. A prompt change that fixes one category of input quietly breaks two others, and nobody knows until a customer complains.

Without an evaluation framework you are not engineering, you are decorating. Every decision rests on anecdote, on whoever argued most forcefully about whichever examples they happened to try. You cannot tell improvement from drift. You cannot safely change anything, because you cannot see what you broke.

What helps: Build the eval harness early, before the feature is interesting. Assemble a dataset of real inputs with known-good characteristics. Define metrics that reflect product quality, not convenient proxies. Make the eval runnable on demand and in CI. Treat a prompt or model change like a code change: it must pass the suite. Include adversarial and edge cases, and grow the set every time a failure escapes to production. The harness converts AI development from anecdote to a feedback loop, the only thing that compounds. I’ve come to call this eval-driven development (EDD): a stochastic subset of test-driven development, where the suite asserts over probabilistic outputs rather than exact returns. I’m planning a separate essay on it.


Part two: product and strategy

Saying yes to everything

The pattern: a SaaS product lands a handful of large customers, and each of them, being large and paying, dictates the roadmap. Every customer’s special request becomes a feature. No triage, no sense of which requests express the product’s purpose and which express one account’s idiosyncrasy. Over a couple of years the product becomes a bunyip, assembled from everyone’s wishes, coherent to nobody. Each new customer is harder to satisfy because the product no longer has a clear shape to sell. Development grinds to a halt under conditional logic and special cases.

The cause is absent product identity. Without a clear answer to “what is this product for, and who is it for,” every request looks equally valid and the loudest voice wins. Saying yes feels like good service. Repeated, it is how a product loses the thread.

What helps: Decide what the product is, and let the decision do real work. A request that serves the core purpose and many customers is a feature. A request that serves one account’s peculiarity is either custom consulting, priced and quarantined as such, or a polite no. Triage every request against the product’s identity, out loud, consistently. Some of the most important strategic moves a product makes are visible refusals. A product shaped for everyone is shaped for no one, and cannot be sold as anything in particular.

Misreading product-market fit

The pattern: early signals look wonderful. Friendly contacts try the product and say encouraging things. A few pilots convert. The founders read this as product-market fit, scale the team, hire ahead of need, and commit to a burn rate that assumes the curve continues. It doesn’t. The warm-network enthusiasm was affection, not demand. The pilots were exploratory budgets, not committed revenue.

Product-market fit is not binary. It comes in degrees, and First Round’s levels of product-market fit is a useful map of that gradient. The mistake here is reading nascent fit as strong fit and betting the company on it.

Two errors feed the misread. First: treating warm-network signals as representative. People who know you will try your thing and say kind words. That is friendship, not evidence. Second: treating pilot run-rate as ARR, which is just bad accounting. A pilot is an option to buy, exercised with someone else’s discretionary money. Annualising it is a story you tell yourself. The standard reflex, hiring people to fix the unease, is one Y Combinator warns founders against repeatedly. Scaling the team early multiplies burn, dilutes culture, and creates the appearance of progress while the underlying question, does anyone actually need this, stays unanswered.

What helps: Discount warm-network feedback heavily. Weight evidence by what it cost the other party to give. Money committed, contracts signed, and unprompted reuse count. Polite enthusiasm does not. Keep pilot revenue and recurring revenue in separate columns and never let them mingle in a board deck. Stay deliberately small and understaffed until the demand signal is loud and comes from strangers. Hiring does not discover product-market fit. It is a bet that follows it.

Not running the Mom Test

The pattern: a team validates an idea by describing it to potential customers and asking whether they’d use it, whether they like it, whether they’d pay. The answers are warm. The team feels validated and builds. The warmth was meaningless. The questions were leading, and the people answering had every social incentive to be kind.

Rob Fitzpatrick’s The Mom Test exists to prevent this failure. The insight: do not ask people for opinions about your idea. Even your mother will lie to spare your feelings. Ask instead about their life. What they did. When they last hit this problem. What it cost them. What they have already tried and paid for. Facts about the past are reliable. Opinions and predictions about your idea are not.

What helps: Never pitch during a validation conversation. Ask about specifics that already happened. “When did you last run into this?” “Walk me through how you handled it.” “What did that cost you, in money or time?” “What have you already tried, and what did you pay for it?” If someone has never sought a solution, never spent anything, cannot recall a concrete instance, you have found a problem nobody is motivated to solve, regardless of how enthusiastically they endorse your slide. Compliments are not data. Behaviour is.

Building something on the commoditisation path

The pattern: a team builds a product that sits in the path of a large platform’s natural expansion, or that is thin enough to be cloned quickly once it works. For a while it sells. Then the obvious happens. The incumbent ships the feature, or three competitors copy it, and the product has no defensible reason to exist. The differentiation was a head start. Head starts expire.

The risk is sharper now. Capable AI models make a large class of once-defensible software cheap to replicate, and platform owners are expanding their surface area aggressively. A product whose entire value is a thin wrapper over a capability everyone can access is not a business. It is a demo with a payment form.

What helps: Before committing, ask where the product sits relative to the giants’ roadmaps and how hard it is to copy. But don’t over-invest in a moat before you have something worth defending. A moat around a product nobody wants is wasted effort. Find real demand first, then make it defensible with an advantage that compounds rather than expires:

  • Deep vertical expertise. Encode the hard-won domain knowledge of a specific industry into the product in a way a generalist platform will not bother to match.
  • A data flywheel. Use generates proprietary data that makes the product better, which attracts more use, a loop a latecomer cannot copy because they lack the accumulated data.
  • Deep tech IP. Novel algorithms, a distinctive architecture, or a hard technical capability that resists copying. The technical special sauce, not a thin wrapper over a commodity model.
  • Workflow integration and switching costs. Become embedded in how the customer works, so leaving is expensive.
  • Regulatory and trust barriers. Certifications, compliance, and earned trust a fast follower cannot shortcut.
  • Network effects. Value that grows with each additional user, so the product improves the more people use it.

The test is whether your advantage grows with time or erodes with it. If it erodes, you are renting your differentiation, and the lease is short.


Part three: planning and process

Waterfall and the year-long roadmap

The pattern: the organisation commits to a detailed roadmap stretching twelve months or more. I have seen multi-year ones. It is maintained not by a single non-technical management layer but by several, a wide, shallow, top-heavy org chart thin on the leaves who actually execute. The roadmap is treated as a promise rather than a guess, and underwriting it is a vast up-front estimation exercise of the kind that cannot be done with any accuracy: estimates at that range and granularity are guesses compounded into a forecast, then frozen into a commitment. Engineers are measured against it. When reality diverges, as it always does, the response is to pressure the team to hit it anyway. The result is burnout, expensive turnover, and the slow loss of institutional knowledge that walks out with each departure.

A long-range software roadmap is fantasy presented as commitment. It assumes you will learn nothing over the year that changes your mind, which is the same as assuming the work is not worth doing. If you learn nothing, you were not exploring anything. It is hubris: a claim to know in January what you cannot know until you have shipped something in March and watched what happened.

The same disease shows up in miniature as process ceremony. RFCs that stay open for months accreting comments, often because a “servant leader” (an antipattern of its own) has no confidence in their own judgement and waits for a consensus that never arrives. A decision needs an owner willing to make it. In product and engineering, a benevolent dictator usually beats a committee: the BDFL model, Andrew Kelley on Zig for instance, ships coherent, opinionated decisions while the democracy is still leaving comments. Issue trackers swell the same way, now often populated in bulk by an AI assistant wired into the project management tool (a Linear MCP server, say), holding hundreds of tickets that describe an approach the team will abandon the moment it learns the approach was wrong. The volume of planning artefacts becomes a measure of activity, and the artefacts are stale on arrival.

What helps: Plan in horizons. Be concrete and committed about the next few weeks, directional about the next quarter, and frankly vague about anything beyond that, because vague is the accurate description of what you know. Shorten the loop where you can: some teams run one-day sprints, planning in the morning, shipping by the end of the day, reflecting and replanning the next, so no plan lives long enough to ossify. Treat the plan as a hypothesis the team is actively trying to disprove, and make updating it a sign of health rather than failure. Optimise for three things: learning speed, non-regrettability (the preference for decisions that are cheap to reverse), and cheap pivots. Keep planning artefacts thin and disposable, and resist over-planning, a temptation made worse now that an AI assistant can generate hundreds of tickets in seconds. A plan that fast to produce is worth about that much; the bottleneck was never writing the tickets, it was learning which ones matter. An RFC should be decided or discarded in days. A backlog of five hundred issues is not foresight. It is debt with a due date you have already missed.


Part four: people and culture

Tolerating the curmudgeon

The pattern: a team carries a senior engineer who is gruff, dismissive, and reflexively negative, and the culture tolerates it because he is “brilliant” or because he has been there longest. Often the brilliance is not even there. Where it is believed, it is usually believed by the non-technical people he has fooled, the ones not equipped to check the work. The archetype is the expert beginner. Someone who reached a local plateau years ago, mistook it for the summit, and stopped climbing. A greenhouse flower: capable inside the one environment he has always known, unaware of the size of what he does not know. His confidence is not earned by range. It is preserved by never leaving the greenhouse.

A revealing variant is how he behaves around people who actually outmatch him in skill. Threatened by true experts, he lashes out: belittling their contributions, stonewalling their proposals, sometimes quietly sabotaging work he cannot match himself. The reflexive negativity is not rigour. It is self-defence, guarding a reputation he suspects he cannot back up.

The damage is disproportionate and compounding. He shoots down ideas reflexively, so people stop offering them. Juniors learn not to ask questions, which means they learn slowly and badly. Good engineers, the ones with options, leave first. What remains is a team selected for tolerance of the curmudgeon, which is not the trait you wanted to select for.

What helps: Name the behaviour early, specifically, and as a performance problem, because that is what it is. Technical skill does not buy an exemption from being a decent colleague. Make “how does this person affect everyone around them” an explicit, weighted part of how senior engineers are evaluated. Counter the greenhouse effect by exposing strong opinions to outside air: external review, rotation, conferences, contact with how other organisations work. Be willing to part with the person if the behaviour does not change. A team almost always speeds up after a tolerated curmudgeon leaves, which tells you what the tolerance was costing all along.

The side-quester

The pattern: a developer who is energetic and visibly busy but rarely on task. Assigned tickets sit open or quietly get handed back while they pursue something more interesting. A tooling migration nobody asked for. A refactor of a part that was working. A shiny new framework introduced over a weekend. The work is real, and visible, which is part of the appeal. The boring, critical foundations get skipped. Coordination with the team gets skipped. They are wounded if the surprise initiative is not applauded, because in their mind they were showing drive.

The cost is subtler than slacking, which is why it is tolerated longer. The side-quester produces output, sometimes impressive output, so it takes a while to notice that committed work is not getting done, that other people are blocked, and that the codebase is accumulating half-finished enthusiasms. They optimise for the interesting and the visible over the necessary and the dull. A team cannot run on that.

What helps, including screening for it: Hard to catch in interviews because the side-quester interviews well. Shiny work shows initiative, breadth, and energy, exactly what a standard interview rewards. A few things help. In the behavioural interview, ask not for an impressive project but a boring one: “Tell me about a tedious piece of work you owned end to end. How did you stay with it?” The side-quester struggles to produce a good answer and often visibly deflates, because the question gives no room for the shiny. Probe handoffs and follow-through: “Tell me about something you started that someone else finished,” and listen for whether they tracked it to completion or lost interest at the fun part. In any take-home or pairing exercise, set a deliberately mundane task and watch whether they do the asked thing or gold-plate, add an unrequested tool, or wander. In references, ask the specific question: “Did they reliably finish the unglamorous parts of what they took on?” Design every signal to reward finishing the boring thing, because that is precisely what the default interview fails to test and the side-quester lacks. Once hired, make completion of committed work the visible, praised metric, and treat unsanctioned side projects as the thing that needs justification, not the thing that earns applause.

Treating R&D as a cost centre

The pattern: leadership frames research and development as overhead, a cost to be controlled, minimised, and justified. Budgets are defended rather than invested. The implicit goal is to spend as little as possible on engineering while keeping the lights on. The framing leaks into every decision. Hiring is reluctant, tooling is starved, exploratory work is the first thing cut when numbers tighten.

This inverts the relationship. In a software company, R&D is not the cost of doing business. It is the business. The function that creates the product, the differentiation, and the future value. Calling it a cost centre is a category error that becomes self-fulfilling. Starve it and it produces less, which seems to confirm that it was a drain, which justifies starving it further. Companies talk themselves into decline this way, one defensible-looking cut at a time.

What helps: Frame and fund R&D as the value-creating engine it is. The question is not “how little can we spend” but “what is the return on what we spend, and how do we raise it.” That reframe changes everything downstream. You invest in tooling because it compounds. You protect exploratory capacity because that is where next year’s product comes from. You hire as an investment with a return rather than a cost to be resisted. Leaders who see engineering as a cost manage it toward the minimum. Leaders who see it as the engine manage it toward leverage. Only one is trying to win.


Common themes

Lay these eleven antipatterns side by side and a few deeper patterns show through. Worth naming, because recognising the theme lets you spot a new variant before it has a name.

Paying for sophistication you have not earned. Microservices, event sourcing, event-driven architecture, serverless, distribution: each is a legitimate solution to a problem some companies have. The antipattern is not the technology. It is adopting the solution before you have the problem, paying the full operational and cognitive cost up front for benefits that only materialise at a scale you have not reached. Sophisticated tools have prerequisites. Using them without the prerequisites buys all the cost and none of the return.

Mistaking activity for progress. The bulging backlog, the months-old RFC, the side-quester’s flurry of visible work, the headcount added before product-market fit, the year-long roadmap: each generates motion, artefacts, and the comfortable feeling of effort. None necessarily moves the thing that matters. Much dysfunction is the substitution of legible activity for actual progress, because activity is easier to see, easier to measure, and easier to feel good about.

Refusing to let learning change the plan. The waterfall roadmap assumes you will learn nothing. Event-sourcing-from-day-one assumes the design needs no revision. Saying yes to everything is a refusal to learn what the product is. Misreading product-market fit is a refusal to hear what the market is saying. The healthy posture treats every plan, architecture, and product belief as a hypothesis to be tested and cheerfully revised. The antipatterns all, in their different ways, treat the early guess as a commitment and defend it against the evidence.

Avoiding the boring and the necessary. Gratuitous technology diversity, the side-quester’s shiny migrations, R&D managed as cost rather than craft: the recurring move is flight from unglamorous fundamentals toward something newer and more visible. Contract discipline, a boring database, finishing the assigned ticket, an evaluation harness, paying down the foundations: this is the work that compounds, and consistently the work that gets skipped because it does not look like much.

Optimism unchecked by instrumentation. No evaluation framework, so the AI feature is “better” because it feels better. Warm-network signals read as demand. Pilot revenue read as ARR. The Mom Test ignored, so compliments are read as validation. The failure is believing the flattering interpretation because nothing was built to produce a truthful one. The cure is always the same in shape. Build the instrument first: the eval suite, the separate revenue columns, the behavioural question. Reality needs a way to reach you before the expensive decision is made.

Tolerating the wrong things. The curmudgeon is kept for his seniority. The side-quester is praised for visible energy. The unearned architecture is admired for its elegance. The roadmap is respected for its detail. Each is a culture rewarding the wrong signal: comfort, polish, visible effort, apparent rigour, rather than what is actually wanted, a team that learns fast and ships steadily. Cultures get the behaviour they tolerate and reward. If the wrong things are tolerated, the wrong things compound.

If there is one sentence under all of it: things grind to a halt when a team optimises for how things look (sophisticated, busy, planned, harmonious, impressive) instead of for the humble, measurable, and often boring reality of learning quickly and shipping steadily. Every antipattern here is a version of that trade, made for understandable reasons, regretted later. The way out is not cleverness. It is the discipline to prefer the earned over the impressive, and the discipline to build the instruments that tell you which is which.

// Share

Disclosure: LLMs have been used in the editing and research of this post.

// Context & author

You are reading Field Notes by Auxil

Auxil is an independent software systems consultancy and active product factory operated by veteran software practitioner Tim Farland alongside a vetted peer network of senior specialists. Based on Waiheke Island, Auckland, we design, build, and audit high-stakes SaaS systems and production-grade AI pipelines globally.

Explore →

Tim Farland

Operator / Architect / Engineer
// Contact

Let's discuss your project

If you are looking for a reliable, competent, efficient Principal Architect or Engineer for scoped, delivery-focused contracting or advisory, reach out.

Waiheke Island, Auckland · Available for remote or CBD hybrid engagements