Building Domain Frameworks for Business Applications
Tags: architecture, dotnet, opensource, payroll
Published: 2023-08-07 06:24:15

Frameworks are standardized environments that support the creation of software platforms. In this article, I would like to share my experience in building the framework for the **Payroll Service Provider** business domain. The framework should enable the Payroll Service Provider to provide payroll services to companies in different industries.

### Identify the Hot Spots
The first step was to analyze the [Hot Spots](https://www.amazon.com/Domain-Specific-Application-Frameworks-Experience-Industry/dp/0471332801) of the business domain, i.e. the functional areas where the framework needed to be flexible. The hot spot analysis was conducted with experienced payroll specialists and divided into payroll service providers and their customers.

#### Hot Spots for Payroll Service Providers
▶️ Automatic application of regulatory changes without software update.
▶️ Compliance with regulatory reporting requirements.
▶️ Customized client onboarding and services.

#### Customer Hot Spots
▶️ Cancellation of company or employee cases.
▶️ Processing of specialized employee cases.
▶️ Business case simulation and predictive analytics.

### Isolate the Domain Objects
Based on the hot spots, the payroll relevant objects have been isolated in the `Regulation` container. The objects were divided into [processing](https://en.wikipedia.org/wiki/IPO_model) phases and their runtime behavior was determined.
![Regulation objects](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/adcwnfpt2w85sloeuskq.png)

### Scale the Domain Objects
To merge regulations from different sources, they are stacked as layers in the `Payroll` object.
![Payroll Regulations](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q24mjom3wp9f25wl8iqt.png)

Regulation objects can be overridden and extended in the layers above them. The dynamic composition of regulation layers results in dynamic data entry screens and additional payroll results and reports.

### Time nature of the data
When analyzing the data in terms of its time behavior, two types of data emerged: payroll-related data and neutral business data, which we called *time data*.

#### Payroll-related data
The wage definition (calculation) and external data, such as tax tables, are taken into account within the payroll period and are valid at the beginning of each payroll period. The time frame of the payroll run is determined by the `Cycle` (for example, year) and the `Period` (for example, month).

#### Time data
Most business transactions contain information that spans multiple payroll periods, such as an employee's monthly salary. To represent such values in the payroll calendar, the case field supports time data values, that store state changes using the [Event Sourcing](https://martinfowler.com/eaaDev/EventSourcing.html) approach. With this information, the framework converts the time data value to the payroll period.

A time data value consists of
- the creation date
- the start date from which the value is valid
- the end date to which the value applies (indefinite if not specified)
- the value that is valid between the start date and the end date.

#### Forecasts
Business data can be captured for simulations and predictive analytics that are only included in predictive payroll runs.
![Forecast case](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9c4tyhsxajc80x9y433t.png)

The framework distinguishes between legal and forecast payroll runs.
![Forecast payroll run](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v4n86n223bbrdn6lms8i.png)

### Low-code and No-code
Low-code and no-code development lowers the barriers to entry for users, which is important when building complex payroll solutions.

#### Low-code
The first design decision in evaluating low-code technology was the choice of development language. I decided against a domain language ([DSL](https://en.wikipedia.org/wiki/Domain-specific_language)) and in favor of C# as the scripting language. Besides modern development tools, C# offers some possibilities to build domain-specific features.

The following example shows a scenario where the mutations of the monthly wage and the risk bonus overlap.
![Time data](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7nmez95olb2376m2d4yo.png)

You can use the addition (`+`), subtraction (`-`), multiplication (`*`), division (`/`), and modulus (`%`) [operators](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading) to calculate time values that take overlaps into account.

The following wage type value script calculates the above example.
```c#
var values = GetCaseValues("Salary", "RiskBonus");
decimal baseSalary = values["Salary"];
return baseSalary + (values["Salary"] * values["RiskBonus"]);
```

#### No-code
`Actions` can be used to control data entry and validation without programming knowledge. As in Excel, an action is a predefined function that can be conditionally executed, similar to the Excel function `IIf()`. The action provides access to user input, previous case values, and lookup tables.

The following example uses the `Limit` build action and the `ValueBetween` validation action to limit the value of the `Salary` case field to between `500` and `25,000`.
```json
"cases": [
  {
    "name": "Salary",
    "caseType": "Employee",
    "buildExpression": "true",
    "validateExpression": "true",
    "fields": [
      {
        "name": "Salary",
        "valueType": "Money",
        "timeType": "CalendarPeriod",
        "buildActions": [
          "Limit(500, 25000)"
        ],
        "validateActions": [
          "ValueBetween(500, 25000)"
        ]
      }
    ]
  }
]
```

### Test the Domain Objects
All objects of the regulation can be tested automatically.

| Test method          | Test scope                                    |
|:--|:--|
| Case Available Test  | Test for case availability.    |
| Case Build Test      | Test for case build.           |
| Case Validate Test   | Test for validating the case.  |
| Payrun Test          | Test the company payroll run.  |
| Payrun Employee Test | Test the employee payroll run. |
| Report Build Test    | Test the report build.         |
| Report Execute Test  | Test the report execution.     |

The test system is suitable for test-driven regulation development.

### Framework Applications
The following applications are available for users to interact with the framework.
- **Framework libraries** as NuGet packages
- **Back-end server**, an ASP.NET Core REST API, and a SQL Server database
- **Automation Console**, a .NET Core application
- **Web application**, an ASP.NET Core Blazor server application

The applications are accompanied by documentation (Swagger, Scripting Reference, Whitepaper...), examples and tutorials.

### Hot Spot Coverage
The chosen architecture of the framework covers the identified hot spots as follows.

▶️ Automatic application of regulatory changes without software update.
✅ Versioned regulations with activation date used for retroactive calculations.

▶️ Compliance with regulatory reporting requirements.
✅ Executions status during payroll runs and report generation.

▶️ Customized client onboarding and services.
✅ Development of proprietary business and customer regulations.

▶️ Cancellation of company or employee cases.
✅ Unlimited case cancellation based on time data.

▶️ Processing of specialized employee cases.
✅ Build custom regulations with no-code and low-code.

▶️ Business case simulation and predictive analytics.
✅ Forecast specific case changes and payroll runs.

### Summary
Identifying the hot spots and objects in the business domain and determining the timing behavior is the basis for building complex frameworks. This approach is particularly useful for distributed and heterogeneous business domains such as payroll.

---

This framework is available as an open source project (MIT) on [GitHub](https://github.com/Payroll-Engine/PayrollEngine/Wiki).