specification


layout: pattern
title: Specification
folder: specification
permalink: /patterns/specification/
categories: Behavioral
tags:

– Data access

Also known as

Filter, Criteria

Intent

Specification pattern separates the statement of how to match a
candidate, from the candidate object that it is matched against. As well as its
usefulness in selection, it is also valuable for validation and for building to
order.

Explanation

Real world example

There is a pool of different creatures and we often need to select some subset of them.
We can write our search specification such as “creatures that can fly”, “creatures heavier than 500 kilograms”, or as a combination of other search specifications, and then give it to the party that will perform the filtering.

In Plain Words

Specification pattern allows us to separate the search criteria from the object that performs the search.

Wikipedia says

In computer programming, the specification pattern is a particular software design pattern, whereby business rules can be recombined by chaining the business rules together using boolean logic.

Programmatic Example

If we look at our creature pool example from above, we have a set of creatures with certain properties.
Those properties can be part of a pre-defined, limited set (represented here by the enums Size, Movement and Color); but they can also be continuous values (e.g. the mass of a Creature).
In this case, it is more appropriate to use what we call “parameterized specification”, where the property value can be given as an argument when the Creature is instantiated, allowing for more flexibility.
A third option is to combine pre-defined and/or parameterized properties using boolean logic, allowing for near-endless selection possibilities (this is called “composite specification”, see below).
The pros and cons of each approach are detailed in the table at the end of this document.

public interface Creature {
  String getName();
  Size getSize();
  Movement getMovement();
  Color getColor();
  Mass getMass();
}

And Dragon implementation looks like this.

public class Dragon extends AbstractCreature {

  public Dragon() {
    super("Dragon", Size.LARGE, Movement.FLYING, Color.RED, new Mass(39300.0));
  }
}

Now that we want to select some subset of them, we use selectors. To select creatures that fly, we should use MovementSelector.

public class MovementSelector extends AbstractSelector<Creature> {

  private final Movement movement;

  public MovementSelector(Movement m) {
    this.movement = m;
  }

  @Override
  public boolean test(Creature t) {
    return t.getMovement().equals(movement);
  }
}

On the other hand, when selecting creatures heavier than a chosen amount, we use MassGreaterThanSelector.

public class MassGreaterThanSelector extends AbstractSelector<Creature> {

  private final Mass mass;

  public MassGreaterThanSelector(double mass) {
    this.mass = new Mass(mass);
  }

  @Override
  public boolean test(Creature t) {
    return t.getMass().greaterThan(mass);
  }
}

With these building blocks in place, we can perform a search for red creatures as follows:

    List<Creature> redCreatures = creatures.stream().filter(new ColorSelector(Color.RED))
      .collect(Collectors.toList());

