<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ayusch</title>
    <description>The latest articles on DEV Community by Ayusch (@ayuschjain).</description>
    <link>https://dev.to/ayuschjain</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F364601%2F49c747d6-9fbb-4185-a3fb-5183ed187d24.jpg</url>
      <title>DEV Community: Ayusch</title>
      <link>https://dev.to/ayuschjain</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ayuschjain"/>
    <language>en</language>
    <item>
      <title>Android System Design: Design a Notes App - by Mockingly</title>
      <dc:creator>Ayusch</dc:creator>
      <pubDate>Mon, 06 Apr 2026 15:00:00 +0000</pubDate>
      <link>https://dev.to/ayuschjain/android-system-design-design-a-notes-app-by-mockingly-1bb5</link>
      <guid>https://dev.to/ayuschjain/android-system-design-design-a-notes-app-by-mockingly-1bb5</guid>
      <description>&lt;h1&gt;
  
  
  Android System Design: Design a Notes App
&lt;/h1&gt;

&lt;p&gt;This post was originally published on &lt;a href="https://mockingly.ai" rel="noopener noreferrer"&gt;MockinglyAI&lt;/a&gt;. It's the best resource to prepare for system design interviews. Try a &lt;a href="https://mockingly.ai" rel="noopener noreferrer"&gt;free&lt;/a&gt; Mock Interview.&lt;/p&gt;

&lt;p&gt;This question shows up at Google, Microsoft, Notion, Dropbox, and pretty much any company building productivity tools on Android. It's popular precisely because it's a clean, bounded problem that happens to touch every hard Android topic at once: offline-first design, Room schema decisions, background sync with WorkManager, multi-device state reconciliation, and rich text storage.&lt;/p&gt;

&lt;p&gt;The best candidates don't just describe a notes CRUD app — they treat it as a distributed systems problem running on a constrained mobile device.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Clarify the Scope
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Interviewer:&lt;/strong&gt; Design a notes app for Android.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Candidate:&lt;/strong&gt; Before I dive in — a few questions. Are we designing a local-only notes app or one that syncs across devices? If it syncs, do we need real-time collaboration, or is eventual consistency between the user's own devices acceptable? Do notes support rich text — bold, italics, lists, embedded images — or plain text only? Do we need folder organisation, tagging, or search? And what's the offline expectation — can the user create, edit, and read notes without network access?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interviewer:&lt;/strong&gt; The app syncs across the user's own devices. No real-time collaboration — just eventual consistency. Rich text support — at least bold, italic, bullet lists. Tags and search are in scope. Full offline support is a hard requirement. Assume Google Keep or Apple Notes as the reference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Candidate:&lt;/strong&gt; Perfect. Offline-first is the most important architectural constraint here — it shapes every single decision from schema design to sync strategy. Let me start with requirements and then walk through the architecture.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Functional
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Create, edit, and delete notes fully offline&lt;/li&gt;
&lt;li&gt;Notes contain rich text (bold, italic, bullet lists) and optionally images/attachments&lt;/li&gt;
&lt;li&gt;Tag notes for organisation; filter notes by tag&lt;/li&gt;
&lt;li&gt;Full-text search across note content and title&lt;/li&gt;
&lt;li&gt;Notes sync across the user's own devices when connectivity is available&lt;/li&gt;
&lt;li&gt;Handle conflicts when the same note is edited on two devices while offline&lt;/li&gt;
&lt;li&gt;Archive and pin notes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Non-Functional
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Offline-first&lt;/strong&gt; — all core operations must work without a network connection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero perceived latency&lt;/strong&gt; — UI writes must feel instant; syncing happens in the background&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No data loss&lt;/strong&gt; — a note written offline must never be silently dropped&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Battery-safe&lt;/strong&gt; — background sync must not drain the battery&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conflict resilience&lt;/strong&gt; — concurrent edits across devices must be resolved correctly and predictably&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Back-of-the-Envelope Estimates
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Interviewer:&lt;/strong&gt; Give me a sense of the numbers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Candidate:&lt;/strong&gt; For a per-device estimate:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Notes per user:             ~500 average (active user)
Average note size (text):   ~5 KB
Notes with attachments:     ~10%
Average attachment size:    ~500 KB (photos, audio clips)

Local storage (text only):
  500 notes × 5 KB = ~2.5 MB — trivially small, no concern

Local storage (with attachments):
  50 attachments × 500 KB = ~25 MB — manageable per device

Sync payload per session:
  Assume user edits 5 notes per day
  5 × 5 KB = 25 KB delta upload — negligible bandwidth

Search index:
  Room FTS4 overhead is ~2× the text content size
  500 notes × 5 KB × 2 = ~5 MB — fine for SQLite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The numbers confirm this is not a scale problem on the client. Notes apps don't have high write throughput or large data volumes per device. The interesting challenge is correctness — not performance. Specifically: how do you guarantee offline writes don't get lost, and what happens when two devices edit the same note while offline.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Client Architecture
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Interviewer:&lt;/strong&gt; Walk me through the overall architecture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Candidate:&lt;/strong&gt; Clean Architecture with MVVM, Room as the single source of truth, and WorkManager handling all background sync.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UI Layer
  NoteListScreen / NoteEditScreen  ←  ViewModel (StateFlow / Compose State)

Domain Layer
  Use Cases: CreateNote, UpdateNote, DeleteNote, SearchNotes, SyncNotes

Data Layer
  NoteRepository
    ├── Local Source  → Room (all reads and writes, always)
    └── Remote Source → Retrofit (sync only, never on the critical path)

Sync Layer
  NoteSyncWorker (WorkManager CoroutineWorker)
  SyncStatusTracker (exposes sync state to UI)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The critical principle: &lt;strong&gt;the UI never talks to the network directly.&lt;/strong&gt; Every read and write goes through Room. The ViewModel observes Room via &lt;code&gt;Flow&lt;/code&gt; — when a note is saved, Room emits the update and the UI reacts. Sync happens entirely in the background.&lt;/p&gt;

&lt;p&gt;This is what makes offline feel seamless. When a user types a note with no internet, the experience is identical to when they have full connectivity. Room doesn't know or care about the network.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Room Schema Design
&lt;/h2&gt;

&lt;p&gt;This is the first place interviewers probe in depth. A weak schema here cascades into problems with sync, conflict resolution, and search.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Interviewer:&lt;/strong&gt; Walk me through the Room schema for a notes app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Candidate:&lt;/strong&gt; Let me walk through each entity and explain why each field exists.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tableName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"notes"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;NoteEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nd"&gt;@PrimaryKey&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;// UUID — client-generated, not server auto-increment&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;contentJson&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;             &lt;span class="c1"&gt;// rich text serialised as JSON (covered below)&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;contentPlainText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        &lt;span class="c1"&gt;// stripped plain text — for FTS indexing&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;isPinned&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;isArchived&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;// hex colour string, nullable&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                 &lt;span class="c1"&gt;// epoch millis, set on creation, never changes&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;updatedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                 &lt;span class="c1"&gt;// epoch millis, updated on every local edit&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;serverUpdatedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;// the server's last-modified timestamp — for conflict detection&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;syncStatus&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SyncStatus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;// SYNCED, PENDING, CONFLICTED&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;isDeleted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;       &lt;span class="c1"&gt;// soft delete — never hard-delete before sync&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SyncStatus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;SYNCED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;PENDING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;CONFLICTED&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;A few decisions to call out explicitly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Client-generated UUID.&lt;/strong&gt; If the primary key were a server-assigned integer, the client couldn't create a note offline — it would have no ID until the server responds. A UUID generated on the device means the note has an ID from the moment of creation, before any network interaction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;contentPlainText&lt;/code&gt; alongside &lt;code&gt;contentJson&lt;/code&gt;.&lt;/strong&gt; Rich text content is stored as JSON (explained below). But Room FTS can't tokenise JSON structure — it needs plain text. So we maintain a stripped version for search indexing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;syncStatus&lt;/code&gt;.&lt;/strong&gt; This is the heartbeat of the offline-first design. Every note is in one of three states: &lt;code&gt;SYNCED&lt;/code&gt; (local and server agree), &lt;code&gt;PENDING&lt;/code&gt; (local change not yet sent to server), or &lt;code&gt;CONFLICTED&lt;/code&gt; (a conflict was detected that needs resolution). The sync worker queries for &lt;code&gt;PENDING&lt;/code&gt; notes; the UI surfaces &lt;code&gt;CONFLICTED&lt;/code&gt; notes to the user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Soft delete with &lt;code&gt;isDeleted&lt;/code&gt;.&lt;/strong&gt; Never hard-delete a note before it's synced. If you delete a note locally and it's never been synced, you need to inform the server on the next sync. A hard delete loses that signal.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Tags schema:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tableName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;TagEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nd"&gt;@PrimaryKey&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;tableName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"note_tags"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;primaryKeys&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"noteId"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"tagId"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;NoteTagEntity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;noteId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;tagId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;FTS virtual table for full-text search:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Fts4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;contentEntity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;NoteEntity&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Entity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tableName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"notes_fts"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;NotesFts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;contentPlainText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Room's &lt;code&gt;@Fts4&lt;/code&gt; annotation creates a SQLite full-text search virtual table backed by &lt;code&gt;contentPlainText&lt;/code&gt; and &lt;code&gt;title&lt;/code&gt;. FTS4 tokenises content at write time, enabling &lt;code&gt;MATCH&lt;/code&gt; queries that are orders of magnitude faster than &lt;code&gt;LIKE '%term%'&lt;/code&gt; on large note collections. We'll use this for the search feature.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Rich Text Storage
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Interviewer:&lt;/strong&gt; How do you store and render rich text in the note editor?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Candidate:&lt;/strong&gt; This is an area where candidates often say "use a WebView" and move on. Let me give a more considered answer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it is:&lt;/strong&gt; Android's native text system uses &lt;code&gt;Spanned&lt;/code&gt; / &lt;code&gt;SpannableString&lt;/code&gt; — in-memory objects that hold text alongside formatting ranges (bold from position 5 to 10, italic from 20 to 25, etc.). These are great for rendering in &lt;code&gt;EditText&lt;/code&gt; but can't be directly persisted to Room.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The storage strategy:&lt;/strong&gt; serialise the rich text document to JSON. The format stores the raw text plus an array of spans with their type, start, and end positions:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Meeting notes&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;Don't forget to review the PRD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"spans"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BOLD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ITALIC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;43&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;On write: convert &lt;code&gt;SpannableString&lt;/code&gt; → JSON, store in &lt;code&gt;contentJson&lt;/code&gt;. Also extract &lt;code&gt;text&lt;/code&gt; as &lt;code&gt;contentPlainText&lt;/code&gt; for FTS.&lt;/p&gt;

