Zum Inhalt springen

Wiederkehrende Aufgaben als Entwickler automatisieren

Praktische Strategien, um wiederkehrende Aufgaben zu erkennen und zu automatisieren – Shell-Skripte, Codegeneratoren, Git-Aliasse und Scaffolding.

5 Min. Lesezeit
Flussdiagramm, das zeigt, wie manuelle, sich wiederholende Aufgaben durch automatisierte Skripte und Tools ersetzt werden

Die meisten Entwickler verbringen jede Woche Stunden mit Aufgaben, die sie schon hundertmal erledigt haben — Boilerplate-Dateien anlegen, Test-Fixtures einrichten, auf Staging deployen, Dateistapel umbenennen. Diese Aufgaben sind nicht schwer, aber sie unterbrechen. Sie zu automatisieren beseitigt eine ganze Klasse von Kontextwechseln und macht den Kopf frei für echte Problemlösungen.

Die Faustregel: Wenn du etwas mehr als dreimal tust, automatisiere es. Wenn die Automatisierung weniger Zeit kostet, als die Aufgabe noch fünfmal manuell zu erledigen, amortisiert sie sich schnell. Der Nebeneffekt ist Konsistenz — automatisierte Aufgaben vergessen keine Schritte und produzieren keine Tippfehler.

Ermitteln, was man automatisieren sollte

Führe eine Woche lang ein Protokoll über sich wiederholende Aufgaben. Die meisten Entwickler sind überrascht, wie viel Zeit in mechanischer Arbeit steckt.

markdownmarkdown
## Automation Candidates (1 week log)
 
### High Frequency (daily)
- Creating new React component files (same structure every time)
- Running database migrations before starting dev server
- Switching between Git branches and rebuilding
 
### Medium Frequency (weekly)
- Setting up test fixtures for integration tests
- Generating API client code from OpenAPI specs
- Creating pull request descriptions from commit history
 
### Low Frequency (monthly)
- Spinning up a new microservice from template
- Rotating API keys across environments
- Generating release notes from merged PRs
tstypescript
// ❌ Manual component creation — every single time
// 1. Create src/components/UserProfile/
// 2. Create UserProfile.tsx with boilerplate
// 3. Create UserProfile.test.tsx with test structure
// 4. Create index.ts with export
// 5. Add to component barrel file
// Time: 3-5 minutes, repeated 3x per day = 15 minutes/day
 
// ✅ Automated — one command
// $ gen component UserProfile
// Creates all 4 files with correct structure
// Time: 5 seconds

Shell-Aliase und -Funktionen

Die einfachste Form der Automatisierung sind Shell-Aliase und -Funktionen. Sie fassen mehrstufige Befehle zu einem einzigen Aufruf zusammen.

shbash
# ~/.zshrc or ~/.bashrc
 
# Git shortcuts
alias gs='git status'
alias gco='git checkout'
alias gp='git pull --rebase'
alias gcm='git commit -m'
 
# Development workflow
alias dev='npm run dev'
alias build='npm run build'
alias test='npm run test'
alias lint='npm run lint -- --fix'
 
# Complex workflows as functions
function fresh() {
  # Fresh start: pull latest, install deps, run migrations, start dev
  echo "🔄 Pulling latest changes..."
  git pull --rebase origin main
  echo "📦 Installing dependencies..."
  npm ci
  echo "🗄️  Running migrations..."
  npm run db:migrate
  echo "🚀 Starting dev server..."
  npm run dev
}
 
function branch() {
  # Create a new feature branch from latest main
  local branch_name=$1
  if [ -z "$branch_name" ]; then
    echo "Usage: branch feat/my-feature"
    return 1
  fi
  git checkout main
  git pull --rebase
  git checkout -b "$branch_name"
  echo "Created and switched to $branch_name"
}
shbash
# ❌ Multiple commands every time you start work
git checkout main
git pull --rebase
npm ci
npm run db:migrate
npm run dev
# Time: 2 minutes of typing + waiting
 
# ✅ One command
fresh
# Same result, zero thinking, zero typos

Codegeneratoren

