Building reusable backend components.

typescript dev.to

Your backend is probably not as modular as you think

Your backend infrastructure might have more duplicated plumbing than it needs to.

In recent discussions about shared logic across services, the common suggestions were solid: monorepos, shared packages, internal frameworks, careful service boundaries, domain-driven business logic, and shared schemas or contracts (like protobuf).

Those approaches help a lot. But even then, many teams still find themselves repeatedly building similar supporting infrastructure around their core logic.

Things like:

•⁠ ⁠Third-party API integrations
•⁠ ⁠Job queuing and scheduling
•⁠ ⁠Retry policies
•⁠ ⁠Auth flows
•⁠ ⁠Storage abstractions
•⁠ ⁠Webhook handling
•⁠ ⁠Monitoring hooks
•⁠ ⁠Orchestration patterns

For example, a basic Stripe integration in Node.js often ends up with manual HTTP calls or repeated setup code. Same for queue workers — you end up configuring connections, retries, delays, and monitoring in multiple places.

This surrounding “plumbing” can become significant over time, even when business logic itself is well organized.

We’ve been exploring a different angle with Ductape.

The idea is to treat certain backend infrastructure patterns as reusable runtime components. Instead of wiring up transport, auth, config, and execution concerns in every service, these can live in defined, reusable “connections” or actions.

It looks something like this:

const result = await ductape.actions.run({
  env: 'prd',
  product: 'my-product',
  app: 'stripe-app',
  action: 'create_payment_intent',
  input: {
    amount: 2000,
    currency: 'usd',
    customer: 'cus_123456'
  }
});

Enter fullscreen mode Exit fullscreen mode

Or for jobs:

const job = await ductape.actions.dispatch({
  env: 'prd',
  product: 'my-app',
  app: 'order-service',
  event: 'process_order',
  input: { orderId: 'ord_123' },
  retries: 3,
  schedule: { delay: 60000 }
});

Enter fullscreen mode Exit fullscreen mode

Under the hood, a context engine resolves environment details, credentials, and configuration at runtime (with caching after the first resolution) and provides structured logging.

The goal isn’t to replace your business logic or claim this is the only way to build backends. It’s an attempt to reduce the repetitive infrastructure work that often surrounds it — making certain integrations and execution patterns more composable and consistent across services.

This is still early exploration. There are clear trade-offs: added abstraction, governance considerations, and situations where more direct control (official SDKs, thin wrappers, or dedicated orchestration tools) will be preferable.

We’re testing how well this model holds up in real projects. If you’re dealing with duplicated integration or job infrastructure across multiple services, I’d be interested in your thoughts.

Ductape

Source: dev.to

arrow_back Back to Tutorials