{"id":4343,"date":"2024-10-17T19:45:15","date_gmt":"2024-10-17T19:45:15","guid":{"rendered":"https:\/\/algocademy.com\/blog\/asana-technical-interview-prep-a-comprehensive-guide\/"},"modified":"2026-10-15T10:34:49","modified_gmt":"2026-10-15T10:34:49","slug":"asana-technical-interview-prep-a-comprehensive-guide","status":"publish","type":"post","link":"https:\/\/algocademy.com\/blog\/asana-technical-interview-prep-a-comprehensive-guide\/","title":{"rendered":"Asana Technical Interview Prep: Coding, Design and Product Sense"},"content":{"rendered":"<p>Asana makes work-management software, so the problems that fit its interviews are about tasks, projects, dependencies, notifications and many people editing the same data. Prepare the standard data-structure and algorithm set, then practice applying it to that kind of product: ordering tasks with dependencies, keeping a cache, handling real-time updates. This page gives you tested solutions for the likely coding problems and a plan for the design round.<\/p>\n<p>Asana does not publish its interview script. Candidate reports describe the familiar shape: a recruiter call, a technical phone screen (45 to 60 minutes of coding), and a final loop with coding, system design and behavioral rounds. Some teams may add a take-home or a pairing session. Ask your recruiter what applies to your role, and which languages you can use.<\/p>\n<h2>What to know about the product and stack<\/h2>\n<p>Using the product for a week beats reading about it. Create a project, add dependencies, assign tasks, use a timeline view, and notice what updates live. Asana&#8217;s engineering page on its tech stack says it uses React on the web, native mobile apps, and an in-house reactive data layer called LunaDb, written in Scala, that pushes changes to subscribed clients; as of that page it was being modernized toward GraphQL-style queries. You will not be asked to reproduce this, but it shows what the company cares about: loading related data efficiently and keeping many clients in sync. Source: <a href=\"https:\/\/asana.com\/inside-asana\/asana-tech-stack\">Asana&#8217;s tech stack page<\/a>.<\/p>\n<h2>Coding problems, with solutions that run<\/h2>\n<h3>Order tasks that depend on each other<\/h3>\n<p>This one is almost a literal feature of the product. Given tasks and &#8220;A must finish before B&#8221; dependencies, return a valid order, or report that no order exists because of a cycle. The standard solution is topological sort with in-degree counting (Kahn&#8217;s algorithm): start with tasks that have no unfinished prerequisites, and as you finish each, decrement its dependents.<\/p>\n<pre><code class=\"language-python\">from collections import deque, defaultdict\n\ndef schedule(tasks, deps):\n    \"\"\"deps: list of (before, after). Returns an order, or None if there is a cycle.\"\"\"\n    out_edges, indeg = defaultdict(list), {t: 0 for t in tasks}\n    for a, b in deps:\n        out_edges[a].append(b)\n        indeg[b] += 1\n    q = deque(t for t in tasks if indeg[t] == 0)\n    order = []\n    while q:\n        t = q.popleft()\n        order.append(t)\n        for nxt in out_edges[t]:\n            indeg[nxt] -= 1\n            if indeg[nxt] == 0:\n                q.append(nxt)\n    return order if len(order) == len(tasks) else None\n\nprint(schedule([\"design\", \"build\", \"test\", \"ship\"],\n               [(\"design\", \"build\"), (\"build\", \"test\"),\n                (\"test\", \"ship\"), (\"design\", \"test\")]))\n# ['design', 'build', 'test', 'ship']\nprint(schedule([\"a\", \"b\"], [(\"a\", \"b\"), (\"b\", \"a\")]))   # None\n<\/code><\/pre>\n<p>O(V + E) time. If any task is left unprocessed, the graph has a cycle, which is exactly the case where the UI should refuse a new dependency. Follow-ups: detect the cycle when a single new edge is added (a DFS from the new edge&#8217;s target looking for its source), and find the longest chain of dependent tasks (the critical path) with dynamic programming over the topological order. Our <a href=\"https:\/\/algocademy.com\/link\/?lang=py&amp;problem=find-if-path-exist-in-a-graph&amp;solution=1\">graph DFS lesson<\/a> covers the traversal underneath.<\/p>\n<h3>Detect a cycle in a linked list<\/h3>\n<p>Floyd&#8217;s algorithm: a slow pointer moves one step, a fast pointer two. If there is a cycle they meet; if not, the fast one reaches the end. O(n) time, O(1) space, which beats the hash-set solution on memory.<\/p>\n<pre><code class=\"language-python\">class Node:\n    def __init__(self, v):\n        self.v, self.next = v, None\n\ndef has_cycle(head):\n    slow = fast = head\n    while fast and fast.next:\n        slow, fast = slow.next, fast.next.next\n        if slow is fast:\n            return True\n    return False\n\na, b, c = Node(1), Node(2), Node(3)\na.next, b.next = b, c\nprint(has_cycle(a))   # False\nc.next = b\nprint(has_cycle(a))   # True\n<\/code><\/pre>\n<h3>LRU cache<\/h3>\n<p>A hash map plus recency order gives O(1) get and put. In Python <code>OrderedDict<\/code> does both jobs; in Java <code>LinkedHashMap<\/code> does. Be ready to build it from a hash map and a doubly linked list, and explain why each piece is there. The trade-offs against other policies are in our post on <a href=\"https:\/\/algocademy.com\/blog\/understanding-cache-replacement-policies-a-deep-dive-into-lru\/\">LRU and cache replacement<\/a>.<\/p>\n<h3>Median from a data stream<\/h3>\n<p>Keep the smaller half in a max-heap and the larger half in a min-heap, with sizes differing by at most one. Adding a value is O(log n), and reading the median is O(1).<\/p>\n<pre><code class=\"language-python\">import heapq\n\nclass MedianFinder:\n    def __init__(self):\n        self.lo, self.hi = [], []     # lo is a max-heap (negated values)\n\n    def add(self, x):\n        heapq.heappush(self.lo, -x)\n        heapq.heappush(self.hi, -heapq.heappop(self.lo))\n        if len(self.hi) &gt; len(self.lo):\n            heapq.heappush(self.lo, -heapq.heappop(self.hi))\n\n    def median(self):\n        if len(self.lo) &gt; len(self.hi):\n            return -self.lo[0]\n        return (-self.lo[0] + self.hi[0]) \/ 2\n\nm = MedianFinder()\nfor x in [5, 2, 8, 1]:\n    m.add(x)\n    print(x, m.median())\n# prints: 5 5, then 2 3.5, then 8 5, then 1 3.5 (one pair per line)\n<\/code><\/pre>\n<p>Mention what changes if values come from a small range (a counting array) or if you only need an approximate median (a sketch).<\/p>\n<h3>Other problems worth practicing<\/h3>\n<ul>\n<li>K-th smallest element in a binary search tree (in-order traversal, stop early).<\/li>\n<li>Serialize and deserialize a binary tree (preorder with null markers).<\/li>\n<li>Merge overlapping intervals, relevant for calendars and timelines.<\/li>\n<li>Find the missing number in 1..n: sum formula or XOR, O(n) time and O(1) space.<\/li>\n<\/ul>\n<p>Those fundamentals are the base. If you are still shaky on them, <a href=\"https:\/\/algocademy.com\/link\/?lang=py&amp;problem=level-order-traversal&amp;solution=1\">Level Order Traversal<\/a> and the <a href=\"https:\/\/algocademy.com\/link\/?lang=py&amp;problem=hash-map&amp;solution=1\">Hash Map<\/a> lesson are good places to start.<\/p>\n<h2>System design<\/h2>\n<p>For more senior roles, expect a design round. Prompts that fit the company: a task management system, a notification system, real-time collaboration on a shared document or list, search across a workspace, or tracking task dependencies. Work through &#8220;design a task manager&#8221; in this order:<\/p>\n<ol>\n<li><strong>Requirements:<\/strong> create, assign and comment on tasks; projects and workspaces; permissions; notifications; search. State what you will not cover.<\/li>\n<li><strong>Scale:<\/strong> number of users, tasks per project, read-to-write ratio. Projects are read far more than they are written.<\/li>\n<li><strong>Data model:<\/strong> users, workspaces, projects, tasks, task-to-project membership (a task can live in several projects), dependencies, comments. Explain what you index and why.<\/li>\n<li><strong>API:<\/strong> list tasks in a project with pagination, update a task, subscribe to changes.<\/li>\n<li><strong>Real-time updates:<\/strong> clients hold a connection (WebSocket or similar) and receive change events for what they are looking at. Discuss what happens on reconnect, when events were missed (resend from a version number or reload), and conflicting edits (last write wins per field is the simple answer; say what you give up).<\/li>\n<li><strong>Scale and failure:<\/strong> cache hot projects, shard by workspace so most queries stay on one shard, queue notifications so a slow email provider does not block writes.<\/li>\n<\/ol>\n<p>The most useful habit is to name a trade-off at every step. Our <a href=\"https:\/\/algocademy.com\/blog\/how-to-use-trade-off-analysis-in-system-design-interviews\/\">trade-off analysis post<\/a> explains how.<\/p>\n<h2>Behavioral questions<\/h2>\n<p>Typical ones: a challenging project and how you got past obstacles, a disagreement with a teammate, choosing between perfect code and a deadline, how you learn a new framework. Prepare real stories and tell them in the Situation, Task, Action, Result order. For a company that sells collaboration, how you work with others is a real part of the evaluation, so describe the role of the other people in your stories, not only your own.<\/p>\n<h2>A two-week plan<\/h2>\n<ul>\n<li><strong>Days 1 to 5:<\/strong> arrays, hash maps, linked lists, trees, graphs; one or two problems a day, solved aloud.<\/li>\n<li><strong>Days 6 to 9:<\/strong> heaps, topological sort, intervals, and the four problems above written from memory in your interview language.<\/li>\n<li><strong>Days 10 to 12:<\/strong> two design sessions with a friend, one of them on the task manager.<\/li>\n<li><strong>Days 13 and 14:<\/strong> a mock interview, your behavioral stories, and questions for the interviewers. Sites like LeetCode and HackerRank have large problem banks, and <a href=\"https:\/\/app.algocademy.com\/\">AlgoCademy<\/a> offers guided lessons if you want explanations as you go.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Prepare for an Asana software engineering interview: likely coding problems with tested Python solutions, system design for a task manager, and a study plan.<\/p>\n","protected":false},"author":1,"featured_media":4342,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[23],"tags":[],"class_list":["post-4343","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-problem-solving"],"_links":{"self":[{"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/posts\/4343"}],"collection":[{"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/comments?post=4343"}],"version-history":[{"count":1,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/posts\/4343\/revisions"}],"predecessor-version":[{"id":8713,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/posts\/4343\/revisions\/8713"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/media\/4342"}],"wp:attachment":[{"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/media?parent=4343"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/categories?post=4343"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/algocademy.com\/blog\/wp-json\/wp\/v2\/tags?post=4343"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}