Skip to content

Best Practices

Build robust, scalable, and maintainable applications with De. Platform by following industry best practices.

Why Best Practices Matter

Following these guidelines will help you:

  • Build more reliable applications
  • Reduce bugs and technical debt
  • Improve performance and scalability
  • Enhance security and data protection
  • Simplify maintenance and updates

Code Organization

Project Structure

1

Organize by Feature

Group related files together

src/
├── features/
│   ├── auth/
│   │   ├── AuthManager.ts
│   │   ├── AuthUI.tsx
│   │   └── auth.types.ts
│   ├── tracking/
│   │   ├── TrackingManager.ts
│   │   ├── MapView.tsx
│   │   └── tracking.types.ts
│   └── orders/
│       ├── OrderManager.ts
│       ├── OrderList.tsx
│       └── order.types.ts
├── shared/
│   ├── components/
│   ├── utils/
│   └── types/
└── config/
    ├── de.config.ts
    └── environment.ts
2

Separate Concerns

Keep business logic separate from UI

typescript
// ❌ Bad: Mixed concerns
function DeliveryComponent() {
  const [delivery, setDelivery] = useState(null)
  
  useEffect(() => {
    const access = new De.Access({...})
    access.request({...}).then(setDelivery)
  }, [])
  
  return <div>{delivery?.status}</div>
}

// ✅ Good: Separated concerns
// hooks/useDelivery.ts
function useDelivery(orderId: string) {
  const [delivery, setDelivery] = useState(null)
  const access = useDeAccess()
  
  useEffect(() => {
    access.request({
      url: `/orders/${orderId}`,
      method: 'GET'
    }).then(setDelivery)
  }, [orderId])
  
  return delivery
}

// components/DeliveryView.tsx
function DeliveryView({ orderId }: Props) {
  const delivery = useDelivery(orderId)
  return <div>{delivery?.status}</div>
}

Configuration Management

Environment-Specific Config

typescript
// config/de.config.ts
const configs = {
  development: {
    apiUrl: 'https://dev-api.dedot.io',
    msiUrl: 'https://dev-map.dedot.io',
    debug: true
  },
  staging: {
    apiUrl: 'https://staging-api.dedot.io',
    msiUrl: 'https://staging-map.dedot.io',
    debug: false
  },
  production: {
    apiUrl: 'https://api.dedot.io',
    msiUrl: 'https://map.dedot.io',
    debug: false
  }
}

export const config = configs[
  process.env.NODE_ENV as keyof typeof configs
]

Never Hardcode Secrets

typescript
// ❌ Bad
const access = new De.Access({
  workspace: 'ws_abc123',
  accessToken: 'sk_live_xyz789'
})

// ✅ Good
const access = new De.Access({
  workspace: process.env.DE_WORKSPACE_ID,
  accessToken: process.env.DE_ACCESS_TOKEN
})

Error Handling

Comprehensive Error Management

1

Create Error Handler

Centralized error handling utility

typescript
// utils/errorHandler.ts
export class ErrorHandler {
  static handle(error: any, context: string) {
    // Log to monitoring service
    console.error(`[${context}]`, error)
    
    // Categorize error
    if (error.status === 401) {
      return this.handleAuthError(error)
    } else if (error.status === 429) {
      return this.handleRateLimitError(error)
    } else if (error.status >= 500) {
      return this.handleServerError(error)
    }
    
    return this.handleGenericError(error)
  }
  
  private static handleAuthError(error: any) {
    // Redirect to login
    window.location.href = '/login'
    return { message: 'Authentication required', retry: false }
  }
  
  private static handleRateLimitError(error: any) {
    return {
      message: 'Too many requests. Please try again later.',
      retry: true,
      retryAfter: error.headers?.['retry-after']
    }
  }
  
  private static handleServerError(error: any) {
    return {
      message: 'Server error. Our team has been notified.',
      retry: true
    }
  }
  
  private static handleGenericError(error: any) {
    return {
      message: error.message || 'An error occurred',
      retry: false
    }
  }
}
2

