We recently wrote down the development principles we've been following at Geocodio for the past 10+ years. Thought it might be interesting to share.
We recently put together a development manifesto for Geocodio -- not a big shift in how we work, just writing down the principles we've already been following over the past 10+ years. It's helped us have clearer conversations about technical decisions and onboarding.
We figured it might be interesting to share. Maybe you'll find it useful for your own team, or maybe you'll just find it interesting to see how another team approaches things.
These principles guide how we build at Geocodio. They’re not rigid rules -- they’re a framework for making good decisions as a small, bootstrapped team building for the long term.
We build for the long term. Geocodio is over 10 years old. How can we build so it will easily last 10 more? This means choosing maintainability over cleverness, and stability over cutting-edge.
We use "boring" and known technologies. For the most part, we avoid experimenting with new frameworks and technologies for Geocodio. We save experimentation for internal tooling, side projects, and Hack Friday. Once technologies have proven themselves and we've built familiarity with them, they become candidates for our main repositories.
We run lean, sustainable infrastructure. Being bootstrapped means we’re cost-conscious, not cheap. We find efficient solutions that maintain performance.
KISS. Keep it Simple Stupid. Is there a simpler, less complex way of solving this problem? Simpler solutions are easier to maintain and easier for others to understand.
When in doubt, ask. We're a small team. A 5-minute conversation can save hours of rework. Don't hesitate to pull someone in when you're unsure about an approach or would like a second point of view.
We <3 tests. When working on a code change, consider what type of test would best cover the feature: Integration, Unit, and/or Browser tests. We want substantial tests that meaningfully verify functionality -- not tests just for the sake of hitting coverage numbers. Mocking is a powerful tool - use it thoughtfully and be intentional about what you choose to mock.
Avoid duplication when it’s easy to reuse existing code. For cases that need actual refactoring to be reusable, follow the “rule of three” - wait until the pattern repeats three times before abstracting. This helps you find the right approach. When refactoring, use action classes, services, or SDK-like abstractions.
Avoid magic numbers or strings hardcoded in logic. Instead, use class constants, Laravel’s config patterns, or enums.
Follow Clean Code principles. Functions should have descriptive names, not grow too large, and should avoid multi-level logic branches.
Code should be expressive and speak for itself. Comments should be limited to business logic and decisions. Avoid single character variable names. Take the extra time to come up with a more descriptive variable name.
Refactor as you go. Instead of trying to refactor large parts of our codebase, try to improve the part of the codebase you’re working on while you’re there. Always leave the code you touched better than you found it (the “Boy Scout rule”).
We treat servers like cattle, not pets. We spin up and tear down servers as needed. Any server should be replaceable -- and preferably within minutes.
2+ of everything. Single points of failure are a serious risk that we always want to avoid.
We consider trade offs between performance and cost (especially important with AWS). Being bootstrapped means we’re disciplined about infrastructure spending -- but never at the expense of user-facing performance or latency.
Fail fast. A failing piece of infrastructure, e.g. a database, can have serious cascading effects for app servers. Always configure timeouts when possible.
Consider scale. But only when necessary. We don’t want to build for scale prematurely, but we also need to be aware of hotspots where considering scale is key.
Ship early, ship often. We prefer frequent, small deployments over large, risky releases. Sometimes we deploy several times a day. Small changes are easier to test, easier to review, and easier to roll back if something goes wrong.
We love good documentation. Whether it's internal docs (Notion, markdown files, READMEs) or external docs (API documentation, guides, blog posts), good documentation makes everyone's life easier -- including your own.
Documentation doesn't need to be long -- it needs to be useful. Write clearly and concisely. A short, readable explanation is better than a comprehensive wall of text that nobody will read.
Document the "why," not just the "what." Code shows what we're doing. Documentation should explain why we made certain decisions, especially for non-obvious choices.