How we develop

Beliefs

Simple beats complex

If there’s a simpler way to do something, do that. A CSS-only solution is preferable to cumbersome JavaScript libs that achieve the same thing. A static solution is preferable to a dynamic one if the data rarely changes. A boring, obvious solution that works is better than a clever one that needs explanation. Complexity has a cost: it slows understanding, increases bugs, and makes future changes harder. We only regress into complexity when simplicity genuinely can’t meet the need.

Document everything

Code is read far more often than it is written. As you write code, comment why something exists, not just what it does. Write short explanations outside the code that describe how the system works. Add a date when documenting non-obvious behavior so others know how current the explanation is. It’s much harder to explain code after the fact, especially in larger codebases. Documenting as you go allows others — and future-you — to pick up work confidently without reverse-engineering intent.

Speak the second language

Every codebase is written in a language (eg javascript, ruby). But every codebase also has a second language: patterns, conventions, structure, and assumptions. When working in an existing codebase, follow its patterns, even if you’d personally do it differently. Match naming, structure, and style. Resist the urge to “clean up” unrelated areas unless explicitly asked. Consistency is tidiness. A system where everything is blue is clearer than one where one section is green because someone preferred it once.

Red, green, refactor

First solve the problem, even if the solution is a bit rough. Then make it correct, reliable, and complete. Finally, refactor it into something elegant and simple. Don’t let the desire for the perfect solution prevent forward progress. The end result should be clean and thoughtful, but you are more likely to arrive at that solution if you allow yourself to make it work imperfectly first.

If in doubt,discuss

If you suspect something already exists in the codebase (a function, helper, pattern, solution to a similar problem, etc.), then recreating it should be a last resort. First take a moment to search more deeply, ask a peer, or flag the uncertainty. A few minutes of due diligence can prevent years of duplicated logic and technical debt. When unsure, conversation beats assumption.

Partner-ready != locally correct

Code is not done when it works on your machine. It’s done when it’s wired into the real system, edge cases are handled, errors fail gracefully, a partner cannot accidentally break it through normal use, and it's integrated into its surroundings.

Process

Asset Grab

Before writing code, we make sure we understand what we’re building and what we’re building with. This means reviewing the design materials provided, reviewing the existing codebase (if there is one), and understanding how the new work fits into what already exists. Sometimes everything we need is already present in the system. Sometimes assets, decisions, or clarifications are missing. In both cases, it is the developer’s responsibility to identify what’s needed and go and get it.

This does not mean we block all progress until everything is perfect. It means we take ownership of readiness: requesting missing assets. Asking clarifying questions. Flagging assumptions clearly in Basecamp. Development should not stall because something is unclear. If clarity is missing, we actively pursue it while moving forward where reasonable.

Spike

Before committing to implementation, we do a spike. A spike is a short, quick step to sketch and/or write out how a solution will work, explore feasibility or constraints, and sanity-check the shape of the solution with peers. If we can explain how we’re going to build something before we build it, we greatly reduce the risk of rework due to additional context or data later.

Red, Green,Refactor

Once we’re confident in the approach, we build. We follow a Red, Green, Refactor approach. Red: Start with the problem. Make it work by any reasonable means. This stage is about momentum and correctness, not elegance. Green: Stabilize the solution. Ensure it behaves correctly, integrates properly, and handles real usage scenarios. Refactor: Only once the solution works do we make it beautiful by simplifying logic, removing duplication, improving readability, aligning with existing patterns, and generally making it easier for others to work with in the future.

QA

Before anything is considered finished, the work is reviewed internally. This is a moment to present the implementation, test how it all works (both the golden path and edge cases), try to break it, and confirm it behaves as expected in context of a larger work, not just in isolation. This review may involve other developers, designers, even a PM; anyone one degree removed from the work who can provide useful perspective.

Handover

Once the work is complete and reviewed, it is handed over. This means the work is ready to be used, tested, or shipped in the real system. Assumptions are documented. Limitations or follow-ups are clearly stated, and the PM has everything they need to move it forward appropriately. At this point, ownership transitions from development to the PM. The work should be in a state where it can progress without the developer needing to remain attached to it.

Tools

What we use, and why we use them.

Jekyll

Jekyll is our primary tool for building fast, reliable marketing sites. It’s a static site generator that allows us to keep things simple and predictable, avoid unnecessary runtime complexity, and ship sites that are fast, secure, and easy to maintain. Where content changes infrequently or can be managed through structured data, static beats dynamic. Jekyll aligns strongly with our belief that simple beats complex.

Framer

Framer is used when a partner wants a highly visual, drag-and-drop marketing site with fast iteration and direct control. We use it when speed of iteration matters more than long-term extensibility, the site is content-led rather than system-led, and the partner explicitly requests it or it’s clearly the right fit for us to recommend it. When working in Framer, our responsibility is still the same: clarity, consistency, performance, and partner safety.

