Sudarshan Dhakal

Sudarshan Dhakal

Senior Software Engineer · C# / .NET · Hammond, LA

Eleven years building on .NET, the last six at Veriforce. There I led the breakup of a 200K-line monolith into 40+ event-driven services, moved 25TB of documents out of SQL Server, and built the GitHub Copilot agents and skills our team now uses for day-to-day modernization work.

services carved out of a 200K-LOC monolith
40+
services carved out of a 200K-LOC monolith
~100M documents moved from SQL Server to S3
25TB+
~100M documents moved from SQL Server to S3
GitHub Copilot custom agents built and in use
20+
GitHub Copilot custom agents built and in use
shipping C# / .NET in production
11 yrs
shipping C# / .NET in production

Case studies

Three projects that show how I work.

01 · Veriforce · Architecture

Breaking up a 200K-line .NET monolith without a rewrite

Incremental, strangler-fig decomposition of the core compliance platform into 40+ event-driven services while it kept serving 100K+ users.

services in production
40+
services in production
downtime deployments
Zero
downtime deployments
less memory / CPU after the .NET 10 upgrades
~35% / ~30%
less memory / CPU after the .NET 10 upgrades
Toggle details

The problem

The contractor-compliance platform ran as one 200K+ LOC .NET application: one deployable, one database, and every release coordinated across every team. A big-bang rewrite was not an option for a system customers rely on for compliance.

What I did

  • Put a gateway in front of the monolith so endpoints could move to new services one at a time while the monolith kept serving everything else.
  • Drew service boundaries along DDD bounded contexts. Each service owns its data in PostgreSQL, and cross-context communication moved from shared tables to events on Kafka and RabbitMQ.
  • Used CQRS where read and write load diverged, keeping hot read paths off the transactional model.
  • Every extraction ships through the same CI/CD pipeline with xUnit and integration tests and staged rollouts, so no single cutover is a big risk.
  1. Clients
    web · API · integrations
  2. Gateway
    routes per endpoint
  3. Monolith
    shrinking scope
  4. New services
    .NET 8/10 · DDD/CQRS
  5. Event bus
    Kafka · RabbitMQ
Traffic moves endpoint by endpoint; services communicate through events, not shared tables.
02 · Veriforce · Data

Moving 25TB of documents out of SQL Server

Migrated ~100M compliance documents stored as database blobs into Amazon S3 with restartable, idempotent pipelines and no downtime.

moved to S3
25TB+
moved to S3
documents
~100M
documents
downtime
Zero
downtime
Toggle details

The problem

About 100 million documents lived as binary columns in SQL Server. The database had grown past 25TB, which made backups and restores slow, storage expensive, and put heavy I/O on the same server handling transactional traffic.

What I did

  • Batch pipeline copies each blob to S3 under a deterministic key, so any batch can be re-run safely. A retry never creates a duplicate.
  • Progress is checkpointed per batch, so the job can stop, fail, or be throttled at peak hours and pick up where it left off.
  • Each object is verified in S3 before the database row is repointed and the blob removed.
  • The application read path moved to S3 while the migration ran, so there was never a maintenance window.
  1. SQL Server
    document blobs
  2. Batch reader
    checkpointed
  3. S3 upload
    deterministic keys
  4. Verify
    size · hash
  5. Repoint + purge
    row → S3 key
Every step is safe to repeat, so a failed batch is just re-run.
03 · Veriforce · AI-assisted engineering

Making Copilot agents reliable on a legacy codebase

Built 20+ GitHub Copilot custom agents and a library of agent skills that encode how we upgrade, extract, test, and review .NET services.

custom agents
20+
custom agents
use in upgrades, extraction, tests, review
Daily
use in upgrades, extraction, tests, review
agent mode, coding agent, CLI, code review
4 tools
agent mode, coding agent, CLI, code review
Toggle details

The problem

With 40+ services and a monolith still being dismantled, a lot of the work is repetitive but risky: .NET version upgrades, EF6 to EF Core, pulling code out of the monolith, writing tests around old behaviour. Off-the-shelf AI assistance got the easy parts right and missed our conventions on the rest.

What I did

  • Split the work into narrow custom agents (upgrade planner, service extractor, test writer, PR reviewer, incident triage) instead of one general-purpose agent.
  • Wrote agent skills (SKILL.md) that capture how we actually do things: .NET upgrades, EF6 to EF Core, config migration, our service template, PR review, and Datadog log and trace analysis.
  • Characterization tests are written before any refactor, so every agent change is checked against existing behaviour.
  • Agent-authored PRs go through the same CI gates and human review as everyone else’s. The agent saves time; it does not skip review.
  1. Task / issue
  2. Custom agent
    + matching skills
  3. Tests first
    lock current behaviour
  4. Change on a branch
  5. CI + human review
    then merge
A failing gate goes back to the agent with the error. Nothing merges on the agent’s word alone.

How I work with AI

