factory-function-composition

factory-function-composition

Beliebt

Apply factory function patterns to compose clients and services with proper separation of concerns. Use when creating functions that depend on external clients, wrapping resources with domain-specific methods, or refactoring code that mixes client/service/method options together.

3.9KSterne
262Forks
Aktualisiert 1/21/2026
SKILL.md
readonlyread-only
name
factory-function-composition
description

Apply factory function patterns to compose clients and services with proper separation of concerns. Use when creating functions that depend on external clients, wrapping resources with domain-specific methods, or refactoring code that mixes client/service/method options together.

version
'1.0'

Factory Function Composition

This skill helps you apply factory function patterns for clean dependency injection and function composition in TypeScript.

When to Apply This Skill

Use this pattern when you see:

  • A function that takes a client/resource as its first argument
  • Options from different layers (client, service, method) mixed together
  • Client creation happening inside functions that shouldn't own it
  • Functions that are hard to test because they create their own dependencies

The Universal Signature

Every factory function follows this signature:

function createSomething(dependencies, options?) {
	return {
		/* methods */
	};
}
  • First argument: Always the resource(s). Either a single client or a destructured object of multiple dependencies.
  • Second argument: Optional configuration specific to this factory. Never client config—that belongs at client creation.

Two arguments max. First is resources, second is config. No exceptions.

The Core Pattern

// Single dependency
function createService(client, options = {}) {
	return {
		method(methodOptions) {
			// Uses client, options, and methodOptions
		},
	};
}

// Multiple dependencies
function createService({ db, cache }, options = {}) {
	return {
		method(methodOptions) {
			// Uses db, cache, options, and methodOptions
		},
	};
}

// Usage
const client = createClient(clientOptions);
const service = createService(client, serviceOptions);
service.method(methodOptions);

Key Principles

  1. Client configuration belongs at client creation time — don't pipe clientOptions through your factory
  2. Each layer has its own options — client, service, and method options stay separate
  3. Dependencies come first — factory functions take dependencies as the first argument
  4. Return objects with methods — not standalone functions that need the resource passed in

Recognizing the Anti-Patterns

Anti-Pattern 1: Function takes client as first argument

// Bad
function doSomething(client, options) { ... }
doSomething(client, options);

// Good
const service = createService(client);
service.doSomething(options);

Anti-Pattern 2: Client creation hidden inside

// Bad
function doSomething(clientOptions, methodOptions) {
	const client = createClient(clientOptions); // Hidden!
	// ...
}

// Good
const client = createClient(clientOptions);
const service = createService(client);
service.doSomething(methodOptions);

Anti-Pattern 3: Mixed options blob

// Bad
doSomething({
	timeout: 5000, // Client option
	retries: 3, // Client option
	endpoint: '/users', // Method option
	payload: data, // Method option
});

// Good
const client = createClient({ timeout: 5000, retries: 3 });
const service = createService(client);
service.doSomething({ endpoint: '/users', payload: data });

Anti-Pattern 4: Multiple layers hidden

// Bad
function doSomething(clientOptions, serviceOptions, methodOptions) {
	const client = createClient(clientOptions);
	const service = createService(client, serviceOptions);
	return service.method(methodOptions);
}

// Good — each layer visible and configurable
const client = createClient(clientOptions);
const service = createService(client, serviceOptions);
service.method(methodOptions);

Multiple Dependencies

When your service needs multiple clients:

function createService(
	{ db, cache, http }, // Dependencies as destructured object
	options = {}, // Service options
) {
	return {
		method(methodOptions) {
			// Uses db, cache, http
		},
	};
}

// Usage
const db = createDbConnection(dbOptions);
const cache = createCacheClient(cacheOptions);
const http = createHttpClient(httpOptions);

const service = createService({ db, cache, http }, serviceOptions);
service.method(methodOptions);

The Mental Model

Think of it as a chain where each link:

  • Receives a resource from the previous link
  • Adds its own configuration
  • Produces something for the next link
createClient(...)  →  createService(client, ...)  →  service.method(...)
     ↑                       ↑                            ↑
 clientOptions          serviceOptions              methodOptions

Benefits

  • Testability: Inject mock clients easily
  • Reusability: Share clients across multiple services
  • Flexibility: Configure each layer independently
  • Clarity: Clear ownership of configuration at each level

References

See the full articles for more details:

You Might Also Like

Related Skills

coding-agent

coding-agent

179Kdev-codegen

Run Codex CLI, Claude Code, OpenCode, or Pi Coding Agent via background process for programmatic control.

openclaw avataropenclaw
Holen
add-uint-support

add-uint-support

97Kdev-codegen

Add unsigned integer (uint) type support to PyTorch operators by updating AT_DISPATCH macros. Use when adding support for uint16, uint32, uint64 types to operators, kernels, or when user mentions enabling unsigned types, barebones unsigned types, or uint support.

pytorch avatarpytorch
Holen
at-dispatch-v2

at-dispatch-v2

97Kdev-codegen

Convert PyTorch AT_DISPATCH macros to AT_DISPATCH_V2 format in ATen C++ code. Use when porting AT_DISPATCH_ALL_TYPES_AND*, AT_DISPATCH_FLOATING_TYPES*, or other dispatch macros to the new v2 API. For ATen kernel files, CUDA kernels, and native operator implementations.

pytorch avatarpytorch
Holen
skill-writer

skill-writer

97Kdev-codegen

Guide users through creating Agent Skills for Claude Code. Use when the user wants to create, write, author, or design a new Skill, or needs help with SKILL.md files, frontmatter, or skill structure.

pytorch avatarpytorch
Holen

Implements JavaScript classes in C++ using JavaScriptCore. Use when creating new JS classes with C++ bindings, prototypes, or constructors.

oven-sh avataroven-sh
Holen

Creates JavaScript classes using Bun's Zig bindings generator (.classes.ts). Use when implementing new JS APIs in Zig with JSC integration.

oven-sh avataroven-sh
Holen