Divide and conquer
The best way to achieve good, solid application architecture is to structure code well, create appropriate abstractions, and separate it into components with a single responsibility.
In functional programming it goes even further. The data—and the functions to work on that data—are also separated. The OOP concept of data and methods to work with it are split into two parts. This makes code even more flexible and reusable.
For concurrent code execution it's particularly important to split your code into standalone separate pieces because they can be sent for execution concurrently without blocking each other.
Before we start refactoring the code let's analyze it first. The goal is to identify a component with a single responsibility. I did it and here are those components:
In Data: The first part is our input data. In our case it is a
SalesData
structure that holds immutable data in our application.Calculation function: The next part is our function that knows how to calculate...