I use AI heavily, and I treat its output like a new teammate’s pull request: useful, fast, and reviewed. The work is making it reliable. That means narrow agents, written-down conventions, and tests that decide whether a change is correct.

  1. Plan
    agent drafts, I approve
  2. Skills load
    our conventions
  3. Tests first
    characterization
  4. Implement
    small, reviewable diffs
  5. Gates
    build · tests · analyzers
  6. Human review
    then merge
The loop I run for agent-driven modernization work.

Narrow agents beat one big one

An agent that only upgrades EF6 to EF Core is easier to trust, test and fix than one that “modernizes the service”.

Conventions live in skills, not in people’s heads

If a reviewer keeps leaving the same comment, it becomes part of a skill so the agent gets it right the first time.

Tests decide, not the model

Behaviour is locked with tests before the refactor. A confident explanation from the agent is not evidence.

Same bar as human code

Agent PRs get the same CI gates and code review. Nothing gets a shortcut because a tool wrote it.

From the skill library

Each skill is a SKILL.md an agent loads only when the task needs it.

Upgrades
dotnet-version-upgradeef6-to-efcorenewtonsoft-to-system-text-jsonconfig-to-options
Extraction
extract-bounded-contextservice-templateevent-contract
Quality
characterization-testspr-reviewapi-docs
Operations
datadog-log-triagedatadog-trace-analysisrelease-workflow

What I don’t hand to an agent

  • Cutover and rollback plans for data migrations
  • Authentication, authorization and anything security-sensitive
  • Service boundaries and other architecture decisions
  • Anything that touches production directly
.github/skills/ef6-to-efcore/SKILL.md
---
name: ef6-to-efcore
description: >
  Upgrade a data-access project from Entity Framework 6 to EF Core
  following our conventions. Use when a project references EntityFramework 6.x.
---

1. Run the characterization-tests skill first; stop if tests don't pass on main.
2. Swap packages: EntityFramework -> Microsoft.EntityFrameworkCore.SqlServer.
3. Replace EntityTypeConfiguration<T> with IEntityTypeConfiguration<T>;
   one configuration class per aggregate, in /Persistence/Configurations.
4. Register the DbContext through AddDbContextPool in Program.cs, never in a static.
5. Lazy loading stays OFF. Add explicit Include() calls and note each one in the PR.
6. Build, run the full test suite, and open a draft PR using the pr-review checklist.
Simplified example of a skill’s structure.

Experience

  1. Mar 2020 – Present

    Senior Software Engineer · Veriforce LLC

    Contractor-compliance SaaS platform

    • Led the incremental decomposition of a 200K+ LOC .NET monolith into 40+ event-driven services behind a strangler-fig gateway, with zero downtime across every extraction.
    • Drove successive runtime upgrades to .NET 10 across every service, lowering memory ~35% and CPU ~30%.
    • Migrated 25TB+ (~100M documents) from SQL Server to Amazon S3 with idempotent, checkpointed pipelines and per-object verification, with no downtime.
    • Delivered 99.9% availability and sub-200 ms p95 latency (Datadog) across core APIs serving 100K+ users, profiling and rewriting the SQL Server and PostgreSQL queries behind the slowest endpoints.
  2. Jul 2017 – Mar 2020

    Software Engineer · Emerson Automation Solutions

    AgileOps alarm-management software for industrial operations

    • Launched a real-time monitoring dashboard (.NET Core, React) giving operations teams live visibility across 500+ manufacturing assets, shortening incident response 30%.
    • Integrated React incrementally into a legacy ASP.NET MVC application, converting its 2 largest pages to reusable components and halving UI development time.
  3. Jun 2015 – Jun 2017

    Software Developer · Lamar Advertising

    • Built an inventory and scheduling system (ASP.NET WebForms, JavaScript, SQL Server) handling 50K+ daily transactions for digital billboards across 200+ locations.
    • Streamlined the client registration workflow, taking onboarding from 15 minutes to 3 and deflecting 40% of support tickets.

Education: B.S. Computer Science, Southeastern Louisiana University. The full history is on the resume.

What I work with

Languages & frameworks
C#.NET 8/10ASP.NET CoreEF CoreLINQDapperMediatRTypeScriptReactAngular
AI tooling
GitHub Copilot agent modeCopilot coding agentCopilot CLICopilot code reviewClaude CodeCursor
Agent engineering
Custom agentsagent skillscustom instructionsCopilot modernization for .NET
Cloud
AWS LambdaECS/ECRSQS/SNSS3RDSAPI GatewayAzure FunctionsAzure Application Insights
Data & messaging
SQL ServerPostgreSQLRedisCosmos DBAmazon S3KafkaRabbitMQAzure Service Bus
Architecture
MicroservicesDDDCQRSevent-driven designClean Architecturestrangler-fig migrationOAuth 2.0/JWT
Delivery
DockerKubernetesGitHub ActionsAzure DevOpsJenkinsOctopus DeployDatadogSerilogxUnitNUnitMoqTDD

Get in touch

Email is the fastest way to reach me. I usually reply within a day.