← Back to Skills

Production Ready

product

Ship robust features with proper error handling, feature flags, health checks, and observability built-in.

Production Ready

Guidelines for shipping features that are resilient, observable, and safely deployable.

When to Activate

Error Boundaries

React error boundaries

import { Component, ErrorInfo, ReactNode } from 'react';

interface Props {
  children: ReactNode;
  fallback?: ReactNode;
  onError?: (error: Error, errorInfo: ErrorInfo) => void;
}

interface State {
  hasError: boolean;
  error?: Error;
}

class ErrorBoundary extends Component<Props, State> {
  state: State = { hasError: false };

  static getDerivedStateFromError(error: Error): State {
    return { hasError: true, error };
  }

  componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    // Log to monitoring service
    console.error('Error caught:', error, errorInfo);
    this.props.onError?.(error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback || (
        <div role="alert">
          <h2>Something went wrong</h2>
          <button onClick={() => this.setState({ hasError: false })}>
            Try again
          </button>
        </div>
      );
    }
    return this.props.children;
  }
}

// Usage - wrap critical sections
<ErrorBoundary 
  fallback={<FallbackUI />}
  onError={(e) => Sentry.captureException(e)}
>
  <CriticalFeature />
</ErrorBoundary>

Async error handling

// GOOD - graceful degradation
async function fetchUserData(userId: string) {
  try {
    const response = await api.get(`/users/${userId}`);
    return { data: response.data, error: null };
  } catch (error) {
    // Log but don't crash
    console.error('Failed to fetch user:', error);
    Sentry.captureException(error);
    
    // Return fallback
    return { 
      data: null, 
      error: error instanceof Error ? error.message : 'Unknown error' 
    };
  }
}

// Usage
const { data, error } = await fetchUserData(id);
if (error) {
  showNotification('Using cached data', 'warning');
  return getCachedUser(id);
}

Feature Flags

Simple feature flag system

// flags.ts
type FeatureFlag = {
  enabled: boolean;
  percentage?: number; // Gradual rollout
  allowList?: string[]; // Specific users
};

const FLAGS: Record<string, FeatureFlag> = {
  NEW_CHECKOUT: { enabled: false, percentage: 10 },
  DARK_MODE: { enabled: true },
  BETA_FEATURES: { enabled: true, allowList: ['user_123', 'user_456'] },
};

export function isFeatureEnabled(
  flag: string, 
  userId?: string
): boolean {
  const config = FLAGS[flag];
  if (!config) return false;
  if (!config.enabled) return false;
  
  // Check allowlist
  if (config.allowList && userId) {
    return config.allowList.includes(userId);
  }
  
  // Percentage rollout (deterministic by userId)
  if (config.percentage !== undefined && userId) {
    const hash = hashCode(userId + flag);
    return (hash % 100) < config.percentage;
  }
  
  return config.enabled;
}

// Usage
if (isFeatureEnabled('NEW_CHECKOUT', user.id)) {
  return <NewCheckout />;
}
return <LegacyCheckout />;

Feature flag with remote config

// Using environment-based flags
const config = {
  features: {
    newDashboard: process.env.FEATURE_NEW_DASHBOARD === 'true',
    aiAssistant: process.env.FEATURE_AI_ASSISTANT === 'true',
  },
};

// Or fetch from remote
async function loadFeatureFlags() {
  const response = await fetch('/api/feature-flags');
  return response.json();
}

Health Checks

HTTP health endpoints

// Express.js
app.get('/health', (req, res) => {
  res.json({ status: 'ok', timestamp: new Date().toISOString() });
});

