CTA Awareness study materials
CTA Awareness study resources

340 Components, No Source Control, Three Failed Releases

CTA Awareness · Put your knowledge to work in context.

All case studies

340 Components, No Source Control, Three Failed Releases

A 400-user org has four developers, three full sandboxes and no source control. Releases are assembled as change sets of about 340 components, including 61 Apex classes, 22 triggers, 40 custom fields and 18 flows. The last three releases failed in UAT: two because tests referenced hardcoded record IDs that do not exist outside production, one because a test class used SeeAllData=true and depended on 250,000 seeded rows. Overall coverage sits at 76%, but three triggers have zero coverage. Deploys take 55 minutes and start on Friday nights against a manual 30-step checklist. The next release is due in six weeks and changes a Text field to a Picklist; four integrations read that field. The four developers share one integration user for CI, and the sandbox has not been refreshed in eleven months. Tooling budget is approved; headcount is not.

1. Diagnose why the UAT failures happened and specify the test and code-quality changes required before the six-week release.

Read the worked answer

The failures are test-design failures, not tooling failures. Hardcoded record IDs assume the data in one org exists identically in another; they break on the first sandbox refresh and are the classic symptom of tests that were written against production data. SeeAllData=true makes the test depend on whatever the sandbox happens to contain, so results are non-deterministic and the test cannot be trusted as a gate.

Fix the pattern, not the individual tests: a Test Data Factory that builds the Accounts, Products and Orders each test needs inside @TestSetup, with IDs resolved dynamically from insert results. Ban SeeAllData=true with a static analysis rule in CI. Mark tests that contend on shared data as non-parallel rather than disabling parallel execution globally.

Coverage of 76% is misleading and should be reframed for the team: the deployment requirement is that every class with executable code has at least some coverage, weighted to an org-wide 75%, so three triggers at 0% are both a deployment risk and a signal that nobody tested the logic that matters. Require assertions on behaviour, not just lines executed.

On the field change specifically: converting Text to Picklist fails or loses data when existing values are not in the list, and four integrations will read it. Catalogue every distinct value in production and in each integration's payload, cleanse or stage the change with a temporary field and a backfill, and coordinate a cutover with the integration owners rather than treating it as a metadata deploy.

2. Design the target deployment pipeline and environment strategy within the existing team size and budget.

Read the worked answer

Move to source-driven development. Everything in version control: metadata retrieved with the Salesforce CLI, organised so each component has one owner, with a manifest-based or unlocked-package deployment. Branching model: protected main, short-lived feature branches, pull request with review by one of the other three developers, and a review checklist that includes a test-quality check rather than a coverage percentage.

Pipeline stages: on pull request, validate against an integration sandbox (--test-level RunLocalTests), run static analysis, and block on failure. On merge, deploy to integration and run the smoke suite. Then UAT with a validation-only deploy, so production can use quick deploy once the same validation passes. Use a destructive-changes manifest for deletions and an explicit post-deploy script for permission set assignment, connected app configuration and sharing recalculation - the items the 30-step manual checklist currently covers, which is exactly where human error lives.

Environment strategy given three sandboxes and no new headcount: dev sandboxes per developer, one shared integration, one UAT/full, and a refresh cadence tied to the release calendar, seeded with a data factory rather than a partial copy. Eleven months without a refresh is why the hardcoded IDs survived so long.

Kill Friday deploys. Deploy midweek with named rollback owners and a rehearsed rollback path.

3. What governance controls would you put around shared credentials, change approval and the six-week release itself?

Read the worked answer

Replace the shared CI integration user with a dedicated deployment identity authenticated by a connected app using JWT bearer flow with a certificate stored in the CI secret store. It should hold a minimal deployment permission set group, not System Administrator, and every deployment should be attributable to a pipeline run with a logged initiator. Shared humans-plus-CI credentials are unauditable and a rotation nightmare.

Change approval: define what needs review and by whom. A lightweight change advisory with three tiers works for a team of four - low risk (labels, reports, permission set membership) auto-approved through the pipeline; standard (flows, validation rules, page layouts) reviewed by a peer; high risk (schema changes, sharing rules, integrations, anything touching the four downstream systems) requires an architecture owner plus a written rollback plan and a data-impact statement. The Text-to-Picklist change is high risk by that definition and should be its own release, not bundled with 339 other components.

For the six-week release: freeze scope at week two, run a validation deploy weekly rather than once, and publish a component inventory with owners and dependencies so the 340-item change set becomes a managed list. Record the go/no-go criteria in advance - validation passed in UAT, rollback tested, integrations notified, data cleanse signed off. Report status against those criteria, not against a feeling of readiness.