Software Development Interview Questions for 2026

Software development interview questions decide a growing share of DevOps, SRE, platform, and infrastructure hiring loops, because everything an operations team ships, from CLIs to CI pipelines to controllers, is code someone has to maintain. This page is a complete, tiered bank: 104 questions with worked answers, split into beginner, intermediate, and scenario sections, plus hands-on labs, a cheat sheet of the commands behind the answers, and a knowledge check at the end. Work through it in order, or jump straight to the tier that matches your next round.

Software development interview questions tiered bank with beginner, intermediate, and scenario sections
The three tiers in this bank: foundations, working mechanisms, and judgment calls under pressure.

TL;DR

  • 104 questions, three tiers. OOP and SOLID fundamentals, working mechanisms like design patterns and the testing pyramid, and honest scenarios from review disagreements to breaking change rollouts, each with a worked answer.
  • Framed for engineers who ship tooling. Every answer treats your automation as production code, which is exactly how software development interview questions are graded for DevOps-adjacent roles.
  • Practice is built in. Three scenario labs, a cheat sheet of the commands that come up most, and a five-question quiz to check what stuck.

How the software development interview works in 2026

Most software development interview questions arrive in one of three rounds. The first is a screening call with a hiring manager or senior engineer, mixing definitions with quick checks: name the four pillars of OOP, explain the difference between an interface and an abstract class, say what a retro is for. These are confidence filters. Nobody expects a lecture; they expect a crisp 30-second answer with one level of detail behind it, delivered without hedging.

The second round is the deep technical. Software development interview questions at this stage get mechanical: which SOLID principle a given refactor serves, why a singleton is awkward in a concurrent service, what the testing pyramid predicts about a slow CI suite, what semver obliges you to do before removing an endpoint. Interviewers are listening for whether your knowledge has edges. Saying polymorphism means many forms clears a beginner bar; explaining that it lets callers depend on a contract while implementations vary, and naming where that shows up in a plugin system, clears a working-engineer bar. The second sentence is the one being graded.

The third round is the judgment round, and it is where software development interview questions have genuinely changed. Instead of pure puzzles, you get realistic dilemmas in one sentence: a legacy module nobody can test, a flaky suite blocking every merge, a reviewer and an author deadlocked on an approach, a hard deadline that invites a shortcut you will pay for. What is scored is not the conclusion but the reasoning order: name the tradeoff, name who owns it, name what you would do first. Candidates who pattern-match to it depends without saying what it depends on lose this round.

Role shape moves the emphasis. Backend and full-stack loops weight these questions toward language depth, frameworks, and algorithmic exercises. DevOps and platform loops care more about the maintainability of small, long-lived tools: scripts that become services, tests that gate deploys, reviews that keep infrastructure code reviewable. Software development interview questions for those roles are less about clever algorithms and more about whether the code you leave behind can be operated by someone else at 3am. The bank below covers both shapes, weighted toward the ops side.

Preparation that works is mechanical. Drill the definitions until each one is 30 to 60 seconds spoken, then drill the scenarios out loud with an explicit first move. Most candidates cram lists and never say the answers, so simply rehearsing aloud puts you ahead. Pair this page with a scratch repo: write the failing test, refactor the legacy function, run the ephemeral database, and the scenario tier of software development interview questions becomes a story you have already lived rather than a paragraph you memorized.

Core concepts interviewers expect you to know

Three mental models unlock most software development interview questions: what SOLID is actually protecting, which design patterns you already run without naming, and how a test strategy allocates confidence across layers. Interviewers open here because every scenario they ask later is one of these models wearing a symptom. If you can narrate all three fluently, follow-ups become extensions instead of new topics.

OOP pillars and SOLID, without the poster version

The four pillars are encapsulation, abstraction, inheritance, and polymorphism, and interviewers expect you to state them as mechanisms, not slogans. Encapsulation hides internal state behind methods so invariants cannot be bypassed. Abstraction exposes what a thing does while hiding how. Inheritance shares behavior down a type hierarchy. Polymorphism lets callers treat different implementations uniformly through one contract. The pillars are descriptive; SOLID is prescriptive, five rules that tell you when the pillars are being abused. Single responsibility keeps one reason to change per class. Open/closed pushes variation into new code instead of edits to working code. Liskov substitution requires subtypes to keep the base contract. Interface segregation keeps contracts small enough that implementers implement everything they declare. Dependency inversion points dependencies at abstractions, so high-level policy never imports low-level detail. That pairing, pillars as vocabulary and SOLID as review checklist, is exactly what software development interview questions at this level are listening for.

SOLID: five rules, five failures prevented S Single responsibility O Open / closed L Liskov substitution I Interface segregation D Dependency inversion one reason to change extend, do not modify subtypes keep the promises small, focused contracts depend on abstractions each rule names the review complaint it prevents: god classes, edit risk, broken callers, stub-only implementations, and policy welded to detail
Read each principle as the name of a failure it prevents, which is how interviewers use SOLID in review conversations.

Design patterns you already meet in ops tooling

The pattern round is not about reciting the GoF catalog. It is about recognizing four or five shapes that appear constantly in automation and services. A factory hides construction behind a name: your CLI asks for the AWS client for profile prod and does not care which class gets built. An observer lets a subject notify subscribers: webhooks, event buses, log handlers, Kubernetes informers. A strategy swaps interchangeable algorithms behind one interface: retry policies, auth providers, storage backends. A proxy stands in for a real object and controls access: caching clients, lazy SDK loaders, rate limiters. A decorator wraps a thing with more of the same interface: middleware chains around an HTTP handler. When a software development interview question says how would you make X pluggable, the expected answer is one of these five, named and applied, not a taxonomy lecture.

The testing pyramid and honest process

The testing pyramid is a budget for confidence. Unit tests are numerous because they are fast, deterministic, and pinpoint failures to a function. Integration tests are fewer because they exercise real collaborations, a service against a real database, a CLI against a real API, and they cost setup time. End-to-end tests are fewest because they are slow, broad, and brittle, so each one must guard a revenue-critical path. An inverted pyramid, mostly e2e, predicts a suite that fails on red noise and still misses unit-level edge cases. The same honesty applies to process topics. Software development interview questions about agile are not vocabulary checks; they probe whether you know what ceremonies are for when they work and what they decay into when they do not, from standups that become status theater to story points that become quota. Saying what a practice is for, and what it looks like when it fails, is the senior signal in software development interview questions on process.

The testing pyramid is a confidence budget End to end fewest Integration some, against real dependencies Unit most, milliseconds each, one function at a time slow, broad, brittle catches wiring bugs fast, cheap, precise guards revenue paths with real infrastructure fails point at the bug an inverted pyramid predicts a slow, flaky suite that still misses unit-level edge cases
Layer counts follow cost: the fast and precise layers carry volume, the slow and broad layers carry only critical paths.

Question bank at a glance

The bank below is organized the way software development interview questions are actually asked: broadly increasing difficulty inside each tier, then the judgment round that finishes most loops. Counts are exact so you can pace a week of prep: roughly fifteen beginner questions a day clears the bank in a working week, with the labs on the weekend.

SectionQuestionsWhat it proves
Beginner38You speak the vocabulary of code quality, process, and testing without hesitation.
Intermediate40You can apply SOLID, name the pattern a design needs, and defend a test strategy.
Scenario and troubleshooting26You can make a defensible call on debt, reviews, and legacy code, out loud.

Every answer names the mechanism first, then the consequence or the command, because software development interview questions are graded on both halves: the right term, and the right explanation of why it applies. Difficulty still rises within each tier, so if a section feels easy near its end, move on; that is the signal the tier is behind you.

Beginner software development interview questions

These 38 open most software development interview questions, and they look easier than they are. Interviewers use them to check precision, so answer each in one or two sentences, then add exactly one supporting detail. Say more and you burn round time; say less and you sound like a list. Deliver every answer here without hesitation before spending time on the deeper tiers.

What is object-oriented programming?

Answer: A style that organizes code into objects: bundles of state and the methods that operate on it, defined by classes. Its promise is maintainability at scale: you change one object’s internals without breaking its callers, as long as the interface holds. The honest caveat worth adding is that OOP is a tool, not a religion, and scripts that glue commands together may be better as plain functions. Defining the style by its benefit, not its syntax, is how strong candidates open software development interview questions.

What are the four pillars of OOP?

Answer: Encapsulation, abstraction, inheritance, and polymorphism. Encapsulation hides state behind methods, abstraction exposes what a thing does and not how, inheritance shares behavior down a type hierarchy, and polymorphism lets one contract stand in for many implementations. Name them in that order and attach a one-clause mechanism to each. Most follow-up software development interview questions pick one pillar and drill it, so a one-clause handle per pillar sets up everything that comes next.

What is encapsulation?

