惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The Cloudflare Blog
Microsoft Security Blog
Microsoft Security Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
L
LangChain Blog
W
WeLiveSecurity
P
Proofpoint News Feed
月光博客
月光博客
NISL@THU
NISL@THU
L
LINUX DO - 最新话题
Webroot Blog
Webroot Blog
T
Threatpost
Y
Y Combinator Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
T
Threat Research - Cisco Blogs
Vercel News
Vercel News
Jina AI
Jina AI
阮一峰的网络日志
阮一峰的网络日志
S
Schneier on Security
J
Java Code Geeks
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
小众软件
小众软件
MyScale Blog
MyScale Blog
N
News and Events Feed by Topic
Stack Overflow Blog
Stack Overflow Blog
有赞技术团队
有赞技术团队
The Hacker News
The Hacker News
Schneier on Security
Schneier on Security
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Help Net Security
Help Net Security
Recent Announcements
Recent Announcements
S
Security @ Cisco Blogs
C
CXSECURITY Database RSS Feed - CXSecurity.com
S
Securelist
T
The Exploit Database - CXSecurity.com
云风的 BLOG
云风的 BLOG
C
Cisco Blogs
雷峰网
雷峰网
量子位
Google DeepMind News
Google DeepMind News
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Spread Privacy
Spread Privacy
L
Lohrmann on Cybersecurity
I
Intezer
T
The Blog of Author Tim Ferriss
G
GRAHAM CLULEY
D
DataBreaches.Net
V
Vulnerabilities – Threatpost
P
Privacy & Cybersecurity Law Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
罗磊的独立博客

Dropbox Tech Blog

How we used DSPy to turn AI evaluations into better responses in Dash chat How Dropbox uses MCP and Dash to close the design-to-code security gap Beyond code generation: rethinking engineering productivity in the age of AI agents Introducing Nova, our internal platform for coding agents Improving storage efficiency in Magic Pocket, our immutable blob store Reducing our monorepo size to improve developer velocity How we optimized Dash's relevance judge with DSPy Using LLMs to amplify human labeling and improve Dash search relevance How low-bit inference enables efficient AI Insights from our executive roundtable on AI and engineering productivity Engineering VP Josh Clemm on how we use knowledge graphs, MCP, and DSPy in Dash Inside the feature store powering real-time AI in Dropbox Dash Building the future: highlights from Dropbox’s 2025 summer intern class Fighting the forces of clock skew when syncing password payloads Introducing Focus, a new open source Gradle plugin Making camera uploads for Android faster and more reliable How Dropbox Replay keeps everyone in sync Why we built a custom Rust library for Capture Detecting memory leaks in Android applications How we sped up Dropbox Android app startup by 30% Why we chose Apache Superset as our data exploration platform Revamping the Android testing pipeline at Dropbox Our counterintuitive fix for Android path normalization JQuery to React: How we rewrote the HelloSign Editor How we ensure credible analytics on Dropbox mobile apps Engineering Dropbox Transfer: Making simple even simpler Speeding up a Git monorepo at Dropbox with <200 lines of code Building for reliability at HelloSign Store grand re-opening: loading Android data with coroutines Modernizing our Android build system: Part I, the planning Modernizing our Android build system: Part II, the execution Our journey to type checking 4 million lines of Python The (not so) hidden cost of sharing code between iOS and Android Redux with Code-Splitting and Type Checking The Programmer Mindset: Main Debug Loop On working with designers Incrementally migrating over one million lines of code from Python 2 to Python 3 Crash reporting in desktop Python applications What we learned at our first JS Guild Summit How we rolled out one of the largest Python 3 migrations ever Creating a culture of accessibility Adding IPv6 connectivity support to the Dropbox desktop client Accelerating Iteration Velocity on Dropbox’s Desktop Client, Part 2 Accelerating Iteration Velocity on Dropbox’s Desktop Client, Part 1 DropboxMacUpdate: Making automatic updates on macOS safer and more reliable Annotations on Document Previews Open Sourcing Pytest Tools Open Sourcing Zulip – a Dropbox Hack Week Project Building Carousel, Part III: Drawing Images on Screen The Tech Behind Dropbox’s New User Experience on Mobile (Part 2) Building Dropbox’s New User Experience for Mobile, Part 1 Building Carousel, Part II: Speeding Up the Data Model Building Carousel, Part I: How we made our networked mobile app feel fast and local Scaling MongoDB at Mailbox Welcome Guido! Dropbox dives into CoffeeScript Some love for JavaScript applications Plop: Low-overhead profiling for Python Using the Dropbox API from Haskell A Python Optimization Anecdote Translating Dropbox
Dropbox Paper: Emojis and Exformation
Mime Cuvalo · 2017-11-16 · via Dropbox Tech Blog

