cswork / libraryOpen practice workspace

Interview guides · AdsGency AI

AdsGency AI Software Engineer Interview Guide

AdsGency AI Software Engineer interview guide: four reported rounds, coding, system design and ad-metrics questions, behavioral answers, 7-day plan.

The 60-second brief

AdsGency AI builds advertising technology, and the Software Engineer role described by candidates covers designing and writing the software behind it. The reported work involves applications that support advertising strategies, algorithms that affect how ads perform, and projects that use data analytics and machine learning. Candidates describe the role as involving work with product managers, designers and other engineers, and code reviews. One candidate review describes a fast-paced startup setting with exposure to several areas of the product. The requirements candidates describe are Python or Java, data structures and algorithms, cloud services such as AWS or Azure, and Git. Experience with machine learning frameworks, advertising technology and performance metrics, and agile methods, is listed as a plus.

This guide is for Software Engineer candidates preparing for AdsGency AI. It covers the four reported stages, the 18 questions candidates report (fundamentals, debugging, system design, ad-metrics case studies, coding and behavioral prompts, including the cloud-experience question), and a seven-day plan that moves from coding to design to metrics to stories.

Candidates report four stages over roughly 3-5 weeks: Initial Screening, Technical Interviews (coding and design work), Behavioral Interviews and Final Interviews. The four stages and their order are as candidates report them.

Focus areas

  • Interview Communication Skills
  • Software Engineering (General)
  • Adaptability to Feedback

Overview

The reported question set is broad rather than deep in any one area. It mixes engineering fundamentals (object-oriented versus functional programming, code quality and maintainability, debugging a complex issue), system design (serving targeted ads to millions of users in real time, scalable architecture, data consistency in a distributed system, API design), two ad-metrics case studies (analysing engagement data, diagnosing falling click-through rates) and coding (sorting an array, searching a large dataset, a LeetCode or HackerRank style challenge). Because the technical stage is described as including coding and design work, expect to switch between writing runnable code and reasoning aloud about a system within the same loop.

The case studies are where the advertising context shows up most. Both ask you to reason from metrics to a cause or a decision, so rehearse the vocabulary: impressions, clicks, click-through rate as clicks divided by impressions, and how a change in the denominator differs from a change in the numerator. Candidates also list advertising technology and performance metrics as a plus, and machine learning frameworks as a plus, so one short, honest paragraph on how a model-driven ranking or optimisation feature would affect your design answers is worth having.

The behavioral stage is reported as covering past experiences, teamwork and problem-solving. The behavioral-category prompts candidates report are about a difficult team member, what motivates you, prioritising under several deadlines, and leading a project from inception to completion. The cloud-experience question is also answered from your own history, so prepare it alongside these stories. Prepare real stories with your own decisions and measurable results. Since the role description mentions code reviews and work with product managers and designers, choose at least one story where you disagreed with a peer or reviewer and resolved it.

Preparation should follow the stack the requirements name. Pick Python or Java and write every coding answer in it so syntax never costs you attention. Be able to name the AWS or Azure services you have actually used and say why. Know your Git workflow, including how you review and merge changes, because the role includes code reviews and candidates mention CI/CD and version control as familiar ground.

The AdsGency AI interview process

Candidates describe four stages over about 3-5 weeks. Little is reported about the format of each stage, so each description below ties the stage to the question types that fit its format and to the stack the role lists.

Initial Screening

Candidates describe Initial Screening as the opening stage, a check on basic qualifications and fit. Approach it as a concise match between your background and the requirements candidates list: Python or Java, data structures and algorithms, a cloud provider such as AWS or Azure, and Git. As general preparation, have your cloud-experience answer ready at the level of specific services and decisions rather than a list of names.

What to demonstrate

  • Whether your background lines up with the listed requirements: a language, algorithms, cloud services, Git
  • Fit for a Software Engineer role in advertising technology

How to prepare

  • Write a short walkthrough of your most relevant project naming the language, the cloud services, and how the code was reviewed and released through Git
  • Prepare an answer to the cloud-experience question with one concrete service decision and one lesson from running it
  • Write down why advertising technology and a fast-moving team interest you, in terms of work you have done, not slogans

Technical Interviews

Candidates describe the Technical Interviews as several sessions that combine coding with design problems. Across the loop, candidates report these question types, so cover them all: coding (sorting an array, searching a large dataset, a LeetCode or HackerRank style challenge), system design (real-time targeted ad serving, scalable architecture, distributed data consistency, API design), fundamentals (object-oriented versus functional programming, code quality, a hard technical problem, debugging) and the two ad-metrics case studies. Practise coding in your chosen language without an autocomplete crutch, and practise design by talking through requests, data and failure.