Answer: Keeping an object’s internal data private and reachable only through its methods, so the class alone enforces its rules. A config object that validates on set, never on read, is encapsulated; a bare dict every caller mutates is not. The consequence interviewers want named: without encapsulation, invariants live in everyone’s head instead of in one place, and every bug fix has to audit every caller.

What is abstraction, and how is it different from encapsulation?

Answer: Abstraction decides what to expose: the contract, the what, while hiding the how. Encapsulation is the enforcement side: hiding the internals so the abstraction cannot be bypassed. A storage interface saying save and load is abstraction; the private fields and validation inside each backend are encapsulation. That distinction is a classic software development interview question because it separates candidates who memorized the words from candidates who can point at where each lives in real code.

What is inheritance?

Answer: A relationship where a subclass receives the behavior and state of a parent class and may extend or override it. It is the right tool only for a genuine is-a relationship where the child can be used anywhere the parent is expected. The caveat to volunteer: inheritance couples the child to the parent’s implementation details, which is why experienced developers reach for it far less than tutorials suggest, preferring composition for reuse.

What is polymorphism?

Answer: The ability of different types to be used through one interface, so a caller can treat every storage backend, notifier, or auth provider the same. Mechanically, the caller holds the contract and the runtime picks the implementation. It is the pillar that makes plugins, drivers, and strategy patterns possible. Expect software development interview questions to follow this one with give an example from something you maintain, so have a real one ready from your tooling.

What is the difference between a class and an object?

Answer: The class is the blueprint: fields, methods, and rules defined once. The object is a runtime instance of that blueprint with its own state in memory. One class, many objects, each independent. Worth adding: static members belong to the class itself rather than to any instance, which is why they persist across instances and why overusing them is a smell.

What is the difference between an interface and an abstract class?

Answer: An interface is a pure contract: method signatures with no state, which implementers promise to provide. An abstract class is a partial implementation: it can carry state, constructors, and shared method bodies, but cannot be instantiated directly. Rule of thumb: interface for a capability any class can have, abstract class for shared scaffolding among related classes. Languages blur the edges, Java interfaces gained default methods, Python has ABCs, so mention your language’s flavor.

What is method overloading, and how is it different from overriding?

Answer: Overloading is several methods with the same name but different parameter signatures in one class, resolved at compile time. Overriding is a subclass replacing a parent’s method with the same signature, resolved at runtime. Overloading is a naming convenience; overriding is polymorphism in action. That runtime versus compile-time split is the whole answer, and it recurs in software development interview questions about how dispatch actually works.

What does static mean for a method or field?

Answer: It belongs to the class itself rather than to any instance: one copy shared by everything, callable without an object. Useful for pure helpers and constants. The consequence worth stating: static state is global state, so a static mutable field is shared across all callers and tests, which makes behavior order-dependent and hard to parallelize. Static helpers are fine, static mutable state is a design smell.

What are coupling and cohesion?

Answer: Coupling is how much one module needs to know about another to work; cohesion is how strongly the pieces inside one module belong together. The goal is low coupling, high cohesion: modules with one clear job that talk through narrow contracts. Tight coupling means a change ripples across files; low cohesion means a module is a junk drawer nobody owns. This pair of definitions is the foundation under half of all software development interview questions about design.

What does DRY mean, and where does it mislead people?

Answer: Do not repeat yourself: every piece of knowledge should live in one place, so a change happens once. The trap is applying it to code that merely looks similar but changes for different reasons, which welds unrelated modules together behind a shared helper. The fix is knowing what duplication actually is: duplication of knowledge, not of text. Candidates who can state both halves, the rule and its limit, stand out in software development interview questions on code quality.

What are KISS and YAGNI?

Answer: Keep it simple: prefer the straightforward solution over the clever one, because code is read far more often than written. You aren’t gonna need it: do not build flexibility for requirements that have not arrived, because speculative abstraction is a cost paid now for a guess. Together they are the counterweight to over-engineering. Interviewers raise them to see whether you can push back on complexity, which is a daily move in software development interview questions about design reviews.

What is a side effect, and why do side effects complicate code?

Answer: A side effect is anything a function does beyond returning a value: writing a file, mutating an argument, sending a request. They complicate code because order and context start to matter: the same call can behave differently depending on what ran before it, and tests need the world set up and torn down around each one. Pure functions, no side effects, are trivially testable; the practical pattern is pushing effects to the edges and keeping the core pure.

What is immutability, and why is it useful?

Answer: An immutable value cannot change after creation, so every modification returns a new value. The payoff is reasoning and safety: nothing can mutate shared state under you, which removes whole classes of concurrency bugs and makes values safe to pass around, cache, and compare. Full functional style is optional; even partially immutable config objects eliminate the mystery of who changed this. Mentioning thread safety is the detail that earns credit.

What is the SDLC?

Answer: The software development lifecycle: the stages work passes through from idea to retirement, usually requirements, design, implementation, testing, deployment, and maintenance. Its value in an interview answer is naming that the stages loop, not march: feedback from production feeds the next round of requirements. Expect software development interview questions to use it as a frame, then ask which stage your current team does badly, which is where the real conversation starts.

What is the difference between waterfall and agile?

Answer: Waterfall fixes requirements up front and moves through phases once, so change is expensive and surprises arrive late. Agile works in short iterations that ship working software and re-plan against feedback, so change is expected input rather than a crisis. The senior caveat: neither is a religion, and regulated or hardware-bound work often keeps waterfall-style gates. What interviewers listen for is that you know agile trades predictability of scope for predictability of learning.

What is a sprint?

Answer: A fixed, short timebox, one to four weeks, in which a team commits to a subset of the backlog and produces a potentially shippable increment. The point of the box is rhythm and forced prioritization, not quota. Worth adding: a sprint that always overruns is a planning-signal problem, not a ceremony problem, because the timebox exists precisely to make overcommitment visible. That operational reading is what software development interview questions about Scrum are really checking.

What is a product backlog, and who owns it?

Answer: The single, ordered list of everything the team might build: features, fixes, debt, spikes. The product owner owns its content and priority; the team owns the estimates that inform ordering. Ordered, not just prioritized at the top: position is the decision. A backlog that is an unsorted dump of every idea is a dysfunction worth naming, because ordering is what turns a list into a plan.

What is a user story, and what are acceptance criteria?

Answer: A story is a thin slice of user-visible value, usually told as as a role, I want capability, so that benefit, small enough to finish inside a sprint. Acceptance criteria are the concrete, testable conditions that make it done: given a state, when an action happens, then an observable result. The pairing matters because stories without criteria are wishes, and criteria without the user framing drift into task lists. That pairing is what software development interview questions on agile artifacts want demonstrated.

What are story points?

Answer: Relative sizing units for effort or complexity, used to compare items against each other rather than to promise dates. Teams converge on them in planning poker by anchoring on reference stories. The honest addition: points are a conversation tool inside one team, and they stop working the moment they are converted to hours, compared across teams, or treated as a velocity target, which is the most common way software development interview questions on estimation go bad.

What happens in a daily standup?

Answer: A short sync, timeboxed to about fifteen minutes, where each person covers what moved since last time, what comes next, and what is blocked. It is a planning conversation between teammates, not a status report to a manager. When it decays into reciting yesterday’s ticket updates for an audience, the fix is to bring the blocker conversation back: impediments raised in standup get owners and follow-ups outside it.

What is a retrospective?

Answer: The ceremony where the team inspects its own process at a regular cadence, usually per sprint: what worked, what hurt, and one or two concrete experiments to try next. Its value lives entirely in the follow-through; a retro that produces actions nobody tracks teaches the team that reflection is theater. Psychologically safe retros surface real problems, which is why the blameless norm matters and why interviewers like asking what you would do when a retro keeps raising the same issue.

What is a unit test?

Answer: An automated test that exercises one small unit, a function or class, in isolation, with its collaborators replaced or faked, fast enough to run thousands per minute. Its job is pinpointing failures: when a unit test goes red, you know which function broke. That speed and precision combination is why unit tests form the base of the testing pyramid, and it is the reason nearly every software development interview question about testing starts here.

What is an integration test?

Answer: A test that exercises several real pieces together: your service against a real database, your CLI against a real API sandbox, your queue consumer against a real broker. Its job is catching wiring bugs: the SQL that a mock would have accepted but the schema rejects, the config key nobody reads. Fewer and slower than unit tests, so teams run them on every merge rather than every save.

What is an end-to-end test?

Answer: A test that drives the whole system the way a user would, through the UI or the public API, across real components. It buys the highest confidence per test and costs the most per run: slow, environment-hungry, and prone to breaking for reasons unrelated to the change under test. The discipline is keeping the set small and reserved for critical paths. Explaining that tradeoff well is what separates candidates in software development interview questions about test strategy.

What does arrange-act-assert mean?

Answer: The standard shape of a good test: arrange the inputs and fixtures, act by calling the one behavior under test, assert on the observable result. Three phases, one behavior, and one reason for the test to fail. It keeps tests readable as documentation and keeps failures diagnosable at a glance. When a test needs pages of arrange, that is a design signal that the unit under test has too many dependencies.

