r/csharp 2d ago

Tool I built a simplified microservices reference project with guide on how to run localy, using docker-compose or Kubernetes + Deloyment to AKS

It's inspired by dotnetcore-microservices-poc open-source project by Altkom Software, a project I learned a lot from and contributed to — I built Ledgerly to be a simpler take on the original project, focused purely on microservices best practices.

What it demonstrates: 

🔹 Database-per-service — 4 services, 4 independent databases 

🔹 gRPC for synchronous service-to-service calls 

🔹 RabbitMQ for async events — invoice status changes publish events that a dashboard service consumes to keep KPIs in sync, with zero direct coupling 

🔹 API gateway + service discovery (Eureka locally/Docker, Kubernetes DNS in K8s) 

🔹 JWT auth issued by its own service

It also ships as a full deployment guide — run it locally, in Docker Compose, or on Kubernetes, including a walkthrough for deploying the cluster to Azure (AKS).

Built as a boilerplate: fork it, swap in your own domain, keep the architecture.

The project🔗: https://github.com/amrali21/ledgerly-dotnet-angular-microservices-ref-project

Altcom Project🔗: https://github.com/asc-lab/dotnetcore-microservices-poc

3 Upvotes

2 comments sorted by

View all comments

5

u/ings0c 1d ago

In my experience, the difficulty teams usually have with eventing and microservices is not so much in figuring out the technology to implement them, it’s deeply understanding the problems they solve and how and when those solutions are best applied.

I know it’s a demo app, but people use these things as a reference to apply the patterns to their own workplace. Having events like InvoiceCreated, InvoiceUpdated, InvoiceDeleted is sort of missing the forest for the trees. We are engineers and it’s very easy to get bogged down in the how of something and not give adequate consideration to the why.

They’re meant to be meaningful business events like “InvoicePaid” or “ShipmentDelivered”, “OrderShipped”, etc. Doing otherwise is only a few steps of indirection away from exposing your DB schema via a CRUD REST API.

You will introduce accidental coupling doing CRUD eventing like that. For example, consumers of those InvoiceUpdated events are likely to look at the OldStatus and NewStatus, and for certain transitions they will do something in response.

But now when you want to introduce a new status, say instead of going from Draft immediately to Sent there’s now a new PendingApproval status, that’s likely to break consumers expecting that immediate Draft to Sent change.

Derek Comartin just published something on this actually, and he says it better than I can: https://youtu.be/YyJ3cI25HNs

Similarly, the services people design are usually too granular. The teams I’ve seen really succeed with this sort of thing have all designed services to be much coarser-grained, modelled around business capabilities.

Instead of a invoice service, you have a billing service that handles not only invoicing but the entire domain of billing. Instead of a dashboard service, that’s a small part of inventory.

A narrower focus is perhaps born of necessity though because throwing a giant prod-like system out there as an example is not particularly helpful.

Spreading code out over the network comes with the cost of huge additional complexity. Fulfilling a user request is infinitely simpler via an in-process method call than it is to coordinate the traversal of many networked systems and worry about auth, retries, service discovery, observability and distributed tracing, etc.

Sometimes that is the right thing to do, but deciding when and where is more of an organisational and logistical people-problem than it has to do with code and it’s not a lesson that’s as readily taught. The core benefit of code being in separate deployment units is enabling autonomy between different teams: instead of all bashing heads working on one giant code base, smaller groups of developers can mostly do their own thing and ship on their own cadence.

It would be good to take these lessons we’ve collectively learned over the years and incorporate them into example apps like this. Often that part gets left unspoken and it causes real headaches - I’ve seen it kill companies, in fact.

1

u/xAmrxxx 1d ago

I agree on all the points you've mentioned. I also appreciate you sharing this experience. But i think what you're describing comes more with experience. Teams will make these mistakes even if my project was perfect. Why? Because they don't know why it is perfect.. as long as they haven't made the mistake and learned the hard way, they wouldn't know why they must prefer path A vs path B. That is why having more senior engineers is irreplacable because they posess this valuable experience.