cswork / libraryOpen practice workspace

Interview guides · Avalara

Avalara Software Engineer Interview Guide

Avalara Software Engineer interview prep: reported rounds, approaches to coding, REST API, OOP, SQL and behavioral questions, and a 7-day plan.

The 60-second brief

Avalara sells cloud software that automates transaction-tax compliance: calculating tax on a sale in real time, working out rates across many jurisdictions, tracking exemption certificates, managing tax documents and preparing regulatory filings. In the role descriptions candidates cite, Software Engineers build backend microservices and some serverless components in C#/.NET Core, Java or Node.js. They implement tax-rule validation, rate calculation and multi-jurisdiction reporting logic, build and consume REST APIs and event-driven pipelines that connect to ERP, e-commerce and point-of-sale systems, and write SQL and NoSQL queries against high-volume ledger data. That work explains the shape of the reported questions. Tax amounts have to be exact, so money handling, database transactions and failure handling between services come up alongside the algorithm problems.

This guide is for engineers preparing for an Avalara Software Engineer loop, usually from a backend background in C#, Java, Node.js/TypeScript, Python or C++. It covers the three reported rounds and the 25 reported questions in five groups: data structures and algorithms, REST API integration and concurrency, object-oriented design and runtime internals, database and SQL engineering, and behavioral and project-architecture questions. Each question has an approach and likely follow-ups. Tax, fintech and ERP experience appear as nice-to-haves rather than requirements, so the guide uses tax examples to give design answers context and does not treat the tax domain as a separate subject to study.

Candidates report three rounds (Phone Screen, Technical Interviews, HR Round) over roughly 3-5 weeks. Some accounts add an online coding assessment after the recruiter screen, and the sequence varies by hiring region.

Focus areas

  • Data Structures & Algorithms (DSA)
  • System Design
  • Automation & Compliance Systems (Tax Domain)

Overview

The reported questions fall into five groups that mirror the job: hash-map, tree, stack and sliding-window problems; code that calls paginated REST endpoints and copes with timeouts and rate limits; object-oriented questions on interfaces, dependency injection and polymorphism; SQL joins, indexing, isolation levels and slow-query diagnosis; and behavioral questions anchored in past projects. None of the coding problems is obscure, so the details are what separate answers. Typical slips are reusing the same element in two-sum, popping the min stack wrongly when the minimum value is duplicated, or writing a LEFT JOIN that turns into an INNER JOIN because the filter sits in the WHERE clause.

Give the REST and concurrency group more time than a generic loop would get. Candidates report online assessments that pair array and string problems with REST API invocation tasks, and their tips stress writing an HTTP client from scratch: sending GET and POST requests, branching on status codes, parsing JSON and totalling the results. Practise this in your own language until you no longer need to look up the client API. Then add retries with backoff, a cap on concurrent calls and decimal arithmetic for money amounts.

The database group goes deepest. Candidates report live SQL with several joins, aggregations and subqueries, along with questions on how indexes work and what they cost writes, relational versus document stores, transaction isolation and deadlocks. The databases named for the role are PostgreSQL, SQL Server and MySQL. Pick the one you know best and learn to read its execution plans, because the answer to the slow-query question is an execution plan, not a list of tips.

Your stack affects the language-internals questions. The role descriptions name C#/.NET Core, Java and Node.js, and the garbage-collection question asks you to compare .NET, the JVM and V8. Candidates advise confirming the team's stack with the recruiter early. Once you know it, learn its DI container, exception middleware and logging library by name, because the dependency-injection, exception-handling and logging questions are easiest to answer with real framework hooks.

The Avalara interview process

These are the three stages candidates report. Some also describe an online assessment between the recruiter screen and the technical interviews, and loops differ between hiring regions (the United States, India and Latin America).

Phone Screen

Candidates describe the Phone Screen as a first call about your background and fit for the role. Accounts of this recruiter conversation mention a resume review, compensation expectations, notice period where relevant, and the stack you use today. Some candidates then report an automated stage before the technical interviews: a HackerRank coding challenge with array or string problems and a task that calls a REST API. In some regions and hiring tracks it also includes timed multiple-choice questions on CPU scheduling, memory management in operating systems, quantitative reasoning and short C or Java snippets. Use the call to find out which backend stack the team runs, so the rest of your preparation targets it.

What to demonstrate

  • Your background and fit for the role, as candidates describe the call
  • How well your current stack matches the team's (C#/.NET Core, Java or Node.js)
  • Logistics: compensation expectations and notice period

How to prepare

  • Ask the recruiter which backend stack and database the team uses and whether an online assessment follows. Then aim your remaining days at that stack.
  • Prepare a short spoken summary of one backend project that involved REST APIs and a relational database, since both appear throughout the reported questions.
  • If an assessment is confirmed, practise timed array and string problems (two-sum with a hash map, word counts, sliding windows) plus one script that calls a paginated JSON API. Practise moving on from any problem that stalls you.
  • Settle your notice period and compensation expectations before the call.

Technical Interviews

Candidates describe Technical Interviews as one or more sessions on technical skill and problem solving. Accounts mention live coding and architecture conversations, some with senior engineers and solution architects, covering object-oriented programming, deep dives into projects on your resume, database query optimisation and RESTful service design. Candidates also report direct follow-up questions on resume claims and architectural trade-offs. The reported coding, API, OOP and SQL questions in this guide are what to practise for this stage. Explain your approach and its complexity before you write code. Use your strongest language unless the team's stack is required, and test your code aloud against the edge cases you named.