What is a mock?

Answer: A test double that stands in for a real collaborator: it returns canned answers and, unlike a stub, records how it was used so the test can assert on interactions, like the notifier was called exactly once. Mocks buy isolation and speed; overused, they couple tests to implementation details, so a refactor breaks tests even when behavior is unchanged. The rule to state: mock the boundaries you own, prefer fakes or real objects for everything else, and most software development interview questions on test doubles stop there.

What is code coverage, and what is it good for?

Answer: The percentage of code your tests execute, measured by line, branch, or path. It is useful as a gap detector: uncovered code is untested code, and a sudden drop means a change shipped without tests. It is useless as a target: 100 percent coverage proves execution, not assertion quality, and teams that mandate numbers get tests that run code without checking anything. State both halves and you have answered the question the way software development interview questions intend it.

What is a regression test?

Answer: A test written from a bug after fixing it, pinning the exact failure so it can never return silently. The habit matters more than the definition: every production defect should end its life as a red-to-green test in the suite, which turns incident history into permanent protection. A suite full of regression tests grows exactly where a codebase has actually been hurt, which is a smarter allocation than chasing a coverage number.

What is refactoring?

Answer: Changing a codebase’s structure without changing its behavior: extracting a function, renaming for clarity, splitting a god class, so future changes get cheaper. Refactoring is behavior-preserving by definition, which is only safe when tests prove it, so refactoring and testing are one discipline, not two. The interview follow-up is nearly always when do you refactor, and the working answer is opportunistically: leave code you touch a little better than you found it.

What is technical debt?

Answer: The future cost created by taking a shortcut now: the quick hack that works today but makes every change near it slower and riskier. Debt is sometimes rational, shipped deliberately to hit a date with a plan to repay, and often accidental, accumulated by drift. The metaphor’s point is interest: unpaid debt compounds, it does not sit still. This framing, principal versus interest, is exactly what software development interview questions on debt want to hear from a candidate.

What is a code smell?

Answer: A surface sign that code may have a deeper design problem: a 400-line method, a class named Manager or Utils, a parameter list of nine booleans, copy-pasted blocks. A smell is not a bug; it is a hint worth a second look, and some smells are fine in throwaway scripts or hot paths where clarity lost to performance deliberately. Naming a smell and then saying when you would leave it alone is the mature version of this answer.

What is code review, and why do teams require it?

Answer: Peers read every change before it merges, checking correctness, readability, and fit with the codebase. The primary product is not bug catching, though it helps; it is shared knowledge, so more than one person understands every part, and a consistent bar the whole team owns. The social rule to state: review critiques code, never the author, and the goal of every comment is a better change, not a win. That norm is the subtext of most software development interview questions about reviews.

What is a pull request, and what makes a good one?

Answer: A proposal to merge one branch into another, with a diff, a description, and a review thread attached. A good one is small enough to review in one sitting, self-contained, has a description that says what changed and why, passes CI, and includes its own tests. Enormous PRs get shallow reviews, which is why breaking work into stacked changes is a skill interviewers probe. Small, well-described pull requests are the habit most software development interview questions about collaboration are circling. Tooling calls it a merge request in GitLab, the mechanics are identical.

What belongs in a good README?

Answer: What the thing is, why it exists, how to install and run it, how to test it, and where to go with problems: enough for a new engineer to go from clone to running in minutes without asking anyone. A README is onboarding documentation, not a design doc, and its staleness is measurable: if the install steps fail on a fresh machine, the README is wrong. Saying you would test the README like code is a small answer that lands well in software development interview questions about documentation.

What is semantic versioning?

Answer: A versioning contract of three numbers, MAJOR.MINOR.PATCH: breaking changes bump the major, backward-compatible features bump the minor, fixes bump the patch. Its value is automation: dependency tools can take patch and minor updates safely and hold at a major until a human decides. One nuance that earns credit: pre-1.0 projects often promise nothing, and some ecosystems, like Python’s, treat even minor bumps carefully. Semver is a promise about compatibility, and software development interview questions use it to test whether you treat published interfaces that seriously.

What is a build, and what does a CI pipeline do?

Answer: The build turns source into a runnable artifact: compiled binaries, bundled assets, a container image. A CI pipeline runs that build plus lint and tests automatically on every change, so integration problems surface in minutes instead of at the next release. The operational details worth naming: builds must be reproducible from a clean checkout, and a red main branch is a stop-the-line event, because CI only protects you if main is always releasable.

Intermediate software development interview questions

This tier is where software development interview questions stop testing vocabulary and start testing mechanism. Forty questions follow, and the habit to build is principle, then application: name the rule or pattern, then say what it changes in real code you would actually maintain. That second half is what moves you from book-smart to hireable in an interviewer’s notes.

What does single responsibility mean in practice, at what granularity?

Answer: One module, one reason to change: if requirements for two different actors can force edits to the same class, it has two jobs. Granularity is the real question behind this one. A class with one method can still violate SRP if that method mixes parsing, validation, and persistence, while a modest class with cohesive helpers is fine. The practical test interviewers like: describe the class in one sentence without using and. If you need and, split it. That operational test is what software development interview questions on SRP are fishing for.

What does the open/closed principle look like in real code?

Answer: New requirements are met by adding code, not by editing working code. The mechanism is always the same shape: a stable interface plus implementations behind it. Adding a new storage backend means writing a new class that implements the storage contract, then registering it, not cracking open the service layer with another if provider == branch. The honest caveat: pursuing OCP everywhere produces speculative plugin systems nobody uses. Apply it where variation has actually happened twice, and say so, because that judgment is the level software development interview questions grade here.

What does Liskov substitution actually forbid?

Answer: Subtypes that break the promises of their base: strengthening preconditions, weakening postconditions, or throwing for operations the contract says must work. The classic is a ReadOnlyCollection subclassing a mutable list and throwing on add: every caller that trusted the base contract now needs an instanceof check, which is the tell. The design consequence: if a subclass has to reject half its inherited interface, inheritance was the wrong relationship, and composition or a separate interface is the fix. That tell is the highest-signal detail in software development interview questions on LSP.

Why do fat interfaces hurt, and what is the fix?

Answer: Interface segregation says clients should not depend on methods they do not use, and a fat interface violates that: every implementer must stub out methods it does not support, and every reader must wade past capabilities that do not apply. The fix is splitting by client need: a big Worker interface becomes Schedulable and Retryable, and implementers compose only what they are. You meet the violation as NotImplementedError in half a codebase’s implementers. Expect software development interview questions to show you that smell and ask for the split.

What is the difference between dependency inversion and dependency injection?

Answer: Inversion is the design rule: high-level policy depends on abstractions, not on concrete implementations, so the business logic defines the interface it needs and details implement it. Injection is the plumbing technique: dependencies are supplied from outside, constructor arguments or a container, instead of being constructed inside. They compose: inversion decides the shape, injection decides who wires it. The payoff interviewers want named: with both, you can swap a real mailer for a fake in tests without touching business code, which is why this pair anchors software development interview questions on testability.

What problem does the factory pattern solve, and where do you already meet it?

Answer: It moves construction behind a name so callers ask for a client for this profile instead of building one themselves. That buys one decision point for credentials, endpoints, and retries, and one place to change when providers change. You meet factories constantly: provider SDK clients built from a profile string, logging.getLogger returning configured handlers, driver registries in Terraform providers and kubectl credential plugins. The interview depth move is distinguishing simple factory from factory method, where subclasses decide what to build. Naming where a pattern already lives in your toolchain is exactly what software development interview questions on patterns reward.

Why is the singleton controversial?

Answer: It enforces one instance with a global access point, which buys you a convenient handle and sells you three problems. It hides a dependency: callers reach it implicitly, so nothing in a signature says the code touches global state. It resists testing: tests cannot substitute it without hacks, and state leaks between tests. And it is a concurrency hazard: lazy initialization needs locking, and the instance becomes a contention point under load. The mature position: rely on a DI container or explicit wiring for genuinely single things, and say that when asked. Singletons persist in software development interview questions at every seniority level precisely because everyone has been burned by one.

Explain the observer pattern with an example from real infrastructure.

Answer: A subject keeps a list of subscribers and notifies them when its state changes, decoupling the thing that happened from the things that care. You already run it everywhere: git hooks firing on commit, Kubernetes informers watching resource updates, webhook deliveries on a push, log handlers attached to a logger, cloud event buses routing messages. The design caveats to name: notification order is rarely guaranteed, slow subscribers can stall the subject unless delivery is async, and failures need a policy, retry, dead-letter, or drop. Those caveats are the working level of software development interview questions on observer.

How does the strategy pattern make systems pluggable?