But we could also use our parameterized selector like this:

    List<Creature> heavyCreatures = creatures.stream().filter(new MassGreaterThanSelector(500.0)
      .collect(Collectors.toList());

Our third option is to combine multiple selectors together. Performing a search for special creatures (defined as red, flying, and not small) could be done as follows:

    AbstractSelector specialCreaturesSelector = 
      new ColorSelector(Color.RED).and(new MovementSelector(Movement.FLYING)).and(new SizeSelector(Size.SMALL).not());

    List<Creature> specialCreatures = creatures.stream().filter(specialCreaturesSelector)
      .collect(Collectors.toList());

More on Composite Specification

In Composite Specification, we will create custom instances of AbstractSelector by combining other selectors (called “leaves”) using the three basic logical operators.
These are implemented in ConjunctionSelector, DisjunctionSelector and NegationSelector.

public abstract class AbstractSelector<T> implements Predicate<T> {

  public AbstractSelector<T> and(AbstractSelector<T> other) {
    return new ConjunctionSelector<>(this, other);
  }

  public AbstractSelector<T> or(AbstractSelector<T> other) {
    return new DisjunctionSelector<>(this, other);
  }

  public AbstractSelector<T> not() {
    return new NegationSelector<>(this);
  }
}
public class ConjunctionSelector<T> extends AbstractSelector<T> {

  private List<AbstractSelector<T>> leafComponents;

  @SafeVarargs
  ConjunctionSelector(AbstractSelector<T>... selectors) {
    this.leafComponents = List.of(selectors);
  }

  /**
   * Tests if *all* selectors pass the test.
   */
  @Override
  public boolean test(T t) {
    return leafComponents.stream().allMatch(comp -> (comp.test(t)));
  }
}

All that is left to do is now to create leaf selectors (be it hard-coded or parameterized ones) that are as generic as possible,
and we will be able to instantiate the AbstractSelector class by combining any amount of selectors, as exemplified above.
We should be careful though, as it is easy to make a mistake when combining many logical operators; in particular, we should pay attention to the priority of the operations.\
In general, Composite Specification is a great way to write more reusable code, as there is no need to create a Selector class for each filtering operation.
Instead, we just create an instance of AbstractSelector “on the spot”, using tour generic “leaf” selectors and some basic boolean logic.

Comparison of the different approaches

| Pattern | Usage | Pros | Cons |
|—|—|—|—|
| Hard-Coded Specification | Selection criteria are few and known in advance | + Easy to implement | – Inflexible |
| | | + Expressive |
| Parameterized Specification | Selection criteria are a large range of values (e.g. mass, speed,…) | + Some flexibility | – Still requires special-purpose classes |
| Composite Specification | There are a lot of selection criteria that can be combined in multiple ways, hence it is not feasible to create a class for each selector | + Very flexible, without requiring many specialized classes | – Somewhat more difficult to comprehend |
| | | + Supports logical operations | – You still need to create the base classes used as leaves |

Class diagram

alt text

Applicability

Use the Specification pattern when

  • You need to select a subset of objects based on some criteria, and to refresh the selection at various times.
  • You need to check that only suitable objects are used for a certain role (validation).

Related patterns

  • Repository

Credits

spatial-partition


layout: pattern
title: Spatial Partition
folder: spatial-partition
permalink: /patterns/spatial-partition/
categories: Behavioral
tags:

  • Performance

– Game programming

Intent

As explained in the book Game Programming Patterns by Bob Nystrom, spatial partition pattern helps to

efficiently locate objects by storing them in a data structure organized by their positions.

Explanation

Say, you are building a war game with hundreds, or maybe even thousands of players, who are clashing on the battle field. Each player’s position is getting updated every frame. The simple way to handle all interactions taking place on the field is to check each player’s position against every other player’s position:

public void handleMeLee(Unit units[], int numUnits) {
  for (int a = 0; a < numUnits - 1; a++)
  {
    for (int b = a + 1; b < numUnits; b++)
    {
      if (units[a].position() == units[b].position())
      {
        handleAttack(units[a], units[b]);
      }
    }
  }
}

This will include a lot of unnecessary checks between players which are too far apart to have any influence on each other. The nested loops gives this operation an O(n^2) complexity, which has to be performed every frame since many of the objects on the field may be moving each frame.
The idea behind the Spatial Partition design pattern is to enable quick location of objects using a data structure that is organised by their positions, so when performing an operation like the one above, every object’s position need not be checked against all other objects’ positions. The data structure can be used to store moving and static objects, though in order to keep track of the moving objects, their positions will have to be reset each time they move. This would mean having to create a new instance of the data structure each time an object moves, which would use up additional memory. The common data structures used for this design pattern are:

  • Grid
  • Quad tree
  • k-d tree
  • BSP
  • Boundary volume hierarchy

In our implementation, we use the Quadtree data structure which will reduce the time complexity of finding the objects within a certain range from O(n^2) to O(nlogn), decreasing the computations required significantly in case of large number of objects.

Class diagram

alt text

Applicability

This pattern can be used:

  • When you need to keep track of a large number of objects’ positions, which are getting updated every frame.
  • When it is acceptable to trade memory for speed, since creating and updating data structure will use up extra memory.

Credits

singleton


layout: pattern
title: Singleton
folder: singleton
permalink: /patterns/singleton/
categories: Creational
tags:

– Gang of Four

Intent

Ensure a class only has one instance, and provide a global point of
access to it.

Explanation

Real world example

There can only be one ivory tower where the wizards study their magic. The same enchanted ivory tower is always used by the wizards. Ivory tower here is singleton.

In plain words

Ensures that only one object of a particular class is ever created.

Wikipedia says

In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system.

Programmatic Example

Joshua Bloch, Effective Java 2nd Edition p.18

A single-element enum type is the best way to implement a singleton

public enum EnumIvoryTower {
  INSTANCE;
}

Then in order to use

EnumIvoryTower enumIvoryTower1 = EnumIvoryTower.INSTANCE;
EnumIvoryTower enumIvoryTower2 = EnumIvoryTower.INSTANCE;
assertEquals(enumIvoryTower1, enumIvoryTower2); // true

Class diagram

alt text

Applicability

Use the Singleton pattern when

  • There must be exactly one instance of a class, and it must be accessible to clients from a well-known access point
  • When the sole instance should be extensible by subclassing, and clients should be able to use an extended instance without modifying their code

Typical Use Case

  • The logging class
  • Managing a connection to a database
  • File manager

Real world examples

Consequences

  • Violates Single Responsibility Principle (SRP) by controlling their own creation and lifecycle.
  • Encourages using a global shared instance which prevents an object and resources used by this object from being deallocated.
  • Creates tightly coupled code. The clients of the Singleton become difficult to test.
  • Makes it almost impossible to subclass a Singleton.

Credits

sharding


layout: pattern
title: Sharding
folder: sharding
permalink: /patterns/sharding/
categories: Behavioral
tags:

  • Performance

– Cloud distributed

Intent

Sharding pattern means divide the data store into horizontal partitions or shards. Each shard has the same schema, but holds its own distinct subset of the data.
A shard is a data store in its own right (it can contain the data for many entities of different types), running on a server acting as a storage node.

Class diagram

alt text

Applicability

This pattern offers the following benefits:

  • You can scale the system out by adding further shards running on additional storage nodes.
  • A system can use off the shelf commodity hardware rather than specialized (and expensive) computers for each storage node.
  • You can reduce contention and improved performance by balancing the workload across shards.
  • In the cloud, shards can be located physically close to the users that will access the data.

Credits

service-locator


layout: pattern
title: Service Locator
folder: service-locator
permalink: /patterns/service-locator/
categories: Architectural
tags:

  • Game programming

– Performance

Intent

Encapsulate the processes involved in obtaining a service with a
strong abstraction layer.

Class diagram

alt text

Applicability

The service locator pattern is applicable whenever we want
to locate/fetch various services using JNDI which, typically, is a redundant
and expensive lookup. The service Locator pattern addresses this expensive
lookup by making use of caching techniques ie. for the very first time a
particular service is requested, the service Locator looks up in JNDI, fetched
the relevant service and then finally caches this service object. Now, further
lookups of the same service via Service Locator is done in its cache which
improves the performance of application to great extent.

Typical Use Case

  • When network hits are expensive and time consuming
  • Lookups of services are done quite frequently
  • Large number of services are being used

Consequences

  • Violates Interface Segregation Principle (ISP) by providing pattern consumers with an access
    to a number of services that they don’t potentially need.
  • Creates hidden dependencies that can break the clients at runtime.

Credits

service-layer


layout: pattern
title: Service Layer
folder: service-layer
permalink: /patterns/service-layer/
categories: Architectural
tags:

– Data access

Intent

Service Layer is an abstraction over domain logic. Typically
applications require multiple kinds of interfaces to the data they store and
logic they implement: data loaders, user interfaces, integration gateways, and
others. Despite their different purposes, these interfaces often need common
interactions with the application to access and manipulate its data and invoke
its business logic. The Service Layer fulfills this role.

Class diagram

alt text

Applicability

Use the Service Layer pattern when

  • You want to encapsulate domain logic under API
  • You need to implement multiple interfaces with common logic and data

Credits

serverless


layout: pattern
title: Serverless
folder: serverless
permalink: /patterns/serverless/
categories: Architectural
tags:

– Cloud distributed

Serverless

Serverless eliminates the need to plan for infrastructure and let’s you focus on your
application.

Following are optimization katas you should be aware of while building a serverless
applications

  • The Lean function
    • Concise logic – Use functions to transform, not transport (utilize some of the
      integration available from the provider to transport), and make sure you read only
      what you need
    • Efficient/single purpose code – avoid conditional/routing logic and break down
      into individual functions, avoid “fat”/monolithic functions and control the
      dependencies in the function deployment package to reduce the load time for your
      function
    • ephemeral environment – Utilize container start for expensive initializations
  • Eventful Invocations
    • Succinct payloads – Scrutinize the event as much as possible, and watch for
      payload constraints (async – 128K)
    • resilient routing – Understand retry policies and leverage dead letter queues
      (SQS or SNS for replays) and remember retries count as invocations
    • concurrent execution – lambda thinks of it’s scale in terms of concurrency and
      its not request based/duration based. Lambda will spin up the number of instances
      based on the request.
  • Coordinated calls
    • Decoupled via APIs – best practice to setup your application is to have API’s as
      contracts that ensures separation of concerns
    • scale-matched downstream – make sure when Lambda is calling downstream
      components, you are matching scale configuration to it (by specifying max
      concurrency based on downstream services)
    • secured – Always ask a question, do I need a VPC?
  • Serviceful operations
    • Automated – use automated tools to manage and maintain the stack
    • monitored applications – use monitoring services to get holistic view of your
      serverless applications

Intent

Whether to reduce your infrastructure costs, shrink the time you spend on ops tasks,
simplify your deployment processes, reach infinite scalability, serverless cuts time
to market in half.

Explanation

Serverless computing is a cloud computing execution model in which the cloud provider
dynamically manages the allocation of machine resources. Pricing is based on the
actual amount of resources consumed by an application, rather than on pre-purchased
units of capacity.

Class diagram

alt text

Serverless framework

Serverless is a toolkit for deploying and operating serverless architectures.

(Function as a Service or “FaaS”)

The term ‘Serverless’ is confusing since with such applications there are both server
hardware and server processes running somewhere, but the difference to normal
approaches is that the organization building and supporting a ‘Serverless’ application
is not looking after the hardware or the processes – they are outsourcing this to a vendor.

Some of the Serverless Cloud Providers are

https://serverless.com/framework/docs/providers/aws/
https://serverless.com/framework/docs/providers/azure/
https://serverless.com/framework/docs/providers/openwhisk/
https://serverless.com/framework/docs/providers/google/
https://serverless.com/framework/docs/providers/kubeless/
https://serverless.com/framework/docs/providers/spotinst/
https://serverless.com/framework/docs/providers/webtasks/

Anything that triggers an Lambda Function to execute is regarded by the Framework as
an Event. Most of the Serverless Cloud Providers support following Events

  • Http
  • PubSub Events
  • scheduled

AWS supports processing event generated from AWS Services (S3/Cloudwatch/etc) and
using aws as a compute engine is our first choice.

(Backend as a Service or “BaaS”)

This example creates a backend for ‘persons’ collection which uses DynamoDB NoSQL
database service also provided by Amazon.

AWS lambda function implementation

AWS Lambda SDK provides pre-defined interface
com.amazonaws.services.lambda.runtime
.RequestHandler
to implement our lambda function.

public class LambdaInfoApiHandler implements RequestHandler<Map<String, Object>, ApiGatewayResponse> {

  private static final Logger LOG = Logger.getLogger(LambdaInfoApiHandler.class);
  private static final Integer SUCCESS_STATUS_CODE = 200;


  @Override
  public ApiGatewayResponse handleRequest(Map<String, Object> input, Context context) {

  }
}

handleRequest method is where the function code is implemented. Context provides
useful information about Lambda execution environment. AWS Lambda function needs a
deployment package. This package is either a .zip or .jar file that contains all the
dependencies of the function.

serverless.yml contains configuration to manage deployments for your functions.

Run example in local

Pre-requisites

  • Node.js v6.5.0 or later.
  • Serverless CLI v1.9.0 or later. You can run npm install -g serverless to install it.
  • An AWS account. If you don’t already have one, you can sign up for a free trial that includes 1 million free Lambda requests per month.
  • Set-up your Provider Credentials. Watch the video on setting up credentials

build and deploy

  • cd serverless
  • mvn clean package
  • serverless deploy --stage=dev --verbose

Based on the configuration in serverless.yml serverless framework creates following
resources

  • CloudFormation stack for S3 (ServerlessDeploymentBucket)
  • IAM Role (IamRoleLambdaExecution)
  • CloudWatch (log groups)
  • API Gateway (ApiGatewayRestApi)
  • Lambda function
  • DynamoDB collection

The command will print out Stack Outputs which looks something like this

endpoints:
  GET - https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/info
  POST - https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/api/person
  GET - https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/api/person/{id}
CurrentTimeLambdaFunctionQualifiedArn: arn:aws:lambda:us-east-1:xxxxxxxxxxx:function:lambda-info-http-endpoint-dev-currentTime:4
ServiceEndpoint: https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev
ServerlessDeploymentBucketName: lambda-info-http-endpoin-serverlessdeploymentbuck-2u8uz2i7cap2

access the endpoint to invoke the function.

Use the following cURL commands to test the endpoints

curl -X GET \
  https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/info \
  -H 'cache-control: no-cache'
curl -X POST \
  https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/api/person \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -d '{
    "firstName": "Thor",
    "lastName": "Odinson",
    "address": {
        "addressLineOne": "1 Odin ln",
        "addressLineTwo": "100",
        "city": "Asgard",
        "state": "country of the Gods",
        "zipCode": "00001"
    }
}'
curl -X GET \
  https://xxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev/api/person/{id} \
  -H 'cache-control: no-cache'

