Skip to content

Commit

Permalink
Merge branch 'iluwatar:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
Ehspresso authored Apr 22, 2024
2 parents 5e9689e + b55e85f commit 08eded1
Show file tree
Hide file tree
Showing 30 changed files with 676 additions and 403 deletions.
142 changes: 83 additions & 59 deletions fanout-fanin/README.md
Original file line number Diff line number Diff line change
@@ -1,109 +1,131 @@
---
title: Fan-Out/Fan-In
category: Integration
category: Concurrency
language: en
tag:
- Microservices
- Asynchronous
- Data processing
- Decoupling
- Scalability
---

## Also known as

* Scatter-Gather

## Intent
The pattern is used when a source system needs to run one or more long-running processes that will fetch some data.
The source will not block itself waiting for the reply. <br> The pattern will run the same function in multiple
services or machines to fetch the data. This is equivalent to invoking the function multiple times on different chunks of data.

The Fan-Out/Fan-In pattern aims to improve concurrency and optimize processing time by dividing a task into multiple sub-tasks that can be processed in parallel (fan-out) and then combining the results of these sub-tasks into a single outcome (fan-in).

## Explanation
The FanOut/FanIn service will take in a list of requests and a consumer. Each request might complete at a different time.
FanOut/FanIn service will accept the input params and returns the initial system an ID to acknowledge that the pattern
service has received the requests. Now the caller will not wait or expect the result in the same connection.

Meanwhile, the pattern service will invoke the requests that have come. The requests might complete at different time.
These requests will be processed in different instances of the same function in different machines or services. As the
requests get completed, a callback service every time is called that transforms the result into a common single object format
that gets pushed to a consumer. The caller will be at the other end of the consumer receiving the result.
The Fan-Out/Fan-In service will take in a list of requests and a consumer. Each request might complete at a different time. Fan-Out/Fan-In service will accept the input params and returns the initial system an ID to acknowledge that the pattern service has received the requests. Now the caller will not wait or expect the result in the same connection.

Meanwhile, the pattern service will invoke the requests that have come. The requests might complete at different time. These requests will be processed in different instances of the same function in different machines or services. As the
requests get completed, a callback service every time is called that transforms the result into a common single object format that gets pushed to a consumer. The caller will be at the other end of the consumer receiving the result.

**Programmatic Example**

The implementation provided has a list of numbers and end goal is to square the numbers and add them to a single result.
`FanOutFanIn` class receives the list of numbers in the form of list of `SquareNumberRequest` and a `Consumer` instance
that collects the results as the requests get over. `SquareNumberRequest` will square the number with a random delay
to give the impression of a long-running process that can complete at any time. `Consumer` instance will add the results from
different `SquareNumberRequest` that will come random time instances.
The implementation provided has a list of numbers and end goal is to square the numbers and add them to a single result. `FanOutFanIn` class receives the list of numbers in the form of list of `SquareNumberRequest` and a `Consumer` instance
that collects the results as the requests get over. `SquareNumberRequest` will square the number with a random delay to give the impression of a long-running process that can complete at any time. `Consumer` instance will add the results from different `SquareNumberRequest` that will come random time instances.

Let's look at `FanOutFanIn` class that fans out the requests in async processes.
Let's look at `FanOutFanIn` class that fans out the requests in async processes.

```java
public class FanOutFanIn {
public static Long fanOutFanIn(
final List<SquareNumberRequest> requests, final Consumer consumer) {
public static Long fanOutFanIn(final List<SquareNumberRequest> requests, final Consumer consumer) {

ExecutorService service = Executors.newFixedThreadPool(requests.size());
ExecutorService service = Executors.newFixedThreadPool(requests.size());

// fanning out
List<CompletableFuture<Void>> futures =
requests.stream()
.map(
request ->
CompletableFuture.runAsync(() -> request.delayedSquaring(consumer), service))
.collect(Collectors.toList());
// fanning out
List<CompletableFuture<Void>> futures = requests
.stream()
.map(request -> CompletableFuture.runAsync(() -> request.delayedSquaring(consumer), service))
.collect(Collectors.toList());

CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

return consumer.getSumOfSquaredNumbers().get();
}
return consumer.getSumOfSquaredNumbers().get();
}
}
```

