Microservices
Right-sized microservice architectures with clear boundaries and dumb pipes.
I design microservice architectures only when they earn their place — typically when teams, deploy cadences, or scaling needs diverge. I have implemented and operated multiple microservice systems on AWS, with clear service boundaries, async messaging where it matters, and shared types/contracts to keep integration honest.
How I work with Microservices
I have moved from monolith-first to 'split when there is a real reason' as my default. My early microservice work was over-eager — too many services, too much coordination. Today I look for clear boundaries based on bounded contexts, team ownership, or independent scaling.
On the implementation side I have built microservices in both NestJS (TCP + Redis transports, BullMQ for jobs) and Spring Boot (REST + RabbitMQ-style messaging). I lean on shared TypeScript/Java DTO packages so contracts are explicit and breaking changes are visible.
Operationally I keep the platform layer simple: containerized services on AWS, an API gateway in front, structured logs with a correlation id, and CloudWatch + alerts on the basics. I avoid distributed-system complexity unless the system actually needs it.
Microservices across business domains
Split ingestion, inference, and serving into separate services so the inference layer could scale independently when document volume spiked.
Extracted the reporting + audit-log service from the monolith once it had distinct scaling characteristics and ownership.
Built analytics ingestion as a small, independent service feeding the dashboard service via async events.
Kept the core platform monolithic and only carved out a separate service for media + image processing.
Real issues I resolved using Microservices
Resisted a premature microservice split — and shipped the feature in a third of the time
A new feature was originally scoped as a separate microservice 'for scaling later'. Estimated effort was 6+ weeks because of contract, infra, and deployment overhead.
Pushed back with a written architecture review, kept the feature as a module inside the existing service, and documented the actual triggers that would justify splitting later.
Feature shipped in ~2 weeks instead of 6+, the team avoided maintaining a new service indefinitely, and the documented 'when to split' criteria stayed useful for future decisions.
Replaced sync HTTP calls with async events between services
Two services were communicating over chained HTTP requests; a slow downstream service was visibly slowing the upstream user-facing API.
Introduced an event-driven seam: the upstream service published a domain event and returned 202; the downstream service consumed asynchronously with retries.
User-facing latency dropped sharply, downstream incidents no longer caused upstream outages, and the system became actually-resilient instead of fragile-by-default.
Added correlation ids that turned 30-minute debug sessions into 30-second ones
Tracing a single request across services required grepping multiple log streams by timestamp — slow and error-prone.
Threaded a request id from the gateway into every service via headers, included it in structured logs, and propagated it across async events too.
Cross-service debugging became trivial; engineers could pull a single id and see the full lifecycle.
Often used together
Have a Microservices project in mind?
I am open to full-time and contract work where Microservicesis core to the stack. Let's talk about what you are building.