Skip to content

Commit

Permalink
Merge pull request #181 from dlandi/code-rub-v2-aggregation-clean-ver…
Browse files Browse the repository at this point in the history
…sion

CODE RUB: v2 aggregation clean version
  • Loading branch information
hassanhabib authored Sep 7, 2022
2 parents 888224b + cca0f85 commit 6870b6d
Showing 1 changed file with 21 additions and 21 deletions.
42 changes: 21 additions & 21 deletions 2. Services/2.4 Aggregations/2.4 Aggregations.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# 2.4 Aggregation Services (The Knot)

## 2.4.0 Introduction
Aggregation services main responsibility is to expose one single point of contact between the core business logic layer and any exposure layers. It ensures, if multiple services of any variation share the same contract, that they are aggregated and exposed to one exposer component through one logical layer.
An Aggregation service's primary responsibility is to expose one single point of contact between the core business logic layer and any exposure layers. It ensures that multiple services of any variation share the same contract to be aggregated and exposed to one exposer component through one logical layer.

Aggregation services don't hold any business logic in themselves. They are simply a knot that ties together multiple services of any number. They can have any layer of services as dependencies and it mainly exposes the call to these services accordingly. Here's a code example of an aggregation service:

Expand All @@ -16,10 +16,10 @@ public async ValueTask ProcessStudentAsync(Student student)
}
```

As the snippet shows above, an Aggregation service may have any number of calls in any order without limitation. And there may be occasions where you may or may not need to return a value to your exposure layers depending on the overall flow and architecture, which we will discuss shortly in this chapter. But more importantly Aggregation services should not be mistaken for an orchestration service or any of its variants.
As the snippet shows above, an Aggregation service may have any number of calls in any order without limitation. And there may be occasions where you may or may not need to return a value to your exposure layers depending on the overall flow and architecture, which we will discuss shortly in this chapter. But more importantly, Aggregation services should not be mistaken for an Orchestration service or any of its variants.

## 2.4.1 On The Map
Aggregation services always sit on the other end of a core business logic layer. They are the last point of contact between exposure layers and logic layers. here's a visualization of where aggregation services would be located in an overall architecture:
Aggregation services always sit on the other end of a core business logic layer. They are the last point of contact between exposure layers and logic layers. Here's a visualization of where Aggregation services are located in an overall architecture:

<br />
<p align="center" >
Expand All @@ -30,12 +30,12 @@ Aggregation services always sit on the other end of a core business logic layer.
Let's discuss the characteristics of Aggregation services.

## 2.4.2 Characteristics
Aggregation services mainly exist when there are multiple services, sharing the same contract or sharing primitive types of the same contract, that require a single point of exposure. They mainly exist in hyper-complex applications where multiple services (usually orchestration or higher but can be lower) require one single point of contact through exposure layers. Let's talk in detail about the main characteristics for Aggregation services.
Aggregation services mainly exist when multiple services share the same contract or primitive types of the same contract, requiring a single point of exposure. They mainly exist in hyper-complex applications where multiple services (usually orchestration or higher but can be lower) require one single point of contact through exposure layers. Let's talk in detail about the main characteristics of Aggregation services.

### 2.4.2.0 No Dependency Limitation
Unlike any other service, Aggregation services can have any number of dependencies as long as these services are of the same variation. For instance, an Aggregation service cannot aggregate between an Orchestration service and a Coordination service. It's a partial Florance-Like pattern where services have to be of the same variation but not necessary limited by the number.
Unlike any other service, Aggregation services can have any number of dependencies as long as these services are of the same variation. For instance, an Aggregation service cannot aggregate between an Orchestration service and a Coordination service. It's a partial Florance-Like pattern where services must be of the same variation but not necessarily limited by the number.

The reason for the lack of limitation of the dependencies for Aggregation services is because the service itself doesn't perform any level of business logic between these services. It doesn't care what these services do or require. It only focuses on exposing these services regardless of what was called before or after them.
The lack of limitation of the dependencies for Aggregation services is because the service doesn't perform any level of business logic between these services. It doesn't care what these services do or require. It only focuses on exposing these services regardless of what was called before or after them.

Here's what an Aggregation service test would look like:

Expand Down Expand Up @@ -74,7 +74,7 @@ public async Task ShouldProcessStudentAsync()
}
```

