DPL Education – Sales Tax Activity
Our Software Design and Development Clinics focus on teaching engineers the real-world development skills that will make them more productive and effective.
Part of the class is Doug and I covering several topics, but we try to have a real focus on actually doing things. We want students to develop skill and knowledge, which takes both learning and putting that learning into practice.
For the practice part, Doug and I created a reference implementation to get students started quickly. The reference implementation isn’t a super large application, but it is large enough to begin illustrating the concepts we cover in the clinics. This isn’t a hello world level application; it is an ecommerce application (a domain where almost all of us have experience).
The reference application follows the patterns and practices we encourage in our software solutions we create. The software we write looks a lot like our reference application, but a big difference is our reference implementation uses the world’s most perfect user experience: a console application.
The ecommerce application isn’t fully functional. It has many short cuts so we can just demo the application. One of those short cuts is that the application doesn’t do a real sales tax calculation, it only performs with a flat 7% tax for all items.
In this walk-through, I will take you through modifying our reference application to support a third-party tax library (which we wrote ourselves to use Nebraska’s state sales tax, so I’m playing a bit loose with the term “third-party”). Since this is still for demonstration purposes, we don’t stand behind it as a production-ready library.
Changing our reference application to support calling this third-party library will cause us to change our architecture. Before using this library, our architecture for adding an item to the shopping cart looked like below.
After we changed it, it looks like this.
So how do we go about making the change? First we will add a new accessor, SalesTaxRuleAccessor, into our system. This accessor will call our third-party library to get the sales tax. In a real system, this would probably be a web call to somewhere else.
We will have to load the USATaxer project into Visual Studio and build the library. That will create a USATaxer.dll.
How does the USATaxer library work? Let’s look at its unit test.
Copy the USATaxer.dll to the root of our ecommerce solution and add a reference to it in our Accessors project.
The next step is to add a TaxRateAccessor to our solution. This will require us to add a new a TaxRateAccessor.cs file.
The TaxRateAccessor needs to be wired up into our dependency injection (DI) system. That means we need to modify our AccessorFactory.cs file. In our reference implementation, we are doing all the dependency injection ourselves. In many production systems we may using something like Unity to use dependency injection, but we are trying to keep things simple in our reference implementation.
At this point we have a new accessor and it should be supported by our DI framework. All that is left is to use it.
But wait, we should test it first.
Now that we have a test (and hopefully it passes), we can finally use this accessor in our code by adding it to our TaxCalculationEngine. This can be found in the TaxCalculationEngine.cs file in the Engine project.
After wiring in the use of this new SalesTaxRuleAccessor, we will break some unit tests. This is okay because we have changed how taxes are calculated. Go through and update the unit tests to use what we are now calculating for tax.
This activity shows how to extend our existing reference implementation by calling a third-party library to do sales tax calculations. This example also shows how volatility-based decomposition helps to prevent a simple change from exploding through all of the source. The only existing code that changed was the TaxCalculationEngine.
If you liked what you have read here, consider signing up for our Software Design and Development Clinic.
For more fun, follow me on Twitter at @chadmichel.