FP Module Projects - Engineering Challenges
Level: Intermediate → Engineering | Format: Build, not follow
These are not exercises. They are not walkthroughs. They are project specifications.
You receive a requirements document, a starter skeleton, and expected outputs. You build the implementation. The same way you would at work.
Each project is designed so that the functional programming concepts from the module are not optional - they are structurally required. You cannot complete Project 01 without deeply understanding closures and functools.wraps. You cannot complete Project 02 without generator chaining. You cannot complete Project 03 without pure functions and function composition. The projects force the concepts into place through real engineering constraints.
How to Approach These Projects
Read the full spec before writing a line of code. The requirements are ordered for comprehension, not for implementation. For functional projects especially, the design decisions - which functions are pure, which carry state, how composition is threaded - must be resolved before implementation begins.
Sketch the data flow first. In OOP you sketch a class diagram. In functional programming you sketch a data flow diagram: what goes in, what transformation happens, what comes out at each stage. This is the equivalent design artifact.
Build incrementally and test as you go. Implement one function at a time. Because these functions are mostly pure, testing is unusually simple - no mocks required. Call the function, check the output, move on.
The hints section exists for when you are genuinely stuck - not as a first resort. Try to work through the problem for at least 20 minutes before reading a hint.
Extension challenges are serious. If you complete the core requirements quickly, the extensions will push you into territory that covers the next two lessons.
The Three Projects
Project 01 - Custom Decorator Library
Core FP concepts tested: Closures, functools.wraps, inspect.signature, higher-order functions, decorator factories, composability.
You build a production-quality decorator library containing five decorators: @retry with exponential backoff, @rate_limit using a token bucket, @timeout using threading, @validate for argument type checking, and @log_calls with structured timing output. Each decorator preserves the wrapped function's signature and metadata. All five are composable - you can stack them freely. This is the entry point - if you have never written a decorator that takes arguments, start here.
Estimated time: 4–6 hours for core requirements.
Project 02 - Lazy Evaluation Pipeline
Core FP concepts tested: Generators, generator chaining, lazy evaluation, immutability, higher-order functions, memory-efficient streaming.
You build a lazy data processing pipeline capable of handling datasets larger than available RAM. The pipeline supports filter, map, group_by, aggregate, and limit operations, each returning a new Pipeline object. No data is loaded or processed until the pipeline is iterated. Internally, every operation is implemented as a generator. The project forces you to understand the difference between operations that can be fully lazy (filter, map) and operations that require buffering (group_by), and to document that tradeoff explicitly.
Estimated time: 5–8 hours for core requirements.
Project 03 - Functional Data Processor
Core FP concepts tested: Function composition, pipe, partial, pure functions, functools.singledispatch, the Result monad pattern, operator module.
You build a functional-style data transformation system where raw input flows through a composed pipeline of pure transformation functions. A compose function chains functions right-to-left; a pipe function chains them left-to-right. Error handling avoids exceptions - instead, functions return Ok or Err result types, keeping the composition chain intact even when individual steps fail. functools.singledispatch handles type-based dispatch in serialization and parsing. Because all functions are pure, the test suite requires no mocks - same input always produces same output.
Estimated time: 5–7 hours for core requirements.
Skills Map
| Concept | Project 01 | Project 02 | Project 03 |
|---|---|---|---|
| Closures | Yes | Yes | Yes |
functools.wraps | Yes | ||
functools.partial | Yes | ||
functools.singledispatch | Yes | ||
| Higher-order functions | Yes | Yes | Yes |
| Decorator factories | Yes | ||
inspect.signature | Yes | ||
| Generators | Yes | ||
| Generator chaining | Yes | ||
| Lazy evaluation | Yes | ||
| Immutable pipelines | Yes | ||
| Function composition | Yes | ||
| Pure functions | Yes | ||
| Result / Either pattern | Yes | ||
operator module | Yes |
Setup
All projects are self-contained. No third-party libraries required beyond the Python standard library.
# Create a working directory
mkdir fp-projects
cd fp-projects
# Run your implementation with
python decorator_library.py
python lazy_pipeline.py
python functional_processor.py
Python 3.10 or later is assumed. functools.singledispatch, inspect.signature, and threading.Timer are all standard library. No external dependencies.
What Good Looks Like
A complete submission for any of these projects satisfies four criteria:
- All expected outputs match exactly - the sample outputs in each spec are exact. Your implementation must reproduce them.
- Functions are pure where the spec requires purity - a pure function produces the same output for the same input and has no side effects. If a function is marked pure, it must not mutate its arguments, read global state, or produce output.
- FP structure is not decorative - generators are used because laziness is required, not because generators look clever. Composition is used because the pipeline shape demands it. Decorators are used because cross-cutting concerns belong in decorators.
- The code reads like a data transformation - someone reading your pipeline or composition chain should understand what transformations happen to the data without reading comments.
These are the same criteria a senior engineer would apply in a code review.
