From 5f0577969ebc00cfaab6b087d43eadf580727737 Mon Sep 17 00:00:00 2001 From: Greg Hays Date: Wed, 17 Apr 2024 13:33:25 -0700 Subject: [PATCH] CODE RUB: Services 2.0 Grammer Check --- 2. Services/2. Services.md | 57 ++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/2. Services/2. Services.md b/2. Services/2. Services.md index a8a7cb9..086cc45 100644 --- a/2. Services/2. Services.md +++ b/2. Services/2. Services.md @@ -2,11 +2,11 @@ ## 2.0 Introduction -Services, in general, are the containers of all the business logic in any given software - they are the core component of any system and the main component that makes one system different from another. +Services, in general, are the containers of all the business logic in software—they are the core component of any system and the main component that makes one system different from another. Our main goal with services is to keep them agnostic from specific technologies or external dependencies. -Any business layer is more compliant with The Standard if it can plug into any other dependencies and exposure technologies with the least amount of integration effort. +Any business layer is more compliant with The Standard if it can plug into other dependencies and exposure technologies with the least integration effort. ### 2.0.0 Services Operations @@ -22,21 +22,21 @@ Let's talk about these categories. #### 2.0.0.0 Validations -Validations ensure that incoming or outgoing data match a particular set of rules: structural, logical, or external validations, in that exact order of priority. We will go into details about this in the upcoming sections. +Validations ensure that incoming or outgoing data match a particular set of rules, such as structural, logical, or external validations, in that exact order of priority. We will discuss this in detail in the upcoming sections. #### 2.0.0.1 Processing -Processing mainly focuses on the flow-control, mapping, and computation to satisfy a business need - the processing operations distinguish one service from another and, in general, one software from another. +Processing mainly focuses on flow control, mapping, and computation to satisfy a business need—the processing operations distinguish one service from another and, in general, one piece of software from another. #### 2.0.0.2 Integration Finally, the integration process focuses on retrieving or pushing data from or to any integrated system dependencies. -We will discuss these aspects in detail in the upcoming chapter. The main thing to understand about services is that the design is to be pluggable and configurable to easily integrate with any technology from a dependency standpoint and easy to plug into any exposure functionality from an API perspective. +We will discuss these aspects in detail in the upcoming chapter. The main thing to understand about services is that their design is to be pluggable and configurable, allowing them to easily integrate with any technology from a dependency standpoint and easily plug into any exposure functionality from an API perspective. ### 2.0.1 Services Types -Services have several types based on their disposition in any given architecture. They fall under three main categories: validators, orchestrators, and aggregators. +Services are classified into several types based on their disposition in any given architecture. They fall into three main categories: validators, orchestrators, and aggregators.

