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.ts2
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 deploySummary
Best Practices Overview
Clean Code
Error Handling
Performance
↓
Robust Application

