Admin & Operations

Operations

A technical debt audit you can run on your own org

Most audits produce a list nobody acts on, because everything gets listed and nothing gets ranked. This one is ordered, and every item ends in a decision.

Stacks of old paper files tied with string, edges worn from years in storageAdmin & Operations

Ask for a technical debt audit and you usually get a spreadsheet with several hundred rows, sorted by object, with a severity column somebody filled in from instinct. It gets circulated, admired, and never actioned, because it presents four hundred problems of apparently equal standing to a team with capacity for six.

The fault is not the finding. It is that the audit answered the wrong question: what is wrong with this org, which has no end, rather than what is costing us something we would rather stop paying.

Debt that costs nothing, and debt that costs every sprint

Debt has a carrying cost, and the carrying cost is what makes it worth paying down. A badly built custom object supporting a process retired in 2021, on a page layout nobody opens, is not costing anything. It is ugly. Ugly is free.

The same standard of build sitting on Opportunity, in the path of every change your team makes, charges you on every release: an extra hour of impact analysis, an extra deployment failure, an extra caveat in every estimate. That is the debt worth money.

So the useful audit is a survey of where work happens, ranked by how often the debt is in the way. Two questions run through every area below.

Is anything paying for this today? Not could it theoretically cause a problem, but is it slowing a release, breaking a report, blocking an onboarding, or failing an audit right now.

What would it cost to stop paying? Some debt is expensive to carry and cheap to fix. That is where you start, and it is rarely the thing with the scariest label.

What you collect, and the order to collect it in

Run the areas in the order below: the early ones give you the map you need to read the later ones. Two days of collection is normally enough for a mid-sized org, most of it from Setup, a handful of reports, and your metadata in source control.

First pull the org-wide numbers that give everything else context: the Security Health Check score with the settings behind it, and the Setup Audit Trail export for the last twelve months, which tells you where change actually lands. The audit trail is the most underused input here: the objects appearing most often in it are where debt is expensive.

Objects and fields nobody uses

Inspect. Custom objects with low or zero record counts and no recent record creation. Custom fields with high blank rates. For each candidate field, the references: page layouts, list views, reports, automation, validation rules, Apex, and anything an integration writes to.

A bad result looks like. Fields with no data and no references, in numbers large enough to make the field list unreadable. Several fields on one object holding the same value under different names, which is what happens when nobody could find the original. Objects with a few hundred records, none created in two years, still on a profile's tab set.

The trap is treating unused and rarely used as one category. Unused means nothing writes it and nothing reads it. Rarely used means it is populated at year end, or by one team in one region, or by a partner process running quarterly. A usage percentage cannot tell those apart, and deleting a rarely used field is how an org discovers a process it never documented.

Decide. Does anything read this field, in any release of the last year? If nothing reads it and nothing writes it, remove it. If something reads it rarely, the finding is not the field: it is a business process running with no owner and no documentation, which is a different fix.

Automation on one object, where order matters more than count

Inspect. For each busy object, list everything that fires on save: record-triggered flows, Apex triggers, any surviving workflow rules, managed package logic. Note the timing of each and any explicitly set ordering.

A bad result looks like. Two or more automations at the same timing on the same object with no explicit order, where one writes a field the other reads. Logic that fires, evaluates a condition and exits, on every save of a high-volume object. A chain that re-enters itself through a field update nobody traced.

Count is the wrong metric. Ten well-ordered automations on Account are healthier than three that fight. You are looking for dependency: places where one piece of logic is only correct because another ran first, and nothing records that.

Flow conventions for naming, ownership and consolidation are their own subject, covered in Flow in a large org: conventions that hold at a hundred flows. For the audit, one line is enough: note whether the object carries more automations at a given timing than anybody intended.

Decide. If this object's automation ran in a different order tomorrow, would anything break? If yes, and the order is not set explicitly and written down, that is a defect waiting for a release, not a tidiness issue.

Code without tests, and coverage that asserts nothing

Inspect. Test coverage per class, then open the tests on the classes that matter most. Read what they assert. Check whether they create their own data or rely on what happens to be in the org.

A bad result looks like. Test methods that call a method, assert nothing, and exist to move a percentage. Tests that pass regardless of what the code returns. Classes whose coverage has never produced a failing deployment, which usually means nothing in them is meaningfully exercised.