What to demonstrate

  • Working code for data-structure and algorithm problems, with the complexity stated
  • Object-oriented programming concepts and how you apply them in design
  • Database work: SQL queries, indexing and query optimisation
  • RESTful service design and how deeply you know your own past projects

How to prepare

  • Write two-sum, the min stack, level-order traversal and a sliding-window anagram search from memory in your interview language, and say each one's time and space complexity aloud.
  • Write a function that pages through a JSON API, totals amounts per region with a decimal type, and retries 429 and 503 responses with exponential backoff.
  • Write the customer-filings join query against a three-table schema you define, then pull its execution plan in PostgreSQL or SQL Server and explain each node.
  • Choose one resume project and prepare its architecture, two trade-offs and one thing you would change, in enough detail to survive several follow-up questions.

HR Round

Candidates describe the HR Round as the final interview, focused on behavioral questions and cultural fit. Some accounts describe the closing conversation as a hiring-manager round on leadership scenarios, the impact of past projects and fit with the team. Bring stories, not adjectives. Each story should name the decision you made, the alternative you turned down and a result you can measure. Candidates also advise agreeing offer details, the team's stack and notice-period terms with the recruiter before signing, because some report internal team reassignments.

What to demonstrate

  • Behavioral answers about conflict, ambiguity, production incidents and refactoring
  • Cultural fit and alignment with the team
  • Impact and ownership in past projects

How to prepare

  • Write STAR outlines for the five reported behavioral prompts: the resume project, the production incident, the disagreement with a senior engineer, the ambiguous user story and the legacy refactor.
  • Attach one number to each story (latency, error rate, defect count, delivery date) and be ready to explain how you measured it.
  • List your questions about the team's stack and roadmap, and the offer terms you need in writing before you accept.

Where candidates lose points

Totalling transaction or tax amounts with float or double in the REST aggregation or the SQL answers

Use decimal in C#, BigDecimal in Java, a decimal library or integer minor units in JavaScript, and NUMERIC/DECIMAL columns in SQL. Say out loud where rounding happens (line or invoice) and which rounding mode applies. Practise the paginated-API problem with mixed amounts and check the totals to the cent.

Writing a LEFT JOIN whose WHERE filter silently turns it into an inner join, or summing after a one-to-many join fans out

Put conditions on the optional table in the ON clause, count a column from that table instead of COUNT(*), and pre-aggregate each one-to-many table in a CTE before joining. Check every join query you write against a customer with no filings and a filing with two payments.

Answering the timeout and failure-handling question with 'retry three times' and no word on idempotency

Separate retryable from non-retryable errors, add exponential backoff with jitter and Retry-After handling, and explain how an idempotency key keeps a timed-out POST from recording a transaction twice. Name the resilience library for your stack (Polly, Resilience4j) and what a circuit breaker adds.

Putting projects or technologies on your resume that you cannot defend in depth

Candidates report deep-dive follow-ups on resume claims and architectural trade-offs. For every line you might be asked about, prepare the architecture, your own decisions, one alternative you rejected and a number you can explain. Cut anything you cannot discuss at code level.

Preparing in one stack when the team works in another, or sinking too long into one problem in a timed assessment

Ask the recruiter early whether the team runs .NET Core, Java or Node.js and whether an online assessment follows, then learn that runtime's GC, DI container and exception middleware. In timed tests, set a per-question limit, submit a working brute force, and move on before polishing.

Questions & practice

Given an unsorted array that may contain duplicates, find two numbers that sum up to a target value and explai

Medium · Data Structures & Algorithms

Given an unsorted array that may contain duplicates, find two numbers that sum up to a target value and explain the time complexity of your approach.

Approach

  1. Make one pass with a hash map from value to index. For each element x, check whether target - x is already in the map before inserting x. That order stops an element pairing with itself and still handles duplicates: [3, 3] with target 6 finds the earlier 3.
  2. State the cost: O(n) time and O(n) extra space. The brute-force double loop is O(n^2).
  3. Mention the alternative: sort, then move two pointers inward from both ends, in O(n log n) time. Sorting loses the original indices unless you sort (value, index) pairs, so prefer it only when the question asks for values or memory is tight.
  4. Ask about the return contract up front: the first pair, any pair or all distinct pairs. Also cover no pair (return an empty result or -1, not an exception unless agreed), negative numbers, and integer overflow of target - x in C# or Java.

Follow-up

  • How would you return every unique pair of values without reporting the same pair twice?
  • What changes if the array is already sorted, or arrives as a stream you can read only once?
  • How would you extend this to three numbers that sum to the target, and what is the complexity?

Write an algorithm to count the frequency of words in an input string array and output the sorted word frequen

Medium · Data Structures & Algorithms

Write an algorithm to count the frequency of words in an input string array and output the sorted word frequency list.

Approach

  1. Agree on normalisation first: whether matching ignores case, whether punctuation is stripped, and how a string is split into words. Most bugs in this question come from tokenising.
  2. Count with a hash map (Dictionary<string,int>, HashMap, Map) in O(N) over all words. Then sort the U distinct entries by count descending, breaking ties alphabetically so the output is deterministic, in O(U log U).
  3. If only the top k are wanted, use a min-heap of size k for O(U log k), or bucket counts by frequency for O(N). Name the idiomatic version as well: LINQ GroupBy/OrderByDescending/ThenBy, or Java's groupingBy with counting().
  4. Edge cases: an empty array, empty or whitespace-only strings, words that differ only by case, and non-ASCII text.

Follow-up

  • How would you keep the top five most frequent categories current while order events stream in?
  • What if the word list is too large for one machine's memory?
  • Why does the tie-break order matter if the result is consumed by a test or another service?

