Documentation for a newer release is available. View Latest
Esta página no está disponible actualmente en Español. Si lo necesita, póngase en contacto con el servicio de asistencia de Icon (correo electrónico)

Development Best Practices

Simplify scope of orchestration flows

End to end payment journeys are normally broken up into 2 or more discrete IPF orchestration flows, each representing well bound pieces of domain specific functionality.

Rationale - Breaking up flows by domain specific functionality areas and reducing the complexity and scope of the flows makes them:

  • Simpler to understand for other BAs and engineers

  • Easier to maintain since the impact of changes is smaller

  • Easier to test since the flows can be tested in isolation

Implications - The flows that make up a payment journey should be broken down into discrete functional areas. These typically may include:

  • Payment initiation (order management)

  • Payment execution

  • Clearing & settling

Separate processing for different payment types

Functionally different payment types should have different orchestration flow(s), for example incoming and outgoing payments.

Rationale - Different payment types, for example incoming PACS.008 messages compared to outgoing PAIN.001 messages, are functionally different from a payment processing perspective and therefore they will require different orchestration flows.

Implications - Payment orchestration flows should be split up by different processing types:

  • Incoming vs outgoing payments

  • Different payment message types - PAIN.001, PACS.003, PACS.008 etc

  • Bulk vs individual payments

  • Domestic vs international payments

Different flows will consume data from different message queues allowing different types of payments to be prioritised according to requirements.

It is worth noting that initiation flows are normally CSM/Scheme agnostic.

Reuse components of payment flows where possible

Although different payments types may have different orchestration flows, these flows can & should contain reusable components shared between the flows (e.g. shared components/libraries, sub flows).

Rationale - Processing of different payment types is likely to contain a lot of commonality:

  • Sanctions checking

  • Duplicate checking

  • Common integrations with external domains

Implications - IPF encourages the re-use of flow components by creating reusable flow libraries. These libraries can then be reused in multiple flows.

See these pages for examples and gudies Create reusable libraries & Subflows

Manage notifications from orchestration flows

It is possible to send notifications directly from IPF flows, however IPF has other mechanisms for sending notifications which may be more efficient than adding extra complexity to flows

Rationale - IPF has multiple options to allow clients to receive notifications

  • Adding specific actions to the flow DSL to send notifications when certain states are reached

  • Consuming domain / events from generic Processing Data topic.

  • Using the payments status Notification Service

Implications - Adding notifications to a flow adds complexity and latency to that flow. This may be the best approach when the notification requires complex logic and uses data from the flow’s processing context.

However when notifications are simple and frequent (i.e. sending a notification whenever a new state is reached), consider using either IPF processing data or the payments notification service.

Avoid too many sequenced decision within flows

An excessive number of decision states within a flow suggests too many disparate use cases are being covered by a single flow, as well as causing an exponentially larger number of potential paths through the flow.

Rationale - If there are large number of decisions in a processing flow, this may be because the flow is trying to cover too many business use cases, and hence has too much complexity.

In addition, IPF uses a BDD framework to test flows as part of the build process; during these tests every possible route through a flow is tested. Sequential decisions can exponentially increase the number of possible paths through the flow making the BDDs unmanageable.

Implications - Split large flows, with multiple decisions, into smaller flows and place decisions about which flow to call in the preceding flow.

For example create extra execution flows and place decision logic about which one to call in the initiation flow.

Data management within flows

When interacting with external domains and functions, try to use the minimum data set required for that interaction rather than unnecessarily sending large data payloads.

Rationale - Data which is sent to external domains, and used in other flow processing, is stored on domain and system events. These events are then stored in the database and streamed to other systems (e.g. to the ODS via IPF processing data).

Using unnecessarily large data objects for these interactions causes unnecessary data to be stored and sent, hence consuming unneeded system resources.

Implications - When designing interfaces and interactions with external systems, ensure that the data contracts only require data necessary for that business use case.

Worth noting as well that data is gathered within the ODS (by uowId) and supports the aggregation of data across your flows and external domain interactions.

Implementing logic within flows

Not all logic needs to be implemented in the flow orchestration (ie within the DSL flow). It may be preferable to implement some logic within Java code or even an external service.

Rationale - Sometimes there is complexity in a payments journey which is caused by an interaction with a specific external system (e.g. a quirk of the accounting system); however that complexity would be removed if that system were to be replaced in the future.

Implications - Generally if the logic relates to a specific flow decision or state transition for the processing of the payment, then it belongs in the flow.

However if it is relating to complexity of a specific system, rather than the general payment transaction flow, then it may be best encapsulating that logic in a connector (java code) or better still a separate service. Then if that system is replaced in the future, then the specific logic can be replaced without having to change the DSL of the payments flow.

Make sure flows are versioned

All flows should be versioned so that they can be updated cleanly.

