Skip to content
All essays
CraftMarch 23, 202410 min

Advanced Code Optimization Techniques

Master advanced optimization techniques to make your code run faster and more efficiently

Ü
Ümit Uz
Mobile & Full Stack Developer

Performance optimization is crucial for building applications that scale. Let's explore advanced techniques for optimizing code at various levels.

Algorithm Optimization

Choosing the right algorithm is the foundation of performance.

typescript
// ❌ O(n²) - Nested loops
function findDuplicates(arr: number[]): number[] {
  const duplicates: number[] = [];
  for (let i = 0; i < arr.length; i++) {
    for (let j = i + 1; j < arr.length; j++) {
      if (arr[i] === arr[j] && !duplicates.includes(arr[i])) {
        duplicates.push(arr[i]);
      }
    }
  }
  return duplicates;
}

// ✅ O(n) - Using Set
function findDuplicatesOptimized(arr: number[]): number[] {
  const seen = new Set<number>();
  const duplicates = new Set<number>();
  
  for (const num of arr) {
    if (seen.has(num)) {
      duplicates.add(num);
    } else {
      seen.add(num);
    }
  }
  
  return Array.from(duplicates);
}

Memory Optimization

Reduce memory footprint and prevent memory leaks.

typescript
// Memory pooling for frequently created objects
class ObjectPool<T> {
  private pool: T[] = [];
  
  constructor(
    private factory: () => T,
    private reset: (obj: T) => void,
    private initialSize: number = 10
  ) {
    for (let i = 0; i < initialSize; i++) {
      this.pool.push(factory());
    }
  }
  
  acquire(): T {
    return this.pool.pop() || this.factory();
  }
  
  release(obj: T) {
    this.reset(obj);
    this.pool.push(obj);
  }
}

// Usage for particle systems
const particlePool = new ObjectPool(
  () => ({ x: 0, y: 0, vx: 0, vy: 0, life: 0 }),
  (p) => { p.x = 0; p.y = 0; p.vx = 0; p.vy = 0; p.life = 0; },
  1000
);

Database Query Optimization

Optimize database queries for better performance.

typescript
// ❌ N+1 query problem
async function getUsersWithPosts() {
  const users = await db.users.findMany();
  
  for (const user of users) {
    user.posts = await db.posts.findMany({
      where: { userId: user.id }
    });
  }
  
  return users;
}

// ✅ Optimized with eager loading
async function getUsersWithPostsOptimized() {
  return await db.users.findMany({
    include: {
      posts: true
    }
  });
}

// ✅ Even better with pagination
async function getUsersWithPostsPaginated(page: number, limit: number) {
  const [users, total] = await Promise.all([
    db.users.findMany({
      skip: (page - 1) * limit,
      take: limit,
      include: {
        posts: {
          take: 10,
          orderBy: { createdAt: 'desc' }
        }
      }
    }),
    db.users.count()
  ]);
  
  return { users, total, page, pages: Math.ceil(total / limit) };
}

Caching Strategies

Implement multi-level caching for maximum performance.

typescript
class MultiLevelCache {
  private memoryCache: Map<string, { value: any; expiry: number }>;
  
  constructor(
    private redis: Redis,
    private db: Database
  ) {
    this.memoryCache = new Map();
  }
  
  async get(key: string): Promise<any> {
    // Level 1: Memory cache
    const memValue = this.memoryCache.get(key);
    if (memValue && memValue.expiry > Date.now()) {
      return memValue.value;
    }
    
    // Level 2: Redis cache
    const redisValue = await this.redis.get(key);
    if (redisValue) {
      this.memoryCache.set(key, {
        value: JSON.parse(redisValue),
        expiry: Date.now() + 60000 // 1 minute
      });
      return JSON.parse(redisValue);
    }
    
    // Level 3: Database
    const dbValue = await this.db.get(key);
    
    // Cache in all levels
    await this.redis.setex(key, 3600, JSON.stringify(dbValue));
    this.memoryCache.set(key, {
      value: dbValue,
      expiry: Date.now() + 60000
    });
    
    return dbValue;
  }
}

Lazy Loading and Code Splitting

Load resources only when needed.

typescript
// Lazy load heavy modules
const heavyModule = lazy(() => import('./HeavyModule'));

// Dynamic imports for code splitting
async function processLargeFile(file: File) {
  const { processFile } = await import('./file-processor');
  return processFile(file);
}

// Intersection Observer for lazy loading images
const imageObserver = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const img = entry.target as HTMLImageElement;
      img.src = img.dataset.src!;
      imageObserver.unobserve(img);
    }
  });
});

document.querySelectorAll('img[data-src]').forEach(img => {
  imageObserver.observe(img);
});

Performance Monitoring

Always measure before optimizing.

typescript
class PerformanceMonitor {
  private metrics: Map<string, number[]> = new Map();
  
  measure<T>(name: string, fn: () => T): T {
    const start = performance.now();
    const result = fn();
    const duration = performance.now() - start;
    
    this.record(name, duration);
    return result;
  }
  
  async measureAsync<T>(name: string, fn: () => Promise<T>): Promise<T> {
    const start = performance.now();
    const result = await fn();
    const duration = performance.now() - start;
    
    this.record(name, duration);
    return result;
  }
  
  private record(name: string, duration: number) {
    if (!this.metrics.has(name)) {
      this.metrics.set(name, []);
    }
    this.metrics.get(name)!.push(duration);
  }
  
  getStats(name: string) {
    const measurements = this.metrics.get(name) || [];
    if (measurements.length === 0) return null;
    
    const sorted = [...measurements].sort((a, b) => a - b);
    return {
      count: measurements.length,
      min: sorted[0],
      max: sorted[sorted.length - 1],
      avg: measurements.reduce((a, b) => a + b, 0) / measurements.length,
      median: sorted[Math.floor(sorted.length / 2)],
      p95: sorted[Math.floor(sorted.length * 0.95)],
      p99: sorted[Math.floor(sorted.length * 0.99)]
    };
  }
}

Conclusion

Optimization is an iterative process. Profile first, optimize the bottlenecks, and measure the impact. Remember that premature optimization is the root of all evil—always base your optimizations on real data.

Related essays

Next essay
Docker and Kubernetes Deployment Strategies