&lt;p&gt;On read: deserialise JSON → rebuild &lt;code&gt;SpannableString&lt;/code&gt; and display in &lt;code&gt;EditText&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Markdown as an alternative:&lt;/strong&gt; some notes apps (Notion, Bear) store content as Markdown strings. This is simpler to serialise and portable, but rendering Markdown in Android requires either a third-party library (Markwon is the standard) or a WebView. The trade-off: Markdown is easier to sync and diff across devices (it's just text), but native Markdown rendering is heavier than &lt;code&gt;SpannableString&lt;/code&gt;. For a Google Keep-style app with basic formatting, JSON-serialised spans is the right call. For a Notion-style app with complex block structures, consider a block-based document model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What not to do:&lt;/strong&gt; never store HTML in the database. HTML is verbose, hard to diff, and the WebView it requires for rendering is expensive for list scrolling.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Offline-First Architecture: The Write Path
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Interviewer:&lt;/strong&gt; Walk me through what happens when the user creates a note with no internet connection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Candidate:&lt;/strong&gt; This is the critical path, and it's entirely local:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User types in NoteEditScreen
  │
  ▼
ViewModel.saveNote()
  │  Called on a debounced timer (500ms after typing stops)
  ▼
NoteRepository.save(note)
  │
  ▼
Room.insert/update(note.copy(syncStatus = PENDING, updatedAt = now()))
  │  Returns immediately — sub-millisecond
  ▼
UI observes Room Flow → updates note list with "saving..." indicator
  │
  ▼
WorkManager enqueued with CONNECTED constraint
  (No-op if already enqueued for this note — idempotent enqueue)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The user sees their note saved instantly. There's no loading spinner, no "waiting for network" state. The &lt;code&gt;PENDING&lt;/code&gt; status is invisible to the user at this point — it's an internal state that drives the sync pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The debounce is important.&lt;/strong&gt; Notes apps don't save on every keystroke — that would flood Room with writes. A 500ms debounce means one Room write per burst of typing, not one per character. On process kill, the ViewModel's &lt;code&gt;onCleared()&lt;/code&gt; triggers an immediate save of any pending debounced content so nothing is lost.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Additionally: You should learn about stuff like http vs https, REST vs GraphQL vs WebSockets. Mockingly.AI has a GYM where you can practice these exact questions and more. &lt;a href="https://mockingly.ai" rel="noopener noreferrer"&gt;Try&lt;/a&gt; it out.&lt;/p&gt;




&lt;h2&gt;
  
  
  Background Sync: WorkManager
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What WorkManager does:&lt;/strong&gt; WorkManager is the Jetpack-recommended solution for background work that must complete, even if the app is killed or the device restarts. It persists work to a Room-backed queue, respects battery constraints, and retries with exponential backoff on failure.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Interviewer:&lt;/strong&gt; How does sync work in the background?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Candidate:&lt;/strong&gt; The &lt;code&gt;NoteSyncWorker&lt;/code&gt; runs in three scenarios: when the user explicitly triggers a sync, when the network becomes available (via &lt;code&gt;ConnectivityManager.NetworkCallback&lt;/code&gt;), and on a periodic schedule (every hour).&lt;/p&gt;

&lt;p&gt;The worker runs as a &lt;code&gt;CoroutineWorker&lt;/code&gt; — safe to do Room reads and API calls without blocking the main thread:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NoteSyncWorker.doWork():
  1. Query Room for all notes where syncStatus = PENDING
  2. For each PENDING note:
     a. Try POST/PUT to sync API with { id, contentJson, updatedAt }
     b. Server responds with { serverId, serverUpdatedAt, conflicted: bool }
     c. If no conflict:
           Room update: syncStatus = SYNCED, serverUpdatedAt = response.serverUpdatedAt
     d. If conflict:
           Room update: syncStatus = CONFLICTED
           Store server version alongside local version
  3. Pull new notes from server (delta pull — send lastSyncTimestamp)
     For each server note:
        If note not in Room: INSERT (syncStatus = SYNCED)
        If note in Room and serverUpdatedAt &amp;gt; local serverUpdatedAt:
            Check for PENDING local changes → potential conflict
  4. Return Result.success() or Result.retry() on transient failure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Enqueue the worker as unique work using &lt;code&gt;ExistingWorkPolicy.KEEP&lt;/code&gt;. This prevents multiple simultaneous sync workers from racing each other:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nc"&gt;WorkManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enqueueUniqueWork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"notes_sync"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;ExistingWorkPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;KEEP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;syncRequest&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;For the periodic sync, use &lt;code&gt;enqueueUniquePeriodicWork&lt;/code&gt; with &lt;code&gt;ExistingPeriodicWorkPolicy.KEEP&lt;/code&gt; to prevent redundant periodic sync registrations across app restarts.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Conflict Resolution: The Hard Part
&lt;/h2&gt;

&lt;p&gt;This is where the interview gets interesting, and where the most valuable answers live. A notes app syncing across devices will inevitably have conflicts — the same note edited on two devices while both were offline.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Interviewer:&lt;/strong&gt; The user edits a note on their phone while offline. The same note was edited on their tablet while that was also offline. Both devices reconnect. What happens?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Candidate:&lt;/strong&gt; This is the classic offline sync conflict, and there are three resolution strategies — each with different trade-offs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strategy 1: Last-Write-Wins (LWW)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Compare &lt;code&gt;updatedAt&lt;/code&gt; timestamps. The version with the more recent timestamp wins; the other is discarded.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Phone version:  updatedAt = 14:00, content = "Meeting agenda: review PRD"
Tablet version: updatedAt = 14:05, content = "Meeting agenda: cancelled"
Winner: Tablet (newer timestamp)
Phone's changes silently discarded.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Simple to implement, zero user friction — but can silently discard work the user cares about. Acceptable for apps where notes are short and the cost of a lost edit is low. Not acceptable if a user writes a 500-word note on their phone and later fixes a typo on their tablet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strategy 2: Show Both — User Resolves&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a conflict is detected, mark the note as &lt;code&gt;CONFLICTED&lt;/code&gt; in Room. Store both versions: the local version and the incoming server version. Surface the conflict in the UI — a "conflict detected" badge on the note list item. When the user taps it, show a diff view with both versions and let them choose which to keep, or manually merge.&lt;/p&gt;

&lt;p&gt;This is the safest option for user data — nothing is lost. But it requires a UI for conflict resolution (a diff view is non-trivial to build) and puts cognitive load on the user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strategy 3: Auto-Merge (Best for Text)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the conflicting edits touch different parts of the text — one user added a paragraph at the top, the other edited the middle — they can be automatically merged. Use a three-way merge algorithm: find the common ancestor (the last synced version), apply both sets of changes independently, and combine them.&lt;/p&gt;


&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ancestor:  "Meeting notes"
Version A: "Meeting notes\nAction items:\n- Review PRD"  (appended)
Version B: "**Meeting notes**"  (bolded title)
Merged:    "**Meeting notes**\nAction items:\n- Review PRD"  (both applied)
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;If the edits genuinely conflict (both edited the same sentence differently), fall back to Strategy 2 and surface the conflict to the user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I'd recommend:&lt;/strong&gt; Strategy 3 with a fallback to Strategy 2. Auto-merge handles the majority of real-world conflicts silently; user resolution handles the hard cases. The implementation uses a CRDT-inspired approach or a Myers diff algorithm for text merging. This is what Notion and Apple Notes approximate in production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interviewer:&lt;/strong&gt; What's a CRDT and when would you use one?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Candidate:&lt;/strong&gt; A Conflict-free Replicated Data Type is a data structure designed to be merged from multiple sources without conflicts — mathematical guarantees, not heuristics. Every individual character insertion/deletion is tracked as an operation with a logical clock. Merging two CRDT documents always produces the same result regardless of order.&lt;/p&gt;

&lt;p&gt;The trade-off: CRDT-encoded documents are significantly larger (each character has metadata), more complex to implement, and require a CRDT-aware server. For a simple notes app, the three-way merge approach is simpler and correct for most cases. CRDTs make sense if you're building real-time collaborative editing where multiple users type simultaneously — like a Notion or Google Docs clone. For a single user's notes syncing across their own devices, last-write-wins or three-way merge is almost always sufficient.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Delta Sync: Don't Send Everything
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Interviewer:&lt;/strong&gt; How does the client know which notes to pull from the server on sync?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Candidate:&lt;/strong&gt; Delta sync. Rather than downloading every note on every sync, the client sends its last successful sync timestamp and the server returns only what changed since then.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;Client&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;GET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/sync?since=&lt;/span&gt;&lt;span class="mi"&gt;1733990400000&lt;/span&gt;&lt;span class="err"&gt;&amp;amp;deviceId=abc&lt;/span&gt;&lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;updated:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;note&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;note&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;created&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;modified&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;since&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;that&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;timestamp&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;deleted:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"note_id_5"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;deleted&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;another&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;device&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;since&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;that&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;timestamp&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The client stores &lt;code&gt;lastSyncTimestamp&lt;/code&gt; in &lt;code&gt;DataStore&amp;lt;Preferences&amp;gt;&lt;/code&gt; — not Room. It's a scalar value, not structured data. DataStore is the modern replacement for &lt;code&gt;SharedPreferences&lt;/code&gt; and avoids the thread-safety issues that &lt;code&gt;SharedPreferences&lt;/code&gt; has when accessed from multiple coroutines.&lt;/p&gt;

&lt;p&gt;On the server side, every note update touches a &lt;code&gt;updated_at&lt;/code&gt; server timestamp that the delta query uses. Deletions are soft-deleted and tracked in a &lt;code&gt;deleted_notes&lt;/code&gt; table so they appear in the delta response before the record is permanently purged.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you want to practice explaining exactly this kind of trade-off — why DataStore over SharedPreferences, why delta sync over full refresh — under interview pressure, &lt;a href="https://mockingly.ai" rel="noopener noreferrer"&gt;Mockingly.ai&lt;/a&gt; has Android system design simulations that put you in exactly these conversations.&lt;/p&gt;




&lt;h2&gt;
  
  
  Full-Text Search with Room FTS4
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Interviewer:&lt;/strong&gt; How does search work?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Candidate:&lt;/strong&gt; Room's &lt;code&gt;@Fts4&lt;/code&gt; annotation creates a virtual table backed by SQLite's FTS4 extension. FTS4 tokenises text at insert time and maintains an inverted index, enabling fast prefix and phrase matching.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What FTS4 is:&lt;/strong&gt; SQLite's Full-Text Search extension creates a separate virtual table alongside the main &lt;code&gt;notes&lt;/code&gt; table. When a note is inserted or updated, FTS4 tokenises the text and updates its index. Queries use &lt;code&gt;MATCH&lt;/code&gt; syntax rather than &lt;code&gt;LIKE&lt;/code&gt;, and the lookup is O(log n) against the index rather than a full-table scan.&lt;/p&gt;

&lt;p&gt;The DAO query:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Dao&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;NoteDao&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"""
        SELECT notes.* FROM notes
        INNER JOIN notes_fts ON notes.id = notes_fts.rowid
        WHERE notes_fts MATCH :query
          AND notes.isDeleted = 0
          AND notes.isArchived = 0
        ORDER BY rank
    """&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;searchNotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Flow&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;NoteEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The caller appends &lt;code&gt;*&lt;/code&gt; to enable prefix matching: &lt;code&gt;"meet*"&lt;/code&gt; matches "meeting", "meetup", "meetings". Without the wildcard, FTS4 only matches exact tokens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Room FTS4 doesn't handle:&lt;/strong&gt; fuzzy matching ("meetting" → "meeting"). If fuzzy search is important, consider maintaining a trigram index manually or preprocessing the query to expand common misspellings. For most notes apps, prefix matching is sufficient.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Attachments: Images and Files
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Interviewer:&lt;/strong&gt; How do you handle image attachments in notes?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Candidate:&lt;/strong&gt; Never store image bytes in Room. SQLite is not an object store, and large blobs in a Room database degrade query performance for the entire database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The pattern:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User attaches photo to a note
  │
  ▼
Copy photo to app's internal private storage
  → /data/data/com.example.notes/files/attachments/{uuid}.jpg
  (Internal storage — not accessible to other apps, no storage permission needed)
  │
  ▼
Store only the local file path in Room:
  AttachmentEntity { id, noteId, localPath, remoteUrl, syncStatus }
  │
  ▼
On sync: upload file to remote storage (S3 / GCS) via pre-signed URL
  (same pattern as photo apps — direct upload, not through the app server)
  │
  ▼
Update AttachmentEntity.remoteUrl once uploaded
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Why copy to internal storage?&lt;/strong&gt; The original photo might live in the camera roll, accessible via a content URI. Content URIs are temporary and can be revoked if the user deletes the photo from the gallery. Copying to internal storage gives the notes app durable ownership of the attachment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attachment sync:&lt;/strong&gt; attachments are uploaded asynchronously in a separate &lt;code&gt;AttachmentSyncWorker&lt;/code&gt;. They don't block note text sync. Note text syncs fast (bytes); attachment upload can take seconds depending on file size and network speed. Separating them keeps note sync latency low and allows attachment upload to retry independently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Storage quota:&lt;/strong&gt; warn the user when attachment storage exceeds a configurable threshold (say, 500 MB). Offer a "clear cached attachments" option that deletes locally cached versions of remotely backed attachments — they can be re-downloaded on demand.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Sync Status UI
&lt;/h2&gt;

&lt;p&gt;The UI should reflect sync state transparently without being intrusive.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Interviewer:&lt;/strong&gt; How does the user know if their notes are synced?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Candidate:&lt;/strong&gt; A &lt;code&gt;SyncStatusTracker&lt;/code&gt; in the ViewModel exposes the aggregate sync state as a &lt;code&gt;StateFlow&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SyncState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;Synced&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SyncState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;Syncing&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SyncState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;PendingCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SyncState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Conflict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;noteId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SyncState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;Offline&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;SyncState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The notes list screen observes this state and renders accordingly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Synced:&lt;/strong&gt; no indicator shown — clean state is the default&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Syncing:&lt;/strong&gt; a subtle progress indicator in the toolbar&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PendingCount:&lt;/strong&gt; "3 notes waiting to sync" — visible but not blocking&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conflict:&lt;/strong&gt; a badge on the conflicted note's list item — red dot&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline:&lt;/strong&gt; "Working offline" banner at the top, non-blocking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key UX principle from offline-first design: &lt;strong&gt;optimistic UI&lt;/strong&gt;. Show the note as saved immediately. The "syncing" state is a background concern. Never block the user from editing while sync is in flight. The phrase "Saved locally — syncing" is more reassuring than a spinner that blocks typing.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Handling Edge Cases
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Interviewer:&lt;/strong&gt; What happens if the user deletes a note on their phone while it was being edited on their tablet?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Candidate:&lt;/strong&gt; The delete event gets a &lt;code&gt;serverTimestamp&lt;/code&gt; when it syncs. On the next sync to the tablet, the server sends a &lt;code&gt;deleted&lt;/code&gt; array containing that note's ID. The tablet's sync worker checks: does this note have local unsaved changes (syncStatus = PENDING)?&lt;/p&gt;

&lt;p&gt;If &lt;strong&gt;no local changes&lt;/strong&gt;: apply the deletion. Room soft-deletes the note.&lt;/p&gt;

&lt;p&gt;If &lt;strong&gt;yes, local PENDING changes&lt;/strong&gt;: surface a conflict to the user. "This note was deleted on another device, but you have unsaved changes here. Keep your version or confirm deletion?" This is a case where auto-merge can't help — explicit user decision is required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interviewer:&lt;/strong&gt; What about the note the user created offline that has the exact same UUID as one already on the server?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Candidate:&lt;/strong&gt; UUID collision probability with a standard &lt;code&gt;UUID.randomUUID()&lt;/code&gt; (Version 4 UUID) is approximately 1 in 2^122. With a billion notes created, the probability of any two sharing a UUID is roughly 1 in 10^27. For practical purposes this never happens. But defensively, the sync API validates UUID uniqueness server-side and returns a 409 Conflict if a collision somehow occurs. The client generates a new UUID and retries. This is a theoretical concern worth acknowledging but not worth over-engineering.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Common Interview Follow-ups
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;"How would you implement real-time collaboration — two users editing the same note simultaneously?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This changes the architecture significantly. You'd need a WebSocket connection to a backend that broadcasts operations in real time. The local note model would switch to a CRDT (Conflict-free Replicated Data Type) like Yjs or Automerge, where every character insertion/deletion is represented as an operation with a logical timestamp. Room still holds the local state, but the sync mechanism becomes operation-based (send operations, receive operations) rather than state-based (send full note, receive full note). This is a significantly heavier lift than eventual-consistency sync — worth naming the architectural difference clearly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"How do you handle the case where WorkManager can't sync because the device has been offline for weeks?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The server retains notes in a soft-deleted state for a grace period (say, 90 days) before permanent deletion. Notes flagged as deleted by another device more than 90 days ago will simply not appear in delta sync responses. The client's eventual sync catchup handles all changes within that window correctly. If a device reconnects after the grace period, the user might see stale notes that others consider deleted — surface this edge case honestly in the design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"How would you add a sharing feature — send a note to another user?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Shared notes are a different data ownership model. A note owned by User A can be granted read or write access to User B. Server-side: a &lt;code&gt;note_shares&lt;/code&gt; table with &lt;code&gt;{ note_id, owner_id, recipient_id, permission }&lt;/code&gt;. Client-side: the shared note appears in the recipient's note list via delta sync. The recipient's edits sync to the server, which fans out to the owner's devices on their next delta pull. Conflict resolution applies across users just as it does across devices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"How do you prevent data loss if Room's database gets corrupted?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Room's database file lives in internal storage — not backed up by default by Android's automatic backup. Enable &lt;code&gt;android:allowBackup="true"&lt;/code&gt; and &lt;code&gt;android:fullBackupContent&lt;/code&gt; rules in the manifest to include the Room database in Google's automatic cloud backup (limited to 25 MB). For production: implement explicit export — a background task that periodically exports all notes to a JSON file in the user's Google Drive or via Android's &lt;code&gt;BlobStoreManager&lt;/code&gt;. Defense in depth: if the local database is corrupted, a full re-download from the server is the recovery path. This is why the server is the durable source of truth, not the device.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Interview Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ Clarified scope — sync across devices, rich text, tags, search, full offline support&lt;/li&gt;
&lt;li&gt;✅ Clean Architecture + MVVM, Room as single source of truth&lt;/li&gt;
&lt;li&gt;✅ Client-generated UUIDs — offline note creation without server round-trip&lt;/li&gt;
&lt;li&gt;✅ &lt;code&gt;syncStatus&lt;/code&gt; enum on every note — SYNCED, PENDING, CONFLICTED&lt;/li&gt;
&lt;li&gt;✅ Soft delete (&lt;code&gt;isDeleted&lt;/code&gt;) — never hard-delete before sync&lt;/li&gt;
&lt;li&gt;✅ &lt;code&gt;updatedAt&lt;/code&gt; and &lt;code&gt;serverUpdatedAt&lt;/code&gt; — local and server timestamps for conflict detection&lt;/li&gt;
&lt;li&gt;✅ Rich text stored as JSON spans, plain text extracted separately for FTS&lt;/li&gt;
&lt;li&gt;✅ Room FTS4 for full-text search — &lt;code&gt;@Fts4&lt;/code&gt; annotation, MATCH query, prefix wildcard&lt;/li&gt;
&lt;li&gt;✅ Debounced saves in ViewModel — not on every keystroke, immediate save on &lt;code&gt;onCleared()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;✅ WorkManager &lt;code&gt;CoroutineWorker&lt;/code&gt; for background sync — persists across process kills and reboots&lt;/li&gt;
&lt;li&gt;✅ &lt;code&gt;enqueueUniqueWork&lt;/code&gt; with &lt;code&gt;KEEP&lt;/code&gt; policy — no duplicate sync workers&lt;/li&gt;
&lt;li&gt;✅ Three conflict strategies explained — LWW, user resolution, auto-merge with fallback&lt;/li&gt;
&lt;li&gt;✅ Delta sync with &lt;code&gt;lastSyncTimestamp&lt;/code&gt; — not full re-download on every sync&lt;/li&gt;
&lt;li&gt;✅ &lt;code&gt;lastSyncTimestamp&lt;/code&gt; in DataStore (not SharedPreferences, not Room)&lt;/li&gt;
&lt;li&gt;✅ Attachments copied to internal storage, file path in Room, uploaded separately&lt;/li&gt;
&lt;li&gt;✅ &lt;code&gt;AttachmentSyncWorker&lt;/code&gt; separate from note text sync — different latency/retry profiles&lt;/li&gt;
&lt;li&gt;✅ Optimistic UI — "Saved locally, syncing" pattern&lt;/li&gt;
&lt;li&gt;✅ SyncState exposed as sealed class StateFlow from ViewModel&lt;/li&gt;
&lt;li&gt;✅ CRDT explained as the real-time collaboration upgrade path&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Designing a notes app is a deceptively rich Android interview question. It's not about CRUD — it's about building a system that feels instant, never loses data, handles network absence gracefully, and reconciles state across devices in a way that makes sense to users.&lt;/p&gt;

&lt;p&gt;The candidates who impress interviewers at Google, Microsoft, and Notion aren't the ones who describe a simple Room + Retrofit setup. They're the ones who name the offline-first principle explicitly, explain what &lt;code&gt;syncStatus&lt;/code&gt; buys you, articulate the three conflict resolution strategies and their trade-offs, know why delta sync matters, and can describe what happens in the edit-on-two-devices-while-offline scenario without blinking.&lt;/p&gt;

&lt;p&gt;The design pillars:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Room as single source of truth&lt;/strong&gt; — UI never talks to the network; all reads and writes go through Room&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client-generated UUIDs&lt;/strong&gt; — offline note creation requires a device-side identity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;syncStatus on every record&lt;/strong&gt; — the engine that drives the entire sync pipeline&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WorkManager with unique work policy&lt;/strong&gt; — the only tool that guarantees sync survives process kills&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delta sync with DataStore timestamp&lt;/strong&gt; — don't re-download everything on every sync&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-merge with fallback to user resolution&lt;/strong&gt; — the right conflict strategy for a notes app&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Room FTS4 for search&lt;/strong&gt; — orders of magnitude faster than &lt;code&gt;LIKE&lt;/code&gt; at any meaningful note count&lt;/li&gt;
&lt;/ol&gt;







&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is offline-first architecture in an Android notes app?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Offline-first&lt;/strong&gt; means the app reads and writes to a local database — not a server — as its primary source of truth.&lt;/p&gt;

&lt;p&gt;Every note operation (create, edit, delete) goes straight to Room without touching the network. The UI reflects changes instantly. Sync to the server happens in the background, invisible to the user.&lt;/p&gt;

&lt;p&gt;Key properties of an offline-first notes app:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;All core features work with zero network connectivity&lt;/li&gt;
&lt;li&gt;UI never shows a loading spinner waiting for the network&lt;/li&gt;
&lt;li&gt;Data is never lost because the device lost signal mid-edit&lt;/li&gt;
&lt;li&gt;Server sync runs silently via WorkManager when connectivity returns&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Why use Room as the single source of truth?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Room is the single source of truth&lt;/strong&gt; because it guarantees the UI always has data — regardless of network state.&lt;/p&gt;

&lt;p&gt;If the ViewModel fetched data from Retrofit directly, a network failure would leave the screen blank. With Room:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The UI observes Room via &lt;code&gt;Flow&lt;/code&gt; and reacts to every local change&lt;/li&gt;
&lt;li&gt;The network only writes &lt;em&gt;into&lt;/em&gt; Room — it never drives the UI&lt;/li&gt;
&lt;li&gt;Cached data from the last session is available immediately on app open&lt;/li&gt;
&lt;li&gt;Offline and online states are identical from the UI's perspective&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  How does WorkManager handle background sync in a notes app?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;WorkManager&lt;/strong&gt; is Android's recommended API for guaranteed background work that must complete even after a process kill or device reboot.&lt;/p&gt;

&lt;p&gt;How it handles notes sync:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A &lt;code&gt;NoteSyncWorker&lt;/code&gt; (&lt;code&gt;CoroutineWorker&lt;/code&gt;) is enqueued with &lt;code&gt;ExistingWorkPolicy.KEEP&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;WorkManager persists the job to its own Room-backed database internally&lt;/li&gt;
&lt;li&gt;The job runs when the &lt;code&gt;NetworkType.CONNECTED&lt;/code&gt; constraint is satisfied&lt;/li&gt;
&lt;li&gt;If the process is killed mid-sync, WorkManager re-runs the worker on next launch&lt;/li&gt;
&lt;li&gt;Multiple triggers (network return, app open, manual sync) never spawn duplicate workers&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;KEEP&lt;/code&gt; policy is essential — without it, every app open could enqueue a fresh sync job, eventually queuing hundreds of redundant workers.&lt;/p&gt;




&lt;h3&gt;
  
  
  What is delta sync and why does it matter for a notes app?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Delta sync&lt;/strong&gt; means uploading and downloading only what has &lt;em&gt;changed&lt;/em&gt; since the last successful sync — not the entire note list every time.&lt;/p&gt;

&lt;p&gt;How it works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The client stores &lt;code&gt;lastSyncTimestamp&lt;/code&gt; in DataStore (not SharedPreferences — it's thread-safe)&lt;/li&gt;
&lt;li&gt;On each sync, the client sends this timestamp to the server&lt;/li&gt;
&lt;li&gt;The server returns only notes created or modified after that timestamp&lt;/li&gt;
&lt;li&gt;The client applies those changes to Room&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why it matters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A user with 500 notes who edits 5 per day transfers ~25 KB, not ~2.5 MB&lt;/li&gt;
&lt;li&gt;Sync is faster, uses less battery, and completes before the user notices&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  What is the syncStatus field and why does every note need one?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;syncStatus&lt;/code&gt;&lt;/strong&gt; is an enum on every &lt;code&gt;NoteEntity&lt;/code&gt; that tracks whether the local state has been confirmed by the server.&lt;/p&gt;

&lt;p&gt;The three states:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;SYNCED&lt;/strong&gt; — local and server agree; no action needed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PENDING&lt;/strong&gt; — local change exists that hasn't been uploaded yet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CONFLICTED&lt;/strong&gt; — a conflict was detected that needs resolution&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why it's necessary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The sync worker queries &lt;code&gt;WHERE syncStatus = PENDING&lt;/code&gt; to know what to upload&lt;/li&gt;
&lt;li&gt;The UI shows a badge on &lt;code&gt;CONFLICTED&lt;/code&gt; notes for user attention&lt;/li&gt;
&lt;li&gt;Without this field, the app has no reliable way to track unsent edits&lt;/li&gt;
&lt;li&gt;On process kill mid-sync, &lt;code&gt;PENDING&lt;/code&gt; notes are safely retried on next launch&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  What are the conflict resolution strategies for a syncing notes app?
&lt;/h3&gt;

&lt;p&gt;A conflict occurs when the same note is edited on two devices while both are offline. There are three standard strategies:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Last-Write-Wins (LWW)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compares &lt;code&gt;updatedAt&lt;/code&gt; timestamps; the newer version wins&lt;/li&gt;
&lt;li&gt;Pro: simple, zero user friction&lt;/li&gt;
&lt;li&gt;Con: silently discards edits the user cares about&lt;/li&gt;
&lt;li&gt;Best for: short notes where losing an edit is low-cost&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. User Resolution&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Marks the note &lt;code&gt;CONFLICTED&lt;/code&gt;, stores both versions, asks the user to choose&lt;/li&gt;
&lt;li&gt;Pro: zero data loss&lt;/li&gt;
&lt;li&gt;Con: adds friction; requires a diff/merge UI&lt;/li&gt;
&lt;li&gt;Best for: apps where every word matters (legal, medical notes)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Auto-Merge with Fallback&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses a three-way merge to combine changes touching &lt;em&gt;different&lt;/em&gt; text ranges&lt;/li&gt;
&lt;li&gt;Falls back to user resolution only when edits genuinely overlap&lt;/li&gt;
&lt;li&gt;Pro: handles most real-world conflicts silently&lt;/li&gt;
&lt;li&gt;Con: more complex to implement&lt;/li&gt;
&lt;li&gt;Best for: general-purpose notes apps (Google Keep, Apple Notes style)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Recommended approach:&lt;/strong&gt; auto-merge with a user-resolution fallback. Most conflicts are two edits to different paragraphs — they merge automatically. Genuine overlapping edits are surfaced explicitly.&lt;/p&gt;




&lt;h3&gt;
  
  
  How does Room FTS4 full-text search work in a notes app?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Room FTS4&lt;/strong&gt; creates a SQLite virtual table that tokenises note content at write time and enables instant keyword searches using an inverted index.&lt;/p&gt;

&lt;p&gt;How it differs from a &lt;code&gt;LIKE&lt;/code&gt; query:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;LIKE '%keyword%'&lt;/code&gt; scans every row sequentially — O(n)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FTS4 MATCH 'keyword'&lt;/code&gt; is a direct index lookup — O(log n)&lt;/li&gt;
&lt;li&gt;FTS4 supports prefix matching (&lt;code&gt;meet*&lt;/code&gt; matches "meeting", "meetup")&lt;/li&gt;
&lt;li&gt;Speed difference is imperceptible at 50 notes; significant at 5,000+&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Setup in Room:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Annotate a virtual entity with &lt;code&gt;@Fts4(contentEntity = NoteEntity::class)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Index &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;contentPlainText&lt;/code&gt; (plain text stripped from rich text JSON)&lt;/li&gt;
&lt;li&gt;Query with &lt;code&gt;SELECT * FROM notes INNER JOIN notes_fts WHERE notes_fts MATCH :query&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Append &lt;code&gt;*&lt;/code&gt; to the query string to enable prefix matching&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  How do you store rich text in an Android notes app?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Rich text is serialised to JSON&lt;/strong&gt; and stored in a &lt;code&gt;contentJson&lt;/code&gt; TEXT column in Room. A separate &lt;code&gt;contentPlainText&lt;/code&gt; column stores the stripped text for FTS indexing.&lt;/p&gt;

&lt;p&gt;The JSON format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Meeting notes for Q4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"spans"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BOLD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ITALIC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"end"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The two storage approaches compared:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;JSON spans&lt;/td&gt;
&lt;td&gt;Native Android integration, no library needed&lt;/td&gt;
&lt;td&gt;Harder to diff across devices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Markdown string&lt;/td&gt;
&lt;td&gt;Easy to diff, portable&lt;/td&gt;
&lt;td&gt;Requires rendering library (Markwon)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For a Google Keep–style app with basic formatting, JSON spans integrating with Android's native &lt;code&gt;SpannableString&lt;/code&gt; is the cleaner choice. For a Notion-style app with blocks and embeds, a block-based document model (similar to ProseMirror) is more appropriate.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why are client-generated UUIDs important for offline note creation?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Client-generated UUIDs&lt;/strong&gt; allow notes to have a stable identity from the moment of creation — before any server interaction.&lt;/p&gt;

&lt;p&gt;If the primary key were a server-assigned integer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The app cannot create a note offline (no ID until the server responds)&lt;/li&gt;
&lt;li&gt;The UI must wait for a network round-trip before displaying the new note&lt;/li&gt;
&lt;li&gt;Process kill during creation leaves the app in an ambiguous state&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With &lt;code&gt;UUID.randomUUID()&lt;/code&gt; (Version 4):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The note has an ID instantly — used as the Room PK and the server's document ID&lt;/li&gt;
&lt;li&gt;Offline creation, editing, and deletion all work without network&lt;/li&gt;
&lt;li&gt;The UUID serves as an idempotency key for sync — if a sync POST is retried, the server rejects the duplicate&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Collision probability: ~1 in 10²⁷ with a billion notes. Effectively zero.&lt;/p&gt;




&lt;h3&gt;
  
  
  Which companies ask the Android notes app system design question?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Google, Microsoft, Notion, Evernote, and Dropbox&lt;/strong&gt; all ask variants of this question for senior Android engineer roles.&lt;/p&gt;

&lt;p&gt;Why it's popular:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It's self-contained — clear product scope, no ambiguity about what to design&lt;/li&gt;
&lt;li&gt;It touches every hard Android topic: Room schema, WorkManager, offline-first, conflict resolution&lt;/li&gt;
&lt;li&gt;The depth scales cleanly — a junior candidate describes CRUD; a senior candidate explains &lt;code&gt;syncStatus&lt;/code&gt;, delta sync, and three-way merge&lt;/li&gt;
&lt;li&gt;It maps directly to real products these companies build and maintain&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Red flags interviewers watch for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Designing around Retrofit without mentioning offline handling&lt;/li&gt;
&lt;li&gt;Not explaining what &lt;code&gt;syncStatus&lt;/code&gt; buys you&lt;/li&gt;
&lt;li&gt;Proposing SharedPreferences for &lt;code&gt;lastSyncTimestamp&lt;/code&gt; (not thread-safe)&lt;/li&gt;
&lt;li&gt;Missing soft delete — hard-deleting before sync drops data silently&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;*The notes app question rewards candidates who understand that mobile system design is fundamentally about managing two sources of truth — the device and the server — and making the reconciliation between them invisible to the user. &lt;/p&gt;

&lt;p&gt;If you want to practice talking through conflict resolution strategies, delta sync, and WorkManager lifecycle decisions under real interview pressure, &lt;a href="https://mockingly.ai" rel="noopener noreferrer"&gt;Mockingly.ai&lt;/a&gt; has Android-focused system design simulations specifically built for engineers preparing for senior roles at Google, Microsoft, Notion, and Evernote.*&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>softwareengineering</category>
      <category>interview</category>
      <category>android</category>
    </item>
    <item>
      <title>System Design Interview Tip No One Talks About</title>
      <dc:creator>Ayusch</dc:creator>
      <pubDate>Wed, 19 Nov 2025 21:36:26 +0000</pubDate>
      <link>https://dev.to/ayuschjain/system-design-interview-tip-no-one-talks-about-2o43</link>
      <guid>https://dev.to/ayuschjain/system-design-interview-tip-no-one-talks-about-2o43</guid>
      <description>&lt;p&gt;System design interviews can feel overwhelming. You draw big boxes. You label them. You sketch arrows.You talk about APIs, queues, caching, scalability, data models, and failure modes.&lt;/p&gt;

&lt;p&gt;And even after all that, your interviewer can still say, "What happens when this part fails?" or "Walk me through your data consistency model." It feels endless 😭&lt;/p&gt;

&lt;p&gt;But after seeing hundreds of candidates prepare, practice, and interview, one pattern has become incredibly clear.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why instincts matter more than memorizing architectures
&lt;/h2&gt;

&lt;p&gt;You can memorize dozens of famous system designs from YouTube videos or GitHub repositories. You can replicate architecture diagrams for Netflix, Uber, or Instagram. But real interviews almost never follow that script.&lt;/p&gt;

&lt;p&gt;Instead, interviewers test how you think.&lt;/p&gt;

&lt;p&gt;They ask questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Explain &lt;a href="https://mockingly.ai/trivia" rel="noopener noreferrer"&gt;http vs https&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Why would you choose REST over GraphQL here&lt;/li&gt;
&lt;li&gt;How would you design pagination for millions of records&lt;/li&gt;
&lt;li&gt;When would you use Redis over a database cache&lt;/li&gt;
&lt;li&gt;What consistency model would you pick and why&lt;/li&gt;
&lt;li&gt;How would you handle offline sync in a mobile app&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhftr4xju3jtcl2foq1sj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhftr4xju3jtcl2foq1sj.png" alt="mockingly.ai system design interview preparation" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Solve these questions on &lt;a href="https://mockingly.ai/trivia" rel="noopener noreferrer"&gt;https://mockingly.ai/trivia&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Image above is a screenshot from Mockingly which has these tradeoff-like questions to help you understand the concepts.&lt;/p&gt;

&lt;p&gt;These are all fundamental concepts, not full systems.&lt;br&gt;
If you know the fundamentals well, the interview becomes more like a conversation than an exam. You can explain trade-offs clearly. You can reason on the fly. You can adapt when the interviewer changes constraints.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with most preparation approaches
&lt;/h2&gt;

&lt;p&gt;Most candidates prepare in a way that looks productive, but actually creates a false sense of readiness.&lt;/p&gt;

&lt;p&gt;They binge long system design videos. They read architecture posts. They memorize high-level diagrams.&lt;/p&gt;

&lt;p&gt;But when the interviewer digs into details, everything suddenly feels shaky.&lt;/p&gt;

&lt;p&gt;If your fundamentals are weak, you end up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Over-explaining obvious things&lt;/li&gt;
&lt;li&gt;Forgetting key trade-offs&lt;/li&gt;
&lt;li&gt;Struggling to justify decisions&lt;/li&gt;
&lt;li&gt;Repeating the same patterns regardless of the question&lt;/li&gt;
&lt;li&gt;Freezing when asked about bottlenecks, failure modes, or data flow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Strong candidates look confident because they know the basics so well that they can build any system step by step.&lt;/p&gt;

&lt;h2&gt;
  
  
  So how do you build these instincts
&lt;/h2&gt;

&lt;p&gt;By practicing the fundamentals in short, focused, repeated bursts.&lt;br&gt;
This is the same way people train for chess, competitive programming, language learning, or fitness. Consistent, small reps beat long, passive study sessions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqb93d9wyqw5m0w2bjpdi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqb93d9wyqw5m0w2bjpdi.png" alt="mockingly.ai system design interview preparation" width="800" height="557"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These fundamentals are essential for any system design interview preparation: &lt;a href="https://mockingly.ai/trivia" rel="noopener noreferrer"&gt;Mockingly Trivia&lt;/a&gt;. You want to quickly test yourself on topics like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;REST vs GraphQL vs WebSockets&lt;/li&gt;
&lt;li&gt;SQL vs NoSQL&lt;/li&gt;
&lt;li&gt;Types of pagination and when to use each&lt;/li&gt;
&lt;li&gt;Caching patterns&lt;/li&gt;
&lt;li&gt;Rate limiting techniques&lt;/li&gt;
&lt;li&gt;Message queues vs streams&lt;/li&gt;
&lt;li&gt;Horizontal vs vertical scaling&lt;/li&gt;
&lt;li&gt;Types of consistency models&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the high-signal areas that show up in almost every interview.&lt;/p&gt;

&lt;p&gt;A faster way to build interview instincts I built mockingly.ai for exactly this reason. One feature in particular, Interview Trivia, gives you short, high-value quizzes that target the most important fundamentals.&lt;/p&gt;

&lt;p&gt;These quizzes help you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Strengthen your understanding of core concepts&lt;/li&gt;
&lt;li&gt;Build the reflexes needed during live interviews&lt;/li&gt;
&lt;li&gt;Learn trade-offs in a practical, memorable way&lt;/li&gt;
&lt;li&gt;Train your brain to respond faster and with more clarity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each quiz takes only a minute or two, and covers real topics that candidates struggle with in actual interviews.&lt;/p&gt;

&lt;p&gt;If you want to try it, you can check it out here: &lt;a href="https://mockingly.ai/trivia" rel="noopener noreferrer"&gt;https://mockingly.ai/trivia&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Combine fundamentals with real practice
&lt;/h2&gt;

&lt;p&gt;Trivia alone is not enough. But it gives you a solid foundation. Once your fundamentals are strong, full mock interviews become far easier.&lt;br&gt;
At that point, practice full sessions where you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Draw a system diagram&lt;/li&gt;
&lt;li&gt;Explain data flow&lt;/li&gt;
&lt;li&gt;Handle follow-up questions&lt;/li&gt;
&lt;li&gt;Discuss trade-offs&lt;/li&gt;
&lt;li&gt;Justify design decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where everything clicks. A simple preparation plan you can follow. Here is a balanced way to prep without burning out:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Daily (5 to 10 minutes):&lt;/strong&gt; Do a few Interview Trivia quizzes to sharpen fundamentals.&lt;br&gt;
&lt;strong&gt;Weekly (1 or 2 times):&lt;/strong&gt; Do a full mock system design session.&lt;br&gt;
&lt;strong&gt;After each session:&lt;/strong&gt; Review what confused you and add those topics to your fundamentals practice.&lt;/p&gt;

&lt;p&gt;This creates a cycle of steady improvement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final takeaway
&lt;/h2&gt;

&lt;p&gt;If you want to improve your performance in system design interviews, stop trying to memorize giant architectures. Focus on mastering the core concepts and trade-offs. Build strong instincts. Train them often. Keep your practice light but consistent.&lt;/p&gt;

&lt;p&gt;This one shift separates average candidates from standout ones.&lt;br&gt;
If you want a structured way to build these instincts, try Interview Trivia and free AI mock interviews at: &lt;a href="https://mockingly.ai" rel="noopener noreferrer"&gt;https://mockingly.ai&lt;/a&gt;&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
      <category>interview</category>
    </item>
    <item>
      <title>The Mobile System Design Interview: My FAANG Prep Journey + Free Practice Resource</title>
      <dc:creator>Ayusch</dc:creator>
      <pubDate>Thu, 21 Aug 2025 19:28:09 +0000</pubDate>
      <link>https://dev.to/ayuschjain/the-mobile-system-design-interview-my-faang-prep-journey-free-practice-resource-3jek</link>
      <guid>https://dev.to/ayuschjain/the-mobile-system-design-interview-my-faang-prep-journey-free-practice-resource-3jek</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4z0m9p6yvmfmwvfeisl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo4z0m9p6yvmfmwvfeisl.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;When talking about System Design, most resources, experiences written online focus heavily on backend system designs. But if you’re aspiring to be a mobile (Android, iOS) engineer at one of the FAANGs, you’ll have to go through a rigorous mobile system design interview.&lt;/p&gt;

&lt;p&gt;I’ve interviewed at 3/5 FAANG companies, and have cleared their system design rounds. And after about 6 years as a mobile engineer, I feel I have a fairly good experience about what consists of a system design round at these companies.&lt;/p&gt;

&lt;p&gt;But there’s a dearth of mobile focused system design preparation material. So in this blog, I’ll share my experience interviewing at these companies, and a few tips on how to prep for one. I hope this will help any aspiring mobile devs who have an upcoming interview.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Experience
&lt;/h2&gt;

&lt;p&gt;The interview at FAANG consists of 3 main components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Coding interviews: can range from 2 - 3 rounds of Data Structure and Algorithms focused interview.&lt;/li&gt;
&lt;li&gt;System Design interview: While mostly 1, recently there’s been a push for 2 rounds of system design interviews. I’ve experienced it at one of the big techs.&lt;/li&gt;
&lt;li&gt;Behavioural Interview: These are interviews focused on your past experiences. Questions are situation based and the best way to answer these is using the STAR method.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So let’s talk about System Design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here’s some of system design questions I’ve encountered so far in my interviews:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Design an image caching library like glide.&lt;/li&gt;
&lt;li&gt;Design a 1 to 1 Chat application which can also send images, videos.&lt;/li&gt;
&lt;li&gt;Design a App Store.&lt;/li&gt;
&lt;li&gt;Design an e-commerce app’s homepage.&lt;/li&gt;
&lt;li&gt;Design a stock market app’s ticker page. The page which displays the prices of stocks.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These are some of the major ones that I remember.&lt;/p&gt;

&lt;p&gt;And while you can find answers to most of them online, just mugging up is never the solution. When I tried mugging up initially, it made me anxious as the interview day got closer. I became anxious that I might forget to draw a component.&lt;/p&gt;

&lt;p&gt;After failing a few interviews, I realised I wasn’t failing because I lacked knowledge, I was failing because I obsessed over details instead of thinking like an architect.&lt;/p&gt;

&lt;p&gt;See, for system design interviews, you can direct them in any way you want. It’s up to you how you steer the interview. You can go down the rabbit hole of discussing very specific details, or you can focus on the building blocks of the design and if need be, explain the block which you’re most confident about. Let the interviewer grill you on a component. Don’t make it hard yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Preparation
&lt;/h2&gt;

&lt;p&gt;As a mobile (android, react native) engineer, I couldn’t find many resources to prepare for the interviews. There were questions sprinkled here and there, but nothing like Grokking the system design interview which was heavily backend focused.&lt;/p&gt;

&lt;p&gt;I tried doing some mock interviews with my friends, but they weren’t necessarily helpful. Most of my friends were backend engineers + it was hard to schedule time with them due to our heavy workload. Weekend plans never materialised.&lt;/p&gt;

&lt;p&gt;I came across some websites which offered system design interviews with engineer from FAANGs but it was too costly for me. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Plug: I created &lt;a href="https://mockingly.ai" rel="noopener noreferrer"&gt;mockingly.ai&lt;/a&gt; to solve for this problem. The first mock interview platform with mobile-specific system design questions, instant AI feedback, and on-demand practice. It’s like having a FAANG engineer available 24/7 to mock interview you. Right now, the first session is free!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next up, &lt;a href="https://github.com/weeeBox/mobile-system-design" rel="noopener noreferrer"&gt;weebox’s github repository&lt;/a&gt; was the first resource that was actually helpful for me. It had mobile focused system design questions. &lt;/p&gt;

&lt;p&gt;Then I did the worst thing possible, I tried mugging up all the answers. As I said, design interviews are very subjective and mugging never helps. I failed miserably at a design interview for a job I desperately wanted. I was disheartened. I had been fairly confident that I could clear the design round as I had all the answers in my head, so I couldn’t believe I screwed up the interview. &lt;/p&gt;

&lt;p&gt;I had screwed up some sys design interviews before, but those weren’t for jobs that I was desperately aiming for, this time it hit different. Something had to change.&lt;/p&gt;

&lt;p&gt;And that change was my preparation strategy. I realised that mugging up won’t help. I needed to really understand how system design worked, what are the components to focus on and the concepts. Also, my approach to interviews had to change. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here’s what I did:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I looked at weebox’s mobile system design questions not as an Android, iOS engineer. But as an architect. &lt;/li&gt;
&lt;li&gt;I started thinking in terms of Screens, presentation layer, data layer. I read how repository pattern works.&lt;/li&gt;
&lt;li&gt;Actively tried not to think in terms of Android concepts like work manager, foreground services, etc…I wanted to think high level, like an architect.&lt;/li&gt;
&lt;li&gt;Picked up 1 question from Weebox, and tried to solve it myself.&lt;/li&gt;
&lt;li&gt;Reviewed my diagrams comparing it to Weebox’s answers. &lt;/li&gt;
&lt;li&gt;Next, pick up some concepts which I wanted to learn such as http vs https, rest vs WebSocket vs GraphQL.&lt;/li&gt;
&lt;li&gt;Started actively critiquing my design choices. eg. why did I choose REST and not WebSocket? What’s the difference, how do they both work.&lt;/li&gt;
&lt;li&gt;I tried mock interviewing, but couldn’t find people for it. Moreover, our timings never matched. &lt;a href="https://mockingly.ai" rel="noopener noreferrer"&gt;mockingly.ai&lt;/a&gt; would have been really helpful for preparing for system design interviews. I could do the mocks on demand.&lt;/li&gt;
&lt;li&gt;Designing libraries was no different. Even though they have no screens, they have an entry point. for example: CacheManager for a caching library, which would talk to other components like repository, file cache, sqlite etc…&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It took me almost 4-5 months to get my head around system design interviews. The major change was my thought process. I started to think like an architect instead of a domain expert (like android engineer, iOS engineer).&lt;/p&gt;

&lt;p&gt;Then I scheduled some interviews.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interview experience
&lt;/h2&gt;

&lt;p&gt;Once I got done with my prep, I decided to appear for some interviews, and luckily got a chance at one of the FAANGs.&lt;/p&gt;

&lt;p&gt;This time I wasn’t anxious. At least not about my system design interview. I knew I had the concepts in my head, I knew I had prepared well. And if only I could communicate what I was doing and thinking and explain my decisions, it’d be a breeze!&lt;/p&gt;

&lt;p&gt;And it was, I got the feedback, and even though I didn’t make it (due to a coding round), I had cleared the system design interview and it was s STRONG hire. Yay! I was overjoyed, I had overcome the only obstacle I had in my interview preparations.&lt;/p&gt;

&lt;p&gt;System design had always been a mistery to me. And I had finally solved it.&lt;/p&gt;

&lt;p&gt;I still need to prep for system design rounds, just as I need to do for coding rounds, but it’s not daunting to me anymore. I now have my resources that I can pick up just a month before the interview and be ready.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Preparation tips:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here I’ll collate all the things that you’ll find helpful for your system design interview prep. I’ll keep it mobile focused (sorry backend engineers):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://mockingly.ai" rel="noopener noreferrer"&gt;mockingly.ai&lt;/a&gt; for practicing system design interviews whenever you like.&lt;/li&gt;
&lt;li&gt;Weebox’s &lt;a href="https://github.com/weeeBox/mobile-system-design" rel="noopener noreferrer"&gt;Github repository&lt;/a&gt; for reading up on the questions and answers. It’s like a question bank.&lt;/li&gt;
&lt;li&gt;Alex Lementuev’s youtube channel. Some interviews are helpful. I would not take the answers on face value, but watch the flow of the interview and the candidate’s thought process. &lt;/li&gt;
&lt;li&gt;Speak. Speak a lot! Practice thinking out loud. You’ll need this to direct the interview.&lt;/li&gt;
&lt;li&gt;Understand how things like http, rest, GraphQL, WebSocket work and why would you pick one over the other. &lt;/li&gt;
&lt;li&gt;Think like an architect and not a XYZ engineer.&lt;/li&gt;
&lt;li&gt;Practice…&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next up, a step-by-step framework for any system design interview: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clarify requirements.&lt;/li&gt;
&lt;li&gt;Identify users and flows.&lt;/li&gt;
&lt;li&gt;Break down into layers (UI, data, networking).&lt;/li&gt;
&lt;li&gt;Highlight trade-offs.&lt;/li&gt;
&lt;li&gt;Deep-dive into one component.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let me know if you found this blog helpful. I wished a guide existed for mobile engineers to prepare for mobile system design interviews. Here’s my attempt at creating one :)&lt;/p&gt;

&lt;p&gt;If you’re prepping for mobile interviews, give &lt;a href="https://mockingly.ai" rel="noopener noreferrer"&gt;mockingly.ai&lt;/a&gt; a try and tell me what you think. I’d love your feedback — and maybe your success story will be the next one featured there.&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>programming</category>
      <category>career</category>
      <category>interview</category>
    </item>
    <item>
      <title>Creating a Bottom Sheet in Flutter</title>
      <dc:creator>Ayusch</dc:creator>
      <pubDate>Wed, 13 May 2020 11:52:19 +0000</pubDate>
      <link>https://dev.to/ayuschjain/creating-a-bottom-sheet-in-flutter-4hhn</link>
      <guid>https://dev.to/ayuschjain/creating-a-bottom-sheet-in-flutter-4hhn</guid>
      <description>&lt;p&gt;In one of my &lt;a href="https://ayusch.com/bottom-sheet-in-react-native/" rel="noopener noreferrer"&gt;previous articles&lt;/a&gt;, I outlined how to create a bottom sheet in React Native. In this short tutorial, we’ll see how to create a bottom sheet in Flutter. &lt;/p&gt;

&lt;p&gt;This is by far the easiest framework I’ve encountered on creating a bottom sheet. It literally just involves calling a simple method. So this’ll be short and quick.&lt;/p&gt;

&lt;h1&gt;
  
  
  Getting Started
&lt;/h1&gt;

&lt;p&gt;First step of this tutorial is to create a new &lt;a href="https://ayusch.com/getting-started-with-flutter-app-development/" rel="noopener noreferrer"&gt;flutter&lt;/a&gt; project. If you haven’t already installed flutter, check out this article on how to install flutter on your machine.&lt;/p&gt;

&lt;p&gt;This tutorial will guide you with a step by step tutorial. Next, after you’ve installed flutter, create a new flutter project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;➜  ~ flutter create bottomsheet_tutorial
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Creating the bottom sheet
&lt;/h1&gt;

&lt;p&gt;First, get rid of the initial code that you’re provided by default. We’ll write our own. &lt;/p&gt;

&lt;p&gt;We’ll create a floating action button, and on clicking it, we’ll display a bottom sheet. To create a floating action button in flutter, you’ll need a Scaffold. Scaffold in flutter allows us to use Material Design elements such as AppBar, floating action button, navigation drawer and so on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyApp&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatelessWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;MaterialApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="s"&gt;'Flutter Demo'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;theme:&lt;/span&gt; &lt;span class="n"&gt;ThemeData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;primarySwatch:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;home:&lt;/span&gt; &lt;span class="n"&gt;MyHomePage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="s"&gt;'BottomSheet demo'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyHomePage&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatefulWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;MyHomePage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;key:&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;_MyHomePageState&lt;/span&gt; &lt;span class="n"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_MyHomePageState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;_MyHomePageState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyHomePage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;appBar:&lt;/span&gt; &lt;span class="n"&gt;AppBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;mainAxisAlignment:&lt;/span&gt; &lt;span class="n"&gt;MainAxisAlignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;[&lt;/span&gt;
            &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="s"&gt;'Click the floating action button to show bottom sheet.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;floatingActionButton:&lt;/span&gt; &lt;span class="n"&gt;FloatingActionButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next up, we'll pass a function reference to onPressed of the floating action button. This is the function where we’ll create our bottom sheet in flutter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyApp&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatelessWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;MaterialApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="s"&gt;'Flutter Demo'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;theme:&lt;/span&gt; &lt;span class="n"&gt;ThemeData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;primarySwatch:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;home:&lt;/span&gt; &lt;span class="n"&gt;MyHomePage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="s"&gt;'BottomSheet demo'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyHomePage&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatefulWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;MyHomePage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;key:&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;_MyHomePageState&lt;/span&gt; &lt;span class="n"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_MyHomePageState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;_MyHomePageState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyHomePage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;appBar:&lt;/span&gt; &lt;span class="n"&gt;AppBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;mainAxisAlignment:&lt;/span&gt; &lt;span class="n"&gt;MainAxisAlignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;[&lt;/span&gt;
            &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="s"&gt;'Click the floating action button to show bottom sheet.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;floatingActionButton:&lt;/span&gt; &lt;span class="n"&gt;FloatingActionButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;onPressed:&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;  &lt;span class="n"&gt;displayBottomSheet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now call showModalBottomSheet, this is a method provided by flutter. It takes a context and a builder function. We’ll use an anonymous function as our builder function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/material.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;runApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyApp&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatelessWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;MaterialApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="s"&gt;'Flutter Demo'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;theme:&lt;/span&gt; &lt;span class="n"&gt;ThemeData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;primarySwatch:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;home:&lt;/span&gt; &lt;span class="n"&gt;MyHomePage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="s"&gt;'BottomSheet demo'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyHomePage&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;StatefulWidget&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;MyHomePage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;key:&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;_MyHomePageState&lt;/span&gt; &lt;span class="n"&gt;createState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_MyHomePageState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;_MyHomePageState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyHomePage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;displayBottomSheet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;showModalBottomSheet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;context:&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;builder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;height:&lt;/span&gt; &lt;span class="n"&gt;MediaQuery&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;height&lt;/span&gt;  &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Welcome to AndroidVille!"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="n"&gt;Widget&lt;/span&gt; &lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BuildContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;appBar:&lt;/span&gt; &lt;span class="n"&gt;AppBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="nl"&gt;mainAxisAlignment:&lt;/span&gt; &lt;span class="n"&gt;MainAxisAlignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Widget&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;[&lt;/span&gt;
            &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="s"&gt;'Click the floating action button to show bottom sheet.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
          &lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;floatingActionButton:&lt;/span&gt; &lt;span class="n"&gt;FloatingActionButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;onPressed:&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;  &lt;span class="n"&gt;displayBottomSheet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: I've used MediaQuery to limit the size of bottom sheet to 40% of screen height.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;And it’s done! This is all you need to do to create a bottom sheet in flutter. As I said, this is by far the easiest framework I’ve encountered to create a bottom sheet. &lt;/p&gt;

&lt;p&gt;In the upcoming tutorial, I’ll show you how to create a bottom sheet using Native Android.&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;a href="https://rebrand.ly/73lbl3" rel="noopener noreferrer"&gt;Welcome to AndroidVille&lt;/a&gt; :)
&lt;/h1&gt;

&lt;p&gt;AndroidVille is a community of Mobile Developers where we share knowledge related to Android Development, Flutter Development, React Native Tutorials, Java, Kotlin and much more.&lt;/p&gt;

&lt;p&gt;We have a SLACK workspace where we share updates related to new job opportunities, articles on Mobile Development/updates from the industry. We also have channels to help you with any questions, dev-help that you require. Just post a question and people would be ready to help you out :)&lt;/p&gt;

&lt;p&gt;Click on &lt;a href="https://rebrand.ly/73lbl3" rel="noopener noreferrer"&gt;this&lt;/a&gt; link to join the AndroidVille SLACK workspace. It’s absolutely free!&lt;/p&gt;

&lt;p&gt;If you like any article, do give it a share on Facebook, Linkedin. You can follow me on LinkedIn, Twitter, Quora, and Medium where I answer questions related to Mobile Development, especially Android and Flutter.&lt;/p&gt;

</description>
      <category>bottomsheetinflutter</category>
      <category>flutter</category>
      <category>bottomsheet</category>
      <category>mobiledevelopment</category>
    </item>
    <item>
      <title>Why every Software Engineer should write - At Least once!</title>
      <dc:creator>Ayusch</dc:creator>
      <pubDate>Sat, 11 Apr 2020 07:27:13 +0000</pubDate>
      <link>https://dev.to/ayuschjain/why-every-software-engineer-should-write-at-least-once-2o6e</link>
      <guid>https://dev.to/ayuschjain/why-every-software-engineer-should-write-at-least-once-2o6e</guid>
      <description>&lt;p&gt;I’ve been writing about &lt;a href="https://ayusch.com" rel="noopener noreferrer"&gt;Android Development&lt;/a&gt; for more than 1 year now. There have been a lot of learnings along the way. It opened my mind up to a whole new domain of content generation and content marketing.&lt;/p&gt;

&lt;p&gt;Over time I’ve come to realise that writing about Android has definitely made me a better android developer and a better software engineer overall. So, in this post, I’ll list down all the reasons as to why I believe every software engineer should write - at least once.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Writing Helps you stay updated with the latest in the industry.
&lt;/h2&gt;

&lt;p&gt;No matter whatever you do. Android development, iOS development, javascript, backend, frontend. If you have to write regularly, you’ll need to keep yourselves updated with the latest tech.&lt;/p&gt;

&lt;p&gt;It’s more rewarding to write about a new tech that was just introduced. Partly because there are a very few articles about it and it would help your content rank higher in the search results.&lt;/p&gt;

&lt;p&gt;If you rank higher in search results, more and more people will get to your content and you’ll build credibility as a writer. It’ll enable you to write about topics already covered, but in your own way and be ensured that people are gonna love it.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Greater accountability for what you put out.
&lt;/h2&gt;

&lt;p&gt;Once you start putting out content, you’ll see that people will hold you accountable for even small mistakes. So, you better be sure that you know what you are talking about.&lt;/p&gt;

&lt;p&gt;This accountability pushes you to go that extra mile, go a bit deeper into those concepts which the average Joe would not care about. It also helps you to answer people’s comments/questions better since you know the whys and hows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For example&lt;/strong&gt;, when I wrote this article about ART vs DVM. I had mentioned that a Register Based model is faster and has less code than Stack Based model. &lt;/p&gt;

&lt;p&gt;Now, I could’ve easily copied that from anywhere, there would be many articles about that. But I needed to make sure that I was ready to answer any questions that were thrown on me about that point.&lt;/p&gt;

&lt;p&gt;Hence, I went the extra mile and learnt about CPU instructions in a Register based model and Stack based model. Although I had read about this during grad school, I definitely needed to brush up on that. &lt;/p&gt;

&lt;p&gt;Then I included an example in my post where a simple ADD operation took 3 instructions in stack based model vs 1 instruction in register based model. Even if no one questioned me on that, it was a good feeling to have known about that. It builds your confidence as a writer and an engineer.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Recognition
&lt;/h2&gt;

&lt;p&gt;This is probably the most obvious one. Once you start writing and putting your content out there regularly, you’ll definitely start to grow some followers. People who love your style of writing/explanation.&lt;/p&gt;

&lt;p&gt;If you’ve built a great android library, it’s no good sitting there on github if people don’t get to use it. But first, people will have to know it exists. For this, you’ll need to put out content related to your library.&lt;/p&gt;

&lt;p&gt;Whether it be an article, a tutorial, a demo or even a talk in events such as GDG, ADG etc. Once you gather a following it becomes relatively easier to put out content and get people to use/read it.&lt;/p&gt;

&lt;p&gt;Since, I started writing on Medium in early 2019, I’ve gathered around 650 followers and growing.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. A source for extra income
&lt;/h2&gt;

&lt;p&gt;If you’ve ever tried freelancing on sites such as freelancer.com you’ll know how important is credibility there. As a new freelancer, you’ve got to establish some sort of credibility so that the client can trust you with their projects.&lt;/p&gt;

&lt;p&gt;When I used to do some freelance work, I cannot stress how important my writing came in handy. I mentioned my writing in all the proposals and I got replies regardless of the project being awarded or not.&lt;/p&gt;

&lt;p&gt;Apart from that I’ve gotten some freelance content writing opportunities (in Android Development) as well. &lt;/p&gt;

&lt;p&gt;One of the most brilliant sources in today’s times would be writing articles on Medium. Especially for the Medium Partner Program. You can google it to learn more about how to earn through the Medium Partner Program.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Easier to find new opportunities
&lt;/h2&gt;

&lt;p&gt;You must have noticed that many companies now use online tools such as lever to manage candidates. &lt;/p&gt;

&lt;p&gt;Many a times I’ve seen fields included such as “What sets you apart from other candidates?/ Tell us something interesting”. Often these fields are a good place to boast about your Medium following/writing.&lt;/p&gt;

&lt;p&gt;I don’t know if this helps or not, but I think it is a good way of letting the hiring manager know that you keep your finger at the heart of new developments in your area, while setting you apart from other candidates. &lt;/p&gt;

&lt;p&gt;This might intrigue the hiring manager to speak to you and before you know it, you might’ve got yourselves an interview ;)&lt;/p&gt;