Implement Retry Logic

Automatically retry failed requests

typescript
// utils/retryRequest.ts
export async function retryRequest<T>(
  fn: () => Promise<T>,
  options = { maxRetries: 3, backoff: 1000 }
): Promise<T> {
  let lastError: any
  
  for (let i = 0; i < options.maxRetries; i++) {
    try {
      return await fn()
    } catch (error: any) {
      lastError = error
      
      // Don't retry client errors (4xx)
      if (error.status >= 400 && error.status < 500) {
        throw error
      }
      
      // Wait before retrying (exponential backoff)
      if (i < options.maxRetries - 1) {
        await new Promise(resolve => 
          setTimeout(resolve, options.backoff * Math.pow(2, i))
        )
      }
    }
  }
  
  throw lastError
}

// Usage
const delivery = await retryRequest(() =>
  access.request({
    url: `/orders/${orderId}`,
    method: 'GET'
  })
)

User-Friendly Error Messages

Don't Expose Technical Details

typescript
// ❌ Bad
catch (error) {
  alert(JSON.stringify(error))
}

// ✅ Good
catch (error) {
  const userMessage = ErrorHandler.handle(
    error, 
    'Order Creation'
  )
  showNotification(userMessage.message, 'error')
}

Provide Actionable Feedback

typescript
// ✅ Good: Clear, actionable messages
const messages = {
  network: 'Connection lost. Check your internet.',
  auth: 'Session expired. Please sign in again.',
  validation: 'Please check your input and try again.',
  server: 'Something went wrong. We\'re working on it.'
}

Performance Optimization

API Request Optimization

1

Implement Caching

Cache API responses to reduce requests

typescript
// utils/cache.ts
class APICache {
  private cache = new Map<string, { data: any; timestamp: number }>()
  private ttl = 5 * 60 * 1000 // 5 minutes
  
  set(key: string, data: any) {
    this.cache.set(key, {
      data,
      timestamp: Date.now()
    })
  }
  
  get(key: string) {
    const cached = this.cache.get(key)
    if (!cached) return null
    
    // Check if expired
    if (Date.now() - cached.timestamp > this.ttl) {
      this.cache.delete(key)
      return null
    }
    
    return cached.data
  }
  
  clear() {
    this.cache.clear()
  }
}

// Usage
const cache = new APICache()

async function getOrder(orderId: string) {
  const cacheKey = `order:${orderId}`
  
  // Check cache first
  const cached = cache.get(cacheKey)
  if (cached) return cached
  
  // Fetch from API
  const order = await access.request({
    url: `/orders/${orderId}`,
    method: 'GET'
  })
  
  // Store in cache
  cache.set(cacheKey, order.data)
  return order.data
}
2

Batch Requests

Combine multiple requests into one

typescript
// ❌ Bad: Multiple sequential requests
async function loadDashboard() {
  const orders = await getOrders()
  const vehicles = await getVehicles()
  const drivers = await getDrivers()
  return { orders, vehicles, drivers }
}

// ✅ Good: Parallel requests
async function loadDashboard() {
  const [orders, vehicles, drivers] = await Promise.all([
    getOrders(),
    getVehicles(),
    getDrivers()
  ])
  return { orders, vehicles, drivers }
}

// ✅ Better: Single batch request
async function loadDashboard() {
  const result = await access.request({
    url: '/dashboard/data',
    method: 'POST',
    body: {
      include: ['orders', 'vehicles', 'drivers']
    }
  })
  return result.data
}
3

Debounce User Input

Reduce API calls from rapid user input

typescript
// utils/debounce.ts
export function debounce<T extends (...args: any[]) => any>(
  func: T,
  wait: number
): (...args: Parameters<T>) => void {
  let timeout: NodeJS.Timeout
  
  return function executedFunction(...args: Parameters<T>) {
    clearTimeout(timeout)
    timeout = setTimeout(() => func(...args), wait)
  }
}