Exformation vs. Information

Communication is hard 😖 (it’s ok, little buddy, we’re gonna talk about some tools to combat this). When it comes to conveying a message with other human beings you have to make sure to speak clearly, listen well, use unambiguous words, remember what the other person said, understand the context surrounding the conversation, read between the lines sometimes, pay attention to body language and intonation, comprehend cross-cultural differences, and so many more subtle intricacies. Now compound that problem with trying to communicate with someone over a digital medium. You have to do double the work in conveying and listening — you lose things like the benefit of body language, and intonation of voice. Was the other person angry when they told me “Ok”? Oh, I see that they added a period to “Ok.” — that definitely means that they’re angry! Does it?? If there was only some way that they could tell me how they felt… 🤔 (hmmmm)

If information is the stuff we’re trying to convey, then exformation is the stuff that accidentally gets left out along the way — it’s the details you have to fill in as a listener to try to understand what the other person meant to say 🙊 (monkey says: “you figure out what I’m trying to say”). Ze Frank does a great (and hilarious) job of explaining this:

So this is where emojis come in. Say what now? Oh yes, I totally mean it — emojis can help fill in the gaps in human communication where voice and facial expressions are missing. There’s still no substitute for true face-to-face or even just phone time but if you’re gonna be communicating over email, chat or

Dropbox Paper (ahem) you might as well give in and join the emoji revolution 😄 (blissfully excited, like, omg).

Let’s get this 🎉 (party) started

Four years ago when I joined the Paper team one of my (cupcake) things I did in my spare time was to add support for emojis to the editing surface. Try typing : in a Paper doc and you’ll see! I didn’t want our product to miss out on this sweeping new, disrupting technology 😜 (sarcasm / feeling chuffed with my cleverness). The problem was that back then browsers didn’t support emojis. You’d get this amazing little rectangle box instead:

Literally, fill in the blank on what you think it should mean.

To work around this we made the backing text in your Paper doc be something like :sunglasses:. Then, using Paper’s multi-layered rendering system, we rendered that text on-the-fly in the browser (much like how we auto-link url’s, hashtags, and do code highlighting) into something more interesting like 😎 (captures the feeling of awesomeness). Since the browser couldn’t render the emoji character natively, we would just insert a tag with a background-image corresponding to what the emoji would be.

That system worked well for a while but it did have its limitations. If you started to delete the emoji, what seemed like a single character would revert to something like :tada: and then you’d have to delete all of those backing characters. Plus, if you tried to copy that text out of Paper and paste it somewhere else you’d get :tada: which is pretty 😐 (meh). So, we got together in our “💩.txt” conference room (not making that up, btw) and decided to use our migration system to convert all existing docs to use the actual native character. We still would have to use the fallback images to render the emojis but at least the backing text would be something that would be ready for the native support that was being rapidly added to browsers. It also solved the problem of copying text out of Paper so that it would it be represented by the characters you intended.

Migrating Paper docs and MySQL ➡️ (forward progress)

Paper has a system to mass-migrate documents from one format to another. Because we continually make changes to our document format over the years, we have this system to allow us to make otherwise not-backwards-compatible changes with older documents. Paper documents use something we call a changeset to transform a doc from one state to another one. Our migration system simply acts as a robot that adds a changeset transforming the underlying structure of our doc into the latest format we want. In our case, we had to convert text that matched our legacy :levitating_business_man: or :nerd_face: to be 🕴️ and 🤓 characters (some of my favorite emojis). Seems straightforward enough until you remember the axiom that nothing is ever as simple as it seems.

