Interview guides · Commonwealth Bank of Australia
Commonwealth Bank of Australia Software Engineer Interview Guide
Commonwealth Bank of Australia Software Engineer interview guide: reported rounds, technical and behavioral questions, and a 7-day prep plan.
The 60-second brief
Commonwealth Bank of Australia is a bank, and candidates describe its Software Engineer role as building the software behind banking products: mobile payments, cloud-hosted financial services, microservices, payment-platform security and data pipelines. Reported team stacks differ. Candidates mention Java with Spring Boot, .NET with React, and AWS-based environments, and the listed requirements add REST API design, SQL with transaction management, and CI/CD. Kubernetes, Docker, Kafka or JMS, and TypeScript appear as extras.
This guide is for engineers interviewing for a Software Engineer role at Commonwealth Bank of Australia. It covers the four reported stages, the nine technical and four behavioral questions candidates report, and a seven-day plan that adds the coding and concurrency scenarios candidates describe. Leadership and mentoring are reported mainly for senior roles, so the behavioral section includes prompts for them.
Candidates report four stages over roughly 3-5 weeks: an Online Assessment, Technical Discussions, Behavioral Discussions and Final Technical Panels. The process varies by business unit and location.
Focus areas
- React
- React Context API
- Technical interviews
Overview
The work candidates describe is backend-heavy and money-adjacent: scalable microservices, secure payment platforms, data pipelines, and for some teams a React front end. Reported stacks vary by team (Java/Spring Boot, .NET/React, AWS-based cloud-native work), so the first preparation decision is to pick the stack on your resume and be ready to go deep in it, including concurrency, performance tuning and the testing story around dependency injection.
The reported questions fall into three groups. Five are engineering fundamentals: the pillars of object-oriented programming, abstract classes versus interfaces, dependency injection and testing, REST versus RESTful with PUT versus POST, and OS deadlocks. Four are architecture questions: a real-time fraud detection system, microservices communication against a monolith, relational versus NoSQL database design, and API security with JWT and OAuth. Four are behavioral. Candidates also describe live coding or code review scenarios, such as fixing a threading problem in a payment processing module and writing an LRU cache with O(1) operations, plus design prompts about a real-time transaction dashboard and handling high-frequency payment requests.
Expect to connect theory to something concrete. Candidates say the technical stages mix concept questions with real-world scenarios or code snippets, so every fundamentals answer should include a short example from your own project or a few lines of code. The advice candidates pass on is to explain why you chose something, not only how it works, and to be able to account for every project, certification or internship on your resume.
The behavioral stage is described as an assessment of cultural fit and interpersonal skills, with integrity, collaboration and secure, reliable customer experiences mentioned in candidate preparation advice. Four reported prompts (a team conflict, convincing stakeholders, staying current with technology, and missing a deadline) are enough to build a story bank. Write them out with specifics before the loop begins.
The Commonwealth Bank of Australia interview process
Candidates describe four stages over roughly 3-5 weeks, and they say the exact shape varies by business unit and location. The descriptions below are reports, not a published process.
Online Assessment
Candidates report that the loop opens with an automated assessment of initial skills. Its format is not described in detail, so prepare for both fundamentals and code: the reported coding topics are arrays, linked lists, trees and hash maps, and the reported fundamentals are OOP, interfaces, dependency injection, REST and concurrency. Aim for working, readable code with a stated time and space complexity, since candidates report that complexity analysis comes up in coding discussions.
What to demonstrate
- Initial skills, checked through an automated assessment
- Core data structures and algorithms on arrays, linked lists, trees and hash maps
- Working, readable code in your main language
How to prepare
- Write an LRU cache with O(1) get and put from scratch, using a hash map plus a doubly linked list, then state its complexity
- Re-solve one array, one linked-list and one tree problem in your main language without an IDE
- Review the practice set coding problems on overlapping intervals and per-key aggregation for hash-map technique
Technical Discussions
Candidates report multiple deep-dive technical discussions with peer engineers and technical leads. Live coding or code review is described for technical interviews, and the reported question types here are fundamentals (OOP, abstract classes versus interfaces, dependency injection, REST, deadlocks) and design (fraud detection, microservices, database choice, API security). Reported scenarios include fixing a threading issue in a payment processing module. Answer every concept question with a definition, a trade-off and an example from your own project.
What to demonstrate
- Depth in your primary stack, including performance tuning, concurrency and best practices
- Clean-code and SOLID knowledge, shown in code or code review
- Applying concepts to real-world scenarios or code snippets
How to prepare
- Write a small service with constructor injection, then test it with a fake in place of the real dependency
- Write a deadlock in Java or C# with two locks, fix it with consistent lock ordering, and explain the four conditions it needed
- Review a short pull request out loud, naming one SOLID violation and the refactor that fixes it
Behavioral Discussions
Candidates report behavioral discussions aimed at cultural fit and interpersonal skills, and describe collaboration with architecture, operations and product teams as a constant part of the role. Four reported prompts cover a team conflict, convincing stakeholders of a technical vision, staying current with technology and a missed deadline. Prepare these as STAR stories with your own decisions and a concrete result for each.
What to demonstrate
- Cultural fit and interpersonal skills, as candidates describe the stage
- Collaboration across engineering, architecture, operations and product
- Ownership of your own decisions and their results
How to prepare
- Write one STAR story for each of the four reported prompts, with a named decision and a measurable or observable result
- Prepare the conflict and missed-deadline stories so that your own action takes up most of the time, not the background
- For a senior role, add one story about mentoring someone and one about balancing technical debt against feature delivery
Final Technical Panels
Candidates describe final technical panels, with assessment centers possible, to close the process. The reported design material includes real-time fraud detection, microservices versus a monolith, relational versus NoSQL storage, API security, a real-time transaction dashboard and handling high-frequency payment requests. Candidates also report being asked to defend resume items in detail, so bring a design you can walk through end to end.
What to demonstrate
- System design for high-volume, low-latency, secure services
- Microservice concerns candidates list: service discovery, circuit breakers and distributed tracing
- Security thinking around authentication, authorization and sensitive data in APIs
How to prepare
- Design a real-time fraud scoring service on paper: ingestion, a stream such as Kafka, a low-latency decision path, a fallback if scoring is down
- Prepare a microservices-versus-monolith comparison with one concrete case where you would keep the monolith
- Draw an OAuth 2.0 authorization flow with a JWT access token, and list what you validate on each request
Where candidates lose points
Reciting the four OOP pillars like a textbook with no example from your own project
For each pillar, prepare one sentence of definition and one concrete use, such as encapsulation hiding a payment state machine or polymorphism swapping a payment provider. Tie dependency injection to a test that replaces a real client with a fake.
Answering abstract classes versus interfaces without naming your language's actual rules
State the rules for your language: Java default and static interface methods, C# default interface members, single inheritance of classes against many interfaces, and when shared state or a constructor makes an abstract class the right choice.
Designing the fraud detection or payment system as a happy path with no failure handling
Add the failure story to every design: idempotency keys on payments, a timeout and circuit breaker on the scoring call, a fallback decision when scoring is unavailable, a dead-letter queue for failed events, and tracing across services.
Treating API security as 'use JWT' without explaining authentication versus authorization
Separate who the caller is (OAuth 2.0 or OpenID Connect login) from what they may do (scopes, roles, per-resource checks). Cover token expiry, signature and audience validation, refresh handling, and never putting sensitive data in a token.
Naming a resume item you cannot explain, or telling behavioral stories in 'we' with no personal action
Before the loop, write the architecture, one hard problem and the result for each resume line, and rewrite each story so your own decisions are the middle of it.
Questions & practice
Find overlapping job attempts and peak concurrency from lease records
Medium · sweep line · intervals · leases
A day of job_run history yields about 50,000,000 attempt records: (job_run_id, job_type, attempt, started_at, finished_at which is NULL when the worker died, lease_expires_at). Leases expire on a clock, so a job that outran its lease ran twice. Produce (a) every job_run_id whose attempts overlapped in wall-clock time and (b) the peak number of simultaneously running attempts per job_type with the minute it occurred. Target O(n log n). State how you treat a NULL finished_at and what clock skew does to your answer.
Approach
- Define the interval before sorting anything: an attempt occupies [started_at, COALESCE(finished_at, lease_expires_at)). finished_at is observed and lease_expires_at is only a promise, so every attempt without a finish contributes an estimate and the whole result is a lower bound on overlap rather than an exact count.
- For peak concurrency, sweep: emit 2n endpoints, sort by (timestamp, kind) with ends ordered before starts at equal timestamps, then walk the sequence maintaining a counter per job_type and record each type's maximum with its timestamp. O(n log n) dominated by the sort, O(n) space, or O(1) extra if the sort is external and the walk streams.
- For overlap detection, do not compare attempts pairwise. A single global sort by (job_run_id, started_at) gives both the grouping and the order; within a group, keep the maximum end seen so far and report an overlap exactly when the next start is less than that running maximum, which is one linear pass after the sort.
- Half-open intervals matter and are easy to get wrong: with closed intervals an attempt ending at the same millisecond another begins reads as concurrency two, and across 50,000,000 records that artefact swamps the real signal.
Follow-up
- A handler is not idempotent and you have found 400 overlapping jobs. Which of them actually caused damage, and what would you query to find out?
- Peak concurrency for one job_type is 4 against a configured cap of 4. Is the cap working, or is the data hiding attempts that never started?
Collapse a redelivered event batch into per-aggregate high-water marks
Easy · hashing · at-least-once · aggregation
You drain a batch of up to 5,000,000 events, each (aggregate_id BIGINT, aggregate_version INT, event_type, payload). The log guarantees order within one aggregate only; the batch merges 64 partitions, and a relay failover has redelivered a range, so an older version for an aggregate can appear after a newer one. Given a map of last_applied_version per aggregate, produce the events worth applying, at most one per (aggregate_id, version), plus the count discarded. Target O(n) time. State the memory for 2,000,000 distinct aggregates and what you do when it does not fit.
Approach
- One pass, one hash map from aggregate_id to the highest version kept, and a discard counter. An event whose version is at or below last_applied_version for its aggregate is dropped without further work, which is the whole reason the event carries its version rather than a delta. O(n) expected time, O(d) space in distinct aggregates.
- Keep the maximum, never the last occurrence. The redelivered range means the final appearance of an aggregate in the batch can be an older version than one seen earlier in the same batch, so last-wins applies stale state over newer state and the projection regresses with no error anywhere.
- Cost the memory instead of calling it large: an 8-byte key plus a 4-byte version is 12 bytes of payload, and an open-addressed table held at a 0.7 load factor costs roughly 17 bytes per entry before per-slot metadata, so 2,000,000 aggregates is tens of megabytes in a native layout and several times that in a runtime that boxes both key and value.
- If the distinct set exceeds memory, partition on hash(aggregate_id) mod P and reduce each partition independently. Every event for one aggregate hashes to the same partition, so the per-partition result is exact and the merge is concatenation rather than a second reduction.
Follow-up
- The payload is a patch rather than a snapshot, so applying only the highest version loses the intermediate changes. What changes in your reduction?
- How do you detect that version 7 arrived while version 6 was never delivered, and what should the consumer do about the gap?
Identify the heaviest tenants in a five-minute window under memory pressure
Medium · top-k · heavy hitters · streaming
The edge service handles about 3,000 requests per second across roughly 50,000 tenants, peaking near 9,000. Expose the 50 heaviest tenants by request count over the trailing five minutes so limits can be tightened before one tenant's backfill starves the fleet. You may not retain five minutes of raw records. Give the exact solution and its memory, then the bounded-memory approximation with its error stated as a formula, and say which you would ship and at what tenant cardinality that choice changes.
Approach
- Do the exact version first, because it is affordable at this cardinality: a ring of 300 one-second counters per tenant, advanced lazily, is 1,200 bytes of counters per tenant and roughly 60 to 90 MB for 50,000 tenants with overhead. Carry a running total and subtract the bucket you overwrite so a window read is O(1) rather than 300 adds.
- Extract the top 50 with a size-k min-heap over the tenant sums: O(d log k) for d tenants, against O(d log d) to sort them all. Maintaining the heap continuously instead of on query requires a tenant-to-heap-index map, because incrementing a count already inside the heap means sifting from a known position, and without that map you rebuild the heap on every request.
- State the approximation precisely rather than gesturing at sketches. Misra-Gries with m counters retains every item whose true count exceeds N/(m+1), and each retained count underestimates the truth by at most N/(m+1). With m = 1,000 and N = 900,000 requests in the window the error is roughly 900 requests, which is fine for spotting a tenant sending 50,000 and useless for ranking two tenants 200 apart.
- Say what breaks when the window slides: Misra-Gries and Space-Saving are insert-only and cannot be decremented as records age out. The workable construction is one summary per sub-window, say ten seconds, with 30 summaries merged at query time, and the merged error is the sum of the per-summary errors, so the bound degrades linearly in the number of sub-windows.
Follow-up
- The heaviest tenant is heavy because of one export job rather than user traffic. Should the limiter treat those as the same tenant?
- Two tenants sit tied at the boundary of the top 50. Does your answer flap, and does the flapping matter?
Write the update path that detects a concurrent edit
Medium · optimistic concurrency · transactional outbox · audit history
resource carries version INT NOT NULL DEFAULT 1. resource_revision holds revision_id, resource_id, version, actor_user_id, change_kind, patch JSONB, request_id, created_at with UNIQUE (resource_id, version). outbox_event holds aggregate_type, aggregate_id, aggregate_version, event_type, payload, status. A PUT carries the version the client read. Write the exact statements for the single transaction that applies the edit, records the revision and enqueues 'resource.updated', and give the handler's branch on zero affected rows. Then say what PostgreSQL 16 does under READ COMMITTED when two of these updates hit one row at once.
Approach
- One transaction, three writes, no network call inside it: UPDATE resource SET title = $3, version = version + 1, updated_at = now() WHERE resource_id = $1 AND tenant_id = $4 AND version = $2; then INSERT the resource_revision row at version $2 + 1; then INSERT the outbox_event row at the same aggregate_version. The event goes to a table rather than a broker because no transaction spans both.
- Branch on the affected-row count before doing anything else. Zero has three causes — stale version, wrong tenant, row gone — so re-read once and map to 409 carrying the current version, or 404 for an id outside the caller's tenant, which also stops the endpoint confirming that another tenant's id exists.
- State the engine behaviour instead of assuming it. Under READ COMMITTED the second UPDATE blocks on the row lock, and when the first commits PostgreSQL re-evaluates the WHERE clause against the newly committed row, so the version predicate now fails and the statement reports zero rows. Under REPEATABLE READ the identical collision raises SQLSTATE 40001 instead, so the handler must fold both shapes into one conflict response.
- Keep UNIQUE (resource_id, version) even though the predicate already serialises writers. It is what makes a lost update unwritable if any other path ever reaches the revision table, and it converts a logic bug into 23505 rather than into a silently missing history row.
Follow-up
- A client sends the version it read ten minutes ago and the resource has moved three versions. What is in your 409 so it can resolve the conflict without a full re-fetch?
- Two editors, two disjoint fields, no overlap. Does your answer still refuse the second write, and should it?
Stop tag and share joins from fanning out a page
Medium · join fan-out · semi-joins · many-to-many
resource_tag is (resource_id, tag_id) with PK (resource_id, tag_id); resource_share is (resource_id, shared_with_user_id, permission). The tagged-and-shared listing inner-joins resource to both, filters tenant_id, tag_id = ANY($2) and shared_with_user_id = $3, orders by updated_at DESC and takes 50. Pages come back with fewer than 50 distinct resources and the total in the header is far too high. Explain the row multiplication, rewrite both the page query and the count query so each is correct, and name the index each one needs. PostgreSQL 16.
Approach
- Do the arithmetic against the predicates that are actually there. An inner join emits one row per matching child row, and both joins are filtered: tag_id = ANY($2) admits only the requested tags, shared_with_user_id = $3 admits one user's share rows. So a resource holding three of the requested tags and shared with $3 once yields three rows, not one — the multiplier is its count of matching tags times its share rows for that single user, and that second factor is 1 unless the table admits duplicate (resource_id, shared_with_user_id) pairs. LIMIT 50 then limits rows rather than resources, and COUNT(*) counts pairs — the header is the product, not the population.
- Reject DISTINCT as the fix. It deduplicates after the product has been built, so the planner must materialise and sort the fanned-out set before the LIMIT can apply, and it leaves any SUM or AVG in the same select list wrong.
- Rewrite both filters as semi-joins, keeping resource as the only row source: AND EXISTS (SELECT 1 FROM resource_tag rt WHERE rt.resource_id = r.resource_id AND rt.tag_id = ANY($2)) and the same shape against resource_share. A semi-join stops at the first match per resource and preserves the driving index order, so ORDER BY updated_at DESC, resource_id DESC LIMIT 50 still stops after 50 rows.
- Count with the same predicates and no join at all: SELECT count(*) FROM resource r WHERE r.tenant_id = $1 AND r.status = 'active' AND EXISTS (...) AND EXISTS (...). Nothing multiplies a resource, so the number is the population.
Follow-up
- The filter changes from 'any of these tags' to 'all of these tags'. Rewrite it and state what it costs relative to the ANY form.
- A resource can be shared with the same user twice under different permissions. Does your count change, and should it?
Explain the four pillars of Object-Oriented Programming (OOP) and how you apply them in your current project.
Medium · Technical Fundamentals
Approach
- Name all four and define each in one line: encapsulation (private state changed only through methods that guard invariants), abstraction (callers depend on what a type does, not how), inheritance (is-a reuse of a base type), polymorphism (one call site, behaviour chosen by the runtime type).
- Anchor every pillar in one class from your own project, e.g. an Account whose balance is private and changes only through debit/credit methods that reject an overdraft, and a PaymentGateway interface the service calls without knowing the vendor SDK behind it.
- Separate overriding (runtime dispatch on the object's actual type) from overloading (resolved at compile time from argument types), and show polymorphism replacing a switch on a type field.
- Give the trade-off on inheritance: deep hierarchies create fragile base classes, so prefer composition and keep subclasses substitutable for their base (Liskov); in Java a class extends only one class but can implement many interfaces.
Follow-up
- Where did inheritance cause a problem in your code, and how would you refactor it to composition?
- How does polymorphism let you add a new payment type without editing existing code?
- Is a class with getters and setters for every field encapsulated? Why or why not?
What is the difference between abstract classes and interfaces in your preferred language?
Medium · Technical Fundamentals
Approach
- Pick the language and be exact. In Java an abstract class can hold instance fields, constructors and any access modifier, and a class extends only one; an interface's fields are implicitly public static final, and a class can implement many interfaces.
- Cover modern interfaces: Java 8 added default and static methods, Java 9 private methods; C# 8 added default interface implementations. The remaining difference is state and constructors, not whether a method can have a body.
- State the decision rule: an interface for a capability shared by unrelated types (Comparable, a Repository contract); an abstract class when subclasses share state or a fixed algorithm with overridable steps (template method).
- Mention the common combination: an interface as the public type plus an abstract skeletal class that implements most of it, as java.util.AbstractList does for List.
- Edge case: if a Java class inherits the same default method from two interfaces, it does not compile until the class overrides it, and it can call a specific one with InterfaceName.super.method().
Follow-up
- Why does an abstract class have a constructor if it can never be instantiated?
- What breaks for existing implementers when you add a method to a published interface, and how do default methods change that?
- Would you model a fee calculation rule as an interface or an abstract class? Why?
How does Dependency Injection work, and why is it beneficial for testing?
Medium · Technical Fundamentals
Approach
- Define it: an object receives its collaborators from outside instead of constructing them with new, so it depends on an abstraction and the wiring lives in one place (a container such as the Spring ApplicationContext or .NET IServiceCollection, or a hand-written composition root).
- Prefer constructor injection: dependencies are explicit, fields can be final, the object is never half-built, and a test can construct it with plain new. Field injection hides dependencies and needs reflection or the container to set them.
- Explain the testing benefit concretely: pass a Mockito mock or an in-memory fake of the repository or payment client, so the unit test runs with no database, network or container and can force failures such as a timeout.
- Name lifetimes and the trap: singleton, scoped (per request) and transient; injecting a scoped dependency into a singleton keeps one instance alive for the whole application (a captive dependency).
- Call out circular dependencies: with constructor injection the container cannot build either bean and fails at startup, which points to a missing third abstraction or misplaced responsibility.
Follow-up
- Why choose constructor injection over field injection?
- How is dependency injection different from a service locator, and why does that matter for tests?
- How would you break a circular dependency between two services?
Describe the difference between REST and RESTful APIs; when would you use PUT vs POST?
Medium · Technical Fundamentals
Approach
- Separate the terms: REST is the architectural style (client-server, stateless, cacheable, uniform interface, layered system, optional code on demand); a RESTful API is one that follows those constraints, with resources as nouns and HTTP methods carrying the action.
- PUT replaces the whole resource at a URI the client knows and is idempotent: repeating it leaves the same state. POST asks the server to create a resource or run a process, the server assigns the id, and it is not idempotent; return 201 Created with a Location header.
- Use PATCH for partial updates; a PUT whose body omits fields should be treated as clearing them, which surprises clients that expected a merge.
- For a payment created by POST, make retries safe with a client-supplied idempotency key that the server stores with the first result and replays on a duplicate request.
- Handle concurrent updates with ETag and If-Match, returning 412 Precondition Failed when the version has changed, so two PUTs cannot silently overwrite each other.
Follow-up
- A client's POST for a payment times out. How does it retry without charging twice?
- When would you choose PATCH over PUT?
- Which status codes would you return for a validation failure, a missing resource and a version conflict?
Design a real-time fraud detection system; how would you ensure scalability and low latency?
Medium · System Design & Architecture
Approach
- Fix scope first: a synchronous decision on the authorisation path (approve, decline or step-up) under an agreed latency budget, plus an asynchronous path for slower analysis and analyst review. Clarify transaction volume, the budget and the cost of a false decline.
- Synchronous path: gateway, then a stateless scoring service that reads precomputed features from a low-latency key-value store, applies rules and a model, and returns a decision. It scales horizontally because it holds no state.
- Feature pipeline: publish every transaction to a log such as Kafka keyed by card or account id, so one partition sees each account's events in order; a stream processor keeps windowed aggregates (transactions per card in the last few minutes, new device, distance from the last location) and writes them to the online store.
- Decide failure behaviour explicitly: if the feature store or model times out, fall back to rules or a fail-open/fail-closed policy by amount; make scoring idempotent on transaction id; log the decision, features and model version so every decline can be explained.
- Close the loop: chargebacks and analyst verdicts become labels for retraining; fraud is heavily imbalanced, so judge models on precision and recall at the operating threshold, and run a new model in shadow mode before it can decline anything.
Follow-up
- The online feature store is down. Do you approve, decline or degrade, and what decides that?
- How do you handle late or out-of-order events in the velocity windows?
- How would you roll out a new model without raising false declines?
How do you handle microservices communication, and what are the trade-offs between monolithic and microservice
Medium · System Design & Architecture
How do you handle microservices communication, and what are the trade-offs between monolithic and microservice architectures?
Approach
- Split by interaction: synchronous REST or gRPC when the caller needs the answer now; asynchronous events or queues (Kafka, JMS) when it does not, which decouples availability and absorbs load spikes.
- For synchronous calls, list the protections: a timeout on every call, retries only on idempotent operations with exponential backoff and jitter, a circuit breaker (e.g. Resilience4j) to stop hammering a failing dependency, bulkheads, service discovery, and trace ids propagated for distributed tracing.
- For events: delivery is usually at least once, so consumers must be idempotent (dedupe on event id); use the transactional outbox to commit a database change and its event together; Kafka keeps order only within a partition, so key by the entity whose order matters.
- Without a shared transaction across services, use a saga: a sequence of local transactions with compensating actions (e.g. release a funds hold when a later step fails) instead of two-phase commit.
- Trade-offs: a monolith gives in-process calls, one ACID database, simple deploys and easier debugging; microservices give independent deploy and scaling and fault isolation, at the cost of network failure modes, eventual consistency and heavier operations. A modular monolith is a valid middle ground.
Follow-up
- How do you make sure an event is published if and only if the database write committed?
- One slow downstream service is taking the whole call chain down. What stops the cascade?
- When would you merge two services back together?
Explain your approach to database design—when would you choose a relational database over a NoSQL solution?
Medium · System Design & Architecture
Approach
- Start from access patterns and invariants, not the product: list the queries, write rates and rules that must never break, then model entities, keys and constraints; normalise transactional data (around 3NF) and denormalise only for measured read paths.
- Choose relational when you need multi-row ACID transactions (a transfer debits one account and credits another), enforced constraints (foreign keys, unique, check), joins and ad-hoc reporting. Store money as DECIMAL/NUMERIC, never floating point.
- Choose a NoSQL store when access patterns are known and narrow, write volume or data size needs horizontal partitioning, or the schema varies; the cost is limited joins, design-per-query modelling and weaker or tunable consistency.
- Cover concurrency: pick an isolation level deliberately (read committed allows lost updates on read-modify-write) and prevent them with SELECT ... FOR UPDATE or an optimistic version column checked in the UPDATE's WHERE clause.
- Indexes: a composite B-tree index serves queries on its leftmost columns, so order columns by how queries filter; every index also slows writes. Mixing stores (a relational ledger plus a document or cache store for reads) is a legitimate answer.
Follow-up
- Model an account ledger: do you store a balance column, derive it from entries, or both?
- Which isolation level would you use for a funds transfer, and what anomaly does it prevent?
- Writes outgrow one relational primary. What are your options?
How do you ensure API security, particularly regarding authentication and authorization (e.g., JWT, OAuth)?
Medium · System Design & Architecture
Approach
- Separate the two: authentication proves who the caller is, authorisation decides what it may do. OAuth 2.0 is a delegated authorisation framework; OpenID Connect adds authentication with an ID token on top of it.
- Pick flows by client: authorisation code with PKCE for browser and mobile apps (the implicit flow is discouraged), client credentials for service-to-service; access tokens short-lived, refresh tokens rotated.
- Validate a JWT properly: it is signed, not encrypted by default, so no secrets in claims; verify the signature against the issuer's keys (JWKS) with an allow-listed algorithm (never 'none', no RS256/HS256 confusion), then check iss, aud, exp and nbf. In Spring Security this is the OAuth2 resource server configuration.
- Authorisation is not just a scope check at the gateway: each service must verify the caller owns the object it requests (an account id in the URL), since broken object-level authorisation is the top OWASP API risk.
- Round it out: TLS everywhere (mTLS between services), rate limiting, input validation, secrets in a vault, and logs that never contain tokens or personal data. Stateless JWTs are hard to revoke, so use short expiry, a jti denylist or opaque tokens with introspection.
Follow-up
- A user's token is stolen. How do you revoke it before it expires?
- What attack does PKCE prevent?
- Where should a browser app keep its tokens, and what does each choice expose it to?
Explain the concept of deadlocks in Operating Systems and how to prevent them.
Medium · Technical Fundamentals
Approach
- Define a deadlock as a set of threads or processes each waiting for a resource another holds, and list the four Coffman conditions that must all hold: mutual exclusion, hold and wait, no preemption, circular wait.
- Prevention breaks one condition. The usual one is circular wait: acquire locks in a global order, e.g. for a transfer between two accounts always lock the lower account id first, whichever direction the money moves.
- Break hold and wait or no preemption with timed acquisition: Java ReentrantLock.tryLock(timeout, unit), release everything held on failure and retry with randomised backoff so the threads do not livelock.
- Contrast avoidance (Banker's algorithm checks every request against a safe state) with detection and recovery: build a wait-for graph and abort a victim on a cycle, which is what relational databases do, so updating rows in a consistent order matters there too.
- Say how you would find one in a running JVM: a thread dump (jstack) reports a Java-level deadlock with the locks involved, and ThreadMXBean.findDeadlockedThreads() exposes it programmatically.
Follow-up
- transfer(A, B) and transfer(B, A) run at the same time. Write the locking so they cannot deadlock.
- What is the difference between deadlock, livelock and starvation?
- Your service hangs and CPU is idle. What do you capture first?
Suggested practice checklist
The plan follows the reported stages: a resume audit first, then fundamentals, coding, design, and finally the four behavioral stories and a full mock. Practice-set coding and SQL problems are used where the reported scenarios call for them.
Day 1 — Map the loop and audit your resume
- Write out the four reported stages, Online Assessment, Technical Discussions, Behavioral Discussions and Final Technical Panels, and mark the one you are least ready for.
- For every project, certification or internship on your resume, write the architecture, one hard problem and the result.
- Decide which stack you will go deep in (Java/Spring Boot, .NET, React or another) and list five topics in it you could be pressed on.
Deliverable: A one-page loop map, a resume audit sheet with architecture, problem and result for each line, and your chosen stack with five topics.
Day 2 — OOP, interfaces and dependency injection
- Write spoken answers for the four OOP pillars, each with an example from your own project.
- Write a short comparison of abstract classes and interfaces with the actual rules in your language.
- Build a small service with constructor injection and a unit test that swaps in a fake; if React is on your resume, replace prop drilling with the Context API in one component.
Deliverable: Two spoken answers plus a working injected service with its test, and a Context example if React applies.
Day 3 — REST, API security and deadlocks
- Write a PUT versus POST answer covering idempotency and the status codes you would return.
- Draw an OAuth 2.0 flow with a JWT access token and list the checks the API makes on each request.
- Create a two-lock deadlock in code, fix it with lock ordering, and recite the four conditions.
Deliverable: A PUT versus POST answer, an OAuth and JWT diagram with validation checklist, and a deadlock demo with its fix.
Day 4 — Coding: structures and concurrency scenarios
- Implement an LRU cache with O(1) operations and state its complexity.
- Do two practice-set coding problems, the overlapping lease attempts one and the redelivered event batch one, writing the complexity for each.
- Write a short payment counter that is wrong under concurrency, then repair it with a lock or atomic operation and explain why.
Deliverable: A tested LRU cache, two solved practice problems with complexity notes, and a before-and-after concurrency fix.
Day 5 — System design and data
- Design a real-time fraud detection system on paper: ingestion, a stream, a scoring path, storage, and what happens when scoring is down.
- Write a microservices-versus-monolith comparison covering communication styles (synchronous calls against events), failure handling and one case for staying monolithic.
- Write the relational-versus-NoSQL answer with transactions and SQL in mind, then do the practice-set SQL problem on detecting a concurrent edit.
Deliverable: A fraud detection design diagram with failure modes, a one-page architecture comparison, a database-choice answer, and one solved concurrent-edit query.
Day 6 — Write the four behavioral stories
- Write STAR outlines for the conflict, stakeholder-buy-in, staying-current and missed-deadline prompts.
- Rewrite each so your own actions take most of the story and each ends with a concrete result.
- Say each aloud and cut anything the listener does not need.
Deliverable: Four STAR stories, each with a named decision and a result, written out and spoken once.
Day 7 — Full mock panel
- Run a mixed mock: one fundamentals answer, one design question, one live coding task and two behavioral questions, back to back.
- Have a friend ask follow-ups on your resume items and design choices.
- List every answer where you hesitated and rewrite it before the loop.
Deliverable: A recorded or written mock with a list of weak answers and their rewrites.
Behavioral stories for the Commonwealth Bank of Australia loop
Candidates describe the behavioral stage as a discussion about cultural fit and interpersonal skills, in a role that works closely with architecture, operations and product teams. The reported prompts below cover conflict, influence, learning and a missed deadline. Prepare each as a STAR story in your own voice, with a decision you made and a result you can describe.
- Tell me about a time you had to balance technical debt against delivering a feature quickly.
- Tell me about a time you mentored a teammate or set a technical standard for your team.
Tell me about a time you had to handle a conflict within your team; how did you reach a resolution?
Medium · Behavioral & Leadership
Approach
- Choose a conflict about a real technical or ownership issue, such as an API design, a review disagreement or priority clashes over who owned a failing component, not a personality clash. Set the scene briefly: who disagreed, about what, and what was at stake for the project.
- State the other person's position in terms they would accept as fair. This shows you understood it before you tried to settle it.
- Describe the specific steps you took: a one-to-one conversation, a small spike or benchmark to replace opinion with evidence, a written decision record, or bringing in the tech lead when it could not be settled. Use I for your actions.
- End with the outcome and the relationship afterward: what was decided, how the delivery went, and whether you worked well together after. Add one thing you would change.
- The mistake that sinks it is a story where the other person is the villain, or where the result is only 'we compromised' with no detail about how.
Follow-up
- What was the strongest part of the other person's argument?
- What would you do if there had been no data to settle it?
- Did the relationship change afterward, and how do you know?
Describe a situation where you had to convince stakeholders to buy into your technical vision.
Medium · Behavioral & Leadership
Approach
- Pick a technical proposal you drove, such as splitting a service, adopting a message queue, or tightening authentication, and name every stakeholder: product, operations, security, architecture, your lead. Say what each cared about, whether risk, cost, delivery date or on-call load.
- Show how you translated the technical case into those concerns. For example, tie a refactor to fewer production incidents, or tie a security change to a concrete exposure it removes.
- Describe your evidence and your ask: a prototype, a cost estimate, an incident count from your own system, or a phased rollout with a rollback step. A small reversible first step is easier to approve than a large rewrite.
- Report the result honestly, including what stakeholders changed in your plan. Show you adapted the vision instead of only winning.
- The mistake that sinks it is a story where you were right and others were slow to see it; stakeholder concerns should be treated as legitimate.
Follow-up
- What was the hardest objection you heard, and how did you answer it?
- What would you have done if they had said no?
- How did you measure whether the change delivered what you promised?
How do you stay updated with industry trends, and how have you applied a new technology to a recent project?
Medium · Behavioral & Leadership
Approach
- Answer in two parts, as the question does. First, give your real habits: the release notes, conference talks, internal tech sessions, newsletters or open-source projects you actually follow in your stack (Java/Spring, .NET, AWS, React or similar). Name specific ones, because a vague list of buzzwords is easy to spot.
- For the second part, choose one technology you introduced or evaluated on a recent project and walk through STAR: the problem it addressed, how you tested it in a small spike, how you compared it with the current approach, and what risks you checked (compatibility, security, operations, team skill).
- Give the decision and outcome with something concrete: build time, error rate, lines removed, or developer feedback. Include rollout and rollback if it went into production.
- Strengthen the answer with a case where you evaluated something and chose not to adopt it, and say why. This shows judgment rather than novelty-seeking.
- The mistake that sinks it is adopting a technology because it was fashionable; tie the choice to a problem you had.
Follow-up
- Tell me about a technology you evaluated and rejected.
- How did you bring the rest of the team along with the new tool?
- What would have gone wrong if this had failed in production?
Tell me about a time you failed to meet a deadline or a project requirement; how did you communicate this to y
Medium · Behavioral & Leadership
Tell me about a time you failed to meet a deadline or a project requirement; how did you communicate this to your lead?
Approach
- Choose a real miss where your own estimate, planning or communication played a part, such as underestimated integration work or a late-discovered dependency. Avoid a fake failure like 'I care too much'; a candid story reads better than a polished one.
- Give the timeline in order: when you first saw the risk, when you told your lead, and what you brought with you. Telling your lead early, with options, is the part of the story that matters most.
- Lay out the options you presented, for example cut scope, move the date, add a person, or ship in phases, and which one was chosen and why. Say what you delivered and when.
- Close with what you changed afterward: smaller milestones, explicit buffer for integration and testing, earlier demos, or a standing risk check in stand-ups. Show that the change stuck.
- The mistake that sinks it is blaming others or hiding the delay until the last day; both suggest the problem would repeat.
Follow-up
- When did you first know the date was at risk, and what did you do that day?
- How did your lead react, and what would you do differently in that conversation?
- How do you estimate work now, compared with then?