Tag: Apex Trigger

  • Designing a Salesforce solution around one metric leadership will actually track

    Ask most delivery teams what a Salesforce enhancement is meant to achieve and you’ll get a feature description back. “We’re adding a custom object for renewals.” “We’re building an approval process for discounts over 15%.” Ask what number on a leadership dashboard is supposed to move because of it, and you’ll usually get a pause.

    That pause is the problem. A solution built without a target metric gets evaluated on whether it shipped, not whether it worked. Six months later nobody can say if the renewals object actually reduced churn, or if the approval process actually cut discount leakage, because nobody wired the build to a number in the first place.

    Why “it works” isn’t the same as “it moved something”

    I’ve sat in enough steering committees to know the difference between a project that’s technically complete and one that’s actually earning its budget. The first gets a green status and a demo. The second gets renewed funding next year because someone can point at a chart and say “that’s us.”

    Most orgs I’ve reviewed have dozens of automations, reports and custom fields that were built for a stakeholder request, went live, and then quietly stopped being anyone’s responsibility. Nobody’s watching whether they’re doing anything. The gap isn’t in testing. It sits earlier, at the requirements stage, long before a single flow gets built.

    Pick the metric before you open the object manager

    Before any real design work starts, force one question: what single number does this need to move, and who already looks at that number every week? Not a KPI you’ll invent for the project. One that already exists on someone’s dashboard, in someone’s board pack, or in someone’s head when they walk into a Monday meeting.

    For a contact-centre client I worked with, that number was average handle time on a specific case type. Not “improve agent efficiency.” Not “modernise the case workflow.” Handle time, on that case type, measured weekly, already tracked by the operations lead before we touched anything. Every design decision after that got tested against one question: does this reduce handle time on that case type, or doesn’t it?

    That constraint kills a lot of scope creep on its own. A nice-to-have field that doesn’t touch the metric gets deprioritised without an argument. A workaround that adds three clicks but saves the agent from a phone call gets fast-tracked, because someone can show the maths.

    What changes in the technical design

    Once you know the metric, it should show up in three places in the build, not just the final report.

    • The data model needs a field or relationship that captures the event driving the metric, at the point it happens, not reconstructed later from case comments or a separate spreadsheet.
    • The automation needs to fire close enough to that event that the data is accurate. A nightly batch job that recalculates handle time after the fact is a different design than a trigger or flow that stamps timestamps as the case moves through statuses.
    • The reporting layer needs to expose the metric in a way the person who owns it can actually check without asking IT for a custom report every Friday.

    Skip any of those three and you end up with a metric that technically exists but nobody trusts, because getting to it takes fifteen minutes and a pivot table.

    A composite example: the discount approval that didn’t cut leakage

    A typical enterprise org I’ve seen runs something like this. Finance flags discount leakage as a problem. The response is an approval process: discounts above a threshold route to a manager before the quote goes out. It ships. Everyone moves on.

    Eighteen months later, leakage hasn’t moved. The approval process captured whether a discount was approved, not what happened to margin as a result. Nobody built a field for the original list price versus the approved price at the line-item level. Nobody reported on override frequency by manager. The process existed, the metric didn’t, and finance is back asking for the same fix under a different name.

    More approval steps won’t fix that. Going back to the one number that actually matters, margin retained per deal, and checking whether the data model can produce it today, will. Usually it can’t, because the build was scoped around the workflow rather than the measurement.

    The scoping conversation this forces

    When a stakeholder brings a request, I ask them to finish this sentence: “I’ll know this worked when [metric] moves by [amount] by [date].” If they can’t finish it, the request isn’t ready for a solution design session yet. It’s a blunt filter, and a genuinely useful one for separating a real business problem from a feature someone saw in a demo.

    It also changes who signs off. A feature list gets approved by whoever asked for it. A metric commitment gets approved by whoever owns that number, and that person has a much stronger incentive to push back on scope that won’t move it.

    What this looks like in a solution design document

    Practically, add one section before the requirements table: the target metric, its current baseline, who owns it, and how the proposed build is expected to shift it. Keep it to a few lines. If you can’t fill it in, that’s the signal to go back and ask better questions before committing engineering time.

    I’ve started refusing to take a build past discovery without this filled in. It’s cut the number of “why did we build this again” conversations down to almost none, mostly because writing the metric down forces a conversation that usually gets skipped entirely.

    Where this earns its keep

    The payoff isn’t just cleaner requirements. It’s a much easier renewal conversation for whoever’s paying for the work. “We shipped the feature” competes for budget every year. “We moved handle time by 22% on the highest-volume case type” doesn’t need to compete. It gets funded again without a fight.

    That’s the actual argument for doing this on every enhancement, not just the big ones. Small requests accumulate into an org nobody can explain the value of. One metric, tracked from design through to the dashboard, is what turns a backlog of tickets into a track record.

  • Event-driven architecture on Salesforce: Platform Events in practice

    Platform Events sound simple in the Trailhead version: publish an event, subscribers pick it up, everyone’s decoupled and happy. Then you build the real thing, and it turns out “decoupled” doesn’t mean “hands off.” I’ve put Platform Events into production for order fulfilment updates, contact-centre status changes and integration retries, and the pattern only pays off if you design for what it actually guarantees, not what the demo implies.

    The problem they’re solving

    Most Salesforce orgs start with point-to-point calls. A case gets updated, a trigger fires a callout to the order system. The order system changes status, a middleware job polls Salesforce for changes. It works until you add a fourth system that also needs to know when a case changes, and now you’re threading callouts through triggers that were never built to fan out to that many places.

    A Platform Event breaks that coupling. The publisher fires one event. Any number of subscribers, inside Salesforce or outside it, pick it up independently. Nobody’s Apex depends on knowing who’s listening. That’s the real win. Not “event-driven” as a buzzphrase, but the fact that adding a fifth subscriber next year costs you a new trigger or a new external listener, not a change to the publisher.

    Where Platform Events beat the alternatives, and where they don’t

    Change Data Capture looks similar and gets picked by default because it needs no code to publish. But CDC fires on every field change to a record, whether or not that change is business-relevant. If you only care about status moving to “Escalated,” a custom Platform Event that you publish explicitly, from the exact place in your code where that transition happens, is a cleaner signal than filtering CDC payloads downstream for the one change you care about.

    Flow and direct Apex calls still win when both sides genuinely need to know the outcome before moving on. If a case can’t be closed until the refund system confirms the payment reversed, that’s a request-reply problem, not a fire-and-forget one. Publishing an event and hoping something eventually closes the case is the wrong tool for a workflow that has a required next step.

    The publish-timing distinction that catches people out

    Salesforce gives you two ways to publish: immediately, or after the transaction commits. Default triggers and most Apex use immediate publish, which means subscribers can receive the event before your database transaction finishes, and before anyone knows whether that transaction actually succeeds. Publish “Order Confirmed” immediately, and if the transaction then rolls back on a validation rule three steps later, you’ve told the world something that never happened.

    Publish-after-commit, using a transaction finalizer or letting the event fire from a change that’s already committed, avoids that. It costs a bit of latency. It’s worth paying for anything a downstream system will act on with real consequences, like triggering a payment or notifying a customer.

    Designing subscribers that survive contact with reality

    A few things I check on every Platform Event subscriber before it goes anywhere near production:

    • Ordering isn’t guaranteed across a burst. If ten events land within the same few seconds, don’t assume your Apex trigger processes them in the sequence they were published. Design the payload so each event is self-contained and idempotent, not a delta that only makes sense if the previous one landed first.
    • Retention is 24 hours, not forever. If a subscriber is down for a day, replay picks up from where it left off using a stored replay ID, but only within that window. A subscriber offline longer than that has lost events permanently, and your integration needs a reconciliation job as a backstop rather than faith in the event stream.
    • Apex trigger subscribers still run inside normal governor limits. A trigger that fires a callout per event, or does a DML per record without bulkifying, hits limits the moment volume climbs past whatever you tested with. Treat a Platform Event trigger exactly like a record trigger: assume it processes 200 events in one execution context, and write it that way from day one, not after the first bulk load fails.

    Where the actual failures happen

    In practice, the outages I’ve seen weren’t about the event bus dropping messages. Salesforce’s delivery is solid. They were about subscribers written to assume happy-path ordering, or a daily event allocation limit nobody was monitoring until a spike in case volume burned through it by mid-afternoon. Platform Events carry a published daily limit per org, and it’s easy to forget it exists until a marketing campaign drives ten times the normal case volume and your integration user starts silently failing to publish.

    Build monitoring around that limit before you need it. A scheduled Apex job that checks consumption against the org limit and alerts at 80% costs almost nothing to build, and it saves you from discovering the ceiling in production, usually during the exact spike you least want to be debugging blind.

    A pattern that actually holds up

    The design that’s worked well for me on contact-centre integrations: publish a small, versioned Platform Event the moment a business-relevant state change is committed. Keep the payload thin, mostly IDs and the new state, not a full record snapshot. Let each subscriber, an Apex trigger updating a related object, an external system via CometD or the Pub/Sub API, a Flow sending a notification, query for whatever additional detail it needs rather than relying on the event to carry everything.

    That last point matters more than it sounds. A thin event means a schema change on the source object doesn’t force you to version the event contract every time someone adds a field. A fat event that mirrors the whole record becomes a maintenance problem the first time three of your five subscribers don’t care about the new field and one of them breaks on it anyway.

    What to check before you commit to this pattern

    Before building a Platform Event architecture for something new, ask whether the receiving side actually needs to react asynchronously, or whether it’s request-reply wearing an event-driven costume because someone read that events are the modern way to integrate. Not every callout needs decoupling. The ones that do, usually notifications, status propagation, audit trails, background enrichment, are worth the investment: looser coupling, an easier path to adding subscribers later, and a clean separation between “this happened” and “here’s what we do about it.”

    Get the publish timing right, design payloads that assume disorder, and put a limit monitor in place before go-live rather than after the first incident. That’s most of what separates a Platform Event implementation that quietly does its job from one that generates a support ticket every time volume spikes.