Interview guides · Aptino
Aptino Software Engineer Interview Guide
Aptino Software Engineer interview guide: the Screening Call and Technical Deep-Dives, SFMC data questions, worked answers and a 7-day plan.
The 60-second brief
Candidates describe Aptino's Software Engineer role as client-facing marketing-technology work, built mostly around Salesforce Marketing Cloud (SFMC) and data-heavy environments. The engineer turns client and business-unit needs into working campaign logic: writing the segmentation rules that decide who receives a campaign, building the workflows that move and transform the data behind those segments, writing technical specifications, and keeping data correct across the platforms involved. Candidates also list User Acceptance Testing (UAT) and campaign deployment as part of the job, along with gathering and documenting requirements for marketing campaigns. That makes the work half data engineering and half requirements analysis, so prepare for both.
This guide is for engineers interviewing for the Software Engineer role at Aptino, especially those coming from CRM, marketing-automation or data-integration work. It covers the two reported stages, the five reported questions (scalable data workflow design, data accuracy at volume, SFMC or CRM experience, turning client requirements into specifications, and troubleshooting an integration), and the topics candidates list: SFMC, SFMC Data Management, Software Engineering, UAT and Requirements Gathering. The requirements candidates describe are 3-5+ years in technical roles, strong data analysis, CRM or SFMC experience and a background in documentation and requirements gathering. Financial-services experience, advanced SFMC certification and cross-functional stakeholder management are listed as nice-to-haves.
Candidates report two stages over roughly 2-4 weeks: a Screening Call about fit and the role, then Technical Deep-Dives, described as several in-depth technical interviews held over video.
Focus areas
- Salesforce Marketing Cloud (SFMC)
- Software Engineering
- SFMC Data Management
Overview
The reported questions are not algorithm puzzles. Two are design questions about data (how you build a scalable data workflow, and how you keep data accurate at high volume), one asks how you turn client requirements into specifications, and two ask about your own experience: SFMC or a similar CRM, and an integration issue you had to troubleshoot. Most of your preparation should go into explaining real systems you have built and the reasons behind each choice, with enough technical detail to hold up under follow-up questions.
The technical areas candidates describe for this loop are data modelling, system design, code quality (testing, code review, technical debt), requirements gathering, root cause analysis and trade-off analysis. Example scenarios candidates mention include walking through the architecture of your most complex project and redesigning an existing workflow to cope with ten times the data. Prepare one project you can take apart layer by layer: the data model, how data enters and leaves, what happens on failure and rerun, how you tested it, and what you would change now.
Because the role centres on SFMC, refresh how marketing data is actually handled there if you have used it: Data Extensions and their primary keys, sendable Data Extensions related to a subscriber key, SQL Query Activities with Append, Update or Overwrite actions, Automation Studio for scheduled imports and queries, Journey Builder for orchestration, and AMPscript for personalisation. If your background is a different CRM or marketing platform, map each of those ideas to what you used and be clear about the gap.
Data accuracy runs through the whole role as candidates describe it: segmentation, campaign deployment and UAT all fail visibly when the data is wrong, because the wrong people receive a message or the right people miss it. Have concrete controls ready to name (deduplication on a key, reconciliation counts, suppression and opt-out checks, test sends to a seed list before launch) and a story showing that you caught a data problem before it reached a customer.
The Aptino interview process
Candidates report a Screening Call followed by a Technical Deep-Dives stage made up of several technical interviews over video, about 2-4 weeks end to end.
Screening Call
Candidates describe the Screening Call as an initial conversation to assess fit and discuss the role. No technical exercise is reported for it. Use it to show quickly that your background matches the requirements candidates describe for this role: years in technical roles, hands-on data analysis, CRM or SFMC work, and requirements and documentation experience. Be accurate about your SFMC depth here, because the Technical Deep-Dives that follow go into your past work in detail and any overstatement will come up there. Ask which parts of the campaign lifecycle the role owns (requirements, build, UAT, deployment), so you know which of your stories to lead with later.
What to demonstrate
- Fit for the role as discussed on the call
- How your background matches the reported requirements: technical experience, data analysis, CRM/SFMC and requirements documentation
How to prepare
- Write a short career walkthrough that names one data-workflow project, one CRM or SFMC project and one requirements-to-delivery project, each with a number (records, campaigns, defects caught).
- Write an honest one-paragraph answer on your SFMC or CRM depth: which tools you used yourself and which you only know from the outside.
- List three questions about the role, for example how requirements reach engineering, who runs UAT, and how campaign deployments are released.
Technical Deep-Dives
Candidates report the Technical Deep-Dives as several in-depth technical interviews held over video, and say they go past the résumé into the reasons behind technical decisions. The technical areas candidates describe for the loop are data modelling, system design, code quality, requirements gathering, root cause analysis and trade-off analysis, with example scenarios such as walking through your most complex project's architecture or scaling an existing workflow to ten times the data. Treat each interview as a structured explanation: state the context and constraints, draw the data flow, name the decision and the alternative you rejected, then say how you verified the result. When you do not know something, say so and reason through it out loud. Candidates report that this is the right move.
What to demonstrate
- Depth of technical knowledge in your own past projects, including why each choice was made
- Data modelling and workflow design for data-heavy work
- Structured debugging and root cause analysis
- Turning ambiguous requirements into precise, testable technical decisions
How to prepare
- Diagram your most complex project end to end (sources, data model, transformations, outputs, failure handling) and practise explaining it over a shared screen.
- Work through scaling one of your own workflows to ten times the data: identify which step breaks first (full reloads, unindexed joins, per-row API calls) and what you would change.
- Write SQL for two segmentation tasks: deduplicate contacts by key with ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...), and build an audience that excludes unsubscribed or suppressed records.
- Prepare STAR stories for an integration you debugged and a requirements flaw you caught, both told in the first person singular.
Where candidates lose points
Answering the SFMC or CRM question with a list of tools and no project, decision or outcome attached.
Prepare one platform story built around a decision you made: the segmentation logic you wrote, how you deduplicated contacts on a key, how you kept suppressions out, and a number at the end. If your platform was not SFMC, map its pieces to SFMC equivalents and name the gaps yourself instead of waiting to be caught on them.
Designing a data workflow with no answer for reruns, so a retry or backfill would duplicate rows or send a campaign twice.
For the scalable workflow question, make idempotency part of the design from the first sketch: raw staging, upserts on a primary key, watermark-based incremental loads, and an orchestration rule that stops downstream steps after a failure. Practise explaining how you would rerun one failed day safely.
Treating data accuracy as 'I test thoroughly' without naming a single check, threshold or reconciliation.
Have a short list of named controls ready: reconciliation counts between source and target, uniqueness on keys, normalised join keys, a quarantine table for rejected rows, expected-range alerts on audience size, and a seed-list send before launch. Decide in advance which of them block a send.
Describing requirements work as 'I meet the client and document what they want' with nothing testable at the end.
Show how a vague request becomes precise rules and acceptance criteria, and how those criteria turn into UAT test cases. Prepare one real example where pinning down a definition such as 'active customer' changed the build.
Walking through your most complex project at the level of the résumé, without being able to explain the data model, failure handling or the alternatives you rejected.
Diagram that project before the Technical Deep-Dives and prepare the reason behind every major choice: why that data store, why batch or near-real-time, how it was tested, what you would change now, and what would break at ten times the data.
Questions & practice
Collapse a redelivered event batch into per-aggregate high-water marks
Easy · hashing · at-least-once · aggregation
You drain a batch of up to 5,000,000 events, each (aggregate_id BIGINT, aggregate_version INT, event_type, payload). The log guarantees order within one aggregate only; the batch merges 64 partitions, and a relay failover has redelivered a range, so an older version for an aggregate can appear after a newer one. Given a map of last_applied_version per aggregate, produce the events worth applying, at most one per (aggregate_id, version), plus the count discarded. Target O(n) time. State the memory for 2,000,000 distinct aggregates and what you do when it does not fit.
Approach
- One pass, one hash map from aggregate_id to the highest version kept, and a discard counter. An event whose version is at or below last_applied_version for its aggregate is dropped without further work, which is the whole reason the event carries its version rather than a delta. O(n) expected time, O(d) space in distinct aggregates.
- Keep the maximum, never the last occurrence. The redelivered range means the final appearance of an aggregate in the batch can be an older version than one seen earlier in the same batch, so last-wins applies stale state over newer state and the projection regresses with no error anywhere.
- Cost the memory instead of calling it large: an 8-byte key plus a 4-byte version is 12 bytes of payload, and an open-addressed table held at a 0.7 load factor costs roughly 17 bytes per entry before per-slot metadata, so 2,000,000 aggregates is tens of megabytes in a native layout and several times that in a runtime that boxes both key and value.
- If the distinct set exceeds memory, partition on hash(aggregate_id) mod P and reduce each partition independently. Every event for one aggregate hashes to the same partition, so the per-partition result is exact and the merge is concatenation rather than a second reduction.
Follow-up
- The payload is a patch rather than a snapshot, so applying only the highest version loses the intermediate changes. What changes in your reduction?
- How do you detect that version 7 arrived while version 6 was never delivered, and what should the consumer do about the gap?
Diff a projection against the primary without per-row point reads
Hard · reconciliation · range hashing · throttling
The listing projection has drifted and some rows show a stale version. The primary holds 40,000,000 resource rows across 12,000 tenants while serving 1,200 writes and 14,000 reads per second. The obvious repair, reading each resource row and comparing its version against the projection, is correct and would eventually finish. Explain precisely why it is unacceptable here, then give a diff that finds the differing rows, state its complexity, and make it safe to run against a live primary. Replication lag is usually under 100 ms and is not bounded.
Approach
- Quantify the naive cost rather than calling it slow: 40,000,000 point reads at even 0.5 ms each is over five hours serialised, and the only lever is concurrency, which is exactly what you cannot spend. The primary's pool is sized for the write path, and 40,000,000 random reads evict the buffer cache that sustains the 85 percent cache hit rate, so the audit degrades the system it is auditing.
- Replace random access with one ordered pass per side. Both sides can be read in (tenant_id, resource_id) order, which is a sequential scan on each and a merge join in O(n) time and O(1) memory. For a dense diff that is the whole answer, and it reads the primary once instead of 40,000,000 times.
- For the expected sparse case, compare range hashes instead of rows: partition the key space, compute per range an order-independent aggregate over hash(resource_id, version), compare aggregates, and descend only into ranges that differ. With d differing rows and branching factor B, at most d ranges mismatch per level, so the drill-down examines O(d log_B(n/d)) ranges and reads full rows only in mismatching leaves.
- Aggregate with a sum modulo 2^64 or a multiset hash, never XOR. XOR is order-independent but self-cancelling, so two rows wrong in the same way, or a row duplicated on one side, leave the range aggregate matching and the range is declared clean.
Follow-up
- The diff reports 900 stale rows. How do you decide between patching those rows and rebuilding the projection from resource_revision?
- Same job, but the projection lives in a search index that cannot be scanned in key order. What changes?
Archive a resource graph without breaking live references or recursing
Medium · graph traversal · topological order · tenant isolation
Resources reference other resources within a tenant; for the largest tenant the reference table holds up to 2,000,000 nodes and 8,000,000 edges. Archiving a resource must archive everything reachable from it that nothing outside the set still references, refuse when a live external referrer exists, and terminate when references form cycles, which they legitimately do. Produce the archive order and the refusal list, targeting O(V+E). Say what stops the traversal crossing a tenant boundary, and why recursion is the wrong control structure at this size.
Approach
- Load the subgraph with the tenant predicate on both endpoints of the edge, not only on the side you started from. Scoping the left table alone is the classic cross-tenant leak: one mis-entered edge then pulls another tenant's resources into the traversal and, worse, into the archive.
- Traverse iteratively with an explicit stack. A 2,000,000-node graph can hold a chain deep enough to exhaust a native stack in the low tens of thousands of frames, and that failure is a process crash rather than an error you can return.
- Treat cycles as data rather than corruption: compute strongly connected components with Tarjan in O(V+E) using its own explicit stack, then condense. The condensation is a DAG, so a topological order over it gives the archive order, and every member of a component archives in one transaction because no order within a cycle is valid.
- Decide refusals with reverse edges. A candidate is archivable only if every in-edge originates inside the candidate set, so build the transpose or count in-degrees restricted to the visited set, and emit each blocked resource with the id of the external referrer, which is the only part of the answer an operator can act on.
Follow-up
- The graph is read in one query and the archive writes a minute later. What can change in between, and how do you make the write safe?
- The candidate set is 400,000 resources. Is that one transaction, and if not, what does a half-finished archive look like to a reader?
Denormalise tenant onto revisions and backfill it live
Hard · denormalisation · online migration · backfill
resource_revision (revision_id, resource_id, version, actor_user_id, change_kind, patch, request_id, created_at) has 400M rows and no tenant column; tenant_id lives only on resource. Two reads need it: a tenant-scoped audit feed ordered by created_at DESC, and an offboarding purge. Both join back to resource today. Justify adding tenant_id to resource_revision against those two reads, name the anomaly the copy introduces and the constraint that prevents it, then give the ordered migration for a live table taking 1.2k writes/second — the lock each step takes, how the backfill is batched, and where each step stops being reversible. PostgreSQL 16.
Approach
- Justify from the access path rather than from taste. Without the column, the audit feed either scans resource_revision by created_at and discards other tenants' rows, or resolves the tenant's resource_ids first and probes with them — both proportional to the tenant's whole history rather than to one page. With (tenant_id, created_at DESC, revision_id DESC) it is a seek that stops at 50 rows, and the purge becomes a ranged delete instead of a join.
- Name the cost exactly: a second copy of a fact can disagree with the first. Make the disagreement unwritable rather than documented — add UNIQUE (resource_id, tenant_id) on resource so it can serve as a foreign-key target, then FOREIGN KEY (resource_id, tenant_id) REFERENCES resource (resource_id, tenant_id) on the revision table. A revision can then only ever carry its parent's tenant.
- Step one, expand: ALTER TABLE resource_revision ADD COLUMN tenant_id BIGINT NULL, with no default, so it is a catalogue change and no rewrite. It still needs ACCESS EXCLUSIVE for an instant, and that instant queues behind the longest open transaction on the table while every later query queues behind it — set lock_timeout to 2s and retry rather than wait.
- Step two, dual-write: deploy the writer that populates tenant_id on every new revision while reads still use the join. Reversible by redeploying the previous build, because nothing reads the column yet.
Follow-up
- The backfill is half finished and a rollback is required. What state is the table in, and what does the previous build do with a half-populated column?
- How do you verify the backfill actually finished, given rows are still being inserted while it runs?
Hold a per-tenant active cap against concurrent creates
Hard · write skew · isolation levels · constraints
A tenant on the standard plan may hold at most 50 resources with status='active'. The create handler runs SELECT count(*) FROM resource WHERE tenant_id = $1 AND status = 'active', compares to 50, then inserts. Two creates arrive 3 ms apart on different instances and the tenant lands at 51. Name the anomaly, say whether PostgreSQL 16 READ COMMITTED or REPEATABLE READ prevents it and why, then give an implementation that holds the cap at READ COMMITTED with the exact statements. Finally, say what changes when the cap is 'at most one running export per tenant' on job_run.
Approach
- Name it: write skew. The two transactions read an overlapping set and write disjoint rows, so there is no row-level conflict for the engine to detect and each commit is individually legal.
- Rule out the levels precisely. READ COMMITTED takes a fresh snapshot per statement and takes no lock on the counted rows, so both see 49. PostgreSQL's REPEATABLE READ is snapshot isolation: it removes non-repeatable reads and phantoms within the snapshot but still admits write skew, because the anomaly is not a re-read of a changed row, it is a read of a set that a concurrent transaction invalidates. Only SERIALIZABLE closes it, by tracking the read dependency and aborting one transaction with SQLSTATE 40001 — a guarantee that exists only if the application re-runs the whole transaction from the read.
- Convert the set predicate into a single-row conflict: keep tenant.active_resource_count and run UPDATE tenant SET active_resource_count = active_resource_count + 1 WHERE tenant_id = $1 AND active_resource_count < 50 in the same transaction as the INSERT. Zero affected rows is the cap, returned as 409. The row lock serialises the decision at any isolation level, and contention is bounded to one tenant's row — which is also the fair-scheduling unit, unlike a global counter that would convoy every tenant behind one row.
- State the cost you just took on: a counter is a second source of truth that can drift, so every path that changes status must adjust it inside the same transaction, and a periodic reconciliation has to exist, with resource_revision as the authority for what the count should have been.
Follow-up
- A resource moves from archived back to active. Which statements change, and what breaks if the counter update and the status change land in different transactions?
- The cap becomes plan-dependent and a plan can change mid-month. Where does the number 50 live, and who reads it?
How do you approach the design of a scalable data workflow?
Medium · Technical & Domain Expertise
Approach
- Start by pinning down the shape of the workflow: sources and formats, daily volume and growth, how fresh the output must be (batch is fine for a nightly campaign audience, not for a real-time trigger), and who consumes the result.
- Lay out stages with a clear contract at each boundary: land raw data unchanged in a staging table, validate and reject bad rows into a quarantine table with a reason code, transform into the modelled tables, then publish the audience or output. Raw staging lets you reprocess without going back to the source.
- Make every step idempotent so a retry or rerun cannot duplicate data: upsert on a natural or primary key (in SFMC, a Query Activity with the Update action on a keyed Data Extension), and load incrementally from a watermark such as last-modified time instead of reloading everything.
- Scale by making the work proportional to change, not to history: incremental loads, partitioning by date or key, set-based SQL instead of per-row calls, and batching any external API calls with backoff for rate limits.
- Close with operations: orchestration that orders dependent steps and stops downstream steps when an upstream one fails, row-count and freshness alerts, and a backfill path. Name the trade-off you are making: full refresh is simpler and self-healing but costs grow with total data size, while incremental is cheaper but needs careful handling of late or updated records.
Follow-up
- The source volume grows tenfold. Which step breaks first, and what do you change?
- A run fails halfway through. How do you rerun it without duplicating records or sending twice?
- An upstream system renames a column without warning. How does your workflow detect it, and what happens to that day's output?
Explain your process for ensuring data accuracy in a high-volume environment.
Medium · Technical & Domain Expertise
Approach
- Define accuracy in parts you can check: completeness (nothing dropped), uniqueness (no duplicates on the key), validity (types, formats, required fields), consistency (same values across systems) and timeliness (data is fresh enough for the send or report).
- Put checks at each boundary rather than only at the end: schema and type validation on ingest, a quarantine table for rejected rows, uniqueness checks on primary keys, and normalisation of join keys (trimmed, lower-cased email addresses, consistent time zones) before matching.
- Reconcile source against target on every run: row counts, counts per category, and sums or checksums of key columns. Compare against expected ranges so a sudden 40% drop in audience size raises an alert even when the job technically succeeded.
- Decide which checks block publication and which only warn, and say why. For a marketing send, a failed suppression or opt-out check should stop the send, while a small rise in rejected rows can warn and continue. Back this up before launch with a seed-list test send and a spot-check of sample records.
- Mention the high-volume cost: run set-based validations in SQL rather than row by row, sample for expensive checks, and keep check results over time so you can spot drift.
Follow-up
- A blocking check fails at night before a scheduled campaign. Who decides whether it sends, and what information do they need?
- How would you tell silently dropped rows apart from legitimately excluded ones?
- After fixing a data defect, how do you prove that historical outputs are now correct?
How do you translate client requirements into technical specifications?
Medium · Technical & Domain Expertise
Approach
- Begin with the goal and its success measure before any solution: what the client is trying to achieve, how they will judge it, and which constraints apply (deadlines, data they can supply, compliance or consent rules).
- Turn vague phrases into testable rules using examples. If the client says 'active customers', fix the definition: activity measured from which source table, over what window, in which time zone, and with which exclusions. Walk through a few sample records with the client to confirm the rule.
- Write the specification with scope and out-of-scope items, the source-to-target field mapping, segmentation logic as precise rules, edge cases (missing values, duplicates, late data), dependencies, and acceptance criteria phrased as checkable conditions.
- Link requirements to UAT: each acceptance criterion becomes a test case, so UAT confirms the spec rather than discovering it. Get sign-off, and handle later changes through an explicit change process that states the impact on scope and dates.
- Mention the trade-off between speed and completeness: a spec does not need to cover everything up front, but every ambiguous rule that affects who receives a campaign needs a written answer before build.
Follow-up
- The client changes the audience definition two days before launch. What do you do?
- Two stakeholders give you conflicting requirements. How do you resolve it, and who decides?
- Several defects found in UAT turn out to be missing requirements. What do you change in your process?
Listing latency scales with page size, not with filters
Easy · n+1 · latency · query batching
The tenant listing endpoint reads resource filtered by tenant_id and status, ordered by updated_at DESC, and returns each row plus the owner's display name from app_user and the actor of that resource's latest resource_revision. p99 is 55 ms at 10 rows per page and 1.4 s at 200. Database telemetry shows 401 statements per request, each under 1 ms, and nothing in the slow-query log. Diagnose the cause and give the fix, stating the statement count per request and the p99 you expect afterwards.
Approach
- Read the counters before forming a theory. 401 statements for 200 rows is one driver query plus two per row, and sub-millisecond execution with an empty slow-query log rules out a bad plan. The time is round trips, which is why it is invisible in every per-query metric and scales with rows returned rather than with filter selectivity.
- Name the two per-row statements from their normalised text: a single-row app_user lookup by user_id, and a resource_revision lookup by resource_id ordered by version DESC LIMIT 1. Confirm by dropping those two response fields and watching the statement count fall to one. That locates the calls in the serialisation layer, not the repository.
- Check that the arithmetic accounts for the whole gap. Measure one round trip to the replica in isolation; 400 trips at roughly 3 ms of network plus 0.2 ms of execution is about 1.3 s on top of a 55 ms baseline, which matches. If the multiplication had fallen short, the N+1 would only be part of the story and you would keep looking.
- Batch both lookups. Collect owner_user_ids and resource_ids from the driver query, then issue WHERE tenant_id = $1 AND user_id = ANY($2) for the users, and PostgreSQL's SELECT DISTINCT ON (resource_id) ... WHERE resource_id = ANY($2) ORDER BY resource_id, version DESC for the latest revision, which the UNIQUE (resource_id, version) index serves directly. On an engine without DISTINCT ON, use a lateral join or a row_number window. Three statements per request at any page size.
Follow-up
- The page size is capped at 200 today. What breaks first if it is raised to 2,000, and is it still this bug?
- How do you stop the next N+1 from reaching production, given that no individual query is slow and the endpoint's tests pass?
Suggested practice checklist
Each day targets one reported question or one topic candidates list for this role (SFMC data management, workflow design, data accuracy, requirements and UAT, integration debugging), and ends with a mock of the Technical Deep-Dives.
Day 1 — Screening pitch and project inventory
- Write your career walkthrough for the Screening Call around three projects: a data workflow, a CRM or SFMC build, and a requirements-to-delivery project.
- For each project, write down the data volume, your own decisions and one measurable result.
- Write an honest paragraph on your SFMC or CRM depth, listing which features you used yourself.
Deliverable: A screening walkthrough, three project summaries with numbers, and a written statement of your SFMC/CRM depth.
Day 2 — SFMC data management and segmentation SQL
- Review the SFMC data model: Data Extensions, primary keys, sendable relationships to a subscriber key, and the Append, Update and Overwrite actions of a Query Activity.
- Write SQL that deduplicates contacts with ROW_NUMBER() OVER (PARTITION BY key ORDER BY last_modified DESC) and keeps the newest row.
- Write an audience query that excludes unsubscribed and suppressed records, then rehearse your answer to the SFMC or CRM experience question out loud.
- Work the denormalise-and-backfill practice question to practise changing a live table's shape safely.
Deliverable: Two working segmentation queries, the backfill practice solution, and a rehearsed SFMC/CRM experience answer.
Day 3 — Designing a scalable data workflow
- Sketch a staged workflow (raw staging, validation and quarantine, transformation, publication) for a daily campaign audience, with keys and watermarks marked.
- Write down how a failed run is retried and how a single day is backfilled without duplicates.
- Solve the practice question on collapsing a redelivered event batch into per-aggregate high-water marks, which uses the same idempotency idea.
- Answer the scalable workflow question out loud, including what breaks first at ten times the volume.
Deliverable: A workflow diagram with a rerun and backfill note, a solved event-batch practice question, and a recorded spoken answer.
Day 4 — Data accuracy at volume
- List the checks you would run at each boundary of yesterday's workflow and mark each one as blocking or warning.
- Solve the practice question on diffing a projection against its primary without per-row reads, which is reconciliation at scale.
- Answer the data accuracy question out loud, using one real incident where a check caught bad data.
Deliverable: A boundary-by-boundary check list with blocking rules, a solved reconciliation practice question, and a spoken data-accuracy answer.
Day 5 — Requirements, specifications and UAT
- Take a vague request such as 'email our active customers about the new offer' and write a one-page specification: definitions, field mapping, edge cases and acceptance criteria.
- Turn each acceptance criterion into a UAT test case with expected results.
- Prepare a STAR story about a requirements flaw you caught, and answer the requirements-to-specification question out loud.
Deliverable: A one-page specification, a matching UAT test-case table, and a requirements-flaw story in STAR form.
Day 6 — Integration troubleshooting and root cause analysis
- Write your integration troubleshooting story in STAR form, with the debugging sequence, the evidence for the root cause, and the prevention you added.
- Work the practice debugging question on listing latency that scales with page size, saying each hypothesis out loud before testing it.
- Make a checklist of common integration failure causes (expired credentials, rate limits, field mapping, encoding and time zones, duplicate retries) and match each to the evidence that would confirm it.
Deliverable: A written integration story, a solved debugging practice question, and a cause-to-evidence checklist.
Day 7 — Technical Deep-Dive mock
- With a friend, run a mock over video and screen share: architecture of your most complex project, then redesigning it for ten times the data.
- Finish with the behavioral prompts and the estimation practice question, giving a range and the assumptions behind it.
- Write down the weakest answer from the mock and redo it once.
Deliverable: A completed video mock, notes on the weakest answer with a redone version, and an estimation answer with stated assumptions.
Behavioural preparation
Two of the reported questions are about your own experience: your SFMC or CRM background, and an integration issue you troubleshot. Candidates also mention scenarios about requirements flaws and conflicting technical and business goals, and report STAR as the structure to use. Because the role involves clients and cross-functional stakeholders, choose stories where you personally made the call, explained it to a non-technical person, and can show the result.
- Walk me through the architecture of your most complex project.
- Tell me about a requirements flaw you caught before it reached delivery, and how you raised it.
- Describe how you chose between a technical goal and a business goal that pulled in different directions.
- Tell me about explaining a technical problem or trade-off to a client or non-technical stakeholder.
What is your experience with SFMC or similar CRM platforms?
Medium · Technical & Domain Expertise
Approach
- Answer with concrete pieces you have used yourself, not a list of product names. For SFMC that means the data model (Data Extensions, primary keys, sendable Data Extensions related to a subscriber key, Contact Builder relationships), automation (imports, SQL Query Activities, Automation Studio schedules), orchestration (Journey Builder entry sources and splits) and personalisation (AMPscript).
- Anchor it in one project, told in the first person singular: the campaign or integration, the data volume, the segmentation logic you wrote, and a measurable outcome such as audience accuracy, defects caught in UAT, or a manual process you automated.
- If your experience is with a different CRM or marketing platform, map it explicitly: what played the role of Data Extensions, where your segmentation SQL ran, how sends were triggered. Then name the SFMC-specific parts you would still need to learn. Candidates report that owning a gap honestly is the right approach.
- Show data discipline inside the platform: how you deduplicated contacts, kept unsubscribes and suppressions out of every audience, and tested a journey or send before it went live.
- The answer that fails is a feature tour with no decision in it. Include one choice you made, such as overwriting versus updating a target Data Extension, and why you made it.
Follow-up
- The same person exists under two subscriber keys from different sources. How do you find and resolve that?
- How did you test a journey or automation before it reached real customers?
- How did you make sure opted-out contacts never entered an audience, even when a new data source was added?
Describe a time you had to troubleshoot a complex integration issue.
Medium · Technical & Domain Expertise
Approach
- Use STAR, but keep the situation short and spend most of the answer on the action: which systems were involved, what the symptom was (missing records, duplicates, auth failures, mismatched fields), and how many records or users it affected.
- Show a debugging sequence: reproduce the problem, find the first hop where the data is wrong by checking payloads and logs at each boundary, then test likely causes one at a time. Common causes include expired credentials or tokens, rate limiting, field-mapping or type mismatches, encoding or time-zone differences, and retries creating duplicates.
- Separate the root cause from the symptom and say what evidence confirmed it, such as a replayed payload, a log line or a controlled test, rather than 'it stopped failing after I changed X'.
- End with the fix and the prevention: the change you made, the monitoring or validation you added, how you repaired data that was already affected, and how you kept stakeholders informed while it was broken.
- Tell it in the first person singular. A story told entirely as 'we', or one that blames the other system's team, does not show what you did yourself.
Follow-up
- How did you know you had found the root cause and not just a trigger?
- What did you do about the bad or missing data the issue had already produced?
- What monitoring would have caught it sooner, and did you add it?
Estimate work you have never done and defend the range
Hard · estimation · backfills · expand-contract
You are asked to estimate a change you have never attempted: add a column to a 100-million-row table, populate it, move reads across, and drop the old shape. Give a range with the assumptions that generate it, including batch size, the signal your backfill throttles on, and wall-clock hours, and name the three unknowns that would move the number most. Then describe a real estimate you gave under comparable ignorance: how you expressed its uncertainty, what you committed to, and how wrong you turned out to be.
Approach
- Decompose into independently deployable steps before estimating anything: add the column nullable, write both shapes, backfill in batches, verify, move reads, stop writing the old shape, drop it. That is four deploys spread over days, and the calendar estimate is dominated by them rather than by the loop's runtime.
- Do the arithmetic aloud for the part that has arithmetic in it: batch size times number of batches times per-batch duration, at a write rate the primary can absorb alongside roughly 1.2k writes per second of production traffic. The loop is throttled by replication lag and lock waits, not by how fast it can issue statements.
- Price the schema step by its lock rather than its statement duration. In PostgreSQL an ALTER TABLE taking ACCESS EXCLUSIVE waits for every open transaction on that table while later queries queue behind it, so a millisecond change issued during a thirty-second analytics query stalls that table for thirty seconds. Adding a nullable column with a non-volatile default avoids a rewrite from version 11; a new index wants CREATE INDEX CONCURRENTLY, which cannot run inside a transaction block and leaves an invalid index behind if it fails.
- Express the answer as a range whose endpoints each trace to a stated assumption, then name the cheapest experiment that collapses it, which is almost always running one real batch against the real table and multiplying.
Follow-up
- How do you verify the backfill genuinely finished, given rows written by production traffic while it ran?
- Where does the backfill resume from after a worker is killed mid-batch, and what makes that resume point trustworthy?