Answer: It defines one contract for a family of interchangeable algorithms and lets callers inject the one they want, so behavior varies without branching. Retry policy: exponential, fixed, or none, each a strategy handed to the client. Auth: token, IAM role, mTLS. Storage: local, S3, GCS. The litmus test for needing it: the same if/elif ladder appearing in three call sites as requirements drift. Strategy plus a factory that selects by config is the standard pairing in real codebases, and naming both together is what software development interview questions on extensibility listen for.

Patterns you already run in ops tooling Your automation code calls contracts, not constructors Factory builds the provider client from a profile name Observer webhooks and event buses fire handlers on change Strategy swaps auth: token, IAM, mTLS, behind one interface Proxy caching, retrying client standing in for the real one interview answers get strong the moment you point at where each pattern already lives in your stack
Four patterns located in tooling you maintain daily, which is the framing that turns a definition into an interview answer.
What work does a proxy do, compared to the real object it stands in for?

Answer: A proxy implements the same interface as its subject and controls access to it, so callers cannot tell the difference. Real examples: a caching proxy that serves repeat reads without hitting the API, a lazy proxy that opens expensive connections on first use, an SDK stub that marshals calls over the network, a rate-limiting proxy that queues bursts. The interview distinction is proxy versus decorator: both wrap, but a proxy controls access to the same behavior, while a decorator adds behavior. Software development interview questions on SDKs and client libraries almost always route through this distinction.

How does the decorator pattern show up in middleware chains?

Answer: A decorator wraps an object with the same interface and adds behavior before or after delegating: logging, metrics, auth, recovery. Middleware is just decorators composed: the request passes through the logging wrapper into the metrics wrapper into the handler, and the response unwinds back out. Each layer does one job and the stack is assembled per deployment without touching handlers. Worth naming: ordering matters, recovery outside logging means panics are logged, the reverse means they are not, and saying that is the senior detail in software development interview questions on middleware.

When is an adapter the right pattern, and how does it differ from a facade?

Answer: An adapter converts one interface into another that callers expect: your code speaks your ObjectStore interface, the adapter translates to a third-party SDK with different names and semantics. It shines at boundaries, wrapping vendors so they can be swapped without touching the core. A facade does not translate; it simplifies, exposing one clean entry point over a subsystem with many moving parts, like a deploy() function hiding build, push, and migrate steps. Adapter changes the interface, facade hides complexity, and both are anti-corruption layers against external mess.

Why do experienced developers prefer composition over inheritance?

Answer: Composition, assembling behavior from parts an object holds, keeps coupling at the interface: swap the part, nothing else moves. Inheritance welds the child to the parent’s implementation details, so a change to the parent silently breaks subclasses, the fragile base class problem, and the child inherits capabilities it must refuse or stub. The working rule: inherit only for a true is-a with identical contract, compose for reuse and variation. Almost every refactor that removes a two-level hierarchy into injected collaborators demonstrates this, and that demonstration is the heart of software development interview questions on inheritance.

What is the diamond problem, and how do modern languages handle it?

Answer: With multiple inheritance, a class inherits the same method from two parents, and the runtime must pick one: ambiguity, or a silent choice nobody intended. Language answers differ and naming them earns credit: Python linearizes the MRO and resolves cooperatively, C++ requires virtual inheritance to share the base, Java allows multiple interfaces with default methods but forces the class to override and can delegate explicitly with Interface.super.method(). The design takeaway: the diamond is a symptom that shared behavior wants a collaborator, not a parent.

What are the layers of the testing pyramid, and what ratio should a healthy suite have?

Answer: Many unit tests at the base, fewer integration tests in the middle, few end-to-end tests at the top, because cost and runtime per test grow exactly as confidence per test grows. Exact ratios are team-specific; the shape is the contract. Diagnosing an inverted pyramid is the common follow-up: a suite dominated by e2e tests is slow, flaky, and imprecise, and the remedy is pushing coverage down, converting fat e2e scenarios into integration and unit tests around the same behavior. That diagnosis skill is what software development interview questions on the pyramid actually grade.

What is the difference between a mock, a stub, a fake, and a spy?

Answer: Four test doubles with different jobs. A stub returns canned answers to make a path runnable. A mock additionally asserts interactions: it was called, with these arguments, this many times. A fake is a working lightweight implementation, an in-memory database instead of Postgres, so behavior is real while infrastructure is cheap. A spy wraps a real object and records the calls that pass through. The rule that separates seniors: assert on state through fakes where possible, assert on interactions through mocks only at boundaries you own, because interaction assertions are what make tests resist refactoring.

What makes a test deterministic, and what breaks determinism most often?

Answer: Determinism means the same code and inputs always produce the same verdict. The usual saboteurs: wall-clock time, so freeze the clock; randomness, so seed it; unordered collections and parallel execution, so sort and isolate; shared state between tests, so build and tear down fixtures per test; and real networks, so fake them or use ephemeral containers. A suite that only passes on retry is not green, it is lying with extra steps. Fixing flakiness at the cause instead of retrying is the maturity signal software development interview questions on determinism hunt for.

What is TDD, and what is the red-green-refactor cycle actually buying you?

Answer: Test-driven development writes the failing test first, then the least code that passes it, then cleans up with the safety net on. The loop’s real products: instant feedback on every change, a suite that proves behavior rather than retrofits it, and design pressure, because hard-to-test code complains immediately and gets reshaped into small, injected, testable units. The honest limitation to volunteer: TDD suits logic with clear contracts better than exploratory UI or spike work, where you test after the design settles. Naming when it does not fit is part of a complete TDD answer.

TDD: the red, green, refactor loop 1. Red write one failing test 2. Green least code that passes 3. Refactor clean up, tests stay green minutes, not days: the whole loop repeats many times per feature the test arrives before the code, so every line is written against a requirement, not a memory
The TDD loop and its cadence: failing test, minimal implementation, cleanup, repeat.
What does BDD add beyond test syntax?

Answer: Behavior-driven development writes scenarios in a shared Given/When/Then language that product, QA, and engineers all read, then wires those scenarios to executable steps. The real product is the conversation: acceptance criteria become concrete examples before code exists, and disagreements surface at planning instead of in review. The honest risk to name: without that collaboration, BDD collapses into a slow, brittle e2e suite written in Gherkin syntax, which is the most common way teams bounce off it. Software development interview questions on BDD are probing whether you know it is a communication practice wearing a testing syntax.

What problem does contract testing solve between services?

Answer: It verifies that a consumer’s expectations and a provider’s actual behavior agree, without needing both deployed together. The consumer defines a pact: I will call this endpoint with this shape and expect this response. The provider replays those expectations against its real implementation in CI. Integration tests can then stay small, because cross-service compatibility is enforced as a unit-speed check on every build. The operational caveat: contracts must be versioned and published somewhere both sides can see, or the safety silently rots. That deployment-decoupling argument is what contract-focused software development interview questions want to hear.

Why do teams prefer ephemeral containers over a shared staging database for integration tests?

Answer: Testcontainers-style tooling starts a real database or broker per test run in a container, seeds it, and throws it away. That removes the three failure modes of shared environments: drift between staging and what the code expects, interference when two runs collide on the same data, and stale seed data hiding bugs. Every run gets a known-clean dependency at a known version, which makes failures reproducible. Cost is image pulls and startup time, paid back in flake reduction. Naming version pinning of the container image is the detail that shows you have done this.

What is mutation testing, and what does it catch that coverage misses?

Answer: It mutates your code, flips a comparison, off-by-ones a boundary, removes a call, and checks whether any test fails. A mutant that survives means the suite executes that code but asserts nothing meaningful about it: coverage was 100 percent, protection was zero. Tools like mutmut or Stryker report a mutation score, the share of mutants killed, which measures test strength rather than test presence. It is slow, so teams run it on critical modules rather than the whole tree. That coverage-versus-strength distinction is exactly the gap software development interview questions on mutation testing probe.

Scrum and Kanban: what actually differs once you cut the branding?

Answer: Scrum timeboxes work into sprints with committed scope and fixed ceremonies; Kanban is continuous flow with work-in-progress limits and no required cadence, managing throughput with cycle-time metrics instead of sprint commitments. The practical difference is how change enters: mid-sprint scope changes are exceptions in Scrum and just the next card in Kanban. Many real teams run Scrumban: sprint rhythm for planning and retros, WIP limits for flow. Describing which constraints your team actually enforced, rather than reciting both textbooks, is what software development interview questions on process frameworks are listening for.

Why does a definition of done matter more than velocity?

Answer: The definition of done is the team’s shared exit standard: tested, reviewed, merged, deployed, documented, whatever the team explicitly agrees, applied identically to every item. Velocity is a measurement of how much gets done per sprint. Done is the standard that makes the measurement honest: teams without a real DoD count half-finished work as progress, and velocity becomes a fiction that hides integration risk until release week. The senior move is treating every it works on my branch as a DoD violation and saying so without apology.

What are the honest failure modes of story points and velocity?

