https://github.com/kiquetal/fsharp-workout
Hands-on F# training — 6 hyperfocus sessions covering type-driven design, pipelines, pattern matching, domain modeling, async, and integration
https://github.com/kiquetal/fsharp-workout
domain-modeling dotnet fsharp functional-programming hyperfocus-training type-driven-design
Last synced: 8 days ago
JSON representation
Hands-on F# training — 6 hyperfocus sessions covering type-driven design, pipelines, pattern matching, domain modeling, async, and integration
- Host: GitHub
- URL: https://github.com/kiquetal/fsharp-workout
- Owner: kiquetal
- Created: 2026-03-29T00:43:49.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-05-26T15:07:13.000Z (26 days ago)
- Last Synced: 2026-05-26T17:09:19.638Z (26 days ago)
- Topics: domain-modeling, dotnet, fsharp, functional-programming, hyperfocus-training, type-driven-design
- Language: F#
- Homepage:
- Size: 158 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# F# Hyperfocus Training
A structured, hands-on F# training program designed for deep-focus sessions. Each session is **90 minutes max** — short enough to stay in flow, long enough to build something real.
## Philosophy
- **Type-first thinking** — design with types before writing logic
- **Learn by building** — every session produces working code
- **Progressive complexity** — each session builds on the previous one
- **No fluff** — pure practice, no slides
## Schedule
| # | Session | Focus | Duration | Status |
|---|---------|-------|----------|--------|
| 1 | **Types as Design** | Records, DUs, single-case wrappers, making illegal states unrepresentable | 90 min | ✅ Done |
| 2 | **Pipelines & Composition** | `\|>`, `>>`, `Option`, `Result`, railway-oriented error handling | 90 min | ✅ Done |
| 3 | **Pattern Matching & Recursion** | Exhaustive matching, active patterns, recursive data structures | 90 min | ✅ Done |
| 4 | **Modules & Domain Modeling** | Module design, encapsulation, a small bounded context end-to-end | 90 min | ✅ Done |
| 5 | **Collections & Pipelines** | `List.map`, `List.groupBy`, `List.collect`, pipeline composition with `\|>` and `>>` | 90 min | ✅ Done |
| 6 | **Integration & Capstone** | JSON serialization, HTTP, CLI app — tie everything together | 90 min | ✅ Done |
## Part II — State Machines & Data Transformation
| # | Session | What you build | Key concept |
|---|---------|---------------|-------------|
| 7 | **Explicit State Machines** | A deployment pipeline (Pending → Building → Testing → Deployed / Failed) | DUs as states, transition functions that only accept valid moves |
| 8 | **Event Sourcing from Scratch** | An order lifecycle — rebuild current state by replaying events | Events as DUs, state = fold over event list |
| 9 | **Parsing & Transformation** | A log file parser — raw text → structured records → summary report | Active patterns, `Result` chains, pipeline composition |
| 10 | **Recursive Data Structures** | A file system tree or config hierarchy — traverse, transform, flatten | Trees as recursive DUs, catamorphisms (folds over trees) |
| 11 | **Workflow Engine** | A multi-step approval process with branching and rollback | Combining state machines + event sourcing |
| 12 | **Capstone: Infrastructure DSL** | A small DSL that describes infrastructure and validates it at compile time | Computation expressions, type-safe builders |
### Progression
- **Session 7** teaches the raw pattern — a state machine is just a function `State → Event → State`
- **Session 8** shows that storing events gives you time travel for free (replay, audit, debugging)
- **Sessions 9–10** build transformation muscles — taking messy data and shaping it
- **Session 11** combines both skills into something real
- **Session 12** ties it to systems engineering — building a tiny infrastructure DSL (think mini Pulumi/Terraform in F#)
### Where Temporal fits in
After building state machines by hand (Sessions 7–8), you'll understand what tools like [Temporal](https://temporal.io) abstract away:
- **F# state machines** = the logic (which transitions are valid, compile-time safety)
- **Temporal** = the runtime (durable execution, retries, surviving crashes across distributed services)
## Sessions
### Session 1 — Types as Design ✅
**Objective:** Encode domain rules in the type system so invalid states can't exist.
**What you learned:**
- Records for data, discriminated unions for choices
- Single-case DUs with `private` as domain primitives (`Quantity`, `OrderNumber`)
- Smart constructors — validate once at the boundary, trust the types after
- `Result<'T, 'E>` for expected failures instead of exceptions
- Units of measure for compile-time dimensional safety
→ [Full details](docs/session01.md)
### Session 2 — Pipelines & Composition ✅
**Objective:** Chain fallible operations cleanly, accumulate errors, and compose processing pipelines.
**What you learned:**
- `bind`, `map2`, `apply` — the Result combinators that replace nested matching
- Applicative validation — collect ALL errors instead of stopping at the first
- Active patterns — custom decompositions for readable `match` expressions
- Pipeline composition with `|>` from validation through pricing
- Batch processing — partition successes and failures across a list
→ [Full details](docs/session02.md)
### Session 3 — Pattern Matching & Recursion ✅
**Objective:** Exhaustive matching, recursive data structures, and generic folds.
**What you learned:**
- Recursive DU types (`Expr` — a type that references itself)
- Structural recursion — one match branch per DU case
- `evaluate` with `Result.bind` for railway-oriented recursion
- `format` for recursive pretty-printing
- `simplify` for tree transformation (algebraic rules)
- Generic `fold` (catamorphism) — extracting the common recursion pattern
- Factory worker analogy — each branch node combines finished results from below
→ [Full details](docs/session03.md)
### Session 4 — Modules & Domain Modeling ✅
**Objective:** Organize domain logic into modules with clear boundaries.
**What you learned:**
- Module design — group related functions, each module validates what it owns
- `Book` module — status transitions (Available ↔ CheckedOut)
- `Member` module — borrow limits, duplicate checks
- `Library` module — orchestration, calling Book + Member and combining results
- Record updates with `{ x with ... }` — immutable state transitions
- `Map` as in-memory storage — `tryFind`, `add`, `filter`, `values`
- Query functions — `availableBooks`, `booksBorrowedBy`
- Domain vs storage separation — domain stays pure, repository translates
→ [Full details](docs/session04.md)
### Session 5 — Collections & Pipelines ✅
**Objective:** Master F#'s collection functions and pipeline composition.
**What you learned:**
- `List.map`, `List.filter`, `List.sumBy` — basic transformations
- `List.collect` — flatMap for F#, use when your lambda returns a list
- `List.groupBy` — group items by key, returns `(key * items) list`
- `List.sortByDescending`, `List.truncate` — ranking and limiting
- `List.choose` — map + filter in one step using `Option`
- `snd` / `fst` — extract tuple elements
- `>>` composition — build reusable pipelines without data
- `|>` vs `>>` — "run now" vs "save for later"
→ [Full details](docs/session05.md)
### Session 6 — Integration & Capstone ✅
**Objective:** Tie together everything from Sessions 1–5 into one cohesive CLI application.
**What you built:**
- Weather Station Dashboard — parse, validate, analyze, report
- `Parsing` module — safe string parsing with `TryParse`, `parseAll` with partition
- `Validation` module — business rules on top of smart constructors
- `Analytics` module — `averageBy`, `groupBy`, `minBy`/`maxBy`, daily aggregates
- `Report` module — formatted output, per-station summaries, error reporting
- Smart constructors with `private` DUs for `Temperature` and `Humidity`
- Full pipeline: raw strings → typed data → validated data → analytics → report
→ [Full details](docs/session06.md)
## Session Format
Each 90-minute session follows this rhythm:
```
[0:00 - 0:10] Concept intro — read the brief, understand the types
[0:10 - 0:60] Build — implement the exercise, iterate
[0:60 - 0:80] Stretch goal — extend or refactor
[0:80 - 0:90] Review — reflect, commit, note what clicked
```
## Project Structure
```
src/
Session01/ ← Types as Design
Session02/ ← Pipelines & Composition
Session03/ ← Pattern Matching & Recursion
Session04/ ← Modules & Domain Modeling
Session05/ ← Collections & Pipelines
Session06/ ← Integration & Capstone
docs/
session01.md ← Full session 1 details, exercises, concepts
session02.md ← Full session 2 details, exercises, concepts
session03.md ← Full session 3 details, exercises, concepts
session04.md ← Full session 4 details, exercises, concepts
session05.md ← Full session 5 details, exercises, concepts
session06.md ← Full session 6 details, exercises, concepts
patterns.md ← Railway-oriented programming, parse don't validate
java21-functional.md ← F# patterns translated to Java 21+
learning-notes.md ← Validation boundaries, complex types, Result.sequence
tests/ ← Test projects (optional, on demand)
```
## Getting Started
```bash
# Build all projects
dotnet build
# Run a specific session
dotnet run --project src/Session01
# Run with watch (auto-reload on save)
dotnet watch run --project src/Session01
# Build and run the full solution
dotnet build FSharpWorkout.sln
```
## Rules for Yourself
1. **No mutable variables** — if you reach for `mutable`, rethink
2. **No exceptions for expected failures** — use `Result`
3. **Types before functions** — define the domain types first, then the transformations
4. **Commit after each session** — track your progress
## Reference Docs
- [Patterns worth studying](docs/patterns.md) — railway-oriented programming, making illegal states unrepresentable, parse don't validate
- [F# → Java 21+ translation](docs/java21-functional.md) — map/flatMap, sealed interfaces, smart constructors, Stream pipelines
- [Learning notes](docs/learning-notes.md) — validation boundaries, complex types example, Result.sequence vs validation