As you can see above, we are only verifying and testing for the aggregation aspect of calling these services. No return type required in this scenario but there might be in the scenarios of pass-through which we will be discussing shortly.
As you can see above, we only verify and test for the aggregation aspect of calling these services. No return type is required in this scenario, but there might be in the scenarios of pass-through, which we will be discussing shortly.

An implementation of the above test would be as follows:

Expand All @@ -90,17 +90,17 @@ public async ValueTask ProcessStudentAsync(Student student)
```

### 2.4.2.1 No Order Validation
By definition, Aggregation services are naturally required to call several dependencies with no limitation. The order of calling these dependencies is also not a concern or a responsibility for Aggregation services. That's simply because the call-order verification is considered a core business logic. which falls outside of the responsibilities of an Aggregation service. That of course includes both natural order of verification or enforced order of verification as we explained in section 2.3.3.0.1 in the previous chapter.
By definition, Aggregation services are naturally required to call several dependencies with no limitation. The order of calling these dependencies is also not a concern or a responsibility for Aggregation services because the call-order verification is considered a core business logic, which falls outside the responsibilities of an Aggregation service. That, of course, includes both natural order of verification or enforced order of verification, as we explained in section 2.3.3.0.1 in the previous chapter.

It's a violation of The Standard to attempt using simple techniques like a mock sequence in testing an Aggregation service. These responsibilities are more likely to fall on the next lower layer of an Aggregation service for any orchestration-like service. It is also a violation to verify reliance on the return value of one service call to initiate a call to the next.
It's a violation of The Standard to use simple techniques like a mock sequence to test an Aggregation service. It is also a violation to verify reliance on the return value of one service call to initiate a call to the next. These responsibilities are more likely to fall on the next lower layer of an Aggregation service for any orchestration-like service.

### 2.4.2.2 Basic Validations
Aggregation services are still required to validate whether the incoming data is higher-level structurally valid or not. For instance, an Aggregation service that takes a `Student` object as an input parameter will validate only if the `student` is `null` or not. But that's where it all stops.
Aggregation services are still required to validate whether or not the incoming data is higher-level structurally valid. For instance, an Aggregation service that takes a `Student` object as an input parameter will validate only if the `student` is `null` or not. But that's where it all stops.

There may be an occasion where a dependency requires a property of an input parameter to be passed in, in which case it is also permitted to validate that property value structurally. For instance, if a downstream dependency requires a student name to be passed in. An Aggregation service is still going to be required to validate if the `Name` is `null`, empty or just whitespace.
There may be an occasion where a dependency requires a property of an input parameter to be passed in, in which case it is also permitted to validate that property value structurally. For instance, if a downstream dependency requires a student name to be passed in. An Aggregation service will still be required to validate if the `Name` is `null`, empty, or just whitespace.

### 2.4.2.3 Pass-Through
Aggregation services are not also required to implement their aggregation by performing multiple calls from one method. They can also aggregate by offering a pass-through methods for multiple services. For instance, assume we have `studentCoordinationService` and `studentRecordsService` and `anyOtherStudentRelatedCoordinationService` and each one of these services are independent in terms of business flow. So an aggregation here is only at the level of exposure but not necessarily the level of execution.
Aggregation services are not required to implement their aggregation by performing multiple calls from one method. They can also aggregate by offering pass-through methods for multiple services. For instance, assume we have `studentCoordinationService`, `studentRecordsService` and `anyOtherStudentRelatedCoordinationService` where each service is independent in terms of business flow. So an aggregation here is only at the level of exposure but not necessarily the level of execution.

Here's a code example:

Expand Down Expand Up @@ -138,12 +138,12 @@ public partial class StudentAggregationService
As you can see above, each service is using the Aggregation service as a pass-through. There's no need in this scenario whatsoever for an aggregated routines call. This would still be a very valid scenario for Aggregation services.

### 2.4.2.4 Optionality
It is important to mention here that Aggregation services are optional. Unlike foundation services, Aggregation services may or may not exist in any architecture. Aggregation services are there to solve a problem with abstraction. This problem may or may not exist based on whether the architecture requires a single point of exposure at the border of the core business logic layer or not. This single responsibility of Aggregation services makes it much simpler to implement its task and perform its function easily. Aggregation services being optional is more likely to be than any other lower-level services. Even in the most complex of applications out there.
It is important to mention here that Aggregation services are optional. Unlike foundation services, Aggregation services may or may not exist in architecture. Aggregation services are there to solve a problem with abstraction. This problem may or may not exist based on whether the architecture requires a single point of exposure at the border of the core business logic layer or not. This single responsibility of Aggregation services makes it much simpler to implement its task and perform its function easily. Aggregation services being optional is more likely to be than any other lower-level services. Even in the most complex of applications out there.

### 2.4.2.5 Routine-Level Aggregation
If an aggregation service has to make two different calls from the same dependency amongst other calls, It is recommended to aggregate for every dependency routine. But that's only from code-cleanliness perspective and it doesn't necessarily impact the architecture or the end-result in any way.
If an aggregation service has to make two different calls from the same dependency amongst other calls, It is recommended to aggregate for every dependency routine. But that's only from a clean-code perspective, and it doesn't necessarily impact the architecture or the end result.

here's an example:
Here's an example:

```csharp
public async ValueTask ProcessStudent(Student student)
Expand All @@ -160,21 +160,21 @@ private async ValueTask ProcessStudentRecordAsync(Student student)