Answer: Points decay when they are converted to hours, compared across teams, or made a target, because the moment velocity becomes a goal, estimates inflate and splitting tasks games the number. Points also silently assume team stability: a re-teamed or growing team invalidates the calibration the points encoded. The healthier trend metrics are throughput and cycle time, which are measured rather than forecast. Expect software development interview questions here to ask what you would do instead, and the strong answer is: forecast from measured cycle time, keep points only if they still drive real conversations.

Trunk-based development versus long-lived branches: what are the real tradeoffs?

Answer: Trunk-based development keeps short-lived branches merging to main within a day or two, using feature flags to hide unfinished work; long-lived branches, release branches, feature branches measured in weeks, isolate work but accumulate integration risk that lands all at once. Trunk-based keeps main releasable and forces small reviews, but demands disciplined flags and fast tests. Long-lived branches suit shipped binaries and slow release trains. The costs to name explicitly: flag debt from trunk-based, merge hell from long-lived. That pairing of benefit and bill is the level software development interview questions want on branching strategy.

What do feature flags change about releasing and reviewing code?

Answer: A flag decouples deploy from release: the code ships dark, the behavior turns on per environment or per cohort, and rollback becomes a toggle instead of a redeploy. Reviews change too, because reviewers audit the flag-off default and the cleanup plan, not just the diff. The discipline flags demand: a registry of every flag, an owner and expiry per flag, and deletion when the experiment ends, because a codebase with hundreds of dead flags has combinatorial states nobody tests. Flag hygiene is the caveat half of every mature answer on flags, and it is exactly where software development interview questions on the topic usually go next.

How does review latency shape delivery, and what keeps reviews fast?

Answer: Reviews are a queue, and queueing delay dominates cycle time on most teams: a PR that waits a day for first response costs more than all the coding time it saved by being small. What keeps the queue short: small changes that take minutes to review, explicit ownership so someone knows it is theirs, a first-response expectation measured in hours, and batching feedback into one round rather than a trickling thread. Swapping full reviews for pair-reviewed or tool-gated changes on low-risk paths is a legitimate escalation answer.

What does hexagonal architecture buy a codebase in practice?

Answer: Ports and adapters: the core logic defines the interfaces it needs, ports, and everything external, HTTP, databases, queues, CLIs, plugs in as replaceable adapters. The purchases are concrete: tests drive the core through a fake adapter with no database at all, swapping Postgres for another store means writing one adapter, and business rules never leak into framework code. The critique to volunteer: applied to trivial CRUD it is ceremony, layers without payoff. Hexagonal earns its cost where core logic is genuinely independent of its delivery mechanisms, and knowing that boundary is what software development interview questions on architecture are testing.

Modular monolith or microservices: how do you actually choose?

Answer: Choose by team topology and deployment needs, not fashion. A modular monolith, one deployable with enforced internal module boundaries, gives simple operations, transactions, and refactoring, and it is the right default until pain is real. Microservices buy independent deploys and scaling per service, and charge for it in distributed transactions, network failure modes, and operational surface. The rule that survives experience: split along lines the organization already needs to deploy and scale independently, because services follow team structure, Conway’s law in action. Naming a concrete split trigger, one module’s release cadence blocking others, is the senior detail.

Beyond definitions, what does high cohesion and low coupling look like in a repo layout?

Answer: Cohesion: a module’s files change together, its name predicts its contents, and its README explains one responsibility. Coupling: module boundaries are import boundaries, so a change in billing shows up in billing’s diff, not scattered across every directory; cross-module calls go through exported interfaces, never by reaching into another module’s internals. The measurable tells: directory churn reports, where commits touch, and import linters that forbid deep paths. Saying I would measure coupling by looking at which files change together is the answer that separates operators from readers in software development interview questions on structure.

When is a code smell worth fixing, and when should it stay?

Answer: Fix smells where you are already working: the long method you are modifying gets extracted now, because refactoring code you must touch anyway is nearly free and compounding. Leave smells in stable code nothing depends on changing, in hot paths where the ugly version is measurably faster, and in code scheduled for deletion. The rule that keeps this honest: smells are hypotheses about design friction, not defects, so the trigger for fixing them is churn, not aesthetics. Interviewers use this question to see whether refactoring energy gets spent where it returns value.

What are characterization tests, and how do you use them on legacy code?

Answer: Characterization tests pin current behavior, including its bugs, by asserting on what the code actually does today, captured from observation rather than specification. The workflow: find inputs, record outputs, freeze them as tests, then refactor with confidence because any unintended behavior change turns the suite red. They are the safety net that makes legacy refactoring legal. The nuance worth stating: where the pinned behavior is a genuine bug, fix it deliberately in its own change with its own announcement, not silently mid-refactor. This technique is the standard first move in software development interview questions about legacy systems.

With semver, how do you decide whether a change is breaking?

Answer: Breaking is anything that can force a correct consumer to change: removing or renaming an exported function, changing a response field’s type, new required parameters, tightening validation that used to pass, dropping support for a runtime version consumers pin. Behavior changes that were never contractual, like fixing a blatantly wrong return, are judgment calls best shipped with a minor bump and a loud note. The operational habit: read your telemetry before deciding, because consumers depend on things you never documented. That consumer-first reading of the contract is what semver-focused software development interview questions are really testing.

What does a responsible deprecation policy look like?

Answer: Announce the replacement with a written window, emit runtime warnings on the old path, a log line or a Deprecation header, keep both paths working through the window, watch telemetry until old usage decays toward zero, then remove in the next major with release notes saying exactly what left. Internal deprecations add one step: a tracker of the teams still on the old path, with deadlines agreed rather than imposed. The principle underneath: breaking changes are a coordination problem, and the window exists so consumers, not the producer, absorb none of the surprise.

What are architecture decision records, and why keep them?

Answer: ADRs are short, numbered, immutable documents, one per significant decision: context, the options considered, the decision, and the consequences accepted. Superseded decisions get a new ADR pointing back, never an edit of the old one. They earn their keep six months later, when someone asks why the team chose SQLite over a managed Postgres and the alternative is archaeology in Slack, and new joiners read the why behind the code instead of reverse-engineering it. Naming where the ADRs live, next to the code in the repo, is the practical detail interviewers like.

Explain the technical debt quadrant: deliberate versus inadvertent, prudent versus reckless.

Answer: Fowler’s quadrant sorts debt by intent and awareness. Deliberate and prudent: a documented shortcut to hit a date, with a repayment plan. Deliberate and reckless: we do not have time for design, said without a plan. Inadvertent and prudent: you shipped your best design and later learned a better one, the most common and most forgivable. Inadvertent and reckless: nobody on the team knew enough to see the mess. The quadrant matters because the response differs: planned debt gets scheduled and tracked, reckless debt gets process and mentoring, and pretending all debt is deliberate is the lie software development interview questions on this topic are designed to catch.

README, runbook, design doc: what belongs in each?

Answer: The README serves a newcomer’s first hour: what it is, install, run, test. The runbook serves the on-call engineer at 3am: what this service does, its failure modes, dashboards, alert meanings, and the exact remediation steps, written so a person who did not build it can act. The design doc serves the team before building: problem, constraints, options weighed, chosen approach, and what would change the decision. Documentation fails when layers blur, runbooks inside READMEs rot fastest, because operational reality drifts. Mapping documents to readers and moments is the whole answer.

What is a seam, and why does it matter for testing legacy code?

Answer: A seam is a place where you can change how code behaves without editing it in place: an injected dependency, an overridable method, an environment-variable-selected implementation. Seams are how legacy code becomes testable, because you carve one at the boundary where the hard dependency lives, substitute a test double through it, and suddenly the untestable module runs under pytest. Feathers’ Working Effectively with Legacy Code is built on this one idea. Finding a seam before proposing any refactor is the move that proves hands-on experience in software development interview questions about legacy code.

What properties make a codebase CI-friendly?

Answer: Small, independently testable modules, so a one-line change runs a one-minute slice instead of the whole suite. Deterministic tests, because a flaky pipeline trains everyone to ignore red. Hermetic builds: dependencies locked and vendored, no network surprises, artifacts reproducible from a clean checkout. Parallelizable suites with explicit markers separating unit from integration tiers. And fast feedback by design: lint and unit tests in the first minutes, heavier tiers later or nightly. Every one of those properties is a design decision in the codebase first and a pipeline setting second, which is the point software development interview questions on CI-friendly architecture are making.

Scenario and troubleshooting software development interview questions

This tier is the judgment round: one realistic sentence, then silence while you think out loud. For every item, the graded skill is identical: state your first move and the reasoning behind the order, then name the tradeoff and its owner. Silence plus a shrug loses to a spoken plan almost every time, and that plan is what these software development interview questions actually measure.

You must add a feature to a legacy module with no tests and heavy coupling. What is your sequence?