Rationale - If changes are made to a flow and deployed whilst there are in-flight transactions (for example adding a new state) then it may not be possible to continue processing those in flight transactions after the new version is deployed.

Versioning flows solves this by ensuring that all in-flight transactions continue processing on the same version of the flow on which they were initiated.

Implications - Ensure that all flows are versioned, you can find instructions and guidance in the Tutorial.

You should consider creating a new version for core orchestration changes including adding a new decision (hence new route in the flow), a new state, new external domain interaction, a change in event behaviour.

Terminal States

Always ensure that orchestration flows end in a "terminal" state.

Rationale - IPF flows are removed from memory when they reach a terminal state. Therefore if the final state of a flow is not marked as terminal, then the flow will remain in memory depending on the Passivation Strategy and will not be marked as complete.

Implications - Always ensure that the final state in a flow is marked as terminal:

terminal states

Passivation of long-running orchestration flows

When a flow has paused in a particular state, waiting for an input from a long running process, it may be necessary to passivate the flow to prevent it from taking up memory in the Akka cluster.

Rationale - Some flows have states that are known to be long-running, for example:

  • Sanctions checks

  • Human tasks

  • Consolidated posting

  • Waiting for payment execution date

During this time the flow will remain in memory by default unless action is taken to passivate the flow.

Implications - When a flow enters one of these states, it may be performant to programmatically passivate the flow

Correlation with external systems

Ensure that correlation ids are always unique when communicating with external domains.

Rationale - When making asynchronous interactions with external domains, IPF uses a correlation store to associate request / response pairs. Entries in this correlation store are retrieved using a correlation id and therefore every interaction with an external domain, across every flow, needs to use a unique correlation id.

Implications - Ensure that all interactions with external domains have a unique correlation id. You can read more about correlation here Message Association & Correlation Data Model

Handling In-Flight Transactions

When using Flow Versioning, and deploying a new version of your flow, you need to consider and be aware of what happens with current In-Flight transactions.

Rationale - There could be cases where a transaction was started on V1 of the flow but is paused waiting on a response/instruction to a long-running process external to the flow. During this time you have deployed V2 of the flow but the in-flight transactions are still not in a terminal state.

This scenario is perfectly valid and when the old transactions on V1 flow resume they will continue on the flow which they started on, in this case the V1 flow. Any new transactions that have been initiated since the upgrade would run on the V2 flow.

Implications - It’s not possible for a transaction initiated using one version of a flow (e.g. V1) to be resumed using another (e.g. V2). You either need to resume the flow on the original (V1) flow or initiate a new flow on the new version (V2).

Flow Design Example

The following is an example of an outgoing credit transfer where the bank is acting as a debtor agent.

The process flows are split into three sub-domains: Initiation Management, Execution and Clearing & Settlement.

In the case of the bulk payment processing, the initiation flow will encapsulate a debulker component; this will perform the function of debulking the payment instruction and then instigating an execution flow for each of the instructions within the bulk.

flow design example

The following lists the functionality that is typically performed in each sub domain; this is indicative, rather than fixed, and will be depend on the bank’s specific requirements:

Payment Initiation / Instruction Management

  • Payments Domain Functionality

    • Data transformation non-ISO20022 formats

    • Parsing + syntax check ISO20022 formats

    • Debulk

    • Duplicate check

    • Semantic validations

    • Business validations (account status, customer agreement validation, …​)

    • Apply customer processing settings

    • Automated enrichment / repair (incl. account proxies)

    • Human interventions (enrichment, repair, …​) (UIs implementation specific dev)

    • Scheduling

    • Determine payment execution system

    • Generate notifications

    • Standing order management

  • External Domain Functionality (with which payment domain needs to interact)

    • Fraud check

    • Account verification

    • Retrieve (customer) processing settings

Payment Execution

  • Payment Domain Functionality

    • Determine payment type and service level

    • Select CS (clearing & settlement) agent (aka Credit Routing)

    • Apply bank processing settings

    • Apply customer processing settings

    • Human interventions (UIs are implementation specific dev)

    • Date calculations

    • BEN/OUR charges calculation

    • Customer charges calculation

    • Payment status update (to Instruction Management)

  • External Domains Functionality (with which payment domain needs to interact):

    • Account (status) validation

    • Sanction screening

    • Funds reservation

    • Currency conversion

    • Generate and post bookings (batch/single bookings)

Clear & Settle

  • Payment Domain Functionality

    • Schedule bulking

    • Bulk transactions

    • Generate outbound message(s) (pacs.008, pacs.009COV, …​)

    • Payment status update (to Execution)

    • Reconciliation report processing

  • External Domains Functionality (with which payment domain needs to interact)

    • Check/update liquidity position

    • Generate and post settlement bookings (batch/single bookings)