WordPress

WordPress is used when a partner explicitly requests it or already relies on it. When working in WordPress, we favour minimal themes and restraint around plugins, we avoid unnecessary customization and we work with the grain of the platform rather than fighting it, as much as possible.

Partner Codebases (Web Applications)

For web applications, we work within the codebase the partner has provisioned. Our role is to understand the existing architecture, respect established patterns, and integrate changes cleanly without destabilising the system. We do not impose our preferred stack unless they ask.

GitHub

GitHub is used for source control, collaboration, and change history. We use it to make work traceable, review changes clearly, enable others to understand what changed and why, and collaborate without stepping on toes. Commits should be readable and thoughtfully written.

LambdaTest

LambdaTest is used to test work across browsers, operating systems, viewports, and devices. Local testing is not enough: we need to be sure it works for others, too. Anything that ships must be verified in real-world conditions so partners don’t discover issues for us. LambdaTest helps us ensure work is partner-safe, not just locally correct.

Zeplin

Zeplin is how designs are handed over to development. Designers use it to define spacing, colours, typography, components, and communicate visual intent clearly and consistently. Developers use it to reference exact values, avoid guessing, and ensure the built result matches the design. Zeplin is a source of truth for design intent.

Technical checks

Things we always do.

Check the handover

Before starting development, confirm that all inputs are complete and usable: designs, content, requirements, acceptance criteria, and technical constraints. Identify missing assets, unclear behaviors, consider undefined edge cases and flag them explicitly. Development should not rely on guesswork or implied intent.

Continuously re-check the brief

Validate the original goal through implementation. Even if a solution is technically correct, it can still be wrong if it diverges from the problem it was meant to solve. If there are performance, complexity, or scope issues that can cause trade-offs, then surfacing them is preferred to adjusting the course silently.

Engineering vs. implementing

Be explicit about your role on a given task. You could be creating a new solution, or you could be implementing a predefined one. When integrating into an existing system, prioritize utility, consistency, and safety over personal preference. When engineering a new solution, document decisions and rationale clearly.

Quality Bar

Before reporting the work as complete, consider if it shipped right now, would it reflect well on team's technical standards. Look for brittle assumptions, unclear abstraction, look for shortcuts that could erode sustainability. Do not ignore those, but rather raise these concerns before announcing for partner review or delivery.

Collaborate with those working one degree from you

Developers are one degree away from designers, PMs, other engineers on the team, so it makes sense to ensure alignment in order to clarify expectations, surface risks, provide context or ask for one where needed. Smooth collaboration is preferred to isolated technical excellence because not only does it reduce reworking, but also ensures a better product.

Quality standards

Every site we ship is built to a baseline we’re happy to put in writing. These aren’t upsells. They’re just what “done” means to us.

Engineering non-negotiables

Things we never do.

Don’t skip steps

Some of the steps may feel superfluous sometimes, but the work is better when we stick to them. So stick to them.

Don’t ship to partners without peer-review

We’re only human: sometimes a second pair of eyes can be invaluable in spotting things you became blind to due to exposure to the work. Have someone peer-review it, to where they put their name to the deliverable’s quality too. Two sets of eyes committed to the work are better than one.

Don’t assume others know what you’re thinking

Design should feel obvious, but it feels most obvious to the designer. What happens when I click that? What happens when that opens up? Obvious to the designer, in their mind’s eye, intuiting each user interaction. Not obvious to others, unless it’s either visualized or written up. So check user interaction intents throughout the work. Leave no space for assumptions.

Don’t miss deadlines

If we have deadlines, do not miss them. That means proactive communication around your work to ensure you have everything you need in good time, managing your schedule to comfortably meet the deadlines even if multiple rounds of revisions show up, and over-communicating about how things are going on your side of things, so that everybody can see movement and not worry about whether or not you dropped the ball. If a deadline is under threat, communicate it as early as possible—as soon as you suspect it may be. That gives the team time to assess what to do about that: let a partner know if there is one, cut scope to make it fit, increase support on the project so there are more hands working on it, or simply resolve to push through and find the time to make it work if the scope nor the budget can shift, and there is no one else who can jump in to support.

Don’t work in chaos

The development process can be messy at times. But a craftsman always leaves his desk in order. Your code should be neatly formatted and well-documented, so that anyone who uses it in future can easily find what they’re looking for. Files should be grouped and named for easy reuse in the future. Any requests you made should have a follow-up scheduled so you don’t forget (either make a to-do for yourself for that, or snooze an email notification about it, whatever works best for you) so nothing slips through the cracks. Stay organized, so you (or worse, others) don’t have to work in chaos.