Skip to content

Ed Plant's CV

Introduction

I, Ed Plant, am a UK-based Senior Software Architect (IC) for Expend, a FinTech software company handling millions of pounds of customer card spend per year.

I am a Product Engineer able to reason about our customers' business needs and workflows. At the same time, I have a strong understanding of how our system currently works, opinions on how it should work, and can design and implement change safely.

Skills:

  • Python (Starlette, Pydantic, SQLalchemy)
  • AWS (Lambda, ECS, RDS, DynamoDB, SNS, SQS, S3, Cloudwatch, VPC, Route 53, KMS)
  • PostgreSQL and PL/pgSQL
  • GitHub Actions CI/CD
  • Pulumi (Infrastructure as Code alternative to Terraform)
  • TDD
  • Contract/Acceptance Testing
  • Microservices and Event Driven Architecture
  • Dependency Injection Pattern
  • Progressive Rollouts

Contact me on LinkedIn.

2021-Present Senior Software Architect @ Expend

Expend is a UK FinTech expenses software company:

  • ~5k users
  • ~5k cards
  • ~£28m spend made through our platform in ~45k customer transactions in 2025
  • fewer than ten developers
  • ~200 Lambdas, ~40 microservices
  • webservices and event-driven architecture

In the last five years I've improved Expend's developer experience, platform stability, and increased velocity to implement new customer-facing features 🚀.

Integration to a Card Issuer

In 2025-26 I led the implementation effort to integrate with a new Card Issuer partner, Adyen.

I performed a deep analysis of our previous integration, communicated with the partner's consultant to understand their APIs, webhooks and reports, and planned how our use cases could be achieved.

I pushed for some significant deliberate architectural changes compared to the old system, based on pain points I had experienced:

  • it would not be Expend's responsibility to maintain a 'ledger' of account balances, instead we would trust Adyen to provide reliable account balances for generating account statements
  • for card spending realtime authorisation decisions, the partner's transaction rules would support all our use cases, while being more performant than a call-out system like we had before
  • we would publish a stream of transactions to a downstream unified transaction service, supporting multiple sources to support parallel running with the old system

I acted as a project manager to raise epics in a clear sequence, where there were blocking dependencies. I assigned the required front-end and mobile tasks to the relevant team members, and had brief communication sessions (inspired by 'three amigos') before starting work, to check shared understanding.

I collaborated closely with a team-mate on the back-end work, pairing sometimes to make a decision, or work on something tricky, otherwise reviewing each other's PRs. We used the TDD approach and had high confidence in the quality and correctness of what we were shipping, which was borne out by later production usage.

The migration to the new Card provider has gone smoothly with 300+ customers migrated in 6 months, with only one day pre-arranged spending downtime per customer.

The system I architected has stood up well, now that it is being used by real customers in production: the major decisions about trade-offs have not been regretted. The Adyen team said they were impressed with the speed at which Expend integrated with them.

Distributed Monolith -> Microservices

Problem

I inherited an architecture which looked superficially like microservices but was monolithic in practice (shared databases, one folder of shared code, one CICD pipeline), without getting the advantages of either approach.

Solution

As a pre-requisite to allow safe refactoring for each service, I created more acceptance tests which asserted the API contracts with other services independent of the internal behaviour.

With 12 factor app principles in mind, I pulled apart the monolith to distinct projects with clear domain boundaries and dependencies. Each project can now be deployed independently, without blocking PRs for other projects in the monorepo.

I refactored each service to use a dependency injection pattern instead of a singleton 'resource manager' used anywhere and everywhere, so it's more explicit at every level how different pieces fit together, and easier to mock in unit tests.

I split out chunks from the shared code folder into many discrete libraries published with semantic versioning, and then installed only into the projects which need them.

Benefit

Publishing a new library no longer risks breaking all services simultaneously. The trade-off is that promoting the new library version across multiple/all projects is more of a chore.

Introducing clearer boundaries, explicit dependencies and looser coupling has improved confidence, lowered risk and increased deployment frequency. Each developer in the team can easily deploy to production multiple times per day, if required.

By making deployments small and frequent, a regression is easy to trace back to the breaking change and our mean time to recovery (MTTR) is usually less than 2 hours.

Unfortunately we still have some shared databases for complex legacy systems where the risk of change was too high to justify a rewrite. However, we haven't extended that antipattern for any new work since I joined. In some cases we managed to replace direct database access of foreign data with HTTP calls to the owning service, even though both services ultimately still use the same database.

Previous Roles

Education