Workshops / 2024–Present

Private rooms,
public conclusions.

Sessions I have run for product teams. The rooms were closed; the conclusions were not worth keeping to myself.

Every session here was built for one team with one problem, and none of them were open sign-ups. What is published below is the part that survives the team: the failure modes, the trade-offs, and the code. Where a company or a client name would identify them, the entry says so instead of hiding the gap.

Most of these started as a question one engineer could not get answered by reading documentation — usually because the documentation described the mechanism and not the consequence. That gap is the reason the sessions exist.

I take sessions on C#, Java, .NET, SQL, system design, and distributed systems, and adapt the material to what the team already knows so nobody spends an afternoon being taught things they use every day.

What I run

Sessions teams
ask for.

Most requests arrive as a specific stuck point rather than a topic. These are the areas I can run a session on, adapted to what the team already knows.

C# and .NET

Where the framework stops and the runtime starts. Request pipelines, async continuations, DI lifetimes, EF Core concurrency, and the API decisions that get expensive to reverse.

C#ASP.NET CoreEF Core

Java and Spring Boot

Service boundaries that survive a second squad, transaction boundaries that do not span a network call, and a testing strategy that survives the refactor.

JavaSpring BootREST

SQL and data modelling

Schema design, indexing, isolation levels, and migrations against a live table. Where correctness and throughput turn out to be the same decision.

SQLSchema designMigrations

System design

Reviews of real designs rather than textbook ones. Constraints, the options that were rejected, and the failure mode that decides the shape of the system.

Design reviewsTrade-offsADRs

Distributed systems

Idempotency, retries, partial failure, and what actually happens when a dependency is late. Taken from systems that ran in production, not from diagrams.

Failure modesIdempotencyRetries

Event-driven architecture

Broker selection, partition strategy, consumer rebalancing, replay, and schema evolution. Usually the session that shows a team holding two incompatible answers.

KafkaRabbitMQService BusDebezium

Cloud and delivery

Azure and GCP platforms, containers, Kubernetes, Terraform, and a CI pipeline that produces the same artefact every time instead of most times.

AzureGCPDockerKubernetesTerraform

Payments and security

Threat modelling for integrations that move money: idempotent retries, webhook verification, secret handling, and an audit trail worth having afterwards.

Threat modellingPaymentsSecrets
01

Failure handling in event-driven systems

A team could publish but could not reason about what happened after a consumer crashed mid-batch. We rebuilt the failure story around idempotency keys, a poison-message path, and replay that operators had actually rehearsed.

KafkaIdempotencyReplay
2025
02

Leaving a self-managed Kafka cluster

Four brokers, no capacity plan, and a broker upgrade that ate a weekend. The session covered what changes when the platform runs the cluster anyway: compatibility gaps, partition mapping, dual running, cutover, and the rollback nobody had tested.

KafkaAzure Event HubsMigration
2025
03

Change data capture without another integration

Two systems that had to agree, maintained by hand, forever. We replaced the nightly job with logical replication into a stream, then spent most of the session on the part that is actually hard: schema evolution and what a consumer does when it receives a shape it has never seen.

CDCDebeziumSchema evolution
2025
04

Async and await: what the compiler generates

Built for a team whose services passed load tests and still timed out in production. We read a state machine out loud, traced a continuation onto a thread pool, and found where a request was blocking something that looked asynchronous.

C#AsyncThreading
2025
05

The .NET request pipeline, from socket to response

Middleware order is not a matter of taste, and a team was paying for it. Starting at Kestrel and ending at the endpoint, this mapped every hop a request makes, then showed which orderings silently disable features you are still paying to license.

ASP.NET CoreKestrelMiddleware
2024
06

Designing a public API you can still version later

A contract had shipped that could never change without breaking clients. We rewrote it around an honest error model, pagination that does not lie, and an OpenAPI document treated as a build artefact rather than documentation written afterwards.

RESTOpenAPIContract design
2024
07

Row-level concurrency in EF Core

Two users editing one record, last write winning, no signal to either. The session covered isolation levels as they actually behave on the target database, when optimistic concurrency is the right answer, when it is not, and why retry loops turn a race condition into a deadlock.

EF CoreTransactionsConcurrency
2024
08

Threat modelling a payments integration

A third-party callback was the only part of the flow nobody owned. We drew the trust boundaries, moved the secret handling, made the audit trail answerable, and scoped what genuinely had to live inside the cardholder data environment.

SecurityPaymentsAudit
2024

Your team has one of these.

Most sessions above began as a single engineer's question that turned out to be a design problem. If that is what you are looking at, bring the constraint and the failure, not a proposed solution — the solution is the easy half.