Coverage counts lines executed and says nothing about whether the behaviour is correct. A class at high coverage with no assertions is worse than one with none, because it produces a green deployment and a false sense of protection. When platform coverage requirements come up, check the current Salesforce Well-Architected material and product documentation rather than a remembered figure, because those rules change.

Decide. If this class were broken tomorrow, would a test catch it? If the honest answer is no, the coverage number is decoration, and the class is untested for estimating purposes.

Hard-coded IDs and environment-specific values

Inspect. Search Apex, flows, formulas, validation rules and email templates for record type, user, queue, group, profile and report IDs, endpoint URLs and instance-specific links.

A bad result looks like. An eighteen-character ID sitting in a formula. A named credential's job being done by a URL literal in a class. A flow that assigns a case to a queue by ID, so it works in production and silently misroutes in every sandbox.

This is the cheapest area to inspect and one of the more expensive to leave, because the failure mode is a deployment that succeeds and then behaves differently per environment. It gets reported as "it worked in UAT", and costs a day of investigation every time.

Decide. Would this value be correct in a freshly refreshed sandbox? If not, it belongs in custom metadata, a custom setting, a named credential or a developer name lookup, and the fix is normally an afternoon.

Three shorter passes: access, validation rules, reporting

Access, one item. Count permission sets with no assignments, users with broad data access, and licences assigned to people who never log in. Those three numbers say whether access is a finding here. If they are bad, access is its own project rather than a checklist row, and the method is in Permission set debt: how orgs quietly lose track of who can see what.

Validation rules users have learned to defeat. Inspect the rules on your highest-volume objects and, more usefully, the data underneath them. A bad result is a required field where a visible share of records carries a placeholder: a full stop, the word "unknown", a repeated dummy value, a date far in the past. The rule is being satisfied rather than obeyed, and the data is now less trustworthy than before it existed. Decide by asking whether the rule blocks work that legitimately needs doing. If it does, the rule is the debt, not the users.

Reports and dashboards nobody opens. Inspect last-run dates and the folder structure. A bad result is thousands of reports in personal folders, several near-identical versions of the same leadership dashboard, and no way to tell which one the board sees. Decide by asking whether anybody would notice its absence in a quarter. Unopened reports cost little at runtime, but they make the reporting surface unusable, which pushes people into building another copy.

Integrations with no owner and no error handling

Inspect. List every inbound and outbound integration, including any running through an integration user nobody recognises. For each, record the owner, the authentication method, where failures surface, and what happens to a record when a call fails.

A bad result looks like. An integration whose owner is a departed employee, or a vendor whose contract nobody can find. Failures written to a debug log and nothing else. A callout with no retry and no dead-letter path, so a transient outage leaves permanently missing records nobody sees until month-end reconciliation.

This is consistently the most expensive debt in the orgs we review, and the least visible, because a broken integration usually fails quietly.

Decide. If this failed at 2am on a Saturday, who would find out, and how? If the answer is that somebody notices bad numbers days later, the debt is not the integration design but the absence of monitoring, which is usually the smaller fix.

The sandbox and release path

Inspect. How a change gets from a developer to production: sandbox tier and refresh cadence, whether deployments are automated, how long a routine release takes, and how many attempts a typical deployment needs.

A bad result looks like. Changes made directly in production because the path is too slow to use. Sandboxes refreshed so rarely they no longer resemble the org. Deployments that routinely fail on the same familiar errors, each attempt costing somebody twenty minutes.

This area has the highest carrying cost, and it belongs in a debt audit because everything else you found has to travel through it to be fixed. Debt here multiplies every other item on the list. The related discipline of keeping ahead of platform change is in How to triage a Salesforce release in thirty minutes.

Decide. How many hours does a routine change cost end to end, and how much of that is waiting or repeating? If the answer is most of it, fix this before anything else on the list.

Documentation that has drifted from the org

Inspect. Take three things the documentation asserts and check them against the org. A named owner, a described process, a stated integration behaviour.

A bad result looks like. All three wrong. Partly wrong documentation is worse than none: it is trusted until it is caught out, and everyone who trusts it pays the cost of discovering that separately.

