Loading...
Martin Li, Software Engineer II at JPMorgan Chase

Hi, I'm Martin Li

Software Engineer II @ JPMorgan Chase

I build the systems people depend on, and then I look after them. For the past four years that has meant Java, Python, and React at JPMorgan Chase: the fund platform portfolio managers open every morning, and the quieter work underneath it that keeps the lights on. I am finishing an M.S. in Computer Science at Georgia Tech, and most evenings I am building something of my own.

Open to Software Engineer roles Plano, TX AWS Certified M.S. CS (AI/ML), Georgia Tech

5+
Years Experience
35+
Services I Help Run
3.6
Georgia Tech GPA
35+
Microservices migrated
Spring Boot and Jakarta upgrade, co-led
99.9%
Uptime held
Across a 30+ application portfolio
40%
Faster deployments
Containerized delivery and CI/CD
25+
People using what I built
Portfolio managers and internal teams

Where I Fit

I work across the whole stack, so I map onto a few different job titles. Here is the honest version of what I have actually shipped in each, so you can decide for yourself.

Full-Stack Engineer

React and TypeScript front ends on Java and Spring Boot microservices. The fund platform I work on handles onboarding, due diligence, factsheets, and portfolio management for 25+ portfolio managers and internal teams. I have also sole-authored a compliance tool end to end, from the SQL up to the screen.

ReactTypeScriptJavaSpring BootSQL Server

Backend / Platform Engineer

Microservices and REST APIs with OpenAPI contracts, Liquibase-managed schema changes, and tuned SQL. I co-led a Spring Boot and Jakarta migration across 35+ services and wrote the team's incremental upgrade guide after watching too many version jumps go badly.

JavaSpring BootREST APIsOpenAPILiquibaseConcurrency

Cloud & Site Reliability

Observability and resiliency across a 30+ application portfolio, on both on-prem Kubernetes and AWS. I run compliance-gated production releases, built the Python monitoring that emails the team every morning, and audited 22 services across four platforms so nobody hunts for a log index mid-incident.

AWSKubernetesDockerJenkinsPythonLinux

AI / Machine Learning

My M.S. concentration, and the thing I keep building on my own time. Gauntlet is a LangGraph interview engine with a benchmark that grades its own grader. ClearSpeak runs an LLM entirely on your phone, so nothing you say leaves the device.

PythonFastAPILangGraphOn-device LLMsscikit-learn

How I Work

Four habits that show up in almost everything I ship. None of them are original. They are just the things I learned the slow way and now refuse to skip.

Write the runbook, not just the code

I try to write the page I would want to find at 2am during an incident: the exact command, the exact error, the fix, and why. Twenty-two of those pages exist because of a rollout, a migration, or an outage I did not want anyone to have to rediscover.

Leave the decision visible

My interview platform withholds per-question scores until the interview ends, because a running score changes how people answer the next question and destroys the measurement. Its architecture notes have a section called "things deliberately not done" so those read as choices, not oversights.

Fix it even when it is not yours

An audit turned up services deployed to cluster pairs that were not actually in separate availability zones, which quietly defeats the point of having two. I did not own those services. I wrote up the rule, raised the pull requests, and asked the owners to review.

Get it wrong in private, twice if needed

My first two passes at a script meant to run across 35 repositories were subtly broken in ways that would have been harmless on one repo and destructive on thirty-five. Scale turns a small bug into a large one, so I test the blast radius before I widen it.

Tech Stack

Java
🍃
Spring Boot
⚛️
React
🔷
TypeScript
🐍
Python
☁️
AWS
🐳
Docker
🧠
AI/ML

Experience

Five-plus years shipping production systems in financial services: full-stack product work, platform migrations, and the reliability engineering that keeps all of it standing up on a Monday morning.

Software Engineer II

JPMorgan Chase & Co. · Plano, TX

