← Grammarly Interview Insights

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

Senior
May 2026

Summary

System design round at Grammarly for a software engineering role. The whole thing centered on one big design problem that kept branching into uncomfortable territory the longer it went on.

Questions Asked (1)

Q1

Design a messaging system where a sender can blast the same message to multiple recipients privately, each recipient sees it as a 1:1 thread, and the message self-destructs after the recipient reads it once. Walk through your data model, real-time delivery approach, deletion guarantees, and how you'd scale it.

System DesignData ModelingTechnical Trade-offs
Author's notes

I started with the data model and immediately hit a fork: do you copy the message row per recipient or keep one shared record with per-recipient state?

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying requirements and constraints, then propose a high-level architecture that separates message ingestion, fan-out, storage, and delivery. Focus on the unique challenges: private 1:1 threads, read-once semantics, and guaranteed deletion. Walk through data modeling, real-time delivery, deletion guarantees, and scaling, emphasizing trade-offs and failure handling.

Pro tip: Explicitly discuss how you'd handle the 'read once' guarantee under failures and races—e.g., using atomic operations or distributed locks—and mention the trade-off between strong consistency and availability. Also, consider privacy implications like preventing screenshots or forwarding, and how you'd audit deletions.

1. Clarify Requirements and Constraints

Ask about scale (users, messages per second), latency requirements, consistency needs, and whether 'self-destruct' means immediate deletion from all storage or just client-side. Confirm that each recipient sees a separate 1:1 thread and that the sender cannot see recipient reads.

2. Design Data Model

Propose a schema with tables for users, messages (with sender, content, expiration policy), and message_recipients (linking messages to recipients, with status like 'unread', 'read', 'deleted'). Consider using a unique thread ID per recipient to simulate 1:1 threads. Discuss storage choices (SQL vs NoSQL) and indexing for fast lookups.

3. Real-Time Delivery and Read Receipts

Describe how messages are delivered in real-time (e.g., WebSockets, push notifications). Explain how read receipts are sent back to the server, triggering the self-destruct sequence. Ensure that the sender does not receive read receipts to maintain privacy.

4. Deletion Guarantees and Atomicity

Detail how to guarantee deletion after read: use atomic operations (e.g., database transactions, compare-and-swap) to mark as read and schedule deletion. Discuss handling failures (e.g., if deletion fails, retry with exponential backoff) and ensuring the message is not accessible after read, even from backups.

5. Scaling and Trade-offs

Explain how to scale horizontally: sharding by user ID, using a message queue for fan-out, caching for hot data. Discuss trade-offs between consistency and availability (e.g., using eventual consistency for deletion vs strong consistency for read-once). Mention monitoring and metrics for deletion success rate.

Key Points to Mention

  • Fan-out on write vs read: for blast messages, fan-out on write creates N copies upfront, simplifying read-once but increasing storage; fan-out on read reduces storage but complicates deletion.
  • Atomic read-and-delete: use database transactions or Redis Lua scripts to ensure that marking as read and deleting happen atomically, preventing double-reads.
  • Privacy: ensure sender cannot see individual read receipts, and consider end-to-end encryption so server cannot read message content.
  • Deletion from backups and caches: implement a tombstone mechanism and TTLs to purge data from all storage layers, including backups.
  • Real-time delivery: use WebSockets for active users and push notifications for offline, with a fallback to polling.
  • Scalability: shard by recipient ID to distribute load, use a message queue (e.g., Kafka) for reliable fan-out, and consider rate limiting to prevent abuse.

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