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.
- 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
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.
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.
Lesson 3: Immutable Data and Optics
Optimizing reusability and composition for immutable data structures using Optics.
- Issues with Kotlin data class
- Optics for working efficiently with nested immutable data.
- Optics composition and reusability.
- The Optics DSL.
- Stacking optics to create more powerful ones 🔭
Lensfor reading / modifying nested data.
Prismfor conditional reading / modification.
Optionalas the composition of Lens and Prism.
Everyfor working over lists of elements.
FilterIndexfor working over lists of elements based on a predicate.
Indexfor reading or modifying elements obtained by their index.
Isofor isomorphic conversions.
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.
- Exhaustive evaluation.
Eithercomposition and computational blocks (bindings).
Eitherbias towards the happy case.
- Capturing third party library errors.
- Mapping third party errors to strongly typed domain errors.
- Error accumulation.
Validated, when to use each? Fail fast vs error accumulation.
- Flattening lists of
Validatedfor domain model validation.
- Modeling potential absence of a value.
Lesson 5: Functional Effects
Keeping side effects under control.
- Recap on side effects.
Suspendfor tracking effects at compile time.
- The benefits of modeling effects with
- Making effect declaration pure.
- Concern separation - pure logics vs runtime.
- Internals of
suspend- Continuation passing style.
- The impact of
Validatedin 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.
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.
try / catchis not enough.
- Acquiring, using, and releasing a resource.
- Abstraction as a means to leverage composability.
- Ensuring resource disposal to avoid leaks.
- Limitations of
bracketto work with third party libraries.
Lesson 7: Functional Streams
Streams able to embed and evaluate functional effects.
- The need for streams.
- The need for
suspendsupport in streams.
- Streams in Kotlin via
- Modeling functional effects within a
Flows are cold.
- Consuming functional streams safely -
Flowintegration with Arrow Fx operators.
- Cancellation of streams with functional effects via structured concurrency.
- Sneak peek into
Flowbuilders and operators.
- Error path vs happy path in the context of a
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.