Given a binary tree structure, write a function to perform a level-order traversal and calculate the maximum d

Medium · Data Structures & Algorithms

Given a binary tree structure, write a function to perform a level-order traversal and calculate the maximum depth.

Approach

  1. For level order, run breadth-first search with a queue. At the start of each level, record the queue size and dequeue exactly that many nodes into the current level's list while enqueueing their children.
  2. Maximum depth is then the number of levels processed. Recursively it is 1 + max(depth(left), depth(right)), with an empty subtree counting as 0.
  3. Complexity: O(n) time for both. BFS uses O(w) space, where w is the widest level. Recursive DFS uses O(h) stack, and on a skewed tree h = n can overflow the call stack, which is a reason to give the iterative version.
  4. Edge cases: a null root (empty list, depth 0), a single node, and a tree that is a linked list in disguise.

Follow-up

  • How would you return the levels in zigzag order?
  • How would you find the minimum depth, and why can BFS stop early there?
  • How would you return the rightmost node at each level?

Implement a custom stack data structure that supports pushing, popping, and retrieving the minimum element in

Medium · Data Structures & Algorithms

Implement a custom stack data structure that supports pushing, popping, and retrieving the minimum element in constant time.

Approach

  1. Keep two stacks: the main stack and a min stack. When pushing x, also push it onto the min stack if the min stack is empty or x <= its top. When popping, pop the min stack too if the popped value equals its top.
  2. Use <= rather than <. With strict less-than, pushing the same minimum twice and popping once would lose the minimum.
  3. An equivalent design stores (value, minSoFar) pairs on a single stack. It is simpler to get right and costs an extra field per element. Every operation is O(1) time, and extra space is O(n) in the worst case.
  4. Decide what pop, top and getMin do on an empty stack: throw InvalidOperationException or EmptyStackException, or return an optional. Say which and keep it consistent.

Follow-up

  • How would you also support popMax, and why does that stop being O(1)?
  • Can you get O(1) extra space by encoding the difference from the current minimum, and what overflow risk does that add?
  • What would you change to make this stack safe for concurrent callers?

Solve a string manipulation problem requiring character frequency matching and sliding window optimization und

Medium · Data Structures & Algorithms

Solve a string manipulation problem requiring character frequency matching and sliding window optimization under time constraints.

Approach

  1. Name the pattern first. A fixed-size window fits find-all-anagrams or permutation-in-string. A variable window fits minimum-window-substring or longest-substring-with-constraint. Ask which one is meant.
  2. For a fixed window, keep a count array (26 entries for lowercase ASCII, otherwise a hash map) for the pattern and for the window, plus a counter of characters whose counts match. Sliding right adds one character and removes one, adjusting the counter in O(1), so the whole scan is O(n).
  3. For a variable window, extend the right pointer until the window satisfies the requirement (formed == required), then shrink from the left while it still does, recording the best window. Each pointer moves at most n times, so it is O(|s| + |t|) even though the loops are nested.
  4. Edge cases: the pattern longer than the text, empty strings, case sensitivity, characters outside the 26-letter alphabet, and repeated characters in the pattern.

Follow-up

  • How would you find the longest substring with at most k distinct characters?
  • Why is the nested-loop version still linear time?
  • What changes if the input is Unicode text rather than lowercase ASCII?

Implement a thread-safe worker queue or callback-based mechanism that maintains a fixed limit of concurrent ou

Medium · API Integration & Systems Logic

Implement a thread-safe worker queue or callback-based mechanism that maintains a fixed limit of concurrent outgoing REST calls.

Approach

  1. Use a counting semaphore sized to the limit: SemaphoreSlim with WaitAsync and Release in a finally block in C#, java.util.concurrent.Semaphore or a fixed ExecutorService in Java. In Node, keep an active counter and a queue of pending tasks, and start the next task when one settles.
  2. Alternatively, use N workers reading from a bounded queue (Channel<T>, BlockingQueue). A bounded queue also blocks producers when it is full, which gives you backpressure.
  3. Release the permit in finally, or a failing request leaks it and the pool slowly deadlocks. Give each call a timeout so a hung request cannot hold a slot forever.
  4. Choose an error policy (fail fast and cancel the rest, or collect per-item results) and a result order. Write results into an array by input index when order matters.
  5. Watch the shared state: the counter and queue need a lock or atomic operations in multithreaded runtimes. Never block a pool thread waiting on work queued to the same pool.

Follow-up

  • How would you add a per-host limit on top of the global one?
  • How would you lower the concurrency automatically when the API starts returning 429?
  • How do you test that the limit is never exceeded?

