Approach to Software Engineering

Milan Motavar
By Milan MotavarSeptember 20256 min read

To build a developer-first messaging infrastructure, we need to balance speed, reliability, and compliance. Over time, we've found two principles useful: "You Aren't Gonna Need It" (YAGNI) and "Don't Repeat Yourself" (DRY). But we don't treat them as dogma. We treat them as tools, applied with judgment.

You Aren't Gonna Need It (YAGNI)

YAGNI tells you not to build for hypothetical futures. This sounds obvious, but in practice it's hard.

As engineers, we often anticipate requirements that may never arrive. Here is how YAGNI shows up in our work:

  • API design: Our first API set has only two endpoints: SendMessage and GetMessageWebhook. We resisted the urge to add filters, bulk editing, or search until we saw real customer demand.
  • Database schema: We keep audit columns like CreatedOnUtc and UpdatedOnUtc everywhere. But we don't pre-build tables for "event history" or "archival" until the use case is clear.
  • Infrastructure: Instead of introducing Kafka or Redis at day one, we started with SQS and DynamoDB. It solves the current scale problem without adding a new system to maintain.

The trade-off: sometimes we rebuild parts when requirements evolve. But we'd rather rewrite 500 lines of code later than live with thousands of lines of unused abstractions today.

Don't Repeat Yourself (DRY)

DRY is about avoiding duplication of knowledge. In theory, it makes codebases more maintainable. In reality, being too strict with DRY leads to brittle abstractions.

How we handle it:

  • Three-strikes rule: We allow duplication until we see the same pattern at least three times. Only then do we extract a shared library or service.
  • Clarity first: In our .NET APIs, we often copy validation logic into separate controllers instead of creating one massive "validation service" that nobody wants to read.
  • Shared libraries with intent: Our SQLHelperV2 is shared across services because database access patterns repeat often. But we don't abstract business rules as they change really fast in MVP stages.

The mistake we've made before: abstracting too early. Undoing a wrong abstraction costs more time than removing a duplicated method.

Pragmatism Over Dogma

We are opinionated about this: there are no ideal processes. YAGNI and DRY are useful, but context decides everything.

Some examples:

  • We sometimes duplicate logic across Lambda functions to keep them independent. It looks wasteful, but it isolates failures.
  • We sometimes "hack" a feature in the dashboard to validate customer demand before investing in a full design.
  • We sometimes choose manual over automation. For example, we manually verified CloudWatch alarms for the first month before templating them in Terraform. It was slower, but it avoided building automation for false signals.

Pragmatism means choosing the least painful trade-off today while leaving room to adapt tomorrow. Dogma makes engineers slow. Pragmatism keeps us shipping.

Why This Matters

Applying YAGNI, DRY, and pragmatism together shapes both our product and our engineering culture:

  • Our APIs stay simple and accessible.
  • Our infrastructure avoids unnecessary moving parts.
  • Our developers stay focused on shipping features that matter.

Yes, sometimes this means debt piles up or refactors become necessary. But we'd rather pay that price when the business justifies it than lock ourselves into complexity early.

Closing Thoughts

We don't believe in "best practices" as universal truth. We believe in trade-offs, feedback loops, and making judgment calls with the information at hand.

YAGNI keeps us lean, DRY keeps us organized, and pragmatism keeps us moving. That combination has worked well for us, and it reflects how we want to build: infrastructure that is reliable today and adaptable tomorrow.

Approach to Software Engineering - SendZen Blog | SendZen