cswork / libraryOpen practice workspace

Interview guides · Advisor360°

Advisor360° Software Engineer Interview Guide

Advisor360° Software Engineer interview guide: four reported rounds, OOP, SQL, DSA and system design questions with prep guidance and a 7-day plan.

The 60-second brief

Candidate write-ups describe Advisor360° as a SaaS wealth management platform used by financial advisors, broker-dealers and investors. For a Software Engineer, the reported work covers data pipelines, microservices and front-end screens, plus tuning database queries and protecting the integrity of financial data. The stack candidates list is C# .NET or Java on the backend, SQL Server for relational data and Angular on the front end, with AWS or Azure and prior fintech exposure named as nice-to-haves.

This guide is for engineers preparing for the Software Engineer loop at Advisor360°, typically with several years of experience in an object-oriented language such as C#, Java or C++. It walks through the four reported stages, then covers sixteen reported questions: object-oriented programming and SQL fundamentals, core data structures and algorithms, system design and architecture, and behavioral and project discussion. It also gives a seven-day plan and behavioral stories to rehearse.

Candidates report four stages over roughly 3-5 weeks: a recruiter screening call, a technical screening, comprehensive technical rounds and a leadership discussion.

Focus areas

  • Coding Challenges / Technical Assessments
  • Problem Solving
  • DSA (Data Structures & Algorithms)

Overview

The reported questions are classic fundamentals rather than puzzles. One group covers object-oriented programming and databases: the four OOP pillars, SQL injection, join types with a duplicate-finding query, and when an index hurts. A second group covers data structures: string handling, a hand-built stack or queue, DFS versus BFS, and the cost of operations on a balanced binary search tree versus a hash map. Candidate write-ups describe the coding difficulty as average, so the winning move is fluent, correct code with clear complexity statements, not exotic tricks.

The design group mixes two scales. A scalable notification system with rate limiting and queuing, and a distributed caching layer for a high-traffic financial dashboard, are macro questions about components, failure modes and staleness. The contrast between low-level and high-level design, with SOLID applied to daily work, is a micro question about classes and responsibilities. Write-ups also mention example scenarios such as a parking lot class design, refactoring a tightly coupled class, a real-time portfolio tracker that survives spikes in market data, and splitting a monolithic reporting tool into services. Practise both scales out loud, since the reported questions span both.

