Sort names by surname then given names (1–3). Prints to console and writes sorted-names-list.txt.
- SOLID Principles: The program uses SOLID principles to keep components small, testable, and maintainable.
- Factory Pattern (Person):
Personinstances are constructed via a factory. Reason is that the factory centralizes validation and creation logic so domain invariants are enforced in one place and calling code remains simple. Also gives benifit of doing validation in create rather than constructor. - Sealed Records & Sealed Classes: I have used
sealed recordsandsealedclasses to ensure immutability and to prevent unintended inheritance. This helps preserve invariants and makes reasoning about state easier.
Following are the layers of the system.
-
Layers:
App— composition root and orchestrator (wires dependencies and runs the workflow).Core— domain types (Person), parsing (INameParser/NameParser), and sorting (PersonNameComparer).Infrastructure— adapters for I/O file handling (INameRepository/FileNameRepository).
-
AppBootstrap(Why did i use this):- This acts as the application orchestrator / composition root for the small CLI: it accepts the repository, parser and comparer and coordinates parsing, sorting and writing. Basically stitches everything togehter while keeping main program clean.
- Keeps
Program.csthin —Program.csonly registers services and invokesAppBootstrap.RunAsync(args)which improves single-responsibility and testability. - Makes integration and end-to-end testing easy: tests construct
AppBootstrapwith real or fake implementations (seeNameSortingExercise.Tests.EndToEndTests).
-
Exit codes:
0— success.2— invalid usage or missing input file.
-
Testing notes / extensibility:
- Because dependencies are directly injected, you can replace
INameRepositorywith an in-memory implementation for fast tests, or add logging and configuration later by introducing a host.
- Because dependencies are directly injected, you can replace
# from repo root
dotnet build
dotnet run --project NameSortingExercise.App ./unsorted-names-list.txtdotnet testUnit tests: cover parsing (NameParser), sorting (PersonNameComparer), and domain invariants (Person). End-to-end test: runs the whole workflow in a temp directory with real file I/O.
When the GitHub Actions workflow runs, it will:
- Execute all tests with coverage enabled.
- Upload test results (
.trx) and coverage reports (coverage.cobertura.xml) as build artifacts.
(not required but nice to have may be.)
- Go to the Actions tab in this GitHub repository.
- Open the latest workflow run for your branch (e.g.,
main). - Scroll to the Artifacts section at the bottom of the run summary.
- Download
test-results-<os>.zip— it contains:test-results.trx→ Detailed test results.coverage.cobertura.xml→ Code coverage report (Cobertura format).
You can open .trx files with Visual Studio.