Skip to main content

Conference Session

Real-Time Collaboration and the Future of Web Applications

July 14, 2020
Photo of Peta Hoyes

Peta Hoyes

Partner/COO

Photo of Fabian Franz

Fabian Franz

Vice President of Software Engineering

Content teams already collaborate in real time everywhere except the CMS, where editing has stayed single-user for twenty years. That gap forces people to draft in Google Docs and paste into Drupal, losing structure and formatting on the way. Peta Hoyes and Fabian Franz show what it takes to close that gap with Yjs, and why real-time editing at the entity level, not just one text field, is within reach for Drupal today.

Session Description

Collaboration is how most teams actually get work done, yet the content management systems those teams depend on have stayed stubbornly single-user. This session looks at why, and at the open source framework that finally makes shared editing practical inside a CMS.

Peta Hoyes (Partner/COO) opens with the shape of the problem: the spectrum from synchronous to asynchronous collaboration, the presence, change management, and conflict-resolution pieces every real-time application needs, and why building all of that from scratch in each app is not realistic. Fabian Franz (Vice President of Software Engineering) takes the second half into the technical detail, explaining conflict-free replicated data types, walking through how Tag1 integrated Yjs with Drupal using ProseMirror, and covering revisions, access control, comments, and infrastructure. Both share live demos, including a peer-to-peer prototype in WordPress Gutenberg.

What You Will Learn

  • Where applications sit on the synchronous to asynchronous collaboration spectrum, and what each type needs
  • Why presence, change management, and the right underlying algorithms are the foundation of real-time editing
  • What conflict-free replicated data types are, and why "good enough" conflict resolution is genuinely good enough
  • How Tag1 integrated Yjs with Drupal using ProseMirror, and mapped collaborative history onto Drupal revisions
  • How comments, access control, and offline-first sync were designed around the Yjs document
  • What peer-to-peer infrastructure would take, and what a fully collaborative Drupal could look like

Transcript

[00:00:06] Welcome to our talk on real-time collaboration and the future of web applications. I'm Peta Hoyes, Chief Operating Officer and partner at Tag1 Consulting. I'm responsible for day-to-day operations, including projects, clients, and the team. I'm a mechanical engineer by degree, but for the last thirty years I've been bringing the internet in all its glory, sometimes not so much, to the masses. I'm really passionate about open source technology, and this is my very first Drupal talk, so I'm excited to be here.

[00:00:57] I'm joined by Fabian, my partner in crime, the VP of software engineering at Tag1. Most of you already know him, so I won't give a long introduction, but among many things he's the Drupal 7 core committer and framework manager and the co-creator of Big Pipe and the new caching system in Drupal 8 and 9. For those who aren't familiar with Tag1, we're known for being the number two all-time contributor to Drupal. We're Platinum sponsors of DrupalCon, a supporting partner of the Drupal Association, and we donate a lot of resources to help run the Drupal.org websites and infrastructure. If you make money or profit from Drupal, in whole or in part, I ask that you contribute to the project financially if you can.

[00:02:13] Fabian works with lots of technologies outside Drupal, like Laravel and Symfony, and we'll touch on our work in WordPress and the Gutenberg editor, as well as Yjs, a real-time collaboration framework. This talk is in two parts. I'll give a quick overview, and Fabian will do the more technical second half. We'll touch on the types and degrees of collaboration, the core features required to make good multi-user applications, some specific features in a content management context, how we integrate shared editing in Drupal and WordPress, and the challenges of shifting from a single-user to a multi-user model. Please put questions in the chat with a "Q:" so we can spot them, and we'll have a quick Q&A at the end.

[00:04:06] I'm excited for the demos, to finally show off all this work we've been doing and give you some of the technical insights, including where we banged our heads. So great to do this talk together.

[00:04:38] Let's take a quick step back. We're going to look at the different ways people collaborate online, not just the tools but how they work. Collaboration is fundamental to how we all work, learn, and teach. We've had wave after wave of technological advancement, from snail mail to phones and faxes, email, instant messaging, and mobile. These technologies are integral to how we get things done, and it's hard to imagine how we ever did anything before them. Collaborative applications reduce the cost of communicating, make it easier and faster to get things done, and increase our productivity.

