$30 off During Our Annual Pro Sale. View Details »

Killing a Giant - a Practical Guide Through the Martin Fowler's Strangler Fig Pattern

Killing a Giant - a Practical Guide Through the Martin Fowler's Strangler Fig Pattern

Back in 2019, our company was preparing for a period of fast growth. One of the key blockers to that growth was a monolithic application called Accounts. Built initially around 2014 as a rapidly developed proof of concept, it quickly became a central piece for the customer interaction, a billing system, an auth server, a support ticketing system, the project lifecycle management system. The engineering debt grew exponentially with every new feature added. The system needed to be replaced.

Martin Fowler described an interesting solution for a practically zero-downtime migration project from a monolithic application to -- something else. Instead of replacing an app with a single big bang, let’s build the new application around the existing one, and let them slowly take over its responsibilities until we’re ready to just delete it entirely. The concept was stolen from a natural phenomenon of Australian strangler figs growing around the host tree until they kill it.

What could possibly go wrong with such an approach, you may ask yourself. Well -- as we learned in the last couple of years -- quite a lot of things! To name a few: shared state between the legacy and the replacement application, designing the stopgap communication between the applications, balancing the development of the new features with the migration of the existing ones.

Join me for the session where we’ll discuss the theory and practice of the Strangler Vine Pattern around a Drupal 7 monolith, with a special focus on all the embarrassing errors we made along the way.

Branislav Bujisic

June 25, 2022
Tweet

More Decks by Branislav Bujisic

Other Decks in Technology

