💃 A strategy to tame complex business logic 🕺

Domain-Driven Design (DDD) in Salesforce

Good morning, Salesforce Nerds! How’s your latest project going? 🤔 

We all know Salesforce projects often start simple - a few custom objects, a handful of automation rules, and some Apex classes to glue things together.

But before you know it, your org is a sprawling mess of triggers, flow spaghetti, and an Apex monolith that makes debugging a nightmare. 😮‍💨 

It can feel like project after project, client after client the story is the same.

So how do we avoid this?

One way is a concept called Domain-Driven Design (DDD), a software design approach that can bring order to this chaos. 🔥 

Let’s dig in!

TABLE OF CONTENTS

MAKING SENSE OF THE MADNESS

WHAT IS DOMAIN-DRIVEN DESIGN (DDD)?

Domain-Driven Design (DDD) is a software design philosophy that emphasizes structuring applications around the core business domain. 📦️ 

Instead of forcing business logic into a technical framework, DDD ensures that the system mirrors real-world business concepts, making it more maintainable, scalable, and understandable.

These are good things if you’re not sure! 😉 

At its core, DDD is about:

⬇️ Understanding the business domain deeply

🧩 Organizing code around domain concepts

🎁 Encapsulating business rules within domain models

🤝 Improving collaboration between developers and domain experts

BECAUSE YOUR ORG DESERVES BETTER

WHY DOES IT MATTER?

Salesforce, by its nature, is a highly customizable platform that often becomes a dumping ground for ad-hoc solutions.

Without a structured approach, technical debt accumulates quickly. 💨 

Applying DDD principles to Salesforce development can help:

👍️ Reduce complexity by grouping related logic within domain models.

🏗️ Improve maintainability by keeping code modular and reusable.

🤝 Enhance collaboration between technical and non-technical stakeholders.

📈 Scale effectively by designing a system that evolves with business needs.

THE MORE YOU KNOW

CORE CONCEPTS

📦️ Bounded Contexts: Keeping Responsibilities Clear

Salesforce orgs often have multiple departments (Sales, Service, Finance) that share the same data model but operate differently. 🥴 

A Bounded Context helps define clear boundaries for different parts of the system, ensuring that logic relevant to Sales doesn’t interfere with Finance workflows.

Salesforce Example:

  • A Lead record may have different validation and conversion processes in Sales Cloud than in a custom partner portal.

  • Instead of a single bloated LeadService class, split it into SalesLeadService and PartnerLeadService.

ℹ️ Entities and Value Objects: Structuring Your Data

  • Entities are objects with distinct identities (e.g., Account, Opportunity).

  • Value Objects are objects that don’t have an identity but carry information (e.g., an Address on an Account record).

Salesforce Example:

  • Instead of storing address data as plain text fields on an Account, create a Custom Metadata Type or Custom Object for addresses, making it reusable across multiple entities.

🧩 Aggregates: Controlling Data Integrity

An Aggregate is a group of related entities that should be treated as a single unit. 1️⃣ 

One entity (the Aggregate Root) manages consistency across the group.

Salesforce Example:

  • An Opportunity and its related OpportunityLineItems form an Aggregate. Business rules ensuring line item integrity should reside within an OpportunityService class rather than scattered across triggers and flows.

🔄 Domain Services: Keeping Logic Where It Belongs

Not all business rules belong inside an entity. 🚫 

Domain Services handle operations that involve multiple entities.

Salesforce Example:

  • Instead of putting discount validation logic in multiple places, encapsulate it in an OpportunityPricingService class.

🔍️ Repositories: Abstracting Data Access

Repositories provide a clean interface for retrieving and persisting domain objects without exposing implementation details.  

Salesforce Example:

  • Instead of writing SOQL queries directly in controllers or triggers, create a CustomerRepository Apex class to handle retrieval logic for Accounts and Contacts.

GIVE YOUR ORG A MAKEOVER

APPLYING DDD IN SALESFORCE

Alright, so you’re convinced - DDD isn’t just some fancy enterprise jargon, and you want to bring its magic to your Salesforce org. 🪄 

But how do you do it without ending up in an existential crisis over your data model?

Don’t worry; applying DDD in Salesforce isn’t about over-engineering. It’s about bringing structure and sanity to your org before it turns into a spaghetti-coded monolith. 🍝 

Here are some ideas to get started 👇️ 

🗳️ Modularize Your Codebase

Break apart monolithic trigger handlers into domain-specific services. Use Apex classes to separate concerns and keep logic cohesive.

😃 Use Custom Metadata for Business Rules

Hardcoding rules in Apex makes maintenance painful. Store business rules in Custom Metadata Types (CMTs) so they can be changed without deploying code.

🧪 Implement Unit Tests with DDD in Mind

Write tests that validate domain logic rather than focusing solely on DML operations.

📩 Design APIs with DDD Principles

When exposing Salesforce data via APIs, keep endpoints aligned with domain models rather than exposing raw Salesforce objects.

FINAL THOUGHTS

CONCLUSION

DDD provides a structured way to design complex Salesforce implementations while keeping business logic clear and maintainable. 🏗️ 

By embracing DDD principles, you can transform your org from a tangled mess of automation into a well-architected, scalable system that grows with the business.

So the next time you're about to cram another trigger into your already overloaded AccountTriggerHandler, take a step back and think:

💃 Would DDD do it differently? 🕺 

Happy coding!

SOUL FOOD

Today’s Principle

"The hardest part of design is keeping features out."

Donald A. Norman

and now....Salesforce Memes

What did you think about today's newsletter?

Login or Subscribe to participate in polls.