Courses › AI-Assisted Coding › Round Types
Data & Integration Tasks with AI
Messy data files, log-analysis scripts and third-party API integrations, checked properly.
Some AI-assisted rounds aren't about features or algorithms. They're practical engineering chores: process a messy data file, write a script that answers questions about logs, or integrate a third-party API from its documentation. These tasks feel easy with an assistant, which is exactly why candidates fail them. The assistant writes something that runs on the sample, and it quietly gets the real data wrong.
What the interviewer is watching for is whether you inspect the data and the docs yourself and check the output.
Data and scripting tasks
Typical prompts:
- "Here's a 50 MB access log. Which endpoints have the worst p95 latency, and which clients cause most of the 5xx errors?"
- "Merge these two CSV exports, remove the duplicate customers and report what didn't match."
- "Write a CLI tool that summarizes this JSON event stream by day."
Look at the data before you prompt
Spend the first few minutes looking at the real file, not the assistant's guess about it:
head,tailand a random sample of lines. Bad rows often hide in the middle.- Count the lines, and how many match the format you expect.
- Look for the traps: blank lines, headers repeated mid-file, quoted commas in CSV, mixed time zones, missing fields, different units (ms vs s), encodings.
Then give the assistant real sample lines, including bad ones, and state the rules: "Skip malformed lines but count them; timestamps are UTC; latency is in milliseconds."
A robust parsing pattern
Whatever the assistant writes, make sure it has this shape: parse each record strictly, count and report what it skipped, and keep the parsing separate from the analysis so each can be tested.
import re
from collections import Counter, defaultdict
LINE = re.compile(r'(?P<ip>\S+) "(?P<method>[A-Z]+) (?P<path>\S+)" (?P<status>\d{3}) (?P<ms>\d+)ms')
def parse(lines):
records, skipped = [], Counter()
for line in lines:
line = line.strip()
if not line:
skipped["blank"] += 1
continue
m = LINE.fullmatch(line)
if not m:
skipped["malformed"] += 1
continue
r = m.groupdict()
r["status"], r["ms"] = int(r["status"]), int(r["ms"])
r["path"] = r["path"].split("?")[0] # group /orders?id=1 with /orders
records.append(r)
return records, skipped
def p95(values):
values = sorted(values)
return values[max(0, -(-95 * len(values) // 100) - 1)] # nearest-rank method
def report(records):
by_path = defaultdict(list)
errors = Counter()
for r in records:
by_path[r["path"]].append(r["ms"])
if r["status"] >= 500:
errors[r["ip"]] += 1
worst = sorted(by_path, key=lambda p: p95(by_path[p]), reverse=True)
return [(p, p95(by_path[p])) for p in worst], errors.most_common(2)
sample = '''10.0.0.1 "GET /orders?id=1" 200 120ms
10.0.0.2 "GET /orders?id=2" 500 900ms
10.0.0.2 "POST /checkout" 502 300ms
garbage line
10.0.0.3 "GET /health" 200 2ms'''.splitlines()
records, skipped = parse(sample)
print(dict(skipped)) # {'blank': 1, 'malformed': 1}
print(report(records)) # ([('/orders', 900), ('/checkout', 300), ('/health', 2)], [('10.0.0.2', 2)])[!WARNING] Check the numbers by hand Before you present a result, check one or two numbers another way: count a few lines with grep, or compute one value in your head. Percentile formulas, time-zone conversions and deduplication rules are where generated scripts are most often wrong, and they don't crash. They just give a wrong answer.
Saying what you'd do with more data
Interviewers often ask, "What if the file were 100 GB?". Have an answer ready: stream line by line instead of loading everything; keep only aggregates in memory; use an approximate percentile (a histogram or t-digest); or move the job to a database or a distributed tool.
Integration tasks
Typical prompts:
- "Using this payment provider's API docs, add a refund feature."
- "Sync all of a customer's records from this paginated API into our database."
- "Call the weather API for each city and cache the results."
Read the docs yourself
Assistants confidently invent endpoints, parameters and response fields, especially for less common APIs or newer versions. Before prompting, find these in the documentation yourself:
Then paste the relevant section of the docs into your prompt. Don't let the assistant work from memory.
A client that handles pagination, rate limits and retries
import time
class ApiError(Exception):
def __init__(self, status, retry_after=None):
super().__init__(status)
self.status, self.retry_after = status, retry_after
def fetch_all(get_page, max_attempts=4, sleep=time.sleep):
"""get_page(cursor) -> (items, next_cursor); next_cursor None on the last page."""
items, cursor = [], None
while True:
for attempt in range(max_attempts):
try:
page, next_cursor = get_page(cursor)
break
except ApiError as e:
retryable = e.status == 429 or e.status >= 500
if not retryable or attempt == max_attempts - 1:
raise
sleep(e.retry_after if e.retry_after is not None else 0.1 * 2 ** attempt)
items.extend(page)
if next_cursor is None:
return items
cursor = next_cursor
class FakeApi:
"""Three pages; rate-limits once and fails once, as a real API might."""
def __init__(self):
self.pages = {None: ([1, 2], "c2"), "c2": ([3, 4], "c3"), "c3": ([5], None)}
self.failures = [ApiError(429, retry_after=1), ApiError(503)]
self.calls = 0
def get_page(self, cursor):
self.calls += 1
if self.calls in (2, 4):
raise self.failures.pop(0)
return self.pages[cursor]
api, waits = FakeApi(), []
print(fetch_all(api.get_page, sleep=waits.append)) # [1, 2, 3, 4, 5]
print(waits) # [1, 0.1]Testing against a fake that rate-limits and fails is the step candidates skip. It's also the strongest evidence you can show that your integration handles the real world.
[!INTERVIEW] Narrate the failure modes Even if time runs out before you handle all of them, say them out loud: "If the sync crashes halfway, I'd store the last cursor so it can resume. If the same record arrives twice, the insert is an upsert on the provider's ID, so it's safe." That shows the judgment the round is testing.
Common mistakes
- Trusting the sample. The sample file is clean; the real one isn't.
- Silently dropping data. Skipping bad rows without counting them hides problems. Always report what was skipped.
- Retrying everything. Retrying a 400 or a non-idempotent POST makes things worse.
- Hard-coding secrets in code you're sharing on screen.
- Not checking the output. A script that runs isn't a script that's right.
[!TIP] Practice Integrate a Paginated, Rate-Limited API · Analyze Logs with a Script · Debugging with AI · Reviewing AI Code