app.get('/health/ready', async (req, res) => {
  const checks = await Promise.allSettled([
    checkDatabase(),
    checkRedis(),
    checkExternalAPI(),
  ]);
  
  const results = {
    database: checks[0].status === 'fulfilled',
    redis: checks[1].status === 'fulfilled',
    externalAPI: checks[2].status === 'fulfilled',
  };
  
  const allHealthy = Object.values(results).every(Boolean);
  
  res.status(allHealthy ? 200 : 503).json({
    status: allHealthy ? 'ready' : 'degraded',
    checks: results,
    timestamp: new Date().toISOString(),
  });
});

app.get('/health/live', (req, res) => {
  // Simple liveness check - is the process running?
  res.json({ status: 'alive' });
});

Kubernetes probes

# deployment.yaml
livenessProbe:
  httpGet:
    path: /health/live
    port: 3000
  initialDelaySeconds: 10
  periodSeconds: 10

readinessProbe:
  httpGet:
    path: /health/ready
    port: 3000
  initialDelaySeconds: 5
  periodSeconds: 5

Graceful Degradation

Circuit breaker pattern

class CircuitBreaker {
  private failures = 0;
  private lastFailure?: Date;
  private state: 'closed' | 'open' | 'half-open' = 'closed';
  
  constructor(
    private threshold = 5,
    private resetTimeout = 30000
  ) {}

  async execute<T>(fn: () => Promise<T>, fallback: T): Promise<T> {
    if (this.state === 'open') {
      if (Date.now() - this.lastFailure!.getTime() > this.resetTimeout) {
        this.state = 'half-open';
      } else {
        return fallback;
      }
    }

    try {
      const result = await fn();
      this.onSuccess();
      return result;
    } catch (error) {
      this.onFailure();
      return fallback;
    }
  }

  private onSuccess() {
    this.failures = 0;
    this.state = 'closed';
  }

  private onFailure() {
    this.failures++;
    this.lastFailure = new Date();
    if (this.failures >= this.threshold) {
      this.state = 'open';
    }
  }
}

// Usage
const paymentCircuit = new CircuitBreaker();
const result = await paymentCircuit.execute(
  () => paymentAPI.process(order),
  { success: false, message: 'Payment temporarily unavailable' }
);

Structured Logging

Use consistent log format

import pino from 'pino';

const logger = pino({
  level: process.env.LOG_LEVEL || 'info',
  formatters: {
    level: (label) => ({ level: label }),
  },
});

// GOOD - structured, searchable
logger.info({
  event: 'order_created',
  orderId: order.id,
  userId: user.id,
  total: order.total,
  items: order.items.length,
}, 'Order created successfully');

// BAD - unstructured
console.log(`Order ${order.id} created for user ${user.id}`);

Include request context

// Middleware to add request ID
app.use((req, res, next) => {
  req.requestId = req.headers['x-request-id'] || crypto.randomUUID();
  req.log = logger.child({ requestId: req.requestId });
  next();
});

// Use in handlers
app.post('/orders', async (req, res) => {
  req.log.info({ body: req.body }, 'Processing order');
  // ...
  req.log.info({ orderId: order.id }, 'Order created');
});

Timeouts & Retries

Always set timeouts

// GOOD - explicit timeout
const response = await fetch(url, {
  signal: AbortSignal.timeout(5000), // 5s timeout
});

// With retry logic
async function fetchWithRetry(
  url: string,
  options: RequestInit = {},
  retries = 3
): Promise<Response> {
  for (let i = 0; i < retries; i++) {
    try {
      const response = await fetch(url, {
        ...options,
        signal: AbortSignal.timeout(5000),
      });
      if (response.ok) return response;
    } catch (error) {
      if (i === retries - 1) throw error;
      // Exponential backoff
      await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
    }
  }
  throw new Error('Max retries exceeded');
}

Deployment Safety

Pre-deployment checklist

## Before Deploying

- [ ] All tests passing
- [ ] Feature flag configured (if new feature)
- [ ] Rollback plan documented
- [ ] Monitoring alerts configured
- [ ] Database migrations tested
- [ ] API backwards compatible
- [ ] Load tested for expected traffic
- [ ] Security review completed