@@ -56,15 +56,18 @@ Orchestrator services are the core of the business logic layer. They can be proc Orchestrator services mainly focus on combining multiple primitive operations or multiple high-order business logic operations to achieve an even higher goal. -Orchestrator services are the decision makers within any architecture, the owners of the flow control in any system, and the main component that makes one application or software different from the other. +Orchestrator services are: +The decision-makers within any architecture. +The owners of the flow control in any system. +The main component that makes one application or software different from the other. We intentionally design Orchestrator services to be longer-lived than any other type of service in the system. #### 2.0.1.2 Aggregators -Aggregator services' primary responsibility is to tie the outcome of multiple processing, orchestration, coordination, or management services to expose one single API for any given API controller or UI component to interact with the rest of the system. +The primary responsibility of the aggregator services is to tie the outcome of multiple processing, orchestration, coordination, or management services to expose one single API for any given API controller or UI component to interact with the rest of the system. -Aggregators are the gatekeepers of the business logic layer. They ensure the data exposure components (like API controllers) are interacting with only one point of contact to interact with the rest of the system. +Aggregators are the gatekeepers of the business logic layer. They ensure the data exposure components (like API controllers) interact with only one point of contact to interact with the rest of the system. Aggregators, in general, don't care about the order in which they call the operations that are attached to them. Still, it is sometimes necessary to execute a particular operation, such as creating a student record before assigning a library card. @@ -78,15 +81,15 @@ These rules ensure the system's overall readability, maintainability, and config #### 2.0.2.0 Do or Delegate -Every service should either do or delegate the work but not both. +Every service should either do or delegate the work, but not both. -For instance, a processing service should delegate the work of persisting data to a foundation service and not try to do that work by itself. +For instance, a processing service should delegate the work of persisting data to a foundation service rather than try to do that work itself. #### 2.0.2.1 Two-Three (Florance Pattern) -For Orchestrator services, their dependencies of services (not brokers) should be limited to two or three, but not one or not four or more. +For Orchestrator services, the dependencies of services (not brokers) should be limited to two or three, not one, four, or more. -If an Orchestrator depends only on one service, then it violates the definition of orchestration which is the combination of multiple operations from different sources to achieve a higher order of business logic. +Suppose an Orchestrator depends only on one service. In that case, it violates the definition of orchestration, which is the combination of multiple operations from different sources to achieve a higher order of business logic. ###### This pattern violates Florance Pattern @@ -106,7 +109,7 @@ If an Orchestrator depends only on one service, then it violates the definition The Florance pattern also ensures the balance and symmetry of the overall architecture. -For instance, you can't orchestrate between a foundation and a processing service. It causes a form of unbalance in your architecture and difficulty when trying to combine one unified statement with the language each service speaks based on their level and type. +For instance, you can't orchestrate between a foundation and a processing service. This causes an imbalance in your architecture and difficulty when trying to combine one unified statement with the language each service speaks based on its level and type. The aggregators are the only types of services allowed to violate this rule, where the combination and the order of services or their calls don't have any real impact. @@ -114,11 +117,11 @@ We will discuss the Florance pattern in detail in the upcoming sections of The S #### 2.0.2.2 Single Exposure Point -API controllers, UI components, or any other form of data exposure from the system should have one single point of contact with the business-logic layer. +API controllers, UI components, or any other form of system data exposure should have one single point of contact with the business logic layer. -For instance, an API endpoint that offers endpoints for persisting and retrieving student data should not have multiple integrations with multiple services but rather one service that provides all of these features. +For instance, an API endpoint that offers endpoints for persisting and retrieving student data should not have multiple integrations with multiple services but one service that provides all these features. -Sometimes, a single orchestration, coordination, or management service does not offer everything related to a particular entity. An aggregator service combines all of these features into one service ready to be integrated with an exposure technology. +Sometimes, a single orchestration, coordination, or management service does not offer everything related to a particular entity. An aggregator service combines all these features into one service that is ready to be integrated with exposure technology. #### 2.0.2.3 Same or Primitives I/O Model @@ -126,7 +129,7 @@ All services must maintain a single contract regarding their return and input ty For instance, a service that provides operations for an entity type `Student` - should not return from any of its methods from any other entity type. -You may return an aggregation of the same entity whether it's custom or native such as `List` or `AggregatedStudents` models, or a primitive type like getting students count, or a boolean indicating whether a student exists or not but not any other non-primitive or non-aggregating contract. +You may return an aggregation of the same entity, whether it's custom or native, such as `List` or `AggregatedStudents` models, or a primitive type like getting students count, or a boolean indicating whether a student exists or not but not any other non-primitive or non-aggregating contract. A similar rule applies for input parameters - any service may receive an input parameter of the same contract, a virtual aggregation contract, or a primitive type but not any other contract. @@ -134,17 +137,17 @@ This rule focuses the responsibility of a service on a single entity and all its When a service returns a different contract, it violates its naming convention like a `StudentOrchestrationService` returning `List` - and it starts falling into the trap of being called by other services from entirely different data pipelines. -For primitive input parameters, if they belong to a different entity model that is not necessarily a reference to the primary entity, it begs the question of orchestrating between two processing or foundation services to maintain a unified model without breaking the pure-contracting rule. +If primitive input parameters belong to a different entity model that is not necessarily a reference to the primary entity, it begs the question of orchestrating between two processing or foundation services to maintain a unified model without breaking the pure-contracting rule. -Suppose the combination of multiple different contracts in an orchestration service is required. In that case, a new unified virtual model indicates the need for a new unique contract for the orchestration service with mappings implemented underneath on the concrete level of that service to maintain compatibility and integration safety. +Suppose an orchestration service requires a combination of multiple different contracts. In that case, a new unified virtual model indicates the need for a new unique contract for the orchestration service, with mappings implemented underneath on the concrete level of that service to maintain compatibility and integration safety. #### 2.0.2.4 Every Service for Itself -Every service is responsible for validating its inputs and outputs. Do not rely on services up or downstream to validate your data. +Every service is responsible for validating its inputs and outputs. Do not rely on services upstream or downstream to validate your data. -This is a defensive programming mechanism to ensure that in case of swapping implementations behind contracts, the responsibility of any given service is not be affected if down or upstream services decided to pass on their validations for any reason. +This is a defensive programming mechanism to ensure that if implementations are swapped behind contracts, the responsibility of any given service is not affected if downstream or upstream services decide to pass on their validations for any reason. -Within any monolithic, microservice, or serverless architecture-based system, every service is designed so that it can split off from the system at some point and become the last point of contact before integrating with some external resource broker. +Within any monolithic, microservice, or serverless architecture-based system, every service is designed to split off from the system at some point and become the last point of contact before integrating with some external resource broker. For instance, in the following architecture, services map parts of an input `Student` model into a `LibraryCard` model. Here's a visual of the models: @@ -198,11 +201,11 @@ private LibraryCard MapToLibraryCard(Student student) } ``` -As you can see above, a valid student id is required to ensure a successful mapping to a `LibraryCard` - and since the mapping is the orchestrator's responsibility, we are required to ensure that the input student and its id is in good shape before proceeding with the orchestration process. +As you can see above, a valid student id is required to map to a `LibraryCard successfully`. Since the mapping is the orchestrator's responsibility, we must ensure that the input student and its id are in good shape before proceeding with the orchestration process. #### 2.0.2.5 Flow Forward Services cannot call services at the same level. For instance, Foundation Services cannot call other Foundation Services, and Orchestration Services cannot call other Orchestration Services from the same level. -This principle is called a Flow-Forward - as the illustation shows: +This principle is called a Flow-Forward - as the illustration shows:
@@ -234,6 +237,6 @@ public async ValueTask ModifyStudentAsync(Student student) } ``` -In a Foundation Service example above, we cannot call `RetriveStudentByIdAsync` in a `public` method from another `public` method such as `ModifyStudentAsync`. You will see that both methods called the exact same method from a lower dependency like a `StorageBroker` full independent of one another. +In the Foundation Service example above, we cannot call `RetriveStudentByIdAsync` in a `public` method from another `public` method such as `ModifyStudentAsync`. You will see that both methods call the exact same method from a lower dependency, like a `StorageBroker`, fully independent of one another. -While this may seem redundant, the reason for this is that `public` APIs, contracts or otherwise are destined to be deprecated at some point in it's lifetime. It may also be changed completely from an implementation standpoint. If a `public` API depended on another `public` API at the same level the deprecation of one will cause a cascading effect on all others. That's a symptom of Chaotic design which The Standard strongly prohibits. +While this may seem redundant, the reason for this is that `public` APIs, contracts, or otherwise, are destined to be deprecated at some point in their lifetime. They may also be changed completely from an implementation standpoint. If a `public` API depended on another `public` API at the same level, the deprecation of one will cause a cascading effect on all others. That's a symptom of Chaotic design, which The Standard strongly prohibits. \ No newline at end of file