-
Notifications
You must be signed in to change notification settings - Fork 586
Implementation of Exchange Rate Task #809
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
sergiomadd
wants to merge
37
commits into
MewsSystems:master
Choose a base branch
from
sergiomadd:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Wiz Scan Summary
To detect these findings earlier in the dev lifecycle, try using Wiz Code VS Code Extension. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Exchange rate updater
This is a .NET 6 console app that provides exchange rates from the Czech National Bank (CNB) for the CZK currency.
Decisions made for the task
Data Source
I decided to use the official CNB API: https://api.cnb.cz/. It is a documented official data source, updated daily, that provides foreign currency exchange rates in a fixed format.
Console app
I decided to go with a console app as it is the app type provided by the template. Also since I already have a public open source api project, I decided it would fit perfectly to display my skills in another .NET technology.
.NET 6
I chose to remain on the provided .NET 6 version rather than upgrading, since the task requirements did not specify an upgrade, and the project template builds correctly out of the box with .NET 6.
In a real-world scenario, upgrading the target framework of an existing project can introduce many breaking changes, and it would require extensive testing, and careful planning. Framework upgrades should be thoroughly though out and coordinated with other parts of the software.
Using .NET 6 does not pose any limitations for this project, and I am fully comfortable working with older .NET versions when appropriate.
Architecture
The app uses a layered architecture with dependency inversion, built on top of .NET Generic Host.
HttpClientwith retry policy usingPolly. This adds support for transient failures.Logging
For logging I used
ILoggerandSystem.Consoleinterchangeably, with separation of responsibilities.ILoggerfor system relevant logs, process tracking and errors.System.Consolefor user relevant logs and user interaction.MenuHandler
I have added a console menu with a simple lifecycle loop for the user interaction layer. This way I separate the business logic from the user UI. It has these available programs:
[1] Get latest exchange ratesExchangeRateProvider.GetExchangeRates[2] Get exchange rates for a dateExchangeRateProvider.GetExchangeRatesFromDay[3] Compare exchange rates between 2 datesExchangeRateProvider.CompareExchangeRatesBetweenDates[0] ExitOn each action finish, apart from
[0], it prompts the user toPress Enter to continue. OnEnterit clears the console and displays the menu, thus completing the loop.ExchangeRateSource
I decided to use a
IExchangeRateSourceto implement a data obtainer. This design provides a swappable source, so if in the future instead of getting the data from a api, I needed to get it from a database, I would only need create a new implementation of the interface and register it.ExchangeRateProvider
It implements the interface
IExchangeRateProviderwhich allows for easy testing. It uses private helper methods to assist in its function, and makes the logic reusable.ProcessExchangeRatesProcesses incomingExchangeRateDTOto match supported currenciesCompareExchangeRatesCompares 2 lists ofExchangeRateDTO, using only those who match the supported currencies, and returning a list ofExchangeRateDifferencewith calculated difference values.IsExchangeRateDTOValidValidates if the providedExchangeRateDTOis valid.ExchangeRateMapDTOToModelMaps providedExchangeRateDTOto the internal domain model.This design implements SRP, where the
GetExchangeRatesmethod is only in charge of orchestrating the data intake and the processing of the exchange rates. Also it makes the helper methods reusable for other future functions in the provider.Why add ExchangeRateDifference entity?
This additional entity allows for separation of concerns and keeps the domain model focused on each entities function. It also improves maintainability as it ensures updates to calculations don't affect the
ExchangeRateentity.Error Handling
I implemented a
ExchangeRateSourceExceptionto help with maintainable error handling. In addition, exceptions are caught and logged as close to their origin as possible. It allows for detailed logging and shields from throwing low level exceptions, revealing implementation specific details to above layers.Known issues
ILoggerlogging sometimes lags behindConsole.WriteLine. This is caused by theILoggerbuffer, as it asynchronously prints messages, compared toConsole.WriteLinewhich writes right away. This issue can sometimes place logger messages in between console messages.ConsoleLoggerwith flushable wrapper, to make sure theILoggerbuffer empties before proceeding with executionConsole.WriteLinein the menu handler is executed.Improvements
MenuHandlerinteractions.[1]->ltfor latest ratesIExchangeRateDifferenceCalculatorfor managing different ways of calculating the rate differences, instead of doing the calculation on theCompareExchangeRatesmethod. This would separate concerns, and be able to add different calculation methods, likeLogarithmicDifferenceCalculator, without modifying the implementation.How to run the project
Requisites
Building and Launching the App
Build the solution
dotnet build ExchangeRateUpdater.slnRun the application
dotnet run --project ExchangeRateUpdater/ExchangeRateUpdater.csprojExecuting Unit Tests
Run all tests
dotnet test ExchangeRateUpdater.Tests/ExchangeRateUpdater.Tests.csprojCredits
Menu title font from https://patorjk.com/software/taag