No Need for NIH

Leveraging the Typelevel Stack in the Enterprise

Adam Rosien @arosien

Inner Product LLC @InnerProductLLC

ScalaCon, 20 May 2021

inner product logo with url 320

This talk

[.grey]##

NIH

Not-Invented-Here

Leveraging

you receive: more power

Typelevel Stack

oodles of composable libraries

Enterprise

your job

While researching this talk…​

Typelevel Summit 2016

Typelevel Summit, March 2016

End to End and On The Level   Dave Gurnell   YouTube

typelevel stack 1
Meme Generator   Imgflip
typelevel stack 2

The Typelevel Ecosystem

typelevel scala

…​ and more

It’s so useful…​ why?

This talk

  1. The Typelevel ecosystem

  2. Why the Typelevel ecosystem works

  3. Typelevel adoption and integration

The Typelevel ecosystem

typelevel

Capabilities we want

data access

databases, message queues, Kafka stuff, cloud storage, …​

web services

service HTTP requests and responses, JSON handling, clients to other services, …​

testing

property-based testing, …​

domain modeling

parsing, validation, typed invariants, …​

application infrastructure

command-line parsing, configuration, logging, …​

Capabilities we want

data access

web services

testing

domain modeling

application infrastructure

While ensuring we have:

  • safe and well-defined composability

  • managed side-effects and concurrency

  • complex stream processing (if desired)

The Typelevel ecosystem: key libraries

http4s logo

http4s

doobie

doobie

fs2

fs2

cats effect logo

Cats Effect

cats logo

Cats

☝︎

stacks grow upwards

Cats

cats logo

Functor

map

F[A] => (A => B) => F[B]

Applicative

mapN

(F[A], ...) => ((A, ...) => Z) => F[Z]

Monad

flatMap

F[A] => (A => F[B]) => F[B]

Traverse

traverse

F[A] => (A => G[B]) => G[F[B]]

Cats

Functional programming cheatsheet:

  1. Is it map?

  2. Is it mapN?

  3. Is it flatMap?

  4. It’s traverse.

traverse

Cats

More typeclasses:

  • MonadError: raiseError, handleErrorWith, …​

  • Parallel: parMapN, parTupled, …​

  • …​

Data types:

  • Chain: efficient List-like data structure)

  • Ior: modeling errors vs. warnings

  • NonEmptyList, NonEmptyChain: non-empty collections

  • and more

Cats Effect

cats effect logo

Cats Effect

Cats

Cats Effect

Typeclasses:

  • MonadCancel: cancelation-safe finalizers

  • Spawn: concurrent forking and cancelation

  • Concurrent: concurrent coordination

  • Sync: safely suspend side-effects

  • and more

Cats Effect

Data types:

  • IO: safely represent and compose side-effects

  • Resource: safe lifecycle management of state

  • Fiber: handle to concurrently executing effects

  • Ref: atomically updated state

  • Deferred: blocking data synchronization

  • Semaphore: limit concurrent access

  • Queue: concurrent FIFO

  • and more

Cats Effect: effect parallelism

val hello = IO.println("hello")
val world = IO.println("world")

(hello, world).tupled

hello
world

Cats Effect: effect parallelism

val hello = IO.println("hello")
val world = IO.println("world")

- (hello, world).tupled
+ (hello, world).parTupled

Parallel execution (parMapN, parTupled, etc.)

hello
world

or

world
hello

fs2

fs2

fs2

[.grey]##

Cats Effect

effects, concurrency, resources, …​

Cats

sequencing, …​

http4s

http4s logo

http4s

[.grey]##

fs2

streaming requests, responses

Cats Effect

effects, concurrency, resources, …​

Cats

sequencing, …​

Doobie

doobie

doobie

[.small.grey]##

fs2

streaming queries, results

Cats Effect

effects, concurrency, resources, …​

Cats

sequencing, …​

Doobie: composing queries

val qi: ConnectionIO[Int] = ???
val qd: ConnectionIO[Double] = ???

val both: ConnectionIO[(Int, Double)] =
  for {
    i <- qi
    d <- qd
  } yield (i, d)

Sequential composition with monad (flatMap)

Doobie: composing queries

val qi: ConnectionIO[Int] = ???
val qd: ConnectionIO[Double] = ???

val both: ConnectionIO[(Int, Double)] =
- for {
-   i <- qi
-   d <- qd
- } yield (i, d)
+ (qi, qd).tupled

Independent composition with applicative (mapN, tupled, etc.)

Why the Typelevel ecosystem works

“A complex system that works is invariably found to have evolved from a simple system that worked. A complex system designed from scratch never works and cannot be patched up to make it work. You have to start over, beginning with a working simple system.”

Why?

framework

A product with the business logic removed, but all of the assumptions left in.

  1. [.grey]#

  2. [.grey]#

Libraries > frameworks

remove assumptions

no assumptions

  • How much effort is it to add a new library?

  • What existing code do you need to change?

  • How well do they work together? (friction)

Anti-pattern: Introducing a library that has multiplicative (exponential?) integration costs, because it requires high coupling.

Libraries > frameworks

Claim: Using Typelevel libraries have (only!) additive costs.

Because of: composability, parametricity, lawfulness, closure, …​

?

Typelevel adoption and integration

Typelevel adoption and integration

Education

scala with cats essential effects pfp scala

Typelevel adoption and integration

Community
  • Discord

  • GitHub

  • meetups

  • conferences

  • streamers

Typelevel adoption and integration

Support
  • community-led

  • for-hire

  • tooling

Most common scenario
  • Using Future, want to gain safety and reasonability via effect types like IO.

Divide and conquer with Cats Effect.

Scala Steward

scala steward logo

A bot that helps you keep your Scala projects up-to-date

OMG do you know about Scala Steward??!

scala steward prs

Summary and next steps

Summary

unix

The abstractions of Cats, etc., are:

  • composable;

  • closed; and

  • have no side-effects.

With Cats Effect even side-effecting code can be made safe.

The Typelevel layers are orthogonal to your domain.

Thank you!

To learn more

Adam Rosien @arosien

Hire us to help with your projects, or train your staff!

inner product logo with url 320