← Shopify Interview Insights

Shopify·Software Engineer·Onsite - System Design / Architecture·Senior

SeniorPrefer not to say
Apr 2026

Summary

Shopify systems design round for a software engineer role, focused entirely on building a local URL shortener from scratch. Pretty involved for what sounded like a contained problem at first glance.

Questions Asked (5)

Q1

Design and implement a self-contained local URL shortener, covering input validation, encoding strategy, in-memory storage with file persistence, memory estimation, and unit tests.

System DesignTechnical Trade-offsAlgorithms & Data Structures
Author's notes

This was the whole interview basically.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying requirements and constraints, then walk through the design of each component (validation, encoding, storage, persistence, memory estimation) before diving into implementation details. Emphasize trade-offs and justify your choices, and finish by outlining a unit test strategy that covers edge cases and persistence.

Pro tip: Proactively discuss how you would handle collisions in the encoding scheme and how you would estimate memory usage based on expected load, showing that you think about scalability and reliability even in a local context.

1. Clarify Requirements and Constraints

Ask questions to understand expected scale, persistence needs, and any specific validation rules. Confirm that the solution should be self-contained and run locally.

2. Design Encoding Strategy

Choose an encoding scheme (e.g., base62) and explain how to generate unique short codes, handle collisions, and ensure determinism if needed.

3. Implement In-Memory Storage with Persistence

Describe the data structure (e.g., hash map) for storing mappings, and how to persist to a file (e.g., JSON, append-only log) and load on startup.

4. Estimate Memory Usage

Calculate approximate memory per entry and total memory for expected number of URLs, considering overhead of data structures and strings.

5. Outline Unit Tests

List key test cases: valid/invalid input, encoding/decoding, collision handling, persistence (save/load), and edge cases like empty or very long URLs.

Key Points to Mention

  • Input validation: check URL format, length limits, and sanitization to prevent injection or malformed data.
  • Encoding strategy: base62 encoding of an incrementing counter or hash, with collision resolution (e.g., linear probing or rehashing).
  • In-memory storage: use a hash map for O(1) lookups; consider thread-safety if concurrent access is possible.
  • File persistence: write to a file on each update or periodically; use atomic writes to avoid corruption; load on startup.
  • Memory estimation: account for string overhead, map entry overhead, and potential growth; use back-of-the-envelope calculations.
  • Unit tests: cover validation, encoding/decoding, storage operations, persistence round-trip, and error conditions.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

How would you validate that an input URL is well-formed before shortening it?

System DesignTechnical Trade-offs
Author's notes

Straightforward enough.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the requirements: what 'well-formed' means (syntax, scheme, host, etc.) and the context (e.g., user input, API). Then outline a layered validation approach: first basic syntactic checks, then semantic checks, and finally security considerations, discussing trade-offs between strictness and usability.

Pro tip: Mention that validation should be done on the server side even if client-side validation exists, and consider using a well-tested library like validator.js to avoid reinventing the wheel and to handle edge cases.

1. Clarify requirements and scope

Ask questions to understand what 'well-formed' means in this context: should it allow only HTTP/HTTPS? Should it accept internationalized domain names? What about URLs with authentication or ports? This ensures you're solving the right problem.

2. Perform syntactic validation

Check the URL against a standard format, e.g., using a regex or a URL parser. Ensure it has a scheme, host, and optionally path, query, and fragment. Reject obviously malformed strings.

3. Perform semantic validation

Verify that the scheme is allowed (e.g., http, https), the host is a valid domain or IP, and the port (if present) is in a valid range. Optionally, check that the domain is not blacklisted or malicious.

4. Consider security and edge cases

Think about SSRF, open redirects, and homograph attacks. Normalize the URL (e.g., punycode for IDNs) and consider length limits. Discuss whether to resolve DNS or make a HEAD request (trade-off: latency vs. safety).

5. Discuss trade-offs and implementation

Balance strictness vs. user experience. Mention using a library (e.g., validator.js) vs. custom regex. Highlight the importance of server-side validation and error handling.

