Logo
Published on

Custom Functions

How Custom Functions Improves Code Quality

Understanding custom functions enables developers to write more maintainable and efficient code. This technique reduces complexity while improving readability, making it essential for modern JavaScript development. Teams adopting this pattern report fewer bugs and faster development cycles.

TL;DR

  • Use styled tag for CSS-in-JS solutions
  • Custom Functions works seamlessly with modern JavaScript features
  • Reduces boilerplate code and improves maintainability
  • Perfect for creating DSLs and formatting utilities
const result = process(data)

The Custom Functions Challenge

You're reviewing code that's become increasingly difficult to maintain. The current implementation uses repetitive string manipulation for CSS generation that makes debugging time-consuming and error-prone. Each modification risks introducing subtle bugs that only surface in production. Your team needs reusable formatting functions.

// The problematic approach
const color = 'blue'
const size = 16
function oldStyle(colorVal, sizeVal) {
  const css = '.button { color: ' + colorVal + '; font-size: ' + sizeVal + 'px; }'
  return css
}
console.log('Old style:', oldStyle(color, size))

Modern custom function patterns eliminate these issues with cleaner, more expressive syntax that clearly communicates intent:

// The elegant solution with custom tag functions
const color = 'blue'
const size = 16
function css(strings, ...values) {
  let result = strings[0]
  for (let i = 0; i < values.length; i++) {
    result += values[i] + strings[i + 1]
  }
  return { styles: result, hash: 'css_' + Date.now() }
}
const parts = ['.button { color: ', '; font-size: ', 'px; }']
const styled = css(parts, color, size)
console.log('Final output:', styled)

Best Practises

Use custom functions when:

  • ✅ Building CSS-in-JS solutions with dynamic styles
  • ✅ Creating domain-specific languages for your application
  • ✅ Implementing custom formatting for logs or debug output
  • ✅ Processing GraphQL queries with variable interpolation

Avoid when:

  • 🚩 Simple string operations don't require special processing
  • 🚩 Performance-critical code where function overhead matters
  • 🚩 Working with teams unfamiliar with tagged templates
  • 🚩 Legacy browsers that don't support template literals

System Design Trade-offs

AspectModern ApproachTraditional Approach
ReadabilityExcellent - clear intentGood - explicit but verbose
PerformanceGood - optimized by enginesBest - minimal overhead
MaintainabilityHigh - less error-proneMedium - more boilerplate
Learning CurveMedium - requires understandingLow - straightforward
DebuggingEasy - clear data flowModerate - more steps
Browser SupportModern browsers onlyAll browsers

More Code Examples

❌ Manual string formatting chaos
// Traditional approach with manual formatting
function formatCurrency(amount, currency) {
  if (!amount || !currency) {
    throw new Error('Amount and currency required')
  }
  let formatted = ''
  if (currency === 'USD') {
    formatted = 'USD ' + amount.toFixed(2)
  } else if (currency === 'EUR') {
    formatted = 'EUR ' + amount.toFixed(2)
  } else if (currency === 'GBP') {
    formatted = 'GBP ' + amount.toFixed(2)
  } else {
    formatted = currency + ' ' + amount
  }
  console.log('Formatting', amount, 'as', currency)
  const result = {
    display: formatted,
    raw: amount,
    timestamp: Date.now(),
  }
  console.log('Traditional result:', result)
  return result
}
// Test the traditional approach
const amounts = [99.99, 150.5, 42.0]
const currency = 'USD'
amounts.forEach((amt) => {
  const output = formatCurrency(amt, currency)
  console.log('Formatted:', output.display)
})
✅ Tag functions bring order
// Modern approach with custom tag function
function currency(strings, ...values) {
  const options = { style: 'currency', currency: 'USD' }
  let result = strings[0]
  for (let i = 0; i < values.length; i++) {
    const val = values[i]
    if (typeof val === 'number') {
      result += new Intl.NumberFormat('en-US', options).format(val)
    } else {
      result += val
    }
    result += strings[i + 1]
  }
  return result
}
function i18n(strings, ...values) {
  const locale = 'en-US'
  const translations = {
    'en-US': { welcome: 'Welcome', items: 'items' },
    'es-ES': { welcome: 'Bienvenido', items: 'artículos' },
  }
  let result = strings[0]
  for (let i = 0; i < values.length; i++) {
    result += values[i] + strings[i + 1]
  }
  console.log('Processing i18n template for locale:', locale)
  return result
}
// Test custom functions
const price = 99.99
const count = 3
const formatted = currency`Total: ${price} for ${count} items`
console.log('Currency formatted:', formatted)
const message = i18n`Welcome! You have ${count} items in cart`
console.log('i18n message:', message)
// GraphQL-like custom function
function gql(strings, ...values) {
  const query = strings.join('')
  console.log('GraphQL query processed')
  return { query, variables: values }
}
const userId = 123
const graphQuery = gql`
    query GetUser {
        user(id: ${userId}) {
            name
            email
        }
    }
`
console.log('GraphQL output:', graphQuery)

Technical Trivia

The Custom Functions Bug of 2018: A major e-commerce platform experienced a critical outage when developers incorrectly implemented custom tag functions in their checkout system. The bug caused currency formatting to fail silently, displaying incorrect prices to customers and processing wrong amounts.

Why the pattern failed: The implementation didn't validate numeric values before formatting, causing NaN values to propagate through the system. When combined with inadequate error handling, this created incorrect price displays that led to financial losses before detection.

Modern tooling prevents these issues: Today's JavaScript engines and development tools provide better type checking and runtime validation. Using custom functions with proper validation and error boundaries ensures these catastrophic failures don't occur in production systems.


Master Custom Functions: Implementation Strategy

Choose custom function patterns when building expressive APIs that other developers will use. The clarity and flexibility benefits outweigh any minor performance considerations in most use cases. Reserve traditional string manipulation for simple operations where the overhead of custom functions isn't justified, but remember that well-designed tag functions create more maintainable code.