Explain how garbage collection and memory management function in your primary language stack (.NET Runtime vs.

Medium · Core Frameworks & Object-Oriented Progra

Explain how garbage collection and memory management function in your primary language stack (.NET Runtime vs. Java JVM vs. V8 engine).

Approach

  1. Start with the shared idea. All three runtimes use tracing, generational collectors built on the observation that most objects die young, so young objects are collected often and cheaply and survivors are promoted.
  2. .NET has generations 0, 1 and 2, plus a Large Object Heap for objects of 85,000 bytes or more that is collected with gen 2. It offers workstation and server GC modes and background GC. IDisposable/using handles unmanaged resources deterministically, and finalizers delay collection.
  3. The JVM splits the heap into young (eden plus survivor spaces) and old generations. G1 is the default collector since Java 9, and ZGC and Shenandoah target low pause times. Heap size is set with -Xms/-Xmx. V8 uses a semi-space scavenger for the young generation and incremental, concurrent mark-sweep-compact for the old generation, and Node's limit is set with --max-old-space-size.
  4. Managed languages still leak through references you keep alive: static collections, event handlers never unsubscribed, unbounded caches, closures capturing large objects. Diagnose with dotnet-counters/dotnet-dump, jmap heap dumps in Eclipse MAT, or Chrome DevTools heap snapshots by comparing two snapshots.

Follow-up

  • Memory climbs steadily in production. How do you find the leak?
  • How would you reduce GC pressure on a hot request path?
  • Why are finalizers discouraged?

Explain database transactions, isolation levels, and how to prevent deadlock conditions in high-concurrency en

Medium · Database & SQL Engineering

Explain database transactions, isolation levels, and how to prevent deadlock conditions in high-concurrency environments.

Approach

  1. A transaction is atomic, consistent, isolated and durable. Isolation levels trade anomalies for concurrency. Read uncommitted allows dirty reads. Read committed, the default in PostgreSQL and SQL Server, allows non-repeatable reads. Repeatable read blocks those but the standard allows phantoms (PostgreSQL's snapshot-based version also blocks phantoms). Serializable prevents all of them.
  2. Contrast MVCC snapshots with lock-based isolation (SQL Server's READ_COMMITTED_SNAPSHOT option), and name the lost-update problem. The fixes are SELECT ... FOR UPDATE (pessimistic) or a version/rowversion column checked on update (optimistic).
  3. A deadlock is a cycle of transactions each waiting on a lock another holds. The database detects it and aborts a victim (SQL Server error 1205, PostgreSQL SQLSTATE 40P01).
  4. Prevent deadlocks by locking rows and tables in a consistent order, keeping transactions short, making no network or user calls inside a transaction, and indexing so fewer rows are locked. Because deadlocks cannot be ruled out entirely, retry the aborted transaction with backoff.

Follow-up

  • Two requests update the same account balance at once. Walk through what happens at read committed.
  • When is serializable worth its cost?
  • Optimistic or pessimistic locking for a high-contention row: which and why?

How do you approach gathering requirements and estimating technical work when facing an ambiguous user story o

Medium · Behavioral & Past Project Architecture

How do you approach gathering requirements and estimating technical work when facing an ambiguous user story or feature spec?

Approach

  1. Start with the user and the outcome. Then list the open questions and turn them into acceptance criteria with concrete examples, including edge cases such as an exempt customer, a rate change mid-period or rounding at line versus invoice level.
  2. Resolve unknowns with the product manager, and run a short spike on any technical risk, such as an unfamiliar API, before committing to an estimate.
  3. Break the work into small tasks and estimate as a range or in story points, stating your assumptions and risks. Give a confidence level instead of a single date.
  4. Deliver a thin end-to-end slice first to test the assumptions, and re-estimate visibly when new information arrives. Use a real example from your work rather than describing a process in the abstract.

Follow-up

  • The stakeholder insists on a fixed date. What do you do?
  • Tell me about an estimate that was badly wrong and what you changed afterwards.
  • How do you split a story too big for one sprint?

Write a SQL query using complex INNER and LEFT JOINs to retrieve aggregated customer tax filings across multip

Medium · Database & SQL Engineering

Write a SQL query using complex INNER and LEFT JOINs to retrieve aggregated customer tax filings across multiple state jurisdictions.

Approach

  1. Define the schema aloud, for example customers(customer_id, name), filings(filing_id, customer_id, jurisdiction_id, period_end, tax_amount, status) and jurisdictions(jurisdiction_id, state_code). Then agree the output grain: one row per customer per state.
  2. Shape: SELECT c.customer_id, j.state_code, COUNT(f.filing_id) AS filings, COALESCE(SUM(f.tax_amount), 0) AS total_tax FROM customers c LEFT JOIN filings f ON f.customer_id = c.customer_id AND f.status = 'FILED' LEFT JOIN jurisdictions j ON j.jurisdiction_id = f.jurisdiction_id GROUP BY c.customer_id, j.state_code.
  3. Put conditions on the optional table in the ON clause. A WHERE filter on f.status discards the NULL rows and turns the LEFT JOIN into an inner join. Use COUNT(f.filing_id), not COUNT(*), so customers with no filings show 0.
  4. Watch for fan-out. Joining two one-to-many tables (filings and payments) before grouping multiplies the sums, so pre-aggregate each in a CTE and join the totals. Support the query with an index on filings(customer_id, jurisdiction_id) or one that matches the filter.

Follow-up

  • List customers with no filing in a given state.
  • Rank each customer's states by total tax with a window function.
  • The query is now slow on 50 million filings. What do you check first?

Compare relational databases (such as PostgreSQL or SQL Server) with NoSQL document stores in terms of ACID co

Medium · Database & SQL Engineering

Compare relational databases (such as PostgreSQL or SQL Server) with NoSQL document stores in terms of ACID compliance, scaling, and schema flexibility.

Approach

  1. Relational databases (PostgreSQL, SQL Server, MySQL) give multi-row ACID transactions, joins, foreign keys and constraints over a normalised schema. They scale up and out with read replicas and partitioning, and sharding is possible but costly.
  2. Document stores (MongoDB, Cosmos DB, DynamoDB) store each aggregate as one document with a flexible schema and scale horizontally by partition key. Atomicity is natural within a single document. Multi-document transactions exist in some (MongoDB since 4.0) but cost more, and denormalised copies can drift apart.
  3. Schema flexibility moves validation into the application (schema-on-read), which makes data quality your job. Partition-key choice decides whether queries hit one partition or scatter to all.
  4. Apply it to the domain: money, ledgers and filings that need an audit trail favour relational transactions and constraints, while heterogeneous inbound payloads or per-jurisdiction configuration may fit documents. PostgreSQL JSONB is the middle option.

Follow-up

  • How would you choose a partition key for a document store of transactions?
  • Could you build a ledger on a document store, and what would you add?
  • When is JSONB in PostgreSQL the better answer?

Write a program to invoke a multi-endpoint REST API, parse the paginated JSON response, and aggregate transact

Medium · API Integration & Systems Logic

Write a program to invoke a multi-endpoint REST API, parse the paginated JSON response, and aggregate transaction totals across different geographic regions.

Approach

  1. Structure the code as fetch, parse, validate, aggregate. Use one HTTP client instance (HttpClient, java.net.http.HttpClient, fetch/axios) and deserialise into typed objects rather than walking raw JSON.
  2. Follow the API's pagination contract. With a cursor or next link, loop until it is null. With page/offset, stop on an empty page or when you reach the reported total. Offset pagination over changing data can repeat or skip rows, so deduplicate by transaction id.
  3. For multiple endpoints, such as transactions plus a region or location lookup, fetch the lookup once and keep it in a dictionary keyed by id. Do not call it per transaction.
  4. Total into a map keyed by region using decimal or BigDecimal, never float or double. Validate each line item (missing region, negative or null amount, currency mismatch), and count and log rejected items instead of crashing.
  5. Check the status code before parsing. Retry 429 (honouring Retry-After) and 5xx with backoff, and treat 4xx as a bug or bad input. If the pages are known up front, fetch them in parallel with a concurrency cap.

Follow-up

  • What if the result set is millions of records: how do you keep memory flat?
  • The job fails on page 40 of 100. How do you resume without double counting?
  • How would you unit-test this without calling the real API?

Design a validation service that ingests tax rule data via REST endpoints and performs real-time schema valida

Medium · API Integration & Systems Logic

Design a validation service that ingests tax rule data via REST endpoints and performs real-time schema validation and exception logging.

Approach

  1. Clarify the inputs: who submits rule data, how often, batch or single rule, and whether the caller needs an immediate verdict. Small payloads get synchronous validation. Large batches return 202 with a job id.
  2. Validate in two layers. Structural validation checks the payload against a versioned JSON Schema, compiled once and cached. Semantic validation checks the rules themselves: jurisdiction codes exist, rates fall in a sane range, effective-date ranges for the same jurisdiction and product do not overlap.
  3. Return machine-readable errors listing field path, error code and message for every failure, not just the first. Decide whether a batch is all-or-nothing or partially accepted, and document it.
  4. Components: an authenticated API layer, a stateless validator that scales horizontally, a store for rules with version and effective_from/effective_to columns so history is auditable, and a queue plus dead-letter queue for async batches.
  5. For exception logging, emit structured logs with correlation id, submitter, schema version and error codes, with metrics and alerts on the rejection rate. Store rejected payloads by reference with a retention policy instead of dumping them into logs.

Follow-up

  • How do you change the schema without breaking submitters on the old version?
  • A submitter retries the same batch. How do you avoid storing the rules twice?
  • Validation latency grows with batch size. Where do you look first?

Explain the key differences between synchronous REST APIs and asynchronous event-driven messaging patterns whe

Medium · API Integration & Systems Logic

Explain the key differences between synchronous REST APIs and asynchronous event-driven messaging patterns when processing transactional tax data.

Approach

  1. Synchronous REST is request/response. The caller waits, gets the result or error right away, and both services must be up at the same moment. That suits a tax calculation a checkout needs before it can continue.
  2. Event-driven messaging puts a broker (Kafka, RabbitMQ, SQS/SNS) between producer and consumers. That decouples availability, absorbs bursts and lets several consumers react to one event, at the cost of eventual consistency and harder tracing. It suits filing, reporting and audit pipelines that run after the sale.
  3. Delivery is usually at-least-once, so consumers must be idempotent: deduplicate on an event id or use upserts. Ordering holds only within a partition, so key events by something like the transaction or account id. Send poison messages to a dead-letter queue.
  4. Updating the database and publishing an event are two writes that can disagree. The transactional outbox pattern writes the event row in the same database transaction and publishes it from there.

Follow-up

  • Can you get exactly-once processing, and what does that cost?
  • How does a consumer cope with an adjustment event that arrives before the original transaction?
  • How would you trace one transaction through three asynchronous consumers?

Explain the difference between an abstract class and an interface, providing a scenario where you would choose

Medium · Core Frameworks & Object-Oriented Progra

Explain the difference between an abstract class and an interface, providing a scenario where you would choose one over the other in enterprise applications.

Approach

  1. An interface is a contract with no instance state. A class can implement many, and it is the natural seam for dependency injection and mocking. An abstract class can hold fields, constructors and shared implementation, and a class can extend only one.
  2. Since Java 8 and C# 8, interfaces can carry default method bodies. That blurs the line, but they still hold no instance state, so shared state remains the deciding difference.
  3. Choose an interface for a capability many unrelated types provide, such as ITaxCalculator or IExportFormat. Choose an abstract class for a template method where subclasses share most of the algorithm, such as a base report exporter that fixes header, footer and audit and leaves the body abstract.
  4. A common combination is an interface for consumers plus an optional abstract base that implements it for convenience. Adding a member to a published interface breaks every implementer unless it has a default.

Follow-up

  • When does an abstract base class become a liability?
  • How do default interface methods change your answer?
  • How would composition replace the inheritance in your example?

What is loose coupling, and how do dependency injection and inversion of control promote maintainable software

Medium · Core Frameworks & Object-Oriented Progra

What is loose coupling, and how do dependency injection and inversion of control promote maintainable software design?

Approach

  1. Coupling is how much one module depends on another's concrete details. Loose coupling means a class depends on an abstraction it can be given, not on a concrete type it builds with new.
  2. Dependency injection supplies those abstractions from outside, preferably through the constructor so required dependencies are explicit. Inversion of control hands object creation and wiring to a container (ASP.NET Core's built-in container, Spring) that builds the graph.
  3. Show it concretely: a TaxService that takes IRateRepository runs against PostgreSQL in production and against a fake or a Moq/Mockito mock in a unit test. For a service that depends on a database context, wrap the context in a repository, or use an in-memory provider for integration tests.
  4. Mention the pitfalls: lifetimes (transient, scoped, singleton) and the captive-dependency bug where a singleton holds a scoped DbContext; service locator as an anti-pattern; a long constructor parameter list as a sign the class does too much.

Follow-up

  • What goes wrong if a singleton depends on a scoped service?
  • How would you unit-test a service that calls an external database context?
  • Can you do dependency injection without a container?

How do you implement robust global exception handling and structured logging within a cloud microservices arch

Medium · Core Frameworks & Object-Oriented Progra

How do you implement robust global exception handling and structured logging within a cloud microservices architecture?

Approach

  1. Catch exceptions once, at the edge of each service: UseExceptionHandler or IExceptionHandler in ASP.NET Core, @ControllerAdvice in Spring, error middleware in Express. Background workers and message consumers need their own top-level handlers.
  2. Map a small exception hierarchy to responses: validation errors to 400/422, not-found to 404, conflicts to 409, downstream failures to 502/503, everything else to 500. Return RFC 7807 problem details with an error code and trace id, never a stack trace.
  3. Use structured logging (Serilog, Logback with a JSON encoder, pino): every entry is JSON with timestamp, level, service, trace id, tenant and error code, so logs can be queried. Log at the boundary instead of logging and rethrowing at every layer, which produces duplicate entries.
  4. Propagate trace context across services with W3C traceparent headers via OpenTelemetry, so one transaction can be followed across calls. Keep tax ids and personal data out of logs, and alert on error-rate changes rather than single errors.

Follow-up

  • How would you follow one failed transaction across five services?
  • What must never appear in these logs?
  • How do you handle an exception thrown inside a message consumer?

Describe the core concepts of Object-Oriented Programming (OOP) and demonstrate how inheritance and polymorphi

Medium · Core Frameworks & Object-Oriented Progra

Describe the core concepts of Object-Oriented Programming (OOP) and demonstrate how inheritance and polymorphism apply to a payment processing module.

Approach

  1. Cover the four concepts briefly, each tied to the payment module. Encapsulation: a Payment object changes state only through methods such as Authorize, Capture and Refund, never through public setters. Abstraction: callers depend on a PaymentMethod contract.
  2. Inheritance: an abstract PaymentMethod base holds shared validation and audit logging, and CardPayment, BankTransferPayment and WalletPayment extend it. Polymorphism: the processor calls method.Process(amount) and the right override runs, with no type checks or switch statements.
  3. Respect Liskov substitution. If a wallet cannot be refunded, model that in the contract (a capability interface such as IRefundable) instead of a subclass throwing NotSupportedException.
  4. Show where inheritance stops. Variation that cuts across payment types, such as fees by region, belongs in composed strategy objects. Represent amounts as a Money value object (decimal plus currency).

Follow-up

  • How do you add a new payment method without modifying the processor?
  • When would you replace this hierarchy with the strategy pattern?
  • How would you unit-test the processor?

How do database indexes work under the hood (e.g., B-Trees vs. Hash indexes), and what are the trade-offs of a

Medium · Database & SQL Engineering

How do database indexes work under the hood (e.g., B-Trees vs. Hash indexes), and what are the trade-offs of adding multiple indexes to a high-write table?

Approach

  1. A B-tree index keeps keys sorted in balanced pages, giving O(log n) lookups. Linked leaf pages make range scans, ORDER BY and the leftmost-prefix use of composite indexes cheap. This is the default index almost everywhere.
  2. A hash index maps equality lookups to buckets. It cannot serve ranges or sorting. PostgreSQL offers it explicitly, and SQL Server uses hash indexes for memory-optimized tables. Mention clustered versus nonclustered: SQL Server stores the table in clustered-key order, while PostgreSQL keeps a heap plus secondary indexes.
  3. Every index costs writes. Each insert, and each update to an indexed column, maintains every index, which adds I/O, log volume, lock time and storage. Random keys such as GUIDs in a clustered index cause page splits.
  4. Design composite indexes with equality columns before range columns. Use INCLUDE or covering columns to avoid lookups, and skip low-selectivity columns. Find unused indexes with pg_stat_user_indexes or sys.dm_db_index_usage_stats before adding more.

Follow-up

  • Name reasons an index exists but the planner does not use it.
  • How do you choose column order in a composite index?
  • How would you safely add an index to a busy production table?

Walk through a challenging project listed on your resume, detailing your specific architectural contributions

Medium · Behavioral & Past Project Architecture

Walk through a challenging project listed on your resume, detailing your specific architectural contributions and technical trade-offs made.

Approach

  1. Open with the system in two sentences: what it did, for whom, and the scale you can defend. Then state exactly what you owned, saying 'I' for your part and 'the team' for the rest.
  2. Describe the architecture as a data flow: entry point, services, storage, queues and external dependencies. Then pick two or three decisions and give the alternatives you considered and why you rejected them (for example a queue instead of a synchronous call, or one schema over another).
  3. End with a measured outcome and one thing you would change now. Candidates report direct follow-up on resume claims, so every number and technology you mention must hold up down to the code.
  4. The mistake that sinks this answer is a tour of the team's system with no visible personal decision, or a metric you cannot explain.

Follow-up

  • What broke in production, and what did you change because of it?
  • What fails first if traffic grows tenfold?
  • Why not the alternative you rejected?

How would you debug and optimize a slow-performing database query in a production environment with millions of

Medium · Database & SQL Engineering

How would you debug and optimize a slow-performing database query in a production environment with millions of records?

Approach

  1. Measure first. Identify the exact statement and when it slowed down using pg_stat_statements or SQL Server Query Store, and ask what changed: a deploy, data growth, a new filter value, or statistics that were never refreshed.
  2. Get the actual plan, not just the estimate: EXPLAIN (ANALYZE, BUFFERS) or the actual execution plan. Look for full scans on large tables, estimated rows far from actual rows (refresh statistics with ANALYZE or UPDATE STATISTICS), key lookups, sorts or hashes spilling to disk, and nested loops over large inputs.
  3. Fix the cause. Add or reorder a composite or covering index. Make predicates sargable: no function on the indexed column, matching data types, no leading-wildcard LIKE. Replace deep OFFSET paging with keyset paging, and select only the needed columns. In SQL Server, check for parameter sniffing.
  4. Check whether the query is waiting rather than working, using pg_stat_activity/pg_locks or sys.dm_exec_requests for blocking. Verify on production-sized data, build indexes online (CREATE INDEX CONCURRENTLY, ONLINE = ON), and compare latency before and after.

Follow-up

  • The query is fast in development and slow in production. Why?
  • Your new index fixed reads but slowed inserts. What now?
  • How do you recognise and fix parameter sniffing?

Describe a situation where you had to debug a critical production issue under tight time constraints. How did

Medium · Behavioral & Past Project Architecture

Describe a situation where you had to debug a critical production issue under tight time constraints. How did you identify the root cause?

Approach

  1. Use STAR, but spend most of the time on the action. Set the stakes briefly: who was affected and how you knew, whether from alerts, error rates or customer reports.
  2. Show that you mitigated before diagnosing: rollback, feature flag, failover or throttling to stop the damage, then the root-cause search.
  3. Walk through the evidence: what changed and when (deploy, config, data volume, a dependency), correlating logs, metrics and traces by timestamp and trace id, reproducing the fault, and narrowing it by bisection. Separate the trigger from the underlying cause.
  4. Close with the fix, how you confirmed it, and the prevention you added: an alert, a test or a runbook. Avoid a lone-hero story with no mitigation or follow-up, and avoid blaming another team.

Follow-up

  • How did you keep stakeholders informed during the incident?
  • What would you have done if rollback was not possible?
  • What monitoring did you add afterwards, and has it fired since?

Suggested practice checklist

Each day takes one group of reported questions, moving from the coding problems through REST integration, OOP and runtimes, databases and service design to behavioral stories. Every day ends with written code, a query, a design or a spoken answer you can review.

Day 1 — Hash maps and sliding windows

  • Write two-sum with a single-pass hash map in your interview language, test it on [3,3] with target 6, an input with no pair and negative numbers, and state the sort-plus-two-pointers alternative.
  • Write the word-frequency counter with explicit normalisation, sorted by count then alphabetically, plus a top-k version using a size-k heap.
  • Write a fixed-window anagram finder and a variable-window minimum-window-substring, and explain aloud why each is linear.

Deliverable: Three tested solutions (two-sum, word frequency with top-k, two sliding-window variants), each with complexity written at the top.

Day 2 — Trees, stacks and bounded concurrency

  • Write level-order traversal with the queue-size technique and maximum depth both recursively and iteratively, and run them on an empty tree and a skewed tree.
  • Write the min stack with two stacks, then with (value, min) pairs, and test pushing the same minimum twice and popping once.
  • Write a bounded-concurrency runner (SemaphoreSlim, Semaphore or a Node active-count queue) that runs 20 fake HTTP tasks with at most 4 in flight, with a permit released in finally.

Deliverable: Working tree, min-stack and concurrency-limiter code, plus a test or log proving no more than 4 tasks ever ran at once.

Day 3 — REST consumption and failure handling

  • Write a client that pages through a public paginated JSON API (or a local mock), validates each item, and totals amounts per region with a decimal type.
  • Add retry with exponential backoff and jitter for 429 and 5xx, Retry-After support, a per-call timeout, and an idempotency key on a POST.
  • Outline a one-page comparison of synchronous REST and event-driven messaging for transaction data, covering at-least-once delivery, idempotent consumers, partition keys and the outbox pattern.

Deliverable: A runnable aggregation client with retries and timeouts, and a one-page REST-versus-events comparison.

Day 4 — OOP, dependency injection and your runtime

  • Write a small payment module: an abstract PaymentMethod with three subclasses, a processor that relies on polymorphism, and a Money value object; then refactor fee rules by region into strategies.
  • Wire a TaxService that depends on IRateRepository through your stack's DI container and unit-test it with a mock. Write one sentence on each lifetime and the captive-dependency bug.
  • Write a one-page summary of garbage collection in your runtime (.NET generations and LOH, JVM G1, or V8 scavenger and mark-compact) and one leak you could cause and find with a heap snapshot.

Deliverable: Payment-module code with strategy-based fees, a DI-wired service with a passing unit test, and a one-page GC summary for your stack.

Day 5 — SQL, indexes and transactions

  • Create customers, filings and jurisdictions tables in PostgreSQL or SQL Server, load a few thousand rows, and write the per-customer, per-state aggregation with LEFT JOINs, then the anti-join and a window-function ranking.
  • Run EXPLAIN ANALYZE (or the actual plan) before and after adding a composite index, and note which node changed and why.
  • Open two sessions and reproduce a lost update and a deadlock, then fix them with SELECT ... FOR UPDATE, a version column and consistent lock order.
  • Outline the relational-versus-document-store comparison with one example each from the tax domain.

Deliverable: A SQL file with three queries, saved before/after plans, a deadlock repro script with its fix, and a one-page database comparison.

Day 6 — Service design and your own project

  • Design the tax-rule validation service on one page: API contract, schema plus semantic validation, error format, rule versioning with effective dates, async path with a dead-letter queue.
  • Write the global exception handler and JSON logging setup for your framework, mapping four exception types to status codes and attaching a trace id.
  • Rehearse the resume-project walk-through aloud: architecture as a data flow, two trade-offs, one measured result, one change you would make.

Deliverable: A validation-service design, a working exception-handling and logging snippet, and a recorded project walk-through.

Day 7 — Behavioral stories and a full mock

  • Write STAR outlines for the production incident, the disagreement with a senior engineer, the ambiguous user story and the legacy refactor, each with one measured number.
  • Say each story aloud and cut anything that does not show your own decision or its result.
  • Run a mock: one coding problem from day 1 or 2, the slow-query question, and two behavioral stories back to back, then note the weakest answer to revisit.

Deliverable: Four STAR outlines with numbers, a recorded mock, and a list of the weakest answers to fix.

Behavioural preparation

Candidates report that the final HR Round focuses on behavioral questions and cultural fit, and some describe a hiring-manager conversation about past project impact and leadership scenarios. The reported prompts are engineering stories (a project architecture, a production incident, a design disagreement, an ambiguous spec, a legacy refactor), so keep the technical detail in each one. Candidates also report direct follow-up on resume claims and trade-offs.

  1. Walk through a challenging project listed on your resume, detailing your specific architectural contributions and technical trade-offs made.
  2. Describe a situation where you had to debug a critical production issue under tight time constraints. How did you identify the root cause?
  3. How do you approach gathering requirements and estimating technical work when facing an ambiguous user story or feature spec?

How do you handle HTTP timeout exceptions, rate limits, and transient network failures when orchestrating call

Medium · API Integration & Systems Logic

How do you handle HTTP timeout exceptions, rate limits, and transient network failures when orchestrating calls across downstream microservices?

Approach

  1. Sort failures first. Timeouts, connection resets, 502/503/504 and 429 are retryable. 400, 401, 403, 404 and validation errors are not, and retrying them only adds load.
  2. Retry with exponential backoff and jitter, cap the attempts, and honour Retry-After on 429. Only retry operations that are idempotent, or make them idempotent with an idempotency key. A timed-out POST that records a tax transaction may already have committed.
  3. Set a per-call timeout plus an overall deadline that you pass downstream, so retries cannot exceed the caller's budget. Retry at one layer only, because retries at every hop multiply into a storm.
  4. Add a circuit breaker so a failing dependency gets breathing room (Polly in .NET, Resilience4j in Java, opossum in Node) and a bulkhead so one slow service cannot take every thread. Throttle client-side with a token bucket to stay under the partner's rate limit.
  5. Decide the fallback per call. Serving stale cached data may suit a static lookup table, but for a tax calculation, failing clearly is usually safer than returning a wrong amount. Log retries and breaker state changes with a correlation id.

Follow-up

  • A POST timed out. How do you find out whether it was applied?
  • How do you choose the timeout value and the retry count?
  • Walk through the circuit breaker's closed, open and half-open states.

Tell me about a time when you disagreed with a senior engineer or architect regarding system design. How did y

Medium · Behavioral & Past Project Architecture

Tell me about a time when you disagreed with a senior engineer or architect regarding system design. How did you resolve the conflict?

Approach

  1. Pick a concrete technical disagreement, for example synchronous call versus queue, schema shape, or build versus buy, where you held a real position.
  2. Show that you first understood the senior engineer's reasoning and constraints, then framed the discussion around requirements rather than preference.
  3. Show how you settled it with evidence: a prototype, a benchmark, a failure-mode analysis or a written comparison of the options. If you were overruled, show disagree-and-commit and how you made their option work.
  4. Finish with the outcome and what you learned, including where the other person was right. The answer fails if the senior engineer comes across as foolish or if you simply gave in without engaging.

Follow-up

  • What would you have done if the evidence had gone against you?
  • How did the working relationship look afterwards?
  • How would you handle the same disagreement in a code review today?

Describe a scenario where you had to refactor a legacy code module to improve performance, maintainability, or

Medium · Behavioral & Past Project Architecture

Describe a scenario where you had to refactor a legacy code module to improve performance, maintainability, or modularity.

Approach

  1. Give the measured reason for the refactor: defect rate, latency, or how long simple changes took. 'The code was ugly' is not a reason.
  2. Show the safety net first. Add characterisation tests that pin the current behaviour, including the odd parts, before changing structure.
  3. Show incremental steps: extract methods and classes, introduce an interface or strategy (for example replacing a long per-state if/else chain with one strategy per rule), or strangle the module behind a facade. Ship behind a flag or run old and new side by side and compare outputs.
  4. Close with a before/after number and what you deliberately left alone. A big-bang rewrite without tests, or no measured result, sinks the story.

Follow-up

  • How did you get time approved for the refactor?
  • What behaviour differences did the side-by-side comparison find?
  • What would make you choose a rewrite over a refactor?