`Consumer` is used a callback class that will be called when a request is completed. This will aggregate
the result from all requests.
`Consumer` is used a callback class that will be called when a request is completed. This will aggregate the result from all requests.

```java
public class Consumer {

private final AtomicLong sumOfSquaredNumbers;
private final AtomicLong sumOfSquaredNumbers;

Consumer(Long init) {
sumOfSquaredNumbers = new AtomicLong(init);
}
Consumer(Long init) {
sumOfSquaredNumbers = new AtomicLong(init);
}

public Long add(final Long num) {
return sumOfSquaredNumbers.addAndGet(num);
}
public Long add(final Long num) {
return sumOfSquaredNumbers.addAndGet(num);
}
}
```

Request is represented as a `SquareNumberRequest` that squares the number with random delay and calls the
`Consumer` once it is squared.
Request is represented as a `SquareNumberRequest` that squares the number with random delay and calls the `Consumer` once it is squared.

```java
public class SquareNumberRequest {

private final Long number;
public void delayedSquaring(final Consumer consumer) {
private final Long number;

var minTimeOut = 5000L;
public void delayedSquaring(final Consumer consumer) {

SecureRandom secureRandom = new SecureRandom();
var randomTimeOut = secureRandom.nextInt(2000);
var minTimeOut = 5000L;

try {
// this will make the thread sleep from 5-7s.
Thread.sleep(minTimeOut + randomTimeOut);
} catch (InterruptedException e) {
LOGGER.error("Exception while sleep ", e);
Thread.currentThread().interrupt();
} finally {
consumer.add(number * number);
SecureRandom secureRandom = new SecureRandom();
var randomTimeOut = secureRandom.nextInt(2000);

try {
// this will make the thread sleep from 5-7s.
Thread.sleep(minTimeOut + randomTimeOut);
} catch (InterruptedException e) {
LOGGER.error("Exception while sleep ", e);
Thread.currentThread().interrupt();
} finally {
consumer.add(number * number);
}
}
}
}
```

## Class diagram
![alt-text](./etc/fanout-fanin.png)

![Fan-Out/Fan-In](./etc/fanout-fanin.png)

## Applicability

Use this pattern when you can divide the workload into multiple chunks that can be dealt with separately.
Appropriate in scenarios where tasks can be broken down and executed in parallel, especially suitable for data processing, batch processing, and situations requiring aggregation of results from various sources.

## Known Uses

* Large-scale data processing applications.
* Services requiring aggregation from multiple sources before delivering a response, such as in distributed caching or load balancing systems.

## Consequences

Benefits:

* Enhances performance by parallel processing.
* Increases responsiveness of systems.
* Efficient utilization of multi-core processor architectures.

Trade-offs:

* Increased complexity in error handling.
* Potential for increased overhead due to task synchronization and result aggregation.
* Dependency on the underlying infrastructure's ability to support concurrent execution.

## Related Patterns

