Interview guides · Aptonet
Aptonet Software Engineer Interview Guide
Aptonet Software Engineer interview guide: the three reported rounds, contractor and hourly-rate questions, project deep-dive prep and a 7-day plan.
The 60-second brief
Candidate reports for this role do not name Aptonet's products or customers, so this guide makes no claims about them. They do describe the job. Software engineers do technical work for the company's products, services and internal systems. They work with team leads and stakeholders to agreed timelines, and they are expected to manage their own output. Candidates also report that many Aptonet technical roles are contractor engagements billed by the hour. That arrangement shapes the interview as much as the engineering does: the reported questions are about contract alignment, and the technical check is a discussion of the work you have already done.
This guide is for engineers interviewing for a Software Engineer role at Aptonet, particularly anyone who has not worked as an hourly contractor before. It covers the three reported stages (Recruiter Outreach, Structured Discussions, Leadership Discussion). It shows how to answer the three reported questions on hourly contracting, scheduling and engagement models. It also covers how to present your past projects so the technical side of the conversations holds up, and how to reach the leadership stage with your rate and contract terms already decided.
Candidates report three rounds over roughly 3-5 weeks: Recruiter Outreach, a series of Structured Discussions on technical background and logistics, and a Leadership Discussion on contract terms and compensation.
Focus areas
- Recruiter Communication
- Interview Process Navigation
- Screening Questions Handling
Overview
Candidates describe the role as technical delivery work for Aptonet's products, services and internal systems. You work with team leads and other stakeholders, ship to defined timelines and own your output without close supervision. Candidates report that many technical roles are set up as hourly contractor agreements. That fact drives the loop: every question candidates have reported is about contracting, not algorithms.
The reported process is three conversations, not a series of coding rounds. The technical part, as candidates describe it, is a discussion of your background: which technologies you used, what problems you solved, which decisions you made and how they changed the outcome. Candidate reports name no specific language or framework, so treat the job description you applied to as your stack list. Prepare to talk in depth about the items on it that you have actually used.
That gives your preparation two tracks. The first is numbers and terms. Know whether you will accept hourly contract work, what rate you need and how you derived it, how many hours a week you can commit, and whether you prefer project-based or ongoing engagements. The second is project depth. Pick three projects and, for each one, be able to explain a decision, the alternative you rejected and a measurable result.
Candidates also report that recruiters screen closely on how well a resume matches the job description, and that confirming the contract type early saves trouble later. Do both before the first call. Map each requirement in the posting to a line on your resume, and ask the recruiter for the exact engagement type (agency or direct, contractor or hourly employee) before the leadership stage.
The Aptonet interview process
These three stages are what candidates report, in the order they report them. The first two cover your background and logistics, and the last covers contract terms and pay.
Recruiter Outreach
Candidates report that the process opens with a recruiter reaching out. The first conversation covers your background and why you are interested in the role. Many Aptonet technical roles are reported to be hourly contractor engagements, so expect the engagement model to come up early. Have your answer and a rate range ready before the call instead of working them out during it. Candidates also report that a close match between your resume and the job description matters for getting past this screen, so tailor the resume before you reply.
What to demonstrate
- How closely your background matches the job description
- Your interest in the role and openness to an hourly contractor arrangement
- Basic availability and logistics: start date, weekly hours, location and work authorization
How to prepare
- A short spoken walkthrough of your resume that ends on the two or three job-description requirements you match most directly.
- A one-sentence answer to whether you will work as an hourly contractor, plus your rate range and the classification you are assuming.
- Your start date, weekly hours, time zone and any work authorization constraints, written down so you give the same answers every time.
Structured Discussions
Candidates report a series of conversations rather than a single interview. They are used to confirm your technical background and the logistics of the role, including contract type and hourly pay. As reported, the technical side centres on your past projects: the technologies you used, the problems you solved and the decisions you made, with their effect on the result. No candidate report describes a live coding exercise at this stage. Put your preparation into explaining your own work in depth, and keep your logistics answers identical across conversations with different people.
What to demonstrate
- How clearly you explain past projects: the stack, the problem and the outcome
- The reasoning behind your technical decisions and what they changed
- Consistency of your logistics answers (contract type, rate, hours) across conversations
How to prepare
- Three project deep dives, each covering the problem, the technologies, one decision with the alternative you rejected, and a result you can put a number on.
- Spoken answers to the scheduling and the project-versus-hourly questions, each backed by one real example from your work.
- A one-page logistics sheet (rate range, hours, start date, classification) to check before each conversation.
Leadership Discussion
Candidates report that the final stage is a conversation with leadership about contract terms and compensation. Treat it as a negotiation you have prepared for. Arrive with your rate floor and target, a checklist of terms that must be settled, and the questions you want answered in writing. Candidates advise confirming the contract type early in the process. If anything about it is still unclear at this point, settle it here before you agree to anything.
What to demonstrate
- Clarity and firmness on your hourly rate and contract expectations
- Your understanding of what the engagement terms mean for you
- Clear, professional communication with leadership
How to prepare
- A rate position with a floor, a target and a one-sentence justification (market comparison and the costs you carry as a contractor).
- A terms checklist: classification, weekly hours and overtime approval, contract length and renewal, termination notice, invoicing and payment terms, IP ownership and equipment.
- Two or three questions for leadership about the team's current project and how contractor work is scoped and reviewed.
Where candidates lose points
Saying "I'm open to anything" about hourly contract work at the recruiter stage, then raising objections about classification or benefits at the leadership stage.
Decide before the first call whether you will take hourly contract work and under which classification. Write down the conditions you need, and state them in your first answer to the contractor question.
Quoting a salary when asked for an hourly rate, or dividing your current salary by 2,080 and calling that your rate.
Work out your rate from target income divided by realistic billable hours, then add a margin for the benefits, leave and business costs you would cover yourself. Bring a floor and a target, and the one-sentence reasoning behind them.
Describing past projects as a list of technologies with no decision, trade-off or result attached.
For each of three projects, prepare the problem, the stack, one decision with the alternative you rejected, and a measurable outcome. Candidates report that the technical conversations centre on what you did and why, so a list of tools leaves that question unanswered.
Sending a generic resume and losing at the screen on fit before any conversation about skills.
Candidates report that recruiters screen closely against the job description. Map each requirement in the posting to a specific line on your resume, reorder or rewrite bullets so the matches come first, and open your recruiter call with those matches.
Agreeing to an engagement without asking about weekly hours, overtime approval, contract length, termination notice or payment terms.
Take a terms checklist into the leadership conversation and get answers in writing. Candidates advise confirming the contract type early, so ask the recruiter about it in the first conversation and confirm it again with leadership.
Questions & practice
Merge partitioned event streams into one ordered feed with bounded lateness
Hard · k-way merge · watermarks · out-of-order streams
The read-model service consumes 64 log partitions carrying about 4,000 events per second in total. Each partition is ordered within itself, but partitions drift by up to 30 seconds, and the activity feed must present a tenant's events in occurred_at order. Produce the merge. State its complexity, the buffer it requires in events and in bytes, what happens when one partition is idle, and what you do with an event that arrives after you have already emitted its position. Payloads average 1 KB.
Approach
- Merge with a min-heap over the 64 partition heads keyed on (occurred_at, event_id): O(log P) per event and O(n log P) overall. The tie-break on event_id is what makes the output deterministic when two partitions carry the same millisecond, which matters because the feed is paginated and a non-deterministic order reorders pages under the reader.
- Emitting the heap head is only correct once every partition has produced everything up to that timestamp, so the emit condition is a watermark: the minimum across partitions of the highest occurred_at seen, less the allowed lateness. Events are held until the watermark passes them, which is what turns individually ordered streams into a jointly ordered one.
- Size the buffer from the lateness rather than guessing: 4,000 events per second times 30 seconds is 120,000 buffered events, and at 1 KB each about 120 MB of heap. That number is the real price of the ordering guarantee and belongs in front of whoever asked for it.
- Handle the idle partition explicitly, because it fails the feed rather than corrupting it: a partition with no traffic never advances its own maximum, so the watermark freezes and output stops entirely. Either every partition emits a periodic idle marker carrying the broker's current time, or the watermark falls back to wall clock for a partition silent beyond a threshold.
Follow-up
- The lateness budget is raised to five minutes. What is the new buffer, and what besides memory changes?
- The consumer restarts. Where does it resume from, and what does the feed look like for the first 30 seconds?
Identify the heaviest tenants in a five-minute window under memory pressure
Medium · top-k · heavy hitters · streaming
The edge service handles about 3,000 requests per second across roughly 50,000 tenants, peaking near 9,000. Expose the 50 heaviest tenants by request count over the trailing five minutes so limits can be tightened before one tenant's backfill starves the fleet. You may not retain five minutes of raw records. Give the exact solution and its memory, then the bounded-memory approximation with its error stated as a formula, and say which you would ship and at what tenant cardinality that choice changes.
Approach
- Do the exact version first, because it is affordable at this cardinality: a ring of 300 one-second counters per tenant, advanced lazily, is 1,200 bytes of counters per tenant and roughly 60 to 90 MB for 50,000 tenants with overhead. Carry a running total and subtract the bucket you overwrite so a window read is O(1) rather than 300 adds.
- Extract the top 50 with a size-k min-heap over the tenant sums: O(d log k) for d tenants, against O(d log d) to sort them all. Maintaining the heap continuously instead of on query requires a tenant-to-heap-index map, because incrementing a count already inside the heap means sifting from a known position, and without that map you rebuild the heap on every request.
- State the approximation precisely rather than gesturing at sketches. Misra-Gries with m counters retains every item whose true count exceeds N/(m+1), and each retained count underestimates the truth by at most N/(m+1). With m = 1,000 and N = 900,000 requests in the window the error is roughly 900 requests, which is fine for spotting a tenant sending 50,000 and useless for ranking two tenants 200 apart.
- Say what breaks when the window slides: Misra-Gries and Space-Saving are insert-only and cannot be decremented as records age out. The workable construction is one summary per sub-window, say ten seconds, with 30 summaries merged at query time, and the merged error is the sum of the per-summary errors, so the bound degrades linearly in the number of sub-windows.
Follow-up
- The heaviest tenant is heavy because of one export job rather than user traffic. Should the limiter treat those as the same tenant?
- Two tenants sit tied at the boundary of the top 50. Does your answer flap, and does the flapping matter?
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?
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
- 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.
- 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.
- 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.
- 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?
Stop tag and share joins from fanning out a page
Medium · join fan-out · semi-joins · many-to-many
resource_tag is (resource_id, tag_id) with PK (resource_id, tag_id); resource_share is (resource_id, shared_with_user_id, permission). The tagged-and-shared listing inner-joins resource to both, filters tenant_id, tag_id = ANY($2) and shared_with_user_id = $3, orders by updated_at DESC and takes 50. Pages come back with fewer than 50 distinct resources and the total in the header is far too high. Explain the row multiplication, rewrite both the page query and the count query so each is correct, and name the index each one needs. PostgreSQL 16.
Approach
- Do the arithmetic against the predicates that are actually there. An inner join emits one row per matching child row, and both joins are filtered: tag_id = ANY($2) admits only the requested tags, shared_with_user_id = $3 admits one user's share rows. So a resource holding three of the requested tags and shared with $3 once yields three rows, not one — the multiplier is its count of matching tags times its share rows for that single user, and that second factor is 1 unless the table admits duplicate (resource_id, shared_with_user_id) pairs. LIMIT 50 then limits rows rather than resources, and COUNT(*) counts pairs — the header is the product, not the population.
- Reject DISTINCT as the fix. It deduplicates after the product has been built, so the planner must materialise and sort the fanned-out set before the LIMIT can apply, and it leaves any SUM or AVG in the same select list wrong.
- Rewrite both filters as semi-joins, keeping resource as the only row source: AND EXISTS (SELECT 1 FROM resource_tag rt WHERE rt.resource_id = r.resource_id AND rt.tag_id = ANY($2)) and the same shape against resource_share. A semi-join stops at the first match per resource and preserves the driving index order, so ORDER BY updated_at DESC, resource_id DESC LIMIT 50 still stops after 50 rows.
- Count with the same predicates and no join at all: SELECT count(*) FROM resource r WHERE r.tenant_id = $1 AND r.status = 'active' AND EXISTS (...) AND EXISTS (...). Nothing multiplies a resource, so the number is the population.
Follow-up
- The filter changes from 'any of these tags' to 'all of these tags'. Rewrite it and state what it costs relative to the ANY form.
- A resource can be shared with the same user twice under different permissions. Does your count change, and should it?
Are you willing to work as a contractor at an hourly rate?
Medium · Operational and Contractual Alignment
Approach
- Answer in the first sentence: yes, no, or yes with named conditions. An unqualified 'it depends' leaves the question open, and it comes back at the leadership stage, where backing out costs everyone more. Example: "Yes. I have billed hourly before, and my range is X to Y depending on classification and weekly hours."
- Find out which classification you are being offered before you commit. Hourly pay as an employee of Aptonet or of an agency is different from invoicing as an independent contractor through your own business. In the second case you usually carry your own taxes, insurance, equipment and unpaid leave, which raises the rate you need.
- Derive your rate instead of guessing it. Divide your target annual income by realistic billable hours: a full-time year is about 2,080 hours before holidays, leave and gaps between contracts. Then add a margin for any benefits and business costs you cover yourself. Give a range with a floor and a target, not a single number.
- State any conditions plainly: work authorization or sponsorship needs, a minimum weekly hour commitment, interest in converting to a permanent role later, or a notice period at your current job. A condition raised now is far easier to accommodate than one raised after an offer.
Follow-up
- What hourly rate are you looking for, and how firm is it?
- Would you consider converting to a permanent role later, and on what terms?
- How many hours a week can you commit, and are you working for any other client?
How do you manage your schedule when working on an hourly contract basis?
Medium · Operational and Contractual Alignment
Approach
- Start with the concrete commitment: the hours per week you will work, the core hours when you are reachable, and how much of your day overlaps with the team's time zone.
- Explain how you track and report time. Log hours daily against a task or ticket in a time-tracking tool or a shared log, then reconcile weekly before invoicing, so a lead can tie every billed hour to work they recognise.
- Describe how you handle estimates and overruns. Estimate each task in hours before you start. Flag it to the lead when you have used most of the estimate and are not close to done, and get approval before going over an hour cap or working extra hours. Never absorb overruns unpaid without saying so, and never bill extra hours without approval.
- If you have other clients or commitments, say so and explain how you prevent conflicts: fixed blocks in your calendar, no overlap with the team's core hours, and early notice of planned time off.
- Back it with one real example in a STAR shape: a week when a task ran over or priorities changed, what you told the lead and when, and how it turned out. Without an example, the answer sounds like a policy statement.
Follow-up
- What do you do when a task will clearly take longer than the hours approved for it?
- Do you bill meetings, code review and waiting on blocked work, and how do you report them?
- How would you prioritise if another client needed you during the team's core hours?
What are your expectations regarding project-based versus ongoing hourly engagements?
Medium · Operational and Contractual Alignment
Approach
- Show you know the difference. A project-based engagement has a fixed scope and deliverables, is usually paid as a fixed fee or capped hours, and ends on delivery. An ongoing hourly engagement is time and materials: open-ended, renewed or ended with notice. Name who carries the risk in each: scope overruns fall on the contractor under a fixed price and on the client under time and materials.
- State a preference and the reason for it. Examples: continuity and steadier income, depth in one codebase, or flexibility between engagements. Saying either model is acceptable is fine, but say what would make you choose one over the other. Having no view at all is the weakest answer.
- List the terms you would want settled for each model. For project-based work: written scope, acceptance criteria and a change-request process. For ongoing hourly work: expected weekly hours, any minimum commitment, contract length and renewal, termination notice on both sides, invoicing and payment terms, and IP ownership.
- Use a past example in which scope changed mid-project and you handled it with a re-estimate and a written change, not by absorbing the work quietly. It shows you can work under either model.
- If you want a path to a permanent role, say so here. It belongs naturally in a question about how long you expect the engagement to last.
Follow-up
- If a fixed-scope project grew halfway through, how would you handle the extra work?
- How long an engagement are you hoping for?
- How much notice would you want before an engagement ends, and how much would you give?
Read latency spikes on a sixty-second sawtooth
Medium · cache stampede · single-flight · ttl
The cached listing read path serves about 14k reads/second at an 85% hit rate. p99 sits at 35 ms for 57 seconds, jumps to 900 ms for 3, and repeats. During each spike the primary shows several hundred identical listing queries starting within the same millisecond, all carrying one large tenant's id. Cache entries use a 60-second TTL. Give the mechanism, the ordered checks, the fix, and the correctness hazard your fix must not introduce.
Approach
- Match the period to a configured number before theorising about load. A spike every 60 seconds against a 60-second TTL is an entry expiring, and you confirm it by correlating spike timestamps with the entry's write time rather than with the traffic curve. If the period had matched a cron or a GC interval instead, this is a different investigation.
- Establish the concurrency of the miss. Several hundred identical queries in one millisecond means the miss path has no coalescing: every request that arrives between expiry and repopulation recomputes. The herd size is that key's arrival rate times its recompute time, so at 1.2k reads/second for the hot key and a 250 ms recompute you expect about 300 concurrent misses, which matches what is observed.
- Add single-flight on the miss path so one caller per key recomputes under a short-lived lock while the rest wait for its result. Prefer stale-while-revalidate where the read tolerates it: return the expired value immediately and refresh asynchronously, which removes the latency spike rather than serialising it into a queue of waiters.
- De-synchronise the keys. Write TTLs with jitter, for example 60 seconds plus or minus 10%, so a deploy or a mass invalidation does not align every key on the same second and turn a per-key herd into a fleet-wide one.
Follow-up
- The same sawtooth appears on a key that is invalidated on write rather than expired. Is that the same bug?
- How does your answer change if the recompute takes 4 seconds instead of 250 ms?
Suggested practice checklist
The plan follows the three reported conversations. It covers your resume and job-description fit, the numbers behind your rate, each reported contract question in turn, project deep dives for the technical discussions, the leadership negotiation, and a full rehearsal.
Day 1 — Match your resume to the job description
- Copy every requirement from the posting into a list and put next to each one the project or role that shows it.
- Rewrite or reorder your resume bullets so the strongest matches come first, and cut lines that match nothing in the posting.
- Write a short spoken introduction that ends on your two or three closest matches, and say it aloud until it sounds natural.
Deliverable: A requirement-to-evidence map, a tailored resume and a rehearsed spoken introduction.
Day 2 — Set your rate and your answer on contracting
- Calculate your hourly rate from target annual income divided by realistic billable hours, then add a margin for benefits, leave and business costs you would cover yourself.
- Set a floor and a target, and write one sentence justifying them.
- Write and say aloud your answer to whether you will work as a contractor at an hourly rate, including any conditions (classification, sponsorship, conversion interest).
Deliverable: A rate sheet with floor, target and justification, plus a spoken answer to the hourly contractor question.
Day 3 — Show how you manage hourly time
- Write down your weekly hours, core reachable hours, time zone overlap and start date.
- Describe your time-tracking and reporting method, and how you handle a task that runs past its estimate.
- Pick one real week when a task ran over or priorities shifted, and structure it as a STAR story for the scheduling question.
Deliverable: An availability sheet, a written time-tracking method and a STAR story answering the scheduling question.
Day 4 — Decide between project-based and ongoing hourly work
- Write a two-column comparison of fixed-scope and time-and-materials engagements: who carries the overrun risk, how each ends, and what each means for your income.
- State your preference and the reason in two sentences, including whether you want a path to a permanent role.
- List the terms you need settled for each model and turn them into questions you can ask.
Deliverable: A comparison table, a two-sentence preference and a list of terms questions for the project-versus-hourly question.
Day 5 — Build three project deep dives
- For three projects, write the problem, the technologies, one decision with the alternative you rejected, and a result with a number attached.
- Use the practice prompts on arguing against a design, unblocking a stuck engineer and warning callers about a breaking change to pull out a fourth story, about a disagreement or a dependency.
- Explain each project aloud and cut anything that is just a list of tools.
Deliverable: Four written project or decision stories, each with a stated trade-off and a measurable outcome, rehearsed aloud.
Day 6 — Prepare the leadership conversation
- Turn your rate sheet into a negotiation script: opening number, the reason behind it, your floor, and which terms you would trade for rate.
- Finish your terms checklist: classification, hours and overtime approval, contract length and renewal, termination notice, invoicing and payment terms, IP and equipment.
- Write two or three questions for leadership about the team's current project and how contractor work is scoped and reviewed.
Deliverable: A negotiation script, a complete terms checklist and a short list of questions for leadership.
Day 7 — Rehearse all three conversations
- Have a friend play the recruiter: your introduction, the three contract questions and your availability.
- Have them play a technical interviewer who asks you to explain one project's decisions and outcome in depth.
- Finish with the leadership role-play on rate and terms, then note every answer that changed from earlier in the rehearsal and fix it on your logistics sheet.
Deliverable: A full spoken rehearsal of all three stages and a corrected logistics sheet with consistent answers.
Behavioural preparation
Candidates report that Aptonet's conversations cover your background, your past technical decisions and how you will work under an hourly contract. Rehearse the reported contract questions word for word first, then the project and self-management prompts. In this role you are expected to manage your own output to agreed timelines.
- Are you willing to work as a contractor at an hourly rate?
- How do you manage your schedule when working on an hourly contract basis?
- What are your expectations regarding project-based versus ongoing hourly engagements?
- Walk me through a project you delivered: the technologies, the problem, one decision you made and what it changed.
- Tell me about a time you owned a piece of work largely on your own and had to keep a lead informed as it slipped or changed.
Tell callers you do not own that their integration breaks
Medium · deprecation · compatibility · stakeholders
A field in a write endpoint's response must change shape. You own the endpoint; you do not own the four internal callers or the outbound webhook consumers who read it. Describe a deprecation you were responsible for: what you shipped first, how you established who was actually reading the field, the window you gave and what set its length, what you did about the consumer who never moved, and how you decided removal was safe. Name the signal you used, not the announcement you sent.
Approach
- Establish the reader set empirically rather than from a wiki of owners: per-field usage counters keyed by principal, or access logs attributed to a consumer. State the blind spot of whichever you pick, since a consumer that reads the field only on a monthly job will not appear in a week of logs.
- Ship additive first. Populate the new field alongside the old one so no reader is forced to move, which is also what keeps a rolling deploy safe, because old and new instances answer the same requests at the same time and a rollback must still find the old shape present.
- Set the window from the slowest legitimate consumer's release cadence, not from your calendar, and decide separately what to do for a consumer with no release process at all, such as an external webhook endpoint you can only email.
- Convert silence into evidence before you rely on it: a short, low-traffic removal window that makes a still-dependent consumer fail visibly and loudly while you are watching, rather than at three in the morning after you have moved on.
Follow-up
- How would you detect a consumer that reads the field only during a monthly export?
- One caller refuses to move and has a commercial relationship behind it. What changes in your plan and what does not?
Unblock an engineer without taking the keyboard
Easy · mentoring · leases · at-least-once
A teammate has spent two days on a job handler that occasionally writes duplicate rows. They are certain the queue is delivering twice by mistake. You suspect a lease expiring under a slow handler, so the job is running concurrently with itself. Describe how you have unblocked someone in this position: what you asked before offering a hypothesis, what you showed them rather than told them, and what you left them owning. Then say what you would do if their theory turned out to be the right one.
Approach
- Ask before diagnosing, and ask for things answerable from data they already have: the attempt count on the job rows that produced duplicates, the handler's observed duration against its lease expiry, and whether the duplicate rows share a natural key that a unique constraint could have caught.
- Teach the shape rather than the answer. A lease cannot distinguish a dead worker from a slow one, so a handler that outruns its lease is running twice by design, and deploys deliver the other half by killing handlers mid-run on every rollout. Both of their candidate theories produce identical duplicate rows, which is why the evidence has to come from timings rather than from argument.
- Hand over a checklist they execute: a natural key on every write the handler performs so the second copy collides rather than appends, the record of intent written before any external effect, a lease heartbeat while running, and the metric that shows it working.
- Keep ownership with them deliberately. Pair on the first write, then step back; if you finish it yourself you have closed one ticket and left the same person stuck on the next redelivery.
Follow-up
- How would you distinguish a genuine double-delivery from a lease expiry using only the data already stored?
- Their handler calls an external endpoint before recording that it did. What do you tell them to change first?
Argue against a design, lose, and commit anyway
Medium · disagreement · service boundaries · decision records
Describe a design you argued against and lost. State the failure you predicted as a named mechanism, not a feeling about complexity: two services that would need one transaction, a projection with no rebuild path, a write path with no idempotency key. Say what evidence you brought, what the decision maker weighed instead, and what you did after the decision was made: what you instrumented, what you wrote down, and whether the prediction came true. Five minutes.
Approach
- State the prediction in falsifiable form up front: the mechanism, the condition that triggers it, and the observable outcome. A prediction that cannot be checked also cannot be credited to you later.
- Show the evidence you had at the time and label each piece honestly as measured, analogous, or intuition. Keeping the intuition is fine; disguising it as data is the thing that erodes your standing in the next argument.
- Represent the opposing case at full strength, including the constraint you did not control: a fixed date, a team boundary, or the fact that the decision was cheap to reverse and yours was not.
- Make disagree-and-commit concrete. Name the artefact you left behind so the prediction could be settled without you: the alert and its threshold, the counter on the dashboard, the decision note that recorded the trade-off and the condition that would revisit it.
Follow-up
- What threshold on that alert would have proved you right, and did anyone ever look at it?
- If the same proposal arrived tomorrow with the same deadline, would you argue it the same way?