What to demonstrate

  • Working, tested code for algorithm and data-structure problems, which a live coding format inherently requires
  • Design reasoning for a system that must serve many users with low latency
  • Clear explanation of engineering fundamentals and debugging method
  • Reasoning from engagement metrics to a diagnosis or a decision

How to prepare

  • Implement a sort and a binary search from scratch in Python or Java and state complexity, stability and edge cases for each
  • Design real-time ad serving on paper: request path, candidate retrieval, scoring, event logging, caching and what may be stale
  • Build a diagnosis tree for falling click-through rates: tracking and data checks first, then segments by placement, device, campaign and creative
  • Write a one-page API design for an event-ingestion endpoint covering idempotency, versioning and error responses

Behavioral Interviews

Candidates describe Behavioral Interviews as covering your past experiences, teamwork and how you solve problems. Behavioral-category prompts candidates report include a difficult team member, what motivates you, prioritising across multiple deadlines and leading a project from inception to completion. Treat this as a story-bank exercise: a handful of true stories, each with the decision you made, the constraint you worked under and a result you can state plainly.

What to demonstrate

  • How you handle disagreement and collaboration with colleagues
  • How you make trade-offs when several things are due

How to prepare

  • Write four stories on paper, one per reported prompt, each in situation, action, result form with at least one number or observable outcome
  • Be ready to say what you personally decided in each story, and name teammates for their parts
  • Pick one story where you disagreed with a peer or reviewer and show how evidence settled it
  • Add a story about improving a team process, since a process-improvement question is among the examples candidates quote

Final Interviews

Candidates describe Final Interviews as the closing stage, which may include more assessment of fit and skills. Little else is reported, so prepare for a second pass over earlier material rather than a new topic: your weakest technical area, your project-ownership story, and your own questions about the team.

What to demonstrate

  • Fit for the role and the team, assessed further, as the stage description suggests
  • Technical skills, assessed further, as the stage description suggests

How to prepare

  • List the two technical questions you answered least well and rework them end to end, with code or a diagram
  • Rehearse the project-leadership story until its decisions and results can be told in either a short or a long form
  • Prepare informed questions about team structure, current project challenges and how code review works day to day

Where candidates lose points

Answering object-oriented versus functional programming with two textbook definitions

Contrast them on state and mutation, composition versus inheritance, pure functions and testability, then say when you would choose each and give a small code example in Python or Java.

Starting the real-time ad serving design by drawing boxes

Ask for scale, latency budget and what 'targeted' means first. Separate the request path from the event-logging path, say what may be stale, and name what breaks at ten times the traffic.

Naming a cause for falling click-through rates in the first sentence

Check the tracking and data pipeline first, then compare impressions and clicks separately, then segment by placement, device, campaign and creative, before proposing a fix or an experiment.

Coding the sort or search in silence, or reaching for the built-in without discussing it

Ask whether built-ins are allowed, state the approach and its complexity before writing, test on empty, single-element and duplicate-heavy input, and say how the answer changes for data too large for memory.

Telling behavioral stories in 'we' with no result, or answering the cloud question with a list of service names

Write each story with your own decision and a measurable outcome. For cloud, name the services you used, one trade-off you chose and one lesson from running it.

Questions & practice

Write a function to sort an array of integers.

Medium · Coding / Algorithms

Approach

  1. Clarify first: array size, value range, duplicates and negatives, in place or a new array, stability, and whether a library sort is allowed (Python's sorted is Timsort, stable, O(n log n); Java's Arrays.sort on int[] is a dual-pivot quicksort).
  2. Write one comparison sort and state its properties: merge sort is O(n log n) worst case, stable, O(n) extra space; quicksort with a random pivot is O(n log n) expected, O(n^2) worst, in place with O(log n) expected stack, and three-way partitioning handles many duplicates; heapsort is O(n log n) worst case, O(1) space, not stable.
  3. Use the fact that keys are integers: counting sort is O(n + k) for a value range k, and LSD radix sort is O(d(n + b)) for d digits in base b; handle negatives by offsetting values or flipping the sign bit.
  4. Mention the hybrids: insertion sort is O(n) on nearly sorted input and is used for small subarrays inside Timsort and introsort, which falls back to heapsort to cap the worst case.
  5. Test empty, one element, all equal, already sorted, reverse sorted, negatives and extreme values; in Java compute the midpoint as lo + (hi - lo) / 2 to avoid overflow.

Follow-up

  • How would you sort a file of integers that does not fit in memory?
  • Why is quicksort often faster than merge sort in practice despite its worse worst case?
  • How would you make your quicksort robust against adversarial input?

How would you implement a search algorithm for a large dataset?

Medium · Coding / Algorithms

