Quick step towards anticorruption-layer

24 September 2023

The topic is vast, but this particular post will be brief.
Today, we're diving into the world of refactoring. In most cases, you'd want to employ an anti-corruption layer in your domain rather than any other layer. However, occasionally, exceptions might arise.

The general idea is to refactor existing code by encapsulating some high-level concept without actually performing much changes.
It helps to clarify actions in your domain and hide details of those actions. This allows you further modify and adjust the implementation in a way you see fit without worrying too much about backward compatibility.

To put it plain


// Before applying layer
class OrderController
{
    //...
    function placeOrder(Request $request): Response
    {
        $items = $this->getItems($request);
        $order = new Order($this->customer);
        $order->addItems($items);
        $this->orderRepository->save($order);
        $this->stateMachine->transition($order, OrderState::CREATED);
        $this->eventDispatcher->dispatch(new OrderPlaced($order));

        return new Response(['id' => $order->getId()]);
    }
}



// The anticorruption-layer
class PlaceOrder
{
    function execute(Customer $customer, ItemsCollection $items): Order
    {
        $order = new Order($customer);
        $order->addItems($items);
        $this->orderRepository->save($order);
        $this->stateMachine->transition($order, OrderState::CREATED);
        $this->eventDispatcher->dispatch(new OrderPlaced($order));

        return $order;
    }
}


// After applying layer
class OrderController
{
    //...
    function placeOrder(Request $request): Response
    {
        $items = $this->getItems($request);
        $order = $this->placeOrder->execute($this->customer, $items);

        return new Response(['id' => $order->getId()]);
    }
}

That's it. This approach is likely familiar to you, and that's what anticorruption-layer basically is.
You expose high-level contract that's unlikely to change and hide lower level details within it. At this point, you're free to refactor those details as you see fit.
The key is to ensure that the behavior remains compatible: order placed, fsm transitioned, entity stored in repository, event dispatched.

By adopting this approach, you can maintain your technical debt in a linear fashion and prevent it from gradually accumulating each time you make changes to the affected process.

Don't take everything plain: we have to challenge and prove the information we face.

Here is what really helps me to do it.