```

This organizational action doesn't warrant any kind of change in terms of testing or end-result as previously mentioned.
This organizational action doesn't warrant any change in testing or end result as previously mentioned.

### 2.4.2.6 Pure Dependency Contracts
The most important rule/characteristic of an Aggregation service is that its dependencies (unlike orchestration services) must share the same contract. The input parameter for a public routine in any Aggregation service must be the same for all its dependencies. There may be occasions where a dependency may require a student id instead of of the entire student that is permitted with caution as long as the partial contract isn't a return type of another call within the same routine.
An Aggregation service's most important rule/characteristic is that its dependencies (unlike orchestration services) must share the same contract. The input parameter for a public routine in any Aggregation service must be the same for all its dependencies. There may be occasions where a dependency may require a student id instead of the entire student, which is permitted with caution as long as the partial contract isn't a return type of another call within the same routine.


## 2.4.3 Responsibilities
Aggregation services main responsibility is to offer a single point of contact between exposer components and the rest of the core business logic. But in essence, abstraction is the true value Aggregation services offer to ensure any business component as a whole is pluggable into any system regardless of the style of exposure this very system may need.
An Aggregation service's primary responsibility is to offer a single point of contact between exposer components and the rest of the core business logic. But in essence, abstraction is the true value Aggregation services offer to ensure any business component is pluggable into any system regardless of the style of exposure.

Let's talk about these responsibilities in detail.

### 2.4.3.0 Abstraction
An aggregation service performs into responsibility successfully when its clients or consumers have no idea what lies beyond the lines of its implementation. An Aggregation service could be combining 10 different services and exposes a single routine in a fire-n-forget scenario.
An aggregation service performs into responsibility successfully when its clients or consumers have no idea what lies beyond the lines of its implementation. An Aggregation service could combine ten different services and expose a single routine in a fire-n-forget scenario.

But even in pass-through scenarios, Aggregation services abstract away any identification of the underlying dependency from exposers at all costs. It doesn't always happen especially in terms of localized exceptions but close enough to make the integration seem as if it is with one single service that's offering all the options natively.
But even in pass-through scenarios, Aggregation services abstract away any identification of the underlying dependency from exposers at all costs. It doesn't always happen, especially in terms of localized exceptions but close enough to make the integration seem as if it is with one single service that's offering all the options natively.

### 2.4.3.1 Exceptions Aggregation
Aggregation services are also similar to orchestration-like services in terms of mapping and aggregating exceptions from downstream dependencies. For instance, if `studentCoordinationService` is throwing `StudentCoordinationValidationException`an Aggregation service would map that into `StudentAggregationDependencyValidationException`. This falls back into the concept of exception unwrapping then wrapping of localized exceptions which we spoke about in detail in section 2.3.3.0.2 of this Standard.
Aggregation services are similar to orchestration-like services when mapping and aggregating exceptions from downstream dependencies. For instance, if `studentCoordinationService` is throwing `StudentCoordinationValidationException`an Aggregation service would map that into `StudentAggregationDependencyValidationException`. This falls back into the concept of exception unwrapping and then wrapping of localized exceptions, which we discussed in detail in section 2.3.3.0.2 of this Standard.

0 comments on commit 6870b6d

Please sign in to comment.