DEV Community

Max Khramtsov
Max Khramtsov

Posted on

Effect: Schema optimisation with synchronous transformations

Got interested in this optimisation in Schema — and decided to find out how it works under the hood:

If you want more perf you can use ParseResult.flatMap instead of Effect.gen and get eager optimisation skipping the Effect runtime.
Michael Arnaldi


Given

Schema.transformOrFail transformers are expected to return Effect<T, ParseResult.ParseIssue, R>. However, for example, Either is a subtype of Effect, so returning Either<T, ParseResult.ParseIssue> is also valid.

The idea

If a schema only uses Either-transformations, then its decoders/encoders can be run without involving the runtime.

The optimisation

For convenience, the following type is used in the schema:

type ParseResult<A> = Either<A, ParseResult.ParseIssue>
Enter fullscreen mode Exit fullscreen mode
  1. We need to preserve the transformation type as Either and not convert it to Effect — this is handled by functions in ParseResult under the @category optimisation, such as ParseResult.flatMap.

  2. These helpers are primarily used in the ParseResult.go function, which is responsible for walking through all AST nodes of the schema and producing a ParseResult.Parser — the actual encode/decode function.

  3. ParseResult.handleForbidden is the function where the final decision to use the runtime or not is made.

The requirements

From its implementation, it's clear that in order for the optimisation ritual to work, two conditions must be met:

  • The user's intention — to invoke the validate/decode/encode family of functions with the Either/Option/Sync suffix (synchronously)

  • The schema's capability — using ParseResult<A>(alias for Either) specifically in transformations.

Otherwise, the optimisation won’t apply — and the runtime with the synchronous scheduler will be used, which seems effectively the same as Effect.runSync.

The notes

However, it's also important to note that the schema annotations concurrent and batching will not be applied to synchronous transformations — meaning that here, transformations take precedence.


Optimisation through synchronous transformations with ParseResult potentially improves performance by bypassing the Effect runtime. However, I did not conduct any benchmarks; my interest was solely in how the optimisation is implemented.

I hope this overview will be useful to developers when making design decisions and that it’s helpful to know such an optimisation exists.

Top comments (0)