All Projects → lzakrzewski → simple-prepaid-card

lzakrzewski / simple-prepaid-card

Licence: other
Simplified model of a prepaid card. The card holds a balance in GBP and customers can make transactions in GBP.

Programming Languages

PHP
23972 projects - #3 most used programming language
Gherkin
971 projects
HTML
75241 projects
ApacheConf
554 projects
Nginx
273 projects
Makefile
30231 projects

simple-prepaid-card

Build Status

This repository is Proof of concept (POC) to demonstrate a simplified model of a prepaid card. The card holds a balance in GBP and customers can make transactions in GBP.

Sandbox

Sandbox is available here: http://178.62.42.204/. At any time user can reset all sandbox data using a red button from navbar.

Design and Architecture

DDD and Bounded contexts

As in real life, the Customer and the Merchant in the shop are not focused how the CreditCardProvider deals with the transactions on card internally. So, the application was split for 2 main bounded contexts, which are independent individually:

CoffeeShop:

  • Contains Merchant and Customer aggregates and their behavior (buy a product by Customer, authorize a Merchant, capture an authorization etc.)

CreditCard:

  • Contains CreditCard aggregate and behavior (load/block/unblock/charge funds)

It's highly possible that in future the responsibility of CreditCard will by moved to an external 3rd party credit card provider like (https://stripe.com, https://www.braintreepayments.com/).
In order to easy switch CreditCardProvider the CreditCard context was completely decoupled from CoffeeShop context.
CoffeeShop context has an interface CreditCardProvider and current implementation is LocalCreditCardProvider which is a bridge to CreditCard context.
If the external CreditCardProvider will be chosen then CreditCardProvider need to have another implementation like StripeCreditCardProvider.

  • Aggregates were marked with SimplePrepaidCard\Common\Model\Aggregate interface,
  • Value objects with SimplePrepaidCard\Common\Model\ValueObject interface,
  • Domain events with SimplePrepaidCard\Common\Model\DomainEvent interface.

Layered Application Architecture

Each context of that application (CoffeeShop, CreditCard) has layers:

  • Application - This layer coordinates the application activity.
  • Infrastructure - This layer handles interaction with infrastructure. It contains an implementation of adapters to an infrastructure.
  • Model - It handles business rules related to the context. It contains aggregates which trigger domain events.

CQRS and single responsibility

I used SimpleBus/MessageBus to implement CQRS pattern. Each command has only one responsibility and those responsibilities were described with Gherkin scenarios:

CoffeeShop context commands:

CreditCard context commands:

Read model and write model are completely separated.
To expose that fact the write model was realized with Sqlite database and read model with Redis cache.

Hexagonal architecture

Each adapter to an infrastructure has an interface extracted and implementation within Infrastructure layer.
Examples:
StatementQuery => RedisStatementQuery
CustomerRepository => DoctrineORMRepository
CreditCardProvider => LocalCreditCardProvider

It allows me to quickly switch between implementations in a case when I decide for e.g. to use DoctrineODM instead of DoctrineORM.
It is helpful for test purposes as well. Here is another implementation od credit card provider TestCreditCardProvider which allows me to define a behavior of credit card provider for test purposes.

Coupling with framework

The application has framework agnostic model. The entry point for the application model is Symfony controller within the Bundle. The bundle contains only framework related stuff (views) and configuration of them.

Provisioning and Deployment

Here is a simple script to firstly provision http://178.62.42.204/ host with Ansible and then deploy the application on it. Each deployment is triggered in automated way after each successful build with Travis CI. I used encrypted ssh key to allow Travis CI deploy my host.

Testing

An application has wide test-suite:

  • composer static-analysis - (php-cs-fixer was used to fix automatically the broken code standards)
  • composer spec - (PHPSpec was used specification testing of business model)
  • composer integration - (PHPUnit was used for test integration with Sqlite database, Redis cache and Symfony framework)
  • composer behat - (Behat was used for acceptance test of business requirements)
  • composer e2e - It's a test-suite that simulates using a whole application on production. It's for ensuring that everything is able to work together (framework, two bounded contexts etc)
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].