[00:06:00] Collaborative applications are critical to a traditional workforce and to companies that engage with vendors or customers, but for remote workers, like at Tag1 and many others with distributed teams, we couldn't do what we do without them. Before the pandemic, eighteen percent of global workers were fully remote, and fifty-two percent worked at least one day a week remotely. Now far more people are working from home, and it's essential that organizations adopt applications that enable collaboration and let users work remotely.

[00:07:26] Collaboration applications range across a broad spectrum, from synchronous to asynchronous. On the synchronous end you have real-time communication; on the other, more intermittent communication; and in the middle, something near real time. Zoom is very synchronous: to meaningfully participate you want to be in the conversation in real time. Slack is in the middle, near real time; we interact back and forth, but you can't see what I'm typing until I send it, and we can come and go and respond asynchronously. On the far end are knowledge-sharing tools like Confluence and Jira, where we create and access information almost exclusively asynchronously. A great collaboration tool has to support the appropriate level of interaction throughout the whole workflow.

[00:10:06] Drupal, WordPress, Confluence, and Jira are all popular knowledge-sharing and team-collaboration tools that have been around for twenty years. They're great tools that have stood the test of time, but the big question is why, to date, they have been almost exclusively asynchronous. Google Docs came out ten years ago; these aren't new concepts. If collaboration is fundamental to how we work, why isn't it part of how we work in all of these applications? Let's talk about how we make that happen.

[00:11:01] Content editing in a CMS has always lagged behind the needs of its users. Back in the day we wrote content in Word and pasted it into a CMS, which caused all sorts of markup problems, so we built great editors like CKEditor, the default in Drupal. Nowadays people use Google Docs or similar tools to collaborate and then paste into the CMS, but that has the same formatting problems Word had fifteen years ago. Using other tools isn't bad; a CMS can't do everything. But content creation is a core component of any CMS, and no CMS on the market works the way our teams do, collaboratively. So let's talk about changing the status quo.

[00:12:25] There are a few things we need for efficient collaboration, and it's both a human and a computer problem. It requires new UI and UX constructs as well as computer algorithms. The first core component is presence and awareness: information that indicates each user's current availability and status in real or near real time. In Slack I can see if you're online or have notifications snoozed. Zoom has a high degree of presence: I can see and hear you and pick up your tone, intonation, and facial expressions. Google Docs has good presence too; I can see who's in my document, whether they're active or passive, and work around them.

[00:14:17] With tools like Jira and Trello, on the other end, I can't see what you're doing until you've done it and submitted. If two of us edit a description field in a Jira ticket, the first person to get the lock can save it, and the second person's changes won't be saved, without even an error message. That lack of presence awareness causes friction: you can lose data and end up duplicating work. Another big component is change management: we need editorial workflow to support a collaborative content creation process. Without those features, distributed content can't work well.

[00:15:43] The third component is computer algorithms. One reason applications don't have synchronous real-time collaboration is that the underlying technology is very complicated and difficult, which makes it costly and time-consuming to put in every application. Think about several people typing in a document: presence awareness helps avoid conflict, but you also need underlying algorithms so that people making changes at the same time don't produce a complete mess. Imagine a laggy connection or working offline; how do you track what everyone is doing? Two of the most popular and effective algorithms are CRDT and OT, conflict-free replicated data types and operational transformation.

[00:17:02] Another factor is orchestration. Collaborative content creation requires peers to talk to each other in real time, either client-server or peer-to-peer. Either way, tools like PHP aren't ideal for this type of work. Why would we build all of these requirements into each application when we could create a framework for it? To solve these challenges, we turned to Yjs, a real-time collaboration framework.

[00:18:01] We've been working on a project for a top-ten Fortune 500 company where collaborative content creation was a critical feature. We did a lot of research and identified Yjs as the best solution. It's open source under the MIT license, which was a must-have for the client and important to us. It's a framework for making any application collaborative as long as it has structured data. Content creation was the short-term goal, but whiteboarding, diagramming, layout building, and theming are all planned to be collaborative. Yjs provided much of what we needed, and its creator, Kevin Jahns, was willing to partner with Tag1. Working together, we built out the framework and integrated it with Drupal using ProseMirror as our editor. Yjs, ProseMirror, and Drupal are all open source, and our Yjs enhancements are open source too; the Drupal integration is not yet, but we can demo it.

[00:20:02] Yjs is a powerful open source real-time shared-editing framework that enables developers to easily add collaborative capabilities to any type of application. The framework provides a robust and mature set of features enabling content creators to coordinate efforts and work effectively in real time. You can leverage the existing functionality and user experience or create your own custom capabilities. Yjs lets you see who is working with you on a document, with support for usernames, profile pictures, and other information, and shows which users are actively working and who is passive. Each user is represented with a different color, and shared cursors show where other users are and any text they have highlighted.

