Diet Driven - Calorie Counter Mobile App

Work in progress, currently focusing on the backend. Created for nutrition enthusiasts that are unsatisfied with current solutions.


I'm more focused on the UX than on the UI.


A great deal of thought has gone into defining service boundaries to have a cohesive and decoupled system.

Design-time coupling is when a service knows something about another service, this matters during development.

Runtime coupling is when a service depends upon the availability of another service, this matters to synchronous requests.

actor pattern

Actors are used to manage concurrency. Actors are single-instance stateful data processors (although they may internally parallelize work). Actors are interfaced asynchronously through a message queue.

The actor pattern is used both across services, as well as within each service, it's turtles all the way down. Across services, most microservices are actors that communicate though message queues (NATS Jetstream). Within a service, most long-living tasks are actors, and communicate over channels (in-memory).

event sourcing

Some services require the complete history of all operations that occurred. RDBMS-style databases aren't a good fit since they were designed to overwrite previous state (lose information). For these services, I use an event store as the single source of truth, and replay the events when I need to materialize the state. This is called event sourcing (think of git materializing your repository by replaying every commit).

CQRS (command query responsibility segregation) is often used alongside event sourcing to separate the domain model into specialized read and write parts. The write-side is an actor that materializes enough state to validate the next command in the queue (can be optimized by taking snapshots). The read-side is a service that materializes events in real time to respond to synchronous queries (essentially creating the perfect cache). Thanks to event sourcing, the read-side and write-side models can be ephemeral, and additional read models can be created retrospectively.