Decide. Would a new admin be safer with this document or without it? If without, delete it and write one page that is true. Documentation living beside the thing it describes, in a flow or field description, drifts far more slowly than a wiki page.

The checklist, in one table

AreaInspectA bad resultDecide
Objects and fieldsRecord counts, blank rates, referencesFields with no data and no references; duplicates under different namesDoes anything read this in a full year?
Automation orderingEverything firing per object per timingSame-timing logic with no explicit order and a shared fieldWould a different order break something?
TestsCoverage, then what the tests assertCoverage with no assertions; tests that pass regardlessWould a test catch this class breaking?
Hard-coded valuesIDs, URLs, endpoints in code and configRecord type or queue IDs in formulas and flowsWould this be correct in a fresh sandbox?
AccessUnassigned sets, broad access, idle licencesNumbers nobody can explainIs access a project, or a row on this list?
Validation rulesRules plus the data under themPlaceholder values satisfying required fieldsDoes the rule block legitimate work?
ReportingLast-run dates, folder structureDuplicate leadership dashboards, no canonical versionWould anybody notice its absence?
IntegrationsOwner, auth, failure handlingNo owner; failures visible only in a logWho finds out at 2am, and how?
Release pathCycle time, deployment attempts, refresh cadenceChanges made in production to avoid the pathHow much of a change is waiting or repeating?
DocumentationThree assertions checked against the orgPartly wrong, therefore trustedSafer with it or without it?

Sequence by pain per sprint, not by severity score

Severity scores measure how bad something would be if it went wrong, which is a question about a hypothetical. Pain per sprint measures what is already being spent, which is a question about last month, and your team can answer it from memory.

Sort what you found into four groups.

Bleeding. Costing time or trust every sprint: the release path, the integration with no monitoring, the automation ordering on your busiest object. These go first regardless of how small they look, because the saving repeats.

Cheap and permanent. Hard-coded IDs, unassigned permission sets, genuinely dead fields. Low value each, but they never come back once fixed, and they clear noise that hides real findings.

Expensive and contained. A badly built object nobody touches. Record it, note what it would cost, and leave it until something makes you open it. Fix it then, as part of that work, when you are paying the analysis cost anyway.

Accepted. Everything you have decided not to fix, with the reason and the date. This is the group that makes the audit reusable, because in eighteen months somebody will ask about the same item and the answer will already exist.

The output that survives is short: three or four things being fixed now, a handful of cheap items attached to work already scheduled, and a written record of what was deliberately left. Run it again in a year, and the measurement that matters is not how many findings you have, but whether the bleeding group has shrunk.

Sources

  1. Salesforce Well-Architected
  2. Security Health Check
  3. Monitor Setup Changes with Setup Audit Trail

Common questions

Answered, directly.

The questions this piece settles about Admin & Operations, answered in full on this page.

Work through the org in a fixed order and record three things per area: what you inspected, what the result was, and whether the debt costs anything on a recurring basis. Areas worth covering are unused schema, automation ordering, untested code, hard-coded values, access, validation rules, reporting, integrations, the release path and documentation.

Unused means no data and no references: nothing populates it and no report, automation, layout or integration reads it. Rarely used means it is populated infrequently but something depends on it, often an annual or quarterly process. Field usage counts alone cannot separate the two, so check references and ask the owning team before deleting anything.

By pain per sprint rather than by severity score. Debt that slows or breaks work every release earns remediation; debt in a component nobody touches can be recorded and left alone. Anything with a compliance or security consequence is the exception, because its cost arrives all at once rather than gradually.

Free architect conversation

Talk to an architect, not a sales rep.

Salesforce org health check. 60 seconds to brief us, and a certified architect replies within one business day.

What is making the org hard to run?

Pick the closest fit. The health check is free and the findings are yours whether or not we do the work.

Which parts of the org are the problem?

Optional. Choose any that apply, or skip ahead.

Where does your org stand today?

Optional. A few sentences is plenty: what is working, what is stuck, and what you want to be true. Or skip ahead and tell us on the call.

Who should the architect reach?

A certified architect will reply to these details.

Takes about 30–60 seconds · No obligation · Architect replies within one business day

Protected by reCAPTCHA. Google's Privacy Policy and Terms apply.

More from Insights

Read by desk

Ten desks, one delivery team. Every piece is written by the people who do the work.