Functional Programming Fundamentals in Kotlin with Arrow
In this intensive course, we’ll cover Functional Programming essentials in Kotlin over four days / 16-hrs total. By the end of this course, you will have a solid grasp on the course concepts.
Course Dates:
- Monday, September 20th - 14:00 - 18:00 UTC
- Tuesday, September 21st - 14:00 - 18:00 UTC
- Wednesday, September 22nd - 14:00 - 18:00 UTC
- Thursday, September 23rd - 14:00 - 18:00 UTC
Course content
Lesson 1: Functional Programming
Functional programming fundamentals.
- What is it, what is it good for.
- Pure functions.
- Side effects.
- Referential transparency & substitution model.
- Local reasoning.
- Is Kotlin a functional language?
- Higher order functions.
- Deferring execution.
- Exercises.
Lesson 2: Domain Modeling
Modeling our domain from a functional perspective.
- Kotlin type system. Leveraging compiler aid via types.
- Modeling concerns and making them explicit with types.
- Unit and Nothing to model meaningful scenarios.
- Inline classes for type safety and preciseness.
- Algebraic Data Types: Product and Sum types.
- Complexity of ADTs.
- Modeling choice and control flow with sum types.
- Arrow data types as ADTs.
- Eliminating bugs and tests for invariants via type safety.
- Exercises.
Lesson 3: Immutable Data and Optics
Optimizing reusability and composition for immutable data structures using Optics.
- Immutability.
- Issues with Kotlin data class
copy
. - Optics for working efficiently with nested immutable data.
- Optics composition and reusability.
- The Optics DSL.
- Stacking optics to create more powerful ones 🔭
Lens
for reading / modifying nested data.Prism
for conditional reading / modification.Optional
as the composition of Lens and Prism.Every
for working over lists of elements.FilterIndex
for working over lists of elements based on a predicate.Index
for reading or modifying elements obtained by their index.Iso
for isomorphic conversions.- Exercises.
Lesson 4: Domain Modeling II - Error Handling
Learning how to model and handle errors in functional programs.
- Railway oriented programming 🚂 - Happy path vs alternative path.
- Making errors vs success explicit with types.
- The
Either
datatype. - Exhaustive evaluation.
Either
composition and computational blocks (bindings).Either
bias towards the happy case.- Capturing third party library errors.
- Mapping third party errors to strongly typed domain errors.
- Error accumulation.
Validated
andValidatedNel
.Either
andValidated
, when to use each? Fail fast vs error accumulation.Either
andValidated
interoperability.- Flattening lists of
Either
orValidated
. Either
orValidated
for domain model validation.- Modeling potential absence of a value.
- Exercises.
Lesson 5: Functional Effects
Keeping side effects under control.
- Recap on side effects.
Suspend
for tracking effects at compile time.- The benefits of modeling effects with
suspend
. - Making effect declaration pure.
- Concern separation - pure logics vs runtime.
- Internals of
suspend
- Continuation passing style. - The impact of
suspend
in architecture. - Leveraging
Either
andValidated
in suspended contexts. - Arrow integration with KotlinX Coroutines.
- Structured concurrency & cancellation via KotlinX Coroutines.
- Providing a runtime for our suspended program.
- Functional effect operators via Arrow Fx.
- Parallel computations, races, repeating and retrying suspended effects.
- Handling errors in suspended contexts.
- Exercises.
Lesson 6: Safe Resource Handling
Functional operators to work safely with resources across boundaries.
- What is a resource?
- The issues of working with resources in concurrent contexts.
- Why
try / catch
is not enough. - Acquiring, using, and releasing a resource.
- Abstraction as a means to leverage composability.
- Ensuring resource disposal to avoid leaks.
bracket
andbracketCase
operators.guarantee
andguaranteeCase
operators.- Limitations of
bracket
andbracketCase
. Resource
data type.Resource
andbracket
to work with third party libraries.- Exercises.
Lesson 7: Functional Streams
Streams able to embed and evaluate functional effects.
- The need for streams.
- The need for
suspend
support in streams. - Streams in Kotlin via
Flow
data type. - Modeling functional effects within a
Flow
. Flow
s are cold.- Consuming functional streams safely -
suspend
terminal operators. Flow
integration with Arrow Fx operators.- Cancellation of streams with functional effects via structured concurrency.
- Sneak peek into
Flow
builders and operators. - Composing
Flow
s together. - Error path vs happy path in the context of a
Flow
. - Retrying
Flows
. - Exercises.
Lesson 8: Functional Architecture
How to organize and structure functional programs.
- Concern separation from an architecture perspective.
- Keeping architecture pure edge to edge.
- The concept of algebras.
- Isolating side effects, pushing them to the edges.
- Dependency injection in functional codebases.
- Replacing side effects with test doubles.
- The importance of pure functions and determinism for testing.
- The importance of a precise self validated domain for testing.
- Removing tests for invariants with proper types.
- Testing functional codebases.
- Sneak peek into Property Based Testing (PBT) with Kotest.
- Generating input data for our tests.
- Failure shrinking to track down failing cases.
- Detecting edge cases thanks to PBT.
- Exercises.