Writing on Salesforce Development

Short observations from recent engagements. Not marketing — just things we have learned that might be useful.

Apex test coverage: what 95% real coverage actually looks like

Salesforce requires 75% Apex code coverage for production deployment. This means most orgs have tests that exist primarily to pass that gate. Coverage is reported as a single number. The number lies. We have audited dozens of Salesforce orgs in the last three years; the gap between nominal coverage and real coverage is reliably 15-25 percentage points.

Nominal coverage counts lines executed. Real coverage requires meaningful assertions. A test that calls a method and then asserts the result is not null is nominal coverage. A test that calls a method with five distinct inputs and asserts the specific business outcome for each is real coverage. The difference shows up when production behavior breaks and the tests pass anyway.

We use three checks to distinguish: (1) assertion density — at least one assertion per public method tested, ideally per branch; (2) negative-case coverage — every test class has at least one test verifying that invalid input is rejected; (3) data-isolation discipline — no @testSetup methods that quietly leak state, no Test.startTest() blocks that span multiple business operations.

Real 95% coverage on Salesforce is not unreachable; it is unfashionable. The path is: pyright-level test discipline, refusal to ship lines without meaningful assertions, and willingness to refactor untestable code so it can be tested. We have rebuilt test suites from 76% nominal to 92% real on multiple engagements; the regression rate drops 60-80% as a result.

Flow vs. Apex — the decision framework that has not failed us yet

Salesforce has been pushing Flow as the default for business logic since 2021, and the message has landed: orgs are migrating Process Builder and Workflow Rules to Flow at scale. The pendulum has swung too far. Complex logic in Flow becomes unreadable and untestable — and we are now seeing orgs where Flow has accumulated the technical debt that Apex used to carry.

Our decision framework: if the logic has more than 6 decision branches, more than 2 loops, or any non-trivial collection manipulation, Apex is the right answer. Flow excels at simple field updates, simple record creation/update, and screen flows for user interaction. Beyond that, the readability and testability gap with Apex grows fast.

The argument against Apex — that it requires developer skills and slows iteration — is real but overstated for orgs that already have an engineering team. If your business stakeholders are building Flows directly, Flow is the right tool. If your engineering team is maintaining the Flows that business stakeholders built, you have the worst of both worlds: code-shaped logic that you cannot version-control cleanly or test rigorously.

The realistic answer for most orgs in 2026: build a Flow vs. Apex policy and enforce it in code review. Logic complex enough to need debugging belongs in Apex. Logic simple enough that a non-engineer should maintain it belongs in Flow. The boundary is a judgment call, but having an articulated boundary is half the battle.

Salesforce CI/CD in 2026 — honest comparison of Copado, Gearset, sfdx + GitHub Actions

Salesforce CI/CD remains harder than it should be. The tooling has matured significantly since 2020, but the three main approaches (Copado, Gearset, sfdx + GitHub Actions) each have real strengths and real failure modes. We have rebuilt CI/CD pipelines for 11 orgs in the last 18 months across all three approaches, and the choice that makes sense depends on team shape more than features.

Copado. The premium tier. Strong for orgs where business stakeholders need visibility into the deployment pipeline and where managed services support is valuable. The UI is comprehensive; the learning curve is real. License cost is significant — typically $4,000-$8,000/month for mid-size teams. Pick Copado when you have stakeholders who will use it and a budget that can absorb the cost.

Gearset. The sweet spot for most mid-size engineering teams. Strong static-analysis features, good monitoring, predictable license cost ($2,000-$4,000/month). Less feature-rich than Copado but the features it has are well-executed. Pick Gearset when engineering owns the deployment pipeline and you want a turnkey solution.

sfdx + GitHub Actions. The path for teams that want full control and have the engineering discipline to maintain CI/CD themselves. Zero license cost beyond GitHub Actions usage. Steepest learning curve. Highest ceiling. Pick this when you have a strong engineering team that prefers code-driven infrastructure and is comfortable maintaining custom CI pipelines.

What does not work well in 2026: tools that try to do unmanaged-package source tracking, hand-rolled Ant scripts (long deprecated but still seen in legacy orgs), and any pipeline that includes manual approval steps as a substitute for automated checks. The pipelines that fail in production are the ones where the test gates exist but are routinely overridden.

LWC composition patterns we have made work — and ones we have stopped using

Lightning Web Components launched in 2019 and has matured into a genuinely good component framework — better than Aura, comparable to general-purpose JS frameworks for the constrained problems it has to solve. We have built and maintained 60+ LWC components across client engagements; some early architectural patterns have proven durable, others have not.

Composition over inheritance — durable. Build small, focused components and compose them. Avoid extending base Lightning components beyond what the docs explicitly support. When LWC components break (industry pattern) on Salesforce releases, it has been inheritance-heavy designs that broke.

Lightning Data Service over Apex calls — durable for record-centric components. The cache behavior is genuinely useful. The reactivity model is solid. We use LDS for any component that displays or edits a specific record. We use Apex calls (with @AuraEnabled cacheable=true) for everything else.

Custom state management — we have stopped doing this. The early instinct to bring Redux-style state management to LWC was wrong. The component model is reactive enough; the data layer (LDS, Apex caches) is what needs care. We have removed custom state management from three engagements where the previous team added it.

CSS encapsulation discipline — durable but easy to violate. The shadow DOM gives you CSS encapsulation for free. The cost is that styling consistency across many components requires explicit design tokens. We use Salesforce Lightning Design System (SLDS) tokens where they fit, and a small set of custom tokens where they do not. Hard-coded colors in LWC are a smell.

Older notes available on request.