Interview guides · Byline Bank.
Byline Bank. Software Engineer Interview Guide
Byline Bank. Software Engineer interview guide: reported rounds, questions and how candidates describe the process.
The 60-second brief
Byline Bank is a bank, and the Software Engineer role candidates describe sits on the technology side of its banking services. Reported project areas include mobile banking applications, data analytics tools and backend systems that carry transactions. Engineers build, test and maintain these applications, and the role description also ties the job to financial regulation and security standards. The listed stack is Java, C# or Python, a relational database such as SQL Server or Oracle, and web development frameworks, with AWS or Azure, Agile and DevOps practice named as extras.
This guide is for candidates interviewing for a Software Engineer position at Byline Bank.
Candidates report three stages over roughly three to five weeks: a Screening Call, one or more Technical Interviews, and Behavioral Interviews. The stages are what candidates describe, not a published process.
Focus areas
- Software Engineering (General)
- Interview Process Management
- Stakeholder Communication
Overview
The reported work spans three kinds of system: customer-facing mobile banking, analytics tooling, and backend services that carry transactions. For preparation that means two things. Your examples should show you can build and maintain software end to end, including code review, testing, troubleshooting and release. And any design answer should treat correctness as the first requirement: an operation that moves money has to be safe to retry, traceable and secured before it is fast.
The reported question list is broad rather than deep. It mixes general engineering questions (favourite languages, the software development lifecycle, code quality, version control), design questions (a scalable banking system, API design, monolith versus microservices), coding questions (reverse a string, state the complexity, explain a sorting algorithm) and a large block of behavioral and problem-solving prompts. Breadth means every answer needs a short, structured core you can deliver cleanly, plus one concrete example from your own work to back it up.
The stack candidates describe is Java, C# or Python with SQL Server or Oracle behind it. Pick the language you will code in and be fluent in its string handling, collections and sort functions. Be ready to talk about relational queries, indexes and transactions in plain terms, because backend transaction systems sit on a relational store. Cloud (AWS, Azure), Agile and DevOps are listed as extras, so have a sentence or two of real experience ready if you have it, and an honest account of what you have not used if you do not.
Behavioral prompts make up the largest group of reported questions: debugging a complex issue, a challenging team project, conflict, taking initiative, motivation, learning a technology quickly and a project falling behind. A handful of well-chosen stories, each rehearsed in a clear structure, covers all of them. Build that story bank early, because the same story can serve several prompts.
The Byline Bank. interview process
Candidates describe three stages in this order, taking roughly three to five weeks from first call to the end of the loop. Plan for each stage separately, since the first is a conversation about your background and the others are more demanding.
Screening Call
Candidates describe the Screening Call as an opening conversation about your background and your fit for the Software Engineer role. Treat it as the point where your CV, your stack and your reasons for applying get checked against the role description: Java, C# or Python, SQL Server or Oracle, web frameworks, and work on banking applications or backend systems. Go in with a clear account of what you have built and what you owned.
What to demonstrate
- Your background and how it lines up with the listed stack
- How clearly you can describe your own projects and your part in them
- Your reasons for wanting a banking-sector engineering role
How to prepare
- Write a short walkthrough of your last two projects: what the system did, which language and database it used, and which parts you personally built or fixed.
- Prepare an honest answer to the language question (what you prefer and why), tied to a real project rather than a ranking of languages.
- Map your experience onto the listed stack: note where you have used SQL Server or Oracle, a web framework, a cloud platform, Agile or DevOps tooling, and where you have not.
- Write two or three questions about the team, the codebase and how engineers work with product managers and designers.
Technical Interviews
Candidates describe one or more Technical Interviews that assess coding skill and problem-solving. The reported questions for this role span coding (reversing a string, stating complexity, explaining a sorting algorithm), system design (a scalable banking application, API design, monolith versus microservices), and engineering practice (code quality, version control, optimizing an existing application). Prepare for working code plus clear reasoning out loud.
What to demonstrate
- Working code and the ability to state its time and space complexity
- How you break down a design or optimization problem
- Practical engineering habits: code review, testing, version control, troubleshooting
How to prepare
- Write the reverse-a-string solution in your chosen language in two ways (built-in and in-place with two pointers), state the complexity of each, and list edge cases such as empty input, a single character and Unicode.
- Learn two sorting algorithms well, for example merge sort and quicksort, and be able to say when stability, memory use or nearly sorted input would change your choice.
- Outline a design for a scalable banking application in components: clients, API layer, services, relational store, queues, and how a retried transfer stays safe through idempotency keys and transactions.
- Prepare a measure-first answer to optimizing an existing application: profile, find the bottleneck, change one thing, measure again.
Behavioral Interviews
Candidates describe the Behavioral Interviews as conversations about collaboration and cultural fit. The reported prompts cover a challenging team project, conflict, initiative, debugging a hard issue, learning a technology fast, motivation and a project slipping behind. Prepare specific stories from your own work, told in your own words, each with your decision, the result and what you would change.
What to demonstrate
- Collaboration with teammates and cross-functional partners
- How you handle disagreement and pressure on a project
- Ownership: initiative, learning and following a problem through
How to prepare
- Write five stories in situation, task, action, result form: a hard debug, a team project, a conflict, an initiative and a fast learning curve.
- Attach one concrete number or outcome to each story (an incident avoided, a delay recovered, a defect rate fallen) that you can actually stand behind.
- Rehearse the stories aloud until each is short and clear, and decide which prompts each one can answer.
- Prepare an answer to what motivates you that points to real work you have done, not a general statement.
Where candidates lose points
Answering the reverse-a-string question with only the one-liner and no complexity or edge cases
Write the solution by hand with two pointers, say it runs in O(n) time, and name the cost of a copy versus an in-place version. Cover empty input, a single character, and what happens with multi-byte characters or immutable strings in your language.
Treating the banking design question as a generic scalable web app
Open by asking what must never go wrong. Name transactional writes, idempotent retries, an audit trail, authentication and authorization on every API, and separate the read path from the write path. Only then discuss caching and scaling.
Giving the textbook definition of the software development lifecycle or of monolith versus microservices with no experience behind it
Define the term in two sentences, then walk through a project where you lived it: how requirements arrived, how code review and testing ran, how a release went out, or why a monolith was or was not split.
Telling behavioral stories in the team's voice so your own contribution is unclear
For each story, say what you decided, wrote or changed, and who disagreed. Use I for your actions and name teammates' roles for theirs, then close with the result and a lesson.
Saying you would optimize an application by rewriting hot code straight away
Start by defining the slow behaviour and a metric, profile to find the actual bottleneck (queries, network calls, memory, a loop), change one thing at a time, and show the measurement before and after.
Questions & practice
Can you write a function to reverse a string?
Medium · Coding / Algorithms
Approach
- Clarify the input: can it be null or empty, is it ASCII or full Unicode, and should the result be a new string or an in-place reversal of a character array?
- Give the idiomatic answer and its cost: s[::-1] in Python, new StringBuilder(s).reverse().toString() in Java, or new string(arr) after Array.Reverse(arr) in C#. Each is O(n) time and O(n) space, because strings are immutable in all three languages.
- Write the two-pointer version: swap arr[i] and arr[j] while i < j, moving the pointers inward. It takes O(n) time and O(1) extra space on a mutable array. Avoid building the result with += in a loop, which can copy the string on every step (O(n^2)).
- Handle Unicode honestly: swapping UTF-16 code units splits surrogate pairs such as emoji, and code-point reversal still detaches combining accents. Java's StringBuilder.reverse keeps surrogate pairs together; reversing whole user-perceived characters needs a grapheme iterator (BreakIterator, StringInfo).
- Test the edges: empty string, one character, even and odd lengths, a palindrome, null where the language allows it. A recursive version works but uses O(n) stack and can hit Python's default recursion limit of 1000.
Follow-up
- Reverse the order of words in a sentence in O(n) time without a split library call.
- How would your function handle an emoji or an accented character built from two code points?
- Use your function, or the two-pointer idea, to check whether a string is a palindrome while ignoring case and punctuation.
What is the time complexity of your solution?
Medium · Coding / Algorithms
Approach
- Name the variables first (n = length of the string, m = number of words) and count the dominant operations in terms of them. Keep distinct inputs separate instead of collapsing everything into n.
- For the string reversal: O(n) time, since every character is visited once. Space is O(n) for the new string, or O(1) extra for an in-place two-pointer swap on a mutable array. It cannot beat O(n) time, because every character has to be read.
- Point out hidden costs in library calls: slicing and substring copy O(k),
inon a list is O(n) while a hash set is O(1) on average (O(n) worst case under collisions), sorting is O(n log n), and repeated string concatenation can be O(n^2). - Separate worst, average and amortised cases. Appending to a dynamic array or StringBuilder is amortised O(1) because capacity grows geometrically, even though a single append that triggers a resize is O(n).
- Count recursion in space complexity: a recursive solution uses stack frames proportional to its depth, O(n) for naive recursive string reversal.
Follow-up
- What is the space complexity, and does it change if the input may be modified in place?
- Can you prove no algorithm can do better than your bound for this problem?
- What is the difference between amortised O(1) and worst-case O(1)? Give an example of each.
Explain a sorting algorithm and its use cases.
Medium · Coding / Algorithms
Approach
- Explain one algorithm in depth, for example merge sort: split in half, sort each half recursively, merge two sorted runs. It takes O(n log n) time in every case, is stable, and needs O(n) extra memory for arrays. Its merge step also suits linked lists and external sorting.
- Contrast it with quicksort: O(n log n) on average, but O(n^2) worst case with a bad pivot, such as first-element pivots on sorted input. Random or median-of-three pivots make that unlikely. It sorts in place with O(log n) stack if you recurse on the smaller side first, is not stable, and is usually fast thanks to cache locality.
- Cover the rest briefly: heapsort is O(n log n) worst case with O(1) extra space, but not stable. Insertion sort is O(n^2) in general, O(n) on nearly sorted input, and is used for small subarrays. Counting and radix sort run in O(n + k) for bounded integer keys and beat the Ω(n log n) lower bound for comparison sorts.
- Know what your language actually uses: Java's Arrays.sort runs dual-pivot quicksort on primitives and a stable TimSort on objects. Python's sort is a stable, adaptive merge sort. C#'s Array.Sort is an unstable introsort, while LINQ OrderBy is stable.
- Give a concrete use case for stability: to order transactions by date, then by amount within a date, I sort by amount first and then by date with a stable sort, or I sort once with a composite key.
Follow-up
- Why does stability matter, and how would you sort by two keys with an unstable sort?
- How would you sort a 100 GB transaction file on a machine with 4 GB of memory?
- Which pivot strategy would you pick for quicksort, and what input defeats it?
Find version gaps and relay lag with window functions
Medium · window functions · event tables · frame semantics
outbox_event holds event_id, aggregate_type, aggregate_id, aggregate_version, event_type, payload, status ('pending','published','dead'), attempts, created_at, published_at. A projection is missing rows and you must decide whether the relay skipped events or the consumer dropped them. Write three queries over the last seven days: one listing every aggregate_id whose published aggregate_version sequence has a hole, one giving per-day counts with a running total, and one returning the newest published event per aggregate. For each, say where the window function is evaluated relative to WHERE and LIMIT. PostgreSQL 16.
Approach
- Gaps: compute lead(aggregate_version) OVER (PARTITION BY aggregate_id ORDER BY aggregate_version) in a subquery, then filter next_version <> aggregate_version + 1 in the outer query. Window functions are evaluated after WHERE, GROUP BY and HAVING and before the outer ORDER BY and LIMIT, so the predicate cannot sit in the same WHERE clause and PostgreSQL 16 has no QUALIFY.
- Say what the seven-day filter does to the answer: it truncates every partition, so the first row per aggregate has no predecessor inside the window and a hole spanning the boundary is invisible. Widen the window, or join to resource.version as the authority for the true maximum.
- Running total: SELECT date_trunc('day', created_at) AS d, count() AS n, sum(count()) OVER (ORDER BY date_trunc('day', created_at) ROWS UNBOUNDED PRECEDING). An aggregate inside a window call is legal because grouping runs before windowing. The grouping key is unique per row here so ROWS and RANGE agree, but write the frame anyway — over ungrouped rows with tied timestamps the default RANGE frame pulls in every peer row and the total jumps.
- Newest per aggregate: DISTINCT ON (aggregate_id) ... ORDER BY aggregate_id, aggregate_version DESC is the cheap PostgreSQL-only form when an index matches that order; row_number() OVER (PARTITION BY aggregate_id ORDER BY aggregate_version DESC) = 1 is the portable form and needs a subquery for the same evaluation-order reason as the gap query.
Follow-up
- Relay failover redelivers events. Does a duplicate break the gap query, and how would you detect one from this table alone?
- Turn the gap check into a continuous monitor rather than a query someone runs after an incident. What does it watch?
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?
What programming languages do you prefer and why?
Medium · Technical / Domain Questions
Approach
- Pick one primary language from those the role's requirements list (Java, C# or Python) and justify it with concrete properties, not taste: static typing and compile-time checks in Java and C#, mature JVM and .NET tooling, fast iteration and a large data ecosystem in Python.
- Name a real weakness of your choice and how you work around it, for example CPython's GIL limiting CPU-bound threads (I use multiprocessing or native libraries instead), or Java verbosity (records, var, Lombok-style tooling).
- Tie the choice to banking-style work: money must never be a binary float (0.1 + 0.2 != 0.3). I use BigDecimal built from a String in Java, the 128-bit decimal type in C#, or decimal.Decimal in Python.
- Show range: say which language you would pick for a batch job, a REST service and a quick data script, and why the answers differ.
Follow-up
- How would you represent and round a currency amount in your preferred language, and why does new BigDecimal(0.1) surprise people?
- When would you choose a language other than your favourite one for a project?
- How do Java and C# differ in generics, async handling or memory management?
Can you explain the software development lifecycle?
Medium · Technical / Domain Questions
Approach
- Lay out the phases in order: requirements, design, implementation, testing, deployment, maintenance. For each one, give the artefact it produces: user stories or specs, design docs, reviewed code, test results, a release, incident and change records.
- Contrast the models. Waterfall runs the phases once in sequence. Agile (Scrum sprints, Kanban) repeats them in small increments. DevOps automates the path from commit to production with CI/CD pipelines.
- Put testing and security early: unit tests written with the code, integration tests in CI, static analysis and dependency scanning on every pull request, not only in a test phase at the end.
- For a regulated domain, mention practices common in finance: traceable requirements, peer-reviewed changes, separation between who writes and who approves a production change, and an audit trail of deployments.
- Close with one real project of yours, mapped onto the phases, saying where it slipped and what you changed.
Follow-up
- How does an urgent production hotfix move through the lifecycle without skipping review or testing?
- How does an Agile team handle a fixed regulatory deadline with a fixed scope?
- Where in the lifecycle are defects cheapest to fix, and how do you catch them there?
How do you ensure code quality and maintainability?
Medium · Technical / Domain Questions
Approach
- Automate the checks: unit tests on business rules, integration tests against a real database, and a CI pipeline that blocks a merge when tests, the linter or the formatter fail (Checkstyle or SpotBugs for Java, Roslyn analyzers for C#, ruff and mypy for Python).
- Keep code reviews small and focused. A reviewable pull request does one thing. In review I check correctness, edge cases, naming, error handling and whether a test would fail if the logic broke.
- Use design habits that keep change cheap: single-responsibility classes, dependency injection so that I/O can be faked in tests, no duplicated business rules, and explicit names instead of comments that restate the code.
- Measure it rather than claiming it: defect escape rate, change failure rate, cyclomatic complexity hot spots, flaky test count. Line coverage alone proves little, because a test without assertions still covers code.
- Make tech debt visible: log it as tickets with a cost, and pay it down next to feature work in the module you are already changing.
Follow-up
- How would you start improving a legacy module that has no tests? (Characterization tests first, then refactor.)
- What coverage target would you set, and what would you refuse to count toward it?
- Tell me about a code review where you blocked a change. What was wrong?
What experience do you have with version control systems?
Medium · Technical / Domain Questions
Approach
- Name the tool and how deeply you use it, most likely Git: branching, pull requests, branch protection with required reviews and CI checks, and tags for releases.
- Compare branching strategies. Trunk-based development uses short-lived branches and feature flags. GitFlow uses long-lived develop and release branches. Give the trade-off: merge pain and integration risk against release isolation.
- Explain merge versus rebase. Rebase rewrites commit hashes, so I rebase only my local, unpushed work and never a shared branch. Explain revert versus reset: revert adds a new commit that undoes a change and is safe on shared history, while reset moves the branch pointer.
- Show debugging with history: git bisect binary-searches the commits between a good and a bad version, so about log2(n) builds find the commit that caused a regression. git blame and git log -S find when a line or string changed.
- Handle a leaked secret correctly: rotate the credential first, because rewriting history does not remove copies that were already cloned or pushed.
Follow-up
- Walk me through resolving a merge conflict in a file two people changed heavily.
- You committed a database password to a shared repository. What do you do, in order?
- How would you find which of 200 commits introduced a failing test?
How would you design a scalable system for a banking application?
Medium · System Design / Architecture
Approach
- Fix the scope first: accounts, balances, transfers between accounts and transaction history. Then state the non-functional bar: no lost or duplicated money, strong consistency on balances, auditability, and much higher read volume (history, balances) than write volume.
- Model money as a double-entry ledger in an ACID relational store (SQL Server or Oracle appear in the role requirements candidates describe). Each transfer writes balanced, append-only debit and credit entries in one transaction. Balances are either derived from entries or kept in a row that is updated in the same transaction.
- Make writes safe under concurrency and retries. An idempotency key on the transfer endpoint, stored with a unique constraint, turns a client retry into a no-op. Lock the two account rows in a fixed order (for example by account id) to avoid deadlocks, or use a version column for optimistic locking.
- Scale the rest: a stateless service tier behind a load balancer, read replicas for history (stale is fine there, but not for the balance check before a debit), keyset pagination on history, and partitioning by account id when one database is no longer enough. A transfer across partitions then needs a saga with compensating entries.
- Cover integration and safety: a transactional outbox for publishing events, reconciliation jobs against external payment networks, TLS and encryption at rest, OAuth-based authentication, rate limiting, and an immutable audit log.
Follow-up
- A client times out on a transfer and retries. How does your design avoid a double debit?
- How do you transfer money between two accounts that live on different database partitions?
- What breaks first if transaction volume grows tenfold, and how would you see it coming?
What considerations do you take into account when designing APIs?
Medium · System Design / Architecture
Approach
- Start from the consumer and the resources: nouns in URLs (/accounts/{id}/transactions) and HTTP methods with their real semantics. GET is safe and idempotent, PUT and DELETE are idempotent, POST is not, so a POST that moves money needs an Idempotency-Key header.
- Use precise status codes and one error format: 400 for a malformed request, 401 for unauthenticated, 403 for forbidden, 404, 409 for a conflict such as a duplicate key, 422 for a failed business rule, 429 for a rate limit. RFC 9457 problem details is a standard error body.
- Plan for evolution: version through the URL or a header, and make additive, backward-compatible changes (new optional fields). Removing or renaming a field, or changing its type, is a breaking change that needs a new version and a deprecation window.
- Design lists and payloads deliberately: cursor or keyset pagination instead of large offsets, filters and sort parameters, and money as a decimal string or integer minor units plus an ISO 4217 currency code, never a float.
- Build security in: OAuth 2.0 scopes per operation, server-side validation of every field, no account numbers or tokens in query strings (they end up in logs), rate limits, and audit logging of state-changing calls.
Follow-up
- How would you make POST /transfers safe for a client to retry after a network timeout?
- How do you remove a field that some clients still depend on?
- When would you choose gRPC or GraphQL over REST for an internal service?
Explain the differences between monolithic and microservices architectures.
Medium · System Design / Architecture
Approach
- Define both. A monolith is one deployable unit with in-process calls and usually one database, so ACID transactions across features are easy. Microservices are independently deployable services that each own their data and talk over the network.
- Monolith trade-offs: simple to build, test, debug and operate, but the whole app scales and deploys as one unit, a bad change can take everything down, and a large shared codebase slows teams. A modular monolith with enforced module boundaries is a middle path.
- Microservices trade-offs: independent deploys and scaling, fault isolation and team ownership, paid for with network latency and partial failure (timeouts, retries, circuit breakers), eventual consistency between services, and heavier operations (distributed tracing, service discovery, one pipeline per service).
- Handle cross-service consistency without two-phase commit: sagas with compensating actions and a transactional outbox, so that a database write and its event never diverge.
- Decide by criteria, not fashion: team count, deploy frequency, parts with very different load, and domain boundaries. To migrate, use the strangler fig pattern, carving one bounded context out at a time behind a routing layer.
Follow-up
- How would you decide where to draw the first service boundary when splitting a monolith?
- An operation must update data owned by two services. How do you keep them consistent?
- When would you advise a team not to move to microservices?
Describe a past project where you implemented a new system architecture.
Medium · System Design / Architecture
Approach
- Open with the measured problem that forced the change (deploy frequency, p99 latency, incident count, a database at its limits) and your own role, in the first person: what I decided, not what the team watched happen.
- Show the options you weighed and why you rejected them, for example scaling the existing system vertically, adding a cache, or splitting out one service, each with its cost.
- Describe the new architecture in enough detail to sketch: components, data stores, how they communicate (synchronous API or queue), and where consistency and failure handling live.
- Explain the migration and its safety net: strangler routing, feature flags, backfill plus dual writes or change data capture, shadow traffic to compare outputs, and a rollback plan you actually tested.
- Finish with before and after numbers, what broke during the rollout, and what you would design differently now.
Follow-up
- What went wrong during the migration, and how did you detect it?
- How did you persuade people who preferred the old design?
- What would you change if you rebuilt it with today's knowledge?
How would you approach optimizing an existing application?
Medium · Problem-Solving / Case Studies
Approach
- Define the target before touching code: which user-facing metric is too slow or too expensive (p95/p99 latency, throughput, memory, cloud cost), and reproduce it with production-like data and load.
- Measure where the time goes: APM traces across services, then a profiler on the hot path (Java Flight Recorder or async-profiler, dotnet-trace or PerfView, cProfile or py-spy). Optimise the largest share first. Amdahl's law caps the total speedup at 1 / ((1 - p) + p / s).
- Check the database early, because it is often the bottleneck. Read execution plans (SQL Server actual plans, Oracle DBMS_XPLAN), look for missing or unused indexes, N+1 queries generated by an ORM, SELECT * over wide rows, and unbounded result sets.
- Apply the fix that matches the cause: a better algorithm or data structure (a hash lookup instead of a nested loop), batching and connection pooling for I/O, async work for slow side effects, and caching only with a clear invalidation rule (never for a balance that must be exact).
- Prove it and keep it: a before and after benchmark, regression tests for correctness, a performance check in CI, and production monitoring with an alert on the metric you improved.
Follow-up
- The profiler shows time spread evenly across many functions. What do you do next?
- Your new cache served a stale account balance. How do you fix the design?
- How would you stop the same slowdown from coming back after future changes?
What steps would you take if a project is falling behind schedule?
Medium · Problem-Solving / Case Studies
Approach
- Quantify the slip first: remaining work against remaining capacity (burn-down or burn-up), and the cause: underestimation, scope creep, a blocked dependency, or unplanned support work. Each cause has a different fix.
- Lay out the levers with their costs: cut or defer scope (MoSCoW prioritisation), move the date, or add people. Brooks's law warns that new people on a late project slow it down at first through onboarding and communication overhead. Lowering quality or skipping testing is not a lever for financial software.
- Tell stakeholders early, with options rather than only bad news: what ships on the original date, what ships later, and the risk of each path, so the owner of the trade-off makes the decision.
- Re-plan to regain control: split work into smaller deliverables, remove blockers daily, protect the critical path, and track progress against the new plan visibly.
- Afterwards, run a blameless retrospective on why the estimate failed and change how estimates are made (reference-class data, buffers for known unknowns).
Follow-up
- The stakeholder refuses to move the date or cut scope. What do you do?
- How can you tell whether the slip came from estimation or from execution?
- When does adding an engineer to a late project actually help?
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 follows the reported loop: a story bank for the Screening Call, coding and SQL for the Technical Interviews, design and engineering-practice answers, then behavioral rehearsal and a full mock. Each day names the reported questions it practises.
Day 1 — Map the loop and your own projects
- Write the three reported stages (Screening Call, Technical Interviews, Behavioral Interviews) and what you will need for each.
- Write a walkthrough of your two most relevant projects, noting language, database, framework and what you owned.
- Answer aloud the language question and the version control question using real examples from those projects.
Deliverable: A one-page loop map, a two-project walkthrough, and spoken answers on languages and version control.
Day 2 — Coding and complexity
- Write reverse a string three ways in your chosen language and state the time and space complexity of each.
- Implement merge sort and quicksort from memory and write down the deciding properties: stability, extra memory, worst case, nearly sorted input.
- Practise saying the complexity of your solution aloud, including the space it uses.
Deliverable: Working code for string reversal and two sorts, with a written complexity note for each.
Day 3 — SQL and relational databases
- Review joins, grouping, window functions and indexes, since SQL Server or Oracle is the listed database.
- Work the window-function practice question on version gaps and relay lag, and write each step of your query in plain words.
- Work the practice question on join fan-out and check the row counts of your result against the source tables.
Deliverable: Two solved SQL practice questions with a short note on how you checked each result.
Day 4 — System design and APIs
- Outline a scalable banking application: components, data stores, queue use, and how a retried payment is made safe.
- Write an API design checklist covering resource naming, versioning, pagination, error format, authentication and idempotency.
- Write a monolith versus microservices comparison with one concrete situation where each is the better choice.
Deliverable: A design outline for the banking application, an API checklist and a monolith versus microservices comparison page.
Day 5 — Engineering practice and optimization
- Write your approach to code quality: review checklist, tests, static analysis and what maintainable means to you.
- Write a measure-first plan for optimizing an existing application and the order in which you would check each layer.
- Work the practice debugging question about a table stalling mid-deploy and note the diagnostic order you used.
- Review the software development lifecycle and note where Agile and DevOps practice fit in your experience.
Deliverable: A code quality note, an optimization plan, a debugging write-up and a lifecycle summary tied to your own work.
Day 6 — Behavioral story bank
- Write situation, task, action, result outlines for a complex debug, a challenging team project, a conflict and an initiative.
- Write a story about learning a technology quickly and a plan for a project falling behind schedule.
- Rehearse each story aloud, then cut anything that does not show your own decision or the result.
Deliverable: Five rehearsed story outlines, each marked with the reported prompts it can answer.
Day 7 — Full mock and gaps
- Run a full mock in loop order: introduce yourself, solve a coding question, outline a design, then tell two stories.
- Answer the motivation question and review any weak answers from earlier days.
- Write down the three questions you would ask the team.
Deliverable: A recorded mock, a list of weak spots to fix, and three written questions for the team.
Behavioral preparation for the Byline Bank loop
Behavioral interviews are reported to focus on collaboration and cultural fit, and many of the reported prompts are about how you worked on a team, handled friction and learned on the job. For a role that includes review, troubleshooting and working with product managers and designers, choose stories where you made a decision, said what you changed, and can state the result.
- What steps would you take if a project is falling behind schedule?
Describe a time you debugged a complex issue.
Medium · Technical / Domain Questions
Approach
- Choose a bug you personally chased across more than one layer, such as a transfer applied twice after a client retry or a report that disagreed with the ledger, and state the symptom and who was affected in a sentence or two.
- Narrate the investigation as a sequence: reproduce it, narrow the search (compare a good and a bad request, bisect commits, read logs and traces), test one hypothesis at a time, and say what each test ruled out.
- Name the root cause precisely, then the fix, then the safeguards that keep it fixed: a regression test, an alert, a note in the runbook.
- Say how you kept production safe while investigating, for example reading logs rather than changing live data, or using a feature flag for the fix.
- Avoid the story where the fix is the whole answer or where the debugging was luck. The point is a repeatable method.
Follow-up
- How did you know it was the root cause and not just a symptom?
- What would you have logged or monitored earlier to find it faster?
- How did you stop the same class of bug from returning?
Give an example of a challenging team project. What was your role?
Medium · Behavioral / Leadership
Approach
- Pick a project that was hard for a stated reason (tight scope, an unfamiliar system, several teams, shifting requirements) and say in one or two sentences what the project had to deliver.
- State your role exactly: what you owned, which parts were someone else's, and how you coordinated with product managers, designers or other engineers.
- Describe two or three decisions you made under the difficulty, with the alternative you rejected and why.
- Finish with the result and a measurable outcome (a release, a defect count, a hand-off) and one thing you would change.
- A common mistake is describing the team's achievement in the plural, so a listener cannot tell what you did.
Follow-up
- Which decision on that project would you reverse today?
- How did you work with people outside engineering on it?
- What would you have done if a teammate had missed their part?
How do you handle conflict within a team?
Medium · Behavioral / Leadership
Approach
- Choose a real disagreement over a substantive topic, such as an approach in code review, a design trade-off or a priority call, rather than a personality clash.
- Show how you handled it: ask the other person to explain their reasoning first, restate it to confirm you understood, then compare options against the facts (a benchmark, a requirement, a failing test).
- Say how it was settled: a data-backed choice, a small experiment, or escalation to the person who owned the decision, and that you committed to the outcome either way.
- Close with the working relationship afterwards and one habit you kept, for example writing decisions down.
- The mistake that sinks it is a story where you were simply right and the other person was difficult.
Follow-up
- What if the other person had still disagreed after the evidence?
- Have you ever been the one who was wrong in a conflict like this?
- How do you give critical feedback in code review?
Describe a time you took the initiative on a project.
Medium · Behavioral / Leadership
Approach
- Choose a situation where nobody had asked you to act: a recurring manual task, a flaky test suite, an undocumented deployment step or a missing monitoring check.
- Explain how you decided it was worth the time and how you got agreement: a short write-up, a small prototype, a conversation with your lead.
- Describe what you did yourself and how you kept your regular work on track while doing it.
- Give the result in numbers where you can (time saved, failures removed, people who adopted it) and what happened to the thing after you finished.
- Avoid a story where the initiative was only working extra hours. It should show judgment about what to fix and how you brought others along.
Follow-up
- How did you convince others it was worth doing?
- What would you have done if your manager had said no?
- Did anything about the change cause trouble later?
What motivates you to do your best work?
Medium · Behavioral / Leadership
Approach
- Answer with specifics: name two or three things that have actually driven your best work, such as solving a hard defect, shipping something people use, or learning from a strong reviewer.
- Back each with a short example from a real project, so the answer shows behaviour rather than slogans.
- Connect it honestly to the role as candidates describe it: building and maintaining banking applications and backend systems, reviewing code, and working with product and design colleagues.
- Say what you do when motivation is low, for example breaking work into small deliverables, to show it is a habit and not a mood.
- Avoid generic lines about passion and avoid answers that sound only about pay or title.
Follow-up
- Tell me about a time that motivation was missing and what you did.
- What kind of work drains you, and how do you handle it?
- How does that motivation show up when working with others?
Describe a time when you had to learn a new technology quickly to complete a project.
Medium · Problem-Solving / Case Studies
Approach
- Pick a concrete case with a deadline, such as picking up a new framework, a cloud service, or a different language such as moving from Python to Java, and state what the project needed from it.
- Describe your learning method: scope what you needed to know first, read the official documentation, build a small spike, ask someone experienced to review, then build the real thing in small slices with tests.
- Say how you managed risk: which parts you kept simple, what you did not learn yet, and how you checked your work before it shipped.
- End with the result and what you retained, plus how you shared it, for example a short write-up for the team.
- Avoid claiming you learned everything instantly. A sound answer shows a method and honest limits.
Follow-up
- How did you know your understanding was correct before shipping?
- What did you leave deliberately unlearned and why?
- How do you choose between learning something and asking a colleague?