Für das wiederholte Anlegen von Dateien beseitigt ein Codegenerator Boilerplate und setzt die Projektkonventionen durch.

tstypescript
// scripts/generate-component.ts
import fs from 'fs';
import path from 'path';
 
interface ComponentConfig {
  name: string;
  directory: string;
  withTests: boolean;
  withStories: boolean;
}
 
function generateComponent(config: ComponentConfig): void {
  const dir = path.join(config.directory, config.name);
  fs.mkdirSync(dir, { recursive: true });
 
  // Component file
  const component = `interface ${config.name}Props {
  className?: string;
}
 
export function ${config.name}({ className }: ${config.name}Props) {
  return (
    <div className={className}>
      <h2>${config.name}</h2>
    </div>
  );
}
`;
  fs.writeFileSync(path.join(dir, `${config.name}.tsx`), component);
 
  // Test file
  if (config.withTests) {
    const test = `import { render, screen } from '@testing-library/react';
import { ${config.name} } from './${config.name}';
 
describe('${config.name}', () => {
  it('renders without crashing', () => {
    render(<${config.name} />);
    expect(screen.getByText('${config.name}')).toBeInTheDocument();
  });
});
`;
    fs.writeFileSync(
      path.join(dir, `${config.name}.test.tsx`),
      test
    );
  }
 
  // Index file
  const index = `export { ${config.name} } from './${config.name}';\n`;
  fs.writeFileSync(path.join(dir, 'index.ts'), index);
 
  console.log(`Created ${config.name} in ${dir}`);
}
 
// CLI entry point
const name = process.argv[2];
if (!name) {
  console.error('Usage: tsx scripts/generate-component.ts MyComponent');
  process.exit(1);
}
 
generateComponent({
  name,
  directory: 'src/components',
  withTests: true,
  withStories: false,
});

Git-Hooks für automatisierte Prüfungen

Git-Hooks automatisieren Qualitätsprüfungen zu den richtigen Zeitpunkten — vor dem Commit, vor dem Push. Sie verhindern, dass typische Fehler im Repository landen.

shbash
# .husky/pre-commit — lint only changed files
npx lint-staged
 
# .husky/commit-msg — enforce commit message format
#!/bin/sh
COMMIT_MSG=$(cat "$1")
PATTERN="^(feat|fix|docs|style|refactor|perf|test|chore|ci|revert)(\(.+\))?: .{1,100}$"
 
if ! echo "$COMMIT_MSG" | grep -qE "$PATTERN"; then
  echo "❌ Commit message does not match conventional format."
  echo "   Expected: type(scope): description"
  echo "   Example: feat(auth): add password reset flow"
  exit 1
fi
jsonjson
// lint-staged.config.json — auto-format on commit
{
  "*.{ts,tsx}": ["eslint --fix", "prettier --write"],
  "*.{css,scss}": ["prettier --write"],
  "*.md": ["prettier --write"]
}

Datenbank- und API-Automatisierung

Automatisiere wiederkehrende Datenbankoperationen und die Generierung von API-Clients, um manuelle Synchronisationsarbeit loszuwerden.

shbash
#!/bin/bash
# scripts/sync-staging.sh — pull staging database for local development
 
set -euo pipefail
 
DB_NAME="myapp_dev"
STAGING_URL="${STAGING_DATABASE_URL:?Set STAGING_DATABASE_URL}"
 
echo "⬇️  Dumping staging database..."
pg_dump "$STAGING_URL" \
  --no-owner \
  --no-privileges \
  --exclude-table='sessions' \
  --exclude-table='audit_logs' \
  > /tmp/staging_dump.sql
 
echo "🗑️  Dropping local database..."
dropdb --if-exists "$DB_NAME"
createdb "$DB_NAME"
 
echo "📥 Restoring to local..."
psql "$DB_NAME" < /tmp/staging_dump.sql
 
echo "🔒 Anonymizing PII..."
psql "$DB_NAME" <<SQL
  UPDATE users SET
    email = 'user_' || id || '@test.local',
    first_name = 'Test',
    last_name = 'User_' || id;
SQL
 
