Salesforce Developer common mistakes
Salesforce Developer · Understand the traps and how to avoid them.
Answers a record-access question by naming the user's Profile or Permission Set, and answers an object/field-access question by naming the user's Role in the role hierarchy.
Both settings live under the same user record and both are called 'security', so candidates collapse them into one idea and stop reading whether the question is about records or about objects and fields.
What to do instead
Split security into two buckets before answering: object/field access = Profile + Permission Sets (CRUD, FLS, system permissions); record access = OWD, role hierarchy, sharing rules, manual sharing, teams. Say the bucket name out loud, then pick the option from that bucket.
Assumes a sandbox refresh will push work built in the sandbox up to production, or that metadata can be deployed from production back into a sandbox with a change set.
The word 'refresh' sounds bidirectional, and sandboxes feel like branches in source control, so candidates treat them as two-way sync.
What to do instead
Memorise the one-way arrows: a sandbox refresh copies production configuration (and optionally data) down and overwrites the sandbox; sandbox to production moves upward only via change sets or the Metadata API. Production to sandbox is only a refresh, never a deployment.
Chooses Master-Detail for a child object on the assumption it is 'stronger', then cannot answer where the child record goes when the parent is deleted, or how the field can be made optional.
Candidates learn that Master-Detail enables roll-up summaries and assume it is the default best choice, without checking the three consequences: required field, cascading delete, and no independent lifecycle for the child.
What to do instead
Decide from requirements first. If the child must be optional, must be reparentable without limits, or must survive the parent, choose Lookup. If the child cannot exist alone and should cascade-delete, choose Master-Detail. Only then check whether a Roll-Up Summary field is required, because that natively needs Master-Detail.
Picks 'create a Roll-Up Summary field' as the solution for aggregating child records through a Lookup relationship, or picks 'mark the field as Unique' as the fix for an upsert that fails to match records.
Roll-up summaries and unique fields are the two declarative features candidates remember, so they attach them to the wrong relationship or the wrong field property without checking the prerequisites.
What to do instead
State the prerequisite with the answer: native Roll-Up Summary requires Master-Detail (lookup aggregation needs a Flow, trigger, or third-party rollup tool); upsert matching requires the field to be marked External ID (and Unique for the match to be reliable), not just any text field.
Builds a record-triggered before-save Flow containing a Create Records element, an Update Records element on a different object, or an HTTP Callout, and expects it to save successfully.
The Flow canvas offers the same elements under both triggers, so candidates assume the trigger type only affects timing, not which elements are legal.
What to do instead
Remember: before-save = same record, in memory, no DML, no callouts, no governor-counted database work. Move anything that touches another record or an external system into an after-save flow, and keep before-save for overwriting fields on the triggering record.
Writes an after-save flow that updates a field on the record that fired it, with no guard, and expects it to run once.
Candidates think of the flow as an event handler like a UI callback; they do not account for the update re-entering the automation engine as a new save.
What to do instead
Use a before-save flow for same-record field changes, which never re-triggers. If the update genuinely must be after-save, add an entry condition that excludes records already in the target state (for example, a checkbox or a comparison against the prior value) so the second pass exits immediately.
Describes the page layout assignment screen (Setup > Object > Page Layouts > Page Layout Assignment) when asked how different users see different fields on a Lightning record page, or describes activating a Lightning page when asked which fields appear in a related list.
Page layout assignment and Lightning page activation both use profiles and record types as their targeting, so the two screens look interchangeable when recalled from memory.
What to do instead
Keep the split: page layout assignment controls fields, related lists, buttons and record types per profile; Lightning App Builder activation controls which Lightning record page (and therefore which components and Dynamic Forms) a given app, record type and profile gets. Most 'different users, different fields' questions in Lightning are really about Dynamic Forms on an activated Lightning page.
Writes one test method that inserts a single record, performs no System.assert, and relies on 'no exception thrown' as proof, then is surprised the deployment still fails or that a bug reached production.
The goal is perceived as 'get 75% coverage', and a single-record happy path produces coverage lines fastest, so assertions and bulk behaviour are treated as optional extras.
What to do instead
Write to a template: create data, wrap the exercise in Test.startTest()/Test.stopTest(), run the code, assert specific field values (not just non-null) with System.assert/Assert.areEqual, and repeat with a bulk list of 200 records to expose per-record SOQL or DML. Use System.runAs to prove behaviour for a specific user.
Believes the deployment gate is a single 75% number, so a class with 80% coverage that contains a trigger with no direct test is treated as safe, and a validation erroring test is counted as contributing coverage.
The 75% org-wide figure is the one repeated in every study resource, so the per-trigger rule and the fact that only passing test methods count are dropped.
What to do instead
Remember the two-part rule: 75% org-wide for Apex, and every trigger must have at least some coverage from a test that actually executes it. Also remember coverage comes only from successfully executed test lines, so a test that fails on an assertion or an unhandled exception contributes nothing and blocks deployment.
Inserts System.debug() calls, runs the code, sees nothing in the log, and concludes the debug statement or the code path is broken; or reads a log without first checking which log level was captured.
Candidates assume debug output is always captured, not that each log level (none, error, warn, info, debug, fine, finer, finest) is a filter set by a trace flag and a debug level, and that the log truncates at a size limit.
What to do instead
Before interpreting any log, open the trace flag and confirm the debug level sets Apex to FINEST and System to DEBUG for the user and time window. Then use the Execution Log tabs (Execution Tree, Stack Tree) and filter by the class name rather than scrolling, and shorten the window if the log was truncated.