// Usage in search component
const searchOrders = debounce(async (query: string) => {
  const results = await access.request({
    url: '/orders/search',
    method: 'GET',
    query: { q: query }
  })
  setSearchResults(results.data)
}, 300)

<input 
  onChange={(e) => searchOrders(e.target.value)}
  placeholder="Search orders..."
/>

Map Performance

Lazy Load Map

typescript
// Only load map when needed
const MapComponent = lazy(() => 
  import('./components/Map')
)

function App() {
  const [showMap, setShowMap] = useState(false)
  
  return (
    <div>
      <button onClick={() => setShowMap(true)}>
        Show Map
      </button>
      {showMap && (
        <Suspense fallback={<Loading />}>
          <MapComponent />
        </Suspense>
      )}
    </div>
  )
}

Optimize Markers

typescript
// Use clustering for many markers
const msi = new De.MSI({
  element: 'map',
  accessToken: token,
  options: {
    clustering: {
      enabled: true,
      maxZoom: 14,
      radius: 50
    }
  }
})

// Limit visible markers
const visibleVehicles = vehicles.filter(
  v => v.lastUpdate > Date.now() - 5 * 60 * 1000
)

Security Best Practices

Authentication Security

1

Secure Token Storage

Store tokens safely

typescript
// ✅ Web: Use httpOnly cookies or secure storage
class TokenManager {
  private static readonly KEY = 'de_access_token'
  
  static setToken(token: string) {
    // For web apps with backend
    document.cookie = `${this.KEY}=${token}; Secure; HttpOnly; SameSite=Strict`
    
    // For client-only apps (less secure)
    sessionStorage.setItem(this.KEY, token)
  }
  
  static getToken(): string | null {
    return sessionStorage.getItem(this.KEY)
  }
  
  static clearToken() {
    sessionStorage.removeItem(this.KEY)
    document.cookie = `${this.KEY}=; expires=Thu, 01 Jan 1970 00:00:00 UTC`
  }
}

// ✅ Mobile: Use secure storage
import * as SecureStore from 'expo-secure-store'

class MobileTokenManager {
  static async setToken(token: string) {
    await SecureStore.setItemAsync('de_access_token', token)
  }
  
  static async getToken() {
    return await SecureStore.getItemAsync('de_access_token')
  }
}
2

Validate Input

Always sanitize and validate user input

typescript
// utils/validation.ts
export const validators = {
  phone: (phone: string) => {
    const regex = /^\+?[1-9]\d{1,14}$/
    return regex.test(phone)
  },
  
  email: (email: string) => {
    const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
    return regex.test(email)
  },
  
  coordinates: (coords: { lng: number; lat: number }) => {
    return (
      coords.lng >= -180 && coords.lng <= 180 &&
      coords.lat >= -90 && coords.lat <= 90
    )
  }
}

// Usage
function createOrder(data: any) {
  if (!validators.phone(data.customerPhone)) {
    throw new Error('Invalid phone number')
  }
  
  if (!validators.coordinates(data.deliveryLocation)) {
    throw new Error('Invalid coordinates')
  }
  
  // Proceed with order creation
}

Data Protection

Never Log Sensitive Data

typescript
// ❌ Bad
console.log('User data:', {
  phone: user.phone,
  email: user.email,
  accessToken: token
})

// ✅ Good
console.log('User loaded:', {
  uid: user.uid,
  accountType: user.account.types
})

Sanitize Data for Display

typescript
// utils/sanitize.ts
export function sanitizeHTML(html: string) {
  const div = document.createElement('div')
  div.textContent = html
  return div.innerHTML
}

// Usage
function CustomerNote({ note }: Props) {
  return (
    <div dangerouslySetInnerHTML={{
      __html: sanitizeHTML(note)
    }} />
  )
}

Testing

Unit Testing

1

Test Business Logic

Write tests for critical functions

typescript
// __tests__/delivery.test.ts
import { describe, it, expect, vi } from 'vitest'
import { DeliveryManager } from '../delivery'

