Legacy, but not left alone
Builds that pass again, dependencies updated in order, tests around the parts people fear, a deploy that one person can run. Then the backlog of small cuts.
C# and .NET, 2009 to 2021
Ten years of C#, .NET, ASP.NET, Entity Framework and XAML, including my own chat product on sharded .NET servers with 30,000 concurrent users. Since 2017 TypeScript and Node.js. I keep legacy .NET alive, stabilize it, and when it is time, move it over without a rewrite from scratch.
Available from November 2026 · Wrocław, Poland (CET), remote

Builds that pass again, dependencies updated in order, tests around the parts people fear, a deploy that one person can run. Then the backlog of small cuts.
Strangler pattern: a new TypeScript service in front, one endpoint at a time, both systems live until the numbers agree. I have moved a desktop 3D product to the browser with a .NET backend kept in place.
LINQ to array methods, Task<T> to Promise<T>, records to interfaces, nullable reference types to | null. The demo below does the mechanical part so the conversation can be about the design.
Horizontally scaled, sharded C# servers, a moderation panel and automated NSFW detection for a product with 1.5 million downloads. I know what production .NET looks like at 3 a.m.
Proof
Problem, what I did, result. Client names only where I am allowed to use them.
See also: SaaS & MVP
See also: Games
See also: React
One foot in the door
Two ways to see how I work before you commit to a sprint. Fixed scope, a number in writing after a short call.
I read the repo, CI, tests, security and the parts the team avoids. You get a written report with findings ranked by risk, a plan with milestones and a go or no-go you can defend. I have run this for a large software house before its clients saw the code.
Send me the diff that worries you. Within a few days you get line-level comments, the three things I would change first and whether I would merge it.
Live demo
A rule-based translator, running entirely in your browser: properties to fields, async Task<T> to Promise<T>, LINQ chains to array methods, records to interfaces, nullable types to unions. It is deliberately simple. The point is to show which parts of a migration are mechanical and which need a human.
Demo loading…
Paste a class from your codebase. If the output is wrong, that line is exactly where the migration needs thought.
How it works
You describe the product and the problem. I ask the questions I would ask on day one. If I am not the right person, I say so and point you to someone who is.
A short written plan follows: what we build first, what we measure, how we work together and what it costs. No slide deck.
The first slice ships in the first week: deployed, measured, reviewable. From there the work is paced by what the numbers say.
Fit check
Working style
A bug is fixed or consciously closed, never parked. Alerts and error tracking in every project, so I learn about problems before the client does.
Hundreds of pull requests reviewed. I review for the product and its reasons. The code comes second.
PostHog in every project from day one. A tracking plan per feature and dashboards leadership actually reads.
FAQ

A free 30-minute call. You bring the problem, I bring questions. No prices on this page because scope comes first.
If I am the wrong person I will say so on the call and point you to someone better.
After you book: a calendar invite, then the call. Nothing else to fill in.
Available from November 2026 · B2B contract or employment · Wrocław, Poland (CET), remote