* MapReduce: Similar to Fan-Out/Fan-In, MapReduce also involves distributing tasks across a number of workers (map) and aggregating the results (reduce), which is particularly useful for processing large data sets.
* [Command](https://java-design-patterns.com/patterns/command/): Command Pattern facilitates the decoupling of the sender and the receiver, akin to how Fan-Out/Fan-In decouples task submission from task processing.
* [Producer-Consumer](https://java-design-patterns.com/patterns/producer-consumer/): Works synergistically with Fan-Out/Fan-In by organizing task execution where producers distribute tasks that are processed by multiple consumers, and results are then combined, enhancing throughput and efficiency in data processing.

## Related patterns

Expand All @@ -114,4 +136,6 @@ Use this pattern when you can divide the workload into multiple chunks that can

* [Understanding Azure Durable Functions - Part 8: The Fan Out/Fan In Pattern](http://dontcodetired.com/blog/post/Understanding-Azure-Durable-Functions-Part-8-The-Fan-OutFan-In-Pattern)
* [Fan-out/fan-in scenario in Durable Functions - Cloud backup example](https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-cloud-backup)
* [Understanding the Fan-Out/Fan-In API Integration Pattern](https://dzone.com/articles/understanding-the-fan-out-fan-in-api-integration-p)
* [Understanding the Fan-Out/Fan-In API Integration Pattern](https://dzone.com/articles/understanding-the-fan-out-fan-in-api-integration-p)
* [Java Concurrency in Practice](https://amzn.to/3vXytsb)
* [Patterns of Enterprise Application Architecture](https://amzn.to/49QQcPD)
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import java.util.concurrent.Executors;

/**
* FanOutFanIn class processes long running requests, when any of the processes gets over, result is
* FanOutFanIn class processes long-running requests, when any of the processes gets over, result is
* passed over to the consumer or the callback function. Consumer will aggregate the results as they
* keep on completing.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import lombok.extern.slf4j.Slf4j;

/**
* Squares the number with a little timeout to give impression of long running process that return
* Squares the number with a little timeout to give impression of long-running process that return
* at different times.
*/
@Slf4j
Expand All @@ -39,7 +39,7 @@ public class SquareNumberRequest {
private final Long number;

/**
* Squares the number with a little timeout to give impression of long running process that return
* Squares the number with a little timeout to give impression of long-running process that return
* at different times.
* @param consumer callback class that takes the result after the delay.
* */
Expand Down
77 changes: 49 additions & 28 deletions feature-toggle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,39 @@ title: Feature Toggle
category: Behavioral
language: en
tag:
- Extensibility
- Decoupling
- Extensibility
- Feature management
- Scalability
---

## Also known as
Feature Flag

* Feature Flag
* Feature Switch

## Intent
A technique used in software development to control and manage the rollout of specific features or functionality in a
program without changing the code. It can act as an on/off switch for features depending on the status or properties of
other values in the program. This is similar to A/B testing, where features are rolled out based on properties such as
location or device. Implementing this design pattern can increase code complexity, and it is important to remember to
remove redundant code if this design pattern is being used to phase out a system or feature.

A technique used in software development to control and manage the rollout of specific features or functionality in a program without changing the code. It can act as an on/off switch for features depending on the status or properties of other values in the program. This is similar to A/B testing, where features are rolled out based on properties such as location or device. Implementing this design pattern can increase code complexity, and it is important to remember to remove redundant code if this design pattern is being used to phase out a system or feature.

## Explanation

Real-world Example
> This design pattern works really well in any sort of development, in particular mobile development. Say you want to
> introduce a feature such as dark mode, but you want to ensure that the feature works correctly and don't want to roll
> out the feature to everyone immediately. You write in the code, and have it switched off as default. From here, it is
> easy to turn on the code for specific users based on selection criteria, or randomly. This will also allow the feature
> to be turned off easily without any drastic changes to the code, or any need for redeployment or updates.

> This design pattern works really well in any sort of development, in particular mobile development. Say you want to introduce a feature such as dark mode, but you want to ensure that the feature works correctly and don't want to roll out the feature to everyone immediately. You write in the code, and have it switched off as default. From here, it is easy to turn on the code for specific users based on selection criteria, or randomly. This will also allow the feature to be turned off easily without any drastic changes to the code, or any need for redeployment or updates.
In plain words

> Feature Toggle is a way to introduce new features gradually instead of deployment all at once.
Wikipedia says
> A feature toggle in software development provides an alternative to maintaining multiple feature branches in source
> code. A condition within the code enables or disables a feature during runtime. In agile settings the toggle is
> used in production, to switch on the feature on demand, for some or all the users.

> A feature toggle in software development provides an alternative to maintaining multiple feature branches in source code. A condition within the code enables or disables a feature during runtime. In agile settings the toggle is used in production, to switch on the feature on demand, for some or all the users.
## Programmatic Example
This example shows Java code that allows a feature to show when it is enabled by the developer, and when a user is a
Premium member of the application. This is useful for subscription locked features.

This example shows Java code that allows a feature to show when it is enabled by the developer, and when a user is a Premium member of the application. This is useful for subscription locked features.

```java
public class FeatureToggleExample {
// Bool for feature enabled or disabled
Expand All @@ -55,32 +56,52 @@ public class FeatureToggleExample {
}
}
```
The code shows how simple it is to implement this design pattern, and the criteria can be further refined or broadened
should the developers choose to do so.

The code shows how simple it is to implement this design pattern, and the criteria can be further refined or broadened should the developers choose to do so.

## Class diagram
![alt text](./etc/feature-toggle.png "Feature Toggle")

![Feature Toggle](./etc/feature-toggle.png "Feature Toggle")

## Applicability

Use the Feature Toggle pattern when

* Giving different features to different users.
* Conditional feature access to different users and groups.
* Rolling out a new feature incrementally.
* Switching between development and production environments.
* Quickly disable problematic features
* External management of feature deployment
* Ability to maintain multiple version releases of a feature
* 'Hidden' deployment, releasing a feature in code for designated testing but not publicly making it available

## Known Uses

* Web development platforms use feature toggles to gradually roll out new features to users to ensure stability.
* Enterprise applications use feature toggles to enable or disable features during runtime to cater to different market needs.

## Consequences
Consequences involved with using the Feature Toggle pattern

* Code complexity is increased
* Testing of multiple states is harder and more time-consuming
* Confusion between friends on why features are missing
* Keeping documentation up to date with all features can be difficult
Benefits:

* Facilitates A/B testing and canary releases.
* Allows for quicker rollback and minimal risk deployments.
* Enables conditional feature execution without redeploying the application.

Trade-offs:

* Code complexity is increased.
* Testing of multiple states is harder and more time-consuming.
* Potential for technical debt if toggles remain in the code longer than necessary.
* Risk of toggle misconfiguration leading to unexpected behavior.

## Related Patterns

* [Strategy](https://java-design-patterns.com/patterns/strategy/): Both patterns allow changing the behavior of software at runtime. The Feature Toggle changes features dynamically, while the Strategy allows switching algorithms or strategies.
* [Observer](https://java-design-patterns.com/patterns/observer/): Useful for implementing feature toggles by notifying components of feature state changes, which allows dynamic feature modification without restarts.

## Credits

* [Martin Fowler 29 October 2010 (2010-10-29).](http://martinfowler.com/bliki/FeatureToggle.html)
* [Feature Toggle - Java Design Patterns](https://java-design-patterns.com/patterns/feature-toggle/)
* [Feature Toggle - Martin Fowler](http://martinfowler.com/bliki/FeatureToggle.html)
* [Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation](https://amzn.to/4488ESM)
* [Release It! Design and Deploy Production-Ready Software](https://amzn.to/3UoeJY4)
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,12 @@ public PropertiesFeatureToggleVersion(final Properties properties) {
/**
* Generate a welcome message based on the user being passed and the status of the feature toggle.
* If the enhanced version is enabled, then the message will be personalised with the name of the
* passed {@link User}. However if disabled then a generic version fo the message is returned.
* passed {@link User}. However, if disabled then a generic version fo the message is returned.
*
* @param user the {@link User} to be displayed in the message if the enhanced version is enabled
* see {@link PropertiesFeatureToggleVersion#isEnhanced()}. If the enhanced version is
* enabled, then the message will be personalised with the name of the passed {@link
* User}. However if disabled then a generic version fo the message is returned.
* User}. However, if disabled then a generic version fo the message is returned.
* @return Resulting welcome message.
* @see User
*/
Expand Down
Loading

0 comments on commit 08eded1

Please sign in to comment.