rm /tmp/staging_dump.sql
echo "✅ Local database synced with anonymized staging data"
tstypescript
// scripts/generate-api-client.ts
// Auto-generate TypeScript API client from OpenAPI spec
 
import { execSync } from 'child_process';
 
const SPEC_URL = 'https://api.example.com/openapi.json';
const OUTPUT_DIR = 'src/api/generated';
 
// Generate client using openapi-typescript-codegen
execSync(
  `npx openapi-typescript-codegen \
    --input ${SPEC_URL} \
    --output ${OUTPUT_DIR} \
    --client fetch \
    --useOptions`,
  { stdio: 'inherit' }
);
 
console.log(`API client generated in ${OUTPUT_DIR}`);

Projekt-Scaffolding

Für Teams, die regelmäßig neue Services oder Pakete anlegen, stellt ein Scaffolding-Tool sicher, dass jedes Projekt mit derselben Struktur, denselben Konfigurationen und CI-Pipelines startet.

tstypescript
// scripts/scaffold-service.ts
import fs from 'fs';
import path from 'path';
 
interface ServiceConfig {
  name: string;
  port: number;
  hasDatabase: boolean;
  hasRedis: boolean;
}
 
function scaffoldService(config: ServiceConfig): void {
  const base = path.join('services', config.name);
 
  const structure: Record<string, string> = {
    'src/index.ts': generateEntryPoint(config),
    'src/routes/health.ts': generateHealthRoute(config),
    'Dockerfile': generateDockerfile(config),
    'docker-compose.yml': generateDockerCompose(config),
    '.env.example': generateEnvExample(config),
    'tsconfig.json': JSON.stringify(tsconfig, null, 2),
    'package.json': JSON.stringify(
      generatePackageJson(config),
      null,
      2
    ),
  };
 
  for (const [filePath, content] of Object.entries(structure)) {
    const fullPath = path.join(base, filePath);
    fs.mkdirSync(path.dirname(fullPath), { recursive: true });
    fs.writeFileSync(fullPath, content);
  }
 
  console.log(`Scaffolded service '${config.name}' in ${base}/`);
  console.log(`Next steps:`);
  console.log(`  cd ${base}`);
  console.log(`  npm install`);
  console.log(`  npm run dev`);
}
shbash
# ❌ Manual service creation
# 1. Create directory structure (5 min)
# 2. Copy and modify Dockerfile from another service (10 min)
# 3. Set up tsconfig, package.json, eslint config (15 min)
# 4. Create health check route (5 min)
# 5. Set up docker-compose with database (10 min)
# 6. Configure CI pipeline (15 min)
# Time: ~1 hour, inconsistent across services
 
# ✅ Scaffolded in seconds
npx tsx scripts/scaffold-service.ts --name user-service --port 3001 --db --redis
# Time: 10 seconds, consistent every time

Wichtige Erkenntnisse

  1. Protokolliere eine Woche lang sich wiederholende Aufgaben — du kannst nicht automatisieren, was du nicht identifiziert hast; Häufigkeit und Zeitaufwand werden dich überraschen
  2. Fang mit Shell-Aliassen an — der schnellste Weg, mehrstufige Befehle loszuwerden; fünf Minuten Einrichtung sparen monatelanges Tippen
  3. Baue Codegeneratoren für Boilerplate — jede Dateistruktur, die mehr als dreimal angelegt wird, sollte einen Generator haben
  4. Automatisiere Datenbank-Syncs mit Anonymisierung — Staging-Daten in der lokalen Entwicklung beschleunigen das Debugging, ohne PII offenzulegen
  5. Nutze Scaffolding für neue Projekte — jeder neue Service oder jedes neue Paket sollte von einer konsistenten Vorlage starten, nicht per Copy-Paste aus einem anderen Projekt
  6. Investiere proportional in Automatisierung — verwende 30 Minuten darauf, etwas zu automatisieren, das du täglich tust, nicht etwas, das du einmal im Jahr machst
Wilfredo Rujel

Wilfredo Rujel

Full-Stack-Softwareentwickler

Diesen Beitrag teilenX