Development Tenets for do.dev

These core principles guide every decision we make in building and maintaining the do.dev platform. They are not aspirational - they are requirements.

Our Mission: Democratize developer infrastructure to create opportunities for all builders.

Our technical tenets exist in service of this mission. Great code alone isn't enoughβ€”we build with purpose.


Foundation: Values-Driven Development

Before the technical tenets, we ground ourselves in why we build:

Builders First

Every technical decision starts with: "Does this help developers succeed?" We optimize for developer experience, not just engineering elegance.

Accessible by Design

We build for developers at every stageβ€”from students to enterprises. Complexity should be hidden, not exposed. Documentation should be clear, not clever.

Shared Success

When contributors improve our platform, they share in the success. When our customers grow, we celebrate. Our prosperity is connected to the prosperity of our community.


1. Real-Time First πŸš€

We build for the speed of thought.

  • Everything should be as near to real-time as possible
  • Use Convex real-time subscriptions for data that isn't natively real-time
  • User actions should have immediate visual feedback
  • Background processes should use optimistic updates
  • WebSocket connections over polling when feasible

2. Fail Gracefully, Never Silently πŸ›‘οΈ

Every edge case is a user's reality.

  • Handle loading states explicitly (no blank screens)
  • Account for race conditions (auth initialization, webhook delays)
  • Provide meaningful error messages that guide users to solutions
  • Always have a fallback (if Clerk fails, if webhooks are delayed, if APIs timeout)
  • Log errors comprehensively but never expose sensitive data

3. Type Safety is Non-Negotiable πŸ“‹

If it compiles, it should work.

  • TypeScript strict mode always on
  • No any types without explicit justification
  • Define interfaces for all data structures
  • Test TypeScript compilation locally before deploying
  • Prefer explicit interfaces over conditional types

4. Developer Experience is User Experience πŸ‘©β€πŸ’»

The best code is code that developers love to work with.

  • Clear, semantic naming (no abbreviations unless universal)
  • Self-documenting code over extensive comments
  • Consistent patterns across the codebase
  • Git commits that tell a story
  • Fast local development with hot reload
  • Comprehensive development documentation

5. Performance from Day One ⚑

Speed is a feature, not an optimization.

  • Measure performance impact before merging
  • Lazy load what you can
  • Bundle size matters - check it
  • Optimize images and assets
  • Use proper caching strategies
  • Server-side render when it improves UX

6. Security by Default πŸ”’

Trust no input, verify everything.

  • All user input must be validated
  • Authentication and authorization on every protected route
  • Webhooks must be verified
  • API keys and secrets in environment variables only
  • Regular security audits
  • Principle of least privilege for all roles

7. Don't Repeat Yourself (DRY) πŸ”„

Write once, use everywhere.

  • Shared components over duplicated code
  • Centralized configuration
  • Reusable utilities and hooks
  • Single source of truth for business logic
  • Extract patterns when you see them repeated 3+ times

8. Progressive Enhancement πŸ“ˆ

Start simple, enhance intelligently.

  • Core functionality works without JavaScript
  • Features degrade gracefully
  • Mobile-first responsive design
  • Accessibility from the start, not as an afterthought
  • Support users on slower connections

9. Ship Small, Ship Often 🚒

Perfect is the enemy of shipped.

  • Small, focused pull requests
  • Feature flags for gradual rollouts
  • Continuous deployment
  • Quick iterations based on user feedback
  • Rollback strategy for every deployment

10. User Trust is Sacred 🀝

Every interaction should build confidence.

  • Transparent about system status
  • Clear about data usage
  • Honest about limitations
  • Quick to acknowledge and fix issues
  • Proactive communication during outages

11. Data Integrity Above All πŸ’Ύ

Lost data loses users.

  • ACID compliance where it matters
  • Backup strategies for critical data
  • Audit trails for important operations
  • Data validation at every layer
  • Clear data retention policies

12. Observability is Mandatory πŸ“Š

You can't fix what you can't see.

  • Structured logging with context
  • Performance monitoring on key metrics
  • Error tracking with proper grouping
  • User behavior analytics (privacy-respecting)
  • Real-time alerts for critical issues

13. Community Prosperity 🌱

Our success is shared success.

  • Contributors who improve the platform share in the rewards
  • Free tier enables real production use, not just testing
  • Open source what we can to give back to the ecosystem
  • Celebrate customer successesβ€”their wins are our wins
  • Build features that help all developers, not just paying customers

Applying These Tenets

When making decisions, ask yourself:

  1. Does this make the user experience more real-time?
  2. Have I handled all the ways this could fail?
  3. Is this type-safe and will it catch errors at compile time?
  4. Would I enjoy maintaining this code in 6 months?
  5. Will this perform well at scale?
  6. Is this secure by default?
  7. Am I repeating code that already exists?
  8. Does this work for all users, not just the ideal case?
  9. Can I ship this incrementally?
  10. Does this build or erode user trust?
  11. Is the data safe and validated?
  12. Will I know if this breaks in production?
  13. Does this serve our whole community, not just paying customers?

Examples in Practice

βœ… Good: Webhook Race Condition Handling

// Assume new users without roles are waitlist (webhook hasn't fired yet)
const isWaitlistUser = userRoles.length === 0 || (userRoles.length === 1 && userRoles[0] === "waitlist")

❌ Bad: Silent Failures

// Don't do this
try {
  await saveUser(data)
} catch (e) {
  // Silent failure - violates Tenet #2
}

βœ… Good: Type-Safe Interfaces

interface AuthUser {
  id: string
  email: string
  roles: string[]
  // ... other fields
}

❌ Bad: Using Any

// Don't do this
const processData = (data: any) => {
  // Violates Tenet #3
}

βœ… Good: Community-First Feature Design

// Feature available to all tiers, with enhanced options for paid
const sendEmail = async (options: EmailOptions) => {
  // Free tier gets core functionality
  // Paid tiers get additional features like analytics
  // No artificial limitations that don't serve a real purpose
}

❌ Bad: Artificial Limitations

// Don't do this - limiting free tier just to drive upgrades
if (!isPaidUser && emailCount > 10) {
  throw new Error("Upgrade to send more emails")
  // Violates Tenet #13 - limit should be based on real costs, not artificial scarcity
}

Living Document

These tenets evolve with our understanding. If you find yourself consistently violating a tenet, either:

  1. You're doing something wrong, or
  2. The tenet needs updating

Discuss with the team before changing core tenets.

On this page