DEV Community

Bruno Souza
Bruno Souza

Posted on

Open/Closed Principle (OCP) in MuleSoft: APIs and Flows That Evolve Without Breaking

What is OCP?

The Open/Closed Principle states that a component should be open for extension but closed for modification. This means you should be able to add new functionality to the system without altering existing code, minimizing the risk of introducing errors in already tested components.

In the context of MuleSoft, this involves designing flows that allow the addition of new behaviors or integrations without modifying the main flows.


Why Is OCP Important in Integrations?

Imagine that your order system needs to add support for the PayPal payment method, alongside existing methods like credit card and bank slip. If the payment logic is embedded directly in the main flow, any change would require modifying existing code—violating OCP.

This approach can lead to:

  • Regression risks: Changes may break existing functionalities.
  • High maintenance costs: Each new feature requires alterations to already implemented flows.
  • Low scalability: The main flow becomes increasingly complex and harder to manage.

How to Apply OCP in the Payment System?

1. Practical Example – Before (Violating OCP)

In this example, the main flow contains routing logic for existing methods (creditCard and bankSlip). Adding a new method (like PayPal) would require modifying the main flow.


<flow name="processPayment">
    <choice>
        <when expression="#[payload.paymentMethod == 'creditCard']">
            <flow-ref name="processCreditCard"/>
        </when>
        <when expression="#[payload.paymentMethod == 'bankSlip']">
            <flow-ref name="processBankSlip"/>
        </when>
        <otherwise>
            <set-payload value="Unsupported payment method"/>
        </otherwise>
    </choice>
</flow>

<!-- Existing subflows -->
<sub-flow name="processCreditCard">
    <!-- Logic for credit card -->
    <logger message="Processing payment via credit card"/>
</sub-flow>

<sub-flow name="processBankSlip">
    <!-- Logic for bank slip -->
    <logger message="Processing payment via bank slip"/>
</sub-flow>

Enter fullscreen mode Exit fullscreen mode

Problem:

To add PayPal, you would need to modify the main flow by adding a new condition, violating OCP.


2. Practical Example – After (Applying OCP)

Here, we use a YAML file to configure payment methods dynamically. New methods can be added without altering the main flow.

Step 1: Configuration in YAML (payment-config.yaml)

payment:
  flow:
    creditCard: processCreditCard
    bankSlip: processBankSlip
    payPal: processPayPal # New method added
Enter fullscreen mode Exit fullscreen mode

Step 2: Main Flow with Dynamic Routing


<flow name="processPayment">
    <!-- Retrieve subflow name from YAML -->
    <set-variable 
        variableName="paymentFlow" 
        value="#[p('payment.flow.' ++ payload.paymentMethod)]"/>

    <!-- Dynamic routing -->
    <choice>
        <when expression="#[vars.paymentFlow != null]">
            <flow-ref name="#[vars.paymentFlow]"/>
        </when>
        <otherwise>
            <raise-error type="ORDER:PAYMENT_METHOD_NOT_SUPPORTED"/>
        </otherwise>
    </choice>
</flow>

<!-- Existing subflows (unchanged) -->
<sub-flow name="processCreditCard">
    <logger message="Processing payment via credit card"/>
</sub-flow>

<sub-flow name="processBankSlip">
    <logger message="Processing payment via bank slip"/>
</sub-flow>

<!-- New subflow for PayPal -->
<sub-flow name="processPayPal">
    <logger message="Processing payment via PayPal"/>
</sub-flow>

Enter fullscreen mode Exit fullscreen mode

How Does This Respect OCP?

  1. Extensibility Without Modification:

    To add PayPal, simply:

    • Add payPal: processPayPal in YAML.
    • Create the processPayPal subflow.
    • No changes to the main flow are required.
  2. Decoupling:

    The main flow depends only on the subflow name configured externally, not on specific implementations.


Benefits of This Approach

  • Reduced Risks: New methods can be added without touching the main flow.
  • Centralized Configuration: Payment methods are managed via YAML.
  • High Cohesion: Each subflow has a single responsibility (SRP).

Checklist for Applying OCP in MuleSoft

  • [ ] The main flow is not modified when new functionalities are added.
  • [ ] New behaviors are configured externally (YAML/properties).
  • [ ] Specialized subflows are independent of the main flow.

Next Steps

Now that we’ve covered OCP, let’s move on to the next principle: Liskov Substitution Principle (LSP) — ensuring consistency in API responses.

← Previous Principle: SRP | → Next Principle: LSP


SOLID in MuleSoft – The Art of Designing Evolutionary Integrations

Complete Series:

  1. Introduction
  2. Single Responsibility Principle (SRP)
  3. Open/Closed Principle (OCP)
  4. Liskov Substitution Principle (LSP)
  5. Interface Segregation Principle (ISP)
  6. Dependency Inversion Principle (DIP)

Top comments (0)