Football Scoreboard is a .NET 8 class library developed as part of a coding exercise for a job interview. It provides functionalities to manage live football games, including tracking scores, starting and finishing games, and retrieving a summary of ongoing games.
The coding exercise instructions are documented in docs/Exercise.md
file.
This is version (v2.0.0)
, which builds upon the MVP version (v1.0.0).
The MVP focused on meeting the core requirements of the coding exercise and
is available in the v1.0.0
tag. The current version enhances the design by:
- General Refactoring
- Implementing the Repository Pattern and Strategy Pattern for flexibility and scalability.
- Adding comprehensive XML documentation for improved usability.
- Improving test coverage with additional unit, integration, and functional tests.
- Game Lifecycle Management: Start and finish football games.
- Live Score Updates: Update scores for ongoing games.
- Game Summaries: Retrieve a summary of games, sorted by total score and start time.
- Clean Architecture:
- Repository Pattern for abstracting data storage.
- Strategy Pattern for flexible sorting of game summaries.
- Testability: Fully tested using Unit, Integration, and Functional tests.
- Clone the repository:
To use the MVP version (v1.0.0), checkout the corresponding tag:
git clone https://github.com/LuisOreOri/football-scoreboard.git
git checkout tags/v1.0.0
- Open the
FootballScoreBoard.sln
solution in Visual Studio 2022. - Ensure you have the .NET 8 SDK installed.
- Build the solution to restore dependencies.
The ScoreBoard class provides multiple constructors to accommodate different use cases. Here are the available options:
- Description: Uses
InMemoryGameRepository
for in-memory storage andDefaultGameSortingStrategy
for sorting. - Example:
var scoreboard = new ScoreBoard();
- Description: Allows you to provide a custom implementation of
IGameRepository
. The default sorting strategy (DefaultGameSortingStrategy
) is used.
var customRepository = new CustomGameRepository(); // Implement your own repository
var scoreboard = new ScoreBoard(customRepository);
- Description: Allows you to provide a custom implementation of
IGameSortingStrategy
. The default repository (InMemoryGameRepository
) is used. - Example:
var customSortingStrategy = new CustomSortingStrategy(); // Implement your own sorting logic
var scoreboard = new ScoreBoard(customSortingStrategy);
- Description: Allows you to provide both a custom
IGameRepository
and a customIGameSortingStrategy
for maximum flexibility. - Example:
var customRepository = new CustomGameRepository();
var customSortingStrategy = new CustomSortingStrategy();
var scoreboard = new ScoreBoard(customRepository, customSortingStrategy);
To start a game, create an instance of the ScoreBoard
class and call StartGame
:
var scoreboard = new ScoreBoard();
var game = new Game("Team A", "Team B");
scoreboard.StartGame(game);
Update the scores for an ongoing game:
scoreboard.UpdateScore(game, 3, 2); // Team A: 3, Team B: 2
Get a sorted summary of games:
var summary = scoreboard.GetSummary();
foreach (var game in summary)
{
Console.WriteLine($"{game.HomeTeam} {game.HomeScore} - {game.AwayTeam} {game.AwayScore}");
}
Remove a game from the scoreboard:
scoreboard.FinishGame(game);
The project includes a comprehensive set of tests:
- Unit Tests:
- Validates individual components:
Game
,ScoreBoard
,InMemoryGameRepository
, andDefaultGameSortingStrategy
.
- Validates individual components:
- Integration Tests:
- Ensures interaction between components, such as
ScoreBoard
andInMemoryGameRepository
.
- Ensures interaction between components, such as
- Functional Tests:
- Simulates real-world scenarios, like retrieving game summaries.
Run all tests using the following command:
dotnet test
-
Test-Driven Development (TDD):
- Implemented functionality incrementally, guided by comprehensive unit tests.
-
Clean Code:
- Followed SOLID principles for better maintainability and scalability.
- Ensured adherence to KISS (Keep It Simple, Stupid) and YAGNI (You Arenβt Gonna Need It) principles.
-
Repository Pattern:
- Abstracted data storage for flexibility and scalability.
-
Strategy Pattern:
- Used for sorting game summaries, allowing easy extension for alternative sorting rules.
- Used Dictionary<string, IGame> in the repository for optimal lookups by game ID, ensuring:
- O(1) complexity for adding, retrieving, and removing games.
- Efficient operations suitable for handling large datasets.
v1.0.0
: Initial MVP implementation, available as a Git tag.v2.0.0
: Current version with enhanced design patterns, documentation, and testing.
- The project is intended to be used as a class library by external .NET projects.
- Interfaces (
IGame
,IScoreBoard
,IGameRepository
) ensure testability and flexibility for dependency injection. - Comprehensive XML Documentation:
- All public classes, interfaces, methods, and properties include XML documentation to provide guidance and assist users when integrating the library.
- This improves the developer experience by offering IntelliSense support in IDEs like Visual Studio and Visual Studio Code.
- The library currently handles football matches. Extending it to other sports would require additional domain-specific classes.
- Default sorting prioritizes games with higher scores and, for ties, games started later.
- Custom sorting strategies can be injected as needed.
- The
InMemoryGameRepository
is optimized for small-scale, in-memory operations but can be replaced with a database-backed implementation.
- Ensures robust error handling with meaningful exceptions (e.g.,
ArgumentNullException
,InvalidOperationException
).
src/
βββ FootballScoreBoard/
β βββ Core/ # Core interfaces and business logic (IGame, IScoreBoard, Game, ScoreBoard)
β βββ Infrastructure/ # Infrastructure components (IGameRepository, InMemoryGameRepository)
tests/
βββ FunctionalTests/ # Tests simulating real-world scenarios
βββ IntegrationTests/ # Tests for interactions between components
βββ Mocks/ # Helpers for mocking
βββ UnitTests/ # Unit tests for core components
docs/
βββ Exercise.md # Coding exercise instructions (with company references removed)
While the library meets the current requirements and adheres to the KISS principle as suggested in the exercise, I have carefully balanced simplicity with extensibility. In some cases, I hesitated to apply additional complexity, ensuring that the solution remains straightforward and aligns with the challenge's scope. However, here are potential areas for future development:
- Extend the library to handle different sports by introducing a more generic game model and domain-specific extensions (e.g., basketball, tennis).
- Introduce domain-specific exceptions (e.g.,
GameNotFoundException
,DuplicateGameException
) to improve error handling and provide more meaningful feedback.
- Replace the in-memory repository with a database (e.g., SQL, NoSQL) or a cloud storage provider.
- Provide more sophisticated sorting strategies based on additional criteria (e.g., alphabetical order, regional prioritization).
- Study (algorithm and betchmarking) if it is possible to improve the repository and sorting logic for handling a larger volume of games in real-time scenarios.
- Introduce mechanisms to handle concurrent operations safely (e.g., simultaneous updates or game deletions). Integration
- Prepare the library for distribution as a NuGet package, including proper versioning, metadata, and automated builds.
This project was developed as part of a coding challenge for a job interview. It is not intended for production use or public distribution.