Building Developer Tools: Creating Internal Tools That Teams Love

Building Developer Tools: Creating Internal Tools That Teams Love

BySanjay Goraniya
2 min read
Share:

Building Developer Tools: Creating Internal Tools That Teams Love

The best code you write might not be in your main application—it might be the tools that help your team work better. After building internal tools that saved hundreds of hours, I've learned what makes tools that teams actually use.

Why Build Internal Tools?

Benefits

  1. Time savings - Automate repetitive tasks
  2. Consistency - Same process every time
  3. Reduced errors - Less manual work = fewer mistakes
  4. Knowledge sharing - Tools document processes
  5. Team productivity - Focus on important work

Types of Internal Tools

1. CLI Tools

Command-line tools for common tasks:

Code
#!/usr/bin/env node
// scripts/create-user.js

const readline = require('readline');
const { createUser } = require('../services/userService');

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

async function createUserCLI() {
  const email = await question('Email: ');
  const name = await question('Name: ');
  const role = await question('Role (admin/user): ');
  
  try {
    const user = await createUser({ email, name, role });
    console.log(`✅ User created: ${user.id}`);
  } catch (error) {
    console.error(`❌ Error: ${error.message}`);
  }
  
  rl.close();
}

function question(prompt) {
  return new Promise(resolve => {
    rl.question(prompt, resolve);
  });
}

createUserCLI();

2. Admin Dashboards

Web interfaces for managing data:

Code
// Admin dashboard
app.get('/admin/users', requireAdmin, async (req, res) => {
  const users = await getUsers();
  res.render('admin/users', { users });
});

app.post('/admin/users/:id/activate', requireAdmin, async (req, res) => {
  await activateUser(req.params.id);
  res.redirect('/admin/users');
});

3. Data Migration Tools

Tools for moving/transforming data:

Code
// Migration tool
async function migrateUsers(sourceDB, targetDB) {
  const users = await sourceDB.query('SELECT * FROM users');
  
  for (const user of users) {
    try {
      await targetDB.query(
        'INSERT INTO users (id, email, name) VALUES ($1, $2, $3)',
        [user.id, user.email, user.name]
      );
      console.log(`✅ Migrated user: ${user.email}`);
    } catch (error) {
      console.error(`❌ Failed to migrate ${user.email}: ${error.message}`);
    }
  }
}

4. Monitoring Tools

Tools for system health:

Code
// Health check dashboard
app.get('/admin/health', async (req, res) => {
  const health = {
    database: await checkDatabase(),
    redis: await checkRedis(),
    api: await checkAPI(),
    timestamp: new Date().toISOString()
  };
  
  res.json(health);
});

Building Effective Tools

1. Solve Real Problems

Build tools for problems your team actually has:

Code
// Problem: Manually checking deployment status
// Solution: Deployment status tool

async function checkDeployments() {
  const deployments = await getDeployments();
  
  deployments.forEach(deploy => {
    const status = deploy.status === 'success' ? '✅' : '❌';
    console.log(`${status} ${deploy.service} - ${deploy.environment}`);
  });
}

2. Make It Easy to Use

Code
// Good: Simple, clear interface
$ npm run create-user
Email: user@example.com
Name: John DoeUser created

// Bad: Complex, unclear
$ node scripts/user-management/create-new-user.js --email user@example.com --name "John Doe" --role user --send-email true

3. Provide Feedback

Code
// Show progress
async function processOrders(orders) {
  let processed = 0;
  
  for (const order of orders) {
    await processOrder(order);
    processed++;
    
    // Progress feedback
    process.stdout.write(`\rProcessed: ${processed}/${orders.length}`);
  }
  
  console.log('\n✅ All orders processed');
}

4. Handle Errors Gracefully

