Resume
Principal Software Engineer specializing in distributed systems, platform architecture, information retrieval, and production ML. I've spent the last decade building high-scale infrastructure and reusable platforms across search, recommendations, data, and developer tooling.
Areas of Expertise
Click a category for the technologies behind it.
Experience
Click a role for details.
Principal Software Engineer, Core Platform · Home Depot
Establishing architecture, ownership boundaries, and long-term strategy for a newly created platform organization spanning 10 teams.
- Established architecture, ownership boundaries, and operating model for the newly created platform org across 10 teams, following a restructure that separated Platform and Experience teams.
- Designed a five-year service modernization roadmap for the new organization.
Principal Software Engineer, Search & Recommendations · Home Depot
Led the transition from rule-based to ML-driven search and modernized the recommendation platform.
- Provided technical direction for a team of over 60 associates and 50 contractors.
- Redesigned the search platform into a modular ML-driven retrieval and ranking platform, separating infrastructure from model strategy so teams could iterate on retrieval and ranking independently..
- Built a system integrating the in-house search platform with external partners (Bing, Google retail search) through an intelligent routing layer.
- Reduced required recommendation services by 60%.
- Cut overall cloud costs for search and recommendations by 20%.
- Designed and implemented a feature store to serve batch and real-time calculated features, supporting 300+ features.
- Expanded the recommendation product catalog to include modern modeling approaches.
- Expanded the recommendations platform to support real-time model inference in both retrieval and ranking models using a flexible configuration-first architecture.
- Redesigned the front-end experimentation for recommendations to support more, quicker A/B testing.
Staff Software Engineer, Tail Search · Home Depot
Built external search integrations and optimized long-tail query performance.
- Designed and implemented the integration between the in-house search platform and Bing search.
- Introduced a KNN query-rewriting system to improve tail-search performance.
- Migrated the platform's API layer from REST to GraphQL.
- Reduced data-science team friction by building an offline relevancy service.
Senior Software Engineer, Data Platform · Home Depot
Migrated the legacy Endeca search platform to Solr on GCP; built the batch/streaming indexing platform at scale.
- Ran a 17-engineer search platform team (7 onsite, 10 offshore).
- Built search-as-a-service internally, onboarding two new product teams to searchable/filterable catalogs.
- Maintained a 15-minute real-time data indexing SLO across 2,500+ stores and 4+ million products.
- Scaled Solr from 10GB across 3 shards to 60GB across 10 shards, holding a 200ms SLO across 33M queries/day.
Automation Engineering Contractor · Home Depot
QA and validation tooling for a large-scale cloud migration.
- Built a validation service used as the final blue/green deployment gate across all backend apps.
- Built cloud-native tooling to compare Endeca vs. Solr for performance and data integrity.
- Automated previously-manual front- and back-end test coverage across the search platform.
Software Engineer, Back Office · Incomm Interactive Communications
Started as a Software Engineering Intern before converting; modernized back-office pricing, billing, and remittance systems.
- Segmented the core transactional database used by the transaction-processing service.
- Redesigned and rewrote the legacy pricing and billing application.
- Designed and built a remittance application to replace a manual process.
- Implemented DevOps practices for the team.
Notable Projects
Click a project for problem, architecture, tech, and outcomes.
Real-Time & Batch Indexing Platform Built a Lambda-style indexing platform combining batch and streaming ingestion to keep search data fresh, auditable, and recoverable at scale.
- Problem
- During migration from managed Endeca to self-hosted Solr Cloud, the platform needed to support both time-sensitive updates such as availability and larger scheduled batch loads. It also needed full change visibility, replay capability, backups, and reliable recovery paths.
- Architecture
- Bifurcated ETL pipeline with scheduled batch jobs for daily and hourly ingestion as well as an event-driven path for real-time updates. Both paths synchronized into a staging database as the source of truth, then triggered indexing events for search and audit events for the data warehouse.
- Tech used
-
- Cassandra staging database
- GCP Pub/Sub event queue
- Apache Spark batch processing
- Apache Dataflow streaming pipeline
- Outcomes
- Delivered a durable indexing platform that still supports the search stack years later. The system provides full auditability and replay, enables search-index recovery after failures, sustained around 1,000 upserts per second at peak, and maintained a 15-minute freshness SLO.
Solr Cloud on Google Cloud Migrated the search team's platform from on-prem WCS (Endeca) to Solr Cloud running on GCP.
- Problem
- Moving from a managed service to a self-hosted solution is always a large project. For us, we needed to replicate the entire functionality as well as maintain SEO. ENDECA has a specific url pattern that includes its filters in base 36 encoded string identifiers. We needed to maintain those, even outside of ENDECA. We also needed to use what at the time was an experimental Solr Cloud mode to host Solr in a distributed setup. This comes with coordination, scaling, and deployment questions to solve.
- Architecture
- Deceptively simple structure: a single GCP instance group per shard, scaled groups for replicas. Separate Zookeeper deployment to lessen blast radius. Live and offline clusters to have immediate failovers. Spark job which uses an embedded SQLite db, constrained to the driver, to generate new identifiers for url filters.
- Tech used
-
- Spark for dimension and refinement value generation
- GCP Compute Engine for infrastructure
- GCP availability zones for redundancy
- Zookeeper for coordination, discovery, monitoring, and config deployments
- Custom applications for deployment, scaling, and monitoring
- Outcomes
- The system worked for 4 years with only one outage. The outage was caused by an edge case in Solr where querying with a term too broad can trigger memory overflows. Maintained 200ms 95th percentile response time while scaling the cluster from a 10GB index across 3 shards to over 60GB across 10 shards. Came with SRE headaches due to difficult-to-monitor processes and complicated deployments. Eventually replaced with Elastic when evolving to hybrid search.
Search Platform GraphQL Migration Migrated the search platform's API layer from REST to GraphQL, unifying client access patterns.
- Problem
- The online team had various teams all working on full stack systems, but without a good unifying platform. This resulted in fragmented frontend templates, scripts, and sourcecode that caused headaches when deploying and merging. This was replaced with strict react for all front-end components and a BFF pattern that modelled Apollo's federation gateway for all backend systems. This then required all other teams to adopt the federation gateway approach of GraphQL subdomains, which was a full overhaul.
- Architecture
- SPA front-end templates move to a dynamic react component system. Single library for making data requests. Custom BFF application to route subdomains, enforcing GraphQL adoption for back-end apis. Search api migrated to the Java Micronaut GraphQL library.
- Tech used
-
- React for front-end components
- Java for BFF gateway
- Micronaut with GraphQL for domain orchestration
- Outcomes
- A complete rewrite of the Search API, implementing the core GraphQL principle of avoiding over-fetching by honoring the request's selection set. Provided no meaningful engineering benefit to the search team, but allowed front-end teams to separate their code into smaller modules and granular deployments which boosted feature development across the online team.
KNN Query Rewriting for Tail Search Introduced k-nearest-neighbor query rewriting to significantly improve relevance on long-tail, low-volume search queries.
- Problem
- Tuning a search system is a pendulum generally described as a tradeoff between recall and precision. Recall describes the breadth of results whereas precision describes the accuracy and to focus on one you almost by definition need to sacrifice the other. This means the business focuses on the "head queries", or the queries that make up the majority of actual sales, which trends towards high recall systems. This works well for sales, but it means sacrificing the performance of more specific, less seen "tail" queries. So how can we improve tail performance by having it piggyback on the performance of head queries?
- Architecture
- Query rewriting is an old technique, but it has a lot of difficulties. We implemented a rewriting approach which used a k-nearest neighbor algorithm to find the nearest head query for an identified tail query and used that to augment the search results. A query comes in and we determine if it's a tail query through a batch-computed cache. We then look up the head query closest to it and apply a confidence filter to remove low confidence matches. You then use the head query to search instead of or in addition to the parsed tail query.
- Tech used
-
- In-memory Redis query cache
- GKE for KNN index and wrapper app
- Apache Beam embedding pipeline
- Spark
- Outcomes
- 30 basis point improvement on select tail query performance while adding no measurable overhead. Scope was limited to a small enough subset that the cost of maintaining the system made keeping the system questionable. Whole thing was replaced later due to newer technologies rendering it unnecessary.
Bing Search Integration Built configurable external-search integrations to test whether recall-oriented engines could improve long-tail search performance and business outcomes.
- Problem
- Bing launched a new retail-search offering and invited us to serve as an early partner. The question was fundamentally business-driven: could an external, recall-oriented engine improve long-tail search without harming conversion, revenue per search, reformulation rate, bounce rate, or average order value? It was also a practical build-vs-buy evaluation for a team heavily optimized around head-query performance.
- Architecture
- Built a new Beam-based indexing path, a Go orchestration API, and a configurable routing layer that could direct traffic to the in-house engine, Bing, or both. The router reused an in-memory head-query cache to target tail traffic first, while leaving room for future classifier-driven routing, controlled experiments, and whitelist overrides. A small refactor to the existing search API made external engines pluggable rather than a one-off integration.
- Tech used
-
- Apache Beam indexing pipeline
- Go orchestration API
- Redis head-query cache
- Configurable routing and experiment framework
- Bing and Google retail-search APIs
- Outcomes
- The in-house engine remained stronger on topline conversion and revenue per search, while Bing improved average order value and reformulation rate. The experiment pushed the broader search strategy toward higher-recall retrieval. After an unexpected outage in the primary search platform, the integration was patched to support browse traffic and served the full site for several weeks while the main system was repaired.
Real-Time & Batch Feature Store Designed and built a configurable feature platform that served hundreds of batch and real-time features for low-latency ranking models.
- Problem
- Ranking models needed a shared way to consume batch-computed and request-time features. Existing feature-store products did not meet the requirements, and the data-science team needed roughly 300 real-time features that combined query context with per-result computation. The challenge was delivering that work within a strict search-serving latency budget while preserving compatibility with Python-based offline feature logic.
- Architecture
- Designed a GKE-based feature platform with a Java orchestration layer, stateful caching, and isolated Python computation services. Requests fanned out by requested feature; configuration determined whether each feature came from a low-latency batch store or a real-time computation path. Small autoscaled Gunicorn workers handled CPU-bound feature calculation, allowing the platform to parallelize work without coupling scale to I/O behavior.
- Tech used
-
- GKE and Kubernetes autoscaling
- Java orchestration services
- Apache Beam batch pipelines
- Bigtable low-latency batch serving
- Python and Gunicorn computation workers
- Stateful caching and batch-feature serving
- Configuration-driven feature definitions
- Outcomes
- Successfully served approximately 300 real-time features for an initial ranking model, then reused the platform for a subsequent model with another roughly 300 features. The full feature path added about 60 ms at p95 and allowed features to be added or removed through configuration rather than code changes.
Hybrid Search Migration Rebuilt the search platform around managed Elasticsearch, semantic retrieval, behavioral prediction, and real-time reranking.
- Problem
- The existing Solr platform was optimized for lexical retrieval and pre-ranking, but could not support a flexible lexical, semantic, or hybrid retrieval model with real-time reranking. Indexing throughput was also becoming a constraint. The goal was to expand retrieval quality without replacing stable indexing and API layers unnecessarily.
- Architecture
- Retained the existing indexing platform and search API while introducing a managed Elasticsearch cluster and a new retrieval-and-ranking orchestration path. The system could route requests to lexical retrieval, semantic retrieval, or both; merge candidates; and rerank them in real time. It integrated customer-behavior data directly into the search platform and self-hosted three new models: PECOS for behavioral prediction, SBERT for semantic embeddings, and XGBoost for reranking.
- Tech used
-
- Managed Elasticsearch
- PECOS behavioral prediction model
- SBERT embeddings and semantic retrieval
- XGBoost reranking model
- Custom retrieval, merge, routing, and model-serving orchestration
- Outcomes
- The hybrid retrieval and reranking approach outperformed the previous in-house platform by roughly 85 basis points, driven largely by behavioral prediction. It also reduced bounce and reformulation rates; average order value declined somewhat, but the broader outcome set was strongly positive.
LLM-Driven Complementary Recommendations Used an LLM as a content-understanding pipeline to create explainable, category-aware complementary product recommendations.
- Problem
- Existing complementary recommendations relied on narrow accessory and co-purchase models. They were collaborative, noisy, difficult to explain, and limited in their ability to represent multiple reasons a customer might want related products. The goal was a broader content-based system that could generate clear, customer-relevant recommendation contexts while maintaining the commercial quality of established models.
- Architecture
- Used an LLM as a multi-stage feature-generation pipeline over existing product titles, descriptions, and attributes. For each item, the pipeline generated a customer-facing complementary-product guide and several compatible product groupings, each with its own title and explanation. The source item and group descriptions were embedded, then KNN retrieval produced a deliberately small set of high-confidence candidates per grouping. A later co-purchase reranking stage adjusted the top candidates using observed sales behavior.
- Tech used
-
- LLM-based structured content generation
- Product titles, descriptions, and attribute data
- Embedding generation and vector retrieval
- KNN candidate selection
- Co-purchase reranking
- Outcomes
- Created a new, explainable complementary-recommendation experience that increased engagement and matched the performance of existing approaches. The result created a path to retire older aggregation models, including frequently-bought-together recommendations, in favor of a more flexible content-based platform.
Small Language Model for Ranking Built a low-latency language-model ranker that could personalize results across recommendation models without requiring a bespoke ranker for each one.
- Problem
- Recommendation models are typically specialized around different data, customer behaviors, and objectives, which often means each pipeline also needs its own ranking logic. To support personalized ranking broadly, we needed a global ranker that could evaluate candidates from any recommendation model using product, user, and session context. The challenge was making a Qwen 3 variant with 4K–6K-token prompts serve within a roughly 100–200 ms tail-latency budget rather than taking a second or more per request.
- Architecture
- Compiled and served the model with TensorRT-LLM and Triton, using optimized kernels, modern attention implementations, and prefill caching. Prompt structure placed static product content before dynamic user and session context to maximize cache reuse. Rather than asking the model to generate an ordered list, each candidate received a single-token label; the model produced one token, and filtered logits across candidate labels were normalized into ranking probabilities. This avoided expensive multi-token decoding while retaining a contextual score for every candidate.
- Tech used
-
- Qwen 3 variant
- TensorRT-LLM and Triton Inference Server
- Prompt caching and structured prompt design
- Logit-based candidate scoring
- NVIDIA A100 GPU inference
- Outcomes
- Achieved roughly 200 requests per second at about 60 ms p95 latency on a single A100 GPU, demonstrating that contextual language-model ranking could meet real-time serving requirements. The business experiment was less successful: a persistent approximately 5% hallucination rate and unreliable interpretation of numerical feature values limited production value, despite the serving system performing well. This caused us to pivot to a solution which uses two XGB models followed by a gated MOE cross-coder to combine them over time.
Real-Time Predictive Personalized Recommendations Built a real-time two-tower recommendation system that personalized cart add-ons from live session and cart context.
- Problem
- Most recommendation models were batch-based, which made them poorly suited to cart recommendations where the current cart and session create context that cannot be precomputed. The goal was to recommend relevant add-ons in real time, using current customer behavior and cart state while optimizing directly for add-to-cart activity.
- Architecture
- Built a transformer-based two-tower model: a query tower represented the customer’s live session and cart context, while an item tower represented the product corpus. The system used TensorFlow Recommenders for model development, TensorFlow Serving for inference, a Java orchestration service for request handling, and a stateful vector index for candidate retrieval. The supporting MLOps flow handled distributed training, post-training validation, coordinated model-and-index deployment, and serving rollout.
- Tech used
-
- TensorFlow Recommenders and TensorFlow Serving
- Two-tower transformer architecture
- GKE-based model hosting
- Stateful vector index
- MLflow, later migrated to Vertex AI pipelines
- Outcomes
- Improved every measured outcome, including conversion, click-through rate, add-to-cart rate, average order value, and revenue per visit. The model became the foundation for several subsequent recommendation models, while its deployment and validation pipeline helped establish a more mature production ML workflow.
Agentic Modernization Pipeline Built an agentic pipeline that upgrades Java services through current LTS and framework versions, modernizes observability, and opens a tested pull request.
- Problem
- In a large service estate, maintenance work routinely loses priority until outdated Java, frameworks, observability libraries, and runtime conventions become difficult to upgrade safely. Many applications remained on Java 11 or Java 17 despite newer LTS releases, and a conventional migration could consume weeks of engineering time per repository. The goal was to make broad modernization practical while improving runtime behavior and engineering standards along the way.
- Architecture
- Built a ten-stage orchestrator-and-subagent system running on GKE. An intake service creates a long-lived, isolated pod with persistent storage for each repository; it clones the codebase, establishes a tested baseline, performs the upgrade, and raises a pull request. The orchestrator spawns specialized agents with fresh context for each phase, uses a ledger to retain necessary state, and enforces testing gates before progression. The pipeline adds missing test coverage where needed, performs sequential Java LTS and framework upgrades with OpenRewrite, migrates OpenCensus/Sleuth/Zipkin patterns to OpenTelemetry, then tunes runtime settings, thread pools, and JVM arguments for the application’s workload.
- Tech used
-
- Agentic orchestrator and specialized subagents
- GKE long-running worker pods and persistent storage
- Java LTS and framework upgrade workflows
- OpenRewrite
- OpenTelemetry modernization and automated test gates
- Outcomes
- Reduced modernization of a complex repository from weeks of manual engineering work to less than a day. The pipeline produces tested pull requests while upgrading language and framework versions, standardizing observability, and applying workload-aware runtime improvements in the same workflow.