Key Points to Mention

  • Use of standard URL parsing libraries (e.g., WHATWG URL API, Python's urllib.parse) over regex for robustness.
  • Validation of scheme (only allow http/https) and host (valid domain, no IP if not needed).
  • Handling of internationalized domain names (IDN) via punycode.
  • Security concerns: SSRF, open redirects, and homograph attacks.
  • Trade-offs between strict validation and user experience (e.g., rejecting valid but unusual URLs).
  • Importance of server-side validation and normalization (e.g., lowercasing scheme/host, removing default ports).

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

Walk through your encoding strategy for generating short codes. How do you handle hash collisions?

Algorithms & Data StructuresTechnical Trade-offsSystem Design
Author's notes

I went with MD5 truncated to 6 characters of base62, which the interviewer seemed fine with.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying requirements (scale, code length, character set, expected lifetime) and then present a layered strategy: base encoding with a collision-resistant hash, followed by collision resolution via a deterministic probing or counter-based approach. Emphasize trade-offs between simplicity, performance, and uniqueness guarantees, and mention how you'd validate and monitor collisions in production.

Pro tip: Mention that you'd use a bloom filter or a precomputed set to quickly check for collisions before hitting the database, and that you'd consider using a distributed counter or a unique ID generator like Snowflake to avoid collisions altogether.

1. Clarify Requirements

Ask about scale (e.g., millions of URLs), desired code length, allowed characters, and whether codes need to be guessable or not. This determines the encoding and collision strategy.

2. Choose Encoding Strategy

Decide between hashing (e.g., MD5, SHA-256) truncated and base62-encoded, or a counter-based approach. Discuss trade-offs: hashing is stateless but collision-prone; counter is collision-free but requires coordination.

3. Handle Collisions

For hashing, use linear probing or re-hash with a salt until a free slot is found. For counter, use a distributed ID generator (e.g., Snowflake) and encode the ID. Mention checking against a database or in-memory set.

4. Optimize and Scale

Discuss caching, sharding, and using a bloom filter to reduce database lookups. Consider pre-generating codes or using a key generation service (KGS) for high throughput.

5. Monitor and Validate

Explain how you'd track collision rates, latency, and storage. Mention logging and alerting for unexpected collision spikes, and periodic re-evaluation of the strategy.

Key Points to Mention

  • Base62 encoding for URL-friendly short codes
  • Hash function choice (MD5, SHA-256) and truncation
  • Collision resolution techniques: linear probing, re-hashing with salt, or using a counter
  • Distributed ID generation (e.g., Snowflake) to avoid collisions
  • Bloom filter for fast collision checks
  • Trade-offs between stateless hashing and stateful counter-based approaches

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q4

How would you estimate the memory footprint of your in-memory URL map, and what would you do if you outgrew a single process?

System DesignTechnical Trade-offs
Author's notes

Hadn't thought about this concretely before and it showed.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by breaking down the memory footprint into components: the hash table overhead, key storage, value storage, and any additional metadata. Then, discuss strategies for scaling beyond a single process, such as sharding, consistent hashing, or using a distributed cache, while considering trade-offs like latency and complexity.

Pro tip: Mention that you would measure actual memory usage with tools like jmap or heap dumps before optimizing, and consider the impact of object headers and alignment in Java, which can significantly increase the footprint.

1. Estimate per-entry memory

Calculate the memory for a single entry: key (string length + object overhead), value (object size), and the map entry object itself. Include hash table array overhead.

2. Calculate total footprint

Multiply per-entry memory by the number of entries, then add the overhead of the hash table array (capacity * reference size). Consider load factor and resizing.

3. Validate with measurements

Use profiling tools (e.g., JVM heap dumps, memory profilers) to measure actual usage and compare with your estimate, adjusting for factors like object alignment and garbage collection overhead.

4. Scale beyond single process

If the map outgrows a single process, consider sharding the map across multiple processes using consistent hashing, or use a distributed cache like Redis. Discuss trade-offs: increased latency, complexity, and consistency.

5. Consider alternatives

Evaluate if an in-memory map is still appropriate; maybe a disk-based store or a database with caching layer is better. Discuss hybrid approaches.

Key Points to Mention

  • Object overhead in Java (e.g., 16-byte header, padding)
  • Hash table load factor and resizing impact
  • String memory: char[] vs byte[] (Java 9+ compact strings)
  • Sharding strategies: consistent hashing, range partitioning
  • Distributed caches: Redis, Memcached, and their trade-offs
  • Monitoring and profiling tools for memory usage

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q5

What unit tests would you write for this URL shortener, and how would you force a hash collision in a test?

Technical Trade-offsSystem DesignAPI & Integrations
Author's notes

The collision test via stub was the interesting part here.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by outlining the core components of a URL shortener (encoding, storage, redirection) and the unit tests for each, focusing on edge cases and error handling. Then, explain how to force a hash collision by either mocking the hash function or using a deterministic algorithm with known collisions, and describe how to test collision resolution.

Pro tip: Demonstrate awareness of trade-offs: for example, discuss how collision handling affects performance and consistency, and mention that in production you'd use a distributed counter or a unique ID generator to avoid collisions altogether.

1. Identify components to test

Break down the URL shortener into units: URL validation, hash generation, storage (create/read), and redirection logic. This ensures comprehensive coverage.

2. Design unit tests for each component

For each component, list test cases including happy paths, edge cases (e.g., empty URL, very long URL, invalid format), and error conditions (e.g., duplicate short code, non-existent code).

3. Explain how to force a hash collision

Describe techniques: mocking the hash function to return a fixed value, using a hash algorithm with known collisions (e.g., MD5), or precomputing two inputs that collide. Emphasize that this tests the collision resolution logic.

4. Test collision resolution behavior

Write a test that inserts two URLs that collide and verify that both are stored and retrievable correctly, either by appending a counter or using a different mechanism.

5. Discuss trade-offs and production considerations

Mention that while forcing collisions in tests is useful, in production you'd avoid collisions with a unique ID generator, and discuss the impact on performance and scalability.

Key Points to Mention

  • Unit tests for URL validation (e.g., malformed URLs, supported schemes)
  • Tests for hash generation determinism and uniqueness
  • Storage layer tests: create, read, and handle duplicates
  • Redirection tests: correct HTTP status and Location header
  • Techniques to force collisions: mocking, known collision pairs, or weak hash
  • Collision resolution strategies: linear probing, chaining, or counter suffix

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.