Paper uses MySQL for its databases and it turns out that the default character encoding for MySQL is utf8. That sounds great — I mean, jeez, at least it isn’t latin1 anymore, right? Yeah, it’s great until you realize that utf8 in MySQL world doesn’t include emojis 😑 (wat). That’s right, if you want to store emojis in your database you’ll need to be using the newer utf8mb4 or otherwise you’ll have madness! (😺 and 🐶 living together, mass hysteria, you get the idea). Because of this, what should have been a simple document migration that can run in the background, required actually putting Paper into maintenance and read-only mode so that we could successfully migrate our databases over the course of a couple hours. 😤 (no, that emoji isn’t conveying anger, that’s triumph!)

Great, with that hurdle aside, another challenge in converting our characters to be a ‘single character’ was that emojis don’t consist necessarily of one single character! For example, take the Spock “live long and prosper” emoji and combine it with the Fitzpatrick skin tone emoji scale:

🖖 + 🏿 == 🖖🏿

What looks rendered as one character (🖖🏿) is actually two characters (🖖 + 🏿) behind the scenes!
Here’s another example where eight(!) separate characters get combined to end up as a single character of two people kissing:

👩 + U+200D + ❤ + U+FE0F + U+200D + 💋 + U+200D + 👩 == 👩‍❤️‍💋‍👩

It goes even further! Let’s take the example of the Spock emoji. Even just the original character (🖖 without an additional skin tone modifier) is actually two characters behind the scenes. In JavaScript:

"🖖".length = 2 // !!!
"🖖".charCodeAt(0).toString(16) == "d83d"
"🖖".charCodeAt(1).toString(16) == "dd96"

Regular expressions will start to fail in interesting ways as well:

/foo.bar/.test('foo🖖bar') == false

This difference in the apparent rendered length of characters vs. the actual character length behind-the-scenes would have messed a lot with Paper’s logic, since Paper is entirely Typescript on the frontend and backend. Syncing multiple characters in Paper of course works as you would expect. However, if we were applying a changeset to a document, say, to remove four characters from the beginning of “foo🖖bar”, we have to be careful where that 4th character starts and ends. The intent is to remove the 🖖 character entirely. However, without an understanding of how long emojis actually are it would have deleted only half of the emoji (e.g. the "d83d" part of the Spock emoji) leaving us with a � character and effectively corrupting the text. So, with a lot of work put in by Travis Hance, one of our expert Paper engineers, we were able to detect the start and end of an emoji so that we could treat it as a single character even though it was really far from being a single character at all. For a more in-depth and fantastic write-up about this problem, please check out Mathias Bynens’ article “ JavaScript has a Unicode problem”.

Design Challenges 💪 (but, we got this)

The next big shift was that emojis took off! Newer versions of emojis were being added all the time by the Unicode Consortium and when multiplied with the new skin tone and other modifiers we were talking about 1,000 new emojis! We had decided initially back during our migration that we would let the browser render natively where it was supported. However, depending on the combination of your browser, operating system, or phone you were using you either had support for the new emojis or you didn’t. On top of that, even where operating systems did support emojis, sometimes they did a terrible, terrible job of displaying those emojis 😨 (the horror, the horror):

Along came EmojiOne to save the day. They do an absolutely fantastic job of unifying the grand mess that is supporting emojis across different OSes and browsers. We use EmojiOne to make our emoji experience the seamless one that it is today.

EmojiOne! All the feels.

Along with switching to EmojiOne, we improved our design which had been originally just a short dropdown of emojis sorted alphabetically into a UI that currently lets you browse, jump by category, change skin tones, and add custom emojis. One interesting challenge was getting our browsable emoji UI to be performant — previously in our dropdown we would only display 20 or so emojis for you to search by keyword. But in the new UI we had 1500+ emojis to display which put a noticeable strain on React’s rendering system. Even despite the emoji UI and its components being pure rendered, it still manifested itself as a several second delay on page load. One of our engineers Sergio Almécija Rodríguez took on this challenge and was able to make a cache of our individual emoji components within our list UI to make sure we were rendering more efficiently. Now we were really 🤘 (rockin’)

Custom Emojis 🎁 (just for you and your team)

