{"id":1975,"date":"2026-07-20T10:08:24","date_gmt":"2026-07-20T04:38:24","guid":{"rendered":"https:\/\/lastroundai.com\/blog\/?post_type=iq&#038;p=1975"},"modified":"2026-07-20T10:26:52","modified_gmt":"2026-07-20T04:56:52","slug":"thoughtworks","status":"publish","type":"iq","link":"https:\/\/lastroundai.com\/interview-questions\/thoughtworks","title":{"rendered":"ThoughtWorks Interview Questions (2026), Real, With Answers"},"content":{"rendered":"<p>A candidate who&#8217;d cleared four rounds at a big product company in six weeks once told me the ThoughtWorks loop was the first one that made him nervous about a laptop he never had to touch alone. There&#8217;s no algorithm quiz on a shared doc. Instead there&#8217;s a real editor, and a consultant sitting next to him for close to two hours asking him to write tests first and explain every decision out loud as he types. ThoughtWorks describes its own process as &#8220;collaborative&#8221; on its careers site, built around a recruiter conversation, a technical stage that can include pair programming, case studies, and design challenges, and a separate conversation about leadership and culture fit (<a href=\"https:\/\/www.thoughtworks.com\/careers\" target=\"_blank\" rel=\"noopener noreferrer\">ThoughtWorks Careers<\/a>). For entry-level graduate hires through the STEP program, that technical stage is preceded by an aptitude MCQ round and a shorter phone screen before the onsite.<\/p>\n<p>Candidates on Indeed rate the overall difficulty around 6 out of 10 and the timeline close to a month end to end, with a chunk reporting it stretches past that (<a href=\"https:\/\/www.indeed.com\/cmp\/Thoughtworks\/interviews\" target=\"_blank\" rel=\"noopener noreferrer\">Indeed, ThoughtWorks interview reviews<\/a>). What makes the loop distinct isn&#8217;t difficulty in the LeetCode sense. It&#8217;s that the pairing round splits into two separate sessions, often with two different consultants, specifically so nobody&#8217;s day gets defined by one person&#8217;s read of a candidate. One session usually leans toward a coding kata done test-first; the other leans toward reading and improving code that&#8217;s already there, closer to what a real engagement with a client looks like in week one.<\/p>\n<p>This page collects the actual questions candidates report being asked across that loop: the MCQ-style aptitude questions from the graduate screen, DSA problems from technical phone screens, the kata-style pairing problems ThoughtWorks is known for (Bowling Game, Mars Rover, Conference Track Scheduler, and the String Calculator kata originated by Roy Osherove and widely used across TDD-focused pairing rounds, per <a href=\"https:\/\/codingdojo.org\/kata\/\" target=\"_blank\" rel=\"noopener noreferrer\">Coding Dojo&#8217;s kata catalog<\/a>), CS fundamentals, low-level design prompts, and the values-driven behavioral questions the culture round is known for. Every question below is one you could actually be asked out loud. None of them are questions about the format of the interview itself.<\/p>\n<div class=\"iq-stats not-prose\"><div class=\"iq-stat\"><span class=\"iq-stat__value\">50<\/span><span class=\"iq-stat__label\">Questions<\/span><\/div><div class=\"iq-stat\"><span class=\"iq-stat__value\">4<\/span><span class=\"iq-stat__label\">Rounds<\/span><\/div><div class=\"iq-stat\"><span class=\"iq-stat__value\">Pair Programming<\/span><span class=\"iq-stat__label\">Format<\/span><\/div><div class=\"iq-stat\"><span class=\"iq-stat__value\">~1 Month<\/span><span class=\"iq-stat__label\">Timeline<\/span><\/div><\/div>\n<h2>Online assessment: aptitude and SQL screen<\/h2>\n<p>Graduate and campus hires usually see this first at ThoughtWorks, before any human enters the loop. It&#8217;s short, timed, and closer to a logic test than a programming exam.<\/p>\n<div class=\"iq-dsec iq-dsec--easy\"><div class=\"iq-dsec__row\"><h2 class=\"iq-dsec__h\" id=\"easy\"><span class=\"iq-dsec__dot\" aria-hidden=\"true\"><\/span>Easy questions<\/h2><span class=\"iq-dsec__n\">19<\/span><\/div><div class=\"iq-dsec__bar\" aria-hidden=\"true\"><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">If a train covers 60 km in 45 minutes, what is its average speed in km\/h?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Aptitude<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>This is 60 divided by 0.75 hours, which comes out to 80 km\/h. The trap isn&#8217;t the arithmetic, it&#8217;s converting 45 minutes to 0.75 hours before dividing rather than dividing by 45 and fixing units afterward. Candidates who set up the unit conversion first almost never get this wrong; candidates who try to do it in their head backwards from km\/h sometimes do.<\/p>\n<p>Interviewers use a handful of these early because a candidate who visibly slows down and writes out units, rather than guessing at a formula, tends to carry that same discipline into the pairing session later that day.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Find the next number in the series: 2, 6, 12, 20, 30, ?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Aptitude<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>The differences between consecutive terms are 4, 6, 8, 10, which themselves increase by 2 each time. The next difference is 12, so the next term is 30 + 12 = 42. Another way to see it: each term is n(n+1), so the sixth term is 6 x 7 = 42.<\/p>\n<p>Both routes get the same answer, and either is a fine thing to say out loud in a ThoughtWorks screen. What the screen is actually checking is whether you can spot a second-order pattern at all, not which method you use to get there.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">A shopkeeper marks up an item by 25% and then offers a 10% discount on the marked price. What is the net profit percentage?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Aptitude<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Take a cost price of 100. Marked price after a 25% markup is 125. A 10% discount on 125 is 12.5, so the selling price is 112.5. Net profit is 12.5 on a cost of 100, which is a 12.5% profit.<\/p>\n<p>The common mistake is subtracting the two percentages directly, 25% minus 10%, and answering 15%. Markup and discount apply to different base amounts, the cost price and the marked price respectively, so they don&#8217;t combine by simple subtraction.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Reverse a singly linked list in place.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Data Structures<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Walk the list once, keeping track of the previous node, and flip each node&#8217;s next pointer to point backward instead of forward.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">java<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-java\">\n\nNode reverse(Node head) {\n\n    Node prev = null;\n\n    Node curr = head;\n\n    while (curr != null) {\n\n        Node next = curr.next;\n\n        curr.next = prev;\n\n        prev = curr;\n\n        curr = next;\n\n    }\n\n    return prev;\n\n}\n<\/code><\/pre><\/div><\/p>\n<p>The follow-up a ThoughtWorks interviewer usually has ready: can you do it recursively, and what&#8217;s the tradeoff? Recursive reversal is a few lines shorter but costs O(n) stack space instead of O(1), which matters on a long list where the iterative version is the safer default.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Given an array of integers and a target value, find two numbers that add up to the target.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Arrays<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>The brute-force nested loop is O(n squared) and is the wrong answer here on purpose, it exists so you can name the tradeoff before improving it. A single pass with a hash map gets you O(n) time and O(n) space: for each number, check whether target minus that number has already been seen.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">python<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-python\">\n\ndef two_sum(nums, target):\n\n    seen = {}\n\n    for i, n in enumerate(nums):\n\n        complement = target \u2013 n\n\n        if complement in seen:\n\n            return [seen[complement], i]\n\n        seen[n] = i\n\n    return []\n<\/code><\/pre><\/div><br \/>\n<\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Given a string, find the first non-repeating character in it.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Strings<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Count every character&#8217;s frequency in one pass, then walk the string a second time and return the first character whose count is exactly one.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">python<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-python\">\n\ndef first_unique(s):\n\n    counts = {}\n\n    for c in s:\n\n        counts[c] = counts.get(c, 0) + 1\n\n    for c in s:\n\n        if counts[c] == 1:\n\n            return c\n\n    return None\n<\/code><\/pre><\/div><\/p>\n<p>Two passes, each O(n), which is worth stating explicitly since some candidates assume a two-pass solution is automatically worse than a one-pass one. It isn&#8217;t here, both are linear, and the two-pass version is easier to read correctly on the first try under time pressure.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Check whether a given string is a valid palindrome, ignoring case, spaces, and punctuation.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Strings<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Use two pointers starting from both ends, skipping any character that isn&#8217;t alphanumeric, and compare the remaining characters case-insensitively as the pointers move toward the middle.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">python<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-python\">\n\ndef is_palindrome(s):\n\n    left, right = 0, len(s) \u2013 1\n\n    while left &lt; right:\n\n        while left &lt; right and not s[left].isalnum():\n\n            left += 1\n\n        while left &lt; right and not s[right].isalnum():\n\n            right -= 1\n\n        if s[left].lower() != s[right].lower():\n\n            return False\n\n        left += 1\n\n        right -= 1\n\n    return True\n<\/code><\/pre><\/div><br \/>\n<\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Given a binary tree, find its maximum depth.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Trees<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>The depth of an empty tree is zero. Otherwise it&#8217;s one plus the larger of the depths of the left and right subtrees, which is a direct recursive definition.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">java<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-java\">\n\nint maxDepth(Node root) {\n\n    if (root == null) return 0;\n\n    return 1 + Math.max(maxDepth(root.left), maxDepth(root.right));\n\n}\n<\/code><\/pre><\/div><\/p>\n<p>Interviewers sometimes ask you to convert this to an iterative version using a queue or stack right after you finish the recursive one, mostly to see whether you understand why the recursive version works rather than having memorized it.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Determine whether two given strings are anagrams of each other.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Strings<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Sort both strings and compare, which is O(n log n), or count character frequencies in both and compare the counts, which is O(n). The frequency-count version is the one worth leading with once asked to optimize.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">python<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-python\">\n\nfrom collections import Counter\ndef is_anagram(a, b):\n\n    return Counter(a) == Counter(b)\n<\/code><\/pre><\/div><br \/>\n<\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Implement FizzBuzz, then extend it so the rules are configurable, for example print Fizz for multiples of 3, Buzz for multiples of 5, and Bazz for multiples of 7, in any combination.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Pairing Kata<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>The base version is trivial and isn&#8217;t really the point. The extension is: instead of hardcoding a chain of if\/elif checks, store the rules as a list of (divisor, word) pairs and build the output by checking each rule in order.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">python<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-python\">\n\ndef fizzbuzz(n, rules=((3, \u201cFizz\u201d), (5, \u201cBuzz\u201d))):\n\n    result = []\n\n    for i in range(1, n + 1):\n\n        output = \u201c\u201d.join(word for divisor, word in rules if i % divisor == 0)\n\n        result.append(output or str(i))\n\n    return result\n<\/code><\/pre><\/div><\/p>\n<p>What the pairing partner is actually evaluating is whether you notice the hardcoded version doesn&#8217;t scale the moment a third or fourth rule gets added, and whether you refactor toward the data-driven version on your own before being asked to.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Implement a String Calculator that takes a string of numbers separated by commas and returns their sum, supporting an empty string returning zero and a newline as an alternative delimiter.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Pairing Kata<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>This is Roy Osherove&#8217;s well-known TDD kata, and the point of the exercise is the order you build it in, not the final code. You&#8217;re expected to write the smallest possible failing test first, empty string returns 0, make it pass, then add one test at a time: single number, two numbers, newline as a delimiter, and only then generalize.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">python<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-python\">\n\ndef add(numbers):\n\n    if numbers == \u201c\u201d:\n\n        return 0\n\n    normalized = numbers.replace(\u201c\\n\u201d, \u201c,\u201d)\n\n    return sum(int(n) for n in normalized.split(\u201c,\u201d))\n<\/code><\/pre><\/div><\/p>\n<p>Pairing partners notice candidates who write the fully general solution on the first line and then retrofit tests to match it. That inverts the exercise. The whole point is letting each new test case pull a small piece of new behavior out of you, one at a time.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the difference between a process and a thread?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Operating Systems<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A process is an independent unit of execution with its own memory space, file handles, and resources, isolated from other processes by the operating system. A thread is a unit of execution that lives inside a process and shares that process&#8217;s memory space with every other thread in it.<\/p>\n<p>That shared memory is exactly why threads are cheaper to create and communicate faster than processes, and exactly why they introduce race conditions that separate processes don&#8217;t have to worry about. Two threads writing to the same variable without synchronization can corrupt it. Two processes can&#8217;t touch each other&#8217;s memory at all without explicit inter-process communication, which is slower but a lot harder to get subtly wrong.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the difference between TCP and UDP, and when would you actually choose UDP?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Networking<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>TCP guarantees ordered, reliable delivery through acknowledgments and retransmission, at the cost of connection setup overhead and latency when packets need to be resent. UDP sends packets with no delivery guarantee, no ordering guarantee, and no connection setup, which makes it faster but leaves reliability entirely up to the application if it needs any at all.<\/p>\n<p>UDP makes sense wherever a late packet is worse than a lost one: live video calls, multiplayer game state, DNS lookups. A video frame that arrives 400 milliseconds late is useless anyway, so TCP&#8217;s retry logic just adds latency for no benefit. A banking transaction is the opposite case, where losing a packet silently is unacceptable and TCP&#8217;s guarantees are exactly what you want.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What does dependency injection actually solve, and can you point to a case where you used it?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Design Patterns<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Dependency injection means a class receives the objects it depends on from the outside, usually through its constructor, rather than constructing them itself internally. The class that needs a database connection doesn&#8217;t instantiate one directly, it accepts one as a parameter.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">java<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-java\">\n\n\/\/ Without DI: hard to test, tightly coupled to a real database\n\nclass OrderService {\n\n    private Database db = new PostgresDatabase();\n\n}\n\/\/ With DI: the caller decides what implementation to pass\n\nclass OrderService {\n\n    private Database db;\n\n    OrderService(Database db) { this.db = db; }\n\n}\n<\/code><\/pre><\/div><\/p>\n<p>The concrete payoff is testability, which is exactly what ThoughtWorks interviewers are probing for here. With injection, a test can pass in a fake database that returns fixed data instantly, instead of standing up a real database connection just to test business logic that has nothing to do with SQL.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s the difference between an abstract class and an interface, and when would you reach for one over the other?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">OOP<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>An abstract class can hold shared state and partial implementation that subclasses inherit directly, but a class can only extend one abstract class. An interface defines a contract with no shared implementation (outside default methods in newer language versions), but a class can implement as many interfaces as it needs.<\/p>\n<p>Reach for an abstract class when several related types genuinely share behavior, not just a shape, and reach for an interface when you&#8217;re defining a capability that unrelated types might all need to support. A Dog and a Car have nothing in common as classes, but both can reasonably implement a Comparable interface. ThoughtWorks pairing partners often ask this as a quick warm-up before moving into a design prompt.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Why ThoughtWorks?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Behavioral<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>The weak version of this answer is reciting the careers page back. The stronger version connects something specific ThoughtWorks is known for, its consulting model, its open-source contributions, its public stance on social and economic justice, to something concrete you&#8217;ve actually cared about in your own work, not just admired from a distance.<\/p>\n<p>Interviewers here aren&#8217;t looking for a rehearsed answer so much as a coherent one, something that would still make sense if they asked a follow-up about why that specific thing matters to you rather than letting you finish a memorized paragraph.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Tell me about a time you mentored someone less experienced than you.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Behavioral<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>The strongest answers here describe a specific person and a specific gap, not &#8220;I always help junior developers.&#8221; What did they not know, what did you actually do about it beyond answering questions when asked, and what changed for them afterward that you could point to concretely.<\/p>\n<p>A genuinely useful detail to include: a time mentoring didn&#8217;t go smoothly at first, and what you adjusted. That reads as more credible than a story where everything worked immediately, and it&#8217;s closer to what real mentoring on a client engagement actually looks like.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What&#039;s a technology decision on a past project you&#039;d make differently if you had to do it again?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Behavioral<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>This question is checking for honest self-assessment more than it&#8217;s checking for a specific technical answer. A candidate who can&#8217;t name a single decision they&#8217;d revisit reads as either inexperienced or unwilling to admit a mistake out loud, neither of which is a great signal for a consulting role where owning a wrong call in front of a client is part of the job.<\/p>\n<p>The stronger answers explain what information was missing at the time the original decision got made, not just what you know now that makes the old choice look bad in hindsight. Hindsight makes everything look obvious; the useful part of the answer is what would have actually changed your mind back then.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Tell me about a time you had to learn a new language or framework quickly for a project.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Behavioral<\/span><span class=\"iq-badge iq-badge--easy\">Easy<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>ThoughtWorks moves consultants across client stacks regularly, so this question is really asking whether you have a repeatable way to get productive in something unfamiliar fast, rather than whether you happen to already know a long list of languages.<\/p>\n<p>A specific, credible answer names the actual gap (a language, a framework, a domain you didn&#8217;t know), what you did in the first week that mattered most, and where you were still weak a month in and how that showed up. Vague answers, &#8220;I&#8217;m a fast learner, I picked it up quickly&#8221;, tend to get a direct follow-up asking for the actual timeline and what specifically you struggled with.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-dsec iq-dsec--medium\"><div class=\"iq-dsec__row\"><h2 class=\"iq-dsec__h\" id=\"medium\"><span class=\"iq-dsec__dot\" aria-hidden=\"true\"><\/span>Medium questions<\/h2><span class=\"iq-dsec__n\">22<\/span><\/div><div class=\"iq-dsec__bar\" aria-hidden=\"true\"><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Write a SQL query that returns the second-highest salary from an Employee table.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">SQL<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>The cleanest version avoids ties breaking the query and doesn&#8217;t assume a specific number of rows:<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">sql<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-sql\">\n\nSELECT MAX(salary) AS second_highest\n\nFROM Employee\n\nWHERE salary &lt; (SELECT MAX(salary) FROM Employee);\n<\/code><\/pre><\/div><\/p>\n<p>This works because it sidesteps offset-based approaches entirely: find the maximum salary strictly less than the overall maximum, and that&#8217;s the second-highest by definition, even if several employees share the top salary. A LIMIT\/OFFSET version, ORDER BY salary DESC LIMIT 1 OFFSET 1, looks simpler but silently returns the wrong row when two people are tied for first place, since both rows have the same top salary and the offset just skips one of them.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What does integer division of -7 by 2 return in Python, and why does that surprise people coming from Java or C?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Programming Fundamentals<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>In Python, -7 \/\/ 2 returns -4, not -3. Python&#8217;s floor division always rounds toward negative infinity, so it takes the floor of -3.5, which is -4. Java and C truncate toward zero instead, so the equivalent expression in those languages gives -3.<\/p>\n<p>The question is really testing whether a candidate has internalized that &#8220;integer division&#8221; isn&#8217;t one universal rule across languages, it&#8217;s a specific rounding behavior each language chose, and assuming your home language&#8217;s behavior transfers is exactly the kind of bug that survives code review and shows up in production months later.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Given a log file where each line has a timestamp, write a function to count unique visitors per hour.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Data Processing<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Parse each line, truncate the timestamp down to the hour, and use that truncated hour paired with a visitor identifier as a set key so repeat visits within the same hour don&#8217;t get double-counted.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">python<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-python\">\n\nfrom collections import defaultdict\ndef unique_visitors_per_hour(log_lines):\n\n    hourly = defaultdict(set)\n\n    for line in log_lines:\n\n        timestamp, visitor_id = parse_line(line)\n\n        hour_bucket = timestamp.replace(minute=0, second=0, microsecond=0)\n\n        hourly[hour_bucket].add(visitor_id)\n\n    return {hour: len(visitors) for hour, visitors in hourly.items()}\n<\/code><\/pre><\/div><\/p>\n<p>This one is really a data-modeling question dressed up as a coding problem, and it&#8217;s a favorite in ThoughtWorks technical screens for exactly that reason. The interviewer wants to see whether you reach for a set to dedupe correctly on your own, before being told the log has duplicate lines for a single visitor loading multiple assets in the same hour.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Detect whether a linked list contains a cycle.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Data Structures<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Floyd&#8217;s cycle detection, two pointers moving at different speeds through the same list, is the expected answer. If there&#8217;s no cycle, the fast pointer reaches the end. If there is one, the fast pointer eventually laps the slow pointer and they meet at the same node.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">java<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-java\">\n\nboolean hasCycle(Node head) {\n\n    Node slow = head, fast = head;\n\n    while (fast != null &amp;&amp; fast.next != null) {\n\n        slow = slow.next;\n\n        fast = fast.next.next;\n\n        if (slow == fast) return true;\n\n    }\n\n    return false;\n\n}\n<\/code><\/pre><\/div><\/p>\n<p>O(1) space is the point of this solution over a hash-set approach that stores every visited node. The interviewer usually asks you to name that tradeoff even if you don&#8217;t derive the algorithm from scratch under pressure.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Given an array of intervals, merge all overlapping intervals.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Arrays<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Sort the intervals by start time first. Then walk through them once, and whenever the current interval&#8217;s start is less than or equal to the end of the last merged interval, extend that merged interval instead of adding a new one.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">python<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-python\">\n\ndef merge(intervals):\n\n    intervals.sort(key=lambda x: x[0])\n\n    merged = [intervals[0]]\n\n    for start, end in intervals[1:]:\n\n        last_end = merged[-1][1]\n\n        if start &lt;= last_end:\n\n            merged[-1][1] = max(last_end, end)\n\n        else:\n\n            merged.append([start, end])\n\n    return merged\n<\/code><\/pre><\/div><br \/>\n<\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Write a function that flattens a nested list of arbitrary depth into a single flat list.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Recursion<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Walk the list, and for each element check whether it&#8217;s itself a list. If it is, recurse into it and extend the result; if it isn&#8217;t, append it directly. Depth isn&#8217;t known ahead of time, which is exactly why this has to be recursive rather than a fixed number of nested loops.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">python<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-python\">\n\ndef flatten(lst):\n\n    result = []\n\n    for item in lst:\n\n        if isinstance(item, list):\n\n            result.extend(flatten(item))\n\n        else:\n\n            result.append(item)\n\n    return result\n<\/code><\/pre><\/div><br \/>\n<\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Implement a Mars Rover that starts at a given position and heading on a grid, then executes a sequence of move-forward and turn commands, reporting its final position and heading.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Pairing Kata<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Model heading as one of four discrete states, N, E, S, W, and represent turning as moving forward or backward through that cycle rather than as a pile of separate if-branches for every possible current-heading-plus-turn combination.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">java<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-java\">\n\nclass Rover {\n\n    int x, y;\n\n    char[] headings = {\u2018N\u2019, \u2018E\u2019, \u2018S\u2019, \u2018W\u2019};\n\n    int headingIndex;\n    void turnRight() { headingIndex = (headingIndex + 1) % 4; }\n\n    void turnLeft() { headingIndex = (headingIndex + 3) % 4; }\n    void moveForward() {\n\n        switch (headings[headingIndex]) {\n\n            case \u2018N\u2019: y++; break;\n\n            case \u2018E\u2019: x++; break;\n\n            case \u2018S\u2019: y\u2013; break;\n\n            case \u2018W\u2019: x\u2013; break;\n\n        }\n\n    }\n\n}\n<\/code><\/pre><\/div><\/p>\n<p>The natural follow-up is adding obstacle detection, so a move command that would land on an obstacle gets rejected and reported instead of silently executed. Candidates whose original design cleanly separates &#8220;compute the next position&#8221; from &#8220;apply the move&#8221; tend to handle that follow-up in a couple of lines. Candidates who inlined everything into one big switch statement usually have to restructure first.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Given a list of conference talks, each with a title and a duration, implement a Conference Track Scheduler that packs them into morning and afternoon sessions of fixed length.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Pairing Kata<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>This is a bin-packing problem in disguise, and the expected approach is a greedy algorithm rather than an optimal one: sort talks by duration, then try to fill each session by picking talks that fit the remaining time, closest to full first.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">python<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-python\">\n\ndef pack_session(talks, session_length):\n\n    talks_sorted = sorted(talks, key=lambda t: -t.duration)\n\n    session, remaining = [], session_length\n\n    for talk in talks_sorted:\n\n        if talk.duration &lt;= remaining:\n\n            session.append(talk)\n\n            remaining -= talk.duration\n\n    return session\n<\/code><\/pre><\/div><\/p>\n<p>Pairing partners usually ask you upfront whether you&#8217;re solving for an optimal packing or a reasonable one, since true optimal bin packing is NP-hard. Saying that out loud and picking a greedy approach on purpose reads a lot better than silently building something that happens to be greedy without knowing why that&#8217;s the right tradeoff.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Refactor this function to remove the nested conditionals without changing its behavior.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Pairing Kata<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>This is a common ThoughtWorks pairing prompt because refactoring under someone&#8217;s eyes reveals a lot more than a from-scratch problem does.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">java<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-java\">\n\ndouble calculateDiscount(Customer customer, Order order) {\n\n    double discount = 0;\n\n    if (customer.isPremium()) {\n\n        if (order.getTotal() &gt; 100) {\n\n            discount = 0.2;\n\n        } else {\n\n            discount = 0.1;\n\n        }\n\n    } else {\n\n        if (order.getTotal() &gt; 200) {\n\n            discount = 0.05;\n\n        } else {\n\n            discount = 0;\n\n        }\n\n    }\n\n    return discount;\n\n}\n<\/code><\/pre><\/div><\/p>\n<p>Guard clauses collapse this into a flat sequence of early returns, which reads top to bottom without the reader having to hold two levels of state in their head at once:<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">java<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-java\">\n\ndouble calculateDiscount(Customer customer, Order order) {\n\n    if (customer.isPremium() &amp;&amp; order.getTotal() &gt; 100) return 0.2;\n\n    if (customer.isPremium()) return 0.1;\n\n    if (order.getTotal() &gt; 200) return 0.05;\n\n    return 0;\n\n}\n<\/code><\/pre><\/div><\/p>\n<p>The interviewer is watching for whether you refactor in small, verifiable steps, running the existing tests after each change, rather than rewriting the whole function at once and hoping it still behaves the same way.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Write the tests first for a function that calculates shipping cost based on package weight and destination zone, then implement it to make the tests pass.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Pairing Kata<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Start with the simplest case: a light package to the nearest zone, and write one assertion for it before any implementation exists. Add a case for a heavier package. Add a case for a farther zone. Only after several concrete cases exist does a general formula, or a lookup table if the rules are irregular, get introduced.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">python<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-python\">\n\ndef test_light_package_nearest_zone():\n\n    assert shipping_cost(weight=1, zone=1) == 5.0\ndef test_heavy_package_nearest_zone():\n\n    assert shipping_cost(weight=10, zone=1) == 15.0\ndef test_light_package_far_zone():\n\n    assert shipping_cost(weight=1, zone=3) == 9.0\ndef shipping_cost(weight, zone):\n\n    base = 5.0\n\n    per_kg = 1.0\n\n    per_zone = 2.0\n\n    return base + per_kg * (weight \u2013 1) + per_zone * (zone \u2013 1)\n<\/code><\/pre><\/div><\/p>\n<p>The reason this shows up so often in the pairing round: it&#8217;s a plausible five-minute slice of real client work, a pricing rule that will change again in six months, and it rewards writing the boring, obvious tests first instead of jumping straight to a clever general formula that might not match what the business actually needs.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">How does a hash map handle two keys that hash to the same bucket?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Data Structures<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Collisions are resolved either by chaining, where each bucket holds a small linked list (or, in modern Java, a balanced tree once a bucket gets large enough) of every entry that landed there, or by open addressing, where a colliding entry gets probed forward to the next available slot instead.<\/p>\n<p>The consequence worth naming: a hash map&#8217;s average-case O(1) lookup degrades toward O(n) if your hash function is bad enough that most keys collide into the same few buckets. A hash map is only as fast as its hash function is good at spreading keys evenly, which is why a poorly written equals\/hashCode override on a custom object is a real, recurring source of production performance bugs.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Explain composition over inheritance with a concrete example.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">OOP<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Inheritance models an is-a relationship and locks it in at compile time, a Duck is-a Bird. Composition models a has-a relationship and can change at runtime, a Duck has-a FlyBehavior it can swap out.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">java<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-java\">\n\n\/\/ Inheritance: every Duck subclass is stuck with whatever fly() Duck defines\n\nclass Duck { void fly() { \/* default flying *\/ } }\n\nclass RubberDuck extends Duck { void fly() { \/* can\u2019t actually fly, awkward override *\/ } }\n\/\/ Composition: behavior is a separate, swappable object\n\nclass Duck {\n\n    FlyBehavior flyBehavior;\n\n    void fly() { flyBehavior.fly(); }\n\n}\n<\/code><\/pre><\/div><\/p>\n<p>The rubber duck case is the classic argument for composition: it inherits a fly() method that makes no sense for it and has to override it into a no-op, which is a sign the inheritance hierarchy modeled the wrong relationship in the first place. Composition sidesteps that by never forcing a shared method onto a type that doesn&#8217;t actually need it.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Walk through the ACID properties in the context of a bank transfer between two accounts.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Databases<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Atomicity means the debit from one account and the credit to the other happen as a single unit, if the credit fails partway through, the debit rolls back too, so money never vanishes. Consistency means the transaction can&#8217;t leave the database violating a defined rule, like a balance going negative when that&#8217;s disallowed. Isolation means two transfers happening at the same time don&#8217;t see each other&#8217;s uncommitted intermediate state. Durability means once the transfer commits, it survives a crash immediately afterward.<\/p>\n<p>Isolation is the one candidates usually understand least precisely, because different isolation levels trade correctness for throughput differently, and &#8220;isolation&#8221; doesn&#8217;t mean total isolation by default in most databases unless you explicitly ask for the strictest level, which most systems don&#8217;t use everywhere because of the performance cost.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Can you give a real example of a SOLID principle you saw violated and how you fixed it?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Design Principles<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A common one: a single class that both validates an order and sends a confirmation email, which violates single responsibility, because a change to email formatting now requires touching and retesting order validation code, and vice versa.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">java<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-java\">\n\n\/\/ Violates SRP: one class doing two unrelated jobs\n\nclass OrderProcessor {\n\n    void validate(Order o) { \/* \u2026 *\/ }\n\n    void sendConfirmationEmail(Order o) { \/* \u2026 *\/ }\n\n}\n\/\/ Split: each class has one reason to change\n\nclass OrderValidator { void validate(Order o) { \/* \u2026 *\/ } }\n\nclass OrderNotifier { void sendConfirmationEmail(Order o) { \/* \u2026 *\/ } }\n<\/code><\/pre><\/div><\/p>\n<p>A ThoughtWorks interviewer usually cares less about which SOLID letter you name and more about whether you can point to a real change that got harder because two unrelated responsibilities were tangled together in one class, since that&#8217;s the actual cost the principle is trying to prevent.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">How would you model the classes for a library checkout system?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">LLD<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Core entities: Book (the catalog entry), BookCopy (a physical instance of a Book, since a library owns several copies of the same title), Member, and Checkout (linking a specific BookCopy to a Member with a due date). The distinction between Book and BookCopy is the part candidates most often skip, and skipping it breaks the model the moment two people try to check out &#8220;the same book&#8221; and the system needs to know which physical copy is actually available.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">java<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-java\">\n\nclass BookCopy {\n\n    Book book;\n\n    boolean checkedOut;\n\n}\nclass Checkout {\n\n    BookCopy copy;\n\n    Member member;\n\n    LocalDate dueDate;\n\n}\n<\/code><\/pre><\/div><\/p>\n<p>A reasonable ThoughtWorks follow-up: how do you handle a hold queue when every copy of a popular title is checked out? That&#8217;s a Reservation entity tied to a Book (not a specific copy), which gets promoted to a Checkout once any copy of that title becomes available.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Model a vending machine as a set of classes, including its states.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">LLD<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>This is the classic textbook example of the State pattern for a reason: a vending machine&#8217;s behavior genuinely changes based on which state it&#8217;s in. Selecting an item does nothing meaningful in an Idle state, but triggers dispensing in a HasMoney state. Modeling that as a chain of if-statements checking a status flag works at first and turns into an unreadable mess once a second state variable gets added.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">java<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-java\">\n\ninterface VendingState {\n\n    void insertCoin(VendingMachine m);\n\n    void selectItem(VendingMachine m);\n\n}\nclass IdleState implements VendingState {\n\n    void insertCoin(VendingMachine m) { m.setState(new HasMoneyState()); }\n\n    void selectItem(VendingMachine m) { \/* no-op, no money inserted *\/ }\n\n}\n<\/code><\/pre><\/div><br \/>\n<\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Tell me about a time you disagreed with a teammate on a technical approach. How did you resolve it?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Behavioral<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>The interviewer wants the disagreement itself described honestly, not sanded down into &#8220;we talked it through and agreed.&#8221; What was each side&#8217;s actual position, what evidence or reasoning changed anyone&#8217;s mind, and if nobody&#8217;s mind changed, how did the team move forward anyway without it curdling into resentment.<\/p>\n<p>A detail that reads well here: whether you were the one who was wrong. A story where you were right all along and eventually convinced everyone is fine, but a story where you changed your own position because of something a teammate pointed out shows the same skill from the harder side, and interviewers notice which one you default to telling.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Describe a time you had to convince a client to change direction on something they were attached to.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Behavioral<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>This is close to the center of what a ThoughtWorks consultant actually does day to day, so a ThoughtWorks interviewer weighs the answer more heavily here than in most companies&#8217; behavioral rounds. What was the client attached to, what was actually wrong with it from your side, and how did you make the case without just pulling rank on expertise or steamrolling their stated priorities.<\/p>\n<p>Strong answers usually involve showing rather than telling, a small prototype, a concrete cost estimate, a short pilot, something that let the client reach the conclusion largely on their own rather than being argued into agreeing on the spot.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Tell me about a project where you had to advocate for a technical decision that wasn&#039;t popular with the rest of the team.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Behavioral<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A ThoughtWorks interviewer is checking two things at once here: whether you can hold a position under social pressure when you genuinely believe it&#8217;s right, and whether you know when to stop pushing once you&#8217;ve made your case and the team has decided otherwise.<\/p>\n<p>A red flag answer here is one where you were unpopular and turned out to be right, and the story ends with vindication and nothing else. The stronger version includes what you did in the meantime while the team disagreed with you, whether you kept working productively on the shared plan or quietly worked around it, since the second option is a much worse signal than losing the argument itself.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">What does social and economic justice mean to you in the context of your work as a technologist?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Values<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>ThoughtWorks is public and specific about this being part of its identity, not a slogan bolted onto a careers page, so a generic answer about using tech for good tends to fall flat here. The stronger answers are concrete: a project where a technical decision had a real effect on who could access something, or a time you pushed back on a requirement because of who it would exclude, not an abstract statement of values with no example attached.<\/p>\n<p>It&#8217;s a fair answer to say you haven&#8217;t had much direct exposure to this in your career so far, if that&#8217;s honestly true, paired with a genuine account of why it matters to you anyway. What doesn&#8217;t land well is an answer that sounds rehearsed specifically for this interview rather than something you&#8217;d say the same way in any other context.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Describe a time you made a mistake that affected production. What did you do next?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Behavioral<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A ThoughtWorks interviewer expects you to own the mistake specifically, what broke, how you found out, and what the immediate fix was, before getting to the more important part: what changed afterward so the same class of mistake doesn&#8217;t happen again. A missing test, a missing alert, a process gap that let a bad deploy through unreviewed.<\/p>\n<p>The weakest version of this answer blames the deploy pipeline, a teammate&#8217;s review, or unclear requirements as the real cause and treats your own role as incidental. Even in situations where those things genuinely contributed, the strongest answers still find the part that was actually yours to own.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">How do you handle being told your code doesn&#039;t meet the quality bar a client or reviewer expects?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Behavioral<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>This is partly about ego management and partly about whether you can extract something useful from feedback that stings in the moment. A concrete example matters more than a general philosophy: a specific piece of feedback, what your first reaction actually was, not the reaction you wish you&#8217;d had, and what you changed afterward.<\/p>\n<p>Candidates who can describe genuinely feeling defensive at first, and then explain what got them past that to actually engage with the feedback, tend to read as more self-aware than candidates who claim they always take criticism gracefully on the first try. Nobody does, every time, and pretending otherwise reads as either untrue or unreflective.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-dsec iq-dsec--hard\"><div class=\"iq-dsec__row\"><h2 class=\"iq-dsec__h\" id=\"hard\"><span class=\"iq-dsec__dot\" aria-hidden=\"true\"><\/span>Hard questions<\/h2><span class=\"iq-dsec__n\">4<\/span><\/div><div class=\"iq-dsec__bar\" aria-hidden=\"true\"><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Find the longest palindromic substring in a given string.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Strings<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>The expand-around-center approach handles both even and odd length palindromes cleanly in O(n squared) time and O(1) extra space, which beats the naive check-every-substring approach at O(n cubed) without needing the more involved O(n) Manacher&#8217;s algorithm most interviewers won&#8217;t expect from you.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">python<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-python\">\n\ndef longest_palindrome(s):\n\n    def expand(l, r):\n\n        while l &gt;= 0 and r &lt; len(s) and s[l] == s[r]:\n\n            l -= 1\n\n            r += 1\n\n        return s[l + 1:r]\n    result = \u201c\u201d\n\n    for i in range(len(s)):\n\n        odd = expand(i, i)\n\n        even = expand(i, i + 1)\n\n        result = max(result, odd, even, key=len)\n\n    return result\n<\/code><\/pre><\/div><\/p>\n<p>Every center, whether it&#8217;s a single character (odd length) or the gap between two characters (even length), needs its own expansion call. Missing the even-length case is the single most common bug candidates ship here, and it fails silently on inputs where the correct answer spans two centers rather than one.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Design and implement an LRU cache with O(1) get and put operations.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">System Design<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A hash map alone gives you O(1) lookup but no ordering, so you can&#8217;t cheaply find the least-recently-used item to evict. A doubly linked list alone gives you ordering but O(n) lookup. Combine them: the hash map stores keys pointing directly to nodes in the linked list, and the list tracks recency by moving accessed nodes to the front.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">python<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-python\">\n\nclass Node:\n\n    def __init__(self, key, value):\n\n        self.key, self.value = key, value\n\n        self.prev = self.next = None\nclass LRUCache:\n\n    def __init__(self, capacity):\n\n        self.capacity = capacity\n\n        self.map = {}\n\n        self.head = Node(0, 0)\n\n        self.tail = Node(0, 0)\n\n        self.head.next = self.tail\n\n        self.tail.prev = self.head\n    def _remove(self, node):\n\n        node.prev.next = node.next\n\n        node.next.prev = node.prev\n    def _add_front(self, node):\n\n        node.next = self.head.next\n\n        node.prev = self.head\n\n        self.head.next.prev = node\n\n        self.head.next = node\n    def get(self, key):\n\n        if key not in self.map:\n\n            return -1\n\n        node = self.map[key]\n\n        self._remove(node)\n\n        self._add_front(node)\n\n        return node.value\n    def put(self, key, value):\n\n        if key in self.map:\n\n            self._remove(self.map[key])\n\n        node = Node(key, value)\n\n        self.map[key] = node\n\n        self._add_front(node)\n\n        if len(self.map) &gt; self.capacity:\n\n            lru = self.tail.prev\n\n            self._remove(lru)\n\n            del self.map[lru.key]\n<\/code><\/pre><\/div><\/p>\n<p>ThoughtWorks interviewers watch for whether you reach for the combined structure directly or try a pure hash map first, then get stuck when asked how you&#8217;d find the least-recently-used entry without scanning everything.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Implement a Bowling Game scorer that computes the total score for a ten-frame game, correctly handling strikes and spares.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Pairing Kata<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>A strike scores 10 plus the next two rolls. A spare scores 10 plus the next one roll. The trap is the tenth frame, which can have up to three rolls if the player strikes or spares there, and those bonus rolls have to be included without re-triggering another bonus lookup past the end of the game. ThoughtWorks pairing partners lean on this one specifically because it&#8217;s easy to get almost right.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">java<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-java\">\n\nint score(int[] rolls) {\n\n    int total = 0, rollIndex = 0;\n\n    for (int frame = 0; frame &lt; 10; frame++) {\n\n        if (rolls[rollIndex] == 10) { \/\/ strike\n\n            total += 10 + rolls[rollIndex + 1] + rolls[rollIndex + 2];\n\n            rollIndex += 1;\n\n        } else if (rolls[rollIndex] + rolls[rollIndex + 1] == 10) { \/\/ spare\n\n            total += 10 + rolls[rollIndex + 2];\n\n            rollIndex += 2;\n\n        } else {\n\n            total += rolls[rollIndex] + rolls[rollIndex + 1];\n\n            rollIndex += 2;\n\n        }\n\n    }\n\n    return total;\n\n}\n<\/code><\/pre><\/div><\/p>\n<p>This is the kata I&#8217;d tell someone to actually practice more than any other on this page, not because it&#8217;s algorithmically deep, it isn&#8217;t, but because it punishes sloppy TDD specifically. Candidates who write one test for a gutter game, jump straight to a test with all strikes, and try to make both pass at once usually tangle themselves in an off-by-one bug in the bonus lookup that a smaller, more incremental set of tests would have caught two steps earlier.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Given a small piece of existing code, add a new behavior to it while changing as little of the existing logic as possible.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">Pairing Kata<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>ThoughtWorks pairing partners use exercises like this one, based on the well-known Gilded Rose refactoring kata, to see how you treat code you didn&#8217;t write.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">java<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-java\">\n\n\/\/ Existing: updates item quality and sellIn each day\n\nvoid updateQuality(Item item) {\n\n    if (item.sellIn &lt;= 0) {\n\n        item.quality = Math.max(0, item.quality \u2013 2);\n\n    } else {\n\n        item.quality = Math.max(0, item.quality \u2013 1);\n\n    }\n\n    item.sellIn\u2013;\n\n}\n\n\/\/ Task: add a \u201cConjured\u201d item type that degrades in quality twice as fast as normal items\n<\/code><\/pre><\/div><\/p>\n<p>The move that works here is isolating the new behavior behind a check for the item&#8217;s name or type, rather than threading new if-branches through the existing logic and risking a regression in how normal items already behave.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">java<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-java\">\n\nvoid updateQuality(Item item) {\n\n    int degradeRate = item.name.equals(\u201cConjured\u201d) ? 2 : 1;\n\n    if (item.sellIn &lt;= 0) {\n\n        item.quality = Math.max(0, item.quality \u2013 (degradeRate * 2));\n\n    } else {\n\n        item.quality = Math.max(0, item.quality \u2013 degradeRate);\n\n    }\n\n    item.sellIn\u2013;\n\n}\n<\/code><\/pre><\/div><\/p>\n<p>Pairing partners are watching two things here specifically: whether you run the existing test suite before touching anything, so you know what &#8220;still works&#8221; means before you start, and whether your first instinct is to understand the existing logic&#8217;s intent before editing it, rather than deleting and rewriting a function you don&#8217;t fully trust yet.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-dsec iq-dsec--scenario\"><div class=\"iq-dsec__row\"><h2 class=\"iq-dsec__h\" id=\"scenario\"><span class=\"iq-dsec__dot\" aria-hidden=\"true\"><\/span>Real-time scenario questions<\/h2><span class=\"iq-dsec__n\">5<\/span><\/div><div class=\"iq-dsec__bar\" aria-hidden=\"true\"><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Design the classes for a parking lot system that supports multiple vehicle sizes and multiple floors.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">LLD<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Start with the entities: ParkingLot, Floor, ParkingSpot (with a size), and Vehicle (with a size and type). The interesting design decision, and the one a ThoughtWorks interviewer usually probes hardest, is how a vehicle finds an available spot, that logic belongs on the ParkingLot or a dedicated SpotAllocator, not scattered across Floor objects, since the allocation strategy is exactly the kind of thing that changes later, compact cars allowed in motorcycle spots, reserved spots for electric vehicles, and you want that change contained to one place.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">java<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-java\">\n\nclass ParkingSpot {\n\n    VehicleSize size;\n\n    boolean occupied;\n\n}\nclass ParkingLot {\n\n    List&lt;Floor&gt; floors;\n\n    ParkingSpot findSpot(Vehicle v) {\n\n        for (Floor f : floors) {\n\n            ParkingSpot spot = f.findAvailableSpot(v.getSize());\n\n            if (spot != null) return spot;\n\n        }\n\n        return null;\n\n    }\n\n}\n<\/code><\/pre><\/div><br \/>\n<\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">At a high level, how would you design a URL-shortening service?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">LLD<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Two pieces matter more than the rest: how you generate a short, unique code for each long URL, and how you handle the read path, since a URL shortener is read-heavy by a wide margin, most short links get looked up far more often than they get created. Base62-encoding an auto-incrementing ID is the simplest reliable approach, it guarantees uniqueness without a collision check, unlike hashing the URL and hoping for no collisions.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">python<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-python\">\n\nALPHABET = \u201c0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\u201d\ndef encode(num):\n\n    if num == 0:\n\n        return ALPHABET[0]\n\n    result = []\n\n    while num:\n\n        num, rem = divmod(num, 62)\n\n        result.append(ALPHABET[rem])\n\n    return \u201c\u201d.join(reversed(result))\n<\/code><\/pre><\/div><\/p>\n<p>Caching the read path (the long URL for a given short code almost never changes once written) is the follow-up worth raising before being asked, since it&#8217;s the single biggest optimization for a read-heavy system like this one.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Walk through how you&#039;d design a simple ride-sharing system that matches a rider to the nearest available driver.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">LLD<\/span><span class=\"iq-badge iq-badge--medium\">Medium<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Model Driver and Rider as separate entities with a location, and give Driver a status (available, en route, in trip). A MatchingService takes a ride request and filters drivers down to those marked available, then picks the closest one, the same shape as the parking-spot allocator above: filter first, rank second, and keep both steps as separate, swappable pieces of logic rather than one nested loop.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">python<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-python\">\n\ndef find_driver(riders_location, drivers):\n\n    available = [d for d in drivers if d.status == \u201cavailable\u201d]\n\n    if not available:\n\n        return None\n\n    return min(available, key=lambda d: distance(d.location, riders_location))\n<\/code><\/pre><\/div><\/p>\n<p>The follow-up worth expecting: what happens if the closest driver declines the request? The matcher needs to fall back to the next-closest driver rather than failing outright, which is a strong signal for whether you designed ranking as a sorted list you can step through, instead of a single min() call with no fallback path.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">Design a rate limiter for an API that allows at most N requests per user per minute.<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">LLD<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>The sliding-window-log approach stores a timestamp for every request per user, and on each new request drops timestamps older than one minute, then checks whether the remaining count is under N. It&#8217;s exact but memory-heavy under high traffic. The token-bucket approach instead gives each user a bucket that refills at a fixed rate and drains one token per request, rejecting requests once the bucket is empty, trading a little precision for a fixed, small memory footprint per user.<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">python<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-python\">\n\nclass TokenBucket:\n\n    def __init__(self, capacity, refill_rate):\n\n        self.capacity = capacity\n\n        self.tokens = capacity\n\n        self.refill_rate = refill_rate\n\n        self.last_refill = time.time()\n    def allow_request(self):\n\n        now = time.time()\n\n        elapsed = now \u2013 self.last_refill\n\n        self.tokens = min(self.capacity, self.tokens + elapsed * self.refill_rate)\n\n        self.last_refill = now\n\n        if self.tokens &gt;= 1:\n\n            self.tokens -= 1\n\n            return True\n\n        return False\n<\/code><\/pre><\/div><\/p>\n<p>Naming the memory tradeoff between the two approaches unprompted is usually what separates a strong ThoughtWorks answer here from an average one.<\/p>\n<p><\/div><\/div><\/div>\n<div class=\"iq-qa\"><button class=\"iq-qa__q\" type=\"button\" aria-expanded=\"false\"><span class=\"iq-qa__qtext\">How would you design the class model for an elevator control system serving multiple floors?<\/span><span class=\"iq-qa__meta\"><span class=\"iq-qa__tag\">LLD<\/span><span class=\"iq-badge iq-badge--hard\">Hard<\/span><span class=\"iq-qa__chev\" aria-hidden=\"true\"><\/span><\/span><\/button><div class=\"iq-qa__a\"><div class=\"iq-qa__a-inner\"><\/p>\n<p>Core entities: Elevator (current floor, direction, a queue of requested floors), ElevatorController (decides which elevator answers a new request), and Request (a floor plus a direction, since a hallway button press specifies up or down, unlike a button pressed inside the car).<\/p>\n<p><div class=\"iq-code not-prose\"><div class=\"iq-code__bar\"><span class=\"iq-code__lang\">java<\/span><button class=\"iq-code__copy\" type=\"button\">Copy<\/button><\/div><pre><code class=\"language-java\">\n\nclass Elevator {\n\n    int currentFloor;\n\n    Direction direction;\n\n    TreeSet&lt;Integer&gt; upRequests;\n\n    TreeSet&lt;Integer&gt; downRequests;\n\n}\nclass ElevatorController {\n\n    Elevator assignElevator(Request request, List&lt;Elevator&gt; elevators) {\n\n        \/\/ pick the elevator with the least total work relative to request.floor\n\n    }\n\n}\n<\/code><\/pre><\/div><\/p>\n<p>The part that separates a strong answer here: recognizing that a hallway request (up or down at a specific floor) and a car request (a floor selected from inside a specific elevator) are genuinely different kinds of requests with different assignment logic, and modeling them as the same thing tends to produce a controller that can&#8217;t correctly decide which idle elevator should answer a call.<\/p>\n<p><\/div><\/div><\/div>\n<h2>How to prepare for a ThoughtWorks interview<\/h2>\n<p>Practice the ThoughtWorks kata round specifically, not generic LeetCode. Bowling Game, Mars Rover, and the String Calculator are all short enough to run through in under thirty minutes each, and the value isn&#8217;t memorizing the solution, it&#8217;s practicing writing the smallest possible failing test first and only generalizing once you have three or four real cases pulling you toward the general shape. Do each one twice, once alone and once talking out loud the whole time as if someone&#8217;s watching, since narrating your reasoning under time pressure is its own skill separate from solving the problem correctly.<\/p>\n<p>For the ThoughtWorks LLD round, sketch two or three of the designs above on paper before the interview, parking lot, library checkout, vending machine, and specifically practice explaining why you drew the class boundaries where you did. The actual answer matters less than being able to defend it when the interviewer changes one requirement partway through and asks what breaks in your design.<\/p>\n<p>For the values and behavioral round, write down four or five real stories from your own work before the interview, not during it. A disagreement you had, a mistake you made, a time you pushed back on something. Vague behavioral answers built on the spot are the most common weak point candidates report after the fact, not the coding round.<\/p>\n<h2>Get the reps in before the real thing<\/h2>\n<p>Reading a kata&#8217;s solution is not the same as writing tests for it live while someone asks why you chose that assertion first. <a href=\"\/products\/mock-interviews\">LastRoundAI&#8217;s mock interview mode<\/a> runs live coding and pairing-style sessions with real-time follow-up questions in your browser, and the free plan includes 15 credits a month that reset monthly rather than piling up unused. Starter is $19\/mo if a handful of sessions isn&#8217;t enough runway before a real loop.<\/p>\n<p>Once your reasoning holds up under a follow-up question, the slower part of the process is usually finding enough consulting and engineering roles that actually run a pairing-style loop instead of a pure algorithm screen. <a href=\"\/products\/auto-apply\">Auto-Apply<\/a> queues tailored applications for your review, 10 a month on the free plan, up to 400 a month on the Ultimate plan, and nothing goes out until you approve it.<\/p>\n<p>Questions about either product go to contact@lastroundai.com. That&#8217;s the only inbox we check.<\/p>\n<div class=\"iq-sources not-prose\"><div class=\"iq-sources__title\">Sources &amp; further reading<\/div><ul class=\"iq-sources__list\"><li><a href=\"https:\/\/www.thoughtworks.com\/careers\" target=\"_blank\" rel=\"nofollow noopener\">ThoughtWorks Careers, Interview Process<\/a><\/li><li><a href=\"https:\/\/www.indeed.com\/cmp\/Thoughtworks\/interviews\" target=\"_blank\" rel=\"nofollow noopener\">Indeed, ThoughtWorks Interview Reviews<\/a><\/li><li><a href=\"https:\/\/www.geeksforgeeks.org\/interview-experiences\/thoughtworks-interview-experience\/\" target=\"_blank\" rel=\"nofollow noopener\">GeeksforGeeks, ThoughtWorks Interview Experience<\/a><\/li><li><a href=\"https:\/\/codingdojo.org\/kata\/\" target=\"_blank\" rel=\"nofollow noopener\">Coding Dojo, Kata Catalog<\/a><\/li><\/ul><\/div>\n","protected":false},"excerpt":{"rendered":"<p>A candidate who&#8217;d cleared four rounds at a big product company in six weeks once told me the ThoughtWorks loop was the first one that made him nervous about a laptop he never had to touch alone. There&#8217;s no algorithm quiz on a shared doc. Instead there&#8217;s a real editor, and a consultant sitting next&#8230;<\/p>\n","protected":false},"author":5,"featured_media":1995,"comment_status":"open","ping_status":"closed","template":"","meta":{"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","footnotes":""},"tags":[],"class_list":["post-1975","iq","type-iq","status-publish","has-post-thumbnail","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.8 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>ThoughtWorks Interview Questions (2026), Answered<\/title>\n<meta name=\"description\" content=\"Real ThoughtWorks interview questions: pairing katas like Bowling Game and Mars Rover, DSA problems, LLD prompts, and values questions, with 50 answers.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/lastroundai.com\/interview-questions\/thoughtworks\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"ThoughtWorks Interview Questions (2026), Answered\" \/>\n<meta property=\"og:description\" content=\"Real ThoughtWorks interview questions: pairing katas like Bowling Game and Mars Rover, DSA problems, LLD prompts, and values questions, with 50 answers.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/lastroundai.com\/interview-questions\/thoughtworks\" \/>\n<meta property=\"og:site_name\" content=\"LastRound AI\" \/>\n<meta property=\"article:modified_time\" content=\"2026-07-20T04:56:52+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/07\/iq-thoughtworks-og.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"38 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/thoughtworks\",\"url\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/thoughtworks\",\"name\":\"ThoughtWorks Interview Questions (2026), Answered\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/thoughtworks#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/thoughtworks#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/iq-thoughtworks-og.png\",\"datePublished\":\"2026-07-20T04:38:24+00:00\",\"dateModified\":\"2026-07-20T04:56:52+00:00\",\"description\":\"Real ThoughtWorks interview questions: pairing katas like Bowling Game and Mars Rover, DSA problems, LLD prompts, and values questions, with 50 answers.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/thoughtworks#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/thoughtworks\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/thoughtworks#primaryimage\",\"url\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/iq-thoughtworks-og.png\",\"contentUrl\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/iq-thoughtworks-og.png\",\"width\":1200,\"height\":630,\"caption\":\"ThoughtWorks interview questions \u2014 LastRoundAI\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\\\/thoughtworks#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/lastroundai.com\\\/blog\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Interview Questions\",\"item\":\"https:\\\/\\\/lastroundai.com\\\/interview-questions\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"ThoughtWorks Interview Questions (2026), Real, With Answers\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/\",\"name\":\"LastRound AI\",\"description\":\"Interview Assistant prep, tech careers and AI tools\",\"publisher\":{\"@id\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/#organization\",\"name\":\"LastRound AI\",\"url\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/lastroundai-transprant-logo-optimized-BxEo2Wtq.png\",\"contentUrl\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/lastroundai-transprant-logo-optimized-BxEo2Wtq.png\",\"width\":400,\"height\":400,\"caption\":\"LastRound AI\"},\"image\":{\"@id\":\"https:\\\/\\\/lastroundai.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"ThoughtWorks Interview Questions (2026), Answered","description":"Real ThoughtWorks interview questions: pairing katas like Bowling Game and Mars Rover, DSA problems, LLD prompts, and values questions, with 50 answers.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/lastroundai.com\/interview-questions\/thoughtworks","og_locale":"en_US","og_type":"article","og_title":"ThoughtWorks Interview Questions (2026), Answered","og_description":"Real ThoughtWorks interview questions: pairing katas like Bowling Game and Mars Rover, DSA problems, LLD prompts, and values questions, with 50 answers.","og_url":"https:\/\/lastroundai.com\/interview-questions\/thoughtworks","og_site_name":"LastRound AI","article_modified_time":"2026-07-20T04:56:52+00:00","og_image":[{"width":1200,"height":630,"url":"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/07\/iq-thoughtworks-og.png","type":"image\/png"}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"38 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/lastroundai.com\/interview-questions\/thoughtworks","url":"https:\/\/lastroundai.com\/interview-questions\/thoughtworks","name":"ThoughtWorks Interview Questions (2026), Answered","isPartOf":{"@id":"https:\/\/lastroundai.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/lastroundai.com\/interview-questions\/thoughtworks#primaryimage"},"image":{"@id":"https:\/\/lastroundai.com\/interview-questions\/thoughtworks#primaryimage"},"thumbnailUrl":"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/07\/iq-thoughtworks-og.png","datePublished":"2026-07-20T04:38:24+00:00","dateModified":"2026-07-20T04:56:52+00:00","description":"Real ThoughtWorks interview questions: pairing katas like Bowling Game and Mars Rover, DSA problems, LLD prompts, and values questions, with 50 answers.","breadcrumb":{"@id":"https:\/\/lastroundai.com\/interview-questions\/thoughtworks#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/lastroundai.com\/interview-questions\/thoughtworks"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/lastroundai.com\/interview-questions\/thoughtworks#primaryimage","url":"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/07\/iq-thoughtworks-og.png","contentUrl":"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/07\/iq-thoughtworks-og.png","width":1200,"height":630,"caption":"ThoughtWorks interview questions \u2014 LastRoundAI"},{"@type":"BreadcrumbList","@id":"https:\/\/lastroundai.com\/interview-questions\/thoughtworks#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/lastroundai.com\/blog"},{"@type":"ListItem","position":2,"name":"Interview Questions","item":"https:\/\/lastroundai.com\/interview-questions"},{"@type":"ListItem","position":3,"name":"ThoughtWorks Interview Questions (2026), Real, With Answers"}]},{"@type":"WebSite","@id":"https:\/\/lastroundai.com\/blog\/#website","url":"https:\/\/lastroundai.com\/blog\/","name":"LastRound AI","description":"Interview Assistant prep, tech careers and AI tools","publisher":{"@id":"https:\/\/lastroundai.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/lastroundai.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/lastroundai.com\/blog\/#organization","name":"LastRound AI","url":"https:\/\/lastroundai.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/lastroundai.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/06\/lastroundai-transprant-logo-optimized-BxEo2Wtq.png","contentUrl":"https:\/\/lastroundai.com\/blog\/wp-content\/uploads\/2026\/06\/lastroundai-transprant-logo-optimized-BxEo2Wtq.png","width":400,"height":400,"caption":"LastRound AI"},"image":{"@id":"https:\/\/lastroundai.com\/blog\/#\/schema\/logo\/image\/"}}]}},"_links":{"self":[{"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/iq\/1975","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/iq"}],"about":[{"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/types\/iq"}],"author":[{"embeddable":true,"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/comments?post=1975"}],"version-history":[{"count":2,"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/iq\/1975\/revisions"}],"predecessor-version":[{"id":2060,"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/iq\/1975\/revisions\/2060"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/media\/1995"}],"wp:attachment":[{"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/media?parent=1975"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lastroundai.com\/blog\/wp-json\/wp\/v2\/tags?post=1975"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}