Approach

  1. Clarify the data and the query: keys, text or vectors; size relative to memory; static or constantly updated; exact match, range, prefix, full-text or nearest neighbour; and the read/write ratio.
  2. In memory: a linear scan is O(n); a hash table gives O(1) average exact lookup but no range queries; a sorted array with binary search gives O(log n) lookup plus ranges (Python's bisect_left and bisect_right); a balanced BST keeps O(log n) with updates.
  3. On disk: a B+ tree index has high fanout, so a lookup costs O(log_B n) page reads and range scans follow the leaf chain; LSM trees suit write-heavy loads, and a Bloom filter skips lookups for absent keys (false positives possible, no false negatives).
  4. Text and similarity: an inverted index from term to sorted posting lists, intersected and ranked with BM25; a trie for prefix search; approximate nearest-neighbour indexes such as HNSW or IVF trade some recall for speed.
  5. At scale, shard the index, scatter the query to all shards, and merge each shard's top k with a heap; add replicas for throughput. If asked to code it, write binary search with a clear loop invariant and an overflow-safe midpoint.

Follow-up

  • Write binary search that returns the first index of a target in an array with duplicates.
  • The data changes constantly. How does your index stay current?
  • How would you return the global top 10 results from 50 shards?

Solve a coding challenge from platforms like LeetCode or HackerRank during the interview.

Medium · Coding / Algorithms

Approach

  1. Restate the problem, ask for input size and constraints, and walk one small example before coding; the bound on n suggests the target (around 10^5 elements rules out O(n^2), so aim for O(n log n) or O(n)).
  2. State the brute force and its complexity, then improve it by recognising the pattern: hash map for lookups and complements, two pointers or a sliding window for contiguous ranges, a heap for top-k, BFS or DFS for graphs and grids, binary search on the answer, dynamic programming for overlapping subproblems.
  3. Write clean code in Python or Java with small helpers and clear names, saying the invariant out loud as you write each loop.
  4. Trace your code on the example and on edge cases (empty input, one element, duplicates, negatives, maximum size), fix bugs you find, then state the final time and space complexity.
  5. If the optimal idea does not come, finish a correct simpler solution first and explain how you would improve it; a working answer beats an unfinished optimal one.

Follow-up

  • Can you reduce the space complexity?
  • How would your solution change if the input arrived as a stream?
  • What changes if the input can contain duplicates or is not sorted?

Keep soft-deleted accounts from blocking re-registration

Easy · soft delete · unique constraints · engine differences

app_user holds user_id, tenant_id, email CITEXT, password_hash (NULL for SSO principals), email_verified_at, auth_version, status ('invited','active','suspended','deactivated'), created_at, updated_at, deleted_at. Two live accounts for one address inside a tenant must be impossible, but an address freed by a soft delete must be reusable, and the same tenant may delete and re-register it repeatedly. Write the uniqueness DDL for PostgreSQL 16, then the equivalent for MySQL 8 where partial indexes do not exist, and say what each permits once three deleted rows already hold that address.

Approach

  1. Start from what is actually unique: not (tenant_id, email), but (tenant_id, email) among live rows. PostgreSQL says that directly — CREATE UNIQUE INDEX app_user_live_email ON app_user (tenant_id, email) WHERE deleted_at IS NULL. A full constraint over the same two columns burns the address permanently the first time someone deletes an account.
  2. Keep case-insensitivity in the type or the index, never in the application: CITEXT as given, or UNIQUE (tenant_id, lower(email)) as an expression index where the extension is unavailable. A case-sensitive unique column is exactly how two accounts for one human appear.
  3. For MySQL 8 the predicate has to move inside the key: add a discriminator column that is a constant 0 while the row is live and is set to user_id on delete, with UNIQUE (tenant_id, email, deleted_marker). Live rows share the constant and still collide; deleted rows differ from each other and stop colliding.
  4. State the NULL variant and its dependency: leaving the marker NULL for deleted rows also works, because a unique index treats NULLs as distinct — true in MySQL, and true in PostgreSQL only under the default NULLS DISTINCT, which PostgreSQL 15 lets you reverse. Check the polarity against the three existing deleted rows: constant-on-live is what preserves the collision you want, and reversing it silently admits duplicate live accounts.

Follow-up

  • A deleted account re-registers with the same address the next day. Do the old resource rows follow the new user_id, and how does the API keep the two principals apart?
  • How do you honour an erasure request while resource_revision.actor_user_id still references this table?

Find version gaps and relay lag with window functions

Medium · window functions · event tables · frame semantics

outbox_event holds event_id, aggregate_type, aggregate_id, aggregate_version, event_type, payload, status ('pending','published','dead'), attempts, created_at, published_at. A projection is missing rows and you must decide whether the relay skipped events or the consumer dropped them. Write three queries over the last seven days: one listing every aggregate_id whose published aggregate_version sequence has a hole, one giving per-day counts with a running total, and one returning the newest published event per aggregate. For each, say where the window function is evaluated relative to WHERE and LIMIT. PostgreSQL 16.

Approach

  1. Gaps: compute lead(aggregate_version) OVER (PARTITION BY aggregate_id ORDER BY aggregate_version) in a subquery, then filter next_version <> aggregate_version + 1 in the outer query. Window functions are evaluated after WHERE, GROUP BY and HAVING and before the outer ORDER BY and LIMIT, so the predicate cannot sit in the same WHERE clause and PostgreSQL 16 has no QUALIFY.
  2. Say what the seven-day filter does to the answer: it truncates every partition, so the first row per aggregate has no predecessor inside the window and a hole spanning the boundary is invisible. Widen the window, or join to resource.version as the authority for the true maximum.
  3. Running total: SELECT date_trunc('day', created_at) AS d, count() AS n, sum(count()) OVER (ORDER BY date_trunc('day', created_at) ROWS UNBOUNDED PRECEDING). An aggregate inside a window call is legal because grouping runs before windowing. The grouping key is unique per row here so ROWS and RANGE agree, but write the frame anyway — over ungrouped rows with tied timestamps the default RANGE frame pulls in every peer row and the total jumps.
  4. Newest per aggregate: DISTINCT ON (aggregate_id) ... ORDER BY aggregate_id, aggregate_version DESC is the cheap PostgreSQL-only form when an index matches that order; row_number() OVER (PARTITION BY aggregate_id ORDER BY aggregate_version DESC) = 1 is the portable form and needs a subquery for the same evaluation-order reason as the gap query.

Follow-up

  • Relay failover redelivers events. Does a duplicate break the gap query, and how would you detect one from this table alone?
  • Turn the gap check into a continuous monitor rather than a query someone runs after an incident. What does it watch?

Explain the difference between object-oriented and functional programming.

Medium · Technical / Domain Questions

Approach

  1. Define both precisely: OOP bundles state with the methods that change it (encapsulation, polymorphism through interfaces, composition or inheritance); FP builds programs from pure functions over immutable values, with higher-order functions and side effects pushed to the edges.
  2. Name the expression-problem trade-off: in OOP adding a new type is one new class, but adding an operation touches every class; with algebraic data types and pattern matching, adding an operation is one function, but adding a variant touches every function.
  3. Give the practical consequences: pure functions are testable without mocks and immutable data can be shared across threads without locks; the cost is copying, which persistent data structures reduce through structural sharing.
  4. Show both in a language you use: Java records plus streams (map/filter/reduce) or Python frozen dataclasses with comprehensions and functools.reduce, then say most production code mixes them, objects at module boundaries and a functional core for data transformations.
  5. Avoid the common errors: FP does not mean no state (state is passed and returned explicitly), and OOP does not require inheritance; prefer composition.

Follow-up

  • When is mutable state the better choice even in a codebase that prefers FP style?
  • A class hierarchy keeps growing a switch on type. How would you refactor it, in either style?
  • How does a closure relate to an object with one method?

How do you ensure code quality and maintainability?

Medium · Technical / Domain Questions

Approach

  1. Automate the cheap checks: formatter, linter and type checker (ruff and mypy for Python, Checkstyle or SpotBugs for Java) run in CI and block the merge, so review time goes to design and correctness instead of style.
  2. Describe the test strategy as a pyramid: many fast unit tests on pure logic, fewer integration tests against real dependencies (for example containers in CI), a handful of end-to-end tests; test behaviour rather than implementation, and add a regression test for every bug fixed. Treat coverage as a floor, not a goal.
  3. Keep changes reviewable: small pull requests on a Git branch, required approval plus green CI before merge, and a review focus on naming, boundaries, error handling and missing tests.
  4. Design for change: clear module boundaries, dependencies injected so code can be tested in isolation, no abstraction until a pattern repeats, dead code deleted, and the why recorded in comments or short design records.
  5. Back it with one concrete example from your own work, such as a flaky suite you stabilised or a module you split, and the measurable result (fewer rollbacks, faster CI, fewer escaped bugs).

Follow-up

  • You must change a legacy module with no tests. What do you do first?
  • How do you handle a flaky test that blocks everyone's merges?
  • What would you insist on in a code review, and what would you let go?

Describe a challenging technical problem you faced and how you resolved it.

Medium · Technical / Domain Questions

Approach

  1. Pick a problem with real technical depth that you personally diagnosed or designed, and set it up in two or three sentences: the system, the symptom, and the constraint that made it hard (scale, latency, data volume, a deadline).
  2. Walk the investigation as evidence: each hypothesis, what you measured to test it (profiler, logs, metrics, a minimal reproduction), and what that ruled out; then the options you weighed for the fix and why you chose one.
  3. Give the result as a number and how you verified it, for example p99 latency before and after, error rate, or cost, confirmed by a load test, canary or before-and-after dashboard.
  4. Close with what stopped it recurring (a test, an alert, a runbook, a design change) and one thing you would do differently.
  5. What sinks this answer: a team story where your own contribution is unclear, a problem that was only hard because of process, or an ending with no measured outcome.

Follow-up

  • What other solutions did you consider, and why did you reject them?
  • How did you confirm the root cause rather than a symptom that correlated with it?
  • What would break first if the same system saw ten times the load?

Design a system that can serve targeted ads to millions of users in real-time.

Medium · System Design / Architecture

Approach

  1. Fix scope and numbers first: peak ad requests per second, the end-to-end latency budget (split it per stage), targeting inputs (user segments, context, geo, device), ads returned per request, and constraints such as budgets and frequency caps.
  2. Read path: stateless ad servers behind a load balancer; a low-latency key-value store of user profiles and segments keyed by user id; an in-memory inverted index from targeting attribute to eligible campaigns, replicated to every server and refreshed from the campaign database through a change stream; candidate retrieval, then filtering (budget, frequency cap, brand safety), then ranking.
  3. Ranking: score candidates by expected value per impression, predicted CTR times bid for click-priced ads (eCPM is that times 1000), with a model served in-process or behind a feature store; return the top K, and on a timeout fall back to a cached or default ad instead of failing the request.
  4. Write path: log impressions and clicks to a partitioned event log; stream processors update budget-pacing and frequency counters, and batch jobs feed billing and model training. Budget counters are eventually consistent, so give each server a slice of the remaining budget to bound overspend.
  5. Scale and failure: shard the profile store by user-id hash, precompute segments offline, deploy per region, cache hot profiles, and state what goes stale (counters, the index) and by how much.

Follow-up

  • How do you enforce a daily campaign budget across hundreds of servers without overspending?
  • How would you enforce a cap of N impressions per user per day?
  • How does a newly created campaign become servable, and how quickly?

What factors do you consider when designing a scalable architecture?

Medium · System Design / Architecture

Approach

  1. Start from numbers, using the ad-serving case. For illustration, assume 50,000 ad requests per second at peak with a p99 latency target of a few tens of milliseconds. If each request returns several ads and each shown ad logs an impression, with some clicks on top, the event write rate is several times the request rate, perhaps 200,000 or more events per second. Reads and writes scale differently, so size them separately.
  2. Find what runs out first. The profile store takes roughly one read per ad request, so its read QPS and memory footprint matter. The event log takes the multiplied write rate, so partition count and disk throughput matter. Budget and frequency counters concentrate writes on a few hot keys for big campaigns, and that is often the first real limit.
  3. Keep ad servers stateless so they scale horizontally behind a load balancer; push state into stores, and cache read-heavy data (campaign index, hot profiles) with an explicit TTL or invalidation rule.
  4. Data layer: shard the profile store with a deliberately chosen key (user id spreads load; campaign id does not for counters, so split a hot counter into sub-counters), use read replicas for read scaling, and pick SQL versus NoSQL by access pattern and consistency needs.
  5. Decouple event ingestion with a queue or log, with backpressure and idempotent consumers; handle failure with timeouts, retries using exponential backoff and jitter, and a fallback ad. Cover observability, autoscaling and the cost of headroom, and avoid microservices until a team or scaling boundary needs them.

Follow-up

  • In a system you built, which component would bottleneck first, and how do you know?
  • How do you handle a single hot key that one shard cannot serve?
  • When would you split a monolith, and what would you split first?

How would you handle data consistency in a distributed system?

Medium · System Design / Architecture

Approach

  1. Ask which invariants need strong consistency (no double charge, no negative balance) and which tolerate eventual consistency (counters, feeds, analytics); under CAP a partition forces a choice between consistency and availability, and PACELC adds latency versus consistency when there is no partition.
  2. Within one data store: single-leader replication with synchronous or quorum acknowledgement; with leaderless quorums, R + W > N makes read and write sets overlap (sloppy quorums and concurrent writes weaken this); for linearizability use consensus (Raft or Paxos) through etcd, ZooKeeper or a database built on it.
  3. Across services: avoid two-phase commit (it blocks if the coordinator fails); use a saga with compensating actions, a transactional outbox so the state change and its event commit together, and idempotent consumers with dedupe keys, since delivery is at-least-once.
  4. Handle concurrent writes explicitly: optimistic concurrency with a version column and compare-and-set, CRDTs for counters and sets, and caution with last-write-wins because clock skew silently drops writes; give read-your-writes by reading from the leader or with session tokens.
  5. Verify continuously: monitor replication lag and run reconciliation jobs that compare sources of truth and repair drift.

Follow-up

  • How do you guarantee an event is published if and only if the database write commits?
  • Two clients update the same record at the same moment. What happens in your design?
  • What does exactly-once processing really mean in a message pipeline?

Describe your approach to API design.

Medium · System Design / Architecture

Approach

  1. Start from the consumers, using the ad domain. An impression and click event-ingestion endpoint is called by many client apps and servers, so a resource-oriented REST or simple HTTP API with a versioned schema fits. A campaign-management API is used by dashboards and partners, so REST with filtering fits. Internal ad-server to feature-store calls suit gRPC with protobuf for typed, low-latency calls.
  2. Define the contract for ingestion: POST /v1/events accepting a batch of events with event_id, type (impression or click), ad_id, campaign_id and timestamp; validate input against an OpenAPI or protobuf schema; return 202 for accepted, 400 or 422 for bad input, 429 with Retry-After under load, and a machine-readable error body such as RFC 9457 problem details.
  3. Make retries safe: clients retry on timeout, so a click must not be counted twice. Require an Idempotency-Key header (or per-event event_id), store the first result under it, and return that stored result on replay; GET, PUT and DELETE are idempotent by HTTP semantics. For campaign updates, use ETag with If-Match so two editors cannot silently overwrite each other.
  4. Plan for scale on the campaign API: GET /v1/campaigns?status=active&limit=50&cursor=... with a cursor-based pagination token (encoded last id plus sort key) instead of OFFSET, so the list stays stable while campaigns are created and deep pages do not scan; add filter and sort parameters and scoped auth tokens per advertiser.
  5. Plan for evolution: only additive changes within a version, never rename or remove fields, version in the URL or a header, announce deprecation (for example a Sunset header), and run contract tests against consumers.

Follow-up

  • The client times out on a click event and retries. How does your API avoid counting it twice?
  • How would you paginate a campaign list that changes while the client is paging through it?
  • How do you roll out a breaking change without breaking existing clients?

You have a set of data that represents user engagement metrics. How would you analyze this data to improve ad

Medium · Problem-Solving / Case Studies

You have a set of data that represents user engagement metrics. How would you analyze this data to improve ad performance?

Approach

  1. Pin down the goal: which ad-performance metric (CTR, conversion rate, cost per acquisition, return on ad spend), which engagement fields exist (impressions, clicks, dwell, conversions) and at what grain; say why maximising CTR alone can lower conversions.
  2. Clean first: deduplicate events, filter bot and invalid traffic, align time zones, fix the attribution window, and check for logging gaps before computing anything.
  3. Build the funnel (impression, click, landing, conversion) and break rates down by creative, placement, audience segment, device and time; attach confidence intervals (a CTR's standard error is sqrt(p(1-p)/n)) so small segments do not mislead, and check for Simpson's paradox when the traffic mix shifts.
  4. Turn findings into tested changes with an A/B test: one primary metric fixed in advance and a sample size from a power calculation. A rule of thumb at 80% power and alpha 0.05 is about 16p(1-p)/delta^2 per arm. At a 2% CTR, a 5% relative lift is a 0.1 percentage point absolute lift (delta = 0.001), so n is about 160.0196/0.000001, roughly 314,000 impressions per arm. For many creatives, a multi-armed bandit such as Thompson sampling balances exploration and exploitation.
  5. For targeting, model click or conversion probability (logistic regression or gradient-boosted trees on user, ad and context features), and keep correlation separate from causation when you recommend changes.

Follow-up

  • How would you tell whether one segment's higher CTR is real or noise?
  • CTR rose after a change but conversions fell. What do you do?
  • Roughly how large a sample do you need to detect a 5% relative CTR lift?

Given a scenario where ad click-through rates are declining, how would you approach diagnosing the issue?

Medium · Problem-Solving / Case Studies

Approach

  1. Confirm the drop is real: see whether clicks fell or impressions rose, then check tracking-tag changes, pipeline delays, bot-filter or metric-definition changes, and compare the dashboard against raw event logs.
  2. Read the shape of the timeline: a sudden step points to a deploy, config change, tracking break or supply-partner change; a gradual slide points to creative fatigue, seasonality, audience saturation or competition.
  3. Segment to localise: platform, app version, browser, geo, placement, campaign, creative, traffic source, new versus returning users. A drop confined to one app version suggests a client bug; check for mix shift too, since overall CTR can fall while every segment holds if impressions moved to lower-CTR placements.
  4. Separate internal from external causes: ranking-model or frequency-cap changes (compare against a holdout), inventory changes, versus year-over-year seasonality, ad blockers or OS privacy changes that affect click tracking.
  5. Quantify the impact, mitigate (roll back, refresh creatives), and add per-segment CTR alerts with thresholds set from historical variance.

Follow-up

  • CTR is down but total clicks are flat. What does that tell you?
  • How would you tell creative fatigue apart from a ranking-model regression?
  • How would you alert on this earlier without paging on normal noise?

How do you approach debugging a complex issue?

Medium · Technical / Domain Questions

Approach

  1. Scope before theorising: the exact symptom, how often, who is affected (all users or one region, version or customer), and when it started; line that start time up against deploys, config and feature-flag changes, dependency upgrades and traffic shifts. If users are hurting, mitigate first (roll back, disable the flag).
  2. Observe before changing anything: logs joined by request or trace IDs, metrics and distributed traces to find which service or span is slow or failing; confirm the instrumentation itself did not change.
  3. Bisect to shrink the search space: git bisect across commits (logarithmic in the number of commits), toggling flags, or checking intermediate outputs stage by stage in a pipeline.
  4. Form one falsifiable hypothesis at a time and test it with the smallest reproduction; for intermittent failures suspect races, timeouts, retries, resource exhaustion and stale caches, and add targeted logging instead of guessing.
  5. Fix the root cause, add a regression test, watch the metric after release, and write a short postmortem with the alert that would have caught it sooner.

Follow-up

  • How do you debug something that only reproduces in production?
  • How do you approach an intermittent failure you cannot reproduce locally?
  • When do you roll back before you understand the cause?

Suggested practice checklist

The plan starts with a baseline, spends two days on coding, then covers system design, fundamentals, ad-metrics case studies and finally the behavioral and cloud stories, following the question types candidates report.

Day 1 — Map the loop and set a baseline

  • Write the four reported stages and sort the 18 reported questions by type: coding, design, fundamentals, case study, behavioral.
  • Solve the sorting question cold in Python or Java and note what you could not recall.
  • Mark the two question types you are least ready for.

Deliverable: A one-page loop map with the questions grouped by type, a cold-attempt sort function, and a ranked list of weak areas.

Day 2 — Sorting and searching in depth

  • Implement merge sort and quicksort, and write when you would choose each (stability, memory, worst case, nearly sorted input).
  • Implement binary search plus two variants: first occurrence of a value and a search in a rotated array.
  • Write a short answer for searching a dataset too large for memory: an index, external merge sort, or partitioned search.

Deliverable: Tested implementations of two sorts and three searches, plus a half-page note on large-data approaches.

Day 3 — Platform-style coding practice

  • Solve three LeetCode or HackerRank style problems on arrays, hash maps and heaps in your chosen language, talking through the approach before coding.
  • For each, write its complexity and three edge cases, then run them as tests.

Deliverable: Three solved problems, each with a complexity statement and an edge-case test list.

Day 4 — System design: ad serving, consistency and APIs

  • Draw the request path for serving targeted ads in real time (retrieval, filtering, scoring, response) and a separate path for impression and click events.
  • Write what must be strongly consistent and what may be stale, for example a budget counter versus a cached ad list, and how you make event ingestion safe to retry.
  • Sketch an event-ingestion API with idempotency keys, versioning and an error taxonomy, and a campaign list with cursor pagination.
  • List the scaling factors you would name for a scalable architecture and what breaks first at ten times the traffic.

Deliverable: One ad-serving design diagram, a one-page consistency note and an API sketch for event ingestion.

Day 5 — Fundamentals, quality and debugging

  • Write a comparison of object-oriented and functional styles with the same small example coded both ways.
  • List the practices behind maintainable code: review, tests, CI/CD, naming and small changes, each with one example from your work.
  • Write a debugging playbook from a real incident: what changed, how you narrowed it, how you proved the cause, and the challenging technical problem you can tell as a story.

Deliverable: A two-style code comparison, a code-quality checklist with examples, and a written debugging playbook with one incident story.

Day 6 — Ad-metrics case studies

  • Build a diagnosis tree for falling click-through rates, separating tracking or data problems from real behavior changes, then segmenting by placement, device, campaign and creative.
  • On a small toy dataset in pandas or SQL, compute click-through rate by segment and week and find which segment explains the change.
  • Write how you would analyse engagement data to improve ad performance, ending with one experiment and its sample-size estimate.

Deliverable: A diagnosis checklist, a segment table from the toy data, and a written analysis plan ending in one experiment.

Day 7 — Behavioral stories and cloud experience

  • Write one story for each reported behavioral prompt (difficult team member, motivation, prioritising deadlines, leading a project) with your decision and a measurable result.
  • Write a sixth story about team collaboration or improving a team process, with your own contribution and the outcome.
  • Write the cloud-experience answer with services used, one trade-off and one incident.
  • Rehearse all six aloud, then list questions to ask about team structure, current challenges and code review.

Deliverable: Six rehearsed answers (five stories and the cloud answer) and a list of questions to ask at the end of the loop.

Team, ownership and cloud stories

Behavioral stages are reported as covering past experiences, teamwork and problem-solving approaches. The behavioral-category prompts candidates report concern a difficult team member, motivation, prioritising several deadlines and running a project end to end, and the cloud-experience question is answered from your own history too. Choose real stories where you made the decision, state the result plainly, and use 'I' for your own actions.

  1. Can you describe an instance where team collaboration led to a successful project outcome?

What is your experience with cloud technologies?

Medium · Technical / Domain Questions

Approach

  1. Choose one system you shipped or ran and say where it ran: which AWS or Azure services (compute, object storage, a managed database, a queue), who deployed it and how, and how configuration and secrets were handled.
  2. Describe one real decision with a trade-off, such as a managed database versus self-hosting, autoscaling versus fixed capacity, or one region versus several, and the evidence that drove the choice.
  3. Add one incident or cost surprise and what you changed afterwards, with a measurement (latency, error rate, bill) before and after.
  4. Be honest about the boundary of your experience: name what you used in production, what only in a side project, and how you would learn the rest. The mistake that sinks this answer is a list of service names with no decision attached.

Follow-up

  • Why did you pick that service over the alternative?
  • What happened the last time an instance or an availability zone failed?
  • How did you keep cost under control or find out it was growing?

Describe a time you worked with a difficult team member. How did you handle it?

Medium · Behavioral / Leadership

Approach

  1. Describe behaviour, not personality: say what the person did (missed handoffs, dismissed review comments, changed requirements late) and what it cost the project.
  2. Show your first move: a private conversation to find out their constraint or view, before escalating. Quote what you said or asked.
  3. Describe the working agreement that came out of it, such as a review turnaround rule or a written design note, and the follow-up that checked it held.
  4. State the result in observable terms (the feature shipped, review cycles shortened) and what you changed in how you work with disagreement. The mistake is a story that blames the other person or in which you only watched.

Follow-up

  • What would you have done if the conversation had not changed anything?
  • When did you involve your manager, and what did you ask of them?
  • How do you handle this differently now with a new teammate?

What motivates you to perform well in your job?

Medium · Behavioral / Leadership

Approach

  1. Name two motivators that you can prove with behaviour, for example owning a measurable outcome or working on hard problems, and give one concrete action each has driven, such as staying with a flaky pipeline until the root cause was fixed.
  2. Connect the motivator to the work the role describes only where it is true for you: data analytics, algorithms that affect ad performance, or shipping features with product and design colleagues.
  3. Say what happens when motivation dips, such as repetitive maintenance work, and how you keep quality up. The mistake is a generic statement about challenge and growth with no example behind it.

Follow-up

  • Tell me about a time that motivation was tested and what you did.
  • What would make you lose interest in a role?
  • How do you stay engaged on routine maintenance work?

How do you prioritize your tasks when faced with multiple deadlines?

Medium · Behavioral / Leadership

Approach

  1. Start from a concrete situation with numbers: the deadlines, the dates, who owned each and what each was worth. Then list the sorting criteria you used: cost of delay, dependencies, effort and what could be done in parallel.
  2. Show that you checked what was truly fixed by asking the owners, and that you renegotiated scope or dates where one could move, with the person affected told early.
  3. Say what you dropped or postponed and how it was recorded, and protect time for urgent bugs or reviews you owe others.
  4. Close with the outcome and a learning. The mistake is answering with 'I work harder' or a plain task list and no trade-off.

Follow-up

  • What if two deadlines come from managers of equal rank?
  • What did you drop, and who objected?
  • How did you respond when an estimate turned out to be wrong?

Provide an example of how you have led a project from inception to completion.

Medium · Behavioral / Leadership

Approach

  1. Pick a project where you made the decisions, even without a manager title, and open with the problem and why it mattered in two sentences.
  2. Walk the stages in order: scoping and the design alternatives you rejected, splitting work across engineers, milestones, how code review and CI/CD kept quality up, and the main risk you retired early.
  3. Say where the plan slipped and what you changed, then give the outcome with a measure (adoption, latency, incidents avoided).
  4. Use 'I' for your decisions and name teammates for theirs. The mistake is telling it as 'we' throughout, so your role is invisible, or telling only the technology and not the coordination.

Follow-up

  • What was the biggest risk, and how did you reduce it?
  • Where did the plan slip, and what did you do about it?
  • How did you resolve a design disagreement on the way?