describe('DeliveryManager', () => {
  it('should calculate correct ETA', () => {
    const manager = new DeliveryManager()
    const eta = manager.calculateETA({
      distance: 10000, // 10km
      speed: 50 // 50km/h
    })
    
    expect(eta).toBe(12) // 12 minutes
  })
  
  it('should validate delivery addresses', () => {
    const manager = new DeliveryManager()
    
    expect(manager.validateAddress({
      street: '123 Main St',
      city: 'New York',
      coordinates: { lng: -74.0060, lat: 40.7128 }
    })).toBe(true)
    
    expect(manager.validateAddress({
      street: '',
      city: '',
      coordinates: { lng: 200, lat: 100 }
    })).toBe(false)
  })
})
2

Mock API Calls

Test without making real API requests

typescript
// __tests__/api.test.ts
import { vi } from 'vitest'
import De from '@de./sdk'

vi.mock('@de./sdk')

describe('API Integration', () => {
  it('should handle successful order creation', async () => {
    const mockRequest = vi.fn().mockResolvedValue({
      data: { id: 'order_123', status: 'pending' }
    })
    
    De.Access = vi.fn().mockImplementation(() => ({
      request: mockRequest
    }))
    
    const access = new De.Access({...})
    const result = await access.request({
      url: '/orders',
      method: 'POST',
      body: { ... }
    })
    
    expect(result.data.id).toBe('order_123')
    expect(mockRequest).toHaveBeenCalledTimes(1)
  })
})

Integration Testing

3

Test User Flows

Test complete user journeys

typescript
// __tests__/e2e/delivery-flow.test.ts
import { test, expect } from '@playwright/test'

test('complete delivery flow', async ({ page }) => {
  // Navigate to app
  await page.goto('http://localhost:3000')
  
  // Enter delivery details
  await page.fill('#pickup-address', '123 Main St')
  await page.fill('#delivery-address', '456 Oak Ave')
  await page.click('#create-delivery')
  
  // Wait for map to load
  await page.waitForSelector('#map-container')
  
  // Verify tracking status
  const status = await page.textContent('.status-card')
  expect(status).toContain('Order Created')
  
  // Wait for delivery simulation
  await page.waitForTimeout(5000)
  
  // Verify status updated
  const updatedStatus = await page.textContent('.status-card:last-child')
  expect(updatedStatus).toContain('In Transit')
})

Monitoring & Logging

Application Monitoring

1

Implement Error Tracking

Use error tracking service

typescript
// utils/monitoring.ts
import * as Sentry from '@sentry/browser'

export function initMonitoring() {
  Sentry.init({
    dsn: process.env.SENTRY_DSN,
    environment: process.env.NODE_ENV,
    tracesSampleRate: 0.1,
    beforeSend(event, hint) {
      // Filter sensitive data
      if (event.request) {
        delete event.request.cookies
        delete event.request.headers?.Authorization
      }
      return event
    }
  })
}

// Track custom events
export function trackEvent(name: string, data?: any) {
  Sentry.captureMessage(name, {
    level: 'info',
    extra: data
  })
}
2

Performance Monitoring

Track application performance

typescript
// utils/performance.ts
export class PerformanceMonitor {
  private marks = new Map<string, number>()
  
  mark(name: string) {
    this.marks.set(name, performance.now())
  }
  
  measure(name: string, startMark: string) {
    const start = this.marks.get(startMark)
    if (!start) return
    
    const duration = performance.now() - start
    
    // Log slow operations
    if (duration > 1000) {
      console.warn(`Slow operation: ${name} took ${duration}ms`)
    }
    
    // Send to analytics
    analytics.track('performance', {
      operation: name,
      duration,
      timestamp: Date.now()
    })
    
    return duration
  }
}

// Usage
const monitor = new PerformanceMonitor()

monitor.mark('map-load-start')
await msi.load()
monitor.measure('map-load', 'map-load-start')

Logging Best Practices

Structured Logging

