From harness-claude
Simplifies complex subsystems using the Facade pattern. Provides a clean, unified interface over multiple subsystems to reduce client coupling.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:gof-facade-patternThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Provide a simplified interface to a complex subsystem to reduce coupling for clients.
Provide a simplified interface to a complex subsystem to reduce coupling for clients.
Classic facade hiding multiple subsystems:
// Complex subsystems — lots of moving parts
class VideoEncoder {
encode(filePath: string, format: 'mp4' | 'webm'): Promise<string> {
console.log(`Encoding ${filePath} to ${format}`);
return Promise.resolve(`${filePath}.${format}`);
}
}
class ThumbnailExtractor {
extract(videoPath: string, atSeconds: number): Promise<string> {
console.log(`Extracting thumbnail at ${atSeconds}s from ${videoPath}`);
return Promise.resolve(`${videoPath}-thumb.jpg`);
}
}
class CDNUploader {
upload(filePath: string, bucket: string): Promise<string> {
console.log(`Uploading ${filePath} to ${bucket}`);
return Promise.resolve(`https://cdn.example.com/${bucket}/${filePath}`);
}
}
class MetadataStore {
save(videoId: string, meta: Record<string, unknown>): Promise<void> {
console.log(`Saving metadata for ${videoId}`);
return Promise.resolve();
}
}
// Facade — single coherent interface over the subsystem
class VideoProcessingFacade {
private encoder = new VideoEncoder();
private thumbExtractor = new ThumbnailExtractor();
private uploader = new CDNUploader();
private metaStore = new MetadataStore();
async processUpload(
rawFilePath: string,
videoId: string,
options: { format: 'mp4' | 'webm'; thumbnailAt: number } = { format: 'mp4', thumbnailAt: 5 }
): Promise<{ videoUrl: string; thumbnailUrl: string }> {
// Orchestrate subsystems — client doesn't need to know any of this
const encodedPath = await this.encoder.encode(rawFilePath, options.format);
const thumbPath = await this.thumbExtractor.extract(encodedPath, options.thumbnailAt);
const [videoUrl, thumbnailUrl] = await Promise.all([
this.uploader.upload(encodedPath, 'videos'),
this.uploader.upload(thumbPath, 'thumbnails'),
]);
await this.metaStore.save(videoId, { videoUrl, thumbnailUrl, processedAt: new Date() });
return { videoUrl, thumbnailUrl };
}
}
// Client code — clean, simple
const videoFacade = new VideoProcessingFacade();
const result = await videoFacade.processUpload('/tmp/raw-upload.mov', 'vid-123');
console.log(result.videoUrl);
API service facade (common in backend apps):
// Instead of clients knowing about Prisma, Redis, and Stripe separately
class UserAccountFacade {
constructor(
private readonly db: PrismaClient,
private readonly cache: RedisClient,
private readonly payments: Stripe,
private readonly mailer: Mailer
) {}
async createAccount(data: CreateAccountInput): Promise<UserAccount> {
// Transaction across multiple systems
const user = await this.db.user.create({ data: { email: data.email } });
const customer = await this.payments.customers.create({ email: data.email });
await this.db.user.update({ where: { id: user.id }, data: { stripeId: customer.id } });
await this.cache.set(`user:${user.id}`, JSON.stringify(user), 'EX', 300);
await this.mailer.sendWelcome(user.email);
return user;
}
async getUser(userId: string): Promise<UserAccount | null> {
const cached = await this.cache.get(`user:${userId}`);
if (cached) return JSON.parse(cached);
return this.db.user.findUnique({ where: { id: userId } });
}
}
Facade vs. Adapter: Facade simplifies an interface — it's for you, the client. Adapter translates one interface to another — it's about compatibility. A Facade can internally use Adapters to talk to subsystems.
Facade vs. API Gateway: In microservices, an API Gateway is a Facade at the network level. It provides a unified entry point over multiple backend services. Same pattern, different layer.
Facade does not prevent direct subsystem access: The facade provides a simpler path but doesn't lock out direct use. Clients who need fine-grained control can still access subsystems directly. Document when the facade is insufficient.
Anti-patterns:
Testability: The facade is the right seam for integration tests. Test the facade's contract. Test the individual subsystem components in isolation.
refactoring.guru/design-patterns/facade
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeProvides a unified, simplified interface to a complex subsystem, reducing client coupling and hiding internal complexity. Useful for wrapping intricate APIs or libraries.
Provides a simplified interface to complex subsystems by composing multiple subsystem calls into a single high-level API. Useful for reducing import complexity and hiding orchestration logic.
Generates Facade pattern classes and unit tests for PHP 8.4 to simplify interfaces for complex subsystems like order processing, notifications, or legacy APIs.