Engineering Principles

Why Bettermenters build software the way we do

Back to Our Principles

How Our Apps Communicate

Our apps communicate over the network directly with other apps, not via message busses, event streams, queues, or distributed logs because suspending state in flight between owners complicates the inter-app contract and app operations, and creates another system to own.

Given unexceptional performance needs, our apps communicate in JSON over REST because it drives toward revealingly-named, customer-oriented contracts without shared serialization code, and it’s fast enough.

Given an application domain that does not provide a commodity service to large number of undifferentiated client apps, we use explicit producer-driven event dispatch instead of pubsub because it should be clear from the producer codebase which services depend on its events, and why, so that important contracts aren’t accidentally violated by unaware producer teams, and event producers can refactor fearlessly.

Given we’re not designing a commodity service that serves a variety of undifferentiated client apps, we design backends for frontends - specialized controllers for each consumer’s use case - because generalized endpoints hamper beneficial divergence of client contracts over time while BFF keeps payloads and query costs minimal, and is essentially free when paired with skinny controllers.

Given we’re not designing a commodity service, we design consumer driven contracts where the consumer’s needs drive a negotiation with the provider team resulting in a minimal cohesive contract because being customer-focused is fractal. When in doubt, what would make the most sense to the end customer wins, and the consuming app’s domain language trumps the producer’s if the producer has any business understanding that domain.

We use circuit breakers and bulkheads to incrementally add resilience to our systems, cognizant of the cost benefit ratio, because these patterns provide high leverage on solving unplanned service availability problems. Even so, graceful degradation requires us to define domain-specific behavior for each use case.

Next: How We Ensure Distributed System Consistency

Back to Our Principles