Sometimes even the rich (and occasionally bizarre) existing set of emojis isn’t enough to convey what you mean. In Paper, during one of Dropbox’s twice-a-year Hack Weeks, we decided to add support for custom emojis for all the little in-jokes and memes your team might have. In our case we could have waited until the Unicode Consortium had accepted our requests for cupcake, roly-poly cat, dancing wizard, trollface, and red panda, but instead we decided to just roll our own. [Update: 🧁is now a thing!]

First, I’ll describe some basics on how Paper works. A Paper doc consists of attributed text (atext for short) and an attribute pool (apool). Although it may seem that way, we don’t save HTML to our backend because that would be an absolute nightmare; instead, we take regular text and use attributes to describe the position of regions that have certain characteristics (hence, why string length is so important in our Spock emoji discussion above). We use attributes, for example, to indicate sections as being bold or containing a link to a website. Let’s introspectively look at how a part of this very paragraph is constructed in Paper!

text: A Paper doc consists of attributed text (atext for short)...
attributes: *0+15*0*d+5*0|1+c
apool: {
  "0":["author","d.YHOvhpCS9BNxz1xJE78xjz4q7DRColaUpHFBqz"],
  "d":["inline-code","true"]
}

Let’s break down the operations of attributes above:

*0+15  // Apply the 'author' attribute to the first 41 characters ('15' is in base 36)
*0*d+5 // Next, apply the 'inline-code' & 'author' attributes to the next 5
       // characters, on the word 'atext'
*0|1+c // Finally, apply just the 'author' for the rest of the line

Ok, now you have a baseline of how Paper saves its underlying data. We use attributes for much more than bolding text though. We put attributes on our richer objects to indicate things like the start of a list, or having an image associated with them. In Paper, these richer objects are called “Magic Objects” and they include things like lists, headers, checkboxes, images, , tables and at-mentions. We represent them by the * character (the text part of atext) and with an attribute pointing to the richer object that it represents. This lets us tell our renderer to take the * character and paint it instead using it the React class or component that defines its behavior.

Custom emojis are yet another example of a Magic Object in Paper’s ecosystem. In the case of custom emojis, we would add attributes saying:

[
  ["magicObject", "customEmoji"],
  ["customEmoji",
    "{
      'url': 'https://d2mxuefqeaa7sj.cloudfront.net/s_3E96F0DC82F6167C312B4C5D5168AA5B78613CFB37B684B23B628387E0E77CBC_1447989593464_87c2578fe0ce2023.png',
      'tags': 'cupcake'
    }"
  ]
]

The renderer looks at the * character and instead paints an image indicated by the url. In addition, we instruct the editor to treat it much like it would a regular character.

We actually had our original implementation creating custom emojis in the Private Use Area of Unicode. This worked ok but custom emojis are team-specific. This had the problem of not being able to be copy & paste the text across different teams without emojis turning out to be a � character. By converting the emoji to use Paper’s standard atext and Magic Object system (using our previously mentioned migration system) we were able to manipulate the data backing custom emojis much more easily.

Emojis Everywhere! 🌍 (not just big in Japan anymore)

The success of emojis in Paper influenced our other designs in-turn. We added stickers to our commenting area not too long afterwards. On top of that, we added emoji reactions (“reacji”) to tell your colleagues how you felt in the comments section. Again, all these things might seem a little silly, but they do help people feel more at ease in a world where one can easily feel misunderstood online. Besides, they plain just make the day more fun. Emojis help you more fluidly communicate with your team, so that you can get things done with aplomb. 🤜 🤛 (fist-bump of accomplishment)

In addition to stickers and emoji reactions, we recently launched a brand new feature! If you add an emoji to the start of your title of a Paper doc we’ll change the favicon in your browser’s tab for an easy-to-spot visual to your doc; in addition, we also set the emoji as the document icon on your list of docs on Paper’s homepage. Emojis everywhere!!!

Emojis as Favicon for easy-to-find tabs
Emojis in the document list

Now that we’re communicating clearly with each other and having fun while doing it, can we all get in a room and agree on what in the word (🙄, universal response to pun) some of these emojis mean? 💁 🙆 🙇 🙏

Mime Čuvalo🕴️
Staff Engineer on Paper wizard