typescript
// utils/logger.ts
export const logger = {
  info: (message: string, context?: any) => {
    console.log(JSON.stringify({
      level: 'info',
      message,
      timestamp: new Date().toISOString(),
      ...context
    }))
  },
  
  error: (message: string, error?: any) => {
    console.error(JSON.stringify({
      level: 'error',
      message,
      error: error?.message,
      stack: error?.stack,
      timestamp: new Date().toISOString()
    }))
  }
}

Log Levels

typescript
const logLevels = {
  debug: 0,
  info: 1,
  warn: 2,
  error: 3
}

const currentLevel = 
  process.env.NODE_ENV === 'production'
    ? logLevels.warn
    : logLevels.debug

function shouldLog(level: keyof typeof logLevels) {
  return logLevels[level] >= currentLevel
}

Code Quality

TypeScript Best Practices

1

Use Proper Types

Avoid 'any' and use strict types

typescript
// ❌ Bad
function createOrder(data: any) {
  return access.request({
    url: '/orders',
    method: 'POST',
    body: data
  })
}

// ✅ Good
interface CreateOrderRequest {
  customerPhone: string
  pickupLocation: {
    address: string
    coordinates: { lng: number; lat: number }
  }
  deliveryLocation: {
    address: string
    coordinates: { lng: number; lat: number }
  }
  items: Array<{
    name: string
    quantity: number
    weight?: number
  }>
}

async function createOrder(
  data: CreateOrderRequest
): Promise<Order> {
  const result = await access.request({
    url: '/orders',
    method: 'POST',
    body: data
  })
  return result.data
}
2

Document Your Code

Add JSDoc comments for clarity

typescript
/**
 * Calculates the estimated time of arrival for a delivery
 * @param distance - Distance in meters
 * @param averageSpeed - Average speed in km/h
 * @param trafficFactor - Traffic multiplier (1.0 = no traffic, 2.0 = heavy traffic)
 * @returns ETA in minutes
 */
function calculateETA(
  distance: number,
  averageSpeed: number,
  trafficFactor: number = 1.0
): number {
  const distanceKm = distance / 1000
  const adjustedSpeed = averageSpeed / trafficFactor
  const hours = distanceKm / adjustedSpeed
  return Math.round(hours * 60)
}

Code Review Checklist

Code Review Guidelines
Category
Check
Why
Security
No secrets in code
Prevent credential leaks
Performance
No unnecessary re-renders
Optimize React/Vue performance
Error Handling
All async calls wrapped
Graceful error recovery
Testing
Tests for new features
Prevent regressions
Documentation
Complex logic explained
Easier maintenance

Deployment Best Practices

Pre-Deployment Checklist

Build & Test

  • [ ] All tests passing
  • [ ] Production build successful
  • [ ] Bundle size optimized
  • [ ] Source maps generated
  • [ ] Environment variables configured

Security Review

  • [ ] No secrets in code
  • [ ] HTTPS enforced
  • [ ] CORS configured
  • [ ] Rate limiting enabled
  • [ ] Input validation in place

Monitoring Setup

  • [ ] Error tracking configured
  • [ ] Analytics integrated
  • [ ] Performance monitoring enabled
  • [ ] Logs aggregated
  • [ ] Alerts configured

Documentation

  • [ ] README updated
  • [ ] API docs current
  • [ ] Deployment guide ready
  • [ ] Rollback plan documented
  • [ ] Team notified

Continuous Integration

1

Automate Your Pipeline

Use CI/CD for consistent deployments

yaml
# .github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
      - run: npm ci
      - run: npm test
      - run: npm run build
      
  deploy:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Deploy to Production
        env:
          DE_WORKSPACE_ID: ${{ secrets.DE_WORKSPACE_ID }}
          DE_ACCESS_TOKEN: ${{ secrets.DE_ACCESS_TOKEN }}
        run: |
          npm run build
          npm run deploy

Summary

Best Practices Overview
Clean Code
Error Handling
Performance
Robust Application

Next Steps

Additional Resources

Style Guide

Code formatting and naming conventions

Learn more →

Architecture Patterns

Common design patterns for De. apps

Learn more →

Performance Guide

Deep dive into optimization techniques

Learn more →