2 releases
0.1.1 | Nov 8, 2023 |
---|---|
0.1.0 | Nov 8, 2023 |
#2 in #scoreboard
1MB
637 lines
Contains (WOFF font, 400KB) NanumBarunGothic-0f09457c7a19b7c6.ttf.woff2, (WOFF font, 135KB) FiraSans-Medium-8f9a781e4970d388.woff2, (WOFF font, 130KB) FiraSans-Regular-018c141bf0843ffd.woff2, (WOFF font, 82KB) SourceSerif4-Bold-a2c9cd1067f8b328.ttf.woff2, (WOFF font, 77KB) SourceSerif4-Regular-46f98efaafac5295.ttf.woff2, (WOFF font, 45KB) SourceCodePro-It-1cc31594bf4f1f79.ttf.woff2 and 3 more.
Scoreboard
Coding exercise
Develop a new live World Cup scorebard library that shows all the ongoing matches and their scores
Requirements
- Must be a library implementation
- Use in-memory store solution
- Use TDD, pay attention to OO design, Clean Code and SOLID
- Implement basic API:
- Start a match. Assuming initial score "0-0", should capture two parameters: home team and away team
- Update score. Should receive a pair of absolute scores: home team score and away team score
- Finish match. Remove a match currently in progress from the scoreboard
- Get a summary. Returns all the current matches ordered by total score, even total scores are ordered by most recent start
Assumptions
- No specific programming language is expected. For learning purposes, this project will use Rust
- There is no mention of thread safety. It's assumed to be a "nice to have" feature
- A team can be playing a single match only at a given time. For example, if there is a currently an ongoing match between Honduras and Costarica, neither of those two teams can be present in a newly created match
- In all the API calls, "home" team always comes before "away" team. If the order of the teams is wrong for an operation, it returns an error
- Getting a summary of the current results will be much more frequently used than all the other API functions combined. This will impact optimization choices
Progress
Base requirements
Requirement | Status | Comments |
---|---|---|
1. Library | Devloped as an independant Rust library crate | |
2. Storage | Using standard Vec vector collection. See "Possible additional features -> Optimization" below for more comments on this |
|
3. TDD | TDD followed to a degree. Most functions are so small it was possible to write the final correct version for the first test and then add the other corner cases | |
4. API | Public ScoreBoard struct and its methods |
|
4.1. Start | ScoreBoard.start_game(home_team_name, away_team_name) |
|
4.2. Update | ScoreBoard.update_score(home_team_name, home_score, away_team_name, away_score) |
|
4.3. Finish | ScoreBoard.finish_game(home_team_name, away_team_name) |
|
4.4. Summary | ScoreBoard.get_summary() |
Extra features
Features | Status | Comments |
---|---|---|
Team uniqueness | start_game(team1, team2) rejects the request if any of the teams is already playing a match |
|
Thread safety | Rust compiler provides thread safety, unless serious hacks get involved. There is no unsafe code in this repository |
Documentation
The project is documented with code annotations
Manually generated
Run this command to generate documentation and open it:
cargo doc --open
Online
The generated documentation is available on GitHub Pages under daydreamest.github.io or on crates.io
Installation and usage
Installation
- Install Rust work environment. Use the standard Rust installation guide with all the default options
- This should also install Cargo, Rust default package manager
- Clone this repository
Compilation
Move to the "scoreboard" directory and run:
> cargo build --release
On the first execution Cargo will download dependencies (ex. the logging crate). After that, the library will be compiled to a binary:
scoreboard/target/release/libscoreboard.rlib
Usage
As Rust source code
Copy the scoreboard.rs
file to your project and include the module anywhere you need it with:
use scoreboard::*;
As compiled Rust library with rustc compiler
Copy compiled libscoreboard.rlib
file to your project and add a flag to your compilation options:
rustc main.rs --extern scoreboard=libscoreboard.rlib
As cargo library
Add the following line in Cargo.toml
file under [dependencies]
:
scoreboard_world_cup = "0.1.1"
Testing
To run tests move to the "scoreboard" directory and run:
> cargo test
Possible additional features
API
- Team names are kept internally as UTF-8 strings and not verified extensively. This allows for matches like "AAAA - jskdfhgidsf", "USA - U.S.A." or any other two distinct string names. A good improvement would be to create an enum or a dictionary that keeps a list of all available names and verify against it
update_score()
is very unwieldy and allows to change the score arbitrarily. In footbal the score changes come in quanta (commonly known as "goals"), so there should be a methodadd_goal(team_name)
that adds 1 to the score of the mentioned team
Optimization
- Time stamps are used to verify which match started first. This may be an overkill, but it's cleaner and easier than implementing internal counters, at the cost of being less efficient on the CPU
Vec
is used as a data container. There are others collections available, but even the Rust guide suggests sticking to the good, reliable vector. Alternatives could be considered to improve efficiency, but they would need profiling and real world usage of the library- Data is sorted after each addition, score change and removal. The sorting could be moved to the summary display method, so it would "happen" only once in the code, but this has disadvantages:
get_summary()
method would have to be mutable and change the state of the score board, which is a bad design- alternativlety,
get_summary()
could make a copy of the data an sort it locally before returning, but this adds unnecessary memory usage get_summary()
is expected to be called much more often than all the other API functions combined, so it has to be quick and simple. Adding sorting to it can have serious time impact for a large number of concurrent matches- Current implementation of
sort()
does extremely well with collections that are partly sorted or have stretches of sorted elements (source). As such, it should have little impact on the functions that use it now, as their changes apply to single matches and leave the rest of the collection sorted
- Alternatives to
Vec
andpush()
could be considered that might allow to skip sorting in some cases. A newly created match has the lowes possible total score and the freshest timestamp, so sorting onstart_game()
could be probably omitted, but this requires more analysis
Issues
- "match" is a keyword in Rust, so the word "game" is used throughout the code in the meaning of "a match between two teams"