[00:20:51] All changes are shown in real time, with updates immediately propagated and no delays. Snapshots or version histories can be saved manually by users or automatically at defined intervals. You can view the differences between versions, see which users made changes, and revert to any version. You choose how you implement each feature; in this example, users can only undo or redo the content they individually created, without affecting simultaneous edits by others. Users can highlight any content and leave a comment for others, and reply to or remove comments. Yjs is highly tuned for shared editing of rich text, with plugins for many editors including ProseMirror, CodeMirror, Ace, Quill, Monaco, and Gutenberg, and you can create your own plugins. Free support is available for open source development via the Yjs community forums, and commercial support and consulting are also available.

[00:22:44] So how does this all work? Peta talked about CRDTs. What is a CRDT? It's a conflict-free replicated data type. Let's do a small example. Text editors basically insert an H at position 15, then the next character at position 16, and so on. That's roughly what OT does, tracking positions. CRDTs instead give each character a stable identity. Here's an analogy: in New York, would you rather have the instructions "go three blocks left, then two blocks up, then four blocks right," with no navigation to update them, or just the address, 271 Bleecker Street? An address never changes, but a position does, like turn-by-turn navigation that recalculates when there's construction. OT is like the navigation that always changes; with a CRDT you always know where everything is, because each character has a perfect address.

[00:24:36] I prefer this object-based approach because it's much simpler to understand. So what does Yjs give us? It gives us CRDTs on common data types. The to-do list is the most common example in the front-end world, the new hello world. You store the data in a JavaScript array, and if the array changes, the to-do list changes. The magic part: you put that in a Y array, connect it to a server, and it's automatically collaborative and real time. When I first realized what this means, it felt like magic. This ease of integration is, for me, the future of collaborative web applications.

[00:26:36] Rich text is more complex than plain text: once you say this is bold or italic, it gets harder. So we partnered with Kevin Jahns, the author of Yjs, to bring Yjs to Drupal, and for me an exciting journey began, learning about collaborative text editing, OT, and CRDTs. There have been challenges. One important one is personal undo and redo: if I'm working with Peta on a document, I don't want to undo her changes, just mine. Here's a future idea for anyone who wants to get inspired: a moderator could take over and undo a person's changes on their behalf. In theory CRDTs let you do that, but no one has done it yet.

[00:27:56] The real challenge with undo is that you need to undo all the things. You create a table, then undo the table, but in the meantime someone has written text into it, so what happens? You have several options; one is to say you can't undo the table creation until the other person undoes their change. But here's a huge thing I learned: perfect conflict resolution is not needed. Google Docs supports personal undo, and yet it does not have perfect conflict resolution. Good enough is actually enough. I was shocked that the leader in collaborative documents has pretty bad conflict resolution in the nitty-gritty.

[00:28:57] Everyone was thinking we needed to be perfect, resolving all conflicts and handling every edge case. You don't. Google Docs doesn't. I did test cases: I pasted a large Wikipedia document seven times and undid it several times, and Google Docs really chokes, taking seven seconds or more. Then there was CP by Salesforce, used by a client, which completely freezes; you can crash the web application. And Yjs, using ProseMirror, was happily snappy: you can undo and redo as many times as you want and paste huge documents. That was the moment Kevin sold me on the technology, while we were still evaluating.

[00:30:27] Another test case: break a paragraph and make it a list at the same time, or indent something and then create a list out of it. If you have some fun with Google Docs offline mode, on a computer and a phone in flight mode, you can get into a state where your indentation markers end up outside the actual content, and undoing several times gets it completely confused. If it's good enough for Google Docs to be imperfect, it's good enough for us. The reason we don't need perfect conflict resolution is that awareness solves most conflict problems: users are careful not to step on each other's toes because they can see who's editing what in real time.

[00:32:02] What about offline mode? Yjs can easily do it. You work on a document for a whole flight, get back on the internet, and it happily syncs, because Yjs is offline-first. You could shelter somewhere for a year, come back, connect to the server, and it would still sync. Or if the internet cable between the Americas and Europe were cut, two teams could keep working and then merge both versions back together. There is a wrinkle: automatic conflict resolution is tricky. It can be perfectly correct mathematically and yet make no sense to a human reading it. The future here is tools that not only track changes since you last saved but let you selectively apply them where you want.