Because the product handles financial data, tie each design choice to correctness and security. Say which numbers may be a few seconds stale on a dashboard and which must never be, how you keep writes idempotent so a retried message never double-applies, and how queries are parameterised and permissions kept narrow. The stack candidates list (C# .NET or Java, SQL Server, Angular) is worth reviewing for vocabulary, but the reported questions are language-neutral, so answer in whichever language you code in fastest.

The last two stages lean on your own history. Candidates report a project architecture discussion in the technical rounds and a leadership conversation about team alignment, roles and organizational expectations. Four reported behavioral prompts cover a disagreement, a resume and project walkthrough, prioritising under shifting requirements, and mentoring plus code review. Choose two or three real projects now, write down your personal decisions in each, and let them feed every answer.

The Advisor360° interview process

These are the four stages candidates describe, in the order they report them. The reported questions are grouped by topic, and the loop descriptions do not tie a given question to a given round.

Recruiter Screening Call

Candidates report the first stage as a recruiter call about your background, your career goals and whether the role fits. Write-ups also say that work arrangements such as hybrid or remote are usually raised here. Treat it as the place to settle logistics and to confirm which stack the team uses (candidates list C# .NET or Java, SQL Server and Angular), so you can aim the rest of your preparation. Have a short, chronological account of your career ready, with one concrete result per role, and a clear reason for wanting wealth management software specifically.

What to demonstrate

  • How your background and career goals line up with a Software Engineer role
  • Whether your experience maps to the stack and domain the role describes
  • Practical fit, including work arrangement and location

How to prepare

  • Write a chronological CV narrative with one measurable outcome for each role, and say it aloud until it flows without notes
  • Prepare a specific reason for choosing a wealth management SaaS product over a generic employer
  • List your hands-on years in C#, Java or C++, SQL Server or another relational database, and Angular, so you can answer stack questions precisely
  • Write two or three questions about the team's stack, the remaining stages and the work arrangement

Technical Screening

Candidates describe the technical screening as a mix of conceptual discussion about software fundamentals and a practical coding assessment. Candidate write-ups warn that online assessments are monitored for copied code, so plan to write your own solution without outside help. Practise the conceptual half as short spoken answers with a concrete example, and the coding half as a full cycle: clarify, state complexity, write, test with edge cases.

What to demonstrate

  • Command of software fundamentals when explained verbally
  • Ability to turn a short problem into working, clean code
  • How clearly you communicate while coding

How to prepare

  • Practise short spoken answers to the reported fundamentals questions, such as the four OOP pillars, SQL injection defences, join types with a duplicate-finding query, and when to skip an index, each with a code or query example
  • Solve the first non-repeating character problem and a string reversal in your main language, with tests for empty, single-character and all-repeating inputs
  • Practise the longest substring without repeating characters and linked-list cycle detection, narrating each decision as you write
  • Do one practice session in a plain editor without autocomplete or outside help, matching an unassisted assessment

Comprehensive Technical Rounds

Candidates report that the comprehensive technical rounds cover data structures, system design and project architecture. The practice topics below fit those three areas. Begin every design answer by scoping requirements, then draw components, then name failure modes and trade-offs, and for data structure work state the cost of each operation as you write it.

What to demonstrate

  • Data structure choice and complexity reasoning
  • Ability to scope and structure a system design from requirements
  • Depth of understanding of your own project's architecture and trade-offs

How to prepare

  • Implement a stack on a resizable array and a queue on a linked list or circular buffer, and state the cost of every operation
  • Write iterative and recursive DFS and BFS on a graph, and say which you would choose for shortest paths in an unweighted graph versus exhaustive search
  • Whiteboard the notification system and the dashboard cache, each with components, a failure mode and a staleness rule
  • Draw your own project's architecture and prepare two technology choices you would defend and one you would change

Leadership Discussion

The final stage is described as a conversation with leadership about how you would fit the team, what the role covers and what the organization expects. Prepare concrete stories from your own work and your own questions about team structure and priorities.

What to demonstrate

  • Alignment with the team and the shape of the role
  • Ownership, collaboration and communication in real situations
  • Your understanding of what the organization expects from the role

How to prepare

  • Rehearse the four behavioral stories in this guide: disagreement, project walkthrough, prioritising under shifting requirements and mentoring or code review
  • Prepare a two-sentence summary of your most impactful project: the problem, your decision and the outcome
  • Write questions about how engineering and product agree on scope, and how code review and releases work for the team
  • Review how you would take a feature from development through deployment, since write-ups describe the role as owning features across that span

Where candidates lose points

Answering the SQL injection question with escaping or stored procedures alone

Lead with parameterised queries or bind parameters, where data never becomes SQL text. Add that stored procedures that build dynamic SQL by string concatenation remain injectable, that column or table names in ORDER BY clauses need an allow-list because they cannot be parameters, that the database account should have least privilege, and that validation is a second layer, not the defence.

Mixing up join types, or finding duplicates with DISTINCT instead of grouping

State the row behavior of inner, left and full outer joins on a tiny two-table example, and note that a WHERE filter on the right table silently turns a left join into an inner join. For duplicates, group by the key that defines sameness, such as email, and keep groups with HAVING COUNT(*) > 1, or number rows with ROW_NUMBER partitioned by that key to select the extras.

Adding indexes by reflex without checking the execution plan or whether the predicate is sargable

Explain that an index speeds reads but taxes every write and costs storage, so skip it on tiny tables, write-heavy tables and low-selectivity columns. Show a predicate that defeats an index, such as a function wrapped around the column or a leading-wildcard LIKE, and say you confirm each index with the execution plan: seek versus scan, key lookups, estimated versus actual rows.

Starting a notification or dashboard-cache design by naming products instead of scoping the system

Ask first about volume, latency needs, delivery guarantees and what happens on failure. Then draw producers, a queue, workers, retries with idempotency keys, and a rate limiter, or for the cache a key scheme, expiry, invalidation on write and protection against a stampede when a hot key expires. For a financial dashboard, say which values may be seconds stale and which must be read from the source of truth.

Walking through a project as a list of technologies the team used, with no personal decision or trade-off

Before the rounds, write for each of two projects the problem, your own decisions, the alternatives you rejected, a measured result and one regret. Practise saying the architecture aloud while drawing it, since the reported technical rounds include a project architecture discussion and the leadership stage covers roles and expectations.

Questions & practice

Given a string, write an efficient algorithm to reverse it or find the first non-repeating character.

Medium · Data Structures & Algorithms

Approach

  1. Reverse: strings are immutable in C# and Java, so I copy to a char array and swap with two pointers (i from the start, j from the end) until they meet. That is O(n) time and O(n) space for the copy; on an already mutable array it is O(1) extra space. Java's StringBuilder.reverse() also works.
  2. I raise the Unicode edge case: C# and Java chars are UTF-16 code units, so a naive swap splits surrogate pairs (emoji) and detaches combining accents. Java's StringBuilder.reverse() keeps surrogate pairs together; whole grapheme clusters need StringInfo text elements in .NET or BreakIterator in Java.
  3. First non-repeating character: two passes. Pass one counts frequencies in a hash map, or an int[26]/int[128] array for a known alphabet. Pass two scans the string again and returns the first character whose count is 1. O(n) time, O(k) space for an alphabet of size k.
  4. Edge cases I state up front: empty string, no unique character (return -1 or null and say which), case sensitivity, and whether spaces and punctuation count.
  5. For a very long input I can avoid the second scan by storing each character's first index alongside its count, then taking the minimum index among characters with count 1. That costs O(k) after the single pass.

Follow-up

  • Characters arrive as a stream: after each one, return the current first non-repeating character. What structure gives amortized O(1)?
  • How would you reverse the order of words in a sentence in place?
  • How does your solution change if the input is arbitrary Unicode rather than ASCII?

How would you implement a custom stack or queue using basic arrays or linked lists?

Medium · Data Structures & Algorithms

Approach

  1. Stack on a dynamic array: push writes at index top and increments, pop decrements and returns. When the array is full I double its capacity, which makes push amortized O(1). In Java or C# I clear the popped slot so the garbage collector can reclaim the object.
  2. Stack on a singly linked list: push and pop both work at the head, O(1) worst case with no resizing, at the cost of a pointer and an allocation per node.
  3. Queue on an array: a circular buffer with a head index and a count; the tail position is (head + count) % capacity. Keeping a count resolves the full-versus-empty ambiguity of head == tail. On resize I copy the elements in logical order starting from head, so the wrapped segment is unrolled.
  4. Queue on a linked list: keep both head and tail pointers. Enqueue appends at the tail, dequeue removes at the head, both O(1). When the last node leaves I set tail to null too, the bug people most often miss.
  5. API decisions: pop, dequeue and peek on an empty structure either throw (as Stack<T>.Pop does in .NET) or return a TryPop-style result, plus generics for the element type. It is not thread-safe unless asked.

Follow-up

  • Implement a queue using two stacks and explain why dequeue is amortized O(1).
  • Add getMin() to the stack in O(1) time.
  • How would you make the queue bounded and safe for multiple producer and consumer threads?

Explain the difference between Depth-First Search (DFS) and Breadth-First Search (BFS). In what scenarios woul

Medium · Data Structures & Algorithms

Explain the difference between Depth-First Search (DFS) and Breadth-First Search (BFS). In what scenarios would you choose one over the other?

Approach

  1. BFS uses a FIFO queue and visits nodes level by level, so the first time it reaches a node is along a path with the fewest edges. Memory grows with the widest frontier.
  2. DFS uses a stack, explicit or the call stack through recursion, and follows one path as deep as it goes before backtracking. Memory grows with the depth. It underlies cycle detection, topological sort, connected components and backtracking searches.
  3. Both run in O(V + E) on an adjacency list (O(V^2) with an adjacency matrix). On graphs, unlike trees, I need a visited set. In BFS I mark a node when I enqueue it, not when I dequeue it, so it is never queued twice.
  4. Choosing: BFS for shortest path in an unweighted graph, minimum steps, or when the target is likely close to the start. DFS when I need to explore whole paths, enumerate solutions, or order dependencies. Recursive DFS on a deep graph can overflow the call stack, so I switch to an explicit stack.
  5. Limit I state: BFS gives shortest paths only when all edges have equal weight. With weights I need Dijkstra (non-negative weights), or 0-1 BFS with a deque when weights are only 0 and 1.

Follow-up

  • How do you detect a cycle in a directed graph with DFS (three-colour marking or a recursion-stack set)?
  • Count the islands in a grid of 0s and 1s. Which traversal do you use and why?
  • What is iterative deepening DFS, and when does it beat plain BFS on memory?

What is the time complexity of searching, inserting, and deleting elements in a balanced binary search tree ve

Medium · Data Structures & Algorithms

What is the time complexity of searching, inserting, and deleting elements in a balanced binary search tree versus a hash map?

Approach

  1. Balanced BST (red-black or AVL): search, insert and delete are all O(log n) worst case, because rebalancing keeps the height O(log n). An unbalanced BST degrades to O(n), for example when keys arrive in sorted order.
  2. Hash map: search, insert and delete are O(1) on average, O(n) worst case when keys collide into one bucket. Java 8+ HashMap converts a long bucket chain (more than 8 entries, once the table has at least 64 buckets) into a tree, bounding that bucket at O(log n) for comparable keys. Insert is amortized O(1): an individual resize costs O(n).
  3. Ordering is the deciding property. Java's TreeMap (a red-black tree) supports in-order iteration, firstKey/lastKey, floorKey/ceilingKey and subMap range queries in O(log n + k). .NET's SortedDictionary only exposes ordered iteration: it has no floor, ceiling or range API, and LINQ Last() on it is O(n). In C# I use SortedSet<T> with Min, Max and GetViewBetween for range and min/max queries, or binary-search a sorted List<T>. A hash map (HashMap, Dictionary) has no key order.
  4. Hash maps depend on correct, consistent equals/hashCode (Equals/GetHashCode); mutating a key after insertion makes it unreachable. They also trade memory for speed through the load factor (0.75 by default in Java's HashMap).
  5. Example: for 'all trades for this account between two dates' I would pick a sorted structure, and for 'look up a security by its symbol' a hash map.

Follow-up

  • When would you accept O(log n) lookups from a TreeMap over O(1) average from a HashMap?
  • What happens if you change a field used in hashCode after the object is already a key in the map?
  • What is a hash-flooding attack, and how do language runtimes defend against it?

How do you prevent SQL injection in an enterprise-grade application?

Medium · Object-Oriented Programming & Databases

Approach

  1. I start with the root cause: injection happens when user input is concatenated into SQL text, so the database parses data as code. The fix is parameterized queries: SqlCommand with SqlParameter in ADO.NET, PreparedStatement in JDBC. The value travels as a bind parameter and is never parsed as SQL.
  2. ORMs such as Entity Framework and Hibernate parameterize by default, but their raw-SQL paths reopen the hole. In EF Core, FromSqlRaw with a concatenated string is vulnerable, while FromSqlInterpolated turns interpolated values into parameters. String-built HQL/JPQL has the same problem.
  3. Identifiers cannot be bound: table names, column names and ORDER BY direction. I map user choices onto a fixed allow-list (for example a dictionary from 'date' to the trade_date column) and reject anything else.
  4. Stored procedures help only if they do not build dynamic SQL inside. In SQL Server I use sp_executesql with parameters, never EXEC on a concatenated string.
  5. Defense in depth: the application's database login gets least privilege (no DDL, only the schemas it needs), raw database errors never reach the client, and code review or static analysis flags concatenated SQL. A WAF is a backstop, not the fix.

Follow-up

  • How would you support a user-chosen sort column safely?
  • What is second-order SQL injection, and why does validating input only at the API boundary not stop it?
  • How do you parameterize a LIKE search, and what do you do about % and _ characters inside the user's value?

What is the difference between an inner join, a left join, and a outer join in SQL? Write a query to find dupl

Medium · Object-Oriented Programming & Databases

What is the difference between an inner join, a left join, and a outer join in SQL? Write a query to find duplicate records in a user table.

Approach

  1. INNER JOIN returns only rows with a match on both sides. LEFT (OUTER) JOIN returns every left row, with NULLs in the right-hand columns where nothing matches. FULL OUTER JOIN returns all rows from both tables, with NULLs on whichever side is missing. I clarify which one 'outer join' means, since LEFT and RIGHT joins are outer joins too.
  2. I name the classic trap: a WHERE filter on a right-table column after a LEFT JOIN discards the NULL rows and quietly turns it into an inner join. That condition belongs in the ON clause. I also note that a one-to-many join multiplies left rows.
  3. For duplicates I first define what a duplicate is, usually the same email after trimming and lowercasing. Query: SELECT LOWER(TRIM(email)) AS email_key, COUNT() AS n FROM users GROUP BY LOWER(TRIM(email)) HAVING COUNT() > 1.
  4. To list or delete the extra rows: ROW_NUMBER() OVER (PARTITION BY LOWER(TRIM(email)) ORDER BY created_at, id) AS rn in a CTE, then rows with rn > 1 are the duplicates. That keeps the earliest account, and SQL Server allows DELETE directly from such a CTE.
  5. Edge cases: GROUP BY puts all NULL emails in one group, so I filter out NULLs if they should not count as duplicates. I also check whether the duplicates have child rows (orders, logins) that need re-pointing before any delete.

Follow-up

  • How would you stop duplicates from being inserted again (unique index on a normalized computed column, and how existing rows block creating it)?
  • If the right table has three matches for one left row, how many rows does the LEFT JOIN return?
  • How would you merge duplicate users when other tables hold foreign keys to both ids?

Explain the concept of database indexing. When would you avoid creating an index on a table?

Medium · Object-Oriented Programming & Databases

Approach

  1. An index is a separate sorted structure, usually a B-tree, keyed on one or more columns and pointing at rows. A lookup becomes an O(log n) seek plus a range read instead of a full scan. In SQL Server the clustered index is the table's row order (one per table). A nonclustered index stores its key plus a row locator, and INCLUDE columns can make it covering, which avoids key lookups.
  2. Composite indexes follow the leftmost prefix. An index on (account_id, trade_date) supports a seek for WHERE account_id = @a AND trade_date >= @d, but not for trade_date alone. I put equality columns first and the range column last.
  3. I list what makes an index unusable for a seek (non-sargable predicates): wrapping the column in a function such as YEAR(created_at) = 2024, a leading-wildcard LIKE '%abc', and implicit type conversions between parameter and column.
  4. When to avoid one: write-heavy tables, because every INSERT, UPDATE and DELETE maintains every index; low-selectivity columns such as a boolean flag, where a scan is cheaper; tiny tables; columns never filtered or joined on; indexes that duplicate the prefix of an existing one. For large bulk loads I drop or disable the nonclustered indexes, or use a minimally logged bulk insert, then rebuild. I never disable the clustered index in SQL Server: that makes the table inaccessible and the inserts would fail.
  5. I check the decision with the execution plan (seek vs scan, key lookups, estimated vs actual rows), not by guessing.

Follow-up

  • Why can a random GUID clustered key cause page splits and fragmentation, and what would you use instead?
  • When would a filtered (partial) index be the right tool?
  • A query got slower after you added an index. What could explain it?

Explain the four pillars of Object-Oriented Programming (OOP): Inheritance, Encapsulation, Abstraction, and Po

Medium · Object-Oriented Programming & Databases

Explain the four pillars of Object-Oriented Programming (OOP): Inheritance, Encapsulation, Abstraction, and Polymorphism. Provide real-world coding examples for each.

Approach

  1. Encapsulation: I keep state private and expose only operations that protect its invariants. Example: an Account class whose balance has no public setter, where Withdraw(amount) rejects negative amounts and overdrafts, so no caller can leave the object in an invalid state.
  2. Abstraction: callers depend on what something does, not how. Example: an IPriceFeed interface with GetQuote(symbol); the dashboard code does not know whether the quote comes from a vendor API, a cache or a test stub. I keep this distinct from encapsulation: abstraction hides complexity behind a contract, encapsulation guards data inside one object.
  3. Inheritance: an is-a relationship that reuses behaviour. Example: an abstract Account base with BrokerageAccount and RetirementAccount subclasses that share an id and holdings. I mention the cost: deep hierarchies couple subclasses to base-class internals, so for has-a relationships I prefer composition.
  4. Polymorphism: one call, behaviour chosen by the object's type. Runtime polymorphism is virtual/override (C#) or overriding (Java): iterating a List<Account> and calling CalculateFee() dispatches to each subclass. Compile-time polymorphism is method overloading. It is what lets me add a new account type without editing the loop.

Follow-up

  • When would you choose composition over inheritance, and how would you refactor an existing hierarchy towards it?
  • What is the difference between an abstract class and an interface in C# or Java now that both languages allow default interface methods?
  • Give an example of a subclass that breaks the Liskov substitution principle.

Walk through the design of a scalable notification system. How would you handle rate limiting and message queu

Medium · System Design & Architecture

Walk through the design of a scalable notification system. How would you handle rate limiting and message queuing?

Approach

  1. I fix requirements first: channels (email, SMS, push, in-app), what triggers a notification (domain events vs scheduled digests), per-user preferences and opt-outs, delivery guarantee (at-least-once), and priority classes, since a security alert and a weekly summary should not share a lane.
  2. Components: an intake API or event consumer validates the event and looks up preferences and templates, then publishes to a message queue (Kafka, SQS or RabbitMQ) with separate queues or topics per channel and priority, so a slow SMS vendor cannot block push. Stateless channel workers call the providers, and a store records each notification's status for the in-app feed and for audit.
  3. At-least-once delivery means duplicates, so each message carries an idempotency key (event id + user + channel). The worker claims the key as 'pending' with a short lease, sends, and flips it to 'sent' only after the provider accepts; if the worker crashes, the lease expires and another worker retries, so nothing is lost. Where the provider supports it, I pass the same idempotency key to it. Retries use exponential backoff with jitter, and after N failures the message goes to a dead-letter queue.
  4. Rate limiting works at two levels: per user, so nobody gets spammed, and per provider, to respect vendor quotas. I use a token bucket in Redis updated atomically (a Lua script). Over-limit messages are delayed or folded into a digest rather than dropped, except low-value ones.
  5. Scaling: partition the queue by user id to keep per-user ordering, scale workers horizontally on queue lag, and put a circuit breaker on each provider with failover to a secondary vendor.

Follow-up

  • The email provider is down for an hour. What happens to the backlog, and what do users see?
  • How would you guarantee a user never sees the same alert twice in the in-app feed?
  • How do you send a scheduled notification to every user at once without overloading the system?

Describe the difference between Low-Level Design (LLD) and High-Level Design (HLD). How do you apply SOLID pri

Medium · System Design & Architecture

Describe the difference between Low-Level Design (LLD) and High-Level Design (HLD). How do you apply SOLID principles to your daily coding tasks?

Approach

  1. HLD is the system view: services, data stores, how they communicate (REST, gRPC, queues), scaling, and how failures are handled. LLD is the inside of one component: classes, interfaces, method signatures, relationships, design patterns and the data model.
  2. Single Responsibility: a class has one reason to change. I give a concrete split, e.g. a ReportService that fetches data, computes returns and renders PDF becomes a repository, a calculator and a renderer, each testable alone.
  3. Open/Closed and Liskov: I add behaviour by adding a class, e.g. a Strategy per fee type behind an IFeeCalculator, instead of growing a switch statement. Every implementation must honour the base contract: a read-only account whose Withdraw throws breaks Liskov.
  4. Interface Segregation and Dependency Inversion: small, focused interfaces so clients do not depend on methods they never call. High-level code depends on abstractions injected through the constructor (the .NET DI container or Spring), so I can unit-test with fakes.
  5. For 'daily' I give one real example from my own code or a review, and say where I stop: I do not add an interface with a single implementation and no test seam, because that is speculative abstraction.

Follow-up

  • Design the classes for a parking lot system and show where SOLID shapes your design.
  • What is the difference between dependency inversion and dependency injection?
  • Tell me about a time you deliberately broke one of these principles. Why?

How would you design a distributed caching layer for a high-traffic financial dashboard?

Medium · System Design & Architecture

Approach

  1. I classify the data by freshness tolerance first: reference data such as security metadata can live for hours, positions and balances for seconds to minutes, live quotes barely at all. I also separate shared data (prices) from per-user data (holdings), because the key design and the security rules differ.
  2. Core pattern: cache-aside on a Redis cluster (keys sharded across hash slots, replicas for failover), with TTLs per data class. The write path invalidates or updates keys from change events emitted by the source of truth, so freshness does not rely on TTL alone.
  3. Security: per-user keys include the user or account id, and the service checks entitlement before serving a cached entry, so one advisor never receives another client's data. Connections are encrypted in transit, and I cache only the fields the dashboard needs.
  4. Hot keys and stampedes: a short-TTL in-process L1 cache in front of Redis for very hot shared data, jittered TTLs so keys do not expire together, and request coalescing (a single-flight lock) or stale-while-revalidate so one miss does not send thousands of queries to the database.
  5. Failure and consistency: the cache is never the source of truth. If Redis is unavailable, reads fall back to the database behind a circuit breaker and rate limit. The UI shows an as-of timestamp, and after a user's own write I invalidate that key (or bypass the cache) to get read-your-writes.

Follow-up

  • How do you invalidate entries when the dashboard runs in several regions?
  • Your hit ratio drops from 95% to 60% overnight. How do you investigate?
  • Which Redis eviction policy would you choose, and what happens when memory fills up?

Walk us through the architecture of your current or most complex project. What trade-offs did you make regardi

Medium · System Design & Architecture

Walk us through the architecture of your current or most complex project. What trade-offs did you make regarding technology choices and system boundaries?

Approach

  1. I open with one sentence on the problem and who used the system, plus the scale numbers I can actually back up (requests, data volume, users). Then I sketch the diagram: clients, services, data stores, async paths and external integrations. Then I mark which parts I personally built or decided.
  2. I pick two or three decisions and, for each, the alternative I rejected and the constraint that decided it: relational vs document store, one deployable vs separate services, synchronous REST vs a queue, build vs buy.
  3. For system boundaries I explain why each boundary sits where it does (data ownership, team ownership, deployment cadence, scaling profile) and how consistency crosses it: one database transaction, or eventual consistency through events with an outbox and idempotent consumers.
  4. I close with evidence and hindsight: a failure or incident and what changed after it, a before/after metric (latency, cost, error rate), and what I would design differently today.
  5. I keep 'I' and 'the team' distinct throughout, and I know the details one level below every box I draw, because each box is a natural place for a deeper question.

Follow-up

  • What breaks first if load grows ten times?
  • If you rebuilt it today, which boundary would you move and why?
  • How did you test and deploy changes that crossed service boundaries?

Read latency spikes on a sixty-second sawtooth

Medium · cache stampede · single-flight · ttl

The cached listing read path serves about 14k reads/second at an 85% hit rate. p99 sits at 35 ms for 57 seconds, jumps to 900 ms for 3, and repeats. During each spike the primary shows several hundred identical listing queries starting within the same millisecond, all carrying one large tenant's id. Cache entries use a 60-second TTL. Give the mechanism, the ordered checks, the fix, and the correctness hazard your fix must not introduce.

Approach

  1. Match the period to a configured number before theorising about load. A spike every 60 seconds against a 60-second TTL is an entry expiring, and you confirm it by correlating spike timestamps with the entry's write time rather than with the traffic curve. If the period had matched a cron or a GC interval instead, this is a different investigation.
  2. Establish the concurrency of the miss. Several hundred identical queries in one millisecond means the miss path has no coalescing: every request that arrives between expiry and repopulation recomputes. The herd size is that key's arrival rate times its recompute time, so at 1.2k reads/second for the hot key and a 250 ms recompute you expect about 300 concurrent misses, which matches what is observed.
  3. Add single-flight on the miss path so one caller per key recomputes under a short-lived lock while the rest wait for its result. Prefer stale-while-revalidate where the read tolerates it: return the expired value immediately and refresh asynchronously, which removes the latency spike rather than serialising it into a queue of waiters.
  4. De-synchronise the keys. Write TTLs with jitter, for example 60 seconds plus or minus 10%, so a deploy or a mass invalidation does not align every key on the same second and turn a per-key herd into a fleet-wide one.

Follow-up

  • The same sawtooth appears on a key that is invalidated on write rather than expired. Is that the same bug?
  • How does your answer change if the recompute takes 4 seconds instead of 250 ms?

Suggested practice checklist

The plan follows the reported loop: fundamentals first (SQL, OOP), then data structures, then system design, then project and behavioral stories, ending with a full spoken run. Days name the reported questions they practise.

Day 1 — Map the loop and your stack

  • Write the four reported rounds in order with one line each on what you will need for it: recruiter call, technical screening, comprehensive technical rounds, leadership discussion.
  • List your hands-on experience against the stack candidates mention: C#, Java or C++, SQL Server or another relational database, Angular, AWS or Azure.
  • Candidates report a strong Angular emphasis on the front end, so if your screen may touch it, outline how you would split a holdings dashboard into components and services, feed it with RxJS observables, and keep change detection cheap on a data-heavy grid (OnPush, trackBy).
  • Choose the two projects you will use for architecture and behavioral answers, and note your own decisions in each.

Deliverable: A one-page loop map, a stack self-assessment with gaps marked, a short Angular dashboard outline, and two chosen projects with the decisions you owned.

Day 2 — SQL and database fundamentals

  • Create a users table with duplicate emails and write two duplicate-finding queries: GROUP BY with HAVING, and ROW_NUMBER partitioned by email.
  • On two small tables, write inner, left and full outer joins and record the row count of each, including the unmatched rows.
  • Write down when you would skip an index (small tables, heavy writes, low-selectivity columns) and show one query that cannot use an index because of a function on the column.
  • Write a parameterised query in your language, and note the allow-list approach for ORDER BY columns.

Deliverable: A SQL sheet containing both duplicate queries, the join row-count table, an index decision list and a parameterised query example in your language.

Day 3 — OOP and design principles

  • Code a small account hierarchy that shows inheritance, encapsulation, abstraction and polymorphism, and say aloud what each pillar buys you.
  • For each SOLID principle, write a violation from real code you have seen and the refactor that fixes it.
  • Sketch a parking lot class design and refactor a tightly coupled class to follow the Single Responsibility Principle, then say how this low-level design differs from a high-level architecture.

Deliverable: A compiling class sketch for the four pillars, a SOLID violation-and-fix table, and the parking lot class diagram.

Day 4 — Data structures and algorithms

  • Solve first non-repeating character with a counting map and a reversal, state complexity, and test empty and all-repeating strings.
  • Implement a stack on a resizable array and a queue on a linked list or circular buffer, with push, pop and peek or enqueue, dequeue and size.
  • Write DFS and BFS on a graph, recursive and iterative, and note when each fits, including cycle handling with a visited set.
  • Fill a table of search, insert and delete costs for a balanced binary search tree and a hash map, including worst case and ordered iteration.

Deliverable: Four tested solutions plus a complexity table, each with the edge cases you tested.

Day 5 — System design components

  • Whiteboard a scalable notification system: producers, queue, workers, retry with idempotency, rate limiting per user and per channel, and a dead-letter path.
  • Whiteboard a distributed cache for a high-traffic financial dashboard: cache-aside, key scheme, expiry, invalidation on write and stampede protection.
  • Practise the real-time portfolio tracker and the monolith-to-services migration as extra design scenarios, naming the failure modes of each.

Deliverable: Two diagrams with a written failure-mode list each, and a note stating which dashboard data may be stale and which may not.

Day 6 — Project architecture and first behavioral stories

  • Draw your main project's architecture from memory and write the trade-offs you made in technology and service boundaries.
  • Write a STAR story for a technical disagreement with evidence and an honest outcome.
  • Deliver your spoken resume walk once and cut anything that is not a decision or a result.

Deliverable: An architecture diagram with a trade-off list, a written disagreement story and a revised resume walk script.

Day 7 — Full spoken run and weak-spot repair

  • Write and rehearse your prioritisation story under shifting requirements and your mentoring and code-review story.
  • Run through the loop in order aloud: recruiter pitch, one SQL answer, one coding problem, one design, one project walkthrough.
  • Redo your weakest item from days 2 to 5 and write the questions you will ask recruiters and leaders.

Deliverable: Two rehearsed stories, a recorded or timed full run with a note on the weakest answer, and a question list for the first and last stages.

Stories to rehearse for the project and leadership discussions

Candidates report four behavioral and project questions, a project architecture discussion in the comprehensive technical rounds, and a leadership conversation as the final stage. The first four prompts below are the reported questions; the last two are extra practice prompts, not reported ones. Strong stories show decisions you owned, how you handled disagreement, how you prioritised under pressure and how you raised the standard of the code around you. Prepare one real story per prompt, with a number or concrete outcome in each.

  1. Extra practice prompt: Tell me about a time you refactored code you did not write. What did you change first, and how did you know nothing broke?
  2. Extra practice prompt: Why wealth management software, and what do you want to learn about this engineering team?

Describe a time when you had to work with a difficult stakeholder or a team member who disagreed with your tec

Medium · Behavioral & Project Experience

Describe a time when you had to work with a difficult stakeholder or a team member who disagreed with your technical approach. How did you resolve it?

Approach

  1. Choose a real technical disagreement where you held a position and the other person had a legitimate one, such as a schema change, a library choice or a testing trade-off. If the other person was plainly wrong or unreasonable, the story reads as blame.
  2. Open with two sentences of context, then state the other person's view in terms they would accept. Showing that you understood their reasons first is what makes the resolution believable.
  3. Describe how you moved from opinion to evidence: a prototype, a benchmark, a load test, a small spike, or a written comparison of options with costs. Name the specific measure that decided it.
  4. State the result honestly, including a compromise or the times you were the one who changed your mind. Close with what the relationship and the codebase looked like afterwards.
  5. Do not use a story where you escalated to a manager as the main action, and do not end with the other person conceding because you were right.

Follow-up

  • What if they still disagreed after seeing the evidence?
  • What would you do differently if you ran that disagreement again?
  • How did you keep working with them during and after the dispute?

Walk me through your resume and explain the technical challenges of your most impactful project.

Medium · Behavioral & Project Experience

Approach

  1. Structure the resume walk as a thread, not a list. Give each role one sentence of scope and one result, and show why each move led to the next. End on the work most similar to a wealth-management SaaS product: data-heavy, correctness-sensitive, many users.
  2. Choose the project where you made architectural decisions. Open with the problem and the constraints, such as data volume, number of users, deadlines and compliance, before naming any technology.
  3. Describe the architecture in components: services and their boundaries, datastores, how they communicate, and where data enters and leaves. Then pick two or three genuinely hard technical challenges and for each say the options you weighed, why you chose one, and what it cost.
  4. Give measurable outcomes (latency, error rate, deploy frequency, query time) and one thing you would redo. Use I for your own decisions and the team for shared work, so the listener can tell what you personally owned.
  5. The sinking mistake is a tour of technologies with no reasons, or a project where every decision belonged to someone else.

Follow-up

  • Why did you pick that datastore or communication style over the alternative?
  • What failed in production, and how did you find and fix it?
  • If you rebuilt it today, which boundary or technology would you change?

How do you manage your time and prioritize tasks when working under tight deadlines with shifting requirements

Medium · Behavioral & Project Experience

How do you manage your time and prioritize tasks when working under tight deadlines with shifting requirements?

Approach

  1. Pick one episode with a real deadline and at least one requirement change after work had begun. Say concretely what was due, who set it and what changed.
  2. Show a repeatable method: list the work, rank by user or business value against risk and effort, identify the smallest slice that meets the deadline, and mark what depends on what. Say what you cut or deferred, not only what you did.
  3. Show negotiation: you took the trade-off to the product manager or owner in writing, with options (reduce scope, move the date, add people) and a recommendation, rather than silently working longer. Mention feature flags or incremental releases if you used them to ship safely.
  4. Protect the parts that must not slip, such as tests on money-handling or data-integrity code, and review of risky changes, and say which polish you consciously skipped and logged as follow-up work.
  5. Avoid answers that rely on long hours or on agreeing to everything. They show no judgment about priority.

Follow-up

  • What exactly did you cut, and who agreed to cutting it?
  • How would you handle a major requirement change after the code was already in review?
  • How do you stop shortcuts taken for a deadline from becoming permanent technical debt?

What are your expectations regarding team culture, and how do you mentor junior engineers or contribute to pee

Medium · Behavioral & Project Experience

What are your expectations regarding team culture, and how do you mentor junior engineers or contribute to peer code reviews?

Approach

  1. Answer both halves with behavior, not adjectives. For culture, say what you want from a team in observable terms, such as small pull requests, reviews that return quickly, blameless incident write-ups, and clear ownership of services, and give one example where you helped create it.
  2. For code review, describe your checklist: correctness and edge cases, tests, readability and naming, security points such as parameterised queries and input validation, and performance of database access. Separate blocking comments from optional ones and phrase feedback as a question or a reason.
  3. For mentoring, give a specific case: how you paired with a junior engineer on a first task, gave context before the answer, delegated a bounded feature with check-ins, and how you knew they had grown, for instance by owning a later review.
  4. Also show how you receive review: a time a comment changed your approach. A story only about giving feedback sounds one-sided.
  5. The common mistake is generic praise for collaboration with no incident behind it.

Follow-up

  • How do you respond when a senior colleague's pull request has a design you disagree with?
  • What do you do when a junior engineer keeps repeating the same mistake?
  • How do you keep reviews fast without letting quality drop?