Develop a new live World Cup scorebard library that shows all the ongoing matches and their scores
- 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
- 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
The project is documented with code annotations
Run this command to generate documentation and open it:
cargo doc --open
The generated documentation is available on GitHub Pages under daydreamest.github.io or on crates.io
- 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
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
Copy the scoreboard.rs
file to your project and include the module anywhere you need it with:
use scoreboard::*;
Copy compiled libscoreboard.rlib
file to your project and add a flag to your compilation options:
rustc main.rs --extern scoreboard=libscoreboard.rlib
Add the following line in Cargo.toml
file under [dependencies]
:
scoreboard_world_cup = "0.1.1"
To run tests move to the "scoreboard" directory and run:
> cargo test
There are a total of 39 unit/module tests and 4 documentation tests
- 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
- 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
- "match" is a keyword in Rust, so the word "game" is used throughout the code in the meaning of "a match between two teams"