[00:33:20] This sounds a lot like Git, but CRDTs are more advanced. ProseMirror internally has a Git-like collaboration mode, which we talk about more in our webinars and podcasts, but that mode doesn't have offline capability because it's a reconciliation approach rather than a scientifically sound one like CRDTs. The foundation for track changes is there; you saw it in the demo. But more work on it would need sponsors for the Yjs project.

[00:34:09] Now to what's probably most interesting to you: implementing this collaboration in Drupal, with editors, workflows, revisions, and more. First we need an editor. Fortunately, with Yjs we didn't need to reinvent the wheel, because Yjs supports so many. If your web application already uses ProseMirror or Quill, you can just hook up Yjs and it will work. There are many examples on the Yjs site. Under the hood, it uses its own Y XML fragment; when changes come over the network, it compares, similar to a virtual DOM, and selectively applies the changes. So it's basically two-way synchronization.

[00:35:19] We went on a journey to integrate a first modern editor into Drupal. Drupal's editor works with arbitrary HTML: it's fed HTML and stores HTML. Modern editors define a schema and are fed JSON and store JSON. There are two ways to solve this. One is JavaScript-based: run everything client-side and use Node for server-side rendering and search indexing, which is a perfect fit for decoupled applications. I wanted a more traditional approach, so we render the editor content to a hidden text area. The text area contains JSON that includes an HTML key, so the rendered HTML is there like from the legacy editors. That made it simple: we create a field formatter that returns the HTML part of the JSON, load the JSON part into the editor, and export both back to the text area, communicating through the same text area as usual. Search API then works out of the box.

[00:36:35] What about full HTML? Modern editors have problems with it, so what do we do? You just don't use it, because a schema clashes with full HTML support. If you do use it, use it sparingly, because giving editors full HTML decreases accessibility a lot; we found that when auditing a huge document library for a client. Instead, create rich widgets for the editor so editors can fill them with the data they need and integrate videos from a third party without dealing with inline scripts. For legacy documents, the best approach I found was a catch-all block type that displays raw HTML as unformatted code, even with syntax highlighting if you integrate with CodeMirror.

[00:37:50] The biggest challenge was not technical but philosophical: how do many users work in a system designed for a single user? We need to integrate revisions, content workflow, and track changes into one workflow, and figure out who owns these documents. A fun fact: Wikipedia could have had simple text-based collaboration years ago, but philosophical challenges, not technical ones, have prevented it. They had a prototype, but they got stuck on questions like what happens with the draft. It's still an unsolved problem there today.

[00:38:47] We designed one technical solution, not necessarily the best one. Yjs has a full history built into its Y document, so all the track changes are in one binary document, and we can access every state by state vector. Whenever someone publishes a new revision in Drupal, we store not only the HTML and JSON but also the state vector, giving a one-to-one mapping between the Yjs state and the Drupal state. In my experience I found nothing like this when searching in those systems: we're able to support traditional Drupal revisions together with the collaborative model, which was very key. Then we frequently save the large Yjs document to persistent storage.

[00:39:58] Revisions are mapped, and a revision might have multiple authors, though one person publishes it. Saving and publishing is still an explicit operation. Unlike Google Docs, where a change is immediately live, we still have a publishing step: now I'm publishing this content and it's live, or now it's a new draft going through workflow. What about several drafts of content, like Git branches? In theory Yjs can match those since it's offline-first, but no one has tried yet, and garbage collection is an open problem. It's really an organizational decision about how to archive and prune, because some organizations need to keep everything for ten years and others can prune after months.

[00:40:52] More challenges: authentication and access control. How do you keep documents safe? We designed the simplest way: an access token that's per entity and per user. You have a secret hash per document, combined with a timestamp, and several tokens available at once. That hash is how you address the document; if you have it you have access, and if you don't, you don't. Future work here includes viewer-only and comment-only access, which needs different hashes and ways to authenticate editors versus viewers, and it's more complex with peer-to-peer.

[00:41:52] How do you implement comments? It's pretty simple once you've wrapped your head around it. You store comments not within the document, because that makes good access control impossible, but as a selection on a portion of text, out of band. Think of it like construction work from 781 to 795 Fifth Avenue: any New Yorker knows the address. The actual comment is stored as a normal comment in Drupal, and the selection only contains a reference to it. That was the simplest and most effective way to store comments.

