<?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>Forem: Jawad Rizvi</title>
    <description>The latest articles on Forem by Jawad Rizvi (@sjriz).</description>
    <link>https://forem.com/sjriz</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%2F3633607%2Fa6a3daa1-980d-4cab-848b-e9087072dff7.jpeg</url>
      <title>Forem: Jawad Rizvi</title>
      <link>https://forem.com/sjriz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sjriz"/>
    <language>en</language>
    <item>
      <title>How I Built a Real-Time, Google Docs-like browser IDE for Python (and it's free!)</title>
      <dc:creator>Jawad Rizvi</dc:creator>
      <pubDate>Fri, 28 Nov 2025 00:37:58 +0000</pubDate>
      <link>https://forem.com/sjriz/how-i-built-a-real-time-google-docs-like-browser-ide-for-python-4mj2</link>
      <guid>https://forem.com/sjriz/how-i-built-a-real-time-google-docs-like-browser-ide-for-python-4mj2</guid>
      <description>&lt;p&gt;For the past months, I’ve been building &lt;a href="https://pytogether.org" rel="noopener noreferrer"&gt;PyTogether&lt;/a&gt;, an open-sourced, real-time collaborative Python IDE designed specifically for students, education and pair programming purposes.&lt;/p&gt;

&lt;p&gt;While tools like Replit and VS Code Live Share exist, they often come with significant bloat-paywalls, complex environments, and AI copilots that can actually hinder the learning process for beginners. As a second-year engineering student myself, I wanted to build the opposite: a lightweight, communication-first environment where the code is the focus.&lt;/p&gt;

&lt;p&gt;The result is a fully free, browser-based IDE with real-time selections, voice/live chat, and shared drawing tools. It currently supports over 500 users.&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%2F7f70gc6wnpfk5uebg0t4.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%2F7f70gc6wnpfk5uebg0t4.png" alt="Collab demo" width="800" height="449"&gt;&lt;/a&gt;&lt;br&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%2F6hknj247xdjdj67aewme.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%2F6hknj247xdjdj67aewme.png" alt="Matplotlib Demo" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a deep dive into the architecture, the tech stack, and the specific engineering hurdles I faced building a "Google Docs for Python."&lt;/p&gt;

&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;

&lt;p&gt;At a high level, the app needs to handle two distinct heavy-lifting tasks: synchronising state between multiple users in real-time, and executing Python code safely without crashing the browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Stack:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; React, TailwindCSS, CodeMirror (Linting), Y.js (CRDTs).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution:&lt;/strong&gt; Pyodide (WASM) running in Web Workers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; Django (Django Channels), PostgreSQL, Redis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure:&lt;/strong&gt; Docker, Nginx, VPS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Challenge 1: Running Python in the Browser (Safely)&lt;/strong&gt;&lt;br&gt;
The most significant technical challenge was execution. I didn't want to run user code on my backend (which introduces massive security risks and server costs). instead, I chose Pyodide, a port of CPython to WebAssembly (WASM). This allows the Python code to run entirely client-side.&lt;/p&gt;

&lt;p&gt;However, a major hurdle appeared immediately: &lt;em&gt;Blocking I/O.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Python’s &lt;code&gt;input()&lt;/code&gt; function is blocking. If you run this on the main browser thread, the entire UI freezes while waiting for user input. This is a major deal-breaker for beginners who love using &lt;code&gt;input()&lt;/code&gt;. To solve this, I had to run the Pyodide instance inside a Web Worker.&lt;/p&gt;

&lt;p&gt;I utilized &lt;code&gt;pyodide-worker-runner&lt;/code&gt; to manage the communication between the React frontend and the worker. This allows the main thread to remain responsive (handling UI updates and real-time syncing) while the worker handles synchronous Python execution, including support for running complex libraries like NumPy and Matplotlib (I had to edit some Matplotlib functions directly in a wrapper to output in the console properly). It also auto-installs any detected imported libraries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Challenge 2: Real-Time Collaboration &amp;amp; State&lt;/strong&gt;&lt;br&gt;
For the "Google Docs" feel, I needed to handle race conditions. If User A types a character while User B deletes a line, how do we resolve the conflict?&lt;/p&gt;

&lt;p&gt;I used Y.js, a library for Conflict-free Replicated Data Types (CRDTs). Y.js handles the complex merging logic, ensuring that all users eventually see the exact same document state regardless of network latency or packet order.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Challenge 3: The "Save" Problem (Redis + Celery)&lt;/strong&gt;&lt;br&gt;
Designing an efficient autosave system was the toughest backend challenge (excluding the Y logic).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Naive Approach:&lt;/strong&gt; Save to PostgreSQL on every keystroke.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Problem:&lt;/strong&gt; This would hammer the database with thousands of write operations per minute for a single active group.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The Solution:&lt;/strong&gt; A Redis Buffer. I implemented a "write-behind" caching strategy.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Ingest:&lt;/strong&gt; Real-time changes are pushed to a Redis layer (which also handles the Django Channels layers for WebSockets).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Buffer:&lt;/strong&gt; Active projects are tracked in memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persist:&lt;/strong&gt; A Celery worker loops through active projects every minute to persist the changes from Redis to PostgreSQL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cleanup:&lt;/strong&gt; When all users leave a project, the state is flushed to the DB and cleared from the cache.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This turns thousands of potential DB writes into a single bulk update.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment &amp;amp; Infrastructure
&lt;/h2&gt;

&lt;p&gt;I decided to avoid managed services like Heroku or Vercel for the backend to keep costs low and learn the "ops" side of DevOps.&lt;/p&gt;

&lt;p&gt;The entire backend is Dockerized and deployed on a roughly $7/mo VPS. This required manually configuring Nginx as a reverse proxy, setting up Certbot for SSL, and managing the Docker containers (I made 2 separate docker-compose files; one for development and one for production). I also set up a CI/CD pipeline using GitHub Actions to automate deployment.&lt;/p&gt;

&lt;p&gt;It was a frustrating 8 hours of wrangling configurations, but it gave me total control over the environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;The project is open source and open to contributors. I'm currently working on an offline "playground" feature (which won't require logging in), and also read-only and edit share links per project (currently, in order to collaborate, you must join a group via a keycode).&lt;/p&gt;

&lt;p&gt;If you are a tutor, teacher, student, or just want to code with a friend, give it a try.&lt;/p&gt;

&lt;p&gt;Live Site: &lt;a href="https://pytogether.org" rel="noopener noreferrer"&gt;pytogether.org&lt;/a&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/SJRiz/pytogether" rel="noopener noreferrer"&gt;github.com/SJRiz/pytogether&lt;/a&gt;&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%2Fovc3hat8v0rs72e0xm39.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%2Fovc3hat8v0rs72e0xm39.png" alt="About Page" width="800" height="569"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>architecture</category>
      <category>python</category>
    </item>
  </channel>
</rss>