Answer: Order: pin, carve, test, change. First, write characterization tests around the paths my feature will touch, capturing current behavior including its bugs, so refactoring cannot silently move anything. Second, find or carve a seam at the boundary where the new logic belongs: extract a pure function or inject the hard dependency, without changing behavior, tests still green. Third, write real unit tests against the new seam for the behavior I am adding. Only then implement the feature in the isolated unit. The discipline to state out loud: no feature code until the safety net exists, because that sequence is exactly what separates engineers who can work in legacy code from engineers who only work in greenfield. This is the most common of all legacy-focused software development interview questions.

A test passes locally and fails in CI intermittently. How do you triage it?

Answer: First, reproduce with intent: run the single test in a loop against the CI environment shape, same container image, same parallelism, pytest -x --count or a loop script, because a flake you cannot reproduce you cannot fix. Second, classify by category: time or timezone dependence, unordered maps and sets, shared state between tests, real network calls, port collisions under parallelism, or resource-dependent timing like sleeps used as synchronization. Third, fix at the cause: freeze the clock, seed randomness, isolate fixtures, await conditions instead of sleeping. Last, decide the interim policy: quarantine the test, visible and ticketed, never silently skip, because deleted or skipped flakes take their signal with them. Re-run-until-green is not a policy, and saying that plainly is what flake-focused software development interview questions are listening for.

You and your reviewer disagree about an approach, and the pull request is stuck. What do you do?

Answer: Separate the question of taste from the question of substance. First, restate their objection in your own words and ask what risk it addresses, because many disagreements dissolve once the actual concern is named. If it is substantive, get evidence: a benchmark, a small prototype of their alternative, a citation from the codebase’s own conventions, and let the artifact argue. If it is taste and their way is defensible, concede quickly and say so; the review loop is more expensive than the difference. If it is substantive and unresolved, escalate the decision, not the person: take both options to the team channel or tech lead with a one-paragraph tradeoff summary and a recommendation. The rule to state: opinions are fine, deadlocks are not, and decisions belong to the team, not to whoever reviews last. Of all software development interview questions about review culture, this one rewards the calmest ending.

A feature must ship by a hard deadline, and the shortcut adds real debt. How do you decide?

Answer: Make the debt a decision with a price tag instead of a mood. First, size both options honestly: the shortcut’s cost and the clean path’s cost, in days, and what each delays. Second, bound the shortcut concretely: which corners exactly, what risk they create, what the repayment costs later. Third, put the tradeoff to the accountable owner, usually the product owner, in one paragraph with a recommendation, because shipping debt is a business call, not an engineering fiat. Then, if you proceed, leave a track: a debt ticket with the design sketched, linked in the code with a comment explaining the constraint and the date. Debt taken deliberately with a repayment plan is engineering; debt taken silently is the failure mode. That framing is what deadline-driven software development interview questions are grading.

Staging passes, production fails, and the environments have drifted. How do you handle it?

Answer: Diagnose with the drift hypothesis first: diff the two environments along the axes that actually differ. Config and secrets: same keys, same values, same feature flags. Versions: application build, dependency lockfiles, base images, schema migrations applied. Data and scale: staging’s toy dataset versus production volume, row counts that change query plans. Infrastructure: instance sizes, network policy, adjacent services staging does not run. Reproduce the failure against a production-shaped setup, an ephemeral environment from the same manifests, then fix in code or config in one place, and close the loop by making drift impossible to rebuild: single source of truth for config, same deploy pipeline for both, and a scheduled drift check that diffs environments and alerts. Environments that are built, not tended, is the closing principle, and it is the level software development interview questions grade on drift.

You maintain a published library and must ship a breaking API change. Walk through the rollout.

Answer: Treat it as a migration project with telemetry, in six steps. First, design the replacement API and confirm it covers every known use case from real consumers. Second, announce: changelog, migration guide, and the removal version, named explicitly. Third, ship the new API in a minor release alongside the old one, marking the old path deprecated with runtime warnings, a log line or a Deprecation header, so consumers discover it in their own dashboards. Fourth, watch usage telemetry of the deprecated path until it decays toward zero, chasing the stragglers directly. Fifth, remove the old API in the next major with the version bump semver demands and release notes that repeat the migration guide. Sixth, keep the guide pinned after removal, because stragglers arrive for months. This sequence, window plus telemetry plus major bump, is the full-credit answer to breaking-change software development interview questions.

Rolling out a breaking change without breaking anyone 1. Design replacement covers real consumer use 2. Announce changelog, migration guide, removal version 3. Dual run new API ships, old one warns as deprecated 4. Watch telemetry on the old path decays to zero 5. Remove next major bump, notes repeat the guide the deprecation window belongs to consumers: warnings in their logs, usage on your dashboard, and removal only when the old path is measurably quiet no telemetry on the old path? do not remove it yet.
The five-stage breaking change rollout: the window is measured by observed usage, not by calendar optimism.
The test suite takes 90 minutes and gates every merge. What do you do?

Answer: Measure before cutting: instrument per-test durations and identify the shape of the cost. Usual findings in order of likelihood: a small set of pathological tests, each tens of seconds of sleeps or network; missing parallelism the hardware already supports; integration tests doing setup work every test instead of per suite; and a long e2e tail running scenarios that duplicate lower tiers. Then act in that order: fix or demote the pathological tests, shard the suite across workers, share fixtures per suite, convert fat e2e scenarios into unit and integration tests around the same behavior. Finally, split the gate: lint plus affected unit tests must pass to merge, full suite runs on merge and nightly. The principle to close on: the pipeline’s critical path is a design property of the codebase, not a settings problem. Expect software development interview questions to push on what you would cut first, so know your order.

Coverage is 80 percent, but bugs keep reaching production. Why, and what do you change?

Answer: Because coverage counts execution, not assertion, and neither counts risk. Diagnose where bugs actually escape: pull the last quarter of incidents and tag each by what a test would have needed. Typical findings: unasserted tests that execute code without checking anything, boundary conditions the happy-path tests never hit, concurrency and timing paths, and config or data-shape surprises that only appear in production. Then change the investment: mutation-score the critical modules to find the unasserted tests, write regression tests from every escaped bug, and put edge-case tests where the incident data says the pain is. Coverage becomes a gap detector for the modules that matter, not a target. That data-first reframe is what coverage-focused software development interview questions are after.

A unit test suite is coupled to implementation details, so every refactor breaks dozens of tests. How do you fix it?

Answer: The suite is asserting interactions instead of outcomes: mock expectations on internal calls, private state poked directly, exact call orders pinned. Triage it in three moves. First, categorize failures on a real refactor: tests that break despite identical behavior are implementation-coupled, and they are the target set. Second, rewrite those tests against the public contract: given inputs, assert on returned values or observable state, through fakes for dependencies instead of mocks that verify mechanics. Third, adopt the norm going forward: mock only boundaries you own, and review any test that fails on a behavior-preserving change as a test bug. The sentence to land: tests are clients of the code, and good clients depend on the interface, not the internals. That rewrite-against-the-contract discipline is the working half of software development interview questions about brittle suites.

A god class grew around configuration and startup logic. What is your refactoring plan?

Answer: Plan it as a sequence of behavior-preserving steps, each shippable. First, add characterization tests over the class’s public surface, so the pinning exists before anything moves. Second, map the responsibilities inside it, parsing, validation, wiring, defaults, and rank them by how often they change. Third, extract one responsibility at a time into a module with a narrow interface, running the pinning suite after every extraction, smallest and most volatile first for the fastest payoff. Fourth, once the class is a thin composition root, invert the wiring: the extracted modules take their dependencies as parameters instead of importing the singleton. Fifth, delete the leftovers and write the ADR documenting the target shape. Never attempt the big-bang rewrite alternative without a strangler plan, because the god class exists because nobody could safely touch it.

A pull request is 3,000 lines and nobody is reviewing it. What now?

Answer: Do not review it as one unit; nobody does that well. First, the author or you restructure it: either stack it into a chain of small, individually reviewable changes, or find the seams where independent pieces can split into separate PRs, generated code and vendored files marked and excluded. Second, review the core by hand and the bulk by machine: generated migrations, lockfiles, and bulk renames get a token-level skim plus the CI signal, while the design-bearing files get line-level review. Third, land the reviewable parts and let the rest follow. Then fix the loop that produced it: agree on a soft size ceiling, around 400 lines, and make stacked PRs the standard path for large work. The inspection you state out loud: a PR that cannot be split usually means the change is entangled, and entanglement is the real finding.

Copy-pasted logic has spread across three services and they are already diverging. How do you consolidate?

Answer: Establish the truth before the move: diff the three copies behaviorally, because divergence means at least one service is wrong or serving a variant nobody documented, and that decision needs an owner before any code moves. Then choose the consolidation shape by coupling tolerance: a shared library for stable, pure logic that changes rarely, which pins version alignment as a new cost, or a small service owning the logic behind an API when independent deployment matters more than latency. Migrate one consumer at a time behind a flag or a versioned client, with parity tests comparing old and new outputs during the transition, and delete each copy as it switches. The sentence that earns credit: duplication of knowledge is the bug, and the diff you just read is its symptom. It is among the most practical software development interview questions for senior candidates, because nearly every team carries this debt.