[00:42:42] How does infrastructure look? There are two ways. One is the enterprise way: Node.js with a Redis backend and a persistent store like a MySQL database, or a key-value store like MongoDB. That's used for our enterprise client. The other is a signaling server with WebRTC peer-to-peer communication, so there are no Node instances to add to your stack. That's the solution being developed for WordPress. Right now WordPress is ahead in the race, so if anyone wants to bring Drupal up to par, start a core initiative and contact us. The WordPress demo already looks impressive, so let's take a look.

[00:43:40] What you're seeing is the online demo, a proof-of-concept of Yjs integrated with Gutenberg in WordPress. We have two authors collaborating peer-to-peer, and each user sees the other's content in real time. Actually with Yjs, if you don't hook it up to a server and just open two browser windows, it just works. The proof-of-concept showed that Yjs makes it really simple: images work, blocks work, and you can see text edited in real time. There's not yet presence and awareness in this first prototype, but it has come along since then.

[00:44:42] The Gutenberg prototype was finished in less than twenty-four hours; Kevin did the integration in less than a day, which is a real achievement. And the ProseMirror integration of Yjs is pretty easy. There's an even better implementation now by a former Automattic employee that added comments, an authors user list, and shared cursors. WordPress has collaboration on its road map, so Drupal needs to be careful, because it's a first-class citizen there. WordPress's goal is to enable every instance, from the tiniest shared hosting to the largest enterprise, to have real-time shared editing without installing any additional software.

[00:45:52] There are two components: integrating Gutenberg with Yjs, and setting up peer-to-peer backend infrastructure. Without going into the details, peer-to-peer is very hard. You need a signaling server just to find other users, a long poll or Ajax request, plus STUN and TURN to punch holes through firewalls, and WebRTC to bring it together. Many commercial voice-over-IP systems like Zoom still rely on relay servers. These are hard problems, but we'll hopefully be working on them.

[00:46:33] The possibilities are endless. In the future, we think every application will offer collaboration, with the classic cycle of rapid adoption leading to more effective collaboration and more adoption. In a CMS that means shared editing, layout building, whiteboarding, and more. In Drupal specifically, imagine a real-time layout builder, real-time text editing, and real-time admin notifications: Peta has published this blog post, and you can see who else is online. The whole Drupal instance could be a hub of collaboration. So far the options in Drupal have been limited: a commercial, costly option, and Node channel support since Drupal 7, which we've implemented but is complicated. With stable peer-to-peer support and a signaling server, we could have all of this, fully combinable with the new admin experience everyone is working on. Let's make the future of web applications happen; it has already started.

[00:48:24] (Question from the audience.) One question was about semantically rich content: are you suggesting we put all the semantics in the body? No. I'm talking about a fully collaborative node form, where paragraphs and structured content are collaborative, so you're not only seeing one text editor but all the fields are editors, still with the same structured content as before. And on whether real-time collaboration should be at the entity level, not the HTML block: yes, definitely.

[00:49:06] (Question from the audience.) How would a peer-to-peer connection be facilitated at the network level, since someone needs an open port? First you need to find people, so your Drupal side needs a "who's online" feature, and then it's a long poll or Ajax polling that says these are the IPs that are online, and they start finding each other via various mechanisms. On CKEditor 5 working with Yjs: no, it has its own commercial support for that. On whether this works across field types: right now it's mostly focused on text areas, but to integrate it with structured content we need to make it work on structured things.

[00:51:02] (Question from the audience.) How do you handle revisions for the whole entity when Yjs handles only one field? With structured content, we need all the fields in the Yjs document, so from Drupal it's several fields, but from the Yjs perspective it's still one document and one entity. It's still a tree structure, just several text editors at once. On whether this could work with a Gutenberg-for-Drupal contrib model: it probably could. We haven't tried it, but someone could take the Gutenberg proof-of-concept and put it into the Drupal version of the module and see if it works.

[00:52:24] I think we covered all the questions. Thank you very much, and sorry for going a little over. Hope you had fun, and have a great con. Thanks, everyone.

Event Details

Conference
DrupalCon Global
Date
July 14, 2020
Location
Virtual
Skill Level
Intermediate

Work With Tag1

Be in Capable Digital Hands

Gain confidence and clarity with expert guidance that turns complex technical decisions into clear, informed choices—without the uncertainty.