Interview guides · BOFA
BOFA Software Engineer Interview Guide
BOFA Software Engineer interview guide: the three reported rounds, coding, system design and behavioral questions with approaches and a 7-day plan.
The 60-second brief
BOFA is a bank, and candidates describe the Software Engineer role as building and maintaining software for its financial services customers. The projects they list include financial applications, data analytics and security systems, and the day-to-day work covers designing and developing applications, working with product management, UX/UI design and operations, taking part in code reviews, and troubleshooting defects. The requirements candidates describe name Java, Python or C++, with Spring, React and Docker as tools that may come up.
This guide is for candidates preparing for a Software Engineer interview at BOFA. It covers the three reported rounds and the five groups of reported questions: technical fundamentals, coding, system design, problem-solving scenarios and behavioral prompts. Candidates say the questions vary by team, so treat the list as a map of question types. The requirements candidates describe also mention Agile and Scrum, Git, algorithms and data structures, and, as nice-to-haves, AWS or Azure, microservices, front-end basics and financial services experience.
Candidates report three rounds over about three to five weeks: a Phone Screening, a series of Technical Interviews, and an In-Person Interview with a hiring manager.
Focus areas
- Problem Solving (Coding Challenges)
- System Design
- Algorithms - Sorting (Bubble Sort)
Overview
The projects candidates list for this role touch financial applications, security systems and data analytics. You do not need domain knowledge to answer the reported questions, but your examples will land better if they show care for correctness, input validation and what happens when a dependency fails. When you explain a resume project, say what the failure modes were and how you handled them.
The reported questions fall into five groups. Fundamentals: polymorphism, stack versus queue, REST design principles, why teams use Git, and SQL query optimization. Coding: bubble sort, two numbers that add up to a target, reversing a linked list, a dynamic programming problem such as Fibonacci, and a palindrome check. System design: a URL shortening service, distributed system considerations, a microservices architecture, SQL versus NoSQL, and reliability and availability. Problem-solving scenarios: a project falling behind, prioritizing several projects, a bug found just before a release, user feedback, and pivoting from a solution. Behavioral prompts round out the list. The topic breakdown candidates describe also mentions coding on a whiteboard, so practise writing solutions by hand in one language, without autocomplete.
Because the loop is short, every stage has to be covered by a specific answer rather than general reading. Pick one of Java, Python or C++ and use it for every coding answer. Prepare a sheet for each resume project (your part, the stack, one trade-off, one thing that went wrong), because the phone screening and the final interview are both described as exploring your background. Spend the technical days on the reported coding problems and a few design outlines you can talk through, and keep the last day for stories you can tell with concrete decisions in them.
The BOFA interview process
Candidates describe three stages over about three to five weeks. What follows is their account rather than a published schedule, and they say the questions vary by team.
Phone Screening
Candidates describe the Phone Screening as a first call built around your resume and a basic check of technical understanding. Treat it as two jobs: explain your own projects clearly, and answer the fundamentals out loud without a keyboard. The reported fundamentals questions (polymorphism, stack versus queue, REST principles, the purpose of Git, SQL query optimization) are the natural material to rehearse for a call like this.
What to demonstrate
- How well you can explain your resume projects and your own part in them
- Whether you can state core concepts correctly in spoken form
- Basic technical understanding across object-oriented design, data structures, APIs and SQL
How to prepare
- For each resume project, write your role, the stack, one design trade-off you made and one defect or setback, so none of your own bullets catches you out.
- Give each reported fundamentals question a spoken answer with an example: a Java-style interface with two implementations for polymorphism, or the push/pop versus enqueue/dequeue behavior for stack and queue.
- For SQL optimization, rehearse a fixed sequence: read the execution plan, check indexes on filter and join columns, avoid functions on indexed columns, select only needed columns.
Technical Interviews
Candidates report multiple Technical Interviews that may include coding challenges and system design discussions, and their topic breakdown lists coding on a whiteboard. Expect to produce code by hand in a language you choose from the stack the role lists (Java, Python or C++), then discuss its complexity and edge cases. For the design discussions, work in a fixed order: requirements, API, data model, components, bottlenecks, failure handling.
What to demonstrate
- Working code for the coding challenges, written without an IDE
- Complexity analysis and edge-case handling for algorithm problems
- Design reasoning and trade-offs for distributed systems, microservices and data stores
How to prepare
- Write the five reported coding problems by hand until each is correct on the first pass: bubble sort, two numbers that sum to a target, reverse a linked list, a Fibonacci-style dynamic programming problem, and a palindrome check.
- State time and space complexity for each and name one edge case (empty input, a single element, duplicates, negative numbers).
- Outline the URL shortening service end to end, then reuse its parts (id generation, storage choice, caching, replication) for the distributed systems and reliability questions.
- Prepare a clear comparison of SQL and NoSQL stores and a sketch of how you would split an application into microservices, including which service owns which data.
In-Person Interview
Candidates describe the In-Person Interview as a final conversation with a hiring manager about your past experiences and career aspirations. The reported behavioral and problem-solving scenario questions are the practice material: stories from your own work with decisions, results and what you would change. Have a clear answer for why you want this role and what you want to build next.
What to demonstrate
- Depth and ownership in the experiences you describe
- How you reason through project situations such as delays, priorities and late bugs
- Whether your career aspirations are specific and connect to this role
How to prepare
- Write story outlines for the challenging project, team conflict, fast learning, and taking the lead, each naming your own decisions in the first person.
- Prepare one real example each for a project running late, competing priorities, a bug found before a release, and a pivot away from your first solution.
- Write a short, specific answer to why you want to work at BOFA, built from the role's listed work and stack and your own experience.
- Prepare a few questions about the team's projects and stack to ask the hiring manager.
Where candidates lose points
Writing bubble sort from memory with no early exit and no complexity discussion
Write it by hand with nested passes and a swapped flag that stops when a pass changes nothing. State O(n^2) worst case, O(n) on already-sorted input, in place and stable, and test it on empty, one-element and duplicate inputs.
Answering polymorphism or REST design with a definition and no example
Back each answer with a short concrete case in your chosen language: a base type with two overriding implementations called through the same reference, or resource nouns, HTTP verbs, status codes and idempotent PUT and DELETE for a resource you name.
Starting the URL shortener or microservices design by drawing boxes without stating requirements
Open with scope and numbers you assume: read-to-write ratio, key length, expiry. Then give the API, id generation and collision handling, the store, caching for redirects, and how it behaves when a node fails.
Being unable to go deeper on a resume project when asked about the data model, a bug or a trade-off
Keep a one-page sheet per project with your role, stack, the main trade-off and one failure. Cut any bullet you cannot defend.
Answering the late-project, priority, late-bug and pivot questions with generic process steps
Use one real case for each. For the pre-release bug, show the order: reproduce, assess impact, tell stakeholders, choose between fix, rollback and delay, then add a test.
Questions & practice
Write a function to implement bubble sort.
Medium · Coding / Algorithms
Approach
- Describe the algorithm: repeatedly pass through the array and swap adjacent pairs that are out of order. After pass i, the i largest values are in their final places at the end, so the inner loop only needs to run to n-1-i.
- Write it with an early-exit flag: for i in range(n-1): swapped = False; for j in range(n-1-i): if a[j] > a[j+1]: swap them and set swapped = True; after the inner loop, if not swapped: break. The flag makes the best case O(n) on already sorted input.
- State the properties. Worst and average case are O(n^2). The number of swaps equals the number of inversions, so reverse-sorted input needs n(n-1)/2. Extra space is O(1). The sort is stable because it swaps only on a strict >; using >= would break stability.
- Test the edge cases aloud: empty array, one element, all equal values, duplicates, negatives, already sorted, reverse sorted.
- Compare it to real choices. Insertion sort is also O(n^2) but is usually faster on nearly sorted data. Production libraries use O(n log n) algorithms: Timsort (stable) for Python and Java objects, dual-pivot quicksort for Java primitives.
Follow-up
- Is bubble sort stable? What change to the comparison would break that?
- What determines how many swaps it performs on a given input?
- When would you choose merge sort over quicksort?
Given an array of integers, find two numbers that add up to a specific target.
Medium · Coding / Algorithms
Approach
- Clarify the contract: return indices or values? Is there exactly one answer? Can the same element be used twice? Can values repeat or be negative? Is the array sorted?
- Start with the brute force: check every pair with two nested loops. That is O(n^2) time and O(1) space.
- Then the one-pass hash map: for each index i with value x, if target - x is already in the map, return [seen[target - x], i]; otherwise store seen[x] = i. Checking before inserting stops an element pairing with itself and handles duplicates such as [3, 3] with target 6. This runs in O(n) average time and O(n) space.
- If the input is sorted, or you are allowed to sort it, use two pointers moving inward. That is O(n log n) including the sort and O(1) extra space, but sorting loses the original indices unless you carry them along.
- Handle the remaining edge cases: decide what to return when no pair exists, and in Java or C++ consider overflow when computing target - x with fixed-width integers (use long).
Follow-up
- How would you return all unique pairs instead of one?
- Extend this to three numbers that sum to the target. What is the complexity?
- What changes if the numbers arrive as a stream too large to keep in memory?
How would you reverse a linked list?
Medium · Coding / Algorithms
Approach
- Use the iterative three-pointer method: prev = null and curr = head. While curr exists, save next = curr.next, set curr.next = prev, then advance prev = curr and curr = next. Return prev as the new head. This is O(n) time and O(1) space.
- Give the recursive version: reverse the rest of the list, then set head.next.next = head and head.next = null. It is also O(n) time but uses O(n) stack space, so a long list can overflow the stack (Python's default recursion limit is 1000).
- Check the edge cases: an empty list, a single node, two nodes. Make sure the old head ends up pointing to null so no cycle is left, and return the new head rather than the old one.
- Trace it aloud on 1 -> 2 -> 3, showing prev, curr and next at each step. For a doubly linked list, swap each node's prev and next pointers instead.
Follow-up
- Reverse only the nodes between positions m and n.
- Reverse the list in groups of k nodes.
- Check whether a linked list is a palindrome in O(1) extra space.
Solve a problem involving dynamic programming, such as the Fibonacci sequence.
Medium · Coding / Algorithms
Approach
- Show why plain recursion fails: F(n) = F(n-1) + F(n-2) recomputes the same subproblems, so the number of calls grows exponentially (about 1.618^n). Overlapping subproblems are what make this a dynamic programming problem.
- Top-down memoization: cache each F(k) in a dictionary or with functools.lru_cache. That gives O(n) time and O(n) space, plus recursion depth.
- Bottom-up tabulation: fill from the base cases F(0) = 0 and F(1) = 1. Then notice each step needs only the previous two values and keep just two variables: O(n) time, O(1) space. Reject negative n.
- Mention overflow: F(92) is the largest Fibonacci number that fits in a signed 64-bit integer, so F(93) overflows a Java long. Python integers do not overflow, and many problems ask for the result mod 1,000,000,007.
- Generalise the recipe: define the state, the recurrence, the base cases and the evaluation order. Apply it to climbing stairs, coin change or house robber. For huge n, matrix exponentiation or fast doubling computes F(n) in O(log n).
Follow-up
- You can climb 1 or 2 steps at a time. How many ways are there to climb n steps?
- Find the minimum number of coins that make a given amount.
- How would you compute F(10^18) mod m?
Write a function to check if a string is a palindrome.
Medium · Coding / Algorithms
Approach
- Clarify the rules: case-sensitive or not, ignore spaces and punctuation or not ('A man, a plan, a canal: Panama'), whether an empty string counts as a palindrome, and whether Unicode matters.
- Use two pointers from both ends. Skip characters that are not alphanumeric, compare the rest lowercased, and return false on the first mismatch. That is O(n) time and O(1) extra space.
- A simpler version builds the cleaned lowercase string and compares it with its reverse (clean == clean[::-1]). It is still O(n) time but uses O(n) extra space; say so.
- Cover the edge cases: empty string, one character, even and odd lengths, a string of only punctuation. In Java, use Character.isLetterOrDigit and Character.toLowerCase, and use a StringBuilder rather than concatenating in a loop.
Follow-up
- Is the string a palindrome if you may delete at most one character?
- Find the longest palindromic substring.
- Check whether an integer is a palindrome without converting it to a string.
How do you optimize a SQL query for performance?
Medium · Technical / Domain Questions
Approach
- Measure first. Read the actual plan (EXPLAIN ANALYZE in PostgreSQL, the actual execution plan in SQL Server or Oracle) and find the costliest node: a sequential scan of a large table, a nested loop over a large outer input, or a sort spilling to disk. Large gaps between estimated and actual rows point to stale statistics (run ANALYZE).
- Index for the predicates. Put B-tree indexes on WHERE, JOIN and ORDER BY columns. In a composite index, put equality columns first and the range column last, and remember the leftmost-prefix rule. A covering index allows an index-only scan. The cost is slower writes and extra storage.
- Keep predicates sargable. Wrapping the indexed column in a function (YEAR(created_at) = 2024, LOWER(email)), implicit type casts, and LIKE patterns that start with a wildcard all block a normal index. Rewrite them as range predicates or add an expression index.
- Cut the work the query does: select only the columns you need instead of SELECT *, filter before joining and aggregating, replace correlated subqueries with joins or EXISTS, use keyset pagination instead of a deep OFFSET, and batch N+1 queries coming from the application.
- Look beyond the statement: partition very large tables by date, use materialized views for repeated aggregates, cache results, and check whether the query is waiting on locks rather than doing work.
Follow-up
- The query uses an index but got slower as the table grew. What could explain that?
- When does adding an index make performance worse?
- Why does OFFSET pagination degrade on deep pages, and what replaces it?
What are the trade-offs between SQL and NoSQL databases?
Medium · System Design / Architecture
Approach
- Relational databases: a fixed schema, joins, ACID transactions across rows and tables, and constraints (foreign keys, unique, check) that protect integrity. They fit ledgers and transaction records well. They scale up vertically and out with read replicas, but sharding takes deliberate work.
- NoSQL is several families: key-value (Redis, DynamoDB), document (MongoDB), wide-column (Cassandra) and graph (Neo4j). They offer flexible schemas and are built for horizontal partitioning, often with eventual or tunable consistency. You model data around known access patterns and denormalise instead of joining.
- Decide on concrete criteria: the shape of the data and its relationships, whether query patterns are known in advance, consistency and integrity needs, write volume and scale, and what the team can operate.
- The line has blurred: PostgreSQL stores JSONB, MongoDB has supported multi-document transactions since 4.0, and distributed SQL systems (Spanner, CockroachDB) scale out with SQL semantics. Many systems combine stores, for example a relational system of record with a cache or search index beside it.
Follow-up
- Which would you choose for account transaction history, and why?
- How do you model a one-to-many relationship in a document store?
- What does eventual consistency mean for a user who reads their own write immediately?
Explain polymorphism in object-oriented programming.
Medium · Technical / Domain Questions
Approach
- Define it in one line: one interface, many implementations, with the call resolved by the object's actual type. Then split it into compile-time polymorphism (method overloading, chosen by the static argument types; generics or C++ templates) and runtime polymorphism (overriding, resolved by dynamic dispatch).
- Give a concrete example: an interface PaymentMethod with pay(amount), and Card and BankTransfer classes that implement it. The caller holds a PaymentMethod reference and never branches on the type. In Java every non-static, non-final, non-private method dispatches dynamically. In C++ the method must be marked virtual, or a call through a base pointer runs the base version. Python dispatches through duck typing.
- Explain why it matters: a new type can be added without editing callers (open/closed principle). It replaces switch statements on type codes, and it lets tests substitute mocks behind the same interface.
- Name the traps. Overloads are picked at compile time, so a variable declared as Object calls the overload that takes Object even when it holds a String. Static methods are hidden, not overridden. Java fields are not polymorphic. A subclass that weakens the base contract breaks Liskov substitution.
Follow-up
- What is the difference between overloading and overriding, and which one is decided at compile time?
- How does C++ implement virtual dispatch, and what does it cost per object and per call?
- When would you choose composition over inheritance to get the same flexibility?
What are the differences between a stack and a queue?
Medium · Technical / Domain Questions
Approach
- State the core difference: a stack is LIFO (push, pop and peek at the top), a queue is FIFO (enqueue at the tail, dequeue at the head). Both run their core operations in O(1).
- Cover implementations. A stack sits naturally on a dynamic array (amortised O(1) push). A queue needs a circular buffer or a linked list with head and tail pointers. In Java, use ArrayDeque for both rather than the legacy synchronized Stack class. In Python, use a list as a stack and collections.deque as a queue, because list.pop(0) is O(n).
- Tie each one to its uses. Stacks: the call stack, undo, DFS, matching brackets, expression evaluation. Queues: BFS, task scheduling, buffers between producers and consumers, message queues.
- Mention the variants: a deque allows both ends, a priority queue is a heap with O(log n) insert and remove and is not FIFO, and a blocking queue (Java's BlockingQueue) is used for producer-consumer concurrency.
Follow-up
- Implement a queue using two stacks. What is the amortised cost per operation?
- How would you build a stack that also returns its minimum in O(1)?
- In a bounded producer-consumer queue, what should happen when the queue is full?
Can you describe the principles of RESTful API design?
Medium · Technical / Domain Questions
Approach
- Model resources as nouns with stable URIs (/accounts/{id}/transactions) and let the HTTP method carry the verb. GET is safe and idempotent, PUT and DELETE are idempotent, POST is not, and PATCH is not guaranteed to be.
- Make it stateless: each request carries its own authentication (for example a bearer token), so any instance can serve it and the service scales horizontally. Support caching with Cache-Control and ETags: If-None-Match returns 304, and If-Match gives optimistic concurrency with a 412 on mismatch.
- Use status codes precisely: 201 with a Location header on create, 204 for an empty success, 400 or 422 for validation errors, 401 (not authenticated) versus 403 (not allowed), 404, 409 for conflicts, 429 for rate limits. Return one consistent error body that clients can branch on.
- Cover the practical concerns. Cursor pagination beats OFFSET on large or changing collections. Filtering and sorting go in query parameters. Version through the URI (/v1) or a header. An idempotency key on POST endpoints that move money lets a retry return the original result instead of creating a second transfer.
Follow-up
- A client times out on POST /transfers and retries. How do you guarantee only one transfer happens?
- When would you use PUT rather than PATCH?
- How would you make a breaking change without breaking existing clients?
What is the purpose of using version control systems like Git?
Medium · Technical / Domain Questions
Approach
- Give the purpose: a full history of every change (who, what, why), the ability to revert or compare versions, parallel work on branches with controlled merging, code review through pull requests, and an audit trail of what shipped.
- Explain the Git model. It is distributed, so every clone holds the full history. Commits are content-addressed snapshots, identified by hashes and linked into a DAG. A branch is a movable pointer to a commit, which is why branching is cheap.
- Describe a team workflow: short-lived feature branches, pull requests that pass review and CI, and tags for releases. Compare trunk-based development with GitFlow. On merge versus rebase: rebase gives a linear history but rewrites commits, so never rebase a branch others have pulled.
- Name the recovery tools. git revert adds a commit that undoes another and is safe on shared branches. git reset moves the branch pointer and rewrites history. git bisect binary-searches the commits to find the one that introduced a bug, in about log2(n) steps. git reflog recovers commits that no branch points to any more.
Follow-up
- Walk me through resolving a merge conflict.
- You pushed a bad commit to a shared branch. How do you undo it?
- When would you squash commits, and what do you lose by doing it?
How would you design a URL shortening service?
Medium · System Design / Architecture
Approach
- Scope it. Functional: create a short code for a long URL, redirect, and optionally support custom aliases, expiry and click analytics. Non-functional: redirects far outnumber creates, so the read path dominates. State volume as an assumption.
- Define the API: POST /urls with the long URL returns a code, and GET /{code} redirects. A 301 is cached by browsers, which cuts load but hides repeat clicks from analytics; a 302 sends every click through the service.
- Generate codes by base62-encoding a unique numeric ID: 7 characters give 62^7, about 3.5 trillion codes. The alternatives are a truncated hash of the URL with a collision check, or random codes with a uniqueness check. Sequential IDs are guessable; say whether that matters.
- Store code -> long URL in a key-value store, or a relational table keyed on the code. Since mappings rarely change, cache hot codes in Redis with LRU eviction or at a CDN.
- Scale and protect it. Allocate ID ranges per server, or use a Snowflake-style generator, so servers never collide. Replicate the store. Publish click events asynchronously so analytics never slows a redirect. Rate-limit creation and scan target URLs for abuse.
Follow-up
- Should the same long URL shortened twice get the same code?
- How do many servers generate unique IDs without coordinating on every request?
- How would you expire links, and can expired codes be reused?
What considerations do you take into account when designing a distributed system?
Medium · System Design / Architecture
Approach
- Treat failure as normal: networks partition, nodes crash, and some nodes are just slow. Every remote call needs a timeout, plus retries with exponential backoff and jitter, and operations must be idempotent so a retry cannot apply twice.
- Choose consistency per kind of data. CAP says that during a partition you must give up either consistency or availability; PACELC adds the latency-versus-consistency trade-off when there is no partition. An account balance needs strong consistency, while an activity feed can be eventually consistent.
- Plan data distribution: leader-follower replication or quorums (R + W > N gives overlapping reads and writes), a partition key that avoids hot spots, and consistent hashing so adding nodes moves only a fraction of the keys.
- Coordinate carefully. Avoid distributed transactions where possible and use sagas with compensating actions or a transactional outbox. Use consensus (Raft, via etcd or ZooKeeper) for leader election. Never order events by wall-clock time across machines because of clock skew.
- Build in observability and protection: metrics, centralised logs, distributed tracing with correlation IDs, health checks, backpressure and load shedding.
Follow-up
- How would you move money between two services' databases without two-phase commit?
- A retry fires after the first request actually succeeded. What happens, and how do you make that safe?
- Explain how a quorum read can still return stale data.
Describe how you would architect a microservices-based application.
Medium · System Design / Architecture
Approach
- Split services by business capability (for example accounts, payments, notifications). Each service owns its data store and no database is shared. If the domain boundaries are still unclear, start with a modular monolith and extract services later.
- Pick communication per interaction: synchronous REST or gRPC when the caller needs an answer now, and asynchronous events on a broker (Kafka, RabbitMQ) to decouple services. An API gateway handles routing, authentication and rate limiting, and service discovery locates instances.
- Handle consistency without cross-service ACID transactions. Use sagas (choreographed or orchestrated) with compensating steps, a transactional outbox so events are published exactly when the local write commits, and idempotent consumers because brokers redeliver.
- Design for resilience and delivery: timeouts, retries, circuit breakers and bulkheads. Package services in containers (Docker), run them under an orchestrator such as Kubernetes, give each service its own CI/CD pipeline, and version APIs independently (Spring Boot is a common Java base).
- State the costs: network latency, operational overhead, distributed tracing and centralised logging become mandatory, and testing needs contract tests between services.
Follow-up
- How does one service find and call another?
- A downstream service in a chain of calls is down. What does the user see?
- When would you advise against microservices?
How do you ensure system reliability and availability?
Medium · System Design / Architecture
Approach
- Define the targets first. Choose SLIs such as success rate and p99 latency, set SLOs on them, and use an error budget to balance shipping speed against stability. Each extra nine of availability cuts the allowed downtime tenfold.
- Remove single points of failure: run redundant instances across availability zones behind load balancers with health checks, and replicate the database with automated failover. Dependencies in series multiply, so two 99.9% services in a chain give about 99.8%.
- Fail gracefully: timeouts, retries with backoff and jitter, circuit breakers, rate limiting, load shedding, and degraded modes such as serving cached data when a dependency is down.
- Ship changes safely with canary or blue-green deployments, feature flags, automated rollback, and backward-compatible schema migrations (expand, then contract).
- Detect and recover: alert on SLO burn rather than raw CPU, keep runbooks and an on-call rotation, write blameless postmortems, and test backup restores against defined RPO and RTO targets.
Follow-up
- What is the difference between reliability and availability?
- How would you prove that failover actually works before you need it?
- What RPO and RTO would you set for a payments database, and what do they cost?
How would you approach a situation where a project is falling behind schedule?
Medium · Problem-Solving / Case Studies
Approach
- Quantify it first: how far behind, against which milestone, and why. Re-estimate the remaining work with the people doing it, and find the cause: scope creep, underestimation, a blocked dependency, or unplanned production work.
- Lay out the levers: cut or defer scope (separate the must-haves from the nice-to-haves), move the date, remove blockers, or add people. Brooks's law warns that adding people to a late project often slows it further. Never treat quality or testing as a lever to cut quietly.
- Tell stakeholders early and bring options with their trade-offs, not just the bad news. Record the decision that comes out of it.
- In Agile or Scrum terms: track the slip with a burndown chart and velocity, adjust sprint scope, surface blockers at stand-up, and fix the estimation problem in the retrospective. Tell it in the first person, with a real example if you have one.
Follow-up
- The deadline is regulatory and cannot move. What do you do?
- The slipping piece belongs to a teammate. How do you handle it?
- What would you change so this does not happen on the next project?
Describe how you would prioritize tasks when given multiple projects.
Medium · Problem-Solving / Case Studies
Approach
- Put all the work in one visible list. Rank it by impact and urgency (an Eisenhower matrix works), by the cost of delay, and by dependencies: work that unblocks other people goes first.
- Separate hard deadlines (release dates, compliance dates) from soft ones. Size each item roughly so cheap, high-value items are visible.
- When two projects truly compete, settle it with your manager or the stakeholders instead of deciding alone, and make the trade-off explicit: what slips if this goes first.
- Limit work in progress, time-box exploratory work, re-rank when new information arrives, and tell the people affected when their item moves down.
Follow-up
- Two stakeholders each say their item is the top priority. What do you do?
- An urgent production issue lands mid-sprint. How do you re-plan?
- How do you tell someone their request has been pushed back?
What steps would you take if you identified a critical bug just before a release?
Medium · Problem-Solving / Case Studies
Approach
- Assess before acting: reproduce the bug and establish its blast radius. Which users or data are affected? Is it a regression in this release or already in production? Is there data corruption or a security exposure?
- Lay out the options with the release owner: fix forward if the fix is small and testable, switch the feature off behind a flag, revert the offending commit, or delay the release. A known data-integrity or security defect should not ship.
- If you fix it: write a failing test that reproduces it, make the smallest change that passes, run the full regression suite and CI, and get a review. Do not bundle other changes into the fix. git bisect can find the commit that introduced a regression.
- Keep stakeholders updated as the decision is made. After the release, find the root cause: why did the tests miss it? Add the coverage that would have caught it.
Follow-up
- The business insists on shipping on the original date. How do you respond?
- The bug only reproduces in production. How do you investigate it safely?
- What would you change so this class of bug is caught earlier?
How do you incorporate user feedback into your development process?
Medium · Problem-Solving / Case Studies
Approach
- Gather feedback from several channels: support tickets, in-app feedback, usability sessions, analytics and telemetry, and experiments. Self-reported feedback and observed behaviour often disagree.
- Triage it: remove duplicates, classify each item (bug, usability problem, feature request), and estimate how often it happens and how much it costs users. Separate the problem the user describes from the solution they suggest.
- Turn the valid items into backlog entries with clear acceptance criteria, and prioritise them with the product owner against the existing roadmap.
- Ship in small increments, behind feature flags where possible, measure whether the target metric moved, and tell users what changed.
Follow-up
- The feedback contradicts what the usage data shows. Which do you trust?
- One vocal customer wants a feature nobody else asks for. What do you do?
- How would you show that a change made in response to feedback actually helped?
Discuss a scenario where you had to pivot from your original solution.
Medium · Problem-Solving / Case Studies
Approach
- Open with the original approach and why it was a reasonable choice at the time, in a sentence or two, so the change of course does not sound like carelessness.
- Name the concrete signal that it was failing: a benchmark that missed the target, a load test that broke it, a requirement that changed, or a dependency that turned out unworkable. A story without evidence sounds like a guess.
- Explain how you chose the new direction: the alternatives you weighed, the cost of switching against the cost of continuing (ignoring sunk cost), and who you consulted before committing.
- Describe the switch: what you reused, how you limited risk (a feature flag or a parallel run), and the measurable result. Then the lesson, all in the first person. What sinks this answer is blaming others or presenting the change as luck.
Follow-up
- Looking back, how could you have spotted the problem earlier?
- What did the change of direction cost in time or rework?
- What would you have done if your team had disagreed with switching?
Every query on one table stalls for forty seconds mid-deploy
Medium · lock contention · ddl · migrations
During a release on PostgreSQL, every query touching resource times out for about 40 seconds and then recovers with no intervention. The release ran one migration, ALTER TABLE resource ADD COLUMN archived_reason TEXT, and the migration log shows it completing in 6 ms. Unrelated tables showed no change in error rate. Explain how a 6 ms statement caused a 40-second stall, give the ordered checks you would run on a live system to confirm it, and give the migration procedure that prevents a repeat.
Approach
- Separate the statement's duration from the lock's duration. ADD COLUMN with no default is a catalogue-only change and genuinely runs in milliseconds, but it requires ACCESS EXCLUSIVE, and it cannot acquire that until every transaction already touching the table has finished.
- Account for the queueing, which is the part that surprises people. A lock request that is waiting blocks later requests for conflicting modes behind it rather than letting them overtake, so one long-open transaction holds the DDL and the DDL holds all the traffic. The stall length is set by the longest open transaction, not by the size of the change.
- Confirm on a live system in this order: pg_stat_activity for that table ordered by xact_start, looking for the oldest transaction and specifically for state = idle in transaction; then pg_locks where granted = false to find the waiter; then join them on pid to name blocker and blocked. pg_blocking_pids() does that join for you and is the fastest single call.
- Prevent rather than merely time it better. Set lock_timeout to a second or two on the migration session so the DDL abandons the queue after a bounded wait and is retried, instead of holding it for as long as the oldest transaction lives. Be exact about what that buys: queries arriving during the wait still queue behind the pending ACCESS EXCLUSIVE request, so each attempt costs them up to one lock_timeout of added latency. The outage goes from 40 seconds to about one second per attempt, not to zero. Also run migrations away from deploy-time peaks, and put a statement timeout and an idle-in-transaction timeout on the analytics role that opens the long transactions.
Follow-up
- The same release also wants NOT NULL on that column. What is the sequence that gets there without a long lock?
- Your lock_timeout retry fails ten times in a row because the analytics transaction is always open. What do you change?
Suggested practice checklist
The plan moves from spoken fundamentals and hand-written coding to design, then scenarios and stories, mirroring the three reported rounds and using the reported questions for each day.
Day 1 — Resume sheets and spoken fundamentals
- Write a sheet for each resume project: your role, stack, one trade-off and one setback.
- Write and say aloud answers to the polymorphism, stack versus queue and Git questions, each with a small example.
Deliverable: One project sheet per resume project and three short spoken answers (polymorphism, stack versus queue, Git), each with an example.
Day 2 — REST design and SQL optimization
- Write the REST principles with a resource of your choice: noun-based URLs, verbs, status codes, idempotency and versioning.
- Take a slow query on a table you can test, read its execution plan, add or fix an index, and record the before and after.
Deliverable: A REST endpoint table for one resource, plus a query with its before and after plan notes.
Day 3 — Bubble sort and two-sum by hand
- Write bubble sort in your chosen language with a swapped flag, then state its complexity, stability and best case.
- Write the two-numbers-to-a-target problem as brute force and as a hash map pass, and compare the complexity of the two.
Deliverable: Two hand-written solutions with complexity notes and a list of test cases for each.
Day 4 — Linked list, dynamic programming, palindrome
- Reverse a singly linked list iteratively with three pointers, then recursively, and note the stack cost of the recursive version.
- Write Fibonacci three ways: naive recursion, memoized, and bottom-up with constant space.
- Write the palindrome check with two pointers, then handle case and non-alphanumeric characters.
Deliverable: Three solutions with complexity notes: linked list reversal, Fibonacci in three forms, and the palindrome check.
Day 5 — System design: URL shortener and distributed systems
- Outline the URL shortening service: API, id generation and collisions, storage, caching, redirect behavior.
- List the distributed-system concerns you would raise: partitioning, replication, consistency, retries and timeouts.
- Sketch a microservices split for an application of your choice, naming which service owns which data.
Deliverable: A diagram and notes for the URL shortener, a distributed-systems checklist, and a microservices split with data ownership.
Day 6 — Data stores, reliability and scenario answers
- Build a comparison table of SQL and NoSQL stores by data shape, consistency, scaling and query needs.
- Write a reliability checklist: redundancy, health checks, timeouts, retries, monitoring, rollback.
- Outline one real example each for a late project, competing priorities, a bug before release, user feedback and a pivot.
Deliverable: A SQL versus NoSQL table, a reliability checklist and five scenario outlines taken from your own work.
Day 7 — Behavioral stories and a full rehearsal
- Write STAR outlines for the challenging project, team conflict, learning fast and taking the lead questions.
- Write your answer to why you want to work at BOFA and what you hope to achieve.
- Run through every story and one coding problem aloud, then trim any answer that hides your own role.
Deliverable: Five story outlines (four STAR stories and the why-BOFA answer) rehearsed aloud once.
Behavioral and leadership stories
Candidates report that the final In-Person Interview with a hiring manager explores past experiences and career aspirations, and the reported list includes five behavioral and leadership prompts. Prepare each as a short story from your own work in which your decisions are visible, and keep a separate answer for why this role and what you want next.
- Discuss a scenario where you had to pivot from your original solution.
Describe a challenging project you worked on. What was your role?
Medium · Behavioral / Leadership
Approach
- Choose a project from your resume where you owned a defined piece, not one where you only observed. Set the scene briefly: the system, the goal and what made it hard (a legacy constraint, unclear requirements, a performance target or a tight dependency).
- Separate your actions from the team's. Say 'I designed', 'I decided', 'I wrote' for your parts and name teammates for theirs, so your role is unmistakable.
- Spend most of the answer on the decision points: the options you weighed, the one you chose, and the evidence behind it (a prototype, a measurement, a code review discussion).
- Close with the result in terms you can defend (defects fixed, latency reduced, a release shipped) and one thing you would change if you ran the project again.
- The mistake that sinks this answer is a story where the difficulty was only the amount of work, or where 'we' hides who did what.
Follow-up
- Which part of that project did you write yourself, and what would a reviewer have flagged in it?
- What alternative design did you reject, and why?
- If you ran the project again, what would you do differently?
How do you handle conflicts within a team?
Medium · Behavioral / Leadership
Approach
- Choose a real disagreement about something concrete: a design approach, review feedback, a priority call or an estimate. Avoid a story where the other person was simply wrong, and avoid claiming you have never had a conflict.
- Show the order of your steps: you asked questions until you could state their position fairly, agreed on the shared goal (shipping a correct release, for example), then moved the argument to evidence such as a benchmark, a small prototype or bug history.
- Say how it was decided: one option adopted, a hybrid, or an escalation to a tech lead or manager with both options written down. Name the decision rule you used.
- End with the outcome and the working relationship afterwards, and what you now do earlier to prevent the same conflict.
- The mistake that sinks this answer is describing the other person's flaws instead of your own actions.
Follow-up
- What if the evidence had not settled it and you still disagreed?
- How would the approach differ if the disagreement were with your manager or a product owner?
- Did you change your own view at any point, and what changed it?
Can you give an example of a time you had to learn a new technology quickly?
Medium · Behavioral / Leadership
Approach
- Choose a technology that matches the stack the role lists or a close neighbor (a framework like Spring or React, a cloud service, a new language, a container tool), and state the deadline or task that forced you to learn it.
- Describe a method, not just effort: you scoped what the task actually needed, read the official documentation for that slice, built a small throwaway spike, read existing code in the repository, wrote tests to confirm your understanding, and asked a colleague specific questions.
- Give proof that you learned it: a feature shipped, a review that passed, a bug you diagnosed in the new tool.
- Name something you got wrong first and how you corrected it, and what you did to leave notes for the next person.
- The mistake that sinks this answer is 'I watched tutorials' with no deliverable and no mistakes.
Follow-up
- How did you decide what to skip and what to learn deeply?
- What did you get wrong first, and how did you find out?
- How do you keep your skills current when no deadline forces it?
Why do you want to work at BOFA, and what do you hope to achieve?
Medium · Behavioral / Leadership
Approach
- Build the answer from three parts: what draws you to the work, what you want to achieve, and why your background fits. Keep each part tied to something specific you can say honestly.
- For the first part, use what candidates describe about the role: financial applications, data analytics and security systems, plus work with product, UX/UI and operations teams. Connect one of these to a project or interest of your own rather than praising the company in general.
- For the second part, name concrete goals: the skills you want to build (for example, designing services in Java or running software on AWS or Azure) and the kind of ownership you want to reach.
- For the third part, point to the stack in your experience: the languages, Git, Agile or Scrum practice and any microservices or front-end work that matches the listed requirements.
- The mistake that sinks this answer is repeating mission slogans or reusing an answer that would fit any employer.
Follow-up
- Where do you want your career to be a few years from now?
- What would you want to learn in your first year in this role?
- What other options are you considering, and how does this one compare?
Tell me about a time you took the lead on a project.
Medium · Behavioral / Leadership
Approach
- Use the STAR structure: Situation, Task, Action, Result. Leading does not need a title; pick a case where something lacked an owner and you took it.
- Show the mechanics of leading in the Action: you defined the goal and scope, split the work into tasks, agreed who took each, set up a regular check-in, unblocked others, and reviewed work.
- Include one hard moment, such as a teammate falling behind, scope changing or a disagreement on approach, and say exactly what you did about it.
- Report the result and give credit to others accurately, then state what you learned about leading.
- The mistake that sinks this answer is a story where you did all the work yourself, or one with no other people in it.
Follow-up
- How did you decide who took which part of the work?
- What did you do when a teammate was not delivering?
- What happened when the scope changed midway?