A critical CVE lands in a dependency and the fixed version has breaking changes. What is your path?

Answer: Triage exposure before code: is the vulnerable code path reachable in your usage, and what does the CVE actually exploit, because severity for you is exposure times exploitability, not the advisory’s number. In parallel, read the breaking changes and size the upgrade honestly: what your own tests will catch and what they will not. If exposure is real and the upgrade is small, do it now with a focused regression pass. If the upgrade is large, upgrade the dependency in a branch while containing exposure in production: WAF rule, config to avoid the vulnerable path, or a patched fork as an explicitly temporary measure with a removal date. Ship the upgrade behind your normal review and watch the affected paths. The principle to state: CVEs buy urgency, not exemption from the normal quality gates.

A singleton causes race conditions under load. How do you find and fix it?

Answer: Confirm mechanism first: the singleton’s mutable state is shared by every caller, so races appear when two threads touch it concurrently, and symptoms are load-shaped, rare, and unreproducible on a laptop. Evidence: run with the race detector, go test -race or ThreadSanitizer equivalents, review the singleton for unsynchronized fields, and check for check-then-act patterns in its lazy initialization. Fix in layers: make initialization thread-safe once, a language-level idiom or eager init, then decide whether the shared mutable state is even needed, because the durable fix is usually replacing the singleton with dependencies created at composition time and injected, one per context or one immutable instance. Verify with the race detector under parallel tests and a load test. Naming the lazy-init race specifically is the detail that shows you have met this in production.

Main is red on an end-to-end test and nobody knows which commit broke it. What is your process?

Answer: Stop the bleeding first: main is the team’s source of truth, so either fix forward fast or revert the suspect range and investigate on a branch, because a red main taxes every engineer on the team per hour. Then localize: use git bisect against the failing test, automated so each step is a checkout plus a targeted run, not the full 40-minute suite; the same bisection on CI applies if the failure is environment-shaped. Confirm the culprit by reverting the found commit and watching the test pass, then fix or re-land properly. Close the systemic gap: the e2e test should identify itself with the behavior it guards so failures are readable, and culprit hunts faster than an hour mean the suite is too coarse. The order, restore green, then attribute, is exactly what software development interview questions on broken mains are grading.

New engineers need days to get the app running locally. What do you change?

Answer: Treat onboarding time as a build-health metric with an owner. First, time a clean run yourself on a fresh machine or container, recording every failure, because the actual setup path is always different from the documented one. Second, fix in order of leverage: a script or Compose file that starts every dependency with pinned versions, sane defaults so the app runs with zero manual config, a bootstrap command that lints and tests to prove the install, and a README rewritten to match reality, then validated by having it executed on a clean checkout in CI so it cannot rot silently. Third, remove the tribal knowledge: every step that only exists in someone’s head becomes part of the script. Target and announce a number, clone-to-running in under 30 minutes, and measure new-hire time to first merged PR.

Two teams keep colliding in the same files, and merge conflicts burn days. What is the architectural fix?

Answer: Conflicts are a symptom of a missing module boundary: two teams, one shared file, means the code has no owner-shaped seams. First, examine what both teams keep changing in those files; the churn pattern usually reveals a responsibility nobody extracted, and that responsibility becomes a module with an interface. Second, enforce the boundary mechanically: import linters or CODEOWNERS so each team’s directory has one owner and cross-boundary calls go through the exported contract. Third, if both teams genuinely need to extend the same behavior, provide a registration or plugin point so extension means adding a file, not editing shared ones. Until the refactor lands, stagger the teams’ changes with a shared ownership note on the files. The line to deliver: Conway’s law is already in your merge conflicts; make the architecture agree with it.

Dozens of stale feature flags litter the codebase. What is the cleanup strategy?

Answer: Inventory before deleting: list every flag with owner, creation date, purpose, and current state in production, most flag systems expose this, and mark the ones whose experiment window closed long ago. Then delete in batches by blast radius: flags with a single call site and an obvious default go first, verified by the test matrix running both states one last time; flags wrapped in business decisions get their owner’s sign-off recorded in the removal PR. Prevent the regrowth with policy at creation: every flag is registered with an owner and an expiry date, and the registry check runs in CI, because flags without expiry are how the debt started. Flag cleanup is also behavior cleanup: each removal simplifies the state space the team has to reason about, which is the closing argument.

A production defect slipped past a green test suite. How do you run the gap analysis?

Answer: In order: reproduce the defect as a failing test first, red against current main, because that converts the incident into a permanent regression test and proves you understand the failure. Then ask why the suite missed it, choosing from the standard gaps: the behavior was untested, the test existed but asserted too weakly, the test mocked the failing component away, the input space boundary was never exercised, or the failure needed production scale or data shapes. Fix the class, not just the case: if mocks hid it, add a contract or integration test at that boundary; if boundaries miss, add property-based or table-driven tests over the input space. Then check sibling code paths for the same hole. The outcome to state: every escaped defect leaves the suite measurably stronger, and that expectation is the culture this analysis exists to build. Few software development interview questions reward humility plus systems thinking as directly as this one.

A design spike overran its timebox with no decision. What do you do?

Answer: Diagnose which failure mode you are in, because the responses differ. If the spike is exploring endlessly, cut scope: force the choice by writing the two or three candidate designs as one-paragraph tradeoff docs and picking one with explicit reversal conditions, because a reversible decision made now beats a perfect one made in two more weeks. If the spike revealed genuine unknowns, split it: what was learned becomes a written finding, and the remaining unknown becomes a new, smaller spike with a sharper question and a hard exit criterion. If nobody defined done for the spike, that is the root cause, and the fix is requiring every spike to state its decision deadline and the shape of its output before it starts. Timeboxes exist to force decisions, not to schedule wandering.

Velocity has dropped three sprints running and the team is missing commitments. How do you diagnose it?

Answer: Diagnose before re-planning, because the causes have different owners. Check the work first: are items actually sliced small, or are epics masquerading as stories that always spill? Check the system: how much time goes to unplanned work, production firefighting, interviews, support, because inflight load is invisible in velocity but eats the sprint. Check the process: is the definition of done drifting heavier, reviews stacking up, or the backlog filling with dependencies that stall mid-sprint? Check the people axis honestly: a re-teamed or reduced team resets the calibration. Then act on the largest factor, usually unplanned work, which needs capacity carved for it explicitly rather than absorbed silently. Presenting velocity as a symptom to investigate rather than a number to push is exactly the maturity this scenario is screening for.

A hotfix must ship now, but the release branches are a tangle. What is the safe path?

Answer: Fix on the oldest branch that still runs production, because the hotfix must apply where the bug lives, then cherry-pick forward: branch from the release tag, commit the minimal fix with its regression test, and ship through the release pipeline with its checks intact, no local builds under time pressure. Then propagate: cherry-pick the same commit to every maintained release line and merge to main, so the next release cannot silently resurrect the bug, and tag it as a patch release per semver. Pay the process debt immediately: a written rule that release branches are cut per release and maintained only for supported versions, plus a rehearsal, because branches untangled during an incident stay tangled afterward. The commitment to state: the regression test rides with the hotfix, not after it. This is among the most common scenario software development interview questions for release-focused roles.

One engineer is the only person who understands the billing module. How do you de-risk it?

Answer: Work four levers in parallel, because bus factor is a knowledge-transfer problem with a scheduling component. First, pin behavior: characterization tests over the module’s public surface, written with the owner’s help while they are available, so the safety net does not depend on memory. Second, transfer in chunks: pair on real tickets in the module, rotate a second engineer through its on-call and small changes, and record short walkthroughs mapped to the code. Third, extract the documentation the module lacks: a one-page map of what it does, its invariants, and its known sharp edges, plus an ADR for anything the owner decides from memory. Fourth, de-scarify the code itself on the way: the owner refactors the worst seams with tests green. Verify the risk is actually reduced with a brutal test: the second engineer ships a small change to the module without the owner in the room.

A performance regression shipped quietly two releases ago. How do you catch it and prevent the next one?

Answer: Recover first, prevent second. To catch it: bisect releases against a reproducible benchmark or the production trace that exposes the regression, isolate the mechanism with a profiler, allocation churn, a new lock, an extra query per item, and fix or revert with the benchmark proving the recovery. To prevent the next one: add the missing tripwires, a benchmark suite on the critical paths running in CI with explicit budgets and failing on regression beyond tolerance, plus production signals on the same paths, latency percentiles per endpoint and allocation rates, alerting on sustained shifts. The cultural piece to name: budgets make performance a reviewed property like correctness, because it feels slower is not a gate, and benchmarks drift without owners, becoming wallpaper within two quarters. Prevention-first framing is the level software development interview questions on regressions probe for.