Jul 2022 – Present
  • Shipped the fund platform 25+ portfolio managers and internal teams rely on for onboarding, due diligence, and portfolio management. React and TypeScript on the front, Java and Spring Boot REST APIs over SQL Server behind it.
  • Co-led a Spring Boot and Jakarta migration across 35+ microservices, building the tracker that surfaced the nine repositories with blocking merge conflicts and writing the team's incremental upgrade guide.
  • Sole-authored a full-stack compliance tool in Java, SQL, and React that turned a multi-day manual database process into self-service, taking engineers out of the critical path for routine business operations.
  • Built and own the Python automation that monitors 35+ services for uptime and audits CI/CD compliance across 35+ repositories, emailing the team a status table every morning.
  • Release-engineered compliance-gated production deployments of 13+ services at a time across on-prem Kubernetes and AWS EKS, plus a 22-service observability audit spanning four platforms.
  • Cut deployment time up to 40% by modernizing services to Spring Boot and containerizing delivery on Kubernetes and Docker with Jenkins CI/CD, holding 99.9% uptime across 30+ applications.
  • Cut fund and database setup 70–80% by automating onboarding for 10+ funds with Liquibase-managed schema changes and tuned SQL Server queries.
Java Spring Boot Python React TypeScript SQL Server AWS Kubernetes Docker Jenkins

Software Engineer Consultant

Ouicruit · Remote

Dec 2021 – Jun 2022
  • Modernized Java and SQL API services with OpenAPI/Swagger, stronger validation, CI hardening, and expanded test coverage, improving median API latency by about 30%.
Java REST APIs OpenAPI/Swagger SQL CI/CD

Linux Consultant

Oppenheimer & Co. · New York, NY

Dec 2020 – Jun 2021
  • Automated secure 6–15 GB weekly financial file transfers with Linux, Bash, GPG, and scheduled jobs, cutting transfer errors by 25% and holding 99.9% data integrity.
Linux Bash GPG Automation

Software Engineer Intern

Federal Home Loan Bank · Jersey City, NJ

2019
  • Built a QA data-visualization dashboard that cut outsourced reporting costs by 15% and took the tedium out of a recurring reporting workflow.
Data Visualization Reporting QA

Selected Work

A résumé gives you one line each for these. Here is what actually happened, including the parts I got wrong first. Details are generalized, because the specifics belong to my employer.

Platform migration

Migrating 35+ microservices, one version at a time

The platform ran 35+ services on an aging major version of Spring Boot, and every one sat a different distance from the target: different gaps between the production branch, the mainline, and the upgrade branch. I co-owned the tracking and the method. Two pages held the truth, a three-way branch comparison for the reporting services and a merge-status board for all 35. That board surfaced nine repositories with conflicts blocking the upgrade, four where the mainline already contained the change, and one abandoned service with no active certificate and no commits in a year, which I cut from scope entirely. I also wrote the team's upgrade guide, because I had watched engineers try to jump several major versions at once and hit cascading breakage they could not isolate: step one version at a time, run the automated namespace migration at each step, let the dependency BOM manage versions instead of hardcoding them, and run a full build and test pass before moving on.

Result One source of truth for 35 parallel efforts, with blockers visible before the release window instead of during it.

Observability

Knowing your dependencies are up, not just your service

The platform had grown to 22 services across four deployment targets, and during an incident engineers were losing time hunting for the right log index or APM process group. I audited all 22, confirmed every log index was live and every process group reporting, and put every link in one place. The audit turned up real gaps: services missing the network egress rule their APM collector needed, and one scheduled job that is not a long-running deployment at all, so APM does not apply and only log search does. Then I went a layer down, because knowing our services are up is not the same as knowing their dependencies are. I wrote a custom Spring Boot health indicator that checks 20+ downstream dependencies in parallel with CompletableFuture and reports per-dependency status and response time on its own endpoint, separate from the framework's, plus a Python job that calls it across the fleet and mails a per-service table.

Result One bookmark instead of a scavenger hunt, and dependency-level visibility the team did not have before.

Automation at scale

One config change, 35 repositories

A platform mandate meant removing a legacy block from the deployment config of roughly 35 repositories. Thirty-five hand-written pull requests is a poor use of a week, so I scripted it as a batch change across all of them at once. Getting it right took three attempts, and the wrong ones are the interesting part. The first had a malformed pattern that appended without respecting YAML nesting. The second used a range delete, which is fragile: it removes everything between two markers and will happily swallow an unrelated section. The third used awk to flag on the key and stop at the next non-indented line, identifying the block by indentation and staying correct regardless of how many lines it ran to. Alongside it I ran a Python audit across 38 repositories for deprecated cluster references. It hit an authentication wall, and rather than drop it I moved to token-based API access, which is now how I do all programmatic repository work.