Credits

servant


layout: pattern
title: Servant
folder: servant
permalink: /patterns/servant/
categories: Behavioral
tags:

– Decoupling

Intent

Servant is used for providing some behavior to a group of classes.
Instead of defining that behavior in each class – or when we cannot factor out
this behavior in the common parent class – it is defined once in the Servant.

Class diagram

alt text

Applicability

Use the Servant pattern when

  • When we want some objects to perform a common action and don’t want to define this action as a method in every class.

Credits

semaphore


layout: pattern
title: Semaphore
folder: semaphore
permalink: /patterns/semaphore/
categories: Concurrency
tags:

– Performance

Also known as

Counting Semaphore

Intent

Create a lock which mediates access to a pool of resources.
Only a limited number of threads, specified at the creation
of the semaphore, can access the resources at any given time.
A semaphore which only allows one concurrent access to a resource
is called a binary semaphore.

Class diagram

alt text

Applicability

Use a Semaphore when

  • You have a pool of resources to allocate to different threads
  • Concurrent access to a resource could lead to a race condition

Credits

saga


layout: pattern
title: Saga
folder: saga
permalink: /patterns/saga/
categories: Concurrency
tags:

– Cloud distributed

Also known as

This pattern has a similar goal with two-phase commit (XA transaction)

Intent

This pattern is used in distributed services to perform a group of operations atomically.
This is an analog of transaction in a database but in terms of microservices architecture this is executed
in a distributed environment

Explanation

A saga is a sequence of local transactions in a certain context. If one transaction fails for some reason,
the saga executes compensating transactions(rollbacks) to undo the impact of the preceding transactions.
There are two types of Saga:

  • Choreography-Based Saga.
    In this approach, there is no central orchestrator.
    Each service participating in the Saga performs their transaction and publish events.
    The other services act upon those events and perform their transactions.
    Also, they may or not publish other events based on the situation.

  • Orchestration-Based Saga
    In this approach, there is a Saga orchestrator that manages all the transactions and directs
    the participant services to execute local transactions based on events.
    This orchestrator can also be though of as a Saga Manager.

Class diagram

alt text

Applicability

Use the Saga pattern, if:

  • you need to perform a group of operations related to different microservices atomically
  • you need to rollback changes in different places in case of failure one of the operation
  • you need to take care of data consistency in different places including different databases
  • you can not use 2PC(two phase commit)

Credits

粤ICP备15017284号