The backlog has 400 stale issues nobody triages. How do you fix prioritization?

Answer: Declare triage bankruptcy and rebuild rather than archaeology. First, bulk-close with a public rule: anything untouched beyond a horizon, a year for bugs, a quarter for ideas, is closed with a comment inviting reporters to reopen if it still bites, because reopeners are the true signal. Second, triage what remains into a small, ordered set: bugs ranked by user impact and frequency, ideas parked in a separate parking lot that is explicitly not commitments. Third, prevent the regrowth with an intake contract: new issues get a template with impact and reproduction, a named owner triages within the week, and the backlog carries a soft cap. The principle to articulate: a backlog is a prioritized plan, not an archive, and a 400-item list communicates nothing because priority is a position, not a label.

A junior engineer’s pull requests keep bouncing in review, and weeks in, they are stuck. How do you unblock them?

Answer: Diagnose the loop before coaching: read the last three PR threads and classify the objections. If reviews demand rewrites on taste, the problem is review standards, and the fix is a written convention or an example PR, not more rounds for the junior. If the diffs are genuinely large, the problem is slicing, and you pair on breaking the next task into shippable steps under a few hundred lines. If feedback is correct but dense, the fix is a review contract: one round of consolidated comments, each tied to a written convention, then approve and coach separately. In every branch, close the loop with synchronous time: pair on the next PR from a blank editor so habits form before the review, not after. The metric to watch: time to first approving review, which should fall within two cycles.

Hands-on scenario labs

Reading answers builds vocabulary; the scenario tier of software development interview questions is graded on reflexes, and reflexes come from repetition. Each lab below is safe to run in a throwaway repo or container. Do each one three times: once with the checklist open, once from memory, and once narrating out loud as if an interviewer were listening, because that narration is the exact rehearsal the judgment round rewards.

Lab 1: practice the red-green-refactor loop on a real function

  • Create a scratch repo with git init slugify-lab && cd slugify-lab, and write test_slugify.py with one failing test for a function that turns "Hello CI World" into hello-ci-world.
  • Run pytest -x -q, confirm red for the right reason, then write the least code in slugify.py that passes, nothing more.
  • Add the edge cases one at a time, punctuation, repeated spaces, uppercase input, going red then green for each, and feel how the suite becomes a spec.
  • Refactor once green: rename for clarity and extract the normalization step, then rerun pytest -q to prove behavior never moved.
  • Commit at every color change with git commit -am "green: handle punctuation" so the loop is visible in history.

Lab 2: refactor a legacy function under characterization tests

  • Write or find a deliberately gnarly function, 50 lines of nested branches and mutation, and drop it in legacy.py untouched.
  • Write characterization tests that pin current outputs for six inputs, including one that exposes an existing bug, and run pytest -q to green.
  • Mark the bug with a comment, fix it in a separate commit, and update only that one assertion, narrating why the fix is deliberate rather than silent.
  • Extract the pure core into normalize() and inject the config values that were hardcoded, rerunning the pinning suite after each move.
  • Measure the before and after with pytest --cov=legacy --cov-report=term-missing and git diff --stat, then explain out loud why the behavior contract held.

Lab 3: run an integration test against an ephemeral database

  • Start a disposable dependency: docker run -d --rm --name labpg -e POSTGRES_PASSWORD=lab -p 55432:5432 postgres:16, and note that nothing persists anywhere.
  • Write an integration test in test_repo.py that connects to localhost:55432, inserts a row, reads it back, and asserts the round trip.
  • Run it with pytest -m integration -q, then prove determinism by running it twice and by breaking the schema once to watch it fail loudly.
  • Stop the container with docker stop labpg, rerun, and observe the clean failure that proves no shared state was hiding in the environment.
  • Finish by writing the two-sentence argument for ephemeral dependencies over a shared staging database, as you would say it in an interview.

Cheat sheet: the commands behind the answers

Almost every item in this bank of software development interview questions resolves to one of the commands below, used in the same order you would reach for them live. Learn the table, then attach one spoken sentence to each row, and the practical half of any round stops being improvised.

CommandWhat it tells you
pytest -x -qStop at the first failure; the fastest red-to-fix loop while developing
pytest -k "slugify"Run one slice of the suite by name, the unit-level feedback path
pytest -m "not integration"Split tiers so merge checks stay fast and heavy tests run later
pytest --lfRerun only the last failures when cycling on a bug
pytest --cov=src --cov-report=term-missingCoverage with the uncovered lines named, a gap detector not a target
go test ./... -count=1Defeat cached results when a test’s verdict differs between runs
go test -race ./...Data race detection for shared-state and singleton bugs
git bisect startBinary search the commit that broke a behavior, scripted against one test
git blame -L 40,60 fileWho wrote a line and when, the context you owe a reviewer before judging
git diff main...HEAD --statA pull request’s footprint at a glance, the small-PR habit enforcer
git shortlog -snCommits per author, a quick bus-factor probe on any module
ruff check . / eslint .Static analysis before a human reads the diff, the cheap half of review
pre-commit run --all-filesThe repo’s hook gates locally, so CI surprises stay rare
docker run -d -p 55432:5432 postgres:16An ephemeral, version-pinned dependency for integration tests
mutmut runMutation testing: do the tests fail when behavior actually changes
npm outdated / go list -m -u allDependency drift and available upgrades feeding the CVE triage question
npm version minor / git tag -a v2.1.0Cut a release at the semver bump the change actually deserves
gh pr checks / gh pr diffReview state and diff from the terminal, the triage view of the queue
grep -rn "TODO\|FIXME" src | wc -lSize the debt census honestly before arguing about it
find src -name "*.py" | xargs wc -l | sort -n | tailFind the god files before they find you; churn plus size is smell
time pytest -qSuite duration, the number that quietly gates every merge on the team
docker compose up -dThe whole local environment in one command, the clone-to-running goal

Versioning rules live at semver.org, and the debt framing behind half the scenario answers is best read in Fowler’s original TechnicalDebt article. Both are short, and both arm you for the citation moments software development interview questions occasionally contain.

Key takeaways and FAQ

The through-line of every tier above: software development interview questions reward candidates who pair a term with its mechanism and a scenario with its first move. A definition alone reads as memorization; a mechanism alone reads as theory; together they read like someone whose code other people can maintain. Keep that pairing in every rehearsal, and this bank becomes a script for the whole loop.

How long should I prepare for software development interview questions?

With daily coding in your current role, a focused week: two days speaking the beginner tier aloud, two on intermediate, one on scenarios, the weekend on the labs. If you mostly configure rather than code, plan three weeks and do every lab twice, because the scenario round is scored on reflexes that only practice builds.

Do DevOps and SRE roles really face software development interview questions?

Increasingly yes, because infrastructure code is code: pipelines, controllers, and automation outlive the people who wrote them. The emphasis differs from backend loops, less algorithm golf, more maintainability, testing strategy, and judgment calls about debt and reviews, which is exactly the weighting this page uses. Prepare the full bank either way.

Do I need to memorize all 23 GoF design patterns for software development interview questions?

No. Know five cold, factory, observer, strategy, proxy, decorator, because they cover most questions and most real tooling, and be able to name where each already lives in a stack you maintain. A taxonomy recited without application reads weaker than four patterns grounded in your own code, and interviewers know it.

What if my team does not practice agile by the book?

Almost nobody does, and interviewers know that too. The strong answer describes what your team actually does, which ceremonies earn their time and which decayed, and one thing you changed about the process that measurably helped. Honest specificity beats textbook Scrum in every software development interview question about process, because the question is really checking whether you reflect on how work works.

How technical are the scenario rounds compared to the definitions?

The scenarios are less about recall and more about ordering: name the first move and why it comes first, the tradeoff and its owner, and the prevention step afterward. Practice each scenario on this page as a 60-second spoken answer with an explicit sequence, and software development interview questions in the judgment round become the easiest part of the loop instead of the hardest.

What should I read after this page?

Continue with the Git interview questions bank, since version control mechanics sit under half the collaboration scenarios here, and the CI/CD interview questions bank for the pipeline side of the testing and release topics this page introduces. Then browse the DevOps Prep hub for the rest of the series as it ships.

Software Development Prep Quiz: SOLID, Testing, and Judgment Calls

1 / 5

A subclass of a List class throws an exception on every add() call. Which SOLID principle does this violate?

2 / 5

One test fails in CI about one run in five but always passes on rerun. What is the professionally correct first move?

3 / 5

A team's suite is mostly end-to-end tests, takes 90 minutes, and fails randomly most weeks. What does the testing pyramid prescribe?

4 / 5

Your client code uses an if/elif ladder to pick exponential, fixed, or no retry logic in three places. What is the standard fix?

5 / 5

You must remove a documented endpoint from your published HTTP API. What does semver require?

0%