&lt;h2&gt;
  
  
  6. It’s Fun
&lt;/h2&gt;

&lt;p&gt;It’s fun to learn about Content Creation, content generation, SEO, keywords and what not. It’s a separate world altogether.&lt;/p&gt;

&lt;p&gt;It’s interesting to know about your user retention, returning users, new users, CTR and other metrics. This tells you how engaging your content is and pushes you to improve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;These were some reasons I believe that one should definitely try writing about their work at least once. &lt;/p&gt;

&lt;p&gt;If you want to submit an article for AndroidVille, you’re most welcome to do that at: &lt;a href="https://ayusch.com/submit/" rel="noopener noreferrer"&gt;https://ayusch.com/submit/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;or mail a Word document at &lt;a href="mailto:contact@ayusch.com"&gt;contact@ayusch.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Important&lt;/em&gt;: Join the &lt;a href="https://rebrand.ly/73lbl3" rel="noopener noreferrer"&gt;AndroidVille SLACK&lt;/a&gt;  workspace for mobile developers where people share their learnings about everything latest in Tech, especially in Android Development, RxJava, Kotlin, Flutter, and mobile development in general.&lt;/p&gt;

&lt;p&gt;Click on this link to join the workspace. It’s absolutely free!&lt;/p&gt;

&lt;p&gt;Like what you read? Don’t forget to share this post on Facebook, Whatsapp, and LinkedIn.&lt;/p&gt;

&lt;p&gt;You can follow me on LinkedIn, Quora, Twitter, and Instagram where I answer questions related to Mobile Development, especially Android and Flutter.&lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>android</category>
      <category>ios</category>
      <category>mobile</category>
    </item>
  </channel>
</rss>