Transcript

  1. Killing a Giant
    A practical guide through
    the Martin Fowler’s
    Strangler Fig pattern

    View Slide

  2. Today’s topic
    evolved with
    time

    View Slide

  3. Drupal 7
    monolith
    Billing
    Subscription
    management
    Payments
    Dunning
    User management Oauth2 server
    Support ticket
    management
    UX
    Identity provider
    Trials
    Reporting (BI)
    Perfectly extendable to
    support a rapidly growing
    startup

    View Slide

  4. Design stamina
    hypothesis
    “Is it worth the effort to
    design software well?”
    - Martin Fowler 2007

    View Slide

  5. Drupal 7 becomes a huge source of technical
    debt over the years because:
    + Abuse of the hook system
    + Uncontrollable changes of the object
    state
    + Mutually dependent code (circular
    dependencies!!!), contrib/custom
    code hell, patches...
    + Configuration, content and code,
    managed inconsistently in code or in
    databases; difficult revisioning etc.
    + Infrastructure stuck at old version
    of PHP
    Technical debt

    View Slide

  6. A cunning plan:
    microservices
    Billing
    Subscription
    management
    Payments
    Dunning
    User management
    Oauth2 server
    Support ticket
    management
    UX
    Identity provider
    Trials Reporting (BI)

    View Slide

  7. Replacing a huge legacy system may
    be problematic…
    + Designing a system from the ground up in a
    holistic way is ridiculously complicated
    + The data is too complex to be transformed
    and migrated in a single act
    + There is a lot of risk in releasing
    overwhelming changes in a big bang!
    + A down time must be avoided at all costs

    View Slide

  8. Martin Fowler’s
    Strangler Fig Application
    design pattern

    View Slide

  9. A way to manage risk when
    modernizing or rewriting a
    large, monolithic system.

    View Slide

  10. View Slide

  11. [...] gradually create a new system around the edges of
    the old, letting it grow slowly over several years until
    the old system is strangled.
    Martin Fowler, 2004

    View Slide

  12. Phases of the Strangler Application
    Transform
    Create a new site
    Eliminate
    Remove functionality from the old site.
    Phase 1:
    Phase 2:
    Phase 3:
    Coexist
    Leave the existing site. As a new feature was built, redirect to the new site.

    View Slide

  13. Phases of the Strangler Application
    2nd iteration
    Build a service
    …and another
    service
    Phase 1:
    Phase 2:
    Phase 3:
    Phase 4:
    Create the
    new service
    Add a proxy
    Build another service
    Proxy to
    the new
    service
    Iterate
    until
    perfect
    Clean
    up the
    monolith
    …and
    another
    Phase 4:

    View Slide

  14. Phase 1:
    Transform
    The Proxy
    The New Service
    /feature/(.*)
    The Legacy App
    /(.*)
    + First create a proxy between the
    application and the users. The proxy
    does not do anything other than
    passing all the traffic to the
    application.
    + Start building the replacement
    application in the background.
    Ensure it looks and behaves the
    same as the legacy application.
    RewriteEngine On
    # Serve feature from new service for internal network
    RewriteCond expr “%{HTTP:X-FORWARDED-FOR} -ipmatch ‘192.168.0.1/24’”
    RewriteRule ^/feature/(.*)$ ${NEW_SERVICE_URL}/$1 [P,L]
    # Proxy everything else to legacy application
    RewriteRule ^/(.*) ${LEGACY_URL}/$1 [P]
    ProxyPassReverse / ${LEGACY_URL}/

    View Slide

  15. Phase 2:
    Coexist
    + Proxy requests to the new service
    as soon as it’s done.
    + Serve the rest from the legacy
    application.
    + Start building another
    replacement application in the
    background.
    The Newer Service
    /other-feature/(.*)
    The Proxy
    The New Service
    /feature/(.*)
    The Legacy App
    /(.*)

    View Slide

  16. Phase 3:
    Eliminate
    + After all the features have been
    built in the replacement
    application(s), the legacy app
    serves no more traffic.
    + Switch off the legacy app.
    The Proxy
    The Legacy App
    /(.*)
    The Newer Service
    /other-feature/(.*)
    The Proxy
    The New Service
    /feature/(.*)
    The Legacy App
    Orphaned service
    The Last Service
    /last-feature/(.*)

    View Slide

  17. The strengths
    ● True zero downtime
    ● Reduced risk of failures due to
    frequent small releases
    ● Faster delivery of the value for
    customers
    ● Lesser cognitive load for the
    engineering team

    View Slide

  18. The
    opportunities
    ● Data driven refactoring
    + The proxy is a central place to collect the customer
    requests, log them and allow their analysis to enable
    prioritization of the refactoring, as well as fixing
    broken user experience.
    ● Decoupled frontend
    + Deciding for the proxy to be exclusively an API proxy
    allows the frontend engineering team to grow
    independently; to centralize the API documentation;
    and provides immediate value to the customers.
    ● Mutually independent teams and choice
    of the best tool for the job
    + Microservices allow using different technologies
    inside each one, thus avoiding the one-size-fits-all
    approach.

    View Slide

  19. The result is
    beautiful and it
    makes Total
    Sense™
    Billing
    Subscription
    management
    User management
    Support ticket
    management
    UX
    Trials
    Reporting (BI)
    API Proxy
    + Single unified UX for great
    customer experience.
    + API proxy capable of load balancing
    if needed.
    + Segregated services, each with own
    tech stack and engineering team.

    View Slide

  20. View Slide

  21. The Weaknesses
    and Threats
    (the W’s and T’s in SWOT)

    View Slide

  22. User data
    migration 2h
    Weakness:
    data migration
    Legacy App
    The Proxy
    Auth Service
    Problem: Inconsistent state during the
    migration. Where to proxy the traffic?
    Solution: Close for maintenance

    Problem: Long downtime
    Solution: Data migration strategy which
    does the most of the work in background

    Problem: Rollback strategy in case of
    failure?
    Solution: Snapshots
    Solution: Synchronization back to Legacy
    App?

    View Slide

  23. Weakness:
    shared state
    Legacy App
    The Proxy
    Auth Service
    Subscription
    mgmt
    User management
    Billing
    A customer
    Company
    Name
    Address
    Tax ID
    Email
    An owner
    An ID
    Address
    country
    A user
    Email
    Password
    Address
    country
    An ID
    Problem: Services will be relying on the
    same data! How to synchronize it between
    them?
    Solution: Use the existing restful APIs to
    GET and PATCH when needed
    Keeping services in sync…

    View Slide

  24. Weakness:
    shared state
    Billing
    Subscription
    management
    User management
    Support ticket
    management
    Trials
    Reporting (BI)
    Problem: Lots of point to point API
    communication that bring to tight
    coupling.
    Solution: Message broker

    Problem: Problem of deletion of an
    entity in a service that then needs to
    notify all the other services of it.
    Solution: Tombstones
    Solution: Message broker

    Problem: Message brokers also need
    engineering – both for development
    and maintenance

    View Slide

  25. Threat:
    fragmentation
    of entity data
    Problem: “Store only what you will use”
    Problem: Business intelligence
    depends on reports
    SELECT *
    FROM users
    WHERE uid = 123
    Solution: Data lake (e.g. fivetran + big
    query)
    Solution: Event sourcing?
    The User Entity from Drupal 7
    Legacy App
    The Proxy
    Auth Service
    Subscription
    mgmt
    User management
    An owner
    Billing
    A customer A user
    Company
    Name
    Address
    Tax ID
    Email
    An ID
    Email
    Password
    Address
    country
    An ID
    Address
    country

    View Slide

  26. Threat: a new
    feature
    Legacy App
    The Proxy
    Subscription
    mgmt
    Billing
    Subscription
    management
    Usage
    records
    WIP
    ?
    Things to consider when deciding where
    to build a newly requested feature:
    + The state of the WIP service and
    the minimal change necessary to
    make the new feature
    + The size of the new feature and the
    amount of engineering debt that
    would be created if implemented
    in the legacy application
    + The urgency of the new feature
    New product line

    View Slide

  27. Threat: keeping
    backward
    compatibility
    (At Any Cost™)
    POST /provision POST
    /orgs/{id}/provision
    POST /provision
    The Proxy
    Legacy App
    Subscription
    management
    GET /orgs
    if org # = 0: POST /orgs
    if org # > 1: Throw Exception
    Provision project
    POST /orgs/{id}/stopgap-api

    View Slide

  28. Other
    weaknesses
    and threats
    ● Heavy on engineering resources
    + Maintenance overhead for each service
    + Engineers specialize
    + Silos within the team
    + Tiring joggling between building new and
    rebuilding old features
    ● Requires real good monitoring
    + Health of the each of the services
    + X-service debugging
    ● Fundamental changes break
    processes in other teams
    + CSEs, TAMs, even sales need to be onboarded
    + Major overhaul of internal and external
    documentation

    View Slide

  29. Is it worth the effort?

    View Slide

  30. Thank you!
    Branislav Bujisic
    Director of Accounts Engineering,
    Platform.sh
    [email protected]

    View Slide