Result All 35 updated by automated pull request in days rather than weeks. Eight violations found, six real and fixed, two false positives already commented out.

Environment provisioning

Five services, five completely different failures

I was asked to make a five-service stack work in a development environment where it never had. Every service was broken for a different reason, which is the honest lesson of distributed systems. The front end had no dedicated auth client for that environment at all. The gateway had four separate problems stacked on each other: a wrong database hostname, a missing network egress rule, a service account never provisioned in that database, and an audit table that simply did not exist, which I created by hand. One service was still pointed at a decommissioned cluster and needed new ingress addresses ordered. One had a connection timeout that needed both an egress fix and an access request. The method was unglamorous: read the actual error out of each pod instead of guessing, then fix them one at a time. I did it again later for an eight-service environment wired to a database refreshed nightly from production, which catches data-shaped bugs a static test dataset never will.

Result All services healthy, all seven screens validated, and the investigation written up so nobody starts from zero next time.

Release engineering

Compliance-gated releases, 13 services at a time

I have served as release engineer across two very different ecosystems, one on on-prem Kubernetes and one on AWS. The largest release I ran covered 13 services under a single change request. The gates are real and none of them are optional: code coverage above threshold on new code and overall, security scans with no unresolved critical or high findings, a change request carrying every signed-off ticket and scan link, then approval from the deployment control platform before the pipeline will run in production at all. After that it is notification, deploy from the release branches, sanity-check the screens that matter, confirm, then merge back and tag. A separate release carried ten tickets at once, well above the usual batch of two to four, which meant justifying the size on the grounds that all ten had been validated together in the same sprint.

Result Clean releases with no post-release incidents, and a written SOP the team still follows.

Tooling for operations

A bulk-update tool built for whoever cleans up after it

Corporate actions like stock splits used to mean an engineer hand-running SQL across four tables. I built the wizard that replaced that, and most of the design went into what happens when it goes wrong. The interface works in human-readable instrument identifiers and resolves them to internal keys server-side, so a request can never carry an arbitrary key that touches the wrong security. It shows a small sample of rows before and after, enough for the operations team to sanity-check without dumping the dataset. It names the instrument on a confirmation screen before anything irreversible runs. On a related onboarding tool I mapped all 35 input fields before writing a line of code, which is how I noticed one selection could derive three others and take the form from 35 inputs down to 32.

Result A multi-day, engineer-dependent process became self-service for the team that actually owns it.

Security

Certificates, and making them boring on purpose

I owned the full lifecycle of the mutual TLS certificates behind a managed file-transfer integration: requesting them, installing them, rotating them, and testing them. Certificate work is easy the first time and painful every time after, because whoever does it next is usually doing it under pressure with an expiry date behind them. So I wrote it down as a nine-step SOP with the exact commands, including the keystore format conversions the authentication flow needs, plus a companion guide for exercising certificate auth from an API client before trusting it in a running service.

Result A rotation that used to be an investigation is now a checklist.

Reliability

Two clusters, one datacenter, zero redundancy

Services on the platform are meant to deploy to a pair of clusters sharing a base identifier but sitting in separate availability zones, so losing one zone leaves the other serving. Auditing the deployment config of every service against the load-balancer and cluster dashboards, I found pairs built from mismatched bases, and one service spread across three clusters on three different bases, which means inconsistent patch levels and maintenance windows on top of the redundancy problem. I did not own those services. I documented the pairing rule, ordered the replacement ingress addresses, raised the pull requests myself, and asked the owners to review. I also kept the cluster rebuild SOP, recording each service's release branch and pipeline before a repave so the platform could be brought back in minutes.

Result Correctly paired across availability zones, with the rule written down so the next person checks it before it becomes an incident.

Education & Certifications

🎓

M.S., Computer Science

Georgia Institute of Technology
Specialization: AI/ML

2026 · GPA 3.6
🏛️

B.S., Computer Science

The City College of New York

2020
☁️

AWS Certified Cloud Practitioner

Amazon Web Services

Nov 2022

Featured Projects

These are the things I build when nobody is asking me to. They are where I make every architectural call myself, get them wrong in private, and learn the most.

Let's Connect

I am open to Software Engineer roles across full-stack, backend, platform and reliability, or AI/ML, and I am based in Plano, TX. If you are hiring, or you just want to compare notes on a migration that went sideways, I would genuinely like to hear from you.