工程师在编写软件时采用许多不同的策略来关注用户:例如,倾听用户反馈、修复错误以及添加用户迫切需要的功能。 由于基于 Web 的服务使得用户更容易迁移到新的应用程序,因此,关注建立和保持用户信任变得更加重要。 我们发现,一个非常有效——尽管肯定违反直觉——的赢得和维护用户信任的方法是让用户可以轻松地带着他们的数据离开你的产品。 这不仅可以防止锁定和赢得信任,还可以迫使你的团队在技术优势上进行创新和竞争。 我们称之为数据解放。
直到最近,用户很少在将大量个人信息放入新的互联网服务之前询问他们是否可以快速轻松地取出数据。 他们更可能问的问题是:“我的朋友们在使用这项服务吗?”“它有多可靠?”以及“提供服务的公司在六个月或一年后还在的可能性有多大?” 然而,用户开始意识到,随着他们在物理上无法访问的服务中存储越来越多的个人数据,如果他们没有移除数据的手段,他们将面临失去大量在线遗产的风险。
对于软件工程师来说,从他们使用的服务中提取数据通常比普通用户容易得多。 如果有 API 可用,我们工程师可以拼凑一个程序来提取我们的数据。 如果没有 API,我们甚至可以快速编写一个屏幕抓取器来获取数据副本。 不幸的是,对于大多数用户来说,这不是一个选择,他们常常想知道他们是否可以完全取出他们的数据。
当然,锁定您的用户具有使其更难离开您而转向竞争对手的优势。 同样,如果您的竞争对手锁定他们的用户,那么这些用户就更难转向您的产品。 尽管如此,将您的工程努力花在创新上远比建造更大的围墙和更坚固的门来阻止用户离开要好得多。 让用户今天更容易进行实验会大大增加他们对您的信任,并且他们更有可能在明天回到您的产品线。
锁定用户可能会抑制公司尽可能快地进行创新的需求。 相反,您的公司可能会出于商业原因决定放慢产品开发速度,并将工程资源转移到另一个产品。 这使得您的产品容易受到其他以更快速度创新的公司的攻击。 锁定让您的公司在没有创新时也能拥有持续成功的表象,但实际上它可能正在逐渐衰落。
如果您不锁定——或无法锁定——您的用户,那么竞争的最佳方式是以极快的速度进行创新。 让我们以 Google 搜索为例。 这是一个无法锁定用户的产品:用户无需安装软件即可使用它; 他们无需上传数据即可使用它; 他们无需签订为期两年的合同; 如果他们决定尝试另一个搜索引擎,他们只需将其输入到浏览器的地址栏中,即可立即开始使用。
Google 是如何设法让用户不断回到其搜索引擎的? 通过专注于不断提高其结果的质量。 用户可以如此轻松地切换这一事实,在 Google 的搜索质量和排名团队中灌输了令人难以置信的紧迫感。 在 Google,我们认为,如果我们让用户可以轻松地离开我们的任何产品,那么未能改进产品就会立即向工程师提供反馈,而工程师会通过构建更好的产品来回应。
在 Google,我们的态度一直是用户应该能够控制他们存储在我们任何产品中的数据,这意味着他们应该能够从任何产品中取出他们的数据。 句号。 这样做不应产生额外的货币成本,也许最重要的是,取出数据所需的精力应该是恒定的,而与数据量无关。 单独下载十几张照片没什么不方便的,但是如果用户必须一次下载 5,000 张照片才能将它们从应用程序中取出呢? 那可能要花费他们几周的时间。
即使用户拥有他们数据的副本,如果它采用专有格式,仍然可能被锁定。 15 年前的一些文字处理器文档无法用现代软件打开,因为它们以专有格式存储。 因此,重要的是不仅要访问数据,还要以具有公开可用规范的格式访问数据。 此外,该规范必须具有合理的许可条款:例如,实施它应该是免版税的。 如果导出的数据已经存在开放格式(例如,照片的 JPEG 或 TIFF),那么这应该是批量下载的一个选项。 如果产品中的数据没有行业标准(例如,博客没有标准数据格式),那么至少该格式应该是公开记录的——如果您的产品为您的格式提供解析器的开源参考实现,则可以获得额外加分。
关键是用户应该控制他们的数据,这意味着他们需要一种轻松访问数据的方式。 提供 API 或一次下载 5,000 张照片的能力并不能真正让您的普通用户轻松地将数据移入或移出产品。 从用户界面的角度来看,用户应该将数据解放仅仅看作是一组用于导入和导出产品中所有数据的按钮。
Google 正在通过其数据解放阵线来解决这个问题,这是一个工程团队,其目标是使数据更容易移入和移出 Google 产品。 数据解放工作特别关注可能阻碍用户切换到另一项服务或竞争产品的数据——即用户在 Google 产品中创建或导入的数据。 这是所有通过直接操作有意存储的数据——例如照片、电子邮件、文档或广告活动——如果用户想要将他们的业务转移到其他地方,他们很可能需要这些数据的副本。 作为副作用间接创建的数据(例如,日志数据)不属于此任务范围,因为它与锁定无关。
数据解放的另一个“非目标”是开发新标准:我们允许用户以现有格式导出(如果我们能做到),例如在 Google Docs 中,用户可以下载 OpenOffice 或 Microsoft Office 格式的文字处理文件。 对于没有明显的开放格式可以包含所有必要信息的产品,我们提供一些易于机器读取的内容,例如 XML(例如,对于 Blogger 源,包括帖子和评论,我们使用 Atom),公开记录格式,并在可能的情况下,为该格式提供解析器的参考实现(有关示例,请参阅 Google Blog Converters AppEngine 项目1)。 我们尝试以一种使用户可以轻松导入到另一个产品中的格式向用户提供数据。 由于 Google Docs 处理的是早于开放 Web 兴起的文字处理文档和电子表格,因此我们提供了几种不同的导出格式; 然而,在大多数产品中,我们都在努力避免陷入将数据导出为每种已知格式的困境。
在以下几种情况下,用户可能想要从您的产品中获取其数据的副本:他们可能找到了更适合其需求的另一个产品,并且他们想将其数据导入到新产品中; 您已宣布您将停止支持他们正在使用的产品; 或者,更糟糕的是,您可能做了某些事情来失去他们的信任。
当然,仅仅因为您的用户想要其数据的副本并不一定意味着他们正在放弃您的产品。 许多用户只是觉得拥有数据的本地副本作为备份更安全。 当我们首次解放 Blogger 时,我们看到了这种情况:许多用户开始每周导出他们的博客,同时继续在 Blogger 中托管和写作。 最后一种情况更多地植根于情感而非逻辑。 用户在其计算机上拥有的大多数数据根本没有备份,而托管应用程序几乎总是将用户数据的多个副本存储在多个地理位置,考虑到硬件故障以及自然灾害。 无论用户的担忧是合乎逻辑的还是情感上的,他们都需要感到他们的数据是安全的:重要的是您的用户信任您。
Google Sites 是一个网站创建器,允许通过浏览器进行 WYSIWYG 编辑。 我们在 Google 内部使用此服务作为我们的主要项目页面,因为它对于创建或聚合项目文档非常方便。 我们在 2009 年初承担了为 Sites 创建导入和导出功能的任务。
在设计早期,我们必须确定 Google Site 的外部格式应该是什么。 考虑到 Sites 提供的实用程序是创建和协作处理网站的能力,我们决定最适合真正解放的格式将是 XHTML。 HTML 作为 Web 的语言,也是网站最可移植的格式:只需将 XHTML 页面放在您自己的 Web 服务器上或将它们上传到您的 Web 服务提供商即可。 我们想确保这种形式的数据可移植性尽可能容易,数据丢失尽可能少。
Sites 使用其内部数据格式来封装存储在网站中的数据,包括网站中所有页面的所有修订。 解放这些数据的第一步是创建一个 Google Data API。 然后通过一个开源 Java 客户端工具 提供站点的完整导出,该工具使用 Google Sites Data API 并将数据转换为一组 XHTML 页面。
Google Sites Data API,像所有 Google Data API 一样,构建于 AtomPub 规范之上。 这允许使用 Atom 文档作为 RPC 的线路格式,对 Google Sites 数据进行 RPC(远程过程调用)样式的程序化访问。 Atom 非常适合 Google Sites 用例,因为数据可以相当容易地放入 Atom 信封中。
这是一个 Atom 条目的示例,它封装了 Sites 中的网页。 这可以使用 Content Feed to Google Sites 检索。
我们突出显示(粗体)了正在导出的实际数据,其中包括标识符、ISO 8601 格式的上次更新时间、标题、修订号和实际网页内容。 条目中包含的强制性作者身份元素和其他可选信息已被删除,以使示例简短。
API 就位后,第二步是将一组 Atom 源转换为一组可移植的 XHTML 网页。 为了防止丢失原始 Atom 中的任何数据,我们选择将有关每个 Atom 条目的所有元数据嵌入到转换后的 XHTML 中。 如果转换后的页面中没有此元数据,则会在导入期间出现问题——XHTML 的哪些元素对应于原始 Atom 条目的各个部分变得不清楚。 幸运的是,我们不必发明自己的元数据嵌入技术; 我们只是使用了 hAtom 微格式。
为了演示微格式的实用性,这是使用嵌入的 hAtom 微格式转换为 XHTML 后的相同示例
突出显示的 class 属性直接映射到原始 Atom 元素,这非常明确地说明了在将此信息重新导入到 Sites 时如何重建原始 Atom。 微格式方法还具有附带好处,即如果作者愿意向页面中的数据添加一些 class 属性,则可以将任何网页导入到 Sites 中。 这种以无损方式重新导入用户导出数据的能力是数据解放的关键——它可能需要更多时间来实现,但我们认为结果是值得的。
我们在进行解放项目时经常遇到的问题之一是迎合高级用户。 这些是我们最喜欢的用户。 他们是那些喜欢使用该服务、向其中投入大量数据并希望能够随时进行非常大的数据导入或导出的用户。 例如,五年的博客文章和照片的新闻报道很容易超过几个千兆字节的信息,并且尝试一举移动这些数据是一项真正的挑战。 为了使用户尽可能简单地进行导入和导出,我们决定实施一键式解决方案,该解决方案将为用户提供一个 Blogger 导出文件,其中包含任何 Blogger 博客的所有帖子、评论、静态页面甚至设置。 该文件将下载到用户的硬盘驱动器,并且可以稍后重新导入到 Blogger 中,或者进行转换并移动到另一个博客服务。
我们在为 Blogger 创建导入/导出体验时犯的一个错误是依赖于一个 HTTP 事务进行导入或导出。 当您传输的数据大小变得很大时,HTTP 连接变得脆弱。 该连接中的任何中断都会使操作失效,并可能导致不完整的导出或导入时缺少数据。 对于用户来说,这些是非常令人沮丧的情况,不幸的是,对于拥有大量博客数据的高级用户来说,这种情况更为普遍。 我们忽略了实施任何形式的部分导出,这也意味着高级用户有时需要求助于愚蠢的事情,例如手动分解他们的导出文件,以便在导入时获得更好的成功。 我们认识到这对用户来说是一种糟糕的体验,并希望在未来版本的 Blogger 中解决它。
更好的方法是,竞争对手的博客平台采用的方法,是不依赖用户的硬盘驱动器作为尝试在基于云的博客服务之间迁移大量数据时的中介。 相反,数据解放最好通过 API 提供,而数据可移植性最好通过使用这些 API 构建代码来执行云到云的迁移来提供。 这些类型的迁移需要在服务之间进行多次 RPC 以逐块移动数据,并且每次 RPC 都可以在失败时自动重试,而无需用户干预。 这比单事务导入模型好得多。 它增加了完全成功的可能性,并且为用户提供了更好的整体体验。 然而,真正的云到云可移植性只有在每个云都为其所有用户数据提供解放的 API 时才有效。 我们认为云到云可移植性对用户来说真的很好,它是数据解放阵线的一个原则。
正如您从这些案例研究中看到的那样,数据解放之路的第一步是准确确定用户需要导出什么。 一旦您涵盖了用户自己导入或创建到您的产品中的数据,事情就开始变得复杂起来。 以 Google Docs 为例:用户显然拥有他或她创建的文档,但是属于另一个用户,然后由当前正在执行导出的用户编辑的文档呢? 用户只有读取访问权限的文档呢? 如果您考虑到全局可读文档,则用户具有读取访问权限的文档集可能比用户实际读取或打开的文档集大得多。 最后,您必须考虑文档元数据,例如访问控制列表。 这只是一个例子,但它适用于任何允许用户共享或协作处理数据的产品。
要记住的另一个重要挑战涉及安全性和身份验证。 当您使用户非常容易和快速地将其数据从产品中取出时,您会大大减少攻击者复制所有数据的所需时间。 这就是为什么最好在导出敏感数据(例如他们的搜索历史记录)之前要求用户重新进行身份验证,以及将导出活动过度通信回用户(例如,电子邮件通知已发生导出)的原因。 随着我们继续解放产品,我们正在探索这些机制以及更多机制。
大数据集构成了另一个挑战。 例如,一个庞大的照片集,很容易扩展到多个千兆字节,考虑到大多数家庭互联网连接的当前传输速度,可能会给交付带来困难。 在这种情况下,要么我们有一个用于该产品的客户端,可以同步往返于服务的数据(例如 Picasa),要么我们依赖于已建立的协议和 API(例如,Gmail 的 POP 和 IMAP)以允许用户增量同步或导出其数据。
允许用户获取其数据的副本只是数据解放之路的第一步:要达到用户可以轻松地将其数据从互联网上的一个产品移动到另一个产品的地步,我们还有很长的路要走。 我们期待着这个未来,在这个未来中,作为工程师,我们可以减少在数据传输上的精力,而将更多精力放在构建有趣的产品上,这些产品可以通过其技术优势进行竞争——而不是通过挟持用户。 让用户控制他们的数据是建立用户信任的重要组成部分,我们希望更多的公司能够认识到,如果他们想长期留住用户,最好的方法是让他们自由。
问
1. http://code.google.com/p/google-blog-converters-appengine/wiki/BloggerExportTemplate; 和 http://code.google.com/apis/blogger/docs/2.0/reference.html#LinkCommentsToPosts。
感谢 Bryan O'Sullivan、Ben Collins-Sussman、Danny Berlin、Josh Bloch、Stuart Feldman 和 Ben Laurie 阅读本文草稿。
喜欢它,讨厌它? 让我们知道
Brian Fitzpatrick 于 2005 年在芝加哥创办了 Google 工程办公室,并且是数据解放阵线和 Google Affiliate Network 的工程经理。 Fitzpatrick 是一位已出版的作家、经常发言的人和超过 12 年的开源贡献者,他是 Apache Software Foundation 和 Open Web Foundation 的成员,以及 Apple 和 CollabNet 的前工程师。 尽管在 New Orleans 长大,并在 Silicon Valley 公司工作了职业生涯的大部分时间,但他多年前就认定芝加哥是他的家,并顽固地拒绝搬到加利福尼亚。
JJ Lueck 于 2007 年加入了 Google 的软件工程团队。 他毕业于 MIT,曾是 AOL、Bose 以及初创公司 Bang Networks 和 Reactivity 的工程师,他喜欢思考云到云互操作性等问题,并探索虚拟机的深度和潜力。 他也对 Monty Python 非常着迷。
© 2010 1542-7730/10/1000 $10.00
最初发表于 Queue 第 8 卷,第 10 期—
在 数字图书馆 中评论本文
Ethan Miller, Achilles Benetopoulos, George Neville-Neil, Pankaj Mehra, Daniel Bittman - 远内存中的指针
有效利用新兴的远内存技术需要考虑在父进程上下文之外操作丰富连接的数据。 开发中的操作系统技术通过公开诸如内存对象和全局不变指针之类的抽象来提供帮助,设备和新实例化的计算可以遍历这些抽象。 这些想法将允许在具有分离内存节点的未来异构分布式系统上运行的应用程序利用近内存处理来获得更高的性能,并独立扩展其内存和计算资源以降低成本。
Simson Garfinkel, Jon Stewart - 磨砺你的工具
本文介绍了我们在最初发布十年后更新高性能数字取证工具 BE (bulk_extractor) 的经验。 在 2018 年至 2022 年期间,我们将程序从 C++98 更新到 C++17。 我们还进行了完整的代码重构并采用了单元测试框架。 DF 工具必须经常更新,以跟上其使用方式的变化。 对 bulk_extractor 工具更新的描述可以作为可以并且应该做什么的示例。
Pat Helland - 自主计算
自主计算是一种用于商业工作的模式,它使用协作来连接领地及其使者。 这种模式基于纸质表格,已经使用了几个世纪。 在这里,我们解释了领地、协作和使者。 我们研究了使者如何在自主边界之外工作,并且在保持局外人身份的同时很方便。 我们还研究了如何在不同的领地之间启动、长时间运行并最终完成工作。
Archie L. Cobbs - 持久性编程
几年前,我的团队正在为增强型 911 (E911) 紧急呼叫中心开展一个商业 Java 开发项目。 我们试图使用传统的 Java over SQL 数据库模型来满足该项目的数据存储需求,这让我们感到沮丧。 在对项目的特定需求(和非需求)进行一些反思之后,我们深吸一口气,并决定从头开始创建我们自己的自定义持久层。