بنقرة واحدة
layer-design
Design and compose Effect layers for clean dependency management
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Design and compose Effect layers for clean dependency management
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Create production-ready Effect domain models using Schema.TaggedStruct for ADTs, Schema.Data for automatic equality, with comprehensive predicates, orders, guards, and match functions. Use when modeling domain entities, value objects, or any discriminated union types.
Write comprehensive tests using @effect/vitest for Effect code and vitest for pure functions. Use this skill when implementing tests for Effect-based applications, including services, layers, time-dependent effects, error handling, and property-based testing.
Implement typed error handling in Effect using Data.TaggedError, catchTag/catchTags, and recovery patterns. Use this skill when working with Effect error channels, handling expected failures, or designing error recovery strategies.
Use @effect/platform abstractions for cross-platform file I/O, process spawning, HTTP clients, and terminal operations. Apply this skill when writing code that interacts with the filesystem, spawns processes, makes HTTP requests, or performs console I/O to ensure portability across Node.js, Bun, and browser environments.
Build composable React components using Effect Atom for state management. Use this skill when implementing React UIs that avoid boolean props, embrace component composition, and integrate with Effect's reactive state system.
Master Effect Schema composition patterns including Schema.compose vs Schema.pipe, transformations, filters, and validation. Use this skill when working with complex schema compositions, multi-step transformations, or when you need to validate and transform data through multiple stages.
| name | layer-design |
| description | Design and compose Effect layers for clean dependency management |
Create layers that construct services while managing their dependencies cleanly.
Layer<RequirementsOut, Error, RequirementsIn>
▲ ▲ ▲
│ │ └─ What this layer needs
│ └─ Errors during construction
└─ What this layer produces
export class Config extends Context.Tag("Config")<
Config,
{
readonly getConfig: Effect.Effect<ConfigData>
}
>() {}
// Layer<Config, never, never>
// ▲ ▲ ▲
// │ │ └─ No dependencies
// │ └─ Cannot fail
// └─ Produces Config
export const ConfigLive = Layer.succeed(
Config,
Config.of({
getConfig: Effect.succeed({
logLevel: "INFO",
connection: "mysql://localhost/db"
})
})
)
export class Logger extends Context.Tag("Logger")<
Logger,
{ readonly log: (message: string) => Effect.Effect<void> }
>() {}
// Layer<Logger, never, Config>
// ▲ ▲ ▲
// │ │ └─ Needs Config
// │ └─ Cannot fail
// └─ Produces Logger
export const LoggerLive = Layer.effect(
Logger,
Effect.gen(function* () {
const config = yield* Config // Access dependency
return Logger.of({
log: (message) =>
Effect.gen(function* () {
const { logLevel } = yield* config.getConfig
yield* Console.log(`[${logLevel}] ${message}`)
})
})
})
)
Use Layer.scoped when resources need cleanup:
Effect.acquireRelease or addFinalizer for cleanupUse Layer.effect for stateless services without cleanup needs.
// Layer<Database, DatabaseError, Config>
export const DatabaseLive = Layer.scoped(
Database,
Effect.gen(function* () {
const config = yield* Config
// Acquire resource with automatic release
const connection = yield* Effect.acquireRelease(
connectToDatabase(config),
(conn) => Effect.sync(() => conn.close()) // Cleanup
)
return Database.of({
query: (sql) => executeQuery(connection, sql)
})
})
)
Combine independent layers:
// Layer<Config | Logger, never, Config>
// ▲ ▲ ▲
// │ │ └─ LoggerLive needs Config
// │ └─ No errors
// └─ Produces both Config and Logger
const AppConfigLive = Layer.merge(ConfigLive, LoggerLive)
Result combines:
never | Config = Config)Config | Logger)Chain dependent layers:
// Layer<Logger, never, never>
// ▲ ▲ ▲
// │ │ └─ ConfigLive satisfies LoggerLive's requirement
// │ └─ No errors
// └─ Only Logger in output
const FullLoggerLive = Layer.provide(LoggerLive, ConfigLive)
Result:
never)Logger)Build applications in layers:
// Infrastructure: No dependencies
const InfrastructureLive = Layer.mergeAll(
ConfigLive, // Layer<Config, never, never>
DatabaseLive, // Layer<Database, never, Config>
CacheLive // Layer<Cache, never, Config>
).pipe(
Layer.provide(ConfigLive) // Satisfy Config requirement
)
// Domain: Depends on infrastructure
const DomainLive = Layer.mergeAll(
PaymentDomainLive, // Layer<PaymentDomain, never, Database>
OrderDomainLive, // Layer<OrderDomain, never, Database>
).pipe(
Layer.provide(InfrastructureLive)
)
// Application: Depends on domain
const ApplicationLive = Layer.mergeAll(
PaymentGatewayLive,
NotificationServiceLive
).pipe(
Layer.provide(DomainLive)
)
Switch implementations for different environments:
// Production
export const DatabaseLive = Layer.scoped(
Database,
Effect.gen(function* () {
const connection = yield* connectToProduction()
return createDatabaseService(connection)
})
)
// Test
export const DatabaseTest = Layer.succeed(
Database,
Database.of({
query: () => Effect.succeed({ rows: [] })
})
)
// Use in application
const program = myProgram.pipe(
Effect.provide(process.env.NODE_ENV === "test" ? DatabaseTest : DatabaseLive)
)
Layers are memoized - same instance shared across program:
// Config is constructed once and shared
const program = Effect.all([
Effect.gen(function* () {
const config = yield* Config
// Uses shared instance
}),
Effect.gen(function* () {
const config = yield* Config
// Same instance
})
]).pipe(Effect.provide(ConfigLive))
Handle construction errors:
export const DatabaseLive = Layer.effect(
Database,
Effect.gen(function* () {
const connection = yield* connectToDatabase().pipe(
Effect.catchTag("ConnectionError", (error) =>
Effect.fail(new DatabaseConstructionError({ cause: error }))
)
)
return createDatabaseService(connection)
})
)
*Live - Production implementation*Test - Test implementation*Mock - Mock for testingacquireRelease if neededLayers should make dependency management explicit while keeping service interfaces clean and focused.