Interview guides · Alpha Plus Technologies
Alpha Plus Technologies Software Engineer Interview Guide
Alpha Plus Technologies Software Engineer interview guide: ASP.NET validation, nested SQL tuning, debugging, project defense and a 7-day plan.
The 60-second brief
Candidate reports say little about what Alpha Plus Technologies sells. They describe the Software Engineer job instead. Candidate-sourced descriptions of the role mention backend services, database schemas, production troubleshooting, code review and working with product managers. ASP.NET is the framework named among the must-have skills, alongside advanced SQL and strong debugging. Cloud infrastructure, CI/CD pipelines and agile practice are listed as nice-to-haves. The topics candidates report being tested on follow the same split: SQL, nested SQL queries, debugging, logical error identification and backend development.
This guide is for backend-leaning engineers interviewing for the Software Engineer role at Alpha Plus Technologies, especially those who work in .NET and SQL or can get up to speed on them quickly. It covers the six stages candidates report and gives a worked approach for each of the twelve reported questions: four technical, four about your own project and four behavioral.
Candidates report six stages over roughly 4-6 weeks: Initial Screening, Technical Evaluation, Aptitude Testing, Hands-on Project Work, Project Defense and Leadership Interviews. Candidates describe the loop as sequential, with early stages gating the later ones.
Focus areas
- SQL
- Debugging
- Backend Development
Overview
The reported technical questions are narrow and practical. They ask how ASP.NET validation controls work, how to speed up a nested SQL query, how to find a logic bug in a running service and what different indexes cost. None of them is an algorithm puzzle. The strongest answers come from things you have actually done: an execution plan you read, a server-side validation check you relied on, a wrong total you traced back to one line of code. If your recent work is on another stack, focus your preparation on the ASP.NET request and validation lifecycle and on reading query plans. Those are the two areas where a generic answer will sound thin.
The middle of the loop is built around a project. Candidates report a hands-on project followed by a defense where they present it. In the defense they answer questions about why they chose their tools and patterns, how data moves through the application, and what they would refactor. The four reported project questions all assume you know every part of what you submitted: an end-to-end walkthrough, a scalability refactor, the architectural constraints, and a debugging story from a project built from scratch. Treat the build as preparation for the defense. Keep a decision log while you write the code, so your reasons are written down before anyone asks for them.
Two stages are easy to underrate. Candidates single out the aptitude testing and a group discussion format as checks on logical reasoning and communication style. For group settings, they advise listening and building on other people's points rather than dominating. Candidates report that the leadership stage closes the process with a focus on fit and alignment. The reported behavioral questions ask why you over other candidates, where you want to be in five years, how you cleared a bottleneck with a non-technical stakeholder and how you take code-review feedback. Prepare each one as a specific story with numbers in it, not as a set of claims about yourself.
The Alpha Plus Technologies interview process
These are the six stages candidates report, listed in the order they report them. Candidates describe little of the format inside each stage, so prepare the material rather than memorising a script.
Initial Screening
Candidates report that the process opens with a check of your qualifications. They also say that questions about remote work and location get settled with the recruiter in this initial HR screen. Your background is compared against the requirements candidates describe: a backend framework such as ASP.NET, advanced SQL, and debugging. Lead with the backend work you can defend in depth, because the project defense and leadership stages come back to whatever you claim here. Use the call to find out how the later stages work, especially the scope and deadline of the hands-on project.
What to demonstrate
- How well your background matches the reported must-haves: a backend framework (ASP.NET is named), advanced SQL and debugging
- How clearly you summarise your own experience
How to prepare
- A short pitch that names one backend project, one SQL tuning result and one production bug you fixed, each with a concrete number
- Questions for the recruiter: what the aptitude stage and the project involve, how long you get for the project, and the team's remote policy
- A pass over your resume that removes any technology you cannot discuss in depth
Technical Evaluation
Candidates describe this stage only as a test of technical proficiency. Across the whole process, the technical areas they report are SQL performance (execution plans and indexing), backend practice around validation, security and error handling, and systematic debugging of logic errors. The four reported technical questions fall in those same areas. Prepare each one as a mechanism you can explain and demonstrate, not as a definition. Candidates also report having to explain why the approach they chose beats the alternatives, so pair every technique with a case where you would not use it.
What to demonstrate
- Technical proficiency in your primary stack, as reported
- Explaining why one approach beats the alternatives
How to prepare
- Rewrite one correlated scalar subquery as a LEFT JOIN and one IN filter subquery as EXISTS, then compare the execution plans and logical reads
- A one-page indexing comparison covering clustered, composite non-clustered, covering and filtered indexes, with the write and storage cost of each
- Your step-by-step method for finding a logic bug that throws no exception, written out
- An explanation of each ASP.NET validator type and why the server-side check is required
Aptitude Testing
Candidates report an aptitude stage that tests problem-solving and analytical skill. They warn against underrating it, and describe it, along with the group discussion format, as a check on logical reasoning and communication style. Candidate reports do not describe what the test contains or how it is run, so prepare broadly across the usual aptitude problem types. Work through them under a timer, and get used to explaining your reasoning out loud in case the stage turns out to be a discussion rather than a written test.
What to demonstrate
- Problem-solving and analytical skill, as reported
- Logical reasoning, which candidates say the aptitude and group stages check
How to prepare
- Timed sets of common aptitude problem types: number and letter series, data interpretation tables, syllogisms, seating and arrangement puzzles, percentages and time-work. Use a self-set target such as 20 questions in 20 minutes and log each miss by type
- Practice questions that train careful step-by-step reasoning, such as tracking a rolling failure rate per destination
- Saying your reasoning out loud as you solve, so the same method works in a spoken or group format
Hands-on Project Work
Candidates report a hands-on project meant to show practical skill. They describe it as a test of baseline engineering in your core stack and advise putting effort into clean code and documentation. The project is also the material for the next stage, so build it with the defense in mind. That means a layered structure (UI, service, data access), server-side validation, parameterized queries, error handling that logs useful context, and a README covering setup, architecture and the trade-offs you accepted. Keep a running decision log as you work. It becomes your notes for the defense.
What to demonstrate
- Practical engineering skill in your core stack
- Clean code and documentation, which candidates advise putting effort into
How to prepare
- A README outline: setup, architecture diagram, data model, decisions with the alternatives you rejected, known limitations
- A checklist: server-side validation on every input, parameterized SQL, consistent error handling, a few meaningful tests
- A decision log kept next to the code, with one line per choice and the reason for it
Project Defense
Candidates report presenting their project and defending it in front of interviewers. They name three areas to be ready on: why you chose specific tools or patterns, how data moves through the application, and where your own work could be improved. The reported project questions cover the same ground: an end-to-end walkthrough, a scalability refactor, the architectural constraints you faced, and a debugging story from a project built from scratch. To rehearse, trace one request from input to the database and back. Then point out a weakness in your own code before anyone else does, together with the fix you would make.
What to demonstrate
- Owning your design decisions: the reasons behind your tools and patterns
- Explaining how data flows through your application
- Spotting refactoring opportunities in your own work
How to prepare
- A diagram tracing one request through a core feature of your project
- Three refactors you would make, each with the measurement that would justify it
- Answers to 'why this and not X' for the framework, the data store and the project structure
Leadership Interviews
Candidates report that the process ends with leadership conversations about cultural fit and alignment. Candidates also report behavioral and alignment questions: why you over other qualified candidates, where you see yourself in five years, how you worked with a non-technical stakeholder to clear a bottleneck, and how you handle feedback in code review. Candidates also stress being able to explain technical work simply. Practise describing your project's main trade-off to someone with no backend background, and keep each story focused on a decision you made yourself.
What to demonstrate
- Cultural fit and alignment, as reported
- Explaining technical work to a non-technical audience
How to prepare
- Four STAR stories mapped to the reported behavioral questions, each with a number in the result
- A plain-language explanation of your project's main trade-off
- A five-year answer that connects deeper backend skill to this role
Where candidates lose points
Defending a project you cannot explain line by line, such as boilerplate you generated or code you copied and never read closely
Candidates report that the defense covers why you chose your tools and patterns, how data moves through the application, and what you would refactor. Re-read every file you submit. Be able to say what each dependency does and why you included it. For each major choice, prepare the alternative you rejected. Remove anything you cannot explain before you submit.
Describing ASP.NET validation as something that happens in the browser
Say plainly that client-side validators are a convenience and the server check is the real safeguard. Show where it happens: Page.IsValid in Web Forms, ModelState.IsValid in MVC or Core. Mention that by default only RequiredFieldValidator catches empty input (a CustomValidator with ValidateEmptyText=true is the exception), and that validation sits alongside parameterized queries and database constraints rather than replacing them.
Tuning the nested SQL query by guesswork, such as adding indexes or switching to a CTE without reading the plan
Start from the execution plan and name the expensive operator. Rewrite correlated scalar subqueries as LEFT JOINs against pre-aggregated data, use EXISTS for filter subqueries, and replace NOT IN with NOT EXISTS to avoid the NULL trap. Then prove the result set is unchanged with row counts and EXCEPT in both directions before you talk about speed.
Answering the production logic-error question with 'I add logging and look around'
Give an ordered method: detect the problem through an invariant or metric, scope it by input, time and release, reproduce it as a failing test, isolate it by checking intermediate values, fix it with a regression test, then repair any data that was already written wrong. Name the usual culprits (boundaries, time zones, decimal rounding, nulls, races) so the method sounds practised.
Treating the aptitude and group stages as formalities, or taking over a group discussion
Candidates warn that these stages check logical reasoning and communication style. Practise timed reasoning sets until your error rate is low. In a group, restate another person's point before adding to it, and help the group reach a conclusion instead of trying to win the discussion.
Questions & practice
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?
Track a rolling failure rate per destination for circuit decisions
Easy · sliding window · ring buffer · circuit breaker
The egress service delivers about 1,500 webhooks per second across roughly 40,000 destinations, each call bounded by a 10 second timeout. Maintain, per destination, the failure rate over the trailing 60 seconds so a caller can ask before dispatch whether the circuit should open. Attempts arrive as (destination_id, finished_at_ms, outcome). Requirement: amortised O(1) per attempt, with total memory bounded by the destination count rather than by traffic. Give the structure, its exact memory, and the rule that stops a destination with three attempts from opening a circuit.
Approach
- Name the exact-deque version and then reject it as the default. Holding timestamps and advancing a tail pointer past anything older than now minus 60 seconds is a correct two-pointer window at amortised O(1) per attempt, but its memory tracks in-window traffic, so one destination in a retry storm holds hundreds of thousands of entries while thousands of quiet destinations hold none.
- Use a ring of 60 one-second buckets per destination, each bucket a pair of counters for attempts and failures. On an attempt, advance the ring by the elapsed whole seconds, zeroing at most min(elapsed, 60) buckets, then increment the head. That is amortised O(1) with a fixed footprint per destination.
- State the footprint: 60 buckets times two 4-byte counters is 480 bytes of payload per destination, so 40,000 destinations is roughly 20 to 25 MB with per-entry overhead, bounded by the catalogue rather than by the rate. The cost is granularity, since the oldest bucket ages out in whole seconds, which is far tighter than the decision needs.
- Require a minimum sample before the circuit may open. A destination with three attempts and three failures reads as 100 percent and is not evidence; a floor of roughly 20 attempts in the window makes the ratio meaningful, and below that floor use a run of consecutive failures as the trigger instead.
Follow-up
- The fleet is 30 instances and each sees roughly a thirtieth of a destination's traffic. Where does the rate actually live, and what does a per-instance answer get wrong?
- A destination answers in 9.5 seconds and succeeds. It is not failing but it is consuming your per-destination concurrency. What signal should open the circuit here?
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?
Describe how you would approach optimizing a complex nested SQL query.
Medium · Technical and Domain Knowledge
Approach
- Measure before rewriting. Capture the actual execution plan (EXPLAIN ANALYZE in PostgreSQL; the actual plan plus SET STATISTICS IO, TIME ON in SQL Server) and find the operator that carries the cost. Look for scans on large tables, nested loops over many rows, spills to disk, or row estimates far from the actual counts.
- Find correlated subqueries that run once per outer row and rewrite them. A scalar subquery in the SELECT list becomes a LEFT JOIN to a pre-aggregated derived table or CTE, with COALESCE where the subquery used COUNT, so outer rows with no match keep their NULL or 0. IN (subquery) becomes EXISTS, or a join to a DISTINCT or aggregated set: a plain JOIN duplicates outer rows when the subquery column is not unique. NOT IN becomes NOT EXISTS, which also avoids the trap where a single NULL in the subquery makes NOT IN return no rows.
- Make the predicates sargable, meaning they can use an index. Avoid functions and implicit type conversions on indexed columns: WHERE YEAR(created_at) = 2025 becomes a date range. Then add or adjust indexes on the join and filter columns, and use a covering index (INCLUDE columns) when the query reads only a few columns.
- Aggregate before you join when a one-to-many join would multiply rows. Consider putting an intermediate result in a temp table when it is reused or when the optimizer badly misjudges its size.
- Prove the rewrite is correct. Run EXCEPT in both directions between the old and new results. EXCEPT removes duplicates, so also compare row counts, or GROUP BY all columns with COUNT(*), to catch differences in how many times a row appears. Then compare plans and logical reads rather than a single timed run, since a warm cache can make one run misleading.
Follow-up
- When would you keep the subquery instead of rewriting it as a join?
- The query is fast for one parameter value and slow for another. What is going on?
- How do you confirm the new query returns exactly the same rows as the old one?
Explain why the owner filter ignores the listing index
Medium · composite index · query plans · sort elimination
The only index on resource is (tenant_id, status, updated_at DESC, resource_id DESC). A new endpoint returns one user's resources across all statuses, newest created first: WHERE tenant_id = $1 AND owner_user_id = $2 ORDER BY created_at DESC LIMIT 20. On a tenant with 2M rows it takes 900 ms and EXPLAIN shows a sort above a large scan. Explain precisely why the existing index cannot serve it, give the index that can, and state which of these the new index still will not help: owner_user_id alone across tenants; the same query ordered by updated_at. PostgreSQL 16.
Approach
- Separate the two jobs an index does. For filtering, a composite btree is seekable only on a left prefix, so with no predicate on status the scan can at best range over tenant_id and test owner_user_id per row; PostgreSQL 16 has no btree skip scan to jump the unconstrained column.
- For ordering, the index is sorted by (status, updated_at) within a tenant and not by created_at, so the LIMIT cannot stop early: every matching row is read and then sorted. That is the 'Sort Method: top-N heapsort' line, and it is why the plan reads 2M rows to answer with 20.
- Derive the replacement from the access path — equality, equality, then the ordering column: CREATE INDEX CONCURRENTLY ON resource (tenant_id, owner_user_id, created_at DESC). The scan seeks to the (tenant, owner) range and walks 20 entries in order, so the Sort node disappears along with the row-read.
- Treat INCLUDE (title, status) as conditional, not free. An index-only scan still visits the heap for any row whose page is not marked all-visible, so on a table taking 1.2k writes/second the win depends on autovacuum keeping the visibility map current, and the wider index costs more on every insert.
Follow-up
- 90% of rows are status='active'. Would a partial index WHERE status = 'active' change your answer, and for which of the three queries?
- A dashboard runs this for 40 owners in one page load. What changes about the design?
Explain the purpose and implementation of Validation Controls in ASP.NET.
Medium · Technical and Domain Knowledge
Approach
- Start with the purpose. Web Forms validation controls declare input rules on the page. They run in the browser for quick feedback and then run again on the server. The server run is the one that counts, because client script can be turned off or bypassed with a direct POST.
- Name the controls: RequiredFieldValidator; CompareValidator (compares against another control, a fixed value or a data type using Operator and Type); RangeValidator; RegularExpressionValidator; CustomValidator (a ServerValidate handler that sets args.IsValid, plus an optional ClientValidationFunction); and ValidationSummary, which collects the messages. Key properties are ControlToValidate, ErrorMessage, Display, ValidationGroup and EnableClientScript.
- The implementation details that set an answer apart: in the button handler, call Page.Validate() if needed and check Page.IsValid before saving anything. Set CausesValidation=false on Cancel buttons. Use ValidationGroup when one page holds two independent forms.
- Edge case: by default, every validator except RequiredFieldValidator treats empty input as valid. A CustomValidator with ValidateEmptyText=true is the exception and does run on empty input. When a field is mandatory, pair the RangeValidator or RegularExpressionValidator with a RequiredFieldValidator.
- Put it in context. In ASP.NET MVC and Core, the equivalent is DataAnnotations ([Required], [Range], [RegularExpression]) checked through ModelState.IsValid. UI validation never replaces parameterized queries, business-rule checks in the service layer, or database constraints.
Follow-up
- A user turns off JavaScript and submits the form. What happens, and which line of code stops the bad data?
- How would you check that an end date comes after a start date, on both the client and the server?
- Where else in the stack would you enforce the same rule, and why?
How do you identify and resolve logical errors in a production-ready backend service?
Medium · Technical and Domain Knowledge
Approach
- Start by framing the difference. A logic error throws nothing, so you detect it from wrong output: a user report, a reconciliation mismatch, an alert on a business metric, or a failed invariant check (totals that should match, or states that should never occur together).
- Scope it: which inputs, customers, time window and release are affected. Pull logs by correlation or request id and find the first bad record. If the start time lines up with a deploy, the cause is probably in that diff, and git bisect or a release-by-release comparison will narrow it down.
- Reproduce it with the smallest input that fails, ideally as a failing unit or integration test. Then isolate it by checking intermediate values against the expected ones, cutting the code path in half each time until you find where the value goes wrong.
- Usual suspects to check: off-by-one boundaries (< vs <=), time zones and daylight-saving shifts, float instead of decimal for money, null or default handling, integer division, a stale cache, and race conditions between concurrent requests.
- Keep the failing test as a regression guard when you fix it. Ship the fix behind a flag or with a rollback plan. Repair the data the bug already wrote, using an audit query to find it, and add the monitoring that would have caught the problem sooner.
Follow-up
- It only happens in production and you cannot reproduce it locally. What next?
- How do you find and fix the records the bug has already corrupted?
- What monitoring would have caught this before a user did?
What are the trade-offs between different database indexing strategies?
Medium · Technical and Domain Knowledge
Approach
- Treat every index as a trade. You get faster reads for specific predicates. You pay with slower INSERT, UPDATE and DELETE, more storage, and upkeep (fragmentation, statistics). On a write-heavy table, too many indexes can cost more than they save.
- Clustered vs non-clustered: a table has only one clustered index, which sets the physical row order and suits range scans on its key. Non-clustered indexes are separate structures that may need a lookup back to the table unless they cover the query. A wide or random clustered key, such as a random GUID, causes page splits and makes every non-clustered index bigger.
- In a composite index, column order matters. The index serves predicates on its first columns, so put equality columns first and the range or sort column after them. An index on (customer_id, created_at) serves WHERE customer_id = ? ORDER BY created_at, but does not help a filter on created_at alone.
- Specialised options: covering indexes with INCLUDE columns to avoid lookups; filtered or partial indexes for a small, frequently queried subset (WHERE status = 'open'); hash indexes for pure equality lookups; full-text indexes for word search; and columnstore or bitmap indexes for analytic scans rather than transactional work.
- Selectivity decides whether an index gets used. An index on a low-cardinality column, such as a boolean flag, rarely helps unless it is filtered. Check with the execution plan and index usage statistics, and drop indexes that nothing reads.
Follow-up
- For WHERE a = ? AND b > ? ORDER BY c, which index would you create, and why in that column order?
- The optimizer ignores an index you created. What are the likely reasons?
- How would you decide which indexes to drop on a write-heavy table?
Walk us through the end-to-end workflow of your submitted project.
Medium · Project-Based Assessment
Approach
- Open with the problem and the requirements in a sentence or two. Then show a single architecture diagram: client, web layer (controllers or pages), service layer, data access, database, and any external calls.
- Trace one real request from start to finish: the input, validation on client and server, the business logic, the SQL it runs, how the response is built, and where errors are caught and logged. Following one path is clearer than listing every component.
- For each layer, name the decision you made and the alternative you rejected: why this framework, why this schema and these indexes, why this approach to error handling. Candidates report that explaining the reasons behind choices matters in project discussions.
- Close with how you tested it, what its weakest part is, and what you would change with more time. That way any discussion of refactoring starts from your own list.
Follow-up
- What happens, step by step, when this input is invalid?
- Which part of the project is slowest, and how do you know?
- Why this database design rather than a simpler or more normalised one?
How would you refactor this specific component to improve scalability?
Medium · Project-Based Assessment
Approach
- State the load assumption first (requests per second, data size, growth), or ask for it. Then measure before changing anything: profile the component, run a load test and read the slow-query log to find the real bottleneck.
- Common findings in a backend component, with their fixes: N+1 queries (batch them with a join or a single IN query), unbounded result sets (add pagination), synchronous calls to slow dependencies (use async I/O or a background queue), repeated reads of data that rarely changes (add a cache with a clear invalidation rule), and missing indexes.
- Make the component able to scale horizontally. Remove in-process session state and in-memory caches that assume a single server, move them to a shared store, and make operations idempotent so retries are safe.
- Do the cheapest work first (an index, a query fix, pagination) before structural changes (caching, queues, read replicas). Name the cost of each: caching adds stale data, and queues add eventual consistency and extra failure handling.
- Explain how you would verify the refactor: the same load test before and after, comparing latency percentiles and throughput, plus tests showing the behaviour did not change.
Follow-up
- How do you keep the cache consistent when the underlying row changes?
- What changes when this component runs on two servers instead of one?
- What would you leave unchanged, and why?
What were the primary architectural constraints you faced during the development of this project?
Medium · Project-Based Assessment
Approach
- List the real constraints by type: functional (what it had to do), non-functional (data volume, response time, concurrency) and environmental (a required framework such as ASP.NET, hosting limits, the deadline, the budget, how well you knew a tool).
- For each constraint, name the decision it forced and the option it ruled out. For example: a deadline that pushed you to a monolith instead of separate services, a small dataset that let you skip caching, or a hosting limit that shaped how files are stored.
- State plainly the trade-off you accepted and where it would hurt first: a schema that is simple now but will need a migration, or a synchronous step that will block under higher load.
- Finish with what you would change if a constraint were lifted. That shows your design was a deliberate response to the constraints, not an accident.
Follow-up
- Which constraint shaped the design most, and would you make the same call again?
- If the data volume grew a hundredfold, what would break first?
- Which constraint did you set for yourself, and was it worth it?
One customer endpoint stalls deliveries to every other destination
Medium · bulkhead · timeouts · saturation
The egress service delivers about 1.5k webhooks/second across 40,000 destinations, with a per-destination concurrency cap of 4 and a 10-second connect-plus-read timeout. Throughput falls to 300/second, queue depth climbs, and p99 delivery latency for unaffected destinations goes from 200 ms to minutes, while the error rate barely moves. One tenant holds 900 destination rows whose URLs share a hostname that now answers in 9.5 seconds. Explain the mechanism with the arithmetic, then give the containment in the order you would apply it.
Approach
- Look at saturation before errors. A flat error rate with collapsing throughput says nothing is failing, things are waiting, so the first signal to pull is in-flight request count or pool wait time rather than the error counter. This is the distinction that decides the whole investigation.
- Group in-flight work by resolved host, not by destination id. The cap is keyed per destination row, so 900 rows sharing one hostname buy 3,600 concurrent slots against a single host, each held for 9.5 seconds. The bulkhead was never a bulkhead for that host, and grouping by the wrong dimension is why the dashboard looked healthy.
- Do the arithmetic in both directions. Required concurrency is arrival rate times latency, so 1.5k/second at 200 ms needs about 300 in flight, which is entirely consumed by 3,600 slow slots; conversely whatever concurrency is left sustains rate equals concurrency divided by 9.5 seconds, which is the 300/second you are seeing. Matching both numbers is what promotes this from a plausible story to the mechanism.
- Explain why the circuit breaker never helped. It opens on consecutive failures, and a 9.5-second response inside a 10-second timeout is a success. Slow is not failing, so an error-rate breaker cannot see this; you need a slow-call ratio, a deadline propagated from the caller's remaining budget, or a concurrency limiter.
Follow-up
- The host recovers to 80 ms. How long does the queue take to drain, and what does the drain do to the recovered host?
- Where should the 10-second timeout number actually come from?
Suggested practice checklist
Each day covers one reported stage or question group and ends with something you can reuse: a query rewrite, a debugging write-up, a project decision log or a set of stories.
Day 1 — Screening pitch and resume audit
- List every technology on your resume and next to each, a project where you used it that you can defend in depth. Cut anything you cannot.
- Write a short pitch for why you over other candidates, with one piece of evidence each for backend framework work, SQL and debugging.
- Write a five-year answer that ties deeper backend and database skill to this role, plus one thing you are doing now to get there.
- Write the questions for the recruiter: how the aptitude stage and project work, how long you get for the project, and the remote policy.
Deliverable: A resume audit sheet, a written 'why you' pitch, a five-year answer and a list of questions for the recruiter.
Day 2 — Nested SQL tuning and index trade-offs
- On a sample orders and customers schema, write a query with correlated scalar subqueries, capture its plan, then rewrite it as a LEFT JOIN to a pre-aggregated derived table, using COALESCE for counts. Add a second query with a correlated IN filter in WHERE and rewrite it with EXISTS. Compare plans and logical reads, and check each rewrite with EXCEPT in both directions plus row counts.
- Show the NOT IN trap: add one NULL to the subquery column, watch the result go empty, and fix it with NOT EXISTS.
- Build a table comparing clustered, composite, covering, filtered, hash and full-text indexes, covering read benefit, write cost and when each one fails.
- Work through the practice question on why an owner filter ignores the listing index, and explain the column-order reason out loud.
Deliverable: Before-and-after execution plans for the rewritten queries, a NOT IN demonstration, an index trade-off table and a written answer to the index practice question.
Day 3 — Logic errors in a running backend
- Write your debugging sequence as numbered steps, from detection and scoping through to data repair and new monitoring.
- Plant three logic bugs in a small service (an off-by-one boundary, a time-zone shift, float money rounding) and find each one by following the sequence, not by memory.
- Work through the practice question where one customer endpoint stalls deliveries to every other destination, saying each hypothesis and check out loud.
- Write a STAR story about debugging a critical issue in something you built, with the root cause in one sentence.
Deliverable: A written debugging sequence, three found-and-fixed planted bugs with regression tests, a spoken run-through of the stalled-delivery practice question, and one debugging STAR story.
Day 4 — ASP.NET validation and backend correctness
- Build a Web Forms page using RequiredFieldValidator, RangeValidator, RegularExpressionValidator, CompareValidator, a CustomValidator with a ServerValidate handler, and a ValidationSummary.
- Turn off JavaScript, submit bad input, and confirm the handler refuses to save because it checks Page.IsValid. Add a Cancel button with CausesValidation=false.
- Rebuild the same form in MVC or ASP.NET Core with DataAnnotations and ModelState.IsValid, and write the save with a parameterized query.
- Say out loud, as a single explanation, why validation also belongs in the service layer and in database constraints.
Deliverable: Two working validated forms (Web Forms and MVC or Core), proof that the server-side check blocks bad input without JavaScript, and a spoken explanation of validation across layers.
Day 5 — Aptitude sets and timed coding drills
- Candidates do not describe the aptitude format, so do two timed sets across the usual problem types: number and letter series, data interpretation tables, syllogisms, seating and arrangement puzzles, percentages and time-work. Aim for 20 questions in 20 minutes per set and log every miss by type.
- Redo your missed aptitude problems while explaining your reasoning aloud, so the same method works in a spoken or group format.
- Coding drill: solve the practice question on tracking a rolling failure rate per destination, stating the time and space complexity.
- Coding drill: solve the practice question on collapsing a redelivered event batch into per-aggregate high-water marks, and list the edge cases before you write any code.
Deliverable: An error log grouped by problem type from two timed aptitude sets, plus two solved coding practice problems with their complexity and edge cases written down.
Day 6 — Build to defend: walkthrough, constraints, refactor
- Take your strongest recent project, or a small ASP.NET and SQL app, and draw one request's path from input through validation, service, SQL and back.
- Write the list of constraints, each with the decision it forced and the alternative it ruled out.
- Pick one component and write a scalability refactor plan: the measurement first, cheap fixes before structural ones, and the cost of each change.
- Rehearse the defense out loud with a friend who keeps asking 'why this and not that', and note every question you could not answer.
Deliverable: A request-trace diagram, a constraint-to-decision list, a refactor plan with before-and-after measurements, and a list of defense gaps to close.
Day 7 — Leadership conversations and group discussion
- Write STAR stories for working with a non-technical stakeholder to clear a bottleneck and for handling code-review feedback, each with a measurable result.
- Say the 'why you' and five-year answers aloud again, and cut every adjective that has no evidence behind it.
- Explain your project's main trade-off to someone without a backend background, and revise it until they can repeat it back.
- Run a mock group discussion, or record yourself in one, practising restating another person's point before adding your own.
Deliverable: Two finished STAR stories, tightened 'why you' and five-year answers, a plain-language explanation of the project trade-off, and notes from a mock group discussion.
Behavioural preparation
Candidates report that the process ends with leadership conversations about fit and alignment. The reported behavioral questions cover why you over other candidates, your five-year direction, working with non-technical stakeholders, code-review feedback and debugging something you built yourself. Candidates suggest the STAR structure. Build each answer around a decision you personally made and a result you can put a number on, and be ready to explain the technical parts in plain language.
Describe a time you had to debug a critical issue in a project you built from scratch.
Medium · Project-Based Assessment
Approach
- Pick a bug with real stakes in code you wrote yourself, such as data loss, wrong totals or a crash under load. A typo you found in five minutes will not carry the story.
- Cover the situation and impact briefly: what broke, who noticed and what it affected. Spend most of the answer on the investigation: your hypotheses, the evidence that ruled each one out (logs, a reproduction, a failing test, bisecting commits) and the moment the cause became clear.
- State the root cause in one precise sentence, for example a time-zone conversion applied twice to records saved after midnight UTC. Then describe the fix and the regression test you added.
- End with what changed in how you build: a validation rule, a logging pattern, or a test you now write by default. You built the project from scratch, so own the original mistake plainly. Blaming a library or a deadline sinks the story.
Follow-up
- What did you try first that turned out to be wrong?
- How did you confirm the fix worked and nothing else broke?
- What would have caught this before it reached users?
Convince me why I should hire you over other qualified candidates.
Medium · Behavioral and Strategic Alignment
Approach
- Give two or three reasons that map to what candidates report the role needs: work in a backend framework (ASP.NET is named), advanced SQL, debugging, and communicating with non-technical stakeholders.
- Back each reason with one piece of evidence: a query you took from seconds to milliseconds, a production bug you traced and fixed, a feature you shipped and then maintained. Numbers and outcomes beat adjectives.
- Add one strength that is genuinely yours, such as domain knowledge, a record of mentoring, or a habit like writing a regression test for every bug, and connect it to the work in this role.
- Keep it short. Do not criticise other candidates. Finish with why this role in particular, not a generic wish to grow.
Follow-up
- What is the weakest part of your profile for this role?
- Give one example that proves the first reason you gave.
- Why this role and not a similar backend job somewhere else?
Where do you see yourself in the next 5 years, and how does this role fit that vision?
Medium · Behavioral and Strategic Alignment
Approach
- Describe a believable direction rather than a job title. For example: deeper backend and database expertise first, then owning the design of a service or mentoring other engineers. Ambition is fine; a plan unrelated to backend engineering is not.
- Tie the role to that path concretely. The SQL performance, debugging and project-ownership themes candidates report for this role should be the skills you name as next steps.
- Mention what you are already doing to move that way, such as a course, a side project or a specific area you are working on, so the answer has evidence behind it.
- Be honest, but do not present the role as a stopover on the way to something unrelated.
Follow-up
- On that path, which skill is your weakest today?
- What would make you leave a role like this one?
- A year from now, how will you know you are on track?
Describe a situation where you had to collaborate with a non-technical stakeholder to resolve a project bottle
Medium · Behavioral and Strategic Alignment
Describe a situation where you had to collaborate with a non-technical stakeholder to resolve a project bottleneck.
Approach
- Choose a real bottleneck involving a non-technical counterpart, such as a product manager, an operations lead or a client contact whose request, data or decision held up delivery.
- Cover the situation and task briefly, then focus on your actions: how you found out what they actually needed, how you translated the technical constraint into their terms (cost, time, risk to customers), and which options you gave them, with the trade-offs of each.
- Show the decision and your part in it, then a measurable result: the deadline recovered, the scope trimmed, the manual work removed.
- What sinks this answer: jargon in the retelling, casting the stakeholder as the problem, or a story where someone else resolved it. Close with what you now do earlier so the same bottleneck does not happen again.
Follow-up
- How did you explain the technical constraint without jargon?
- What if they had rejected every option you offered?
- What would you do differently from the start?
How do you handle feedback on your code during a peer review?
Medium · Behavioral and Strategic Alignment
Approach
- Give a concrete example, not a philosophy. Pick one review comment that changed your code, ideally one that taught you something: a missing index, unvalidated input, an unclear name.
- Describe your process. Read the comment as being about the code, not about you. Ask a clarifying question if the intent is unclear. Either make the change, or reply with evidence (a benchmark, a test, a reference) if you disagree, and settle it without letting it drag on.
- Include one case where you pushed back and say how it ended, whether you were convinced or you convinced the reviewer. That shows you weigh feedback instead of accepting or rejecting it by reflex.
- Close with a habit it changed, such as a checklist you now run before opening a pull request. Claiming you rarely get feedback, or that you always agree with it, weakens the answer.
Follow-up
- Tell me about feedback you disagreed with. What happened?
- How do you give feedback on someone else's code?
- What review comment do you now see most often on your code?