Code
async function bulkOperation(items) {
  const results = { success: 0, failed: 0, errors: [] };
  
  for (const item of items) {
    try {
      await processItem(item);
      results.success++;
    } catch (error) {
      results.failed++;
      results.errors.push({ item, error: error.message });
      console.error(`❌ Failed: ${item.id} - ${error.message}`);
    }
  }
  
  console.log(`\n✅ Success: ${results.success}`);
  console.log(`❌ Failed: ${results.failed}`);
  
  if (results.errors.length > 0) {
    console.log('\nErrors:');
    results.errors.forEach(({ item, error }) => {
      console.log(`  ${item.id}: ${error}`);
    });
  }
}

Common Internal Tools

1. Database Management

Code
// Database admin tool
class DatabaseAdmin {
  async backupDatabase() {
    console.log('Creating backup...');
    await exec('pg_dump database > backup.sql');
    console.log('✅ Backup created');
  }
  
  async restoreDatabase(backupFile) {
    console.log('Restoring from backup...');
    await exec(`psql database < ${backupFile}`);
    console.log('✅ Database restored');
  }
  
  async runQuery(query) {
    const result = await db.query(query);
    console.table(result.rows);
  }
}

2. User Management

Code
// User management tool
async function manageUsers() {
  const action = await question('Action (create/list/delete): ');
  
  switch (action) {
    case 'create':
      await createUser();
      break;
    case 'list':
      await listUsers();
      break;
    case 'delete':
      await deleteUser();
      break;
  }
}

3. Deployment Tools

Code
// Deployment tool
async function deploy(environment, service) {
  console.log(`Deploying ${service} to ${environment}...`);
  
  // Build
  console.log('Building...');
  await exec('npm run build');
  
  // Test
  console.log('Running tests...');
  await exec('npm test');
  
  // Deploy
  console.log('Deploying...');
  await exec(`kubectl set image deployment/${service} ${service}=image:latest`);
  
  // Verify
  console.log('Verifying deployment...');
  await waitForDeployment(service);
  
  console.log('✅ Deployment successful');
}

Best Practices

1. Document Everything

Code
/**
 * Creates a new user in the system
 * 
 * Usage:
 *   create-user --email user@example.com --name "John Doe"
 * 
 * Options:
 *   --email    User email (required)
 *   --name     User name (required)
 *   --role     User role (default: user)
 */

2. Make It Safe

Code
// Confirm destructive operations
async function deleteUser(userId) {
  const user = await getUser(userId);
  
  const confirm = await question(
    `Delete user ${user.email}? (yes/no): `
  );
  
  if (confirm !== 'yes') {
    console.log('Cancelled');
    return;
  }
  
  await deleteUserById(userId);
  console.log('✅ User deleted');
}

3. Version Control

Code
// Track tool versions
const TOOL_VERSION = '1.2.3';

function showVersion() {
  console.log(`Tool version: ${TOOL_VERSION}`);
}

4. Logging

Code
// Log tool usage
const logger = require('./logger');

async function createUser(data) {
  logger.info('Creating user', { email: data.email });
  
  try {
    const user = await userService.create(data);
    logger.info('User created', { userId: user.id });
    return user;
  } catch (error) {
    logger.error('Failed to create user', { error, email: data.email });
    throw error;
  }
}

Real-World Example

Problem: Team spending hours manually checking deployment statuses, user data, and system health.

Solution: Built admin dashboard with:

  1. Deployment status - See all deployments at a glance
  2. User management - Search, filter, manage users
  3. System health - Database, Redis, API status
  4. Quick actions - One-click common operations

Result:

  • Time saved: 5 hours/week
  • Fewer errors: Automated processes
  • Better visibility: Know system state instantly

Conclusion

Internal tools are force multipliers. A good tool can save hours every week and make your team more productive. The key is to:

  • Solve real problems - Build what's needed
  • Keep it simple - Easy to use
  • Provide feedback - Show what's happening
  • Document well - Others need to use it

Remember: The best tools are the ones people actually use. Build tools that make life easier, and your team will thank you.

What internal tools have you built? What problems did they solve?

Share: