Getting Started
This section explains how to approach and work with the exercises in the Programming Task Library.
The library contains two main types of exercises:
- Algorithms — focused problems with defined inputs, processing requirements, and expected outputs.
- Modeling — larger scenarios focused on data modeling, relationships, behavior, validation, and system design.
The tasks were originally designed for Go and Rust, but most exercises can be implemented in other programming languages as well.
Before You Start
Do not begin by immediately writing code.
First, analyze the task and make sure you understand:
- What data is provided as input?
- What result is expected?
- What conditions must be satisfied?
- What edge cases may exist?
- What validation is required?
- Are there restrictions on the implementation?
- Can the problem be divided into smaller operations?
For more complex tasks, especially modeling exercises, draw the relationships, execution flow, or possible outcomes before starting the implementation.
The goal is to understand the problem before choosing the solution.
Solving Algorithm Tasks
Algorithm tasks usually define:
- input data
- one or more function arguments
- processing rules
- expected return values
- example cases
- implementation constraints
Read the complete task before implementing the function.
Some requirements may depend on several conditions at the same time.
When examples are provided, use them to understand the expected behavior of the implementation.
Function Signatures
Function names and signatures shown in the tasks should be treated as part of the exercise when they are explicitly specified.
For example:
FindAllGreaterThen(data, 4.8)
or:
CreateGroups(list, 30, 90, 40, 70)
The exact type definitions and signatures will be shown on individual task pages when they are part of the original task specification.
Solving Modeling Tasks
Modeling tasks are intentionally broader than algorithm tasks.
Instead of implementing only a single function, you may need to design multiple structures and define relationships between them.
Before implementing a modeling task, identify the main entities in the scenario.
Then determine:
- what data belongs to each entity
- how entities are related
- what operations are required
- what validation rules exist
- what information must be searchable or queryable
- how data should be loaded, stored, or transformed
Do not create the complete model immediately.
Start with the domain and relationships, then build the implementation around them.
Validation and Error Handling
When a task explicitly requires validation or error handling, those requirements are part of the exercise and should not be ignored.
Consider situations such as:
- invalid input values
- malformed data
- failed type conversions
- missing values
- unsupported operators or options
- invalid ranges
- inconsistent input collections
The exact validation requirements depend on the individual task.
Do not assume additional restrictions unless they are stated or logically required by the task.
Expected Results
Many tasks provide one or more example inputs together with an expected result.
For example:
Input:
data = [[3.2, 5.4], [6.3, 1.4], [2.5, 6.5]]
threshold = 4.8
Expected Result:
[
{5.4, 1, 2},
{6.3, 2, 1},
{6.5, 3, 2}
]
Your implementation should produce behavior consistent with the examples and requirements described by the task.
Examples should be treated as reference cases, not as the only possible inputs.
Implementation Restrictions
Always check whether a task or an entire group defines additional implementation restrictions.
Some exercises intentionally remove convenient language features in order to practice implementing the underlying algorithm manually.
For example, Algorithm Group 5 prohibits the use of built-in functions from the language core.
Such restrictions are part of the exercise.
Performance and Resource Usage
A correct result does not automatically mean that an implementation is efficient.
When solving a task, consider:
- time complexity
- memory usage
- unnecessary allocations
- repeated iterations
- unnecessary data copies
- appropriate data structures
- opportunities to simplify processing
You do not always need the theoretically fastest possible implementation.
The objective is to understand the trade-offs and avoid unnecessary work.
Testing
Use the examples provided by each task as initial test cases.
When appropriate, also test additional cases that may expose problems in the implementation.
Depending on the task, these may include:
- empty inputs
- boundary values
- duplicate values
- invalid values
- values outside expected ranges
- single-element collections
- large inputs
For modeling tasks, testing may also include validation of relationships, queries, state changes, and data-loading behavior.
If a task explicitly defines testing requirements, those requirements take priority.
Language Choice
Go, Rust and C++ are the primary languages associated with this library.
You are free to solve the exercises using either language.
Unless a task explicitly depends on a particular language feature, another programming language may also be used.
The important part is preserving the behavior and constraints defined by the task.
Recommended Workflow
A practical workflow for each exercise is:
Read
↓
Analyze
↓
Model the problem
↓
Identify edge cases
↓
Choose an approach
↓
Implement
↓
Test
↓
Review
After the implementation works, review it again.
Ask whether the solution can be made simpler, clearer, more efficient, or more reusable without unnecessarily increasing its complexity.
The purpose of the library is not only to complete the exercises.
The purpose is to practice the engineering process used to arrive at a good solution.