精益移动开发-全-
精益移动开发(全)
原文:
zh.annas-archive.org/md5/20c69c02625e7ff475d9c1f89a800fd3译者:飞龙
前言
精益创业方法论已经成为创业领域的一个知名术语。有许多书籍涵盖了这一点(和相关方法论),例如《精益创业》(埃里克·莱斯)、《精益创业》(阿什·莫里亚)、《初创公司老板手册》(史蒂夫·布兰克)和《顿悟的四个步骤》(史蒂夫·布兰克)。
精益创业方法论,在许多方面,是关于通过尽早收集反馈来减少浪费。开发一个六个月或更长时间的优秀 App,却发现没有人对它感兴趣,这是没有意义的。
你的初创公司,甚至是一个现有的 App,需要多次但短暂的迭代来找出哪些有效,哪些无效。这引发了一些问题:你的 App 真的解决了值得解决的问题吗?精益创业方法论又是如何介入其中的?
所有书籍目前都专注于你的初创公司或公司的以商业为导向的成员。然而,对于公司中以技术为导向的成员,特别是缺乏一种以移动优先策略为特点的实用方法。理论很酷,但实用方法可以帮助开发者更快地前进。
本书试图填补这一空白。它解释了精益创业方法论的基本要素,并详细阐述了研究和实施。特别是,它关注从技术角度需要做的事情。这使得本书成为如何将精益创业方法论应用于实际 Android 和 iOS 开发的务实指南。因此,它没有任何玄虚。如果你想要真正的行动,如果你想要开发人们真正需要和想要使用的 App,那么这本指南就是为你准备的。
本书涵盖内容
第一章,《是的,有适合这个的 App》,包含了一些需要自问的重要问题,例如:你为什么要开发这个 App,又是为谁而开发?这一章解释了精益创业如何帮助。
第二章,《精益创业入门》,解释了商业模式画布、客户开发是什么,以及最小可行产品(MVP)是什么。
第三章,《在构建移动应用中应用精益的挑战》,详细阐述了市场工作流程和你的 App 的可发现性。
第四章,《简洁敏捷工作流程》,讨论了时间盒编程、信任第三方解决方案以及如何制作临时简报。
第五章,《实用方法》,以实用方式解释了敏捷工作流程、看板和 Scrum 是什么,以及你如何在你的工作流程中实施它们。
第六章,《MVP 总是比你想象的更简约》,探讨了应该将哪些功能纳入最小可行产品,以及这些功能如何帮助证明你的假设。
第七章, 《最小可行产品案例研究》包含了一些 MVP 实施的真实世界示例。
第八章, 《应用实验的云解决方案》讨论了您的应用的后端策略。有哪些第三方服务可用,您是否真的需要一个后端开发者?
第九章, 《原生、混合或跨平台》解释了从哪个平台(Android 或 iOS)开始,以及当您想同时进行时可能有哪些可能性。
第十章, 《有 API 可用!》启发你结合现有数据和服务的使用。它提供了一个结合电影信息、地图和 Uber 集成的示例。最后,我们将看到如何使用 IFTT 构建最小可行产品(MVP)并验证假设。
第十一章, 《用户引导和注册》讨论了用户的引导和转化。它解释了如何降低障碍,并提供了一个使用 Twitter 或电话号码注册的 Android 示例。
第十二章, 《做那些不具规模的事情》指导您专注于验证假设而不是专注于自动化。尽量以最小的努力找出什么有效,什么无效。
第十三章, 《Play 商店和 App 商店的技巧》包含了对拆分测试的初步介绍以及如何将其应用于 Play 商店或 App Store。
第十四章, 《对您的应用进行 A/B 测试》告诉您为什么对您的应用进行拆分测试很重要,以及如何为您的应用设置 A/B 测试。它提供了一个使用 Android 和 Firebase 选项远程配置和分析的示例。
第十五章, 《增加用户粘性和提高留存率》向您介绍什么是用户粘性和留存率,为什么它很重要,以及您可以做什么来增加用户粘性。它还讨论了推送通知在提高留存率(回头用户)中的重要性。
第十六章, 《扩展策略》启发您思考扩展策略。这可能听起来像是一个奢侈的问题,但如果您的应用取得成功,您的后端必须扩展。云服务已经使这个过程变得非常简单。不要急于扩展,但要使您的解决方案具有可扩展性。
第十七章, 《货币化和定价策略》讨论了您的应用的各种货币化选项。例如,如果您选择应用内购买,您还需要一个好的定价策略。
第十八章,持续部署,讨论了 Git 工作流和 CI/CD 工具,如 TeamCity 和 Jenkins。如果您有一个良好的测试策略,这些工具可以帮助您频繁且快速地交付。
第十九章,构建不公平优势,让您思考如何构建一个使您的业务对新进入者具有防御性的“护城河”。
第二十章,飞行案例研究,讨论了一个现有社交媒体应用的案例研究。
附录,阅读清单和网站参考,涵盖了一系列必读书籍和值得访问的网站。
您需要为本书准备的内容
首先,这本书旨在激励那些寻求将领导力融入其开发运营中的初创公司技术型联合创始人以及现有企业的技术领导者。此外,书中还包含了一些 Android 和 iOS 代码示例,我们通过这些示例来解释一些概念。虽然概念比代码更重要,但你也可以亲自尝试这些示例。在适用的情况下,你可以找到指向 GitHub 仓库的链接,其中包含代码。
对于 Android 示例,您需要在您的计算机上安装Android Studio 3(或更高版本)和 Android SDK。Android Studio可在 Windows、OSX 和其他操作系统上免费下载。Android 示例是用 Kotlin 和 Java 编写的。
iOS 示例需要xCode 9或更高版本(xCode 仅在 OSX 上可用,您需要拥有付费的 Apple 开发者账户)。iOS 示例是用 Swift 4 编写的。
一些示例需要(免费)在 Firebase、Facebook、Fabric 或其他服务上进行注册。
本书针对的对象
尤其是本书的受众将是处于初创环境中的技术型联合创始人、开发者或 CTO。然而,如果你是 CTO、开发总监或现有软件公司的开发者,这本书也同样适合你。精益管理,如果运用得当,对初创公司和现有公司都有帮助。
术语约定
在这本书中,您将找到许多文本样式,用于区分不同类型的信息。以下是一些这些样式的示例及其含义的解释。
所有 Android 和 iOS 示例和描述都是基于 Android Studio、xCode 和多种第三方服务,在 OSX 机器上运行的。
控制台输入显示如下:
$ gem install cocoapods
代码块设置如下:
func refresh (sender: AnyObject!) {
...
let cngQuery = client.queryDataset("wwmu-gmzc")
cngQuery.orderAscending("title").get { res in
switch res {
case .Dataset (let data):
self.data = data
...
}
}
Data (XML, JSON or otherwise) is shown as:
<key>UberClientID</key>
<string>your uber client id</string>
<key>UberCallbackURI</key>
<string></string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>uber</string>
</array>
在您需要应用自己的客户端 ID、API 密钥或 API 密钥的地方,例如,在代码或数据中读取为:your client_id。
新术语和重要词汇以粗体显示。屏幕上看到的单词,例如在菜单或对话框中,在文本中显示如下:“点击 Next 按钮将您带到下一屏幕。”
警告或重要注意事项以如下框的形式出现。
小贴士和技巧显示如下。
读者反馈
我们始终欢迎读者的反馈。请告诉我们您对本书的看法——您喜欢或不喜欢的地方。读者反馈对我们很重要,因为它帮助我们开发出您真正能从中获得最大价值的标题。
要向我们发送一般反馈,请简单地发送电子邮件至feedback@packtpub.com,并在邮件主题中提及本书的标题。
如果您在某个主题上具有专业知识,并且您有兴趣撰写或为本书做出贡献,请参阅我们的作者指南,网址为www.packtpub.com/authors。
客户支持
现在您已经是 Packt 图书的骄傲拥有者了,我们有一些事情可以帮助您从您的购买中获得最大价值。
下载示例代码
您可以从www.packtpub.com的账户下载本书的示例代码文件。如果您在其他地方购买了本书,您可以访问www.packtpub.com/support并注册,以便将文件直接通过电子邮件发送给您。您可以通过以下步骤下载代码文件:
-
使用您的电子邮件地址和密码登录或注册我们的网站。
-
将鼠标指针悬停在顶部的“支持”选项卡上。
-
点击“代码下载与勘误”。
-
在搜索框中输入本书的名称。
-
选择您想要下载代码文件的书籍。
-
从下拉菜单中选择您购买本书的地方。
-
点击“代码下载”。
文件下载完成后,请确保您使用最新版本的软件解压缩或提取文件夹:
-
WinRAR / 7-Zip for Windows
-
Zipeg / iZip / UnRarX for Mac
-
7-Zip / PeaZip for Linux
本书代码包也托管在 GitHub 上,地址为github.com/PacktPublishing/Lean–Mobile–App–Development。我们还有其他来自我们丰富图书和视频目录的代码包,可在github.com/PacktPublishing/找到。查看它们吧!
下载本书的颜色图像
我们还为您提供了一个包含本书中使用的截图/图表颜色图像的 PDF 文件。这些颜色图像将帮助您更好地理解输出中的变化。您可以从www.packtpub.com/sites/default/files/downloads/LeanMobileAppDevelopment_ColorImages.pdf下载此文件。
勘误
尽管我们已经尽最大努力确保内容的准确性,但错误仍然可能发生。如果您在我们的书中发现错误——可能是文本或代码中的错误——如果您能向我们报告这一点,我们将不胜感激。通过这样做,您可以避免其他读者的挫败感,并帮助我们改进本书的后续版本。如果您发现任何勘误,请通过访问www.packtpub.com/submit-errata,选择您的书籍,点击勘误提交表单链接,并输入您的勘误详情来报告它们。一旦您的勘误得到验证,您的提交将被接受,勘误将被上传到我们的网站或添加到该标题的勘误表部分。
要查看之前提交的勘误表,请访问www.packtpub.com/books/content/support,并在搜索字段中输入书籍名称。所需信息将出现在勘误表部分。
侵权
互联网上对版权材料的侵权是一个持续存在的问题,涉及所有媒体。在 Packt,我们非常重视保护我们的版权和许可证。如果您在互联网上发现任何形式的非法副本,请立即提供位置地址或网站名称,以便我们可以寻求补救措施。
请通过copyright@packtpub.com与我们联系,并提供疑似侵权材料的链接。
我们感谢您在保护我们的作者和我们为您提供有价值内容的能力方面的帮助。
问题
如果您对本书的任何方面有问题,您可以通过questions@packtpub.com与我们联系,我们将尽力解决问题。
第一章:是的,确实有相应的应用程序
对于几乎所有的事情,似乎都已经有了相应的应用程序。创建一个盈利的应用程序并不容易,但如果你以明智的方式开发你的应用程序,你的公司也可以取得成功!
本书旨在帮助你利用精益创业方法在你的移动应用程序周围建立一个盈利的业务。与许多其他书籍不同,这本书不仅面向你组织中的以商业为导向的成员。相反,它是一本非常实用的指南,解释了可以用来以精益方式开发应用程序的工具和技术。对于技术导向的人来说,对精益创业方法产生热情也很重要,这也是为什么这本书主要面向技术共同所有者和开发者。他们需要拥有正确的工具,以便将方法论应用于他们的日常移动应用程序开发。我们将讨论如何通过使用一系列技术和工具来节省时间和减少浪费。
另一方面,这本书对非技术人员也有兴趣。如果他们能够更好地理解应用程序开发中涉及的基本技术过程,那将是理想的。我们需要商业人士找到并明确界定问题,以便技术人员可以为他们提供正确的解决方案。每个人都需要紧密合作。如果你对彼此的视角有良好的理解,你可以取得更好的结果。
如果你的创业公司缺少一个技术共同创始人,那么现在是寻找的时候了。不要外包开发(现在)。当你的创业公司处于早期阶段时,这通常效果不佳。
在本书的这一章中,我们将首先了解精益创业方法,并学习为什么它对你们创业公司的所有成员都很重要。
本章将讨论以下主题:
-
应用程序生态系统
-
精益创业方法的介绍
-
让你的用户对你的应用程序上瘾
应用程序生态系统
我们首先将深入探讨应用程序生态系统所呈现的悖论——名利双收的前景,但被数百万应用程序淹没的隐秘性。我们还将讨论每个内部创业者或企业家在开始构建新应用程序之前需要思考的关键问题。同样的原则也适用于现有应用程序的新想法。你应该首先问自己的是:
-
用户为什么要使用我的应用程序?
-
他们会在什么目的或什么时候真正需要它?
-
他们为什么要不断回来使用它?
创建一个盈利的应用程序很难,但并非不可能。有许多著名的例子。其中之一是《愤怒的小鸟》。2013 年 5 月,越南的一名不出名的独立应用程序开发者 Nguyen Ha Dong 在 iOS 应用商店发布了一款游戏。该应用程序的初始反应并不热烈,只有少数下载。几个月后,在 2014 年初,该游戏因人气激增而复活,并成为当时应用商店中最受欢迎的游戏。
在 2014 年 1 月达到流行顶峰时,这款游戏每天通过应用内广告和销售赚取 50,000 美元。一个月后,在 2014 年 2 月,Dong 著名地将游戏从商店中撤下。这导致了一个短暂的、狂热的时期,当时安装了该应用的手机在线上以溢价出售。
该应用现在是一个广为人知的从贫穷到一夜暴富的成功故事。但无论是偶然还是有意为之,Dong 的成功远非典型。很少有独立应用开发者成功地货币化他们的应用。
对于每一个拥有闪亮、明亮、新想法的内创业者或企业家来说,他们面临的几率都是不利的。当史蒂夫·乔布斯著名地开玩笑说“有应用可以做到这一点”时,他真的是这么想的。几乎每件事都有应用!那么,你的新想法为什么重要呢?
并非每个应用都有“飞黄腾达”的结局
如果你建好了,他们就会来。嗯,这显然是不正确的。仅仅在 App Store 或 Play Store 发布你的应用是不够的。在谷歌 Play 和苹果 App Store 上,开发者发布的 10 个应用中,有 9 个应用的下载量不到 5,000 次。已经有这么多应用了。人们如何才能注意到你的应用?
无论你的应用有多好,没有良好的计划,它将在应用海洋中淹没。要成功,你首先需要问自己一些重要的问题:
-
谁需要你的应用?
-
人们将如何了解你的应用?
-
为什么有人会下载你的应用?
-
他们为什么还会回来使用它?
-
别人会如何了解到这个应用?
-
一旦你的应用成功,是什么阻止别人复制它?
进入排行榜顶端的应用与没有进入的应用相比,下载量要大得多。在市场上存在长尾特征的情况是有道理的。亚马逊因说过他们卖的书比之前没有库存的书赚得更多而闻名。他们的市场具有强大的长尾特征,几本细分领域的书籍找到了读者。
然而,App Store 的动态并不利于细分市场。应用的发现性仍然是一个挑战,使得出版商在细分类别中难以成功。除了发现性本身,还有更多的摩擦涉及到人们下载应用而不是仅仅访问移动网站。
精益创业方法简介
当前的移动世界已经远远超过了 2000 年代末的淘金热。谷歌 Play 有 190 万款应用,下载量超过 500 亿次。苹果的 App Store 有 140 万款应用,下载量达到 1000 亿次。大多数应用类别都相当饱和,大多数事情都有免费应用。市场的设计激励应用开发者降低价格,以便进入排行榜顶端,从而获得广泛的分布。
你是否会被这一切所劝阻?这难道意味着成功的可能性如此之低,领域如此令人畏惧,以至于我们最好放弃吗?远非如此!正如时间所证明的,总有新的机会。众所周知,今天的一些领先公司,如谷歌和 Facebook,都是从 2000 年代初的互联网泡沫破裂的尘埃中诞生的。
但与公司以前在构建产品时采取的爆炸式方法不同,我们现在拥有更多科学的方法来将新想法推向市场。这就是埃里克·莱斯概述的精益创业方法彻底改变了几个初创公司和大型公司开发软件的方式。
精益创业原则通过快速实验帮助你实现你的愿景。它们提供了一种方法,即首先识别你正在做出的关键高风险假设,这些假设的失败意味着你的想法将失败。下一步是制定小型市场实验来测试这些假设。一个成功的实验将验证一个假设,这让你可以继续到下一个假设并制定下一个实验。实验的失败将使一个假设无效,这意味着你当前形式的想法将失败。
如果你是一名开发者,你可能想知道精益创业方法是否只是一堆为穿着暗色西装的严肃人士保留的商业管理术语。这将是一个不幸的误解。埃里克·莱斯试图为创业开发一个易于理解的管理原则,否则它被视为一种神秘的黑暗艺术形式。
然而,埃里克的根源更接近开发者社区,而不是商业社区。他在 IMVU 构建软件的经历启发了他的精益创业想法。他是早期支持软件开发过程中的持续开发和持续集成的先驱之一。这是一个尝试去除开发者花费时间上的所有浪费周期,并帮助他们专注于构建对客户最重要的东西的尝试。
经验丰富的开发者关心效率和编写真正有影响力的代码。与其他行业相比,软件行业有无数例子表明,数百万行代码被废弃,因为它们被用于构建没有人想要的特性。这是对开发者无尽的努力时间的浪费,这些时间本可以更好地用于构建有用的软件。
精益创业方法也与敏捷软件开发紧密相关。敏捷开发概述了软件构建的重要周期。这个周期通常是内向的,发生在软件开发团队内部,在经理、开发人员和测试人员之间。精益创业增加了客户开发的概念。客户开发是一个外向的周期,发生在软件开发团队和客户之间。这个周期包括通过进行访谈、观察客户行为、进行市场实验以及汇总结果与客户合作。
如果你在一个自上而下的文化组织中担任开发者,那里西装革履的人挥舞着双手,精通 PowerPoint,精益创业可以帮助你。在许多组织中,决策仍然基于谁有最好的 PowerPoint 演示文稿以及关键游说团影响决策的能力。没有什么能比这更能伤害企业的自下而上的创新了。
精益创业为开发者提供了一个框架,使他们能够通过客户实验的真实数据来影响决策。如果需要做出决策,推动会议上的其他人要么提供数据来证明它,要么运行实验来收集它。这是至关重要的。
过去十年中,大多数组织都采用了敏捷开发,Scrum 和极限编程变得司空见惯。在未来的几年里,对精益创业的了解将成为寻求提升技能的开发者的一项宝贵资产。
精益创业不是一个固定不变的过程,它是一套原则,旨在帮助你在未知领域找到方向。在野外,指南针和地图是徒步旅行者用来导航和避免潜在致命陷阱的工具。就像指南针和地图一样,精益提供了一套框架来导航新的发现。这些发现使你能够做出关于下一步该采取哪些步骤以及朝哪个方向前进的关键决策。
精益方法并不能保证下一个《Flappy Bird》的成功。但这样想:我们仍然处于一个从概念到市场的创新仍然具有偶然性的时代。这就像火的发现和轮子的发明一样,可能更多的是偶然和渐进的演变,而不是深思熟虑的选择。在科学使我们能够发展出系统化的实验室实验方法之前,我们花了几个世纪。尽管如此,传奇发明家托马斯·阿尔瓦·爱迪生在发明电灯泡之前也经历了数百次失败的实验。
"天才就是 99%的汗水加 1%的灵感。"
- 爱迪生
尽管如此,科学确实加速了这一过程。偶然发现需要几个世纪。上个世纪见证了新发现和重大科学进步的加速。实验仍然会失败,那些持续多年的研究项目往往会被放弃。但今天,实验室科学家的成功几率显著高于野外穴居人的几率。
精益创业(Lean Startup)改变了我们理解客户需求以及如何构建产品以满足这些需求的方式。我们的成功几率比十年前一个软件开发者要高得多。这种方法论如何帮助开发者利用正确的工具在正确的时间做正确的事情?答案就在这本书里。它面向技术联合创始人以及其他与创业公司相关的开发者。它可以帮助你学习如何将精益创业方法论应用于移动应用程序开发。它将为你提供如何在实用和动手方法之间取得平衡的见解,同时仍然以正确的方式做事。
其中一个关键要素是早期验证。无论你是以解决方案为导向还是以问题为导向的人,你都有一定的假设。这些假设可能是正确的,但更有可能是不正确的。找到答案的唯一方法是通过创建一个可以非常快速构建并用于收集反馈的应用程序或模拟应用程序。这样的解决方案被称为最小可行产品(MVP)。MVP 只包含你需要的功能,以证明你的假设。应用程序中所有不能帮助收集反馈的其他功能都是浪费,不应该存在。
对于一个商人来说,MVP(最小可行产品)的概念可能听起来很奇怪。你只有一次机会给人留下第一印象,对吧?此外,作为一个开发者,你也不想写一大堆代码,然后又把它们扔掉。那么,MVP 究竟应该包含什么?关于 MVP 的更深入解释将在第五章《实用方法》中进行。
让你的用户对你的应用程序上瘾
9/10 的应用程序下载量少于 5000 次,而且 9/10 的应用程序只发布过一次。你可以自己计算。就在那里,你可以看到,拥有一个被超过 5000 人定期使用的应用程序的几率已经下降到 0.01,或者说 100 个中只有 1 个。
发生这种情况的原因有很多。有些用户安装了他们听说的应用程序,但不喜欢它,可能会立即选择卸载。如果他们喜欢这个应用程序,他们可能会保留它。虽然这听起来像是一个胜利,但情况并不总是如此。通常,用户只是忘记了应用程序,甚至可能不会考虑再次启动它,即使它满足了他们的需求。
你可能已经开发了一个帮助用户通过预算节省金钱的出色应用,但除非用户记得定期启动应用并跟踪她的财务状况,否则它将不会帮助她。在第十五章,增长吸引力和提高留存率,该章节讨论了吸引力和留存率,我们将看到一些实用的实现方法来吸引用户的注意力。例如,发送(相关)推送通知通常是一种有效的方法,将用户的注意力重新吸引到应用上。
经常使用会创造更多机会,鼓励人们邀请他们的朋友,广播内容,并通过口碑分享。
让我们退一步,关注这个问题:“人们将如何了解到这个应用?”除非它被特色推荐(例如,由苹果推荐),或者除非它意外被发现(就像 Flappy Bird 那样),否则你需要积极推广它。你可以考虑谷歌广告、传单和电视广告。这可能会变得相当昂贵。然而,如果你能让它自然增长,结果可能会好得多,而且成本会更低。例如,人们可能会在 Twitter 和其他社交媒体平台上听说你的应用有多好。为了实现这一点,人们首先需要成为你应用的热情和常规用户,然后他们才会与他们的朋友或商业同事分享。
持续在产品中发现价值的用户更有可能告诉他们的朋友。
一些产品吸引了广泛的关注。Nir Eyal 在他的书《钩子》中描述了是什么让我们出于纯粹的习惯与某些产品互动。例如,宝可梦 GO!、Facebook 或 Instagram 都是非常上瘾的应用。人们听说这个应用,下载它,并且每天都在使用它。为什么是这样?似乎有一种潜在的模式,解释了技术如何吸引我们。Nir Eyal 通过介绍钩子模型来回答这个问题和其他问题。这是一个四步骤的过程,被嵌入到许多成功公司的产品中,以微妙地鼓励客户行为。
上瘾的用户成为品牌传教士——你公司的扩音器。
Nir Eyal 的经典钩子模型包含四个步骤:
-
触发
-
行动
-
奖励
-
投资

简而言之,这就是你在模型中看到的内容:触发是带来用户到产品采取行动,从而产生奖励,随后是进一步的投入。
在行动步骤中,用户将被要求执行一个简单的动作,这将提高用户的动机。这个钩子阶段借鉴了可用性设计和艺术科学,以确保用户按照设计者的意图采取行动。
提供可变和不可预测的奖励是吸引用户的重要工具。已经存在许多反馈循环,但它们都是可预测的。可预测的循环不会产生任何欲望。我们应该让用户感到惊喜,并在用户中创造欲望。游戏化是完成这一目标的工具之一。我们可以用徽章或其他数字(或非数字)激励来奖励用户。
吸引钩子的最后阶段是我们将要求用户做出相应的行动。我们不仅希望增加用户再次通过吸引钩子的几率,除了鼓励用户继续(解锁新等级并获得另一个徽章!)之外,我们还可以要求用户在 App Store 对应用进行评分,或者我们可以要求用户在社交媒体上分享应用的内容(挑战朋友!)。
如果我们将这个模型应用到另一个知名的游戏,比如《精灵宝可梦 Go!》,那么这个模型看起来会是这样:用户收到通知,屏幕上显示一个宝可梦(触发)。用户感到无聊或想找乐子,想要玩游戏(行动)。用户因为获得了一个(特殊的)宝可梦(可变奖励)而继续玩游戏或被要求分享最近的成就(投资)。
你也可以将这个模型应用到你的应用中。你应用中可能或将会有的上瘾功能是什么?你能做些什么来让用户更频繁地回到你的应用?这个过程不仅可以帮助你的应用成长,还会增加你公司(感知)的价值——投资者对月活跃用户数(MAU)的兴趣比对用户数量的兴趣更大。
要实现这一点,你需要构建一个人们真正想要使用的应用。要了解人们想要什么,你可以问他们他们需要什么。这听起来比实际上容易。确保你提出正确的问题,并避免只得到社会期望的答案。此外,确保你仔细倾听他们告诉你的内容。记住,有时,他们直到看到它之前,都不知道自己想要什么。以下是一个调查的例子。
当我们开始与真正的潜在用户互动时,我们问他们的问题之一如下:
"你喜欢这个应用吗?"
答案总是礼貌的:
"是的,这是一个非常酷的想法。"
"哇,这个卡拉 OK 的想法很棒。"
最初,我们没有足够重视用户的评论:
"你没有我想要的歌或课程。"
"我的老师的歌不在你的应用上。"
"这怎么帮我找到老师?"
"谁会审阅我的录音?"
如果我们当时更加关注用户的评论并提出正确的问题,那么我们可能会更快地意识到,我们正在观察的是一个连接学生和老师的市场,应用是这个连接的工具。我们最终选择了这条路线,并与几位世界著名的音乐家和教师合作建立了平台。但如果我们从一开始就提出正确的问题,我们就可以在早期节省时间和资源。
摘要
在本章中,我们了解到让用户意识到你的应用非常重要。如果他们能够被吸引,那就更好了,这就是你阅读过的钩子模型引入的原因。最后,我们学习了精益创业方法论如何帮助制作出更好的应用。
在接下来的章节中,我们将看到你可以使用哪些工具和方法来缩短开发周期,以及如何减少浪费。在下一章中,我们将探讨商业画布模型,在那里我们可以概述我们业务中每个元素的基本假设。这可以帮助我们确定我们的商业想法,而无需撰写一份 100 页的商业计划,而这份计划没有人会去阅读。这听起来你已经节省了时间。多么酷啊?
第二章:精益创业入门
如果您在没有深入了解精益创业方法论的概念的情况下拿起这本书,这一章将作为快速入门指南,帮助您开始。如果您已经熟悉精益思维,那么这一章可能作为轻松的复习。
在这里,我们将介绍几个构成精益创业基础的关键概念;也就是说,我们将回顾:
-
商业模式画布
-
精益画布
-
敏捷开发
-
客户开发
-
最小可行产品(MVP)
了解这些概念对于掌握和运用本书中的其他课程非常重要,我们鼓励您花时间彻底理解它们。
商业模式画布
每一个有想法的新内部创业家或企业家都希望将自己的创造付诸实践,并随着时间的推移观察其成长。随着时间的推移实现成功增长需要可持续性,这是持久理念的关键因素。传达新想法可持续主张的最常见方式是商业计划。
商业计划概述了一个问题、它所提供的机会、解决问题的方法、生成收入的模式、管理成本的方式以及随着时间的推移实现增长的杠杆。
编写商业计划有两个阶段。第一阶段是实际编写计划,第二阶段是在您的业务发展过程中保持计划的更新。
商业计划通常是为了路演或筹资目的而编写的,然后很快就被遗忘了。投资者的注意力往往会集中在目标上,以及公司朝着这些目标的方向上的表现,而忽略了业务的根本方面。然而,商业计划在您的业务生命周期中发挥着许多作用。它应该被视为一份活文档,并且随着业务的发展,它应该得到维护和更新。
在 2008 年,亚历山大·奥斯特瓦尔德提出了一种新的格式,称为商业模式画布(BMC)。商业模式画布是一页纸的文档,让您能够展示商业计划的各个方面:

让我们将其分解,并逐一介绍画布的每个部分。
关键合作伙伴
随着业务的增长,合作伙伴是其他与你一起工作的个人或企业。
在填写这一部分时,请考虑以下问题:
-
我们的关键合作伙伴是谁?
-
我们的关键供应商是谁?
-
我们从合作伙伴那里获取哪些关键资源?
-
我们的合作伙伴执行哪些关键活动?
合作伙伴对于共同创造和利用他人的规模和影响力至关重要。例如,一个社交发现应用可能会选择与一个电子商务网站合作,该网站允许用户购买其社交网络中其他人推荐的产品。
关键活动
应该列出所有对业务至关重要的广泛活动。
请问自己以下问题:
-
我们的价值主张需要哪些关键活动?
-
我们的分销渠道需要哪些关键活动?
-
我们客户关系需要哪些关键活动?
-
我们收入流需要哪些关键活动?
这些活动可能包括与移动应用生产相关的活动,例如与应用商店、原始设备制造商和设备制造商合作。包括其他想到的活动,例如与应用评论家和博主合作,或通过免费增值、应用内购买或推荐模式跟踪货币化。
价值主张
明确识别您的应用解决的问题、客户如何受益以及哪些具体的情感或身体需求得到满足是很重要的。
请问以下问题:
-
我们为客户提供了什么价值?
-
我们要解决客户哪些问题?
-
我们为每个客户细分提供哪些产品和服务组合?
-
我们在满足哪些客户需求?
为了确保您开发出以客户为中心的产品,确定您企业的独特价值主张至关重要。然而,正如我们将在后续章节中看到的,您的初始价值主张——或者如埃里克·里斯所说的“价值假设”——在您开始从实验中学习后可能会演变或甚至转变。
客户关系
了解互动的本质有助于绘制客户的旅程图以及他们与应用的接触点,因此思考整个体验是有用的。
请问以下问题:
-
我们每个客户细分期望我们与他们保持哪种类型的关系?
-
我们已经建立了哪些?
-
他们如何整合到我们的商业模式中?
-
它们有多昂贵?
考虑到大多数实用型应用的本质涉及 DIY 自助服务关系。像 Uber 或 Ola 这样的应用涉及通过出租车司机的个人协助。Waze 使关系具有共创性和社区方面。了解用户如何使用您的应用将帮助您创建更易用、更有用的应用。
客户细分
对于您正在制作的应用,您要具体针对谁?您需要回答如下问题:
-
我们为谁创造价值?
-
我们对他们的了解有多少?
-
我们最重要的客户是谁?
您对目标受众的定义可能会在长期内扩大。
例如,一个类似 Uber 的应用可能旨在为所有寻求即时交通的通勤者创造价值。然而,正如我们将在后续章节中探讨的,高度具体化使得测试和增长变得容易得多,这是确定您最重要的客户之所以重要的两个原因。在 Uber 的案例中,这些可能是在纽约金融区(一个已经有很多人使用出租车的城市)的年轻职业人士(愿意为他们的时间支付溢价)。
渠道
渠道的重要性往往被低估。正是通过渠道,用户才会了解到你的应用,理解为什么他们必须安装它,并养成在需要时提醒他们使用它的习惯。
在填写这一部分时,请自问以下问题:
-
我们的客户细分群体希望通过哪些渠道被触及?
-
我们目前是如何触及他们的?
-
我们如何整合我们的渠道?
-
哪些效果最好?
-
哪些是最具成本效益的?
-
我们如何将它们与客户习惯相结合?
我们将在本书的后面部分进一步讨论渠道,但这些问题将帮助你迈出正确的第一步。
成本结构
成本结构指的是业务费用,如工资、资源和基础设施。考虑以下问题:
-
我们商业模式中固有的最重要的成本是什么?
-
哪些关键资源成本最高?
-
哪些关键活动成本最高?
对于软件公司来说,成本的主要驱动因素是员工工资。在某些情况下,基础设施成本可能很高,可能是一个重要的考虑因素。如果你的产品涉及硬件,如物联网设备,成本结构可能会更加复杂。在考虑开发者的成本时,选择 iOS、Android 和其他移动平台可能是一个因素。
收入流
可持续性和可行性是每个企业的基本问题,你的移动应用也不例外。弄清楚你的收入模式以及理解你如何将辛勤工作货币化通常是这个谜题中一个棘手的部分。
请自问以下问题:
-
我们的客户真正愿意为哪些价值支付?
-
他们目前为哪些东西付费?
-
他们目前是如何支付的?
-
他们更喜欢如何支付?
-
每个收入流对总收入贡献了多少?
一些应用仅通过广告就取得了成功。其他一些通过免费增值模式或应用内购买取得了巨大成功。最后,还有资产销售,这可以与其他货币化方法一样有利可图。
示例:BMC - 移动市场应用
这里有一个连接音乐学生和音乐教师的移动市场应用的 BMC:

这张图表只是展示如何使用 BMC 来制定商业计划的一个例子。更多例子可以在网上找到。
BMC 摘要
商业计划是一个很好的方式来阐明你的想法,向潜在投资者或利益相关者展示这些想法,并建立业务指南以帮助你走上正轨。
然而,有些人对 BMC 有极端的反应。他们要么非常喜欢它,并认为它是一个商业计划的极大简化版本,要么讨厌它,认为它是一个复杂的理论抽象,非常适合作为研讨会练习,但不是一个实用的工具。
结果表明,大多数人更容易接受 BMC 的一个有趣变体。我们将在下一节中探讨这个变体。
精益画布
2009 年,阿什·莫里亚提出了精益画布。精益画布受到了 BMC 的启发,以及罗伯特·菲茨帕特里克的一个变体,该变体结合了史蒂夫·布莱克的《启示四步》中的工作表。
“大多数创业公司失败,并不是因为它们没有建成他们最初设定的产品,而是因为他们在构建错误产品时浪费了时间、金钱和精力。”
- 阿什·莫里亚
阿什·莫里亚的n变体是为测试新想法的创业者和内部创业者量身定制的。精益画布帮助你测试需要验证的关键假设,以便你找到产品/市场匹配:

一个重要指标
本·约斯科维茨和阿里斯特·克罗尔在他们所著的《精益分析》一书中详细阐述了他们的一个重要指标(OMTM)的概念。
这个概念——关注一个重要指标而不是多个指标——旨在帮助企业家简化并保持专注。根据作者的说法,这意味着在任何给定的时间,都应该有一个你更应该关注的指标。将这种关注传达给你的员工、投资者甚至媒体将真正帮助你集中精力。
这是一个强大的隐喻,有助于在组织内部就关注点提供清晰的指导。现在,困难的部分通常是决定哪个指标最重要。幸运的是,他们的书涵盖了各种例子,根据公司阶段和业务性质等标准,以帮助作为选择正确指标的指南。
我们对前面图表所做的唯一改变是将精益画布中的关键指标与 OMTM 交换:

敏捷开发和客户开发
精益创业的核心 DNA 是一个美丽的螺旋。这个螺旋的两个环关注两个位于精益方法论核心的思想——敏捷开发和客户开发。结合这两个方法,使开发者能够创建真正以用户驱动的产品。
螺旋的外环涉及与市场合作,发现客户需求及其产生的背景,并测试可能的解决方案是否满足这些需求。这个循环最初由史蒂夫·布莱克提出,被称为客户开发。
内环涉及由客户开发确定的客户需求的快速迭代软件开发周期,并开发满足这些需求的解决方案:

敏捷开发在过去十年中已经成熟,Scrum 和 XP 现在在许多组织中都很常见。敏捷彻底改变了习惯于在大型的瀑布式发布中构建软件的组织,将它们转移到迭代模型。这使得团队能够更紧密地与客户合作来构建软件。
与瀑布模型通常期望问题定义是固定的不同,敏捷实践者假设问题定义可能有些灵活。请注意,在两种情况下,解决方案都是未知的。工程团队通过紧密的循环迭代解决方案定义,理解问题定义可能会在过程中演变。
虽然瀑布模型和敏捷开发都假设对问题的定义有一定程度的确定性,但客户开发完全是关于问题发现。我们从通过客户发现探索未知问题开始,这是一个开放式练习,旨在寻找未满足的需求。然后,这导致与客户进行快速循环的工作,以验证他们的需求,并扩展模型。
将这些想法结合起来应用,将使你能够对客户反馈做出响应,更快地适应,并创造客户喜爱的有用产品。你在这个方向上的第一步将是一个实验,测试关于你的商业计划、客户和应用程序想法的假设。
MVP
这个实验被称为最小可行产品(MVP)。MVP 是一个重要的概念,它与传统的大爆炸式方法不同,后者是先构建一个精良的产品,然后再将其推向市场。它代表了在产品中需要构建的最小功能集和功能,以便测试市场可行性和最大化验证学习。
MVP 及其后续迭代最初设计用于测试两件事:客户是否会重视你的产品,以及你的产品扩展的难易程度。
当然,困难的部分通常在于决定你需要多小。初始测试可以是简单的着陆页、交互式线框或功能原型。关键是创建一个 MVP,以测试你在 BMC 中创建的假设的有效性。
例如,一个推广不存在产品的着陆页是一种低成本的方式,可以让你试探市场。它可以测试你的目标受众是否对你的解决方案和价值主张感兴趣。你还可以通过原型来衡量口碑推荐,例如,看看你的解决方案的可扩展性如何。
当被问及“最小化”意味着什么时,埃里克·里斯曾回应说,“比你想象的还要最小化”。但对于许多注重推出精良作品的开发团队来说,这可能是一个挑战。如果他们认为产品不完整,他们可能会犹豫是否将其提交审查和测试。
潜在的恐惧是害怕批评或被拒绝,这是人类的一种自然反应。重要的是要认识到,批评和拒绝是旅程的一部分。
如果你想改进,理解哪些批评和反馈需要采取行动是很重要的。不可避免的是,将产品的最小可行版本推向市场可能会导致关于你可能没有关注的领域的批评性反馈。这就是平衡、实用方法重要性的地方。你可能会选择忽略这些领域的反馈,因为这是你做出的一个有意选择。
然而,MVP(最小可行产品)的发布是有原因的:为了获取关于你某些问题的信息,以及看看你是否正在朝着开发客户想要并能使用的产品的正确方向前进。关注你关心的领域的反馈,以揭示惊喜和数据,这些数据将引导下一轮测试,这是很重要的。
在未来的章节中,我们将看到关注反馈是有效实施构建-度量-学习循环的关键。每一次新的迭代都会为你提供更多的反馈,这些反馈可以用来测试和改进未来的发布。
摘要
在本章中,我们快速介绍了精益创业的关键要素。首先,我们学习了 BMC(构建-度量-学习循环)是什么,它是如何发展的,以及它的好处是什么。然后我们研究了 BMC 的一种变体——精益画布,并讨论了敏捷开发和客户开发如何协同工作。
在下一章中,我们将探讨精益应用开发者面临的一些挑战。
第三章:将精益应用于构建移动应用时的挑战
在上一章中,我们讨论了精益创业的一些核心原则。我们讨论了商业模式画布、敏捷开发、客户开发和 MVP。
在本章中,我们将深入探讨本书背后的基本前提,并探讨作为精益应用开发者将面临的一些最大挑战。虽然关于精益的书籍有很多,但将精益应用于构建移动应用相对是一个新的领域。接下来,我们将介绍其中一些核心挑战,其中许多将在本书后面的部分详细回顾:
-
与开发网络应用相比,应用开发者面临更高的设计标准
-
应用商店的提交周期,这会在你的完成迭代和它们对公众开放的时间之间造成延迟
-
开发多个平台带来的挑战
-
早期测试者面临的困难,以及这如何使得扩大早期用户基础变得困难
-
应用评分,这对你的用户基础增长和运行某些类型实验的能力有直接影响
让我们深入探讨一些主要挑战,看看为什么它们对于一个寻求应用实验的开发者来说非常重要。
更高的设计标准
从 2000 年代中期的普通网络应用中脱颖而出,苹果通过 iPhone 彻底改变了移动世界,提供了自己精心设计的应用,并精选了被 App Store 接受的应用。多亏了苹果对设计的更高标准,消费者开始期待直观、设计良好的应用。这种影响非常深远,促使谷歌推动其边界,开发出材料设计,这是一种已成为 Android 应用独特标志的设计语言。
与网络世界相比,其中一些流行的应用可以忍受平庸的设计,移动应用面临着更高的设计标准。
精益开发者试图通过简单的实验来验证一个初步的概念。然而,应用的基本价值可能会被糟糕的设计和体验所掩盖,导致错误的否定结果。
另一方面,对错误否定的恐惧可能会让开发者走上添加过多抛光以测试假设的道路。
正如我们稍后将警告的那样,避免分析瘫痪和过早的完美主义非常重要。目标是找到一个合适的平衡点,即一个设计糟糕的原型可能会干扰测试和数据,以及一个过度抛光的 app 可能会浪费你的时间和金钱。
苹果应用商店的提交周期
苹果应用商店的审查流程——比谷歌 Play 更严格——可能会在应用迭代准备发布和实际上线之间造成重大延迟。这种滞后会带来头痛,使得时间难以把握,并延长了从客户那里学习的时间。
使用 Web 应用,开发者可以在早餐时边喝咖啡边进行实验,然后在上班前将其回滚。一系列支持持续集成和持续部署的工具使得在 Web 领域具有显著的敏捷性。
然而,移动应用开发者常常需要等待数周,有时甚至数月,才能看到他们的应用在 App Store 中列出。苹果严格的审核流程让开发者感觉与墙对话可能更好。
在 App Store 的早期,公司争先恐后地与苹果建立关系,以确保他们的提交能够顺利通过。我记得应用提交需要数月,需要我们团队与苹果分类领导之间进行多次电子邮件交流:

幸运的是,时代已经改变,如今苹果致力于快速审核。
然而,如果有疑问,可以查看www.appreviewtimes.com以了解 iOS 和 Mac App Store 的平均审核时间。在撰写本书时,审核时间以天为单位,但节假日和重要苹果公告发布时变化很快。
精益开发者必须考虑 App Store 的提交周期,他们专注于缩短完成构建-度量-学习循环的时间。当你不确定何时可以开始与用户进行实际测试时,进度可能会迅速停滞。App Store 不可预测的特性使得难以保持节奏和速度进行敏捷循环,并且快速与客户完成闭环。
无法动态加载库
原生应用开发工具链仅允许静态链接库。这意味着没有直接的方法将库组件动态加载到你的应用中,就像 Web 开发者可能会选择在网络上动态拉取不同的 JavaScript 模块一样。
在 iOS 的情况下,有一些技巧可以通过加载库。默认的 iOS Xcode 设置不允许你创建动态库,但可以通过复制 MacOS 设置来解决这个问题。然而,虽然这可以在本地进行测试,但在代码签名时会出现障碍,内核会杀死未使用相同证书签名的苹果应用库。话虽如此,由于应用审核过程禁止动态加载,它不太可能通过他们的清单。
可以尝试和测试这种或网上可以找到的其他解决方案,看看它们是否能够通过提交流程。然而,如果它们不成功,为你的应用开发静态加载策略可能是有益的:

在 Android 的情况下,有一些类似的技巧可以通过 Dex 文件加载、提取和调用。这是因为 Dalvik 虚拟机允许从本地存储或远程网络等不同位置进行一定程度的自定义类加载。然而,这并不适用于所有应用,并且在正确处理所有场景时具有一定的复杂性。
与网页开发者可以轻松切换开关并更改仪表板上渲染的组件不同,应用开发者需要进行杂技般的操作。如果他更愿意专注于他应用的核心问题,他需要将新的应用版本推送到市场,然后等待用户下载新版本。
在实际情况下,这可能意味着在实验开始之前需要几周到几个月的时间才能达到目标用户群。尽管这种延迟可能会非常成问题,但在后面的章节中,我们将讨论工作流程和技术,可以帮助你绕过这些技术障碍。
跨平台发布
如果你正在推出一款新应用,需要在 iOS 和 Android 之间快速做出选择,这很快就会成为一个早期决策点。如果你是自筹资金,你可能会最终选择其中之一。虽然存在混合解决方案,但它们可能会牺牲一些体验方面的内容。我们将在第九章原生、混合或跨平台中讨论混合与原生的问题。
网页开发者大约十年前在浏览器大战中遇到了某些类似的问题。为 IE、Mozilla 和 Opera 开发感觉有时像是三个完全不同的浏览器。推出新产品时,开发者通常需要谨慎行事,一开始只专注于一个流行的主流平台。
对于移动应用开发者来说,一开始只选择一个平台适用于许多实用型应用。然而,许多应用,如即时通讯应用,涉及到与社区中其他人的互动。在实验环境中,这很快就会变得困难,因为它要求其他人使用相同的平台。在招募用户进行测试时,这也会变得稍微棘手一些,因为你需要专注于那些使用你目标平台的用户。
在本书的后面部分,我们将探讨跨平台应用与原生应用之间的利弊,然后讨论选择正确方法的技术,以适应你的初始业务。
让用户下载应用
作为网页开发者,让某人查看你的应用就像发给他们一个链接并请他们告诉你他们的想法一样简单。你甚至可以与他们进行 Skype 电话通话,让他们在浏览应用时与你共享屏幕,并观察他们的互动。
另一方面,对于移动应用来说,一个重大的障碍是让用户去商店下载你的应用。你可以发送链接给他们,但他们随后必须跟随链接到相关的商店,完成下载过程,然后访问应用以进行测试。iOS 通过要求密码才能下载应用,使得这个过程变得更加困难。
无论你如何招募用户进行实验,尽可能使一系列步骤尽可能无缝是很重要的。在第十一章,入职和注册中,我们将讨论如何通过使用 TestFlight、HockeyApp 和 PlayStore 的 Alpha/Beta 频道等服务来简化入职和测试流程,以减少这种摩擦:

这些工具将有助于简化此过程,但如果目标受众不是技术达人,那么这个过程仍然不太顺畅。针对早期采用者,本书后面也会讨论这一点,这是帮助你找到那些对您的应用有足够需求以克服入职摩擦的用户的一种方法。
维护应用评分
如果你已经在你的应用上拥有大量的用户基础,你可能会受到在应用商店上保持 4+评分的压力。应用评分决定了你的应用可能被突出显示在列表和搜索结果中的可能性,这与你有机扩大用户基础的能力有自然的直接相关性。
例如,在像 Intuit 这样的公司,尽管在税务季节期间会进行许多实验,但随着评分下降,保持评分在 4.0 以上的下载压力显著降低:

运行实验,这些实验对于你的应用进化是必要的,可能会对评分产生不确定的影响。
当将精益方法应用于应用开发时,健康的评分和持续的实验都是必要的。然而,由于评分降低会对用户获取产生负面影响,你需要找到一种方法来最小化这种影响。在可能破坏性实验和良好评分之间找到平衡是一个持续的挑战,尤其是在应用成熟之后。
在早期阶段,快速行动并打破常规是有效的。然而,对于一个评分健康、用户基础稳定的应用来说,进行可能降低评分的实验可能很难合理化。毕竟,较低的评分降低了你的应用被突出显示或获得编辑推荐列表的可能性,这两者都可以极大地增加曝光和下载量。
向其他团队领导证明实验的合理性可能具有挑战性,但在应用已经建立之后,这可能是必要的。毕竟,应用越成功,它获得竞争的可能性就越大。稍后,我们将讨论进行分割测试的方法,这些测试可以提供有用的数据而不会造成太大的破坏。
摘要
将精益方法应用于移动应用开发并不容易。存在一些独特的挑战,这些挑战阻碍了与客户进行紧密的构建-度量-学习循环,并最大化验证学习。在本章中,我们讨论了一些最大的挑战,例如平台、应用商店以及用户自身所提出的挑战。
在下一章中,我们将探讨为什么你应该采取务实的应用开发方法,如何在务实的同时保持结构化,并且我们将探讨一些现实世界的工具和技术,以帮助你保持专注和实用。
第四章:敏捷工作流程概述
在本章中,我们将讨论敏捷开发,以了解它是什么以及我们如何从中受益。
许多公司在开发软件时已经远离了瀑布式方法。他们转向了更适应的方法,如敏捷开发,并且有充分的理由。瀑布式方法只是遵循原始计划和需求,几乎没有改变的空间。显然,这种方法不适合你的应用程序。除非你有一个水晶球,并且从一开始就正确无误,否则这种方法很可能会导致大量的浪费。
敏捷工作流程通过适应性计划适应变化,促进更快的软件开发和交付,并基于持续改进的方法。这正是你需要验证你的假设,并在必要时进行转变的地方。
有许多敏捷软件开发方法的实现。它们都侧重于适应能力和尽快交付可发布软件的能力。其中一些特别关注管理工作流程。最常见的一种是敏捷 Scrum。我们将更深入地研究这种方法,看看它如何与精益软件开发很好地结合。
具体来说,在本章中,我们将学习以下主题:
-
敏捷工作流程
-
精益软件开发、看板和敏捷开发
-
史诗、故事和任务
-
敏捷团队和每日站立会议
-
后续改进和就绪状态的定义
-
迭代计划
-
完成定义
-
迭代回顾、计划和反思
-
你可以使用的一些工具,例如 Trello 和 Jira
敏捷工作流程
使用敏捷工作流程可以帮助你的团队保持灵活,能够快速响应变化。这也意味着你的团队是自我组织的,团队成员能够尽早和经常交付。
良好的沟通是敏捷开发的基础,你的团队成员必须与产品负责人、利益相关者和彼此良好合作。你的应用程序的用户也需要从一开始就参与进来。他们的反馈至关重要,对于你做出正确的应用程序开发决策至关重要。最后,在任何时候,你都应该能够交付一个可工作的软件版本。良好的 Git 工作流程和能够持续交付是这里的关键要素。你将在第十九章构建不公平优势中了解更多关于这一点。
所有敏捷方法共同之处在于它们都促进了改变的能力,在过程中持续学习,并尽快交付软件。
一些敏捷软件开发方法如下:
-
精益软件开发
-
看板
-
敏捷开发
还有更多方法,但这些都是最有趣的。当然,精益软件开发是本书的重点。该方法的要点是:
-
尽早交付
-
尽可能晚做决策
-
通过持续交付收集早期反馈
我们将在下一章中了解更多关于所有这些元素的内容。与其他方法不同,精益更专注于避免浪费。
但是,让我们先从基础知识开始。精益软件开发、看板和敏捷开发有很多共同之处。在本章中,我们将更深入地探讨看板和敏捷开发,并在本书的其余部分讨论精益。
看板
看板是一种可视化每个动作流程和当前状态的方法。每个参与者都可以看到从开始到结束的进度。团队成员在容量允许的情况下开始工作。与敏捷开发不同,由于它是一个连续的过程,因此不需要预测。
�看板是一种使用看板板进行可视化的方法。这种方法起源于精益制造(受到丰田的启发),但通常也用于软件开发。在其最基本的形式中,它包含三列,反映了每个项目的状态——待办、进行中和已完成。请注意,保持进行中列的项目数量最小是很重要的。实际上,人们并不擅长多任务处理,尽管他们认为自己可以。切换上下文会增加浪费,应该避免。
创建看板板你所需要的一切只是一个空白的墙和若干张便利贴,但你也可以使用像 Trello 这样的软件服务。如果你在www.trello.com注册,你可以免费设置自己的项目并定义多个通道。在这个例子中,使用 Trello 设置,每个人都可以清楚地看到每个项目的状态。根据需要,你可以定义额外的通道:

在看板中,工作流程是连续的,但在敏捷开发中,工作被划分为持续特定时间的事件。敏捷开发使用看板板,但增加了预测元素。
敏捷开发
敏捷开发是一种为小型团队设计的软件开发管理方式。团队成员在固定周期的循环中完成一系列动作,这个周期被称为冲刺。冲刺被限制在特定的持续时间。通常持续时间为一周到一个月,两周是最常见的。冲刺的固定长度很重要,因为它允许团队在几个冲刺之后确定他们的速度,即他们完成工作的速度。
在冲刺开始时,团队决定在给定的时间框架内可以完成哪些任务。经过几个冲刺后,由于团队将更好地了解他们的工作,因此做出适当的估计会更容易。了解团队的速度将使团队更容易对故事进行估计,并确保团队真正承诺完成给定冲刺中定义的所有故事(它是可完成的)。
该方法论强调在冲刺结束时有一个可行且可能发布的软件产品。这意味着软件不仅已经开发,而且已经过测试和集成。应该能够展示应用程序,对测试人员进行临时分发,甚至可以在 Play Store 或 App Store 中发布应用程序或更新。
英雄,故事和任务
英雄是一大批几乎总是跨越多个冲刺交付的工作。英雄通常是对功能的高级描述。它不包含具体细节。通过客户反馈,团队可以了解完成英雄所需的内容。一个英雄的例子可能是:作为应用程序的用户,我希望能够在应用程序中设置和审查一个商业模型画布。
英雄是一个功能或功能的概述性描述。由于缺少具体细节,团队需要了解更多关于英雄的信息,通常这会产生多个故事。解决英雄定义的问题可以成为一个故事。
用户故事应该尽可能小,同时仍然提供业务价值。用户故事通常从应用程序用户的角度编写,并使用自然语言描述。它们用几句话描述一个特定的功能,概述期望的结果。这可以帮助团队理解特定期望功能的目标和上下文。
一个故事可能包含一个或多个任务。这些任务可以非常具体地描述为了完成故事需要采取哪些行动。一个任务的例子可能是开发一个编辑框,用户可以在其中编辑文本或添加一个“保存”按钮,并持久化编辑后的文本。指定验收标准也很重要。如果你清楚地定义了故事或任务实施的结果应该是什么,那么你的测试人员接受(或拒绝)新功能将变得更加容易。
Scrum 团队
对于 Scrum 方法,你通常会找到三个主要角色,尽管一些组织可能会定义其他角色,除了这里列出的那些:
-
Scrum 大师
-
产品负责人
-
开发团队(包括测试人员)
Scrum 团队有一个产品负责人。他或她负责确保团队交付所需的业务价值。为此,产品负责人是利益相关者和(技术)团队之间的联系人。产品负责人主要关注业务方面(问题定义)。产品负责人定义用户故事并将它们添加到待办事项列表中。
用户故事描述了需要实现的功能。你可以将待办事项列表视为待办事项清单。团队必须对这些项目做出承诺,并且每个项目都需要一些细化,以明确实现特定功能的确切需求。专注于寻找解决方案的团队将为此提供反馈。待办事项列表也需要优先排序。这种优先排序通常基于特定功能对最终用户(价值)的重要性。
产品负责人向利益相关者展示应用程序,并定义应用程序的里程碑和发布。他或她还向利益相关者通报应用程序的开发情况,并在资金、范围和优先事项的谈判中扮演重要角色。产品负责人需要能够有效地沟通。他/她需要在利益相关者(和最终用户)的利益与与团队成员的合作之间找到平衡,以确保他们为利益相关者发现或定义的问题开发正确的解决方案:
这导致了两个完全不同层次的信息。利益相关者通常只对获得问题的解决方案感兴趣。然而,开发团队更希望听到尽可能详细的反馈,这样他们就会知道一个功能应该如何实现。
开发者、测试员以及其他人员都是自组织团队的一员。他们将关心与交付或更新应用程序相关的所有任务。你可以想到的任务包括:
-
设计
-
UX
-
分析
-
技术研究和开发
-
代码审查
-
测试
-
文档
团队承诺进行冲刺,并负责在每个冲刺结束时交付更新并可以工作的应用程序。更新是外部还是内部并不重要。始终应该能够向利益相关者展示新功能。
另一个角色是 Scrum 大师。Scrum 大师确保遵循 Scrum 框架。他指导团队确保团队交付所有冲刺中的功能。他向团队和利益相关者传授 Scrum 原则。Scrum 大师帮助团队消除(或避免)可能妨碍冲刺成功的内部或外部障碍。
Scrum 大师还维护待办事项列表,并确保故事清晰,并且以非歧义的方式定义。团队理解故事的目标非常重要,这样它才能真正取得进展。Scrum 大师的其他重要职责是帮助团队制定“就绪”的定义(当开发团队能够开始处理一个故事时),以及制定“完成”的定义(何时可以推出新功能)。我们将在稍后更详细地探讨这些定义。
每日站立会议
团队在冲刺的每一天都会举行站立会议(也称为每日 Scrum)。这是一个简短的会议,通常限制在 15 分钟(时间盒)。它每天都在相同的时间和地点举行,即使有些团队成员缺席。任何人都可以参加,尽管只有团队成员应该做出贡献。
在站立会议期间,每个成员都会就与冲刺相关的以下三个问题提供答案:
-
我在上个工作日做了什么?
-
我计划今天完成什么?
-
我看到了哪些障碍阻止我或团队达到我们的冲刺目标?
由于会议是时间盒的,因此每个成员专注于这三个问题本身很重要,不应该有详细的讨论。Scrum 大师将被告知会议期间提到的任何障碍。
障碍包括阻塞器、风险、对其他团队或合作伙伴公司的依赖,以及可能的或预期的延迟。Scrum 大师负责移除障碍,或找到愿意或能够找到解决方案的人。一个显示实际障碍的 Scrum 板可以用来记录这一点,因为找到解决方案是需要在站立会议之外发生的事情。
优先级回顾
在冲刺开始之前,需要定义冲刺待办事项。哪些故事需要进入冲刺?为了回答这个问题,团队需要审查产品待办事项。产品待办事项包含完成产品(应用程序)所需的所有行动(故事)。首先,它们需要在团队可以承诺之前进行细化。
每个故事都需要对涉及的工作量进行估算。这种估算通常以故事点数表示,而不是小时数。故事点数与预期的复杂性和工作量相关。通常,一个具体且明确的行为,如按钮上的编辑文本,将被定义为一点故事。这为定义其他更复杂的故事提供了一个基准。所有估算的故事都将由此派生。
要能够分配故事点数,故事必须清晰且被团队充分理解。计划扑克通常被用来让团队成员做出估算。你可以使用卡片进行估算,或者使用许多可用的应用程序之一。
这里有一个这样的应用程序的例子,称为 Scrum Time。你可以在 Play Store 或 App Store 找到它。

作为应用程序的用户,你可以选择一张带有数字的卡片,并将其展示给其他团队成员。如果团队成员之间的估算点数差异太大,那么他们需要讨论为什么他们认为实现和测试一个故事将花费更多(或更少)的时间。也许团队成员中有知识其他人没有的人,或者他可能以不同的方式看待这个故事。新的见解可以有助于更好的估算。
可选的数字通常来源于斐波那契数列。在数学中,斐波那契数列的特点是每个数(从第三个数开始)都是前两个数的和。这里使用这些数字的原因是,故事越大(拥有更多的故事点),精确估算的难度就越大。如果你没有任何线索,你总是可以玩疑问卡,或者如果与故事相关的行动是无限的(想想提供支持),那么也有相应的卡片。是的,如果你渴了,你总是可以玩咖啡/暂停卡。
1、2、3、5 和 8 的卡片是最常被使用的。拥有更多点的故事很可能需要拆分成多个较小的故事以降低风险。
准备定义
产品负责人负责将故事添加到待办事项列表中。在待办事项细化过程中,团队必须提供反馈,以便将每个故事转化为可执行的状态。待办事项列表顶部的故事,以及即将到来的迭代中的候选故事,必须准备好。如果你希望提高团队的生产力,拥有一个清晰的准备定义(DoR)是非常重要的。
故事需要立即可执行。如果它们不是,那么如何实现或测试一个特性呢?目标必须明确,需要完成哪些工作才能实现,以及需要多少工作量。例如,待办事项列表可能包含用户反馈,如:“我们希望能够更快地创建新的发票。”这个陈述清楚地定义了一个问题,但如果我们想着手解决它,我们需要更多具体的信息。团队必须能够确定需要做什么。如果我们能说在主屏幕上添加创建新发票的按钮是解决方案,那么我们就可以为它做出估算并开始工作。一个准备好的故事是清晰、简洁且可执行的。
迭代计划
团队选择具有最高优先级且已准备好开始工作的项目。团队只能对具有明确目标且不受其他任何事物阻碍的故事做出承诺。此外,团队在迭代期间只能对有限数量的故事做出承诺。这意味着团队需要知道这些故事将涉及多少工作量,以及迭代期间可以完成多少工作量。
为了确定一个迭代中可以投入多少工作量,我们需要知道团队的速率,这是一个表示团队在一个迭代中能够完成的总工作量的数字。这个数字来自于评估和确定之前迭代中完成的工作的平均量(故事点的总和)。当然,季节性影响(假日)和其他可能决定团队容量的因素也需要考虑。一旦团队承诺开始迭代,就不应该向迭代中添加额外的工作。
完成定义
Scrum 框架规定每个故事应该在每个迭代的结束时完成。在理想的世界里,完成定义(DoD)意味着每个故事都已开发、测试并获得批准,并且你的应用程序当前状态处于可发货状态。我们仍然需要明确这究竟意味着什么。DoD 可能因 Scrum 团队而异,但必须在团队内部保持一致。DoD 可以帮助确保特性得到实施和测试,并且它们的添加确实有助于可发货的应用程序。
定义也可以包含其他行动的列表,例如代码审查、运行单元测试和 UI 测试、编写文档以及临时或公开分发。每个行动都应该为产品增加可验证的价值。这有助于团队专注于哪些特性重要,同时避免浪费的活动。
迭代回顾、规划和反思
每个迭代的末尾都有几个事件:迭代审查和迭代反思。还有下一个迭代的迭代规划。
在审查中,团队审查所有已完成的工作,并向利益相关者展示。他们还审查尚未完成的工作。
对于即将到来的迭代,有迭代规划事件。在此事件期间,团队和利益相关者共同努力确定哪些特性可以在迭代中交付,以及如何实现。
反思用于回顾过去迭代,以便团队可以随着时间的推移学习和改进。一般来说,向每个成员提出的主要问题是:
-
迭代中哪些方面做得好?
-
下一个迭代中需要改进的是什么?
Scrum 大师主持活动,并帮助团队确定需要采取哪些行动来改进事情。对于反思,你可以使用 Jira 等工具,但通常使用便签纸效果会更好。
需要改进的任何内容都将被优先考虑,并为前三个问题定义行动。
到现在为止,你对敏捷工作流程和 Scrum 有了基本的了解。要了解更多关于 Scrum 的信息,你可以访问www.scrum.org。
你可以使用的一些工具
你可以使用多种工具来支持、自动化和可视化流程。Jira 和 Agilefant 是知名的基于 Web 的解决方案,可以帮助你定义史诗、故事、估算和迭代。大多数工具也提供将(子)任务添加到故事中的选项。尽管故事应该是可能的最小工作量,但将它们分成多个子任务仍然是有用的。
你可以在www.atlassian.com/software/jira找到更多关于 Jira 的信息。Agilefant 可以在www.agilefant.com找到。
以下是一个 Jira 显示看板板的示例。Jira 特别支持敏捷和 Scrum,而 Agilefant 则更不拘泥于特定方法:

如果你刚开始,可能还不需要所有这些工具。在这种情况下,一块白板和一些便利贴就足以创建你的第一个看板。当你的团队成员都在同一空间工作时,这个看板非常有用。当你有一个分布式团队时,Trello 是一个不错的选择。它不如 Jira 先进,因为它不支持 Scrum,但它是一种有组织地开始的好方法。
要开始使用 Trello,请注册trello.com/,创建一个新的团队和项目,然后你就可以开始使用了。就像 Jira 一样,你可以在 Trello 中创建多个通道,每个通道都反映了卡片/项目的实际状态。正如之前所说,你可以从待办、进行中和完成通道开始。然而,你很快就会意识到仅这些状态是不够的。
如果你配置以下通道,你将为 Trello 中的敏捷工作流程提供一个不错的起点:
-
需求列表
-
准备就绪(故事清晰,理解良好,没有障碍)
-
开发中(开发和测试)
-
测试
-
完成(已测试并批准)
它可能看起来像以下示例。你还可以添加更多通道,例如代码审查,或者最适合你组织的任何内容:

所有故事都从需求列表通道的卡片开始。一旦你清楚地定义了目标,故事就准备好开发。然后你可以将卡片移动到准备就绪通道。当开发者接手故事时,他会将卡片移动到开发通道。目前,实现已完成,故事的单个测试(s)成功,卡片将被再次移动,例如,移动到测试通道或可选地首先移动到代码审查通道:

如果对已实现功能的手动或自动化 UI 测试成功,则可以将故事视为完成,这对应于最终通道。
这当然只是一个简化的流程,并且像 Jira 这样的工具为敏捷和 Scrum 工作流程提供了更好的支持,包括史诗和估算。尽管如此,Trello 对于新手来说仍然是一个不错的起点。Trello 提供了添加标签和定义过期日期和时间的选择。你可以用它用于多种目的,甚至像前面的截图所示,设置史诗和估算。史诗以绿色标签显示,估算的故事点以蓝色显示。
在后面的章节中,你将了解到其他可以帮助你组织敏捷工作流程的工具。想想 Confluence。就像 Jira 一样,它是一个 Jetbrains 基于 Web 的解决方案,允许你组织所有的文档和讨论。
摘要
在本章中,我们简要介绍了敏捷和 Scrum 工作流程以及你可以从中获得的好处。我们现在知道你可以如何使用看板来可视化每个工作项的状态,以及敏捷工作流程的一些可能的实施方式。特别是,我们探讨了 Scrum,存在的不同角色,以及 Scrum 环境所需的规划和估算。
你可能会认为这一切都很有道理,但如果资源有限和时间紧迫,实施起来将会很困难。我们该如何将浪费降到最低,同时仍然采取非常务实的方式行动?你将在下一章中了解到所有这些内容。
第五章:实用主义方法
你已经做出了一些惊人的举动!你知道你热爱什么,也许你已经创建了一个非常初级的最小可行产品(MVP)。这可能是一个网站、一个调查,甚至可能是一个非常简单的应用。它实际上是如何表现出来的并不重要。这里唯一重要的是,它应该是可以证明你的假设并且只需要最小努力的东西。从你得到的反馈中学习,并找出你最早的假设是否正确。如果是这样,那么是时候进行下一步了。
在本章中,我们将看到如何继续前进以及如何应对创业公司面临的最大挑战之一。时间和时机至关重要。这对自筹资金创业公司尤其如此。我们将探讨在没有任何东西的情况下以及当最重要的资源(时间和金钱)非常有限时如何完成任务。你需要的是正确的思维方式和非常实用主义的方法。
你不需要一个巨大的办公室和所有那些花哨的东西。同样,你不需要很多规则,但大多数时候事情不会自动发生。无论如何,我们需要一些规则,无论你的创业公司多么酷。实用主义方法是在完全混乱和官僚主义之间的良好平衡。你将保持对想要达成的目标的清晰关注,开发新功能不会比你严格需要的更长。这种方法将导致在应用特定阶段开发所需的功能。
在寻找产品解决方案或产品市场匹配时,创业领域没有捷径可走,但作为开发者,你通常不需要重新发明轮子。大多数情况下,现成的解决方案都广泛可用。例如,在第八章,云解决方案用于应用实验中,我们将调查哪些方提供移动后端即服务(MBaaS),而在第十章,有 API 就能做到!中,我们将探讨各种混合创意。这些解决方案无论你是用来构建最小可行产品(MVP)还是在整个应用生命周期中使用,都能节省大量时间。
具体来说,我们将涵盖以下主题:
-
了解时间 boxed 编程的好处
-
看看从无到有开始有哪些选项
-
展示如何保持事物结构良好
-
调查是否存在任何捷径
时间 boxed 编程
对于每个迭代,你需要决定它将花费多长时间以及将包含哪些特性。正如你在第四章,“敏捷工作流程概述”中看到的,典型的冲刺需要 2 到 3 周。虽然一开始可能很难,但很快你就会学会在这样一次冲刺中你能和你的团队成员完成什么。有时你甚至不知道一个特性的开发需要多长时间。在这种情况下,时间盒方法也能帮助你。在你开始工作之前,你分配一个特定的时间。之后,你可以确定你完成了什么,并决定是否可以以当前状态发布该特性。即使它不完全功能,只要它不包含(严重的)错误,它也能帮助你获得早期反馈。
保持简单,只为特定迭代开发你真正需要的特性。你应该问自己你想要证明什么,以及你需要什么样的反馈来继续前进。同样,当你审视你的应用当前阶段时,了解这些反馈的相关性很重要。例如,如果你的应用的基本功能尚未完成,你不应该过多关注 In-App Purchase 功能的开发。
“你不会需要它”,也称为 YAGNI 缩写,是敏捷开发和极限编程(XP)背后的理念之一,但这也同样适用。
目标始终应该是以最少的努力实现最大的学习。此外,保持简单,一次只解决一个产品和一种类型客户的一个问题。作为一名开发者,你经常会预见需要支持的场景,所谓的“不愉快流程”,但如果“愉快流程”还没有准备好,谁会在意它们呢?
考虑到时间盒的概念更多地关注于花费的时间而不是完成的任务。因此,与其思考应该在特定时间内完成的特性,不如思考在特定时间内可以实施哪些特性。为了最大化学习,你应用的新版本带来的变化应该尽可能小,同时仍然提供相关的商业价值。时间盒编程对于确保资源在特定时间内交付至关重要。为每个时间盒迭代确定可交付成果和截止日期。使用这种方法,你的生产力将得到提高,你也能对你的客户做出承诺。
通常,了解你的(潜在)客户。更多地了解他们的问题。这是你的应用需要解决的问题。这可能听起来像是你的更商业化的联合创始人的工作,但更好地理解这一点也会使你成为一个更好的开发者。提出问题,找出所有客户的共同问题。
客户服务
重要的是要意识到,你创建的解决方案中的一些部分可能是必不可少的,但可能并不一定是立即自动化的好候选者。这些部分也可以手动提供。这样的解决方案被称为礼宾服务,或称为礼宾最小可行产品(CMVP)。乍一看,这并不真正对开发者有太多意义。你可能认为精益创业方法论是关于最小化浪费的,所以 wonder 为什么我们应该手动处理事情?
事实是,手动处理事情确实不太高效,但就目前而言,这还是可以接受的。这是一个短期解决方案,可以帮助你获得新的见解,并学习如何解决用户或客户的问题。一旦你完全理解了问题,并知道解决方案应该是什么,那么自动化就到时间了。
如果你花上 3 个月时间开发一个令人惊叹的功能,然后发现你的应用似乎并不了解用户的问题,会发生什么?这可能会对所有利益相关者造成巨大的失望,你也会 wonder 为什么会发生这种情况。你应该始终问自己是否拥有解决该问题的所有必要信息,以及你是否理解了客户的需求。如果不是这样,你的努力可能会导致交付一个没有人想要的产品。你可能需要大量重构,或者从头开始。这样的活动将是浪费时间(而且如果你运气不好,你的信誉也会受损)。
它是糟糕的还是完美的?
你之所以关注最重要的功能,是因为它们有助于你想要证明的假设。然而,这并不意味着你的产品必须是糟糕的。采用时间盒方法可以帮助你经常(每天或每周)按时交付。
你将提供的功能可能不会完美,但每次新的迭代都可以改进它们。当然,你将不会有第二次机会来留下第一印象,但追求完美并不能帮助你证明你的假设。相反,它将阻止你尽早获得反馈。然而,选择你的第一批用户非常重要。早期采用者与主流用户非常不同,他们有不同的期望。因此,在要求早期采用者测试你的解决方案时,管理期望非常重要。诚实地告诉他们你的初创公司处于哪个阶段,告诉他们解决方案是为了最大化学习而构建的,你非常希望得到他们的反馈。这可能听起来有点严厉,但最终完美是不存在的。早期采用者的意见很重要,你的意见并不真正重要。
早期快速发布
早期快速发布——例如,每周一次或每两周一次——将最大化你的学习。时间盒编程可以帮助你交付重要的功能。
下图中所示的循环被称为构建-度量-学习反馈循环。如果你知道你的早期采用者,获取反馈很容易。但是,如果你正在开发一个应用程序,这并不总是可能的。有许多工具可以帮助你获取分析数据。在第十三章,应用商店和应用程序商店技巧中,我们将了解更多关于这些工具以及如何通过指标收集反馈:

你如何从无开始?
一张空白页,一个基本想法,以及一个早期的最小可行产品(MVP)。这就是开始的方式,但这并不完全是一无所有。但这并不意味着它是一家公司,或者一个应用程序,当然,它也不一定伴随着客户,除非你有一个真正令人信服的 MVP 或一个出色的生产解决方案。
鸡生蛋问题
根据你正在开发的应用程序类型,迟早你会面临著名的“先有鸡还是先有蛋”问题。简单来说,一个依赖于用户生成内容的应用程序在没有用户的情况下将没有内容,而没有内容的情况下也将没有用户。那么,你从哪里开始呢?
任何基于市场的应用程序都必须应对这个挑战,无论是约会应用程序、求职应用程序还是将公司联系在一起的应用程序。但这同样适用于其他类型的应用程序。应用商店中有许多应用程序。它们都在做更多或更少相同的事情,那么为什么你的用户(以及后来,你的客户)要使用你的应用程序而不是其他应用程序呢?迟早你需要找到答案,即“是什么让你的应用程序更好?”你的应用程序是否因为更便宜而更好,它是否提供了更好的服务,或者你的应用程序是否因为拥有庞大的用户群而显得更有说服力?简而言之,因为你刚刚开始,所以你还没有一个拥有许多用户或评价的平台。哦,是的,你确实有一个“先有鸡还是先有蛋”的挑战!

假装直到你做到
为了解决“先有鸡还是先有蛋”的挑战并启动你的应用,有一些简单的解决方案。其中之一是:假装直到你做到。这听起来像是作弊,或者至少听起来像是不好的事情,而实际上并非如此。这是对“先有鸡还是先有蛋”问题的权宜之计。不,我们不会撒谎,最多只是假装。如果你正在开发一个约会应用,让你的所有亲戚和朋友都注册一个有吸引力的个人资料照片。你可以使用这种方法不仅限于用户数据,还可以用于所有类型的内容。如果你正在开发一个面向企业的应用,你可以购买一些公司数据,丰富它,并假装这是你自己的。参考第十章,有一个 API 可以做到!,关于混合应用,了解更多相关信息。另一个可行的选项(例如,想想一个显示工作信息的应用)是从各种其他来源获取数据,并作为一个提供聚合数据的应用开始。有许多方法可以开始,它们都旨在通过开发内容和用户基础来增长你的应用。
成为专家
你也可以通过实践成为专家。你可以开始成为某个利基领域的更重要的一员。只需在学习的过程中成为那个专家即可。例如,当我们开始围绕窄播和社交媒体结合的概念建立我们的新创业公司时,我们对窄播一无所知,除了在商店或火车站经常看到的电视屏幕。通过撰写关于窄播主题的博客,我们学到了很多,并逐渐成为专家。更重要的是,它帮助我们塑造了我们试图解决的问题的愿景。在我们的案例中,这是关于找到答案的问题,我们如何使窄播成为一个更互动的过程?假装可以帮助你设定目标,一旦你达到了它们,就不再是假装,而是真实的。你可以通过这种方式建立你的声誉。这有多酷?显然,你必须保持真实。如果你永远无法满足随之而来的期望,就不要假装,而应该为了争取更多时间、完成工作或成为专家而这样做。如果你保持真实,你的初创公司将成为你所期望的样子。
抓住并适应
几乎所有的初创想法都源于现有的概念。一点增强、不同的定价、服务、UX 或特定的方法可以是独特卖点(USP),这将导致一个独特的产品。同样的服务,但采用不同的营销方法,可以产生完全不同的产品。这是一个你经常看到的趋势。例如,我一直在为一个移动虚拟网络运营商(MVNO)的促进者工作。他们的客户都是不拥有自己基础设施的移动服务提供商。所有虚拟提供商之间最大的区别只是营销策略。任何人都可以用很少的投资从头开始建立自己的网络。你只需要抓取并适应。不过,你必须小心。你需要意识到专利和版权问题,但有许多(开源)项目你可以用作你应用的基座,或者只是一个初期的 MVP。
用很少的钱,你也可以购买一个接近你的初创想法的概念,甚至是一个完整的应用。在这种情况下,你所需要做的就是增强它,看看你是否能有所区别。为了开始新事物,大多数应用只需要一点变化。例如,看看codecanyon.net。你在这里会发现一些很好的起点。这里有 Android、iOS、基于 Web 的应用程序等等。你可以找到 Flappy Bird 克隆应用、餐厅应用以及介于两者之间的所有应用。
假设你的初创公司正在开发一款旅行应用。你可以搜索这类应用并购买其中之一。你只需对应用进行一些修改,就能快速验证你的假设:

这将节省大量时间,而且值得小小的投资。你所学到的知识将帮助你定义应用在早期阶段应该做什么以及应该看起来像什么。也许后来你仍然想从零开始或多或少的重新开发你的应用。然而,如果你认为现成的基座应用能帮助你快速收集有价值的见解,那么遵循这种方法将不会是一个艰难的决定。
提供一个尚不存在的应用或服务
当你的应用尚不存在时,你该如何提供或描述它?一个不存在的应用很难展示,那么顾客如何得知它的存在,以及他们如何知道为什么应该获取这个应用?他们必须以某种方式了解到有一个(概念)应用可以解决他们遇到的问题。这里有趣的是,你的应用本身并不是那么重要。抱歉,你的应用本身并不是产品。它只是用户完成某事的工具。展示一个幻灯片或视频来解释你的应用做什么以及为什么它能帮助他们解决问题。这同样可以具有说服力。你会吸引他们的注意,如果你做得很好,你将立即获得他们的预订单。
如果你没有制作出色视频的技能,或者你需要一个标志或任何其他设计,那么请看看www.fiverr.com/。那里有许多自由职业设计师可以帮助你。另一个你可以查看的网站是99designs.com/.
一个视频或演示与最小可行产品(MVP)实际上并没有太大的区别,对吧?好吧,它确实是,尽管在这个例子中我们正在测试与产品-市场匹配相关的假设,而不是与产品-解决方案匹配相关的假设。每个初创企业的所有者,无论其角色如何,都必须进行销售,并且能够在产品存在之前就销售产品。这并不是谎言,甚至也不是假装。这是一种创造性的方式,承诺为已知问题提供解决方案。
然而,永远不要伪造推荐信或谎报客户数量,或者把事情夸大十倍。保持真实。相反,努力建立良好的声誉,成为专家,创建一个非常有说服力的网站,并包括功能列表,即使它还没有完成。为了表明人们可以信任你的公司,还可以添加一个包含条款和条件的公司政策链接。即使你还没有准备好销售,也要在网站上添加定价表。衡量(收入)牵引力永远不会太早。在第十五章“增长牵引力和提高留存率”中,我们将学习如何衡量牵引力,而在第十七章“货币化和定价策略”中,你将能够了解更多关于定价策略的内容。
如何保持事物结构良好
如果你从面试或指标中获得的反馈开始学习,那么你应用程序的流程或结构很可能发生变化。由于业务需求经常变化,需要做出临时调整。这要求你重构应用程序的代码。这是大多数开发者认为很重要的事情,但在现实中,它很容易被遗忘,或者根本就没有完成,仅仅是因为没有足够的时间。有时,重构被认为会使应用程序不稳定。然而,不要让你的技术债务变得过大。
如果你对底层过程理解不足,或者没有为开发分配足够的时间,可能会导致技术债务或甚至面条代码。如果一个初创公司只有面向业务的技术技能,它可能已经外包了开发,或者雇佣了一些第三方来完成这项工作。如果是这种情况,对应用程序的技术结构了解很少或没有。我强烈建议你尽可能自己做大部分的开发。如果你拥有一个没有技术合伙人的初创公司,那么请停止阅读,首先找到一位!有许多聚会和网站,你可以在那里遇到拥有你所需技能的人(作为合伙人或其他角色)。看看这些网站:angel.co/ 和 cofounderslab.com/。
保持事物,尤其是你的代码,结构良好是非常重要的。设计模式和许多学科可以帮助你为 Android 和 iOS 构建应用程序。确实,Android Studio 为重构提供了更多的功能,而使用 Xcode 重构则需要额外的努力。然而,重构对于这两个平台同样重要。
设计模式
没有必要重新发明轮子,我们也不需要重复自己。这正是“不要重复自己”(DRY)软件开发原则所规定的。设计模式是针对常见问题的解决方案,这样的模式可以在应用程序的许多地方使用。这是我们能够信赖的方法论,它将帮助我们加快开发过程。模式可以帮助我们以最小的努力开发高质量的软件。它们还可以帮助我们处理关注点的分离。一些著名的模式包括模型-视图-控制器(MVC)模式、某种程度上相似的模型-视图-表示者(MVP)模式,以及模型-视图-视图模型(MVVM)方法。
关于设计模式有很多优秀的书籍,本书的范围不涉及对所有这些书籍的详细探讨,但 MVC/MVP 模式特别引人关注,因为它在移动开发中应用最为广泛。该模式背后的理念是将用户界面与业务逻辑以及数据与逻辑分离。当你仔细观察 Android Studio 或 Xcode 中大多数 Android 或 iOS 应用程序的结构时,你会注意到其中已经包含了一些这种模式的元素。控制器从另一个层获取数据。这个层可以是一个客户端或仓库类。例如,它将从 API 或本地源获取数据。控制器通过模型(或视图模型)将获取到的数据传达给用户界面:

独立自主
理想情况下,你的应用程序是从本地存根、移动后端作为服务(MBaaS)、第三方 API 还是你自己的 API 获取数据,这应该无关紧要。这很容易实现。你只需要意识到分离不同的关注点以及实现合同的重要性。
另一个学到的教训是,你并不总是可以信任第三方服务。你可能听说过 Parse。它曾经是最有前途的 MBaaS 之一,许多应用程序开发人员都依赖它来在云端存储他们的应用程序数据。最近,他们宣布将关闭业务,这让许多开发人员感到沮丧。幸运的是,Parse 已经创建了一个开源版本的 Parse Server。无论如何,它很好地说明了我想在这里表达的观点。确保即使你的一个关键合作伙伴关闭业务,你的业务也不会受到影响。
数据层
如果你的应用程序结构良好,从一家服务提供商切换到另一家(关键合作伙伴)很容易。使用单独的数据访问层,并为你的数据层和控制器之间的通信定义合同。合同被称为接口(对于 Android)或协议(对于 iOS)。它们不包含实现,只是类与类之间的约定。它们定义了可用的方法、所需的参数以及结果类型。
例如,让我们假设我们正在从某种数据源获取数据。在接口IRepository中,我们将定义表示某些操作的所有方法的名称、结果和参数。更精确地说,让我们假设我们想要检索我们存储在云中的公司新闻。它可能位于 Parse 服务器(在 Back4App 或其他地方)、Amazon、Azure 或 Firebase,具体在哪里以及如何获取这些数据并不重要。由于它是一个接口,我们目前不需要关心实际的实现。
对于 Android,它可能看起来像这样:
public interface IRepository{
public void getNews(OnRepositoryResult handler, GetNewsRequest request);
对于 iOS,它看起来像这样(在 Swift 2.x):
protocol RepositoryProtocol {
func getNews(handler: RepositoryResultDelegate, request: GetNewsRequest)
实现此接口或协议的数据层类将执行实际工作。它们将从远程数据源检索数据。
例如,Android 实现开始如下:
public class RemoteRepository implements IRepository {
...
@Override
public void getNews(OnRepositoryResult handler, GetNewsRequest request) {
// Get data asynchronously and return the result
}
而 iOS 实现开始如下:
public class RemoteRepository: RepositoryProtocol {
...
func getNews(handler: RepositoryResultDelegate, request: GetNewsRequest){
在第八章,“应用程序实验的云解决方案”中,我们将看到使用 Firebase 的实现将是什么样的。
数据层也可以从本地模拟或存根数据中获取数据。你可以轻松地在不同的数据源之间切换。这使得它对于测试目的也是一个很好的解决方案。
有任何捷径吗?
不,没有!开个玩笑。有一些服务和方法是值得调查的。它们可以为你节省大量的时间和金钱。想象一下,一个需要与后端通信的应用,因为它需要支持聊天功能,或者支持与其他用户共享文本、图片、音频或视频。这样的应用将有许多要求,例如:
-
从应用同步数据到后端
-
从后端获取数据到应用
-
数据存储
-
数据流
-
离线支持
-
通过电子邮件进行注册和登录
-
使用 Facebook 或 Twitter 进行注册和登录
你可能可以自己构建支持所有这些的后端,但这需要大量的工作,而且没有必要。有许多服务可以处理(或部分处理)之前提到的所有要求:

在第八章“应用实验的云解决方案”中,我们将更详细地探讨 Parse 服务器。稍后,我们还将探讨 Windows Azure。
混合解决方案
混合解决方案可以被视为一个组合应用,它结合了可重用数据、展示和新的逻辑。它通常被视为网络解决方案,但这种方法也可以用于原生应用开发。数据无处不在。政府和各种组织已经通过 API 将他们的数据公开。混合解决方案不需要担心具体内容,而更多地关注展示。它们可能出现在企业、数据导向或消费者混合解决方案中。
应用可能从多个来源收集数据,将它们合并并丰富,然后在应用中展示。一个例子可能就是简单地从提供的数据中生成信息图表。另一个例子是从 Flickr 获取照片并在谷歌地图上展示。还有许多其他更复杂的方法,你可以考虑。混合解决方案可以极大地促进最小可行产品(MVP)或概念验证(PoC)的开发。通常,当混合解决方案被证明是一个有利可图的解决方案时,它主要具有聚合器的功能。例如,一个比较保险公司的网站。
请记住,你可以相对快速地开发一个混合解决方案,但其货币化可能更困难。再次强调,混合解决方案的最大缺点是依赖于第三方。如果事情开始变得严肃,那么不要仅仅消费他们的数据。你需要做更多的事情。避免你的业务因提供数据的公司决定停止服务而可能出现的关闭。如果你让这家公司成为真正的关键合作伙伴,你可以降低这种风险。尽管仍然存在依赖,但它已经不再是一个问题,因为它已经变成了一个可管理的问题。
摘要
在本章中,我们了解了一些可以帮助你开始并持续进行的事情。我们探讨了鸡生蛋还是蛋生鸡的问题以及如何处理它。我们还研究了模式,以及它们如何帮助我们保持事物结构良好。
最后,我们简要介绍了移动后端即服务(MBaaS)解决方案和混合应用。在第八章《应用实验的云解决方案》和第十一章《用户注册和入门》中,我们将分别探讨这两个方面的实际操作实现。但首先,我们将弄清楚一个最小可行产品(MVP)实际上应该是多么的精简。
第六章:MVP 总是比你想象的更简约
MVP 中的 M 代表最小,而不是最大。如果你的 MVP 想法包含了每个潜在用例、每个潜在受众组合、所有可用功能的各个方面,并创建了一个需要开发团队超过 90 天才能完成的待办事项列表,那么你并没有 最小可行产品。相反,你拥有一个完全不同的东西,很多时候它会让团队陷入困境,导致不必要的返工、失去周期、失去收入,以及所有与在未很好地定义和验证用户的产品上工作相关的功能障碍和痛苦。
在书面语境中,定义 MVP 的想法似乎很简单;当团队试图概述和定义在他们的初始产品发布中“最小”意味着什么时,挑战就出现了。“最小有多小?”“我能有多个核心功能吗?”“我的所有用例都被覆盖和考虑了吗?”“屏幕上能有多于 12 个按钮吗?”所有这些问题都使得我们提出的 MVP 是否真正简约和可行变得难以确定。
本指南旨在作为基准工具,将帮助你确保你已经成功定义并验证了一个准备上市发布的 MVP。
我们将涵盖以下主题:
-
什么是 MVP?
-
如何定义你的 MVP
-
快速失败/验证一切
-
迭代并进化你的 MVP - 从可行到受欢迎
什么是 MVP?
最小可行产品(MVP)被定义为:
“新产品的版本,允许团队以最少的努力收集关于客户的最大验证学习”
- 埃里克·里斯
例如 Instagram、Snapchat 和 Tinder 这样的应用程序在推出时都有一个共同点:它们都是今天版本的简化版。智能手机和 iPod 也是如此。在它们诞生的那一刻,它们只做了一件事,而且做得很好。显然,这些产品已经成熟,经过多年的资本投资和开发,已经成为了提供远超其核心功能的应用程序。重要的是要注意,它们是那些以最小功能集发布到市场、针对解决初始用户群体核心问题的产品的绝佳例子。
MVP 的好处
在你的组织中采用精益 MVP 产品设计和开发模型有助于将成本保持在最低,并允许你更快地测试和验证你的想法:
-
保持简单:专注于提供即时价值/实用性的核心功能,可以使你更快地将产品推向市场,而不是承诺进行无休止的开发周期,以交付一个功能齐全的多功能产品。
-
节省资金:揭示你产品的市场有效性,并证明进一步投资和开发的合理性。拥有一个可工作的原型,允许你在最小成本或努力的情况下进行转型或坚持。
-
学习和进化:MVP 模型的迭代和进化特性旨在快速灵活。它允许你在短时间内通过短跑成熟和细化你的产品,同时揭示宝贵的用户反馈和洞察,这些反馈和洞察有助于指导和塑造你的未来迭代。
如何定义你的 MVP
关于如何定义 MVP 存在很多争议,这与回答“最小化到什么程度?”这个问题有关。这是一个非常主观的概念,每个产品都有其独特的细微差别和需求,使其略有不同。这不是全有或全无的提议,但有一些技术和最佳实践可以应用,帮助你将你的产品定义为一个 MVP。市场需求可能需要多个核心功能来定义 MVP。
在本节中,我们将讨论以下主题:
-
如何构建 MVP
-
将组件组合成 MVP
-
将 MVP 应用于企业
构建 MVP
在接下来的第一幅插图里,很明显,预期的 MVP 是构建一个能够让用户从 A 点到 B 点通勤的车辆,而不一定是速度、距离,或者承诺使用机动车辆还是自驱动车辆等等:

显然,在第二幅插图里,考虑了多个用例和条件,因此这个模型不会允许快速的市场验证,并存在增加成本和可能无法满足目标受众的风险:

将组件组合成 MVP
在第一幅插图里,他们汇集了几个部件来制作一块滑板。他们需要一个板子,一些轮子,以及连接轮子到板子的车架。所有这些部件组合在一起构成了通勤车辆的 MVP。将这个比喻和思考过程应用到你所定义的 MVP 上。例如,如果你的 MVP 是客户关系管理软件,在最基本层面上,它需要提供一个中心位置,让用户可以存储客户和潜在客户的联系信息,与同事分享,并跟踪销售进度。为了定义 MVP,需要将多个组件或功能组合在一起。将管理客户的功能和跟踪销售线索的报表功能结合起来,这就是我们示例 CRM 的 MVP 定义。这两个组件本身也是迷你 MVP,作为独立组件并不定义市场上竞争性 CRM 的 MVP。别忘了,V代表可行,这意味着只需具备足够的功能就可以开始销售。
将 MVP 应用于企业
传统的企业软件开发方法集中在在向客户发布之前交付完美的、全面和功能丰富的产品。这与 MVP 指南和最佳实践中的最小和可行都不相符。企业团队在定义最小(恰好数量的功能,增加价值和实用性)和平衡它是否可行(我的产品中是否具有足够的特征,人们愿意为其付费?)方面都感到困难。
有不同的方法可以应用于企业产品,帮助在该领域重新定义最小可行产品:
-
数据驱动的设计:将数据置于产品决策的中心。使用客户的声音、使用指标和现有的性能报告来创建一个可以优先排序并缩减到最小和可行的功能层次结构变得比以往任何时候都容易。
-
了解你的市场:你不能为所有人构建一切。确保你有一个明确的目标市场细分,并从这里开始,即使这意味着你的客户是企业的玩家。明确界定你为谁构建产品将帮助你定义市场进入壁垒并巩固你的 MVP。
-
最小可销售产品 (MSP): 一旦你定义了你的最小可行产品 (MVP),不要忘记确保它是可行的。用你的目标市场来测试它,以确保它具有用户愿意为其付费的最小功能集。并且避免仅依赖产品经理的直觉和内部假设来预测哪些功能驱动产品的常见错误。验证!
-
应用增量用户体验:将 MVP 的概念降低到组件或功能级别,它不再是全有或全无的命题。基本思想是有一个计划中的进展(通过测试留下改进的空间)的每个阶段增加功能的功能。这将使你能够更快地进入市场(可行性)并通过验证学习随着时间的推移成熟你的产品,从而节省时间和成本。
但不要认为每个人都会立即理解这个过程,尤其是在一个企业中,你的同事和团队分布在世界各地。这需要不懈的传教。在我们公司,Dominion Dealer Solutions,我们在美国有办事处,由三个不同国家的离岸团队支持。更具有挑战性的是,许多团队都是我们以前的收购,带来了他们自己的继承文化和偏见。让每个人都理解和接受开发 MVP 的概念需要关键人物进行大量的传教以获得认同。这花费了数月时间,但一旦这个想法站稳脚跟,它就像野火一样迅速传播。
快速失败 – 验证一切
最小可行产品(MVP)的核心要素是获取用户反馈,进行用户测试,并在整个产品生命周期中验证用户是否愿意使用(并付费)您正在推出的产品。不幸的是,一些团队陷入了最小/可行产品的困境,完全忘记了验证。验证学习是定义 MVP、确认市场需求并塑造未来迭代、时间和资源投入产品中的关键组成部分。它是您是否应该在损失太多资金和耗尽资源之前转向并放弃项目,或者坚持不懈并继续在市场上前进的最佳指标。MVP 受“快速失败和快速恢复”的持续验证模型所管理,确保团队在时间、资源和运营资本方面保持超高效率。
让我们看看帮助我们快速失败的三个因素:
-
应用敏捷原型设计——消除技术债务
-
采用精益 UX 周期——构建-衡量-学习反馈循环
-
测试方法和最佳实践
应用敏捷原型设计——消除技术债务
原型允许您探索设计想法,测试假设,并在最小化技术债务的同时收集用户的反馈。对于那些可能不知道的人来说,技术债务是指在团队快速编码以将产品或原型推向市场时,随着时间的推移积累起来的未来工作,而不是为了创建最佳可能的解决方案而编写良好的代码。
在许多情况下,鉴于今天的科技,您可以创建无需任何技术债务的高清原型。如果您在代码提交后需要重新设计并重新创建 MVP 的界面和功能,那么绕过原型设计可能节省的任何时间都会在开发过程中以多倍的速度损失。
这里有一些如果您将敏捷原型设计应用于您的产品设计和开发过程中所获得的优点和好处:
-
所有权和协作:增加团队共识和所有权;在编写代码之前,在原型中发现潜在的可用性问题并进行纠正,从而避免可能的技术债务。
-
工作流程效率:减少和消除编写详细的故事和需求文档的需求。当每个人都可以通过实际体验点击和参与,而不是通过线框图或原型来想象和解释用户交互时,情况就大不相同了。
-
经常验证:从用户那里收集实时反馈,并快速迭代您的最小可行产品(MVP),一次冲刺一次。
精益 UX 周期——构建-衡量-学习反馈循环
精益 UX 的核心组件是建设度量学习反馈循环。这个概念最初来源于埃里克·莱斯所著的《精益创业》一书。其目标是验证不确定性、假设和潜在风险,以指导未来的 MVP 迭代和产品方向。这个循环形成一个循环,这个循环应用于敏捷开发中的冲刺。这种方法提供了一种快速有效地证明产品愿景(MVP)是会失败还是繁荣的方法:

以反馈为导向的开发模型的优点
采用数据驱动、以反馈为导向的开发模型可以使组织更有效地管理开发成本和资源。通过创建可用于验证周期并指导设计过程的 hi-fi 原型,可以立即减少开发时间和劳动力。在数字市场中,无效的商业假设风险太大,成本太高,无法生产。
建设度量学习反馈循环的各个阶段
这个循环有三个阶段:建设、度量和学习。
阶段 I - 建设
第一步是确定需要解决的问题,然后定义和开发一个 MVP 以尽可能快地开始学习过程:
-
构思:发展你的想法或概念。用非常清晰的语言确定需要解决的问题是什么。
-
创建你的原型:考虑简单和小巧。最好是构建最小的增量,以便快速获得足够的验证来指导下一步。
-
定义一个实验/测试研究来证明你的假设:创建问题集,考虑 A/B 测试和任务分析。
阶段 II - 度量
下一步是在互动循环中收集尽可能多的验证学习,并从你的测试中提取模式和洞察,以推动未来对 MVP 的投资和迭代:
-
启动你的测试研究:进行访谈,分发问卷,并验证你的原型。
-
分析:客观地查看你的数据。有什么出现?是否存在任何常见的模式和行为了?
-
组织:将重叠的模式和行为了解并开始形成洞察。
-
整理:将你的洞察转化为可操作的项目和讨论点,这将有助于告知潜在的修订、未来的迭代和发布。
阶段 III - 学习
这时需要做出决定,是坚持还是调整你的最小可行产品(MVP)。在这个语境中,坚持意味着继续以相同的目标前进,而调整至少需要改变,甚至可能完全重置你的原始 MVP 愿景:
-
确定你的 MVP 是否真正解决了用户的问题。我的 MVP 是否满足了我目标用户的需要?
-
建立你的最小可行产品(MVP)的可行性。我的 MVP 是否提供了用户愿意为之付费的功能集?
10 种基本用户体验测试方法
验证是 MVP 产品开发的基石。它是推动 MVP 构建-度量-学习反馈循环的动力。有几种不同的测试方法可以用以帮助定义 MVP,并通过应用构建-度量-学习周期来迭代地持续改进用户体验。
以下是可以用来帮助验证你的 MVP 的 10 种基本用户体验(UX)测试方法:
-
调查:最经济的方法是了解你的用户是谁,他们想要什么,他们做什么,他们购买什么,他们在哪里购物,他们拥有什么,就是通过调查他们。你可以找到免费的调查软件,所以没有借口。
-
用户画像/市场细分:使用调查数据,并在你的用户群体中识别有意义的模式和行为。揭示某些细分市场所要求的功能以及他们所经历的痛点。在你的市场细分中找到你的 MVP 市场甜点。
-
情境调查:有时用户很难准确表达他们想要什么或他们试图实现什么。始终理想的是观察用户在其环境中执行对他们的角色至关重要的任务和功能。在他们执行任务的同时进行探究和调查,以发现哪些有效,哪些需要改进。
-
行业专家/利益相关者访谈:在你的组织内部可以挖掘大量信息。访谈任何行业专家、客户支持、QA、开发、营销或销售人员,以了解需要构建什么,为谁构建,以及为什么。
-
任务分析:通过观察用户参与特定任务和工作流程来衡量可发现性、可用性和性能。
-
面对面调节测试:这适用于移动设备测试,或者当远程设置原型很困难时,在实验室、会议室甚至咖啡馆测试用户,以收集宝贵的反馈和见解。
-
远程调节测试:这是最经济的用户测试形式。使用 Zoom 会议、Google 表格和 InVision 等服务,你可以在互联网上的任何地方记录和调节用户测试。这有助于扩大你的招募基础,并且不会限制用户群体。
-
A/B 测试:这可以在许多条件下使用,如远程、调节等。比较测试布局、界面控件、按钮、CTA、颜色、任务、性能……天空才是极限。
-
比较基准研究:在竞争应用上比较相同任务。使用核心指标,如完成率、时间和任务难度作为创建基准的基础。例如,Zappos 的结账流程是否比亚马逊的结账流程更快、更高效、更易于使用?
-
多变量测试:一次只测试一个变量的方法可能需要很长时间,而且您会迅速消耗掉您的测试人员,速度比预期的要快得多。如果您需要经常进行测试,进行多变量测试将不仅使您从测试池中获得的最大回报最大化,而且还能让您对整个体验如何运作有一个很好的了解。例如,改变按钮的颜色可以收集一些数据,但与您改变按钮的位置、颜色和标签并测试所有变体一起收集的数据相比,这微不足道。您可以在实时环境和原型环境中进行多变量测试。例如,Optimizely 这样的产品可以帮助您在真实用户的环境中组织和启动多变量测试。
迭代和进化——从可行到可爱
现在我们已经成功地将我们的初始 MVP 推向市场,并收集了一些验证过的学习成果,接下来是什么?它是如何扩展的?它只是更多相同的东西吗?不,绝对不是。整个过程都是关于使您的产品、用户和收入不断发展和成熟。目标已经变成了将您的产品从可行变为可爱,引入最小可爱产品(MLP)。
MLP 被定义为以最少的努力从用户那里获得最大爱意的版本。我们都认识在我们生活中那些我们喜爱且无法离开的产品:汽车、由苹果、奥迪、三星和 G-Star 等杰出品牌创造的智能手机。我们喜爱这些产品,因为它们在我们内心唤起了积极的情感联系。简单来说,它们让我们微笑。
与用户建立积极的情感联系有许多不同的方法,但最简单的是通过良好的设计。
从可行到可爱:五个小贴士
以下是一些有价值的见解,可以帮助您的产品走向“令人喜爱”的用户体验之路:
-
关注价值:通常,团队专注于他们正在构建的内容,而不是为什么。用户不会因为“什么”(割草机)而购买,他们会因为“为什么”(我需要割草)而购买。构建有意义的东西。
-
做好一件事:一个稳固的功能或特性远比三个平庸的要好。从像 Dropbox 和 Instagram 这样的成功故事中学习。他们通过专注于做好一件事,简单地创造了大量喜爱他们产品的追随者。
-
验证和迭代:在没有尽头的移动目标上工作等于失去视野、失去机会、失去动力和失去收入。针对短期周期验证您的设计。将您的最小可行产品(MVP)的时间框设置为 90 天增量(12 周周期)。90 天足够实现您的愿景,但不足以让您失去对它的关注。
-
以用户为先:聚焦于对你客户来说是真正痛点的问题。你是否验证了这些痛点,还是只是你的观点?记住,以用户为中心的产品设计是一种以他人为中心的练习。这关乎你的受众对你产品的反应,而不是你自己的。
-
言行一致:对目标做出承诺并保持对过程的纪律性。如果你认为设计很重要,就通过你的行动来展示它:尽早引入设计以协作制定 MVP 策略/愿景——尽早开始制作线框和原型。不要只是说你的客户对你很重要,要通过你的行动来展示:测试和验证你的 MVP 想法。
摘要
在本章中,我们探讨了 MVP 的概念以及为什么它很重要。我们介绍了帮助你定义和构建 MVP 的技术。我们概述了一个遵循精益敏捷 UX 流程,并展示了验证你的 MVP 的优势和好处。最后,我们讨论了如何将你的 MVP 从可行转变为令人喜爱,以及如何激发用户的情感反应。使用这些构建块来节省时间和金钱,并开始构建你知道你的用户会喜爱和需要的产品。
在下一章中,我们将回顾一些案例研究,这些研究展示了这里讨论的许多想法。
用户至上 + 优秀设计 = 令人喜爱的产品
第七章:最小可行产品案例研究
在本章的最后,我们将探讨构建最小可行产品(MVP)的不同策略。
这些包括以下内容:
-
专属顾问
-
登录页面
-
假冒的后端
-
竞争对手应用
-
类比
-
干钱包
-
意向书
上述策略提供了一个框架,用于在不同保真度级别上运行快速实验,并利用所学知识来回答关于您应用商业模式画布的高风险假设。
在本章中,我们将深入研究一个 MVP 案例研究,以了解更多关于它们如何在一系列实验循环中应用。
我们将讨论“哑剧乐趣”,这是一个我和我的团队开发的应用,帮助世界各地的人们通过在线视频聊天室玩哑剧。我们将讨论原始愿景、我们面临的关键高风险假设、我们如何开发以假设为导向的测试方法、我们如何根据所学知识进行迭代,以及我们的最终结论。
哑剧乐趣 - 初始愿景
这是我们的初始愿景、目标受众和起始时的问题陈述:
-
愿景:创建一个有趣的地方,让人们在网上结交新朋友
-
目标群体:青少年、大学生、年轻专业人士、休闲玩家
-
问题:通过愚蠢的哑剧连接在线的人
在思考这个问题时,有几个问题:
-
他们是否对哑剧感兴趣?艾伦的哑剧游戏非常受欢迎,Heads Up Charades!周围也有很多热议,但这并不表明人们会想在线玩。
-
哑剧是否足够吸引人,以至于人们会想定期玩?
-
如果我们设置一个实时游戏来模拟我们习惯的游戏机制,这将需要朋友们同时在场,这可能很难安排。
-
如果安排很困难,人们会愿意在游戏室里与陌生人一起玩,就像在线扑克一样吗?
-
人们会对在线使用视频感到极度不安吗?是否有更开放使用在线视频的社区?
-
如果我们开发一个异步游戏,通过移动应用让人们有时间时就能玩,这可能可行。但是,人们同时手持智能手机面对挑战进行反应,这会实用吗?
-
然后,有一个问题,那就是我们是否有兴趣和技能在游戏方面。
重大不确定性
我们着手分解这些内容,解决我们认为列表上最大的疑虑:
-
人们是否对在线玩哑剧感兴趣?
-
他们是否习惯于在线使用视频?
-
他们是否喜欢这个概念,以至于会邀请朋友或加入公共游戏室?
-
他们是否喜欢在房间内与其他人一起玩游戏的体验?
-
他们是否喜欢这个到足以经常回来玩?
-
他们会邀请其他人吗?
接下来,我们试图围绕主要信念跳跃假设进行实验结构化,以寻求验证。
假设 1
在一组在线寻找猜谜游戏的人中,至少有 25%的人会注册来查看游戏:
-
受众:针对想要在线玩猜谜游戏的人。
-
获取用户:使用谷歌广告。
-
验证:这包括注册的百分比。
-
执行:
-
在一天内构建注册页面。
-
确定关键词并运行一周的广告。
-
跟踪注册情况。
-
-
结果:我们针对搜索“在线猜谜”、“猜谜游戏”和“猜谜词汇”的用户投放了广告,超过 25%的用户注册了。
-
学习:在谷歌上搜索猜谜游戏的人中,对在线玩猜谜游戏感兴趣的人:

假设 2
在目标受众中,向展示游戏概念草图的用户展示,至少有 70%的人对游戏非常感兴趣:
-
受众:针对印度的年轻成年人。
-
获取用户:使用您的朋友网络进行招募。
-
验证:这包括对游戏非常感兴趣的人的百分比。
-
执行:
-
使用 MockFlow 在一天内构建粗糙的模型。
-
带领人们了解模型。
-
收集反馈。
-
-
结果:总体而言,人们对游戏概念表现出一致的兴趣,但有些人提到他们可能对在线视频感到不舒服。
-
学习:总的来说,猜谜在印度很受欢迎,人们有兴趣尝试在线游戏:

假设 3
在被邀请到游戏房间的注册猜谜用户中,至少有 25%的人愿意加入公共房间并使用在线视频:
-
受众:这包括注册的用户。
-
获取用户:N/A。
-
验证:包括在公共房间中使用在线视频的用户百分比。
-
执行:
-
邀请用户进入公共房间。
-
提供关于游戏内容的解释。
-
允许用户打开视频并开始游戏。
-
跟踪分析。
-
-
结果:80%的用户访问了页面,但不到 5%的人打开了视频。
-
学习:这个实验否定了我们错误的希望,即在这个 FaceTime 和 Hangouts 时代,人们不会犹豫使用在线视频。因此,我们需要深入挖掘,并与用户交谈,了解他们的感受:

假设 4
如果用户与朋友一起玩,他们更有可能舒适地使用在线视频,80%或更多的人会这样使用:
-
受众:针对彼此相识但不太了解的朋友。
-
获取用户:使用您的朋友网络进行招募。
-
验证:这包括使用在线视频的用户百分比。对游戏想法感兴趣到足以失望不玩的人的百分比。
-
执行:
-
邀请用户进入公共房间。
-
提供关于游戏内容的解释。
-
允许用户打开视频并开始游戏
-
跟踪分析。
-
-
结果:100%的用户打开了视频,并且兴奋并准备好参与游戏,他们觉得如果无法玩游戏将会非常失望。
-
学习:当被问及是否愿意与不认识的人在线玩游戏时,女性表示会犹豫,而该组中的男性一致表示愿意尝试:

假设 5。
在网上使用视频与陌生人交流的在线社区用户更有可能舒适地相互玩游戏,至少 25%的人会使用在线视频:
-
受众:针对 Chatroulette 和 Chatrandom 社区。
-
获取:使用谷歌广告。
-
验证:这包括打开视频的用户百分比。
-
执行:
-
为 Chatroulette 和 Chatrandom 运行谷歌广告,提供基于视频的在线哑剧,以及结识新人的机会。
-
邀请用户进入公共房间。
-
提供关于游戏内容的解释。
-
允许用户打开视频并开始游戏。
-
跟踪分析。
-
添加一个 Qualroo 风格的提示来找出他们为什么没有打开视频。
-
-
结果:50%的用户访问了页面,但不到 10%的用户打开了视频。5%的用户回答了提示,表示他们不想打开视频,稍后会尝试,或者不确定如何打开。
-
学习:鉴于这些社区的匿名性,直接接触并获取反馈很困难,对提示做出回应的响应者的样本量太小,无法推断出足够的信息。
纠结的问题。
我们与一组用户进行了交谈并收集了反馈。因此,在这个阶段,我们面临了以下从我们的学习中获得的问题:
-
对于哑剧有一定的兴趣,但它主要被视为家庭和朋友之间的游戏。
-
对于那些经常看到朋友和家人的人来说,在线玩哑剧并不吸引人。(在感恩节或圣诞节与他们现场玩游戏仍然很有吸引力。)
-
普通用户不太愿意在网上与陌生人玩游戏。
-
即使是那些在网上处理裸露问题感到舒适且没有顾虑的社区,也没有发现这个想法吸引人。
-
视觉设计和提供解释信息方面的改进并没有增加转化率。
-
这样的游戏需要一个相当活跃的社区,而且看起来哑剧无法维持这种程度的参与度。
-
在次大陆有一个喜欢哑剧表演的社区,但他们所玩的形式相当技术化和古怪,无法大规模推广。
我们做得好的地方。
-
记录了我们的思维过程和假设,为我们成功提供了事实依据。
-
确定了可以以最低成本证明(或反驳)的小批量,快速构建并通过批量迭代。
-
保持诚实和客观,跟踪指标和群体情况良好。
我们本可以做得更好的地方。
-
最初的反馈主要来自次大陆用户,因为接触到国际受众并不容易。因此,反馈并不完全代表目标受众。
-
在我们理解客户及其行为理解的差距之前,我们建造了过多的东西。
-
我们在早期就包括了更多的在线调查,以便获得更好的洞察。
摘要
我们仍然相信原始愿景,并且可能坚持下去并让它在野外继续发展可能会产生一些成果。然而,我们最终被证明是错误的,并决定转向并探索其他想法。事后看来,这是一个明智的决定,可能使我们免于陷入沉没成本谬误的陷阱。
许多人对浪费资源(损失厌恶)持有强烈的保留意见。本章中我们看到的例子涉及一张不可退款的体育赛事门票。许多人会感到有义务参加活动,尽管他们并不真的想参加,因为否则就会浪费门票费用;他们觉得已经过了无法回头的点。
这有时被称为沉没成本谬误。经济学家会将这种行为标记为非理性:它是不高效的,因为它通过依赖于与所做决策无关的信息来错误地分配资源。(via Wikipedia)。
本案例研究的重要启示如下:
-
运行实验所需的严谨性和纪律性
-
根据新的学习和惊喜进行适应的意愿
-
需要专注于愿景(尽管,在这种情况下,我们的团队并没有长期坚持这一愿景)
-
代理用户的优势和涉及的权衡
在下一章中,你将学习更多关于使用软件即服务(SaaS)云服务来快速运行实验循环的知识。
第八章:云端解决方案应用于应用实验
虽然 MVP 可能只是最简单的着陆页、宣布您的应用或应用的实时模拟版本,但总有那么一个时刻,您的应用应该比这更多,无论是为了证明您的下一个假设,还是为了看到其最基本形态的实际应用。是时候创建一个概念验证(PoC)了。
独立应用现在很少见。大多数应用都有在 Twitter 或 Facebook 上分享内容的功能(如果它是游戏),让用户发布图片或视频,拥有排行榜(如果它是游戏),让用户发布聊天或以其他方式相互沟通等功能。为此,您的应用需要有一个后端。
当然,您可以创建自己的 API 或使用为该目的而存在的许多解决方案的 API,即所谓的移动后端即服务(MBaaS)。这些解决方案的工作方式与任何其他软件即服务(SaaS)一样,但专门为此目的而设计。
在本章中,我们将探讨 MBaaS 解决方案,并了解使用 Firebase 构建 Android PoC 需要哪些步骤,Firebase 是一个流行的基于云的后端。
具体来说,在本章中我们将涵盖以下主题:
-
了解是否需要我们自己创建后端
-
利用云端解决方案进行应用实验
-
确定哪些服务可以作为 MBaaS(移动后端即服务)使用
-
检查使用 Firebase 的 Android PoC 应用
您需要自己创建后端吗?
这完全取决于您的应用需求,但对于大多数应用来说,完全没有必要自己创建后端,至少对于您的最小可行产品(MVP)来说是这样。有许多现成的后端解决方案可供选择。
大多数解决方案支持推送通知、数据存储、社交注册和登录(例如使用您的 Facebook 或 Twitter 凭证注册或登录)以及数据同步功能,包括对您的应用的支持离线功能。
如果您必须自己编写所有这些代码,可能会花费很多时间,而且可能需要更多时间来确保没有错误。
几乎所有解决方案都以免费增值服务的形式提供,而且大多数情况下,免费选项足以构建您的 MVP。其中一些,如 Firebase,提供实时支持,使其成为聊天应用的一个很好的基础。稍后,我们将使用 Firebase 构建一个 PoC,但首先让我们看看目前有哪些解决方案可用。
MBaaS 能为您做什么在这里得到了说明。大多数解决方案提供基于网络的内容管理系统(CMS),应用程序编程接口(API)和软件开发工具包(SDK)。这样的解决方案将负责存储远程和本地数据。此外,它还支持数据同步(它将本地持久化数据发送到远程位置,反之亦然)和分发推送通知:

更精确地说,API 是应用程序与存储在远程服务器(云解决方案)中的数据通信的方式。数据通常可以通过 http(s)上的表示状态传输(REST)接口检索。SDK 是一段你可以添加到自己的应用程序的软件。它将使 API 的使用更加方便。通常,API 会处理诸如获取数据和数据同步等问题。使用 API 可以简化服务的集成,但你仍然可以使用 REST 接口,例如,在网站上显示相同的数据。
利用云解决方案进行应用程序实验
MBaaS 解决方案非常适合快速启动项目。大多数解决方案都包含几乎所有应用程序都有的功能,例如注册、登录、检索、保存和共享数据。使用 MBaaS 的另一个重大优势是其可扩展性。目前我们正在致力于开发 MVP,技术扩展问题都是奢侈问题。然而,提前知道这些问题可以通过这些类型的第三方解决方案更容易解决是很好的。你的应用程序具有可扩展性,但尚未需要扩展。如果需要扩展,那么只需切换到更大的计划(从技术角度来看)。你将在第十五章中了解更多关于扩展策略的内容,增长吸引力和提高留存率。
需要考虑的事项
还有一些其他事项需要考虑,例如定价。你可以从免费计划开始,但如果需要扩展你的解决方案,了解价格增长的速度是很重要的。如果你需要处理大量数据,服务是否仍然价格合理。当这种情况发生时,由于你的业务已经显著增长,金钱可能不再是主要问题。也可能你的策略是仅将服务用于第一个最小可行产品(MVP)。只要你有策略,并牢记这些事项,一切就都很好。
另一个需要思考的问题是,你的用户数据存储在第三方服务器上,例如 Facebook 或 Google。你应该问自己是否应该信任第三方来构建解决方案。当然,这很大程度上取决于解决方案的性质。无论如何,有一些事情你确实需要了解,比如“你的数据是否安全,如果服务提供商决定停止其服务,会发生什么?”Parse 服务器和 Firebase 在其推荐信中有一些令人印象深刻的名称,所以我们可能可以假设在大多数情况下,你的数据确实是安全的。
Parse 的故事
第二个问题比你想象的更重要。不久前,Parse 宣布他们将要停止提供服务。这个公告让许多(独立)开发者非常愤怒。这些开发者完全依赖于 Parse 服务。Parse 的停止让他们感到恐惧,因为他们认为他们别无选择,只能结束自己的业务。开发者对服务有很高的期望,这也因为 Parse 被 Facebook 收购。它看起来非常稳固。显然,这次收购也许也导致了那个同样的公告。对于 Facebook 来说,团队可能比服务本身更有趣。
幸运的是,这个童话有一个快乐的结局。Parse 提供了一套不错的迁移计划,现在这被称为开源解决方案 Parse 服务器。你可以自己托管,但如果你不想这么做,也没有问题。许多其他方也迅速加入,开始提供 Parse 服务器托管服务。服务器本身并不具备 Parse 中所有可用的功能,但像 Back4App 这样的公司做了大量工作,将它们全部添加回来。
简而言之,这个故事证明了你不应该完全依赖这类服务。合作伙伴很重要,但当他们变得不可替代时,你创业的未来可能会变得不确定。虽然这个故事是关于 Parse 的,但类似的事情也可能发生在 Firebase 上,例如。这不太可能,但谷歌之前已经关闭了一些服务,所以这也不是完全不可能的。
战略性考虑
如果你需要决定是否使用基于云的服务,以及需要从各种可用服务中进行选择,那么有一些战略性的考虑因素可能很重要。使用此类服务既有优点也有缺点。以下列出了一些。
以下是一些优点:
-
该服务缩短了开发时间
-
开箱即用的服务通常自带注册和登录支持
-
大多数服务可以根据你预期的流量量轻松地进行扩展或缩减
-
几乎所有服务都支持推送通知和媒体存储
以下是一些缺点:
-
一个现成的服务通常更贵。定价可能成为一个问题。
-
你的(用户)数据的隐私可能是一个问题。你必须相信提供该服务的公司正在采取适当的预防措施来确保安全性。
-
总是有这样的风险,即服务可能会被终止。
-
存在锁定风险。当所有数据都驻留在特定提供商处时,迁移到另一个服务可能会很困难。
可作为 MBaaS 使用的服务有哪些?
有一些服务可以作为你应用程序的后端。考虑到上一段中的战略考虑因素以及你应用程序的具体需求,一个服务可能比另一个服务更适合。
一些提供实时数据,使其非常适合聊天应用。其他则更侧重于数据持久化或附带构建块,例如 QuickBlox,让您能够更快地创建应用。一些是相当专业的解决方案,使用起来既简单又快捷,但不够灵活。其他则非常灵活,但学习曲线较陡峭:

大多数解决方案将数据存储在文档相关的数据库中,如 MongoDB。如果您需要为您的应用选择关系型数据库,那么选择 Azure 与 SQL Server 可能是最佳选择。选择与您的应用需求和当前开发技能最匹配的服务:
-
Back4App:该服务提供托管解析服务器。该服务支持推送通知、数据和文件存储,并支持云代码。云代码是在解析服务器上运行的代码,通常是查询。您可以使用常见的 Android 和 iOS 解析 SDK 与服务器通信。
-
SashiDo:与 Back4App 类似,这是一个提供托管解析服务器以及一些额外功能的托管服务。
-
Firebase:它是一个可扩展的实时后端,适用于 Web、Android 和 iOS。它非常适合聊天和协作工具,但也适用于其他需求。与 Parse 服务器或 Azure 等相比,存储媒体(如图像或视频)可能要复杂一些。
-
BaasBox:这是一个为您的移动应用提供的开源后端。它为 iOS、Android 和 JavaScript 提供了 SDK。
-
QuickBlox:这项服务为后端基础设施提供构建块。它提供数据存储、推送通知、文本和视频聊天以及许多其他功能。它允许开发者快速创建应用,但价格略高。因此,它最适合原型验证,而不太适合实际应用。
-
Azure:Microsoft Azure 提供了对推送通知和其他移动服务的支持。它已成为微软的核心业务之一,因此您可以将 Azure 视为最值得信赖的 MBaaS 解决方案之一。该平台肯定会持续存在。事实上,与其他 MBaaS 相比,Azure 服务有时可能有点令人困惑。它并不完全专注于 MBaaS。它能够做很多事情,如果刚开始使用,可能会使服务显得有些令人不知所措。它非常灵活,因此学习曲线相对较陡峭。对于您的应用需求,您可以使用表格和 blob 存储(用于图像、文档等),使用移动服务、API 服务,或者您可以使用 .NET 或其他语言创建自己的 API。Azure 为 Android、iOS 和 Windows 提供了客户端 SDK。
-
Backendless:Backendless 提供即时移动后端作为服务以及整体应用开发平台。
-
remoteStorage:remoteStorage 提供了针对每个用户的开放协议存储。使用您信任的提供商的存储账户,或者设置您自己的存储服务器。
-
CloudBoost.io:这是一个包含数据存储、搜索、实时和其他功能的完整数据库服务。
-
PubNub:PubNub是一个实时网络,它通过提供云基础设施、连接和关键构建块,使软件开发者能够快速构建和扩展实时 APP。
-
Parse server:Parse server 是一个开源解决方案,你可以下载并自行托管。例如,你也可以在 Heroku 或 Azure 上托管它。服务器使用 MongoDB 数据库,并利用 Amazon S3 存储来存储文件,如图像、音频或视频。Parse SDKs for Android 和 iOS 包括各种实用功能,如缓存数据、在后台上传数据或文件。
技术考虑因素
除了战略考虑之外,还有一些技术方面需要考虑。在选择特定服务之前,你应该问自己以下问题:
-
你的 APP 需要实时支持吗?
-
你的 APP 处理大量的媒体(图像、视频和音频)吗?
-
服务提供商应该有多大的可信度?
-
你目前需要使用所选服务的技能有多好?
-
你需要多少灵活性,你有多少可用时间?
在下一段中,我们将检查一个使用 Firebase 的 Android MVP。
Canvapp - 使用 Firebase 的 Android MVP APP
让我们使用 Firebase 构建一个 Android MVP APP。对于这个特定的案例,我们将有一个 APP,允许你通过手机创建和分享你的业务模型画布。任何人都可以查看或编辑彼此的画布,这样你可以轻松地收集反馈。如果你不记得业务模型画布的样子,你可以再次查看第二章,精益创业入门。
我们将使用一个线框工具,例如以下示例中的 SwordSoft Layout。假设 APP 应该看起来大致如此:

第一个视图显示了一个业务模型画布的列表,并且有一个滑动菜单。第二个视图是用户在创建新的画布或从列表中选择画布时看到的视图。它显示了多个页面,每个页面包含一个标题、描述和一些提示。用户可以前后滑动。这是一个非常基础的 APP。它只有三个视图,但这足以展示如何使用 Firebase 作为后端,并且我们可以用它来证明这个 APP 概念是有意义的。
为了简化起见,我们可以说,在这个例子中,你已经验证了你的早期假设。这个解决方案的假设是:
-
创业者希望通过其他创业者获取反馈来分享他们的画布。
-
创业者希望通过智能手机或平板电脑分享他们的画布。这将使我们能够专注于 APP 的技术实现。
你可以在以下位置找到这个项目的源代码:github.com/mikerworks/packt-lean-saas-canvapp。
注册 Firebase
如果你想看到实际操作,你将需要访问www.firebase.com并注册。完成注册后,你可以创建你的第一个应用。唯一重要的是 Firebase 将创建的端点。你需要这个端点来配置你的应用。在下面的示例中,端点是 torrid-head-3108.firebaseIO.com:

首先,从 GitHub 下载 Android Firebase 示例(github.com/mikerworks/packt-lean-saas-canvapp),这样我们就可以浏览它并了解其内容。如果你愿意,并且有时间的话,当然也可以从头开始构建这个应用。目前,你可以下载现成的应用,检查它,并根据需要修改它:

如果你更喜欢在 Android Studio 或其他 IDE 中打开应用,你需要修改的是应用中的 Firebase 端点。折叠应用中的data包节点并打开FirebaseRepository类。在FirebaseRepository类中,找到构造函数并调整 Firebase 引用,使其与你的匹配:
public class FirebaseRepository implements IRemoteRepository {
private Firebase reference;
private Context context;
public FirebaseRepository(Context context){
Firebase.setAndroidContext(context);
this.context = context;
reference = new Firebase("https://<your endpoint here>/canvapp/");
}
当你运行应用并添加了几幅画布后,它看起来大致如此。是的,它已经包含了一些酷点子:

当你运行应用并添加了几幅画布后,它看起来大致如此。是的,它已经包含了一些酷点子。应用将显示在 Firebase 中驻留的画布模型列表。每个模型的标题和描述都将显示。任何人都可以通过点击模型来查看或编辑它。这将显示编辑视图,其中包含可滑动的画布元素集合。可以通过菜单中的选项创建新的画布。
对于这个应用,我们在 Android Studio 中创建了一个新项目,并选择了导航抽屉作为我们的第一个活动。这将给我们一个带有现成菜单的漂亮模板。列表和新画布选项将在这里出现。
布局
项目中有几个布局资源(res/layout),我们将对其进行描述。这些布局如下:
-
列表布局:这个布局显示画布列表
-
分页布局:这个布局显示一系列可滑动的元素。
-
元素布局:这个布局将为商业模型画布的每个元素显示标题、描述、一些提示和编辑框。
-
行布局:这个布局将渲染画布列表中的每一行。
布局文件很小,只包含一些样板代码。它并不花哨,但我们仍然需要它来创建 Android Firebase PoC。如果你想检查它们,现在让我们继续与代码中最重要的部分。
依赖项
要检查应用程序的依赖项列表,请打开 app 文件夹中的 build.gradle 文件。在这里,你将找到 Firebase 和 JSON 反序列化的依赖项,如下所示:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.3.0'
compile 'com.android.support:design:23.3.0'
compile 'com.android.support:cardview-v7:23.1.1'
compile 'com.android.support:recyclerview-v7:23.3.0'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
compile 'com.firebase:firebase-client-android:2.5.2+'
}
在 res 文件夹的 raw 中,你可以找到 canvas.json 文件。该文件中的 JSON 数据将使用 Gson 进行解析。它将作为每个新画布的模板。用户需要做的只是为每个元素提供一个值。
文件中的 JSON 对象看起来像这样。它将由 LocalRepository 类处理:
{
"ELEMENTS":
...
{
"ID": "PROPOSITIONS",
"TITLE": "VALUE PROPOSITIONS",
"DESCRIPTION": "what value do you deliver to the customer? Which of your customer's problems are you helping to resolve? What bundles of services are you offering? Which needs do you satisfy?",
"HINT": "Enter your proposition here. What are the characteristics of it? What does it make unique? Is it price? Cost or risk reduction? A better design or performance? Is it more convenient? Why?..."
},
{
"ID": "SEGMENTS",
"TITLE": "CUSTOMER SEGMENTS",
"DESCRIPTION": "For who are you creating value?\nWho are you most important customers?",
"HINT": "Describe your customer segments here. Be as specific as possible. A niche market is much better as aiming for 'everybody'. If it is a platform what customers do you want to bring together. Who are your most important customers?..."
},
{
"ID": "CHANNELS",
"TITLE": "CHANNELS",
"DESCRIPTION": "Through which channels do your customer segments want to be reached? How are you reaching them now? How are your channels integrated?\nWhich ones work best?",
"HINT": "Describe your channels. How do you raise awareness? How can you help your customers to evaluate the value proposition? How can they purchase your services and how are they delivered?..."
}
此模板实现了一种特定的商业模型画布类型。还有一些变体。例如,Ash Maurya 使用了一个不同且在我看来更合适的画布。他称之为精益画布,并在 [第二章,《精益创业基础》中进行了描述。
随意修改模板或创建一个完全不同的应用程序,例如,用于某种调查。
模型
画布通常包含一组画布元素,每个元素代表商业模型画布的一个部分。为了简化,这些类只包含最基本的信息。
在应用程序中使用的重要模型是 Canvas 和 CanvasElement 模型。Canvas 和 CanvasElement 类都实现了 Parcelable 接口。这将使得将(复杂)对象传递给每个片段变得更加容易:
public class Canvas implements Parcelable {
private String id;
public List<CanvasElement> ELEMENTS;
public Canvas(){
ELEMENTS = new ArrayList<>();
}
public void setId(String value){
this.id= value;
}
public String getId(){
return this.id;
}
...
CanvasElement 类和模板文件中找到的 JSON 对象具有类似的字段。画布的每个元素都有一个 ID、标题、描述和占位符文本。用户输入将填充 value 字段:
public class CanvasElement implements Parcelable {
public String ID;
public String TITLE;
public String DESCRIPTION;
public String VALUE;
public String HINT;
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(this.ID);
dest.writeString(this.TITLE);
dest.writeString(this.DESCRIPTION);
dest.writeString(this.VALUE);
dest.writeString(this.HINT);
}
...
protected CanvasElement(Parcel in) {
this.ID = in.readString();
this.TITLE = in.readString();
this.DESCRIPTION = in.readString();
this.VALUE = in.readString();
this.HINT = in.readString();
}
public static final Parcelable.Creator<CanvasElement> CREATOR = new Parcelable.Creator<CanvasElement>() {
@Override
public CanvasElement createFromParcel(Parcel source) {
return new CanvasElement(source);
}
@Override
public CanvasElement[] newArray(int size) {
return new CanvasElement[size];
}
};
}
本地仓库读取包含模板的原始 JSON 文件。它将数据转换为 CanvasElementsModel 类,该类本质上是对画布元素的包装:
public class LocalRepository {
...
public static CanvasElementsModel getElements(Context context){
Reader reader = getStreamReaderForRawAsset(context,R.raw.canvas);
return new Gson().fromJson(reader, CanvasElementsModel.class);
}
private static InputStreamReader getStreamReaderForRawAsset(Context context, int resId){
InputStream stream = context.getResources().openRawResource(resId);
return new InputStreamReader(stream);
}
}
现在是时候处理一些 Firebase 相关的内容了。IRemoteRepository 接口已被添加到应用程序中。这将避免供应商锁定。如果你想要使用另一个 MBaaS 或你自己的 API,那么你需要做的就是更改以下三个方法的实现:
public interface IRemoteRepository {
Canvas createCanvas();
void loadCanvasModels(OnRepositoryResult handler);
void saveCanvasModel(Canvas model);
}
FirebaseRepository 类是针对 IRemoteRepository 接口的 Firebase 特定实现。以下代码片段展示了存储和检索画布所需的内容。让我们首先看看构造函数。在这里,定义了 Firebase 端点的引用。你可以修改引用值以匹配你自己的 Firebase 应用程序的端点:
public class FirebaseRepository implements IRemoteRepository {
private Firebase reference;
private Context context;
public FirebaseRepository(Context context){
Firebase.setAndroidContext(context);
this.context = context;
reference = new Firebase("https://torrid-heat-3108.firebaseio.com/canvapp/");
}
在 createCanvas 方法中,将创建一个新的 Canvas 对象。它将通过 LocalRepository 类从模板文件中获取的信息进行预填充。我们将引用更改为子节点画布,并将画布节点添加为该节点的子节点。push 方法获取画布的唯一标识符。我们将使用 Firebase 创建的该 ID 与 Canvas 对象一起存储。最后,此方法返回新的 Canvas 对象:
@Override
public Canvas createCanvas() {
Firebase ref = reference.child("canvases");
Canvas canvas = new Canvas()
CanvasElementsModel model= LocalRepository.getElements(context);
canvas.ELEMENTS= model.ELEMENTS;
Firebase postRef = ref.push();
postRef.setValue(canvas);
canvas.setId(postRef.getKey());
return canvas;
}
Firebase 的一个酷特点是开发者不必太担心在线或离线。如果设备离线,此方法仍然会成功。Firebase 将负责在本地持久化新的 Canvas 对象。一旦再次有互联网连接可用,Firebase 将负责在您的应用和远程存储库之间同步数据。
这是在您开始创建新画布时应用的外观示例:

saveCanvasModel 方法的实现甚至更小。它将在用户进行了一些更改的情况下更新 Firebase 数据。您需要做的就是使用给定的 Canvas 对象调用 setValue 方法。该方法检索画布数据节点的引用。我们在 createCanvas 方法中较早获得的唯一 ID 将用于找到正确的节点。最后,我们只需调用 setValue 方法将数据发送到 Firebase:
@Override
public void saveCanvasModel(Canvas model) {
Firebase ref = reference.child("canvases").child(model.getId());
ref.setValue(model);
}
在 loadCanvasModels 方法中,我们将检索所有存储的画布,并将监听器添加到画布节点。每当数据插入或现有数据更改时,onDataChange 事件将被触发。每个事件都会提供一个快照。它包含画布节点下所有子节点的(JSON)数据。
获得的快照的每个子节点都将反序列化为 Canvas 对象。CanvasList 片段将被通知,以便它可以显示或更新列表:
@Override
public void loadCanvasModels(final OnRepositoryResult handler) {
Firebase ref = reference.child("canvases");
ref.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot snapshot) {
CanvasListModel model = new CanvasListModel();
for (DataSnapshot canvasSnapshot: snapshot.getChildren()) {
Canvas canvas = canvasSnapshot.getValue(Canvas.class);
canvas.setId(canvasSnapshot.getKey());
model.canvases.add(canvas);
}
handler.onResult(model);
}
@Override
public void onCancelled(FirebaseError firebaseError) {
System.out.println("The read failed: " + firebaseError.getMessage());
}
});
}
}
MainActivity 类是从带有导航抽屉模板的类派生出来的。它已经稍作修改,以便可以显示各种片段。它还将处理任何菜单项的点击。如果应用首次启动或用户从菜单中选择列表选项,则会触发 onList 方法。如果用户从菜单中选择新的画布选项,则会触发 onEdit 方法。
如果用户点击 CanvasList 片段中显示的任何列出的商业画布,onEdit 方法也将被调用。在 onEdit 方法中,将传递 canvas 参数。getRepository 方法返回一个实现 IRemoteRepository 接口的类,在我们的例子中是 FireBaseRepository 类。如果您想从 Firebase 切换到 Parse 或其他 MBaaS,那么您只需在这里返回另一个存储库:
public void onList(){
CanvasListFragment fragment = CanvasListFragment.newInstance();
showFragment(fragment);
}
public void onEdit(Canvas canvas){
CanvasEditFragment fragment = CanvasEditFragment.newInstance(canvas);
showFragment(fragment);
}
public void onEdit(){
Canvas canvas = getRepository().createCanvas();
onEdit(canvas);
}
private void showFragment(Fragment fragment){
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.main_layout_container, fragment, fragment.getClass().toString());
ft.commit();
}
...
public IRemoteRepository getRepository(){
return new FirebaseRepository(this);
}
...
应用程序使用三个片段。有一个用于显示画布列表,另一个用作一系列可滑动画布元素的容器,还有一个用于画布元素本身。
CanvasListFragment 有一个 loadData 方法,该方法从仓库中调用 loadCanvasModels 方法:
public class CanvasListFragment extends Fragment
implements OnCardViewClicked, OnRepositoryResult{
private RecyclerView recyclerView;
private CanvasListAdapter adapter;
private CanvasListModel viewModel;
...
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_canvas_list, container, false);
recyclerView = (RecyclerView)view.findViewById(R.id.canvas_recycle_view);
loadData();
return view;
}
private void loadData(){
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setItemAnimator(new DefaultItemAnimator());
((MainActivity)getActivity()).getRepository().loadCanvasModels(this);
}
@Override
public void onCardClicked(View view, int position) {
((MainActivity)getActivity()).onEdit(viewModel.canvases.get(position));
}
当检索到结果时,它们将在 onResult 方法中处理,该方法将获取结果并显示列表画布:
@Override
public void onResult(CanvasListModel result) {
viewModel = result;
adapter = new CanvasListAdapter(viewModel, R.layout.adapter_canvas_list, getActivity());
adapter.setOnCardViewClicked(this);
recyclerView.setAdapter(adapter);
}
}
CanvasPagerFragment 是一个容器片段。它可以容纳多个画布元素片段,每个片段代表画布的特定元素。用户可以前后滑动:
public class CanvasPagerFragment extends Fragment
implements OnRepositoryResult, View.OnClickListener {
private static final String ARG_CANVAS = "ARG_CANVAS";
private Canvas canvas;
private ViewPager pager;
private CanvasElementPageAdapter pagerAdapter;
public static CanvasPagerFragment newInstance(Canvas canvas) {
CanvasPagerFragment fragment = new CanvasPagerFragment();
Bundle bundle = new Bundle();
bundle.putParcelable(ARG_CANVAS, canvas);
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
canvas = getArguments().getParcelable(ARG_CANVAS);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_canvas_edit, container, false);
pager = (ViewPager) view.findViewById(R.id.canvas_edit_pager);
view.findViewById(R.id.canvas_edit_save).setOnClickListener(this);
loadData();
return view;
}
在 loadData 方法中,我们将根据提供的 Canvas 对象创建 pagerAdapter:
setOffscreenPageLimit 方法在此处设置为 11(每个画布包含 11 个元素,因此我们需要 11 个 CanvasElementFragment 类的实例)以确保我们可以访问所有元素片段。这只是为了演示目的,在实际应用程序中应避免这样做。它可能会导致内存问题:
private void loadData(){
MainActivity ma = (MainActivity)getActivity();
pagerAdapter = new CanvasElementPageAdapter(
ma.getSupportFragmentManager(),getActivity(),canvas);
pager.setOffscreenPageLimit(11);
pager.setAdapter(pagerAdapter);
}
@Override
public void onClick(View v) {
onSaveData();
}
如果用户点击保存按钮,将触发 onSaveData 方法。在那里,我们调用仓库中的 saveCanvasModel 方法并传递更新的画布对象。最后,我们将导航回画布列表:
private void onSaveData(){
Canvas canvas = pagerAdapter.getCanvas();
MainActivity activity = (MainActivity)getActivity();
activity.getRepository().saveCanvasModel(canvas);
activity.onList();
}
...
}
}
CanvasElementFragment 代表商业模型画布的一个元素。例如,这可能是一个用户可以输入关于价值主张想法的卡片:
public class CanvasElementFragment extends Fragment {
private static final String ARG_ELEMENT = "ARG_ELEMENT";
public static CanvasElementFragment newInstance(CanvasElement element) {
CanvasElementFragment fragment = new CanvasElementFragment();
Bundle bundle = new Bundle();
bundle.putParcelable(ARG_ELEMENT, element);
fragment.setArguments(bundle);
return fragment;
}
private CanvasElement element;
public CanvasElement getElement(){
if (getView() != null) {
EditText editValue = (EditText) getView().findViewById(R.id.element_value);
element.VALUE = editValue.getText().toString();
}
return element;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
element = getArguments().getParcelable(ARG_ELEMENT);
}
在 OnCreateView 方法中,我们将元素对象绑定到视图:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_canvas_element, container, false);
((TextView)view.findViewById(R.id.element_text_title)).setText(element.TITLE);
((TextView)view.findViewById(R.id.element_text_description)).setText(element.DESCRIPTION);
((TextView) view.findViewById(R.id.element_value)).setHint(element.HINT);
if (element.VALUE != null){
EditText editValue = (EditText) view.findViewById(R.id.element_value);
editValue.setText(element.VALUE);
}
return view;
}
}
Firebase 仪表板
如果你稍微玩过这个应用程序,添加了一些画布,然后转到 Firebase 仪表板,你将看到你刚刚创建的所有画布都出现在这里。所有更新都会立即显示(当然,前提是你在测试应用程序的设备是联网的)。
这也使得 Firebase 非常适合聊天应用程序。它也可以反过来工作。如果你在这里添加一个新的画布节点,它将立即出现在应用程序中。只需尝试一下,添加一些节点,玩一会儿,并适当地调整应用程序以测试其他 Firebase 功能。
这就是仪表板可能的样子。
为了阐明这个例子,标题、描述和提示字段,已经本地持久化,也存储在这里。尽可能避免数据冗余,只存储每个元素的 ID 和 VALUE 属性是有意义的:

只需一点代码,你就可以使用 Firebase 在云端持久化你的数据。你不需要担心可扩展性问题、在线或离线以及许多其他情况。Firebase 有许多其他选项,例如用户管理(注册、登录)、安全、限制和分页选项。
摘要
在本章中,我们看到了如果我们不想自己创建应用的后端,我们可以选择哪些服务。我们学习了什么因素对于做出正确的战略和技术选择可能很重要,并且还看到了一个示例应用,该应用使用 Firebase 作为移动后端。你可以使用这个应用来学习,或者你可以对其进行增强,并用作你自己的应用想法的起始项目。
我们所检查的应用仅适用于 Android。如果你想要这个应用为 iOS 构建,会怎样呢?你应该再次创建它,但这次使用 Swift 和 Xcode 吗?有没有其他选项,只需开发一次应用,但适用于多个(移动)平台?你可以查看下一章来了解更多相关信息。
第九章:原生、混合还是跨平台
大多数开发者都清楚,当谈到市场份额时,规模大并不一定意味着更好。也就是说,Android 的更大市场规模并不一定使其成为应用开发的更好选择。同样,iOS 的更高开发者回报本身也不应该使您成为其信徒。那么,在选择平台时,您应该关注什么?
在本章中,我们将采取务实的态度来回答这个问题。简而言之,我们将探讨以下内容:
-
可能对您平台选择产生重大影响的现实因素,例如您受众的需求、您的技术需求和您的技术能力
-
原生应用和混合应用的优缺点,以及各自的利弊
-
可以让您同时在这两个平台上进行开发的跨平台开发工具
让我们先从最基本的几个问题开始探讨。
您的受众是谁?

您的目标受众可能更喜欢某个平台,或者他们可能在这两个平台上均匀分布。尽可能多地了解您的受众将帮助您确定许多关于您应用的事情,包括是否采用原生或混合开发。在进行研究时,要超越现有的概念和刻板印象。
例如,我们大多数人可能已经意识到 iOS 用户和 Android 用户之间的一些表面差异。那就是,iOS 用户更富裕、受教育程度更高、年龄更轻,而 Android 用户则相反。
一些研究还表明,尽管 Android 的市场渗透率很高,但 iOS 用户更愿意为应用付费。苹果公司报告称,2016 年向开发者支付了 200 亿美元(参考 www.apple.com/newsroom/2017/01/app-store-shatters-records-on-new-years-day.html),App Annie 报告称,尽管 Google Play 商店下载量是 App Store 的两倍,但 iOS 应用产生的利润是两倍(参考 www.google.com/url?q=http://bgr.com/2016/07/20/ios-vs-android-developers-profits-app-store-google-play/&sa=D&ust=1501582800060000&usg=AFQjCNFJYS1AAoGra88ceEN2y6y87UdA7g)。
这些数字会为您做出决定吗?也许会,如果您的收入模式依赖于从您的应用中赚钱。如果不是这样,那么您需要关注对您的受众真正重要的事情。在探索您的潜在受众时,始终要深入了解这些广泛报告的表面之下。它们通常过于抽象,无法提供任何真正的见解。相反,使用竞争情报工具(如 App Annie 或 Flurry)进行深入研究,并与市场研究人员合作收集您自己的数据。
测量 - 不要猜测或使用直觉
对于特定市场细分的数据可能不会反映行业平均水平,因此您应该深入挖掘“苹果用户更富裕”的刻板印象,并具体了解您的行业和现有用户基础。您应该使用所有可用的分析来了解您受众的平台偏好。
例如,收集和分析以下内容:
-
分析服务,例如 Google Analytics for Mobile (
www.google.com/analytics/analytics/#?modal_active=none)、Yahoo's Flurry Pulse (developer.yahoo.com/flurry-pulse/)、Localytics (www.localytics.com) 和 Adobe (www.adobe.com/marketing-cloud/web-analytics/mobile-web-apps-analytics.html) -
应用商店分析
-
移动网站消费
-
桌面网站消费
在评估这些数字以及您关于受众的任何其他可用数据后,您可以确定他们是否对任何特定平台有偏见。
大多数人倾向于落入 iOS 阵营或 Android 阵营,这决定了他们购买的设备、他们使用的应用商店等等。
您的技术需求是什么?

并非每个应用都是孤岛。在某些情况下,应用需要与其他平台特定的服务或应用集成。在这种情况下,您将面临可能限制您的开发选择的严格限制。至少,这有助于您明确开发优先级。
正如我们接下来将要看到的,存在跨平台工具包,允许您在多个平台上发布。尽管这些工具打开了一些行动路线,但它们限制了其他路线,并可能阻碍与其他原生应用的兼容性。根据您的技术需求和集成需求,这个问题可能会完全压倒所有其他问题。
您的技术能力如何?
有时候,选择一个操作系统而不是另一个操作系统并不重要。当您的团队在某个平台上具有优势时,要务实,根据您能做什么来选择。毕竟,在陌生的平台上开发存在风险,包括:
-
延长的上市时间
-
较高的技术成本
-
通过错误或其他错误进行返工的风险更高
这些问题的影响可能会延迟有效数据的收集和学习。
在您已经熟悉平台上进行开发具有相应的优势:
-
技术成本降低
-
错误风险降低
-
缩短上市时间
-
缩短学习周期时间。
然而,总有例外。例如,如果您有一个充满活力且成功记录的团队,并且他们想学习特定的平台,那么让他们放手去做可能是明智的。这是一个判断性的决定。只有当您有一支了解如何根据最佳实践构建的资深团队时,才考虑这一点。
原生与混合 - 优势和劣势

现在我们已经涵盖了关于您的受众、技术需求和技术的基线要求,是时候看看原生和混合应用如何比较了。尽管大多数开发者都熟悉两者之间的基本区别,但重要的是要审视每种应用的优缺点。之后,我们将更接近确定最适合您需求的方法。首先,这里有一个简要概述:
原生应用
原生应用是专门为某一平台开发的。在移动领域,这通常意味着 iOS 或 Android。原生应用的主要卖点在于平台特定的应用可以直接调用操作系统 API,这为开发者和设计师提供了更大的灵活性和对用户体验的控制。
采用原生应用可以提供完整的设备功能,但您必须付出代价。原生应用的开发和创建成本更高,需要深入的专业知识...尤其是如果您需要在两个不同的平台上进行原生开发。
混合应用
混合应用部分是原生的,部分是网页。HTML、CSS 和 JavaScript 用于定义应用的网页部分,通常通过设备的渲染引擎(通常是 Webkit)执行。大多数情况下,这些应用的部分仅限于 UI 元素。
混合应用相较于移动网页应用的优势在于,混合应用仍然能够调用原生 API。混合应用位于严格意义上的网页应用和原生应用之间。它们可能只是以原生包装形式提供的网页应用。或者它们也可以包含原生代码,以便利用特定于操作系统的功能。
采用原生的利弊
纯粹主义者坚持“始终原生”的哲学,尽管这种态度近年来有所缓和。然而,所有企业都有有限的资源,因此不可能忽视原生应用的一些缺点:
-
原生应用的开发和维护成本更高
-
它们创建的时间更长,这可能是一个问题,如果您需要尽快推出。
-
它们的开发需要更多的专业知识,这又可能使成本更高,耗时更长
-
如果您或您的团队没有必要的经验,您将不得不获得它
转向原生应用的另一个潜在问题是,为某一平台开发的想法可能会被复制到另一个平台。有人试图窃取您的想法的威胁始终存在,但请记住,新颖的想法总会被复制。在第十九章《构建不公平优势》中,我们将探讨保护您的知识产权免受此类可能性的方法。
尽管存在不利因素和潜在风险,但创建原生应用确实有明确的优点:
-
原生应用针对特定平台和操作系统,因此您可以直接利用不同级别的 API,从 GUI 工具包到文件系统。
-
对应用及其与设备的接口有更精细的控制,让您更好地掌握可能影响用户体验的细节,例如加载时间或其他微妙的 UI 元素。
-
仅当您构建原生应用时,才能与某些特定平台的应用或服务进行集成。
这些考虑因素本身应该表明,在原生和混合应用之间的选择并不总是那么明显。
有时,您真的没有选择,没有什么可争论的。例如,如果集成需求迫使您开发特定平台解决方案,那么这个问题永远不会出现。然而,当您能够进行辩论时,采取以用户为中心的方法来处理这个问题非常重要,这正是原生应用真正发光的地方。
转向原生应用的最大好处
原生应用可以提供对用户体验的更精细控制。当从精益的角度审视应用时,将用户体验置于首位至关重要。随着智能手机的普及,消费者对他们的移动应用提出了越来越多的要求。如今,这种体验往往决定了应用的成败。自 2010 年代初以来,一项又一项的研究表明,客户会迅速放弃表现不佳的应用或网站:
-
在 2012 年底,方程研究对超过 3,000 名移动设备用户进行了调查。84%的人表示,移动应用性能至少在一定程度上很重要,超过 50%的人认为移动应用应在 2 秒或更短的时间内加载。
-
根据 Gomez.com 和 Akamai 在 2011 年进行的一项经常引用的调查,页面加载时间延迟 1 秒会导致销售额下降 7%。他们还发现,40%的用户会放弃加载时间在 3 秒或更长的网页。
-
2016 年 7 月,在先前两次调查结果的基础上,谷歌 Think with Google 评估了大量真实电子商务网站的指标,以创建可以分析网站并预测转化率和跳出率的机器学习模型。结果并不令人惊讶:页面复杂性降低了转化率,加载时间慢增加了跳出率。
性能只是影响整体用户体验的一个因素。你可以开发出具有吸引力的用户界面的应用,但关于跨平台应用的最大抱怨是它们没有真正原生的外观和感觉。然而,混合应用有其自身的优势,这使得它们值得探索。
转向混合的利弊
混合应用介于纯 Web 应用和纯原生应用之间,并从每个领域带来优势。与原生应用一样,没有对错之分——这只是确定哪种适合你的情况的问题。混合应用可能没有原生应用那样的性能或图形潜力,但它们提供了不同类型的优势:
-
编写一次,运行在任何地方。跨平台工具(我们将在下一节中介绍),将代码,如 JavaScript 或 C#,转换为多个平台的本地语言。即使是一个简单的本地外壳包裹着一些 Web 代码,也能让你在两个商店中列出你的应用,并接触到两个受众。
-
由于你可以将应用的一部分作为一个单一代码库来开发,你的开销要低得多。
-
短暂的开发时间不仅降低了开发成本,还意味着你的应用可以更快地发布。
-
由于混合应用具有原生组件,可以在应用商店中列出,因此你将获得与开发原生应用相同程度的曝光。
在所有这些优点面前,很容易理解为什么许多开发者对混合应用采取更为温和的态度,但使用跨平台开发工具创建的应用确实有其自身的缺点:
-
由于你不会对性能有太多控制,混合应用可能会表现不佳,这可能会影响用户体验和用户满意度。
-
某些界面元素难以或无法使用跨平台开发工具重现。
-
每个平台上的应用都有其特定的外观和感觉,除非你非常小心地模仿,否则用户会察觉到差异。
-
如前所述,与其他原生应用或服务的集成可能很困难,或者不可能。
-
最后,随着应用复杂性的增加,即使是混合开发者也可能需要具备一定程度的特定于原生的能力,以便在出现问题时有效地解决某些原生问题。
考虑到所有这些因素,有一些实际的现实情况说服了一些开发者选择混合应用。
不那么美好的真相——当你有明确目标时,一点混合应用并不会造成伤害
纯粹主义者可能不喜欢这一部分,但底线是我们在这里是为了在无论什么预算和时间框架下都能构建出优秀的应用。尽管原生主义者可能会宣扬一个或另一个平台,或者两个都宣扬,但当你有截止日期和有限的资金时,这种策略是行不通的。
当涉及到创建最小可行产品(MVP)时,你最重要的限制是最低限度,无论是从可行性还是从受欢迎程度来看。你需要达到一定的阈值,以便验证你的假设,赢得用户的青睐,并从你的经验中学习。
如果你有一个不切实际的“原生或无”的心态,将你的预算耗尽,那么你就无法做到这一点。这种思维方式实际上与精益方法相悖。完美主义和纯粹主义可能会在应用发布前阻碍它,增加成本,甚至完全失败,所有这些都是在将 MVP 推向市场并开始学习所需的时间内发生的。
如果你可以通过混合应用更快地将你的应用推向市场,那么你应该这样做。下游技术债务(来自将你的混合应用转换为纯原生应用)是可以接受的,只要在它给应用带来问题之前偿还债务。
如果你想在尽可能短的时间内构建最好的应用,那么你需要考虑所有可能性,包括混合应用。值得注意的是,混合应用可以并且确实取得了成功。Twitter、EverNote 和 TripCase 都是众所周知的例子,证明了混合应用即使在长期来看也是一个完全可行的方案。
做出最终决定 - 需要考虑的因素
之前,你已经针对你的受众、技术需求和技能水平回答了基本问题。然后,我们探讨了原生应用和混合应用的优点、缺点和能力。我们还打破了“原生或无”的神话,证明了混合应用可以提供一些非常实际的优势。现在,是时候回答一些具体、实际的问题,这些问题将帮助你决定哪种选择最适合你:
-
应用技术需求的影响:原生功能对你的应用是否至关重要?如果不是,仔细考虑采用混合方法所能带来的好处,例如缩短上市时间、节省成本和访问多个平台。
-
上市速度要求:你是否需要在 6 个月内进入市场?如果是这样,那么原生应用可能就不再是一个选项。
-
可用性和功能:应用的用户体验有多重要?尽管可用性爱好者和平面设计师可能会有不同意见,但再次强调,实用性胜过意识形态。原生应用当然能给你带来优势,但如果你可以用 20%的成本实现 80%的努力,那么你应该保持开放的心态。
-
资源能力和预算:这个预算应包括开发以及长期维护和技术债务。你是否有资源来完成这项工作,并且能否负担得起 iOS 和 Android 开发者?
-
长期目标:权衡你的当前需求和资源与你的长期目标。你未来是否需要本地化并从头开始重建你的代码库?规划可能的行动方案,并考虑这些长期和短期成本如何影响你的商业目标。
实际的决策应该每次都获胜。坚持您需要做的事情的事实,不要忘记您实际上能做的事情。不要专注于应用是如何开发的。相反,关注股东真正关心的事情——或者可能会关心的事情——即市场优势,如市场份额、市场机会、颠覆潜力以及知识产权。专注于构建优秀的应用,并遵循可用性、设计、性能和安全的最佳实践。
利用跨平台开发工具

市场上有许多跨平台开发工具。在本节中,我们将快速浏览一些最常见工具,并讨论它们的优缺点。
Adobe PhoneGap
Adobe PhoneGap 是 Apache Cordova 的开源发行版。它不是一个应用开发框架,而是用于打包和发布在 HTML 5、CSS 和 JavaScript 等网络技术中构建的应用。它是 Adobe Creative Cloud 的一部分,并为其他混合选项提供类似的好处:
-
使用客户端网络语言编写核心代码库,并在一些最受欢迎的平台上进行原生发布。
-
没有原生经验的开发者可以将网络应用转换为原生应用。
-
有许多额外的工具可供选择,这些工具使得预览、构建和下载测试应用变得容易。
PhoneGap 的弱点与其他跨平台工具相一致:
-
其性能与原生应用不相上下。
-
图形功能不足,它无法提供原生外观或感觉。
-
如前所述,PhoneGap 不是一个框架。请记住,PhoneGap 并不会将代码翻译成本地语言,它只是将您的应用封装成原生包。
Xamarin
Xamarin 是专门为在 Android、iOS、Windows 和 Mac 上构建 C# 应用而设计的。该公司于 2016 年初被微软收购,并利用其现有服务使其成为最具竞争力的跨开发工具之一。由于您的大部分应用将从一个共同的代码库构建,您肯定会节省时间和金钱。然而,一些代码,如 UI 和平台特定功能,需要以本地方式编写,因此不要期望效率提高四倍。
应用可以在 Visual Studio、Xamarin Studio(其自带的 IDE)和 Visual Studio for Mac 中开发。根据微软的说法,Xamarin 完全支持 Android 和 iOS SDKs,以及为原生 SDKs 开发的第三方控件或工具,并且该平台将随着新操作系统的发布保持最新。
在撰写本文时,学生、开源软件和独立开发者有免费选项,而专业用户和企业客户有更昂贵的选项。
Appcelerator
Appcelerator 允许您使用 JavaScript 构建应用,并在任何设备上原生运行。其工具箱包括以下内容:
-
可视化应用设计器
-
构建 API 的框架
-
移动分析
与这里提到的其他工具一样,它提供了对原生 API 的直接访问,但应用程序在性能和图形方面仍存在某些限制。尽管 Appcelerator 价格合理,但一些开发者认为其中的错误使其不值得付出努力。
如何选择合适的工具
如果你决定尝试这些工具中的一种,第一步是研究。最好的开始方式是考虑本章中概述的需求和优先级。将你的需求和能力与市场上可用的工具的优缺点进行比较。由于数字生态系统变化如此之快,如果价格和质量存在差异,请不要感到惊讶。
这些只是 2017 年初市场上最受欢迎的几个跨平台开发工具。以下是一些其他值得探索的工具:
-
Ionic:这是一个开源的 HTML5 应用程序框架
-
Sencha Ext JS:这是用于构建数据密集型 HTML5 应用程序的
-
Mobile Angular:这是一个使用 Angular JS 和 Bootstrap 的移动 UI 框架
-
Progress Telerik 平台:这是一个适用于 iOS、Android 和 Windows 手机的开发平台
-
Unity:这是一个跨平台的游戏引擎,包括移动平台,但扩展性非常好
-
Libgdx:这是一个用于跨平台游戏开发的开源平台
如需了解这些工具的更多信息,请从它们网站上的文档开始。GitHub 包含了许多列出的工具的代码库。对于像 PhoneGap 和 Xamarin 这样的更受欢迎的工具,可以在在线教育网站上找到广泛的教程、课程和教程,例如 Pluralsight、Udemy 和 Lynda.com。
摘要
在本章中,我们从实用主义的角度探讨了混合和原生之间的争论。我们概述了你需要问的最关键的问题,以便确定最适合你和你的客户的方法。最后,我们简要介绍了市场上一些最受欢迎的跨平台工具,如果你决定使用混合应用程序开发来加速测试,这些工具应该能为你指明正确的方向。
在接下来的章节中,我们将探讨几种加快实验速度的方法,包括混合、入门策略和应用程序商店技巧。
第十章:有相应的 API!
在本章中,我们将探讨通过构建一个混合应用来验证我们的假设我们能做些什么。这比仅仅创建一个简单的着陆页需要更多的努力,但比开发一个完整的应用程序所需的时间要少。通过结合应用程序或其他资源,你可以用最少的努力为你要解决的问题制定一个解决方案。这对于至少一个概念验证来说是一个有趣的方法。一旦你学到了你想要学习的课程,你总是可以设置一个更稳健的解决方案。另一方面,你的应用程序策略可能就是如此——结合资源,并将其作为你的产品或服务本身推出。这尤其适用于提供聚合信息的应用程序。或者,你也可以考虑需要与社交网络(如 Facebook、Twitter 或 YouTube)进行大量集成的应用程序。与完全自己建立用户基础相比,社交推荐总是更容易,因此将社交组件集成到你的应用程序中始终是一个明智的选择,但如果你用它创建了一个混合解决方案,那就更有趣了。
你可以结合各种应用程序和服务,但还有其他可能产生非常有趣的混合解决方案的东西。几乎关于任何事情都有数据,其中大部分数据已经通过各种 API 公开提供。你可以使用这些数据,将其与其他数据相结合,并以不同的方式可视化结果。例如,你可以在谷歌地图上显示结果,而不是在列表中显示。最受欢迎的混合应用正是这样做的。它们以不同的方式可视化现有数据。
在本章中,我们将涵盖以下主题:
-
调查混合应用如何帮助我们验证假设
-
查看一些流行的混合应用
-
调查可用的 API 和移动 SDK
-
通过构建移动混合解决方案来验证我们的假设
-
使用 IFTT 食谱来验证我们的假设
快速成功或失败
混合应用允许你快速成功或失败。如果你失败了,你可以在早期阶段重新表述你的假设。使用你获得的反馈,你可以构建一个更好的应用程序,并找出人们真正想要的应用程序需要什么。
事实上,通过使用第三方 API 或 SDK,你可以依赖比你的平台更大的平台,并且由于它是经过验证的技术,因此它更不容易出错。例如,如果你想集成除应用内购买之外的其他支付方式,你当然会使用支付提供商的现有解决方案。
你可以通过提供单一登录功能来利用社交网络,为你的应用程序。例如,你可以提供一个用户使用 Facebook 或登录账户注册或登录的方式。这降低了注册门槛,从而提高了注册转化率。用户需要采取的行动更少,你也能获取到额外的数据,如姓名和头像。注册后,这将为应用程序带来更加个性化的体验。我们将在第十一章 Onboarding and Registration 中详细阐述这个过程,关于新用户注册的过程。
混搭解决方案中有什么?
现在,让我们更深入地了解一下混搭。混搭究竟是什么,这种现象是如何产生的?一般来说,混搭会从一个或多个来源消费特定的数据,具有不同的展示方式,并提供额外的逻辑。
混搭通常是由消费可重用数据、特定的复杂功能、展示和一些新的逻辑组合而成的。它不一定需要所有这些元素。混搭可能是一个从多个来源收集和合并数据的解决方案。通过 API,任何人都可以消费各种类型的数据集。你应用程序的附加价值可能仅仅是聚合数据的结果。例如,想象一个应用程序,它显示了所有可用的职位,否则你可能需要访问 10 多个不同的网站。数据挖掘和其他技术可以帮助你进一步丰富数据。
混搭还可以利用 API 执行复杂功能(数据处理和支付处理),或者它们可以被用来外包非数字世界中的各种任务。这可能包括按需 3D 打印、商品交付或执行由人类完成的小任务。Amazon 的 Mechanical Turk API 就是这样一个很好的例子。通过这个 API,你可以将小任务分配给其他人。你可以想象写评论、验证或审查用户输入,或进行研究。有大量的 SaaS 解决方案可用,其中大多数都带有应用程序编程接口(API)。所有这些 API 可以结合起来创造新的东西。它们允许开发者更快地测试他们的假设。
发布一个 API
另一方面,如果你有一些可以分享的(丰富)数据,你也可以自己提供一个 API。如果这些数据可以被他人利用来构建新的东西,你可能想要将 API 视为一种可以收费的服务。如果你的 API 提供了真正的价值,那么你很可能从中获得利润。它可能有一个有趣且可持续的盈利模式。
由于可能很难以传统方式使你的应用盈利,考虑发布与你的应用或应用生态系统相关的 API 可能是一个有趣的想法。许多公司,如 SalesForce 或 Expedia,已经从 API 订阅中获得了大部分收入,所以这是一个值得探索的有趣途径。
乐高还是得宝?
如果你将混合体解决方案与从头开始创建的解决方案进行比较,那就像比较得宝与乐高。如果你使用第三方解决方案,那么你的应用开发将更快、更智能,可能也更便宜。小型且可重用的微服务可以轻松组装成更大、更复杂的应用。显然,玩乐高更有趣,但使用得宝可以更快地搭建一座塔。
你不必深入所有各种技术挑战,你可以专注于最重要的事情。实现将产生你解决方案独特价值主张(UVP)的功能。
有许多不同类型的混合体。想想看,有消费者混合体、商业混合体、数据混合体和逻辑混合体。你需要特定的数据吗?你想提供航班或假期吗?你需要支付解决方案吗?或者,你需要发送大量短信、调暗灯光,或者想要外包任务?猜猜看?为此有一个 API!
API 与 SDK 的比较
API 是接口,通常作为 REST 服务提供。软件开发套件(SDK)专门用于在特定平台(如 iOS 或 Android)上实现 API。这将使集成过程更加顺畅。我们已经在第四章,“敏捷工作流程概述”中看到了一个例子,我们查看了一个使用 Firebase 的 Android 应用。在那个例子中,你可能注意到了 Firebase 的 Gradle 依赖项。这是一个对 Android SDK 的引用,它将负责与 Firebase API 的通信。API 本身允许你执行所有操作,但 SDK 将为你节省大量时间。
依赖项管理
API 和 SDK 的本质是它们将经常更新。因此,一个智能的依赖管理计划很重要。你不想每次 SDK 发布新版本时,都要更新模块或更新应用中的所有代码。
Android
对于 Android,你应该使用外部 Gradle 依赖项,而不是将库模块添加到你的项目中。如果你使用 Android Studio,那么你就可以立即开始使用 Gradle。你将在项目中的应用文件夹中的build.gradle文件中找到你应用的依赖项列表。依赖项部分看起来可能如下所示:
dependencies {
...
compile 'com.android.support:recyclerview-v7:23.1.1'
compile 'com.android.support:cardview-v7:23.1.1'
compile 'com.squareup.retrofit:retrofit:2.0.0-beta3'
compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
compile 'com.squareup.okhttp:okhttp:2.4.0'
compile 'net.hockeyapp.android:HockeySDK:3.6.2'
}
如此例所示,Retrofit、HockeyApp 以及一些其他依赖项在此处被定义。你可能已经熟悉它们。例如,Retrofit 和 Gson 转换器是用于通过 HTTP 消费数据并将结果反序列化为对象的解决方案。虽然依赖项也可以指本地库,但强烈建议使用前面所示的方式使用依赖项。有关 Gradle 的更多信息,请访问gradle.org。
iOS
对于 iOS(以及许多其他语言和 IDE),你也可以使用 Gradle。如果你在 Android 和 iOS 平台上工作,并且希望使用相同的工具通过构建服务器(如 TeamCity 或 Jenkins)构建你的应用程序,这将特别有趣和有价值。关于这一点,请参阅第十八章,持续集成、交付和部署,关于持续交付的更多信息。
另一个广为人知的解决方案,但仅适用于 iOS 开发,是 CocoaPods。它是一个用于 iOS 项目(Objective C 或 Swift)的依赖管理器。它通过创建一个工作区来管理第三方库,该工作区除了包含您自己的项目外,还将包含一个 CocoaPods 项目,我们的依赖将驻留其中。
pod文件包含依赖项列表,其外观如下:
platform :ios, '8.0'
use_frameworks!
target 'example-project' do
pod 'ZXingObjC', '~>3.0'
pod 'JSONJoy-Swift', '~> 1.0.0'
pod 'SwiftHTTP', '~> 1.0.0'
end
如此例所示,pod文件在众多 pods 中,引用了Zxing库。这是一个创建和扫描条形码图像的完美解决方案。安装和配置cocoapods相当简单。你只需在你的终端应用程序中输入gem install cocoapods即可。接下来要做的事情是定义包含项目将使用的引用的pod文件。你需要执行pod install来实际获取依赖库。在终端应用程序中运行此命令将在pod文件中列出所有依赖项。我们将在构建 MVP 的段落中更详细地了解此过程:
$ gem install cocoapods
$ pod install
值得一提的是 Carthage。它是 CocoaPods 的替代方案,并且是第一个明确支持 Swift 的依赖管理器。CocoaPods 是用 Ruby 构建的,而 Carthage 是用 Swift 构建的。Carthage 似乎更加灵活,但使用起来也更复杂。
如需了解有关 CocoaPods 的更多信息,请访问cocoapods.org。如果你想知道更多关于 Carthage 以及 CocoaPods 和 Carthage 之间差异的信息,请查看github.com/Carthage/Carthage。
可用 API
可以通过(公开)API 收集关于许多不同主题和来自各种来源的数据。你可以在提供 SaaS 的许多公司的网站上找到它们,或者你可以检查提供几乎所有可用 API 的聚合列表的网站之一。
在www.programmableweb.com/或mashable.com/上,您将找到许多可以用于灵感的 API。您也会在那里找到许多混合解决方案。您会发现许多可以用于您的应用程序的 API。大多数 API 并非专门为移动应用程序设计,但只要数据可以以 JSON 或 XML 格式消费,这实际上并不是一个问题。在网站上,您可以搜索特定类别、特定数据类型,或者浏览最新的添加内容。正如您所看到的,跟踪天气总是一种有趣的数据来源,并且有许多应用程序使用这些数据。一个例子是应用程序 InstaWeather(见instaweather.me/)。在后面的段落中,我们将看到我们如何使用这些 API 来构建我们的 MVP:

您还可以在其他地方寻找 API 和混合解决方案的示例:
如果您知道一个没有 API 的数据源,那么您可以考虑一个替代方案,比如(网站)抓取。这是一种许多提供聚合内容(工作、房地产和保险)的网站所采用的方法。不过,网站抓取可能会很棘手。它可能会非常容易出错,但有时它是快速完成任务或获取特定数据的唯一方法。特别是对于您的第一次实验(MVP)来说,这是一个有趣的方法。
证明我们假设的 iOS 应用程序,MoviUber
到目前为止,我们已经讨论了理论。现在是时候构建我们的最小可行产品(MVP)了。这个 MVP 结合了来自各种来源的数据,以展示您如何能够快速创建一个有价值的应用程序。在本节中,我们将构建一个 iOS 应用程序,用于探索著名电影的地点。它将展示使用 API 和 SDK 来验证我们假设的概念。
假设
在没有首先定义我们的假设之前,我们无法开始。所有人都喜欢电影。有些人比其他人更喜欢。让我们假设电影狂热者喜欢去像旧金山这样的城市旅行,探索城市并参观著名电影拍摄过的地点。许多地点无法通过公共交通轻松到达。为了到达那里,他们必须使用 Uber。
因此,这个应用是关于在旧金山旅行并使用 Uber 参观电影热门地点的。它消耗数据,提供了对应数据的新的表示形式(也许是在地图上),并将现实生活中的服务,如 Uber,与之连接。也许我们甚至可以通过查找互联网电影数据库(IMDB)中的电影标题来稍微丰富一下数据。让我们把这个应用称为 MoviUber。对于这个应用,我们不会过多地阐述商业模式。我们只想弄清楚我们是否可以连接这些点。如果我们可以让这一切工作起来,那岂不是酷毙了?我们需要做什么才能让它发生?
通过客户访谈验证想法
我们首先需要知道创建这个混合解决方案是否有意义。也许你首先想给这个概念添加自己的特色,然后作为一个练习,尝试验证这个想法。看看你是否能找到一个既热爱电影又已经在使用 Uber 的人。
向他或她介绍这个概念,并询问他或她对它的看法。只问开放式问题。如果你问朋友,“你认为这会是一个极好的主意吗?”,你很可能会得到一个肯定的回答。虽然听起来很令人高兴,但这并不能帮助你验证这个想法。
不管怎样,如果他或她对这个概念非常热情,那么可能会有一些新的想法或功能出现,或者你可能得到一些关于为什么这个整个应用想法实际上是一个非常糟糕的计划的大洞察。你永远不知道。
由于本章专门讨论创建混合解决方案,我们将假设这个想法已经得到了充分的验证。这是一个绝妙的计划,我们通过客户访谈收集到了积极的反馈。让我们构建一个应用。
让我们构建一个应用
要开始,让我们定义我们的 MVP(最小可行产品)的组成部分。如下所示:
-
电影地点(当然),以列表形式展示,可以浏览所有电影和地点。
-
一个 Uber 按钮,用来叫车到那里。
-
IMDB 是一个可选的组成部分,但拥有它会很不错。我们可以用它来显示关于特定电影的额外信息。
-
如果用户想要从一个地点去另一个地点,地图将是一个很棒的功能,可以用来规划路线。
电影地点
使用由 Socrata 提供的旧金山数据 API,我们可以获取旧金山的电影地点。为了获得一些印象,你可以浏览这个位置的数据集:data.sfgov.org/Culture-and-Recreation/Film-Locations-in-San-Francisco/yitu-d5am。你想去莎朗·斯通去过的地方?你可以在这个数据集中查找。
但与其在这里下载数据集,不如通过 API 访问数据更方便。这里可以找到这样的东西:dev.socrata.com/foundry/data.sfgov.org/wwmu-gmzc。经过一番研究,发现甚至还有一个 SDK。这更好。Soda-Swift 是一个本地的 Swift 库,可以访问 Socrata 开放数据服务器。你可以在 GitHub 上找到它:github.com/socrata/soda-swift。
Uber
Uber 为各种平台提供 API 和 SDK,包括 iOS Swift 库,可在 GitHub 上找到。查看github.com/uber/rides-ios-sdk 。API 的描述在developer.uber.com/docs/tutorials-rides-api。
IMDB
目前似乎还没有 IMDb API,但有一个 OMDb API。这是一个免费的在线服务,用于获取电影信息。你可以在www.omdbapi.com找到它。
最后,对于我们将要使用的地图,我们将使用 Apple 地图。为此,你只需要 MapKit 框架。太棒了。我们接下来需要做什么?
对于这个,我们将下载 SDK。同时,我们还将从github.com/socrata/soda-swift下载 Socrata 示例应用。我们将使用这个示例应用来构建我们的最小可行产品(MVP)。我们将修改一些东西,比如数据令牌和数据集。要获取令牌,你首先需要在 Socrata 上有一个开发者账户。你可以在dev.socrata.com免费注册。接下来,你需要在他们的网站上创建一个应用。在 Xcode 中打开 Socrata-Swift 项目,然后从 SODASample 项目打开 QueryViewController。修改客户端的域名和令牌:
let client = SODAClient(domain: "data.sfgov.org", token: "<your token>")
在refesh方法中,你需要修改查询的数据集,并将排序字段改为title:
func refresh (sender: AnyObject!) {
...
let cngQuery = client.queryDataset("wwmu-gmzc")
cngQuery.orderAscending("title").get { res in
switch res {
case .Dataset (let data):
self.data = data
...
}
}
在cellForRowAtIndexPath函数中,将项目的字段改为title和locations,如下面的代码所示:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) ->
UITableViewCell {
let c = tableView.dequeueReusableCellWithIdentifier(cellId) as UITableViewCell!
let item = data[indexPath.row]
let name = item["title"]! as! String
c.textLabel?.text = name
if (item["locations"] != nil){
let street = item["locations"]! as! String
c.detailTextLabel?.text = street
}
return c
}
现在,当你运行应用时,它将在第一个标签页上显示一个漂亮的电影和位置列表。为了在第二个标签页上的地图上显示它们,我们需要做一些额外的工作:

在地图上显示位置
要在地图上以标记点的方式显示位置,我们需要经度和纬度值,但不幸的是,我们只有(模糊的)地址描述。我们需要将地址转换为实际位置。为此,你需要打开 MapViewController,找到我们将要修改的updateWithData函数,我们将使用CLGeocoder来修改它。这个类非常擅长将地址转换为具有经纬度值的实际位置。
对于每个位置,我们将确定特定地址的经纬度值。一旦我们找到了这些或给定位置的 placemark,我们将为它创建一个标记点并将其添加到地图上。最后,我们将用户导航到地图上的旧金山,这样我们就可以实际看到标记点。
代码将看起来像这样:
func updateWithData(data: [[String: AnyObject]]!, animated: Bool) {
self.data = data
if (!isViewLoaded()) {
return
}
if mapView.annotations.count > 0 {
let ex = mapView.annotations
mapView.removeAnnotations(ex)
}
var anns : [MKAnnotation] = []
for item in data {
var location = item["locations"] as? String
if (location != nil){
location = location! + " San Fransisco, CA"
print(location)
let geocoder:CLGeocoder = CLGeocoder();
geocoder.geocodeAddressString(location!) { (placemarks:
[CLPlacemark]?, error: NSError?) -> Void in
print(placemarks?.count)
if placemarks?.count > 0 {
let topResult:CLPlacemark = placemarks![0];
let placemark: MKPlacemark = MKPlacemark(placemark:
topResult);
let a = MKPointAnnotation()
a.coordinate = placemark.coordinate;
a.title = item["title"] as! NSString as String
a.title = a.title! + " " + (item["locations"] as!
NSString as String)
anns.append(a);
if (error == nil && a.coordinate.latitude != 0 &&
a.coordinate.longitude != 0){
self.mapView.addAnnotation(a);
}
}
}
let w = 1.0
let r = MKCoordinateRegionMakeWithDistance(
CLLocationCoordinate2D(latitude: 37.79666680533*w,
longitude: -122.39826411049*w), 40000, 40000)
self.mapView.setRegion(r, animated: false)
}
}
这就是地图将看起来像什么:

Uber 集成
我们现在有一个带有标记点的地图。我们可以从 Uber 功能的集成开始。我们将保持简单,只在我们的应用中显示一个 Uber 行程请求按钮。
在developer.uber.com创建一个新的应用。如果您还没有这样做,请先登录或注册 Uber:

为您的应用提供一个名称和描述,并保存更改。它将揭示您在应用中实现 Uber 功能所需的客户端 ID。您可以在 GitHub 上找到 Uber Swift SDK github.com/uber/rides-ios-sdk,但您也可以使用 CocoaPods 将其包含到您的应用中,这是推荐的方式将 Uber 功能集成到您的应用中。
如果您之前没有这样做,请先安装 CocoaPods:
$ gem install cocoapods
在控制台应用中,转到 Soda Swift 项目所在的文件夹。要创建一个新的pod文件,请输入以下内容:
$ pod init
打开为您创建和修改的pod文件,这样它就会将 UberRides 项目加载到我们的工作区中:
use_frameworks!
target 'SODAKit' do
end
target 'SODATests' do
end
target 'SODASample' do
pod 'UberRides'
end
接下来,使用以下命令安装依赖项:
$ pod install
通过右键单击文件并选择“以源代码方式打开”来修改info.plist内容。将以下键值对添加到字典中,并添加您在 Uber 开发者网站上可以找到的 Uber 客户端 ID:
<key>UberClientID</key>
<string>your uber client id</string>
<key>UberCallbackURI</key>
<string></string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>uber</string>
</array>
以一种方式修改AppDelegate文件,使其使用 Uber 的沙盒模式进行测试。每次测试应用时,在您的位置被接走可能有些不便。在didFinishLaunchWithOptions函数中导入UberRides并启用沙盒模式:
import UIKit
import UberRides
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [NSObject:
AnyObject]?) -> Bool {
// If true, all requests will hit the sandbox
Configuration.setSandboxEnabled(true)
return true
}
在 QueryViewController 中,在 UIKit 导入的下方添加对MapKit和UberRides的新导入:
import MapKit
import UberRides
import CoreLocation
我们需要稍微修改一下didSelectRowAtIndexPath函数。如果用户点击任何一行,将显示一个按钮,可以点击以启动行程。代码和 UI 都需要一些美化,但这超出了 MVP 的范围。为此,将检索选中项的经纬度值,这次是为了告诉 Uber 用户想去哪里(下车地点)。我们没有指定接车地点。默认情况下,Uber SDK 将使用用户的当前位置。这可能并不总是足够准确,但对于 MVP 来说已经足够了。
Uber Rides SDK 会检查CLLocationManager中的locationServicesEnabled()的值,它必须是 true 才能检索用户的当前位置:
override func tableView(tableView: UITableView!,
didSelectRowAtIndexPath indexPath: NSIndexPath!) {
let item = data[indexPath.row]
var location = item["locations"] as? String;
if (location != nil){
location = location! + " San Fransisco, CA"
let geocoder:CLGeocoder = CLGeocoder();
geocoder.geocodeAddressString(location!) { (placemarks:
[CLPlacemark]?, error: NSError?) -> Void in
if placemarks?.count > 0 {
let topResult:CLPlacemark = placemarks![0];
let placemark: MKPlacemark = MKPlacemark(placemark:
topResult);
if (error == nil && placemark.coordinate.latitude != 0 &&
placemark.coordinate.longitude != 0){
let behavior = RideRequestViewRequestingBehavior(
presentingViewController: self)
let dropOffLocationlocation = CLLocation(
latitude: placemark.coordinate.latitude,
longitude: placemark.coordinate.longitude)
let parameters = RideParametersBuilder().
setDropoffLocation( dropOffLocationlocation).build()
let button = RideRequestButton(rideParameters:
parameters, requestingBehavior: behavior)
self.view.addSubview(button)
}
}
}
}
最后,所示的方法在视图中添加了一个 Uber 按钮。这包括用户当前所在的位置和他想去的位置的知识。这使得用户可以点击应用中的按钮来订购行程,并且它包含了 Uber 需要知道的所有知识。
丰富数据
最后,作为一个可选练习,如果您想丰富电影位置数据,您可以从 OMDb API 获取一些额外的电影信息和电影图片。由于我们知道电影的标题,我们可以在 API 上执行查询。格式良好的 JSON 响应告诉我们有关剧情、演员的信息,甚至还提供了 IMDb 图片的 URL。我们可以在应用中显示这些信息,以告知用户电影的内容。
要获取 API 密钥,请访问www.omdbapi.com并点击 API 密钥链接。如果您使用电子邮件地址注册,可以免费获得一个。您将收到一封包含您自己的 API 密钥和激活链接的电子邮件。激活后,您可以在请求中添加您的 API 密钥。www.omdbapi.com/?t=Basic+instinct&y=&plot=short&r=json&apikey=<api key>.
这个查询的响应看起来像这样:
"Title":"Basic Instinct","Year":"1992","Rated":"R","Released":"20 Mar 1992","Runtime":"127 min","Genre":"Drama, Mystery, Thriller","Director":"Paul Verhoeven","Writer":"Joe Eszterhas","Actors":"Michael Douglas, Sharon Stone, George Dzundza, Jeanne Tripplehorn","Plot":"A violent, suspended police detective investigates a brutal murder, in which a seductive woman could be involved.","Language":"English","Country":"France, USA","Awards":"Nominated for 2 Oscars. Another 5 wins & 18 nominations.","Poster":"http://ia.media-imdb.com/images/M/MV5BMTcxMjY2NzcyMV5BMl5BanBnXkFtZTYwMjAxNTQ5._V1_SX300.jpg","Metascore":"41","imdbRating":"6.9","imdbVotes":"131,796","
通过捆绑来自多个数据集的数据,通过以不同的方式显示它们(在移动设备上的列表和地图上),以及通过添加 Uber 功能使从一个地点到另一个地点的旅行更加方便,我们创建了一个真正酷炫的 iOS 混合应用。要查看这可能走向何方,包括 OMDb 数据集成,您可以下载并检查 Packt 的完整应用代码。
我们不得不进行一些编码来构建这个 MVP。你可能想知道是否有不通过编码就能证明事物的方法。确实有。我们这里不讨论用户访谈或分析指标。我们也可以使用If This Then That(IFTT)来构建 MVP。它允许我们自动化简单但往往有趣的任务。
看!没有代码。用 IFTT 证明你的假设
如 IFTT 之类的服务为 API 的可能性添加了一个逻辑组件。如果特定数据源(通道)发生某些事情,那么需要执行其他操作。这对于物联网(IoT)相关概念尤其有效,但您可以连接几乎任何您喜欢的服务。您可以亲自检查iftt.com/?reqp=1&reqr=。
使用 IFTT 需要很少或不需要编程,使其成为自动化小任务(所谓的食谱)的完美环境。它还可以在您实际构建事物之前帮助您验证您的假设。让我们试试。如果您还没有注册 IFTT,请在继续之前注册。我们想证明我们的假设,为了简单起见,这缩小到以下内容:

用户希望被提醒把毛巾放进包里。这在#towel day(5 月 25 日)尤其重要,但当他们去机场时也同样重要,因为 UFO 可以轻易降落。如果你想让他们接你,就挥舞你的毛巾。
嘿,你刚才读了什么?如果你认为这是一个蹩脚的例子,或者它对你来说没有意义,我建议你先读一读《银河系漫游指南》。你也可以在www.towelday.org上查看。无论如何,让我们来探讨 IFTT 是什么以及我们如何使用它来验证这个假设:

食谱、通道和触发器
创建一个新的食谱很简单。对于我们的 MVP,用户位置将是触发器。在这个例子中,我们将使用 IFTT 安卓应用程序。
我们选择 Android 位置作为通道,并选择“你进入一个区域”作为触发器:

接下来,你需要定义特定的位置,即最近的机场。在我的例子中,是鹿特丹机场:

无论何时用户进入这个区域,我们都希望得到通知。让我们使用 Twitter 作为通道发送关于这个事件的短信。每当这个事件发生时,我们都会从 Twitter 收到一条直接消息:

我们就完成了。如果你自己或其他人分享这个食谱,技术上它就可以工作。设置这样的事情来帮助验证你的假设真是太简单了。如果你已经完成了验证过程,你总是可以构建一个能够执行相同任务的真实应用程序。
你可以想到很多其他的食谱。例如,如果你有一个智能恒温器,你可以降低温度,因为你已经在机场了。或者,你可以看看这个食谱;例如,“当你降落时发送电子邮件”在https://ifttt.com/recipes/134835-send-an-email-when-you-land。无需额外努力,你的亲人就会知道你安全了。
摘要
在本章中,我们看到了 API 和混合如何帮助我们验证假设。只需付出最小的努力,我们就可以创建一个 MVP。在我们之前,我们只能使用 API 来消费和组合数据,但现在我们也可以使用它们来外包任务。你可以想象图像识别、3D 打印、配送或由人类执行的任务。
我们看到了什么是混合解决方案以及存在哪些类型的混合。我们创建了一个 iOS MVP 应用程序,展示了结合多个 API 的想法。
最后,我们探讨了 IFTT 提供的服务,这取决于你的需求,可能是验证假设最快的方法,然后是构建实际应用程序。在 IFTT 上有大量的食谱可供使用,或者你可以创建自己的食谱。我们还讨论了集成来自社交网络(如 Facebook 和 Twitter)的 API 和 SDK 的好处。
在即将到来的章节中,我们将更深入地探讨社交网络的整合以及这如何特别影响入职流程。你将在下一章关于入职和注册流程的内容中了解更多相关信息。
第十一章:入职和注册
在本章中,我们将专注于您应用的应用入职和注册部分。它始于从 Play Store 或 App Store 下载应用的人。这已经是一个重要的转化。现在他们需要成为应用的常规用户。这并不像听起来那么简单。研究表明,平均有 20%的应用只使用一次。Google Play Store 或 App Store 中有许多竞争应用。因此,为您的应用制定一个完美的入职策略是必不可少的,并且它可以极大地促进良好的转化。用户对您的应用的第一印象应该是好的。为了使转化尽可能顺利,重要的是要展示对他们有什么好处。你应该问问自己,为什么他们应该继续使用这个应用。从一开始,你必须帮助他们理解应用带来的附加价值。
我们想要用户注册的原因有很多。其中之一是已知用户比匿名用户更有价值,但注册可能成为障碍。特别是在用户需要立即在他们看到的第一个应用屏幕上注册的情况下。由于他们还没有弄清楚应用是关于什么的,你可能会在那里失去一部分观众。你要求得越多,过程就越困难。通过使用各种技术,你可以避免这种情况。在本章中,我们将看到如何降低入职过程的门槛,以及社交登录过程如何对此做出贡献。我们还将探讨通过短信进行注册和验证。
为了展示这一点和其他功能,我们将创建一个使用 Fabric 和 Firebase SDK 的应用。我们还将了解我们可以做些什么来提高应用知名度,以及一个持续的入职流程如何帮助您获得两全其美的效果。这种流程将降低门槛,并且还会导致丰富的用户资料,正如我们将在本章后面看到的。
简而言之,在本章中,我们将涵盖以下主题:
-
了解用户入职是什么,以及我们如何通过降低门槛来提高转化率
-
了解如何使用 Facebook 或 Twitter 进行社交登录
-
看看其他替代方案,例如类似 WhatsApp 的通过电话号码注册
-
了解如何使用持续入职来获得两全其美的效果(低门槛和丰富数据)
-
调查一个展示入职(包括后期入职)的应用
-
了解分享和寻找朋友如何有助于提高应用知名度和帮助入职过程
用户入职是什么?
引导流程始于潜在用户首次下载并打开你的应用程序。你必须说服那个用户,并确保他立即会注意到应用程序的好处。你希望将潜在用户转化为积极参与的用户,而这个过程从应用程序显示的第一个视图开始。为了实现这一点,应用程序的第一印象在视觉上应该有趣,并且应该解释为什么用户应该使用这个应用程序。实现这一目标的一种方法是通过一个或多个幻灯片创建一个介绍视图。记住,在移动设备上空间有限,所以你需要保持简短和简单。它应该清楚地解释应用程序的“为什么”和“是什么”。具体如何操作留待以后再说。
在谈论应用程序的功能(“是什么”)之前,先向用户展示应用程序的好处(“为什么”)。
展示最多三到四个好处。例如,它们可以解释用户如何将应用程序整合到他的生活中,以及应用程序提供了哪些价值。使用页面滑块或其他技术一次展示一个好处。在沟通中保持清晰,并尽量不使用户感到困惑。使用一致的风格、词汇和方式来解释概念。乍一看,引导流程可能看起来相当明显,但实际上并非如此。许多应用程序,即使是知名的应用程序,也要求用户在第一页注册,几乎没有解释应用程序是关于什么的。这可能对几乎每个人都熟悉的 Facebook 应用程序有效。这可能不适合你的应用程序。
典型的流程是这样的:用户下载应用程序后,通过简短的介绍了解其内容,然后被要求注册。那时,通常不清楚为什么用户需要输入用户名、输入密码、确认密码以及输入几个必填字段。在这个阶段,许多潜在用户会流失:

为什么这很重要?
一个出色的介绍故事应该指出应用程序的核心价值以及用户从中能得到什么。引导流程很重要,因为它与成功的转化密切相关。每一步你都会失去客户,这是无法完全避免的,但如果你为你的应用程序有一个出色的引导流程,那么损失的数量可以限制。作为一个例子,让我们考虑这样一个场景:每天有 100 个用户下载你的应用程序,其中 60 个注册,其余的 40 个决定稍后或可能永远不会这样做。在这 60 个用户中,只有 30 个在下一个月仍在使用应用程序。在这 30 个用户中,只有 15 个邀请朋友、分享应用程序的内容或进行应用内购买。这仍然是一个非常乐观的故事。
在这个最后一点上,我们可以考虑将用户视为客户,因为他以某种方式(金钱或认知)为我们带来收入。然而,在从潜在用户到客户的转化过程中,我们失去了 85 人。必须有一种方法可以提高转化率。为了做到这一点,我们必须采取一些明智的措施,并且我们需要收集关于该过程的反馈。
入门流程关乎转化,总结如下:
-
从在 App Store 或 Google Play Store 意识到应用的人到通过下载应用成为潜在用户
-
从下载应用的可能用户到通过注册成为实际用户
-
从注册用户到经常使用应用的用户
-
从普通用户到通过分享或邀请朋友推广应用成为大使
海盗指标(AARRR)
只有如果我们对优化过程有洞察力,我们才能进行改进。如果我们想从过程中学习,我们需要对其进行测量。转化是我们将在另一章中测量的内容。在那里,我们将更详细地研究我们可以应用于移动应用开发的可操作指标。
这些所谓的海盗指标(AARRR,显然这是海盗们说的)完美地描述了为什么入门流程如此重要以及每个阶段在转化漏斗中代表什么。简而言之,流程如下:
-
A 代表 获取 或 认知****,因此他们能在商店中找到您的应用并下载它。
-
A 代表 激活,当用户注册时。
-
R 代表 留存,意味着用户定期使用该应用。下载了应用的用户中,有多少人在一周、一个月或一年后仍在使用?
-
R 代表 收入,因为人们通过应用内购买或其他我们在另一章中将要审查的货币化方式赚钱。
-
R 代表 推荐,其中用户通过分享内容或邀请朋友来告知其他用户关于您的应用。你的应用能否通过口碑或分享而病毒式传播?

可操作指标可以帮助你识别入门过程中的摩擦点。你将在第十三章中了解更多关于这一点,Play Store 和 App Store 技巧(拆分测试)和第十五章中,增加用户粘性和提高留存率。
更高的转化率
通常,移动应用不太关注入门流程。至少,如果你审查 App Store 中的许多应用,你会有这样的印象。你可以为你的应用做出改变。如果你的入门故事更有吸引力,如果注册的门槛更低,那么从获取到激活的转化率会更好。如果你还能向用户展示应用的使用方式,并且他对事物的工作方式感到自信,那么你将提高用户的留存率。他将会频繁地使用你的应用。
为了取得领先,我们需要考虑一种降低用户门槛的方法。有多个已知的引导模式可供选择,而且没有理由你不能将它们结合起来。以下是一些这些模式:
-
简介
-
指南(或游览)
-
乐趣之旅
-
社交注册
-
持续引导
简介方法显示几页幻灯片,通常需要用户注册,但一些应用程序选择立即显示应用程序的内容。指南或游览展示了真正的应用程序,并指出一些示例案例。
乐趣之旅方法略有不同,因为它允许用户立即使用应用程序,并时不时地突出显示对用户来说新的功能。这是展示应用程序内容的一种很好的方式。但请注意。如果你的应用程序比较复杂,这个选项可能会让用户感到有些不知所措。
社交注册允许用户使用他的 Twitter 或 Facebook 账户等快速注册。这可能是有必要让用户能够继续使用应用程序的原因,但如果首先展示应用程序的内容,并且只在需要继续时要求注册,这将降低门槛。
最后,有一个持续引导的概念,它可能非常强大,因为它带来了降低门槛和获取丰富用户档案等好处,通过鼓励用户在后期完成其档案。
如何降低门槛?
可能最好的引导流程根本不需要注册或登录。在应用程序可以使用之前真的需要这样做吗?另一方面,这也同样是真实的,已知用户比匿名用户更有价值。已知用户可以被转化为客户,这将导致一个盈利的应用程序。一个未知用户不过是一个访客。我们关于此类访客的数据很少,转换可能也会很困难:

为了降低门槛,你最好让注册过程尽可能顺畅。我见过一些应用程序在注册过程中要求用户在多个页面上填写多个字段。在移动设备上做这件事并不有趣,我们可以肯定转换损失将会很大。典型的传统引导和注册流程如下:

我们可以做得更好。所以创建一个精彩而激动人心的介绍故事,并确保用户可以立即看到应用程序的核心价值。一个非常清晰的行动号召(想想一个带有解释文本的高亮按钮)和简化的注册表单可以帮助你做到这一点。描述用户注册后将会拥有的好处,或者使用游戏化元素,如数字激励来说服用户。
社交登录选项是提高转化率并了解用户的好方法。它需要更少的步骤,因此如果用户只需点击 Twitter 或 Facebook 的注册按钮,他们更有可能注册。
要查看一些入门案例研究,您应该检查www.useronboard.com。它包含许多知名应用的入门流程,包括改进的评论和建议。您可以在那里找到 WhatsApp、Yo、Twitter、Foursquare、Snapchat 以及许多其他应用的入门流程。
您可能还想访问uxarchive.com以查看更多示例。
使用 Twitter 或 Facebook 等社交网络进行单一登录
社交注册具有多重好处,不仅对用户有利,也对开发者有利。避免漫长的注册过程和许多字段。用户注册的可能性增加,并且,在适当的权限下,您可以立即获取有关该用户的一系列信息,例如,用户的头像和姓名,这对于个性化选项来说非常棒。
提供社交登录可能比基于表单的注册多 50%的注册率。还可以提供其他信息,例如,您可以用来邀请朋友加入应用的联系人列表。根据您应用的性质,您可以让用户使用 Twitter、Facebook、Pinterest、LinkedIn 或其他任何受信任的社交网络登录。如果您的应用提供对平台的访问(双边市场),这也可能取决于您的用户性质。例如,对于在线学习解决方案,有面向教师和专业人士的 LinkedIn 注册功能,但学生使用的是 Facebook 注册流程:

使用社交登录的好处如下:
-
注册更快,因此转化率更高
-
邮箱地址立即验证
-
获得的数据是真实的可能性增加
-
个性化,从而产生更多忠诚的粉丝
-
高度参与度
-
需要的支持(如重置密码服务)减少
-
重复用户数量增加
-
由于邀请和分享,增加了推荐的机会
没有一种解决方案适合所有人。您需要决定您将支持哪些社交网络,也许您会选择支持多个。如果您对您的应用有国际化的目标,这一点尤为重要。在美國和欧洲的大部分地区,Facebook 或 LinkedIn 的注册功能非常合理,但在世界其他地区(例如中国或俄罗斯)这些网络可能不太受欢迎(或者根本无法访问),您可能希望为这些特定地区提供另一种注册选项。这可能是一个社交网络,或者您可以提供一个回退机制。您仍然可以在您的应用中提供基于表单的注册流程。您可以使用它来处理用户无法或不想使用社交注册的情况。如果您决定支持它,这取决于您。您可以通过它获得一些额外的受众,但代价是(开发和转化)。因此,有些应用只选择支持一个或多个社交注册选项。
展示您拥有的东西
另一种方法是立即显示应用的内容(如果应用的性质允许您这样做),只有在需要时才要求社交注册。
这样就不需要或只需要很少的介绍。就像许多电子商务解决方案(想想网店)一样,只有在必要时才要求注册。在网店的情况下,这是结账所必需的。对于移动应用来说,这可能适用于例如用户不再只是消费,还希望为流贡献力量的情况。您可以想到一个允许用户对出现的消息进行评论的新闻应用:

这样可以进一步降低门槛;然而,缺点可能是大量用户永远不会注册,因此对您来说价值较低。例如,匿名用户不太可能从您的应用中分享很多内容,而且由于我们不知道他们是谁,邀请他们的朋友也是不可能的。
电话号码注册 - 一个很好的替代方案
WhatsApp 和其他一些应用正在使用设备的电话号码来识别用户进行注册。这是通过短信验证码完成的。用户输入他们的电话号码,并收到包含验证码的短信,他们需要将其输入到应用中。这将确保电话号码是正确的。甚至还有一些实现拦截接收短信验证码,然后自动填写代码。这将从注册流程中去除另一个步骤:

您必须向用户明确说明,他的手机号码仅用于验证目的,并且它不会在应用中公开可用。使用手机号码还将导致用户做出更有价值的贡献。原因很简单。他知道他的手机号码与他应用中进行的所有操作相关联。有一些服务将消除与实施相关的绝大多数麻烦。在我们将在本章后面讨论的示例应用中,我们将使用 Fabric 和 Firebase,因为这是最容易实现的解决方案,并且它是免费使用的。
持续引导 - 以后完成用户资料
从你的用户那里获取最基本的信息以让他加入是一个降低门槛的聪明方法。以后你可以鼓励用户添加更多细节到他的资料,或者通过用户做出特定的选择,让应用从中学习。持续引导的概念正是如此。用户的资料将通过用户采取的行动而丰富。这将允许应用提供更好、更定制的应用体验,随着时间的推移将变得更加专注。
领英是一个完美的例子,因为每个人都会认出领英显示的提醒。它要求你完成你的资料,支持你的联系人(丰富他人的资料),或者与人建立联系。你经常会收到这样的提醒,但做这些事情永远不会是强制性的。
这里的激励甚至不是很强,但它效果很好。谁不想拥有一个全明星资料呢?你可以用这个想法为你的移动应用,正如我们很快将在示例应用中看到的那样:

讲述一个故事 - 一个示例引导应用
为了展示与引导相关的各种想法,我们将创建一个使用 Fabric 进行 Twitter 身份验证和 Firebase SDK 进行手机身份验证的 Android 应用。你也可以使用 Firebase 进行 Twitter 身份验证,但 Fabric 提供的那个使用起来更方便。
我们将把这个应用命名为“讲述故事”。使用这个应用,用户可以一起编写故事。任何人都可以阅读人们创作的故事,但如果用户想要为故事做出贡献,他需要使用 Twitter 或他的手机号码进行注册。让我们从一个简单的线框开始,它将解释应用的精确流程:

用户首次打开应用时将进入介绍视图。这个视图包含了对为什么他应该想要使用该应用以及它是什么的清晰解释。这里展示了两个非常清晰的行动号召。其中一个是使用手机号码注册的按钮,另一个是使用 Twitter 注册的按钮。
注册后,将显示现有团队故事的列表。用户可以浏览列表,如果他点击任何故事,详细视图中将显示完整的故事。用户也可以决定自己开始一个故事。这里还有一个清晰的行动号召,以“开始一个故事”按钮的形式可视化。
详细视图显示了故事的全部行,包括作者的姓名。现在用户可以阅读完整的故事,或者他可以通过点击“为故事做出贡献”按钮来为故事做出贡献。这样做将带他到“为...做出贡献”视图,在那里他可以输入新的一行代码。如果用户通过点击“开始一个故事”按钮开始一个新故事,他将看到相同的视图。在这种情况下,用户还将被要求提供故事标题。点击“将新行添加到故事”按钮将把新行添加到故事中或创建一个新故事:

需要时进行入职注册
我们还需要在应用中添加一个延迟入职选项。为此,我们将在简介视图中添加一个“暂时跳过”按钮。在第十三章,“应用商店和商店应用技巧”,关于拆分测试的部分,我们将看到如何了解哪种方法最有效。我们需要知道哪种实现将导致最高的转化率。基于这个反馈,我们可以移除“暂时跳过”按钮、简介视图中的注册按钮,或者决定保留简介视图中的所有三个选项。
注意,尽管此按钮被突出显示以演示延迟入职流程,但此按钮不应是主要的行动号召,因此不应将其标记为这样的按钮。我们希望降低门槛,但仍然希望鼓励用户尽早注册:

如果用户选择点击“暂时跳过”按钮,因为他显然还没有完全确信应用的好处,他将会立即看到故事列表。只有当他想要开始一个新故事,或者他想要为现有故事做出贡献时,他才会被要求通过 Twitter 或电话/短信进行注册。对于我们的应用,我们希望支持这两种类型的流程。让我们从实现我们刚才看到的内容开始。
实现
您可以在此处找到本章的示例项目:github.com/mikerworks/packt-lean-onboarding。
代码示例已更新,因此它将使用最新的最佳版本(在撰写本文时)。Digits,Fabric 手机身份验证服务,已被 Firebase 手机身份验证服务取代。代码示例现在使用此服务,而且我在忙碌之余,还将 Android Java 示例转换为 Kotlin。
您可以先查看该应用,或者如果您想为自己配置它,您需要先配置 Fabric 和 Firebase。
访问fabric.io并创建一个账户。一旦您完成并确认,您就可以继续了。输入一个团队名称(例如packt-demo)并选择一个平台(Android)。之后,向导中的新页面将显示多个选项。首先选择 Twitter 选项。第一条信息告诉您如何配置您的 Android 项目。使用向导(或手动操作)在 Fabric 环境中创建第一个应用程序并将其命名为onboarding。您需要这样做以获取允许您在自己的应用程序中使用 Fabric SDK 的密钥和 ID。
接下来,我们需要为电话号码认证做一些事情。Fabric 的 Digit 服务正是这样做的,但它已被 Firebase 电话认证所取代。因此,您需要在 Firebase 上设置一些事情。访问console.firebase.google.com并创建一个新的项目,或者如果您还没有注册 Firebase,您需要先注册。
按照 Firebase 的设置说明操作。在认证部分,您可以选择为您的应用程序使用哪些注册方法。如果您点击手机注册选项并启用它,您就可以继续使用示例应用程序。
让我们浏览一下应用程序。在飞行中,您可以修改 API 密钥和密钥以匹配您自己的设置。一旦在 Android Studio 中打开,您应该展开应用程序文件夹。找到此文件夹中的 build.gradle 文件并打开它。
您会看到该文件包含对 Fabric 和 Firebase 的一些依赖项。我们稍后会使用它们,这样我们就可以使用 Twitter 或 Firebase 电话认证进行登录。此外,我们可以使用TweetComposer类在 Twitter 上分享故事。请注意,您可能需要将版本号更新到最新版本。它们出现在各种包名称定义的末尾:
...
apply plugin: 'io.fabric'
repositories {
maven { url 'https://maven.fabric.io/public' }
maven {
url 'https://maven.google.com'
}
mavenCentral()
}
dependencies {
...
compile('com.twitter.sdk.android:twitter:1.13.3@aar') {
transitive = true;
}
compile('com.twitter.sdk.android:tweet-composer:1.0.3@aar') {
transitive = true;
}
...
implementation 'com.google.firebase:firebase-auth:11.4.2'
implementation 'com.google.firebase:firebase-database:10.2.4'
}
apply plugin: 'com.google.gms.google-services'
现在,打开app/src/main/文件夹中的AndroidManifest.xml文件。元数据部分包含ApiKey的值。修改它,使其具有与您在Fabric.io上的配置相对应的值:
<meta-data
android:name="io.fabric.ApiKey"
android:value="fill in your api key" />
与引导活动关联的布局显示了一段简短的介绍,解释了用户为什么想要使用该应用程序以及开始使用它有多简单。电话号码和 Twitter 注册按钮在这里都是清晰的行动号召:

还有一个额外的按钮,它被有意做得更小、颜色更少。它的目的是允许用户暂时跳过注册过程,以防他只想看看应用程序的内容。
打开strings.xml值并更新twitter_key和twitter_secret。用您自己的值替换它们。您可以在 Fabric 网站上找到它们:
<resources>
<string name="twitter_key">fill with your own Twitter key</string>
<string name="twitter_secret">fill your own Twitter secret</string>
打开OnboardingActivity类。在onCreate方法中,调用了initFabric方法。这就是 Fabric 初始化 Twitter 认证和分享的地方:
private fun initFabric(){
val authConfig = TwitterAuthConfig(getString(R.string.twitter_key), getString(R.string.twitter_secret))
Fabric.with(this, Twitter(authConfig))
Fabric.with(this, TwitterCore(authConfig), TweetComposer())
}
跳过按钮的点击监听器使应用程序立即跳转到列表。如果点击,Twitter 登录按钮将显示一个请求权限的 Twitter 对话框。如果授予此权限,回调的成功方法将被触发。然后我们将存储TwitterSession对象,并通过调用onShowList方法向用户显示故事列表:
为了简化,AuthenticationHelper除了在应用程序的生命周期内之外,不会持久化会话。在生产应用程序中,只要它们有效,持久化它们会更为方便。
您可以在setupTwitterLoginButton和signinWithTwitterAuthCredential方法中找到我们刚才看到的实现,如下所示:
private fun setupTwitterLoginButton(){
twitter_login_button.setCallback(object : Callback<TwitterSession>() {
override fun success(result: Result<TwitterSession>) {
mTwitterSession = result.data
Log.i(javaClass.simpleName, "Twitter login @" + result.data.getUserName() + ")")
val credential = TwitterAuthProvider.getCredential(
result.data.getAuthToken().token,
result.data.getAuthToken().secret)
signinWithTwitterAuthCredential(credential)
}
override fun failure(exception: TwitterException) {
Log.d(javaClass.simpleName, "Login with Twitter failure", exception)
}
})
}
signInWithPhoneAuthCredential方法使用用户的 Twitter 名字作为 Firebase 用户注册用户。我们稍后会使用这个手机号码来识别用户的贡献。
private fun signinWithTwitterAuthCredential (credential: AuthCredential){
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, OnCompleteListener<AuthResult> {
if (it.isSuccessful) {
AuthenticationHelper.user = it.result.user
Log.i(javaClass.simpleName,
"User logged in or registered with twitter name ${AuthenticationHelper.user?.displayName}")
continueFlow()
} else {
if (it.exception is FirebaseAuthInvalidCredentialsException) {
onboarding_code_feedback_text.text = "Invalid code."
}
}
})
}
要使用手机号码注册,我们需要告诉 Firebase 通过短信向用户发送验证码。我们将在sendPhone方法中完成此操作:
private fun sendPhone(){
val number = onboarding_phone.text.toString()
PhoneAuthProvider.getInstance().verifyPhoneNumber(
number, 60, TimeUnit.SECONDS, this, getCallback());
}
回调实现位于getCallback方法中。onCodeSent是最有趣的事件。如果验证码已发送,我们将存储返回的验证 ID。我们稍后会需要它来使用代码验证用户:
private fun getCallback(): PhoneAuthProvider.OnVerificationStateChangedCallbacks {
val callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
...
override fun onCodeSent(verificationId: String?, token: PhoneAuthProvider.ForceResendingToken?) {
mVerificationId = verificationId;
mResendToken = token;
...
}
}
return callbacks
}
在向用户发送验证码后,他必须输入验证码以确保提供的手机号码确实是他的手机号码。这是在sendCode方法中完成的:
private fun sendCode(){
val verification = mVerificationId
if (verification != null) {
val code = onboarding_code.text.toString()
val credential = PhoneAuthProvider.getCredential(verification, code)
signInWithPhoneAuthCredential(credential)
}
}
signInWithPhoneAuthCredential方法使用用户的手机号码作为 Firebase 用户注册用户。我们稍后会使用这个手机号码来识别用户的贡献:
private fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential) {
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, OnCompleteListener<AuthResult> {
if (it.isSuccessful) {
AuthenticationHelper.user = it.result.user
Log.i(javaClass.simpleName,
"User logged in or registered with phone no ${AuthenticationHelper.user?.phoneNumber}")
continueFlow()
这里是两个用户的示例。第一个是使用 Twitter 注册的,而另一个则使用了他的手机号码进行注册:

现在,打开 MainActivity。在onCreate方法中,您会看到我们首先做的事情之一是调用onList方法。onList方法创建一个新的StoriesFragment,通过调用showFragment方法,默认会显示故事列表:
fun onList() {
val fragment = StoriesFragment.newInstance()
showFragment(fragment)
}
fun onCreateStory() {
val newStory = Story()
newStory.lastUpdate = "today"
val fragment = StoryContributeFragment.newInstance(newStory)
showFragment(fragment)
}
fun onContribute(story: Story) {
val fragment = StoryContributeFragment.newInstance(story)
showFragment(fragment)
}
fun onReadStory(story: Story) {
val fragment = StoryDetailFragment.newInstance(story)
showFragment(fragment)
}
fun onLateOnboarding(story: Story) {
val intent = Intent(this, OnboardingActivity::class.java)
intent.putExtra(OnboardingActivity.ARG_LATE, true)
intent.putExtra(OnboardingActivity.ARG_STORY, story)
startActivityForResult(intent, REQUEST_LATE_ONBOARDING)
}
private fun showFragment(fragment: Fragment) {
val ft = fragmentManager.beginTransaction()
ft.replace(R.id.main_fragment_container, fragment, fragment.javaClass.toString())
ft.commit()
}
MainActivity 还负责显示其他片段,例如显示完整故事的StoryDetailFragment和StoryContributeFragment。它还包含对OnboardingActivity的调用,用于后续的注册。这将允许用户在之前跳过注册但后来想要为应用程序做出贡献的情况下注册。通过向故事添加内容或创建新的故事,他们将被要求再次注册:
val repository: Repository get() = Repository(this)
getRepository方法仅返回我们接下来将要研究的Repository类的新实例。
您将找到包含数据包的Repository类。如您所见,getDummyContent方法创建了一个示例故事列表。
repository类已经准备好与 Firebase 一起使用,但由于我们想要演示引导概念,数据仅在应用的生命周期内持久化。如果你已经阅读了第九章,原生、混合或跨平台,设置 Firebase 并修改这个类以能够将故事存储在云中将会非常容易。
类看起来是这样的:
class Repository(private val context: Context) {
fun getStories(handler: OnRepositoryResult) {
val content = getDummyContent()
handler.onResult(content)
}
fun updateContributions(story: Story) {
if (story.id == null) {
addStory(story)
}
dummyContentList.forEach {
if (it.id.equals(story.id, ignoreCase = true)){
it.contributions = story.contributions
}
}
}
fun addStory(story: Story) {
if (story.id == null) {
story.id = UUID.randomUUID().toString()
}
dummyContentList.add(story)
}
companion object {
private var dummyContentList = mutableListOf<Story>()
private fun getDummyContent(): List<Story> {
if (dummyContentList.isEmpty()) {
val dummy = mutableListOf<Story>()
val s1 = Story("A first story", "MikeR", "Today")
s1.id = "1"
s1.contributions.add(Contribution("Once upon a time", "MikeR"))
s1.contributions.add(Contribution("a giant rabbit did exist", "Pete"))
s1.contributions.add(Contribution("in a galaxy far far away", "Floris"))
val s2 = Story("A second story", "MikeR", "Yesterday")
...
dummy.add(s1)
...
dummyContentList = dummy
}
return dummyContentList
}
}
}
getStories方法异步返回所有故事和数据。updateContributions方法向现有故事添加新的贡献,或者如果故事尚不存在,通过调用addStory方法创建一个新的故事,并添加到列表中。
在models包中,你可以找到Story和Contribution类。一个Story有一个标题和多个贡献,每个贡献都有一个作者和一些内容。Parcelable实现使得从一个片段(或活动)向另一个片段传递数据变得更加方便,正如我们稍后将会看到的:
class Story : Parcelable {
var id: String? = null
var title: String? = null
var initiator: String? = null
var lastUpdate: String? = null
var contributions = mutableListOf<Contribution>()
...
fun getFullStory(includeAuthors: Boolean): String { ... }
val summary: String
get() {
val builder = StringBuilder()
if (contributions != null) {
var start = contributions.size - 3
if (start <= 0) { start = 0 }
for (build in start..contributions.size - 1) {
builder.append(contributions[build].paragraph.toString() + "\n")
}
return builder.toString()
} else {
return "This story has not started yet!"
}
}
...
getSummary和getFullStory方法使Story对象稍微智能一些,并分别返回最后三行或完整的故事文本。
Contribution类同样实现了Parcelable接口,原因与Story类相同。每个Contribution实例都有一个作者和一个段落成员。
用户首先看到的是登录视图之后的内容,了解应用的基本功能。对于功能较为复杂的应用,在首次使用时突出显示特定功能可能很有帮助。通过在引导流程中展示这些功能,我们可以鼓励用户注册应用。对于这个应用来说,事情相当明显:

每个人都喜欢故事,所以用户可能的第一步就是点击一个看起来吸引人的故事摘要。(这同样是一个需要证明的假设。)如果用户点击带有加号符号的浮动操作按钮,他将创建一个新的故事:
class StoriesFragment : Fragment(), OnCardViewClicked, OnRepositoryResult {
private var recyclerView: RecyclerView? = null
private var adapter: StoryAdapter? = null
private var viewModel = mutableListOf<Story>()
...
如果你查看StoriesFragment内部,你会看到将使用RecyclerView小部件和StoryAdapter来显示这里显示的数据。在onCreateView方法中,将调用loadData方法,该方法反过来调用Repository类的getStories方法,并将片段本身作为结果的处理者:
override fun onResult(result: List<Story>) {
viewModel = result.toMutableList()
adapter = StoryAdapter(viewModel)
adapter?.setOnCardViewClicked(this)
recyclerView?.adapter = adapter
}
当结果返回时,将创建一个StoryAdapter类的实例并将其附加到RecyclerView实例上。StoryAdapter将每个故事的数据绑定到列表中的行:
override fun onCardClicked(view: View, position: Int) {
(activity as MainActivity).onReadStory(viewModel[position])
}
如果用户点击任何一行,将触发OnCardViewClick事件,这将调用MainActivity中的onReadStory方法,并将选定的故事作为参数传递。这将带我们到StoryDetailFragment的实现。
此片段向用户显示完整的故事,包括贡献者的名字。在这里,用户可以通过点击 CONTRIBUTE(如示例图像所示)来为故事做出贡献:
class StoryDetailFragment : Fragment() {
private var mStory: Story? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mStory = getArguments().getParcelable(ARG_STORY)
}
在onCreate方法中,选定的故事将通过 bundle 接收。在这里,Parcelable实现非常有用。在onCreateView方法中,将使用story对象的getFullStory方法将故事的全部内容设置为textView的文本:

在onClick方法中,你可以找到处理各种按钮点击的处理,例如“贡献”按钮。这将调用onContribute方法,然后反过来调用 MainActivity 的onContribute方法,包括当前选定的故事。这将导致显示与StoryContributeFragment类相关的布局:
在StoryDetailFragment的onShare方法中,你可以找到用于编写和分享推文的代码行:
private fun onShare() {
val builder = TweetComposer.Builder(getActivity())
.text(String.format(getString(R.string.sharing_text), mStory?.title))
builder.show()
}
StoryContributeFragment允许用户为故事做出贡献或开始一个新的故事。在此时刻,用户从被动用户变为主动用户。此外,由于用户需要注册(尽管他可能还没有这样做),用户将被转换为已知用户。片段通过 bundle 参数获取选定的故事。它可能是一个空的,因为用户点击加号按钮,他想要创建一个新的故事。如果它是一个现有的故事,将显示故事的摘要(最后三个贡献)。
如果用户点击“贡献”按钮,将调用onContribute方法。在这里,将创建一个新的Contribution对象,并且可选地创建一个新的故事对象。贡献将被添加到故事中,我们将询问AuthenticationHelper类当前用户是否已经认证。如果用户已经认证,无论是通过 Twitter 注册还是通过 Firebase 手机注册,我们可以通过填写贡献者的名字(Twitter 名字或电话号码)来继续操作。此外,我们调用Repository类的updateContributions方法,该方法将负责存储故事:

如果用户尚未认证,我们将调用 MainActivity 的onLateOnboarding方法。在这里,我们也将故事(以及与之相关的贡献)作为参数传递:
fun onLateOnboarding(story: Story) {
val intent = Intent(this, OnboardingActivity::class.java)
intent.putExtra(OnboardingActivity.ARG_LATE, true)
intent.putExtra(OnboardingActivity.ARG_STORY, story)
startActivityForResult(intent, REQUEST_LATE_ONBOARDING)
}
OnboardingActivity还将动态处理认证过程。虽然来得晚,但总比不来好。如果你想为故事做出贡献,或者想自己创建故事,你必须先注册。现在,活动将显示一条消息,指出这一点,并再次为用户提供使用 Twitter 账户或使用电话号码注册的选择:
private fun continueFlow(){
if (mIsLateOnboarding){
val returnIntent = Intent()
returnIntent.putExtra(OnboardingActivity.ARG_STORY, mStory)
setResult(Activity.RESULT_OK, returnIntent)
this.finish()
...
如果延迟认证成功,结果将返回 MainActivity,MainActivity 将负责将贡献添加到故事中:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
if (requestCode == REQUEST_LATE_ONBOARDING) {
if (resultCode == Activity.RESULT_OK) {
val story = data.getParcelableExtra<Story>(OnboardingActivity.ARG_STORY)
val lastContribution = story.contributions.last()
lastContribution.contributor = AuthenticationHelper.userName
repository.updateContributions(story)
onList()
}
}
}
之后,通过调用MainActivity类的onList方法再次显示故事列表。这次列表将包括贡献,或者不再是不知名的用户的故事。最后注册成功!
到目前为止,对于这个应用,我们已经看到了一些关于注册和后期上线的酷炫实现。如果你喜欢这个概念,那么请随意对应用进行一些进一步的实验。例如,考虑为应用添加另外两个很棒的功能:一个邀请朋友选项(与你一起写故事)和一个分享选项(在 Twitter 或其他社交媒体网络上分享这个故事)。这将提高你应用的知名度。这将帮助你扩大你应用的用户基础。我们将在第十四章中了解更多关于这一点,A/B 测试你的应用,这是关于吸引力和留存率的:

成长黑客(除了其他事情之外,还是一个持续的过程,结果是现有用户邀请朋友加入并使用应用)。人们开始下载你的应用的原因是他们已经意识到了它。当你实施朋友推荐流程时,你会看到更高的转化率。
成长黑客:
成长黑客(基本上是营销的现代说法)是一个值得单独写书的主题。在开始构建你的应用之前,你应该考虑构建一个增长引擎。为你的应用将要解决的问题建立一个受众。这是一种测试你的应用想法和创造意识的好方法。最简单的方法是创建一个关于这个主题的常规博客。

完美的转化是这样的:一旦用户注册并开始了一个故事或对其做出了贡献(激活),然后决定继续这样做(留存),他将成为你应用的代言人,并开始分享故事或邀请朋友一起写故事(推荐)。
推荐很重要,因为口碑是营销中最有效的类型之一。超过 70%的潜在应用用户是基于朋友、同事或家人的推荐下载应用的。考虑到这一点,目标应该是让应用用户能够推动更多的知名度,这正是团队故事应用试图做到的。推荐往往是推广应用的唯一方式。这是因为,对于大多数移动应用来说,用户获取成本(广告)通常会比收入高。
由于其性质,某些特定应用,如社交或消息应用,以及当然还有游戏应用,非常适合邀请朋友。如果以某种方式无法进行协作,它们通常就没有太多意义。对于许多其他应用,分享或邀请的原因可能不那么明显。然而,如果你提供激励,例如,Dropbox 通过为每个新推荐提供额外空间来做到这一点,你仍然可以从推荐中受益。
摘要
在本章中,我们看到了引导用户和鼓励用户注册的多种方法。我们看到了保持门槛尽可能低的重要性,并且你需要从一开始就非常清楚地说明你应用的好处以及用户为什么要使用它。或者,就像西蒙·辛克所说的那样,“从为什么开始”。
我们已经看到,使用 Firebase 或 Fabric SDK 实现社交注册相对容易,我们也学习了如何为用户提供多种选择,包括最初跳过注册的选项。尽管这降低了门槛,但后者并不一定是好事。匿名用户的价值不如已知的用户。此外,已知的用户更容易转化为付费用户(客户)。你需要找出对你应用来说什么最有效。也许你最初只是想扩大用户基础。在下一章中,我们将看到拥有可扩展解决方案的重要性。
第十二章:做那些不具规模的事情
一旦你有了 MVP,你的首要目标就是推动实验通过其第一个迭代周期,以测试你的假设。在这个阶段,主要目的是验证学习。只有在你证明了你的假设之后,你才应该考虑扩展和优化。
在精益模型中,改进是随着时间的推移和用户反馈的结果发生的。当你将那个反馈循环作为你初始实验的核心时,一系列非传统的商业实践开始出现。
看看以下这些要点:
-
如何获取早期采用者并建立一个小规模的实验室,以及为什么这样做可以极大地提高你的学习效果
-
如何利用一些最受欢迎的线框和原型设计工具最大化学习
-
如何在保证质量的需求与市场速度、预算需求或其他限制之间取得平衡
-
制定技术债务管理计划的最佳方式,这对于任何开始扩展的应用至关重要
在覆盖这些主题之前,让我们看看为什么你应该做那些不具规模的事情。
我们所说的“不具规模的事情”是什么意思
在这个阶段,你的目标是进行实验,最大化学习,并最小化完成一次构建-度量-学习循环所需的时间。以反馈循环为目标,你会发现自己在进行看似表面上不合理但能极大地加速你学习的活动。
例如,对于首席执行官或创始人直接与客户互动可能看起来非常低效。如果一个初创公司想要缩短反馈循环并更深入地了解客户的需求,那么这种策略的目的就变得清晰了。
同样,将交互式线框交给用户或展示由编码快捷方式和解决方案组成的原型可能看起来是浪费的。然而,当将其视为 MVP 测试的一个阶段时,这种做法就更有意义了。
我们接下来要探讨的工具和技术可能不具规模,但它们将极大地加速早期学习,并防止技术错误在 MVP 演变过程中压倒你。
做那些不具规模的事情的三个原因
在狭窄的市场内做那些不具规模的事情,在实验、学习和产品开发方面具有显著的好处。以下是采用以用户为中心的焦点而不是传统生产导向方法的三个主要原因。
改进测试和数据收集
正如我们将看到的,以下是与早期采用者的直接互动,这些互动将提供比下游数据收集更有价值的信息。此外,这种反馈将帮助你实施适当的变更、功能和重新设计。你越早收到必要的反馈,你就能节省更多的钱。
在早期就洞察客户的心理将有助于避免昂贵的错误。例如,看看以下这些要点:
-
前期数据帮助你开发客户真正需要的功能,而不是你认为他们需要的功能
-
用户测试,特别是以下提到的某些工具和方法,将帮助你创建客户喜欢的界面设计
-
与你的最小可行产品(MVP)的早期互动也会让你更早地意识到可用性问题
你的第一批用户将帮助你找到最重要的功能、设计和可用性工作流程,这样你就可以在开始扩展之前专注于重要的事情。
可控的失败
并非每个实验都会成功。如果你的想法注定要失败,那么最好是尽早快速失败,原因有几个:
-
在受控环境中失败的低成本实验,其影响范围将小于在大型市场失败的全功能产品
-
你越早发现错误或证伪假设,你就能越早减少损失
-
在小范围内早期失败将对你的或你公司的声誉产生限制或消除任何影响
当精益方法正确应用时,失败成为一种学习和适应的机制,给你提供转向或重新开始的机会。
开发更令人喜爱的产品
如前所述,最小可行产品(MVP)让你能够创建一个目标明确、相关且有用的产品。然而,功能只是方程的一半。人们应该使用你的产品,不仅是因为他们需要,还因为他们想要。
令人喜爱的产品相较于仅仅可用的产品具有显著优势:
-
喜欢使用产品的用户会更频繁地使用它,并且使用时间更长
-
一群热情的用户更有可能谈论你的产品
-
热爱你的产品的客户将更加忠诚
精益、以学习为先的方法应该寻求了解你的客户不仅想要什么,还如何使用应用程序。当你从一开始就优先考虑用户体验时,你可以创建与用户、他们选择的平台和他们的生活相协调的产品。
由于早期采用者是对你的产品需求最强烈的那些人,因此当涉及到改善用户体验时,他们也将是你最有价值的资产。
如何吸引早期采用者并建立小规模实验室
当你在现实世界的实验室中进行首次测试时,你的策略应该旨在加速构建-衡量-学习周期。如前所述,由于重点是学习而不是生产,因此这项早期工作的大部分内容在大规模上将是不可行的。
不可扩展的工作的具体性质会因情况而异。然而,以下三种策略将帮助你加速反馈循环:
-
在狭窄的市场内工作有助于扩张,并提供一个微型实验室,在其中工作。
-
手动招募和与用户互动将立即为你提供关于你的受众和想法的详细信息
-
在这个早期阶段,与早期采用者完美地优化用户体验通常比后期进行更有效、更高效、也更经济。
不可扩展的工作可能意味着手动执行任务、在舒适区之外的工作,或者在你专业领域之外的工作。例如,用户获取和客户服务可能对程序员来说既困难又乏味。
然而,鉴于这些策略为精益开发者带来的巨大益处,它们的重要性无论如何强调都不为过。以下三种策略将帮助您为您的最小可行产品(MVP)建立测试平台,缩短构建-度量-学习周期,并将您的实验更接近可扩展性。
专注于狭窄的市场
在开始时,将实验限制在一个狭窄的市场中,例如特定的地理区域或小群体,非常有用。这有几个原因,如下所述:
-
在目标市场内进行扩张和饱和度提升,比在大市场中要容易得多。
-
狭窄的市场是实现用户临界质量的好方法,这可以帮助你从早期采用者群体过渡到大多数用户。一旦在一个特定的群体、地理区域或市场中达到饱和,你可以利用这个位置作为杠杆,进一步扩大规模。
-
数据收集和测试更容易、更便宜、更有用。
将小市场视为实验的实验室。在验证你的第一个假设时,通常在受限的环境中了解你的客户更好。在大规模上这样做通常是不切实际的且浪费的。
手动招募早期采用者
Y Combinator 这家知名初创公司孵化器的联合创始人保罗·格雷厄姆可能创造了“做那些不可扩展的事情”这个短语。
在一篇广为人知的同名论文中,他说:“创始人最初最常见且不可扩展的任务是手动招募用户。”虽然这个过程繁琐且缓慢,但格雷厄姆表示,几乎所有的初创公司都必须这样做。为了说明这一点,他讲述了支付处理公司 Stripe 是如何起步的。创始人亲自接触新用户,并使用他们的笔记本电脑现场创建新的 Stripe 账户。
虽然当然不可扩展,但手动招募可能是获取用户所必需的。在你聚集了一群早期采用者之后,你可以开始从他们那里学习并改进你的产品。
手动获取用户的另一个重要原因是“现地现物”(genchi genbutsu),这是丰田生产系统的一个核心原则。杰弗里·利克在其著作《丰田之道》中讨论了这个概念,这本书代表了二十年来对丰田的研究。他说:“除非你亲自去查看,否则你不能确定你是否真正理解了任何业务问题的任何部分。”
这就是为什么在这个阶段的第一批用户和收集的第一手数据是无价的。直接的互动会告诉你用户如何看待你的想法,他们是否认为它有用,以及你是否愿意为此付费。
完善用户体验
史蒂夫·乔布斯曾经说过:“你必须从客户体验开始,然后逆向工作到技术。”
爱彼迎的创始人也表达了类似的观点,他们说:“我们以完美的体验开始,然后逆向工作。”值得注意的是,用户体验不仅限于用户与产品的互动——它还包括用户与公司以及公司的服务的体验。
由于用户处于精益思维模式的中心,因此在产品设计中也同样需要将他们置于中心位置。在实验阶段完善用户体验可以实现多个目标:
-
当你从一开始就尽可能让他们的体验变得尽可能好时,他们更愿意提供反馈,并原谅任何不可避免的可用性问题。
-
产品激发的情感与产品的功能性一样重要——改善情感体验的影响与改善功能或可用性一样大。
-
更快乐的用户更有可能成为忠诚的追随者,并向他人推荐你的产品。
为了充分利用用户的参与——从收集数据到建立一个倡导者群体——你必须做的不仅仅是监控和回应反馈。你需要提供超越常规的礼宾服务。换句话说,把你的第一批用户当作皇室成员对待。
在我旧公司的早期,我经常直接联系客户,看看他们是否对产品和服务满意。我的日程安排非常紧张,但直接从使用我的软件的客户那里获取反馈告诉我我在哪里犯了错误,并帮助保持客户满意和参与。
爱彼迎的创始人也因为他们的亲身体验而闻名。当他们的产品在纽约的增长因低质量列表而受到影响时,创始人亲自飞往纽约帮助用户解决问题。
Chebbia 说:“我们带着相机挨家挨户地拍照,把这些公寓放到网上。我住在他们的客厅里。一家一家,一区一区,社区开始成长。人们会访问纽约,然后把这个想法带回到他们的城市。”
这个例子不仅说明了你的产品必须达到何种程度才能取悦用户,而且还说明了通过与用户直接互动你可以学到多少东西。
如何从不可扩展的 MVP 过渡到可扩展的代码
一方面,你有实验的设置,包括你的用户、市场以及现实世界的条件。另一方面,你有 MVP 本身。尽管其最早的迭代只是个实验,但它也是一个实际的产品。从一开始,就需要为潜在的增长进行规划。
在本节中,我们将讨论可以帮助你经济测试和可持续扩展的工具和技术,而不会受到技术债务这一始终存在的危险的影响:

专注于使用线框和原型进行学习
如前文在第五章“实用方法”中所述,线框和原型设计并不直接像实际软件代码那样扩展,但通过为你提供可以向用户展示的东西,它们有助于避免许多下游问题。在早期阶段,通过收集用户对产品的反应数据,你也可以收集初步反馈。随着你继续进行设计选项,你可以结合这些数据来确定何时以及如何添加或修改设计功能。
线框草图和原型设计是早期设计阶段的理想低成本选项。例如,这些可以以手绘草图、Photoshop 文件或 HTML 模拟的形式出现。还有付费工具,它们在将这些设计文件和实际交互式原型之间架起桥梁。
此外,市场上还有许多设计工具专门帮助团队进行协作设计、开发和用户测试。这些是其中最受欢迎和最有用的三个,尽管还有其他工具。我的团队已经使用这三个工具很长时间,并发现它们非常有用。通过确保我们通过原型设计而不是客户投诉来学习,这些工具为我们节省了大量时间、金钱和客户好评。
Zeplin
Zeplin 致力于弥合设计师和开发者之间的差距。
设计师可以从 Photoshop 或 Sketch 导入文件,并使用 Zeplin 生成设计规范,例如字体细节和调色板。它可以导出适用于主要平台的尺寸图像文件、CSS 文件和颜色文件。它与 Slack 集成,并且非常易于使用。
我发现 Zeplin 在避免过去的陷阱方面极其有用,这些陷阱包括你将设计交给开发者切割并应用于应用程序。通常这些交接可能会很混乱,测试过的设计在过程中被开发者有意识地或无意识地妥协——要么是故意的,要么是无意的。Zeplin 提供所有准备就绪的文件,这节省了大量时间和痛苦。
Zeplin 可以免费试用,价格根据你的预算可能相当合理,所以如果你想确保你的测试设计精确到像素,那么它值得一看。
InVision
InVision 是一个必须尝试的工具箱,用于低或高保真度的设计和测试。它允许产品团队能够实时地与彼此以及用户进行协作、共创和沟通。这个软件套件非常适合早期 UI 设计和实验,因为你可以创建交互式设计,向测试用户或利益相关者展示,并立即收集定性数据。
InVision 也继续定期添加更多工具和功能,进一步缩短了设计板和原型之间的差距。例如,Craft 允许你将草图或 Photoshop 设计转换为可以直接在手机上测试的交互式原型。Inspect 工具的操作方式类似于 Zeplin,它会从设计文件中提取编码规范——例如字体信息和调色板信息。
UserTesting.com
UserTesting.com 为应用程序和网站提供一系列测试解决方案。网站、已发布的应用程序和未发布的应用程序都提供视频录制、音频录制和分析。数据可以快速处理,因此你可以快速做出反应。
UserTesting.com 工具的一个优点是,它们通过用户的设备提供视频和音频录制。这允许你向利益相关者和其他团队成员展示硬数据和真实的人类反应。在某些情况下,当需要为一种设计而不是另一种设计辩护时,这个功能可以通过提供测试对象的可执行反馈而变得非常有价值。
专注于扩展和可持续性
在本章的这个阶段,你理解了为什么在早期采用者、狭窄的市场内运营并向他们展示交互式设计和原型很重要。然而,随着你的实验进展,从不可扩展的原型过渡到可扩展的代码将变得必要。随着你的 MVP 发展,你将需要做出许多技术决策。以下是一些包括的内容:
-
何时采取编码捷径
-
何时进行自动化和优化
-
如何处理技术债务
从你实验的开始,这些问题就应该在桌面上占有一席之地。理解这些技术考虑因素将帮助你处理它们,以免它们变得过于昂贵或难以应对。
完美代码编写与完成任务
在每个阶段,你必须做出平衡实际需求(如预算和发布日期)与编码效率及稳定性的选择。
我们已经看到,两家极为成功公司的创始人如何优先考虑客户体验,并尽一切努力将他们的产品推向市场。这意味着,幸运的是或不幸的是,在编码方面你不能成为一个完美主义者。在创建你的最小可行产品(MVP)并在严格的限制下工作时,你必须将学习放在首位,并放下对理想代码的任何执着。
用我喜欢的短语来说,“不要让完美成为优秀的敌人。”
完善实验应该是一个持续的过程,通过客户引导的迭代来实现。如果你完善了未经验证的设计、代码或功能,你就有风险改进用户可能会拒绝的东西。为了避免浪费金钱,尽快将迭代推向市场,以便你能从现实世界中学习。
自动化和优化
当市场速度至关重要时,在合理范围内,测试和快速交付应优先考虑。
在开发生命周期的某个阶段,你需要从不可扩展的过程过渡到可扩展的过程。尽管这种手动、快速且草率的企业实践在小市场中可能更经济,甚至在某些情况下是必要的,但随着时间的推移和你的改进与增长,它们是不可持续的。
自动化——无论是在代码、部署还是监控中——是稳定、安全和性能良好的应用程序的基础。它可以在项目开始时推迟,以便你能够快速学习和适应,但必须随着时间的推移而应用,以最大限度地减少技术债务并避免通过有缺陷和不可靠的应用程序给用户带来痛苦。
如何处理技术债务
技术债务,或你在采取编码捷径时积累的额外工作,就像财务债务一样。有时一点是必要的,但太多可能会要了你的命。
正如之前提到的,如果你是一个完美主义者,你的产品可能会超出预算或无限期地延迟。然而,快速且草率的编程最终需要修复。虽然完美主义可能在短期内让你感到不知所措,但技术债务可能在长期内让你感到不堪重负。
对技术债务的看法有多种方式。你可以将其视为长期与短期、谨慎与鲁莽、有意与无意之间的区别。实际上,技术债务,就像财务债务一样,有时为了实现某个目标可能是必要的。然而,正如这两种类型的债务可能都有用一样,它们也可能失控。
管理技术债务的最佳方式是在产品生命周期的过程中,有意和迭代地从待办事项中消除它。你注意到这里关于迭代实践的模式了吗?很简单;良好的敏捷实践可以帮助防止技术债务将你淹没。
处理技术债务的几个小贴士:
-
制定技术债务管理计划:一个执行得当的计划是解决技术债务的第一步。它应该作为你冲刺周期的一部分持续进行,并根据债务对客户影响的大小进行优先排序——从影响最大的到影响最小的。
-
记录你的债务:待办事项可以帮助你跟踪何时、何地以及为什么做出了某些决策。你的日志应包括修复捷径所需时间的估计,同时记住,你借出的每一笔贷款都会随着时间的推移而累积利息。
-
从财务角度量化债务:编码时间转化为可计费的小时数。因此,技术债务直接转化为财务成本应该是明确的。从财务的角度看待技术债务将帮助你的团队和公司理解开发决策的影响,以便相应地设置优先级。
-
执行你的计划:如果没有责任人,技术债务管理计划将不会有所帮助。建立文档化的指南、责任人员、还款计划,并确保你的债务管理计划定期执行。
一个稳固的技术债务管理计划可以帮助你预防不必要的债务。在债务不可避免的情况下,一个战略性地执行的计划将帮助你控制债务,使其不会控制你。
摘要
做那些无法扩展的事情是关于通过缩短构建-衡量-学习周期来优先考虑学习和市场速度。
大多数情况下,做那些无法扩展的事情是完成任务的唯一途径。在实验阶段,涉及的工作可能会让你进入不熟悉的领域,表面上看起来似乎与行业最佳实践相悖。然而,这些早期的努力往往决定了成功与失败的区别。
当你狂热地致力于成长时,你可以收集关于你市场的数据,快速调整方向,并交付一个能够帮助你学习、迭代和随着时间的推移不断改进的 MVP。
在下一章中,我们将探讨如何通过 Play Store 和 App Store 的技巧来进一步了解我们的 MVP。
第十三章:Play 商店和 App 商店黑客技巧
为了不断地从你的 MVP 中学习,你必须不断地进行测试,收集数据,并发展你的应用程序。然而,验证学习的障碍之一来自应用商店本身。
正如我们将看到的,这两个平台有不同的限制和要求,这影响了应用程序发布的各个方面和阶段。例如,商店列表要求、应用审核延迟、分析和测试版部署选项,在两个平台之间都不同。
然而,有方法可以绕过这些挑战。在本章中,我们将探讨以下内容:
-
拆分测试是什么以及为什么它是每个应用开发者的关键工具
-
如何在商店列表和应用程序中运行拆分测试
-
如何克服在执行现实世界拆分测试时不可避免遇到的限制和障碍
-
重要的拆分测试技术,以及如何在应用商店和谷歌玩中运行拆分测试的示例
在介绍这些主题之前,让我们简要地阐述一下什么是实验:

什么是实验?
就像在科学中一样,商业实验提出一个假设,然后进行测试或测试以验证或否定该想法。在精益方法中,MVPs 是测试关于价值和增长的基本假设的实验——也就是说,你的想法是否解决了问题,以及你的产品是否可以可持续增长。
尽管 MVP 本身就是一个实验,但在这种背景下,你还可以进行许多其他实验。在本章中,我们将探讨在应用商店内测试的障碍,允许你在应用程序和应用商店内进行拆分测试的解决方案,最后,我们将探讨如何通过一些实际示例应用这些技能。
A/B 测试作为一种实验技术
拆分测试可以被视为实验,就像任何其他实验一样,它从假设开始。与建立在整个 MVP 之上的价值假设等大规模假设相比,这些测试的规模要小得多。然而,基本原理是相同的。
对于那些不知道的人来说,拆分测试为用户组提供网页或应用的替代版本,例如,以确定哪个版本转化率最高。在双向拆分测试中,称为 A/B 测试,你可能会测试两个不同的着陆页标题,以测试它们对转化率的影响。
你还可以测试以下内容:
-
写作,例如标题或行动号召
-
设计元素,例如颜色或按钮形状
-
应用商店列表元素,例如截图或描述
为什么进行拆分测试?
如下所述,这将更详细地介绍,但拆分测试有许多好处。以下是一些最大的好处:
-
拆分测试可以帮助你更好地了解你的用户
-
转化率可以改善,即这是一种基础优化方法
-
您可以改善用户体验和可用性
-
重要的指标,如用户留存率和应用内时间,可以更深入地理解和改进
在本章中,我们将介绍两种类型的应用程序实验:商店列表测试和应用程序测试。
商店列表测试
应用商店排名,例如搜索引擎排名,对多少人发现并尝试您的应用程序有巨大的影响。如果您能提高您的商店列表排名及其转化率,那么您将能够获得以下显著的好处:
-
改善有机发现和更多用户
-
增加下载率
-
降低用户获取成本
提高您的应用商店排名,或应用商店优化(ASO),被称为新的 SEO,这是对其重要性的证明。与互联网上的其他搜索引擎保持一致,应用商店搜索算法基于各种可预测的因素进行排名,例如关键词相关性和用户评论。
应用程序市场从未发布过可以指导开发者如何提高其应用商店排名的最佳实践。然而,广泛使用的非官方 ASO 改进技术主要集中在几个重要领域:
-
下载率和卸载率
-
用户评论的质量
-
标题和描述中关键词的相关性
-
列表副本、图标、截图等的有用性
列表测试是分割测试,旨在帮助您直接或间接地改善所有这些领域。每次您分割测试元素时,您都会衡量您试图影响的成果。例如,A/B 测试可以比较两个版本的描述,然后使用安装率来衡量该测试的结果。比较评论请求机制的测试可以检查对正面评论的影响。
应用程序测试
对应用程序本身进行分割测试是您实验工具箱中的另一个关键工具。虽然应用商店列表测试将帮助您提高转化率,但应用程序测试帮助您了解您的用户、改进您的产品并提高参与率。
在测试应用程序时,您将执行旨在改善应用程序体验、可用性和参与度的分割测试。应用程序测试可以在任何数量的与应用程序相关的变量上执行,包括以下内容:
-
屏幕设计
-
用户流程
-
图片
-
按钮
可以帮助您判断测试努力的适当指标包括参与度指标,如应用内时间和留存率或特定目标的转化率。例如,旨在提高广告转化率的更改应衡量广告转化率。与应用商店列表测试一样,您应关注衡量任何给定测试试图影响的成果的指标。
您为什么关心?
应用程序测试不仅仅是锦上添花,因为这些实验可以成就或毁掉一个应用程序。测试已成为精益开发者的操作模式的一个关键方面,因此了解测试为何如此有价值是值得的。
竞争非常激烈
应用需要一种在饱和、竞争激烈的市场中脱颖而出的方式。根据 Statista 的数据,Google Play 从 2013 年 7 月的 100 万应用增长到 2017 年 3 月的 280 万。在 2013 年 6 月至 2017 年 1 月之间,App Store 的应用数量从 90 万增长到 220 万。
这片应用海洋提出了两个问题——不仅开发者需要在应用海洋中保持可见性,他们还需要吸引并保持用户的注意力。
尽管人们每月花费数十小时使用应用,但他们很快就会放弃那些令他们感到无聊的应用。根据 2016 年 Localytics 的数据,这一数据在主要科技博客上被广泛报道,近四分之一的用户在仅使用一次后就会放弃应用。应用放弃率背后的原因有很多,从用户的繁忙日程到可用性问题。
虽然并非所有这些原因都可以影响,但开发者使用实验来保持竞争力的一个原因是。
实验是有效的
就像参与度指标一样,转化率受到多种因素的影响,包括:
-
流量来源:确切数字因信息获取渠道而异,但研究表明,40-50%或更多的用户通过在 App Store 中搜索找到应用。谷歌报告显示,四分之一的用户通过搜索找到他们的应用。
-
应用列表本身:正如所述,App Store 列表的每个元素都可能影响转化率,从图标到描述到截图。
-
行业:并非所有行业都有相同的平均转化率。根据 splitmetrics 发布的数据,音乐应用在 App Store 中的转化率最高,而游戏应用则最低。
-
应用定价:免费应用受不同的平均值约束,而付费应用则不同。一般来说,免费应用的下载率更高,但它们的放弃率也更高。
影响这些因素的最佳方式是通过进行实验。拆分测试可以将 App Store 的转化率提高 20%或更多。
转化率的下降反过来又降低了用户获取成本,而在应用内进行拆分测试有助于提高参与度指标,这通常会对您的收入模式产生直接影响。
虽然应用市场本身存在一些困难,但这些困难并非不可克服。接下来,我们将探讨一些这些障碍以及如何克服它们,以便您能充分利用您的测试。
为什么在 Google Play 或 App Store 上运行实验很困难
一旦您的 MVP(最小可行产品)在 App Stores 上列出,进行拆分测试就会变得更加困难。您的应用将受到每个 App Store 规则的约束。然后,当您想要更新时,您必须等待 App Store 的批准。此外,某些限制阻碍了您进行测试或收集准确数据的能力。
使用商店列表进行测试的障碍
两个主要平台的行为不同,每个平台都有自己的列表要求。一般来说,Google Play 测试更容易,因为重新列出所需时间更短,要求不那么严格,并且它为商店列表提供了简单的拆分测试选项。然而,App Store 的显著受众以及该受众的购买力就足以让开发者针对 iOS 进行编码。
这里有一些主要平台差异,这些差异使得测试变得更加困难。
不同的应用列表要求
当您列出您的应用时,您必须学会在两个不同的生态系统中运营。您不仅需要为每个应用编写不同的代码,还需要学习如何在每个市场中最大化可见性的技巧。
以下是截至本书撰写时的三个示例以及每个 App Store 的不同要求:
-
应用标题: 在 Google Play 上,标题限制为 50 个字符,而在 App Store 上限制为 30 个字符。
-
应用描述: 苹果公司没有简短描述,但它有一个“副标题”。副标题限制为 30 个字符。如果两个平台上的描述差异感觉过于复杂,我们会将此项目替换为促销文本。苹果公司的促销文本限制为 170 个字符。谷歌称此字段为“发布说明”,且限制为 500 个字符。
-
应用类别: App Store 允许您选择主要和次要类别,但在特殊情况下,您可以添加更多类别,从而增加潜在的可视性。另一方面,Google Play 只允许应用和游戏共享一个类别。谷歌允许在类别中添加应用类型。
这些只是您在运行 App Store 优化测试时必须考虑的一些差异。两家商店之间的其他差异包括以下内容:
-
允许的截图数量
-
允许的促销视频长度
-
是否允许社交媒体操作
-
是否允许促销图形
没有标准的方式来衡量结果
每个商店都提供单独的指标来衡量您实验的结果:
-
苹果公司: 您可以通过 iTunes Connect 查看销售和趋势,它为您提供了下载和销售的数据和报告。App Analytics 是一个分析包,它跟踪许多标准指标,例如参与度、货币化和营销。
-
谷歌: 您可以从谷歌开发者控制台跟踪用户获取,并可以选择缩小关注特定的获取渠道、位置和时间段。与苹果的分析包类似,移动 Google Analytics 或 Firebase Analytics 允许您跟踪货币化、参与度和营销活动。
由于这些精确数字不同,即使这些实验同时进行,你也无法并行测量结果。值得一提的是,苹果和谷歌都在不断改进他们的工具,使测试更容易,因此某些特定功能可能在出版时已经改变。
A/B 测试的基础设施有限
一旦你的应用被列出,在商店本身进行拆分测试时,你的选择就有限了。苹果公司通常以其 App Store 的严格标准而闻名,从截图到关键词再到错误。因此,他们不提供拆分测试支持并不令人惊讶。
Google Play 允许你拆分测试商店列表。通过这个程序,你可以创建两种类型的实验:
-
全球化:全球测试允许你测试图形、截图、促销视频和图标。这些测试只影响你的应用默认语言,所以使用其他语言的用户仍然会看到他们默认的本地化版本。
-
本地化:当你进行本地化测试时,你可以测试所有前面的变量,以及多达五种语言的描述。
这些实验是在 Google 开发者控制台中创建和运行的,在那里你可以选择目标信息、属性、变体等等。
为什么并行实验很难进行
到现在为止,为什么并行进行实验不是一件容易的事情可能已经变得很清楚:
-
不同的商店列表要求意味着每个列表都必须不同
-
不同的编码要求使得并行应用创建困难
-
每个应用商店的 A/B 测试能力不同意味着你不能同时运行相同的列表测试
-
不同的指标意味着你将测量略微不同的结果
-
每个商店的周转时间不同意味着你的更新将有不同的时间表
另一个挑战是,由于测试条件随时间波动,在串联测试时很难保持严格的控制和可靠的结果。例如,用户行为和市场情绪在两个时间段之间可能变化足够大,以至于会改变两个本应相同的测试结果。尽管有效的测试显然有其固有的障碍,但我们可以看到,有方法可以克服这些挑战。
解决挑战的技巧
尽管以下方法都不是理想的,但它们将允许你从客户那里学习,验证你的假设,并持续改进你的 MVP。接下来的每个部分都将涵盖一些绕过迄今为止讨论的平台限制的基本技术。
商店列表技巧
如前所述,Google Play 允许你拆分测试列表的核心元素,而苹果则不允许。然而,如果你想要扩展测试选项并执行更复杂的多变量测试,你需要探索其他选项。
用户最初是如何找到应用的?
了解用户来自何方以及他们如何发现你的应用,这对测试和你的业务都非常有用。你不仅可以了解各种流量来源在数量和质量上的比较,还可以在 App Store 之外进行测试,这可以为你提供更多关于客户的信息。
在检查实验本身之前,简要检查主要发现门户和流量来源是值得的:
-
App Store 搜索:如前所述,谷歌研究指出,至少 40%的用户通过在 App Store 内搜索来发现新应用,这使得它成为你最重要的流量来源之一。因此,App Store 索引和优化应该是首要任务。
-
传统搜索:同样的研究还报告说,27%的用户通过搜索引擎发现了应用,这使得搜索成为另一个关键流量来源。
-
应用包:当搜索引擎确定某人在搜索应用时,应用包会出现在标准 Google 搜索结果之上、之内或之下。出现在应用包中的应用是由搜索引擎选择的,而不是 App Store 排名。然而,由于搜索算法依赖于许多相同的因素,结果高度相关。
-
深度链接:深度链接或打开应用的 URI 可以从各种地方触发,包括搜索广告和其他数字广告。如果应用尚未安装,用户将被引导安装应用,然后完成由原始链接发起的操作。
如前所述,谷歌将允许你进行店内列表测试。由于某些流量来源,如店内搜索和应用包,会直接将用户引导到这些列表,因此 Android 开发者应该充分利用这一选项。
使用微测试来收集数据
尽管你无法测试苹果 App Store 中的列表,而且你可以在 Google Play 中运行的测试也有局限性,但你仍然可以使用外部着陆页来测试截图、标题、图标和描述等基本内容。
要执行这种技术,有些人称之为微测试,你只需对模拟 App Store 列表的着陆页进行实验。创建一个尽可能接近 App Store 外观的测试,当用户点击安装按钮时,将他们引导到实际的商店列表。
测试期结束后,使用转化率最高的着陆页来重新创建你的 App Store 列表。
为了跟踪和分析结果,你应该利用 A/B 测试平台。有些是免费的,有些是付费的,但考虑到它们提供的益处,付费平台可能非常值得投资。以下是一些最受欢迎的平台:
-
Google Analytics:这是 Google Analytics 中包含的一个基本测试解决方案,使其易于使用,并融入任何现有的 GA 工作流程。
-
Optimizely: 这是最受欢迎的拆分测试选项之一,提供的功能远超直通着陆页测试
-
Unbounce: 这是一款非常受欢迎的着陆页平台,拥有易于使用的着陆页构建器
-
Kissmetrics: 这是世界上功能最强大的拆分测试和分析平台;Kissmetrics 非常适合深入客户研究
进行一些研究将有助于你确定哪个价格点符合你的预算,哪些功能满足你的需求。对于计划进行广泛跟踪的团队,例如营销测试和应用程序测试,查看更深入的平台是值得的。例如,Kissmetrics 提供应用程序和网站的统计分析,因此你可以从单一位置管理、查看和审查更多的分析数据。
运行应用程序测试
就像你可以使用拆分测试来测试网页元素的多个版本一样,你也可以运行收集应用程序元素(包括设计元素和工作流程更改)数据的测试。这种方法是构建-度量-学习周期的实际应用,你从数据中学习,并构建新的迭代。
当与预生产版本一起工作时,你可以并行运行测试。同时测试应用程序的两个版本可以加倍你收集的信息量。
以下是在两个平台上运行并行测试的方法:
-
Google Alpha Deployments: 在将应用程序发布到生产之前,你可以对具有谷歌账户或 G Suite 账户的用户进行公开和封闭的 alpha 和 beta 测试。由于你只能同时运行一个公开和一个封闭的测试,谷歌建议在公开 beta 测试的同时进行封闭 alpha 测试。
-
Apple TestFlight: 它与 Google Alpha Deployments 类似操作,允许你创建公开或封闭的测试。你可以将多个构建版本分配给最多 2,000 名公开测试者,这为你提供了足够的空间来接收关于你应用程序不同版本的反馈。
-
第三方应用程序: 有许多服务可以帮助简化测试部署和分发。Install, DeployGate 和 Fabric(2017 年初被谷歌收购)是使原型设计阶段更容易、更高效的平台。
通过正确的部署方法和创意的拆分测试方法,你可以绕过两个应用程序市场提出的一些障碍。接下来,我们将通过查看应用商店和 Google Play 中的示例实验来应用我们迄今为止所检查的一些技能和工具。
摘要
实验性和科学的方法是精益方法的基石。
实验和拆分测试是每位开发者工具箱中的基本工具,但在市场上运行测试可能会很棘手且混乱。本章中介绍的技术可以帮助你绕过现实世界的限制和障碍,提高学习效率,并加速成长。提供的示例可以给你提供在 App Store 或 Google Play 中运行自己实验的思路。
在有了合适的工具、合适的技术以及一种创新的测试方法后,即使你在应用市场中发布了产品,你仍然可以继续学习和实验。
现在是时候看看我们如何可以使用拆分测试来找出在我们的应用中什么效果最好,因为我们致力于创建客户喜爱的应用。
第十四章:对你的应用进行 A/B 测试
所有成功的应用开发者都会从他们从用户那里获得的反馈中学习。他们会进行调查,并确定是否需要改进、删除或添加功能,以更好地支持用户的操作流程。在本章中,我们将探讨如果我们不能亲自询问他们,我们可以使用哪些工具来获取用户的反馈。构建一个解决客户问题的应用需要多次测试和优化。分割测试(或 A/B 测试)是一个持续的过程,可以帮助你找到将导致最高转换率的操作流程。使用分割测试,例如,你可以找到最适合你应用的注册流程。在第十章“有 API 可以做到!”,我们看到了一些关于如何改进用户入门流程的好建议。现在你也可以进行一些实验,并衡量什么最适合你的应用。它还可以就其他主题提供反馈,例如用户留存、参与度或应用内购买。我们将看到为什么获取统计数据很重要,以及我们可以从中学习到什么。
作为实用主义者,我们将探讨我们可以用于此目的的工具。我们将快速了解 Firebase、远程配置和分析如何为我们工作。分割测试是一种你可以在任何时候使用的方法,即使你的应用已经在商店中。最后,我们将看到我们可以为分割测试我们的应用或 Play 商店列表做些什么。
具体来说,在本章中,我们将涵盖以下主题:
-
看看为什么统计数据很重要
-
学习什么是可操作的指标
-
了解分割测试是什么以及它如何帮助我们改进我们的应用
-
调查我们可以使用的测试工具
-
了解如何使用 Firebase 远程配置和 Firebase 分析
统计数据为什么重要?
没有统计学,你将几乎没有反馈。你将无法看到你本可以从用户及其行为中获得的所有洞察。不要在没有实现获取分析数据所需功能的情况下发布你的应用:

通常,统计学可以告诉我们以下信息:
-
用户获取性能
-
用户行为和转化
-
用户人口统计信息
-
按细分市场或队列的用户行为
-
财务洞察
因此,正确的统计数据可以告诉我们关于应用使用情况的一些信息。它回答了诸如:应用做得怎么样,"做得好"究竟意味着什么?这是关于下载量吗?活跃用户数?每日新增用户数?不仅要有统计数据,还要有可操作的指标。收集大量数据很容易。确定哪些数字真正重要则更困难。不要被数字淹没。确定你的业务目标,这样你就知道要衡量什么。拥有具体的数字很重要,这样你就可以通过做正确的事情立即采取行动。
关于可操作指标
在第十章“有 API 可以做到!”,我们已经预览了转换和指标的概念。收集关于你移动应用使用的统计数据很重要,因为这通常是获取用户反馈的唯一方式。如果我们想了解关于这种反馈的某些信息,重要的是要认识到你获得的统计数据的质量比数量更重要。虽然收集尽可能多的数据可能很有吸引力,但实际上情况正好相反。关注真正重要的事情。可操作指标是我们想要的。Ash Maurya 在他的书籍《Running Lean and Scaling Lean》中讨论了这一点。他声称用户增长比你的总用户群更重要,他在这一点上确实有道理。
获取和参与度是重要的指标类别。获取数量告诉你有关你的应用下载量、新用户数量和活跃用户数量的信息。参与度是关于你的用户多久打开一次你的应用(并且继续使用它),留存率和流失率(放弃你的应用的用户)。了解有多少下载了你的应用的用户会坚持使用你的应用是很感兴趣的?他们在一周或一个月后还会使用你的应用吗?其他重要的指标包括客户终身价值和关键漏斗行为,但让我们先从获取和参与度开始。
获取
在用户下载你的应用之前,他们需要意识到它的存在。你需要在社交媒体上、在你的网站上,或者以其他方式推广它。否则,人们怎么知道它的存在,你的应用真的很棒呢?每天获取新用户很重要,否则你的活跃用户数量会下降。不管你的应用有多酷,它对某些人来说可能不起作用。这不必成为一个问题。只要获取的数量高于流失率,你的应用就会增长。
参与
用户参与度指标都是关于你应用的粘性。人们花越来越多的时间在移动设备上,这对你的应用来说当然是个好事。但人们的注意力跨度也只有金鱼那么大,所以移动应用的平均流失率(不再使用你的应用的用户)通常更高。
你可能想知道用户在会话期间或特定时间段内花了多少时间在应用上。会话是任何类型的交互,直到用户的注意力被其他事情打断,比如 incoming phone call。为了提高你应用的留存率,你应该经常提醒用户关于应用,或者你应该提供让他们定期访问应用的好理由。电子邮件和推送通知可以用来再次吸引用户的注意力,从而保持应用意识。
保留率是指在一定时间后(比如 2 个月或更长时间)仍然活跃的用户数量。流失率是指在同一时间段后不再使用您应用的用户。为了增长,保留率需要高于流失率。要做到这一点,您的应用需要不断通过提供相关内容、激励措施和新或改进的功能来创造价值。简而言之,您需要不断地给用户留下返回应用的理由。
每日或每周活跃用户是最有价值的,因为它们将是后来最容易转化的。参与度越高,应用对用户的价值就越大。他们可以通过推荐成为您应用的使者,或者通过点击广告或在应用内购买(收入)来为应用变现。
转化率和海盗度量法
如我们在第十章“有 API 就能做到!”中所见,海盗度量法是关于您应用用户的转化。在这里,转化步骤从获取到收入展示如下:

对于我们的应用来说,特别是这些步骤:意识提升、访问和搜索商店、下载应用、打开应用、激活(注册),最后是保留。为了简化,目前这里不显示广告收入或应用内购买(收入):

在每个步骤中,您都会失去一些用户。这是一个完全正常的现象,但您需要确保您不会在途中失去太多用户。比如说,有 1000 人通过在网站或 Twitter 上阅读有关您的应用的信息来了解其存在。其中 800 个点击链接查看应用在商店中的情况。
他们看到应用图标、一些截图、描述以及其他用户的反馈。大约 300 个用户想,“嗯,这不是我想要的。”因此,只有 500 个用户会下载应用。其中 100 个在下载过程中忘记了它(在回家的路上,其他事情吸引了他们的注意力:电话?WhatsApp 消息?)。最终,400 个用户会打开应用。他们看到一个带有明确行动号召的引导故事。应用要求他们使用 Facebook 或 Twitter 注册。可能 200 个会这样做。其余的用户打算稍后这样做(但他们可能也会忘记)。200 个用户开始探索应用,如果他们不经常被提醒应用,并且应用没有给他们足够的理由返回,他们将在几天内忘记它。一周后只有 50 个用户仍在使用应用,一个月后只有 25 个仍然活跃。
这是一个负面场景吗?根本不是。这对许多应用来说是一个非常现实的情况。如果你想区分一个失败的应用和一个成功的应用,那么你需要考虑这一点。此外,我们还没有讨论货币化部分。在第十七章货币化和定价策略中,我们将专门探讨这一部分。
幸运的是,我们有工具来提高转化率。了解确切的转化百分比非常重要。如果,在所有下载了应用的用户中,只有一小部分注册,那么你就知道你需要做些工作了。在你的用户注册过程中可能有一些阻止人们注册的因素。在那种特定情况下,你需要找出是否注册门槛太高,以及你可以做些什么来改变这一点。另一个例子是应用内购买的转化率。如果你注意到他们访问了可以购买此类产品的应用部分,但从未转化为客户(实际上购买了一些东西),这也是一个有趣的模式。那里可能需要改变一些东西。也许产品的附加价值不明确,或者定价水平可能太高。
了解你的受众
但是你需要改变什么?如果你只有少数几个测试用户,你可以直接给他们发短信询问。还有一些工具可以包括某种调查,但大多数人认为它们很烦人。如果你提供一些具体的激励措施(例如免费购买),可能会有所帮助。这些可以是数字激励措施,比如众所周知的徽章(游戏化)或现实生活中的激励措施。如果你对后者感兴趣,可以查看www.kiip.me/developers上的 Kiip,那里有一些例子。他们有一个很棒的 SDK,你可以添加到你的应用中。例如,它允许你向完成其个人资料的用户提供一杯免费的咖啡。
如果你想知道你的应用用户是谁,你需要了解他们的一些额外信息,比如他们的位置以及他们对你应用的期望。了解他们的年龄、性别、他们使用的设备类型,以及他们在何时何地使用你的应用,也是非常有趣的。深入了解你的受众对于能够创建一个完全满足用户期望的应用至关重要。最终,这也将导致你应用更好的货币化。事实上,这就是为什么 Facebook 广告的转化率比 Google 广告要好的原因。Facebook 对其受众和每个个体的了解要多得多,因此广告可以更具体地定位,从而使广告的点击通过率(CTR)更高。我们将在第十四章增长用户粘性和提高留存率中了解更多关于用户粘性和留存率的内容。首先,让我们看看我们需要做什么来更多地了解我们应用的受众:

分割测试可以帮助我们改进我们的应用
A/B 测试,也称为分割测试,在最基本的形式上,归结为向不同类型的人随机展示两种不同的实现。一小部分人,比如 5%,会看到新功能 A,这可能像是一个新功能或新视图,而另外 5%会看到功能 B。其余的用户目前还看不到新功能。将证明最受欢迎的功能(根据转化率或其他目标)将完全实施并向应用的全部受众提供。
如果你想要找出什么最适合注册用户,你可以设置一个像这样的分割测试:

因此,测试受众中的 50%会看到变体 A,显示一个写着“注册”的按钮,这将导致 26%的访问用户注册。其余的 74%可能会想“嗯,这不是为我准备的”,或者决定稍后注册:他们可能很快就会忘记这件事。那么测试受众中的另外 50%会发生什么呢?他们会看到变体 B。它显示一个“开始!”按钮。如果我们看看这个变体,我们会看到 63%的受众决定注册:

理论上,这证明了变体 B 应该是应该实施的一个,因为它导致了最高的转化率。但现实情况有所不同。如果我们对我们的受众知之甚少,上述结论可能是正确的,但如果我们对受众了解得更多,我们可能不会仅仅根据表面价值接受结果,并可能考虑其他问题。看到变体 A 的受众与看到变体 B 的受众是否可以比较?可能存在特定的客户群体,他们可能更偏好某个功能而不是另一个。
如果我们只是进行随机测试,我们将永远无法得知结果。如前所述,只有当我们知道我们的受众和他们想要什么时,我们才能提高我们应用货币化的成功率。第一步是了解我们的受众(通过收集用户数据),第二步是在进行 A/B 测试时考虑这些知识。如果我们能够选择我们的目标受众并看到对他们最有效的方法会怎样?有一些工具可以帮助我们进行更复杂的分割测试。我们将在下一节中探讨它们。
保持变体之间的差异微妙
在我们的例子中,A 和 B 之间的差异非常微妙,这是有原因的。如果两个变体之间的差异太大,你将不知道你在测试什么:

上述内容是一个很好的例子,说明了不应该做什么。如果你的用户引导拆分测试显示变体 A 导致 61% 的转换率,而变体 B 导致 66% 的转换率,那么结果证明了什么?不仅转换率之间的差异并不令人信服,而且也不清楚是什么导致了略微更好的转换。是背景颜色起了作用吗?还是文本(行动号召)?或者可能是注册按钮的颜色?我们永远不知道。这个测试有太多的参数。
考虑测试的目标是什么。你的假设是什么,你将如何通过拆分测试来证明它?一次测试一个元素,这样你知道是什么变化导致了转换率的提高。运行多个拆分测试,因为通常一个测试不会提供足够的信息来完全理解什么最有效。记住,重要的是你的用户会做什么,而不是你认为他们会做什么。你最好尽早找出这一点。
你还应该考虑可能影响你的测试的事件。在假期或特定事件期间进行测试可能会有不同的结果。此外,不同星期的不同日子转换率可能不同。出于这些原因,始终确保你至少运行了为期几周的测试。
拆分测试和获取可操作指标的工具
从技术角度来看,进行网页拆分测试实验相对容易。另一方面,移动优化实验则更难完成。Play Store 或 App Store 是造成这种情况的最重要原因。浏览器总是连接的,但应用程序存在于一个不一定总是连接的设备上。
尽管移动应用程序拆分测试还没有像网站 A/B 测试那样成熟,但有许多工具可以帮助你测试用户。一旦你决定了你想测量的指标,你可以选择最方便的工具:

在众多工具中,你可以使用以下一些:
-
Firebase:它提供了许多选项,例如远程配置和分析。如果你结合这两个功能,Firebase 是拆分测试你应用程序的好选择。远程配置允许即时更新应用程序的外观。也许你已经在使用 Firebase 进行数据存储、实时数据共享或用于用户引导。
-
Taplytics:这是一个拆分测试工具,你可以用它来做出不需要在 Play Store 或 App Store 中更新的更改。即使不更改代码,你也可以进行多次快速测试迭代,这使得它成为移动拆分测试目的中最合适的解决方案之一。
-
Fabric: Fabric SDK 附带了许多实用的工具,关于用户入门。这是一个使安装和维护 SDK 变得容易的平台,例如,包括 Optimizely。除了 Fabric 账户外,您还需要设置 Optimizely 账户。Optimizely 可以帮助轻松地将拆分测试集成到应用程序中。它是一个知名的测试工具,适用于 iOS 和 Android。正如 Firebase 和 Taplytics 的情况一样,运行 A/B 测试不需要 App Store 或 Play Store 更新。
其他有趣的工具包括 SplitForce、Flurry Analytics、Amazing A/B testing、Arise、Switchboard、Leanplum 和 Apptimize。它们都支持 iOS 和 Android。大多数都支持客户细分。此功能允许您为特定类型的受众运行测试。根据您的目标,您需要选择最适合您需求的工具。例如,我们将具体查看 Firebase 远程配置和 Firebase 分析,以了解这是如何工作的。
使用 Firebase 进行拆分测试
您可以使用 Firebase 对您的 Android 或 iOS 应用程序进行拆分测试。有关如何为 Firebase 和远程配置设置教程的具体信息,请参阅firebase.google.com/docs/remote-config/。
对于这个例子,我们将查看 Android 实现。从github.com/mikerworks/packt-lean-firebase-split-testing下载示例项目。您在那里找到的 Android Kotlin 应用程序旨在演示您如何为应用程序的用户入门流程运行拆分测试。它使用 Firebase 远程配置和 Firebase 分析。
项目已使用 Android Studio 工具菜单中的 Firebase 选项设置。Firebase 助手可以帮助您为Analytics和Remote Config配置项目:

对于示例项目,它已经设置好了。在app文件夹内的build.gradle文件中,您将找到以下 Firebase 依赖项:
dependencies {
...
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:25.4.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'com.google.firebase:firebase-config:11.6.0'
}
apply plugin: 'com.google.gms.google-services'
项目中的google-services.json文件应替换为您自己的文件。一旦您配置了应用程序,您就可以从 Firebase 下载它。(在项目概览中选择设置。)您可以使用 Firebase 助手来完成此操作,或者您可以直接访问 Firebase 的开发者控制台console.firebase.google.com:

如果您还没有 Firebase 账户,您需要先创建一个。在控制台中,您可以添加和配置您的项目:

在项目概览中,您可以进入增长部分并选择远程配置选项。如果您在右侧选择 A/B 测试,您可以确定您想要拆分测试的变体:

假设我们的示例项目是一个已经发布的应用程序。现在,让我们假设我们想要测试一个新的用户引导体验。通过点击“创建实验”按钮,我们可以测试哪种方式效果最佳。我们想要找出哪种变体能够带来最高的注册转化率。
有两个变体:变体 A 和变体 B。对照组将看到原始的应用程序;他们不会看到任何变化:

您可以为实验定义一个或多个参数。每个变体都有自己对这些参数的值。我们可以测试的事情,例如:注册按钮的背景颜色(蓝色或绿色)、注册文本或背景图片(草莓或橙子)。正如您所看到的,您可以设置多个参数,但最佳实践是限制它们为两个或三个。
您可以为您的拆分测试定义一个用户细分。在这个例子中,我们将仅针对 5%的用户基础以保持简单。还有更复杂的细分选项也可用。例如,您可以针对特定国家或 18 至 36 岁的用户。如果您收集了关于用户的大量信息,您可以创建非常具体的细分。

应用程序可以读取您在这里定义的任何值。默认值可以在项目中的remote_config_defaults.xml文件(在res/xml文件夹中)找到。我们需要它们以确保在无法检索远程配置值(例如没有互联网连接)的情况下,应用程序可以正常工作。
在 MainActivity 应用程序中,您可以查看如何操作。在这里初始化了 Firebase 远程配置和分析。为调试变体启用了开发者模式。这将确保没有数据缓存,这允许我们首先测试变体。
我们还告诉firebaseRemoteConfig实例,它应该使用remote_config_defaults.xml文件中的变量作为后备选项:
val firebaseRemoteConfig = FirebaseRemoteConfig.getInstance()
var firebaseAnalytics: FirebaseAnalytics? = null
override fun onCreate(savedInstanceState: Bundle?) {
...
val configSettings = FirebaseRemoteConfigSettings.Builder()
.setDeveloperModeEnabled(BuildConfig.DEBUG)
.build()
firebaseAnalytics = FirebaseAnalytics.getInstance(this)
firebaseRemoteConfig.setConfigSettings(configSettings)
firebaseRemoteConfig.setDefaults(R.xml.remote_config_defaults)
val token = FirebaseInstanceId.getInstance().getToken()
Log.i(javaClass.simpleName, "token = ${token}")
val cacheExpiration = 1L
Log.i(javaClass.simpleName,"fetch")
firebaseRemoteConfig.fetch(cacheExpiration).addOnCompleteListener(this)
}
最后,我们记录设备令牌。稍后,我们需要这个令牌来测试测试设备上的特定变体。在这个代码片段的末尾,我们获取数据并监听结果。
如果所有参数和值都已检索,我们告诉firebaseRemoteConfig对象应用这些值。对applyRemoteConfiguration方法的调用确保 UI 将更新:
override fun onComplete(task: Task<Void>) {
if (task.*isSuccessful*){
Log.i(*javaClass*.*simpleName*, "complete success")
firebaseRemoteConfig.activateFetched()
}
else{
Log.i(*javaClass*.*simpleName*, "complete no success")
}
applyRemoteConfiguration()
}
在这里,我们设置了适用于当前变体的所有颜色和文本:
private fun applyRemoteConfiguration(){
val variant = firebaseRemoteConfig.getString("experiment_variant")
Log.i(javaClass.simpleName, "experiment = ${variant}")
firebaseAnalytics?.setUserProperty("Experiment", variant)
val onboardingColor = firebaseRemoteConfig.getString("onboarding_color")
Log.i(javaClass.simpleName, "onboarding color= ${onboardingColor}")
if (onboardingColor=="blue") {
findViewById(R.id.sign_up_button).setBackgroundColor(Color.parseColor("#0000ff"))
}
else{
findViewById(R.id.sign_up_button).setBackgroundColor(Color.parseColor("#00ff00"))
}
val onboardingText = firebaseRemoteConfig.getString("onboarding_text")
Log.i(javaClass.simpleName, "onboarding text= ${onboardingText}")
(findViewById(R.id.sign_up_text) as TextView).text = onboardingText
val onboardingBackground = firebaseRemoteConfig.getString("onboarding_background")
Log.i(javaClass.simpleName, "onboarding bg= ${onboardingBackground}")
if (onboardingBackground=="strawberry") {
(findViewById(R.id.image).setBackgroundResource(R.drawable.strawberry))
}
else{
(findViewById(R.id.image).setBackgroundResource(R.drawable.oranges))
}
}
这将导致在用户引导流程中显示变体 A 或变体 B。由于我们想要测量这两个变体之间的转化率差异,我们为fireBaseAnalytics对象设置一个用户属性,并且如果用户点击注册按钮,我们将事件记录如下:
private fun onSignup(){
logEvent("signUp")
Log.i(javaClass.simpleName, "sign up button clicked")
}
private fun logEvent(eventName: String){
firebaseAnalytics?.logEvent(eventName, Bundle())
}
采用这种方法,我们可以测量注册按钮的点击次数,并且可以在 Firebase 分析仪表板控制台中查看每个变体的结果。
首先,我们需要测试两个变体。如果你第一次运行应用且一切顺利,你将在日志输出中找到类似以下内容(过滤条件:token):
11-10 11:22:09.856 27547-27547/com.packt.splittestdemo I/MainActivity: token = cG-QulinNq0:APA91bH2lOQThh57qNseb3PDoBRDy-mPXvE_vezn1nNFBiDrWd0a…
复制 token 值,然后回到 Firebase 控制台。在那里你可以设置一个测试设备。将 token 粘贴到“实例 ID token”字段,并选择变体 A 或变体 B:

如果你选择变体 A 并现在运行应用,它将看起来像左侧显示的截图。它有一个充满草莓的背景,并且有一个蓝色的“注册”按钮。然而,如果你在 Firebase 控制台中选择变体 B 并再次运行应用,背景会突然显示橙子,并且有一个绿色的“注册”按钮。变体 B 显示在右侧:

这个带有蓝色“行动号召”按钮和草莓背景的引导屏幕会是赢家吗?或者我们会看到使用绿色按钮和橙子背景的引导视图获得最高的转化率(注册)吗?只有时间才能告诉我们结果会怎样。
如果我们运行这个拆分测试几周,我们将知道哪两个结果提供了最高的转化率。获胜的变体将是我们将为所有用户推出的变体。
这只是一个简短的例子。还有许多其他可供探索的选项,这些选项在本章中并未涵盖,因为本章只是对拆分测试(split testing)的介绍。然而,你现在应该已经对可能性有了概念。
要了解更多关于 Firebase 拆分测试(split testing)的具体信息,请查看:
developer.android.com/distribute/best-practices/develop/in-app-a-b-testing.html 或 techcrunch.com/2017/10/31/google-firebase-gets-predictions-crashlytics-integration-and-a-new-ab-testing-service/ 或 firebase.google.com/docs/remote-config/use-config-ios。
摘要
在本章中,我们了解了为什么统计数据很重要以及哪些统计数据很重要。我们学习了拆分测试以及应该做什么和不应该做什么。我们对可用于拆分测试的工具以及我们为设置自己应用的拆分测试需要做什么有了些了解。我们还了解了一些关于指标的知识以及获取和保留的重要性。
在下一章中,我们将学习更多关于保留(retention)的知识以及如何进一步改进它。我们将提升我们的应用的用户粘性(traction),并探讨一些实现这一目标的实际方法。让我们开始吧。
第十五章:增长用户粘性和提高留存率
在本章中,你将了解用户粘性,这是某人想要使用你的产品并且,在大多数情况下,愿意为此付费的证据,最终导致盈利性业务。现在我们已经获得了一些可操作的指标,正如我们在上一章中学到的,我们将看到如何增长用户粘性。如果没有足够的留存率(返回应用的用户)或者过高的流失率(放弃应用的用户),关键时刻将很快过去,我们将失去用户粘性。让我们调查如何提高留存率。此外,我们还将看到我们可以做些什么来保持低流失率。
具体来说,在本章中,我们将涵盖以下主题:
-
了解用户粘性的定义
-
发现我们如何增长用户粘性以及何时“增长黑客”策略开始发挥作用
-
了解我们如何提高留存率
-
学习如何与你的应用用户保持联系
-
了解实现通知机制以提醒用户需要什么
用户粘性
那么,什么是用户粘性?基本上,它是指表明业务规模化和可重复性的趋势。用户粘性是足够大的市场需求和更具体地说关于采用和参与度的证据。如果你做得好,用户粘性就是对你产品或服务假设的证实。用户粘性关乎实际进展,在应用的每个阶段都很重要。它关乎你在刚开始时注册的前几个早期采用者,最终也关乎进行(应用内)购买的用戶。你的应用在将人们转化为用户以及用户转化为客户方面做得如何?
即使是新兴的应用克隆(或模仿者)也是用户粘性的迹象。它证明了随着用户基础的扩大,你应用解决的问题确实很重要,并且这个问题值得解决。
如盈利(收入)、注册和活跃用户数量(留存率)、参与度、流量以及甚至合作伙伴关系等都是你可以用来衡量用户粘性的因素。请注意,孤立的信息并不能真正证明用户粘性。例如,你可以运行一些活动来增加你的用户基础,但如果客户获取成本(CAC)高于每用户平均收入(ARPU),那么仅仅看收入来决定用户粘性就没有意义了。你需要确保客户终身价值(LTV)将高于新用户获取的成本。你需要降低成本或者提高 LTV。为了做到后者,例如,你可以考虑提供订阅服务。除了一次性应用内购买外,它还将带来持续的收入。
在你的应用的可扩展性上下功夫,对业务有所帮助,这有助于获得和提升吸引力。然而,为了了解这对你的应用将如何工作,你通常需要做一些(目前)不可扩展的事情,正如我们在第十一章中看到的,用户入门和注册。你首先必须了解什么有效,什么无效。前面提到的“礼宾服务”肯定不可扩展,但它可以帮助你获得许多有用的见解。你可以做的事情还包括冷 canvassing 和一般的 networking。由于这些策略是商业导向的人喜欢做的事情,但大多数开发者会讨厌,我们将探讨我们还能做些什么来增长吸引力。
你可以做一些事情来提高你应用的知名度,并找到你的早期用户。如果人们看到你的应用列在以下提到的任何网站上,并决定下载你的应用,那么你将看到吸引力的第一个迹象。
除了在 Facebook、LinkedIn 和 Twitter 上发布关于你应用的帖子外,以下是一些你可以开始的地方:
-
Product hunt:
www.producthunt.com -
Betali.st:
Betali.st -
Start-up list:
startupli.st -
Reddit startups:
www.reddit.com/r/startups
这些地方就是你的(潜在)早期用户所在之处,他们对了解新应用和服务充满好奇。由于他们喜欢对新产品提供反馈,这些人正是你所寻找的目标。
当然,你应该有一个关于你应用的博客(如果没有,现在就开始一个),在发布第一个(测试)版本之前。在投入任何开发应用的努力之前,首先建立受众是很重要的。确保你的博客读者有一个清晰的行动号召。尽可能让注册你的电子邮件通讯简报变得方便,并定期向订阅者发送这些通讯简报。一旦你的应用发布,继续你的博客写作,并进行一些实验(对你的电子邮件进行 A/B 测试),看看什么能带来最佳的转化(从阅读到打开你的应用,着陆页和下载,以及使用你的应用)。
免费还是付费?
有些人说,唯一相关的牵引力是价格牵引力。如果你的应用程序完全免费,那么你对应用程序的需求可能是无限的。然而,如果没有收入,这本身并不是很重要。从一开始就为你的应用程序收费是衡量牵引力的最终方式。你越早产生收入,就越快验证应用程序的概念。如果你认为这种方法不会奏效,那么再考虑一下,并查看网络上的各种众筹网站。当然,你需要有一个关于你的应用程序的精彩故事。你需要告诉他们你的应用程序有什么如此出色,但你已经有了一个很好的故事,对吧?
没有任何收入的业务是无法生存的。事实上,免费的应用程序是不存在的。钱必须从某个地方来。提供应用内购买是货币化你的应用程序的一种方式,但只有一小部分用户(2%或更少)会真正这样做。其他 98%将继续使用你的应用程序,而从未为此付费。免费增值模式之所以有效,是因为托管成本低,并且你可以不费太多力气地扩展你的应用程序。然而,你仍然需要关注整个 100%的用户群体。你必须回应他们的评论,并且你必须继续在社交媒体上发布。这可能非常耗时。来自你 2%用户的收入应该覆盖这些成本。
决定应用程序付费版本应包含哪些功能可能很困难。你需要清楚地了解你的应用程序的每一部分对你的用户来说有多有价值。此外,你也可以选择仅提供高级应用程序。如果你从一开始就直接为你的应用程序收费,这将提高门槛,但你的销售数字将是牵引力的真实证明。在第十七章“货币化和定价策略”中,我们将更详细地探讨定价策略。
当然,还有其他方式可以货币化你的应用程序。你可以考虑展示广告。此外,你也可以考虑一个利用网络和移动渠道的解决方案。不要再把你的应用程序视为产品,而是将其视为你服务的渠道。因此,你可以免费提供你的应用程序,但在网络上,你可以要求用户为订阅你的服务付费。这种方法对于面向商业的解决方案尤其有效。收入会更高,可能是因为应用程序本身的价值感知可能较低。这只是一种感知问题,但在市场营销中,感知很重要。这也可能与这样一个事实有关,即,人们往往不太愿意为在较小设备上运行的应用程序付费。这有点荒谬,但无论如何,这是真的。也许我们可以专注于开发仅适用于大电视的应用程序?当然,我只是在开玩笑。
从开发者的角度来看,这完全没有意义。开发者知道这需要相同的工作量,而且设备的大小在这里并不重要。无论如何,感知的价值和使用的渠道确实很重要。它们将对牵引力的大小及其确定方式产生影响。
没有明确的目标,你无法衡量牵引力或任何其他类型的成功。你的目标越抽象,你感知结果就越困难。为了使结果可衡量(可操作的指标),你需要定义明确的目标。明确的目标伴随着数字,比如我们希望在特定时间内(1 个月?)有多少新注册(1,000?),或者我们需要发送多少封电子邮件来将用户的转化率提高 25%?
提高留存
移动应用的留存和参与度是衡量你的应用成功与否的指标。高留存和参与度比率往往是你的应用成功的原因。留存说明了在特定时间内你的用户多久重启一次你的应用。参与度是一个活动指标。它说明了他们在使用你的应用时在做什么,以及他们在特定会话中多久做一次以及做多少次。在这两个指标中,留存可能是最重要的。如果你理解了是什么让你的应用对用户有粘性,那么你将能够提高留存率。
你应该始终思考:对他们来说,这有什么好处?你应该给你的用户提供一些好的理由,让他们定期回到应用中。社交应用有最好的留存率。人们回来是因为他们想保持对常规信息流的更新。这被称为错失恐惧症(FoMo)。这是 Facebook 完全掌握的技能。不幸的是,与 Facebook 不同,大多数应用并不是每天都会被使用。
活跃流失是一个或多或少与留存相反的现象。活跃流失总是存在的,但你尽可能将其保持在最低。今天,数据显示,如果一个应用一周内没有被启动,那么有 60%的人可能会忘记它。你需要保持你的应用的相关性。你必须定期提供新鲜的内容和新功能。不用说,你必须通知用户这些更新。例如,你可以发送推送通知。这是一个非常常见的吸引用户注意并让他们回到你的应用的方法!
一个低门槛的入门体验,提供新鲜和相关的内容和功能,个性化(社交注册策略可能在这里有所帮助),激励措施,以及发送推送通知,这些都是可以极大地促进更好的留存和参与价值的特性。
激励与游戏化密切相关。两者都奖励用户在您的应用中达到特定成就。虽然游戏化更多地涉及数字激励,例如徽章(例如在 Foursquare 和 Stack Overflow 上可用),但激励则是关于现实世界、非数字奖励,例如在最近的咖啡馆里免费提供一杯咖啡。如果您想了解更多关于激励的概念,您可以查看kiip.me。
有许多方法可以提高用户留存率,从而获得更好的推广效果。目前,我们将仅探讨如何通过启用推送通知来保持与用户的联系。您需要给人们一个理由让他们继续回来,并且您通常需要提醒人们您的应用的存在。如果您不希望您的应用被遗忘、废弃,最终被删除,您应该友好地提醒他们。
有许多方法可以提高用户留存率,从而获得更好的推广效果。目前,我们将仅探讨如何通过启用推送通知来保持与用户的联系。您需要给人们一个理由让他们继续回来,并且您通常需要提醒人们您的应用的存在。如果您不希望您的应用被遗忘、废弃,最终被删除,您应该友好地提醒他们。
请不要向用户发送垃圾信息。不要发送太多消息,并通过细分,只发送相关信息。如果用户长时间不活跃,并且您有一些有趣的内容想要与他们分享,您可以发送一个友好的提醒。如果您想了解哪种提醒效果最好,这是一个绝佳的礼宾服务候选。找出哪种消息效果最好,并看看哪些客户细分市场将显示出最佳的转化率。一旦您了解了这些,然后您可以稍后进行自动化。如果您已经拥有庞大的用户群,您还可以进行 A/B 测试,看看哪种方法效果最好。有许多服务可以帮助您进行客户细分和运行拆分测试。
此外,考虑一下提醒的频率。一周的禁食期是否是发送提醒的好时机?或者两周更好?讲述一个故事并构建一个体验很重要。明确告诉他们从中可以得到什么,应该伴随着一个明确的行动号召,例如“查看我们的新功能 X”或“看看你的朋友 Y 发布了什么”。
推送通知可以帮助提高用户留存率。数据显示,平均而言,选择接收推送通知的用户留存率提高了 25%。这似乎很有道理。顺便说一下,iOS 应用的推送通知总是需要用户主动选择接收。只有当用户明确表示他们希望接收推送通知时,他们才会收到这些通知。Android 系统有一个退出机制。用户安装应用后,除非他们选择退出,否则会收到推送通知。
通知
您可以使用以下三种方式通过通知消息和徽章与您的应用程序用户进行沟通:
-
本地通知
-
推送通知
-
应用内通知
本地通知
本地通知就像服务一样,在用户的设备上运行。您的应用程序不需要处于活动状态即可接收与您的应用程序相关的本地通知。它们也不需要互联网访问或服务器。相反,它们被安排在特定的日期和时间,就像闹钟一样。它们是由您的应用程序初始化的。
您可以安排一个本地通知来提醒用户关于应用程序,但一旦用户启动您的应用程序,就取消该通知。这是一个提醒用户您的应用程序存在的绝佳工具:

您可以使用本地通知来提高您应用程序的留存率。您可以在应用程序关闭或失去焦点时安排通知,但在应用程序再次变得活跃时取消它们。如果您将日期设置为现在的一周或两周后,并且用户忘记了您的应用程序,他们将收到一个友好的提醒。然而,如果他们在这一特定时间段内使用应用程序,那么通知将被取消,用户将不会受到任何提醒通知的打扰。
推送通知
推送通知涉及服务器(以及随之而来的互联网连接)来启动操作。此类通知是促销活动的绝佳工具,可以通知用户关于应用程序中新内容和新功能的情况。此外,根据应用程序的性质来决定哪些通知是相关的。对于约会应用程序,当有新的应用程序时收到通知会很不错。在这种情况下,在应用程序图标上显示表示新匹配和消息数量的徽章也会非常有帮助。对于新闻应用程序,每当有新的重要消息到来时收到通知会很棒。您可以根据兴趣或地理位置等来创建用户细分,例如,仅通知您的用户有关当地新闻事件。
应用内通知
最后,您可以使用应用内通知来指示有新事件发生。您可以在相关的地方显示徽章,比如标签或菜单项。您还可以在应用程序使用时使用应用程序通知来刺激特定的行为。例如,考虑一个提醒通知,如“给这个应用评 5 星!”一些方法可能相当巧妙,比如只有在用户使用应用程序五次(参与度)且应用程序没有崩溃时才显示的对话框。
只有在这种情况下,对话框才会请求给予 5 星评价!为对您应用程序充满热情的用户提供便利并降低评价应用的门槛是很重要的。对于可能对您的应用程序不太满意的用户,您可以保持当前的门槛。这将有助于您获得更好的 App/Play Store 评价。
有一些组件正是为此而设计的。其中之一是 iOS 的 iRate。只需几行代码,你就可以在你的应用中实现一个“给我们评分”或“给我们 5 星”的弹出窗口。你可以配置它何时以及什么条件下会显示:

对于每种类型的通知,重要的是不要让用户感到烦恼。不要过于频繁地向用户提出过多要求。只有当有相关内容需要提及时,才应该通知用户。没有特定原因的推送通知,只是为了让用户回到应用,可能一次转化效果不错。然而,如果这种情况发生得太频繁,就会变得令人烦恼,用户可能会选择卸载应用。
推送通知服务
要将你的推送通知分发到安卓和 iOS 设备,你需要有一个推送通知服务器,它会将消息发送到正确的设备。虽然你可以自己构建这个服务器,但使用为这个目的提供的现成解决方案会更方便。现有解决方案的好处,除了节省大量时间外,还包括它们的可扩展性、多平台支持和分段选项,这使得确定哪些消息发送给哪些用户变得更加容易。
这样的解决方案的例子包括 Urban Airship、Azure 推送通知中心、Amazon Push、托管 Parse 服务器解决方案(例如在 back4app.com 上找到的),以及 Firebase 推送通知服务。它们都有不同的定价计划,并支持不同的操作系统。
例如,这里有一个 Azure 推送通知中心的示意图。它可以向 iOS 和安卓(如果你仍然真的想这么做,也可以是 Windows Phone)发送推送通知:

如果你想要向除安卓或 iOS 以外的操作系统发送推送通知,或者如果你想在西方世界之外发送推送通知,那么仔细检查不同的选项是很好的。比如说,你想要将你的应用推向中国市场。在这种情况下,了解亚马逊支持百度推送通知是很有帮助的,因为并非所有服务都支持这一点。亚马逊有一个中心节点,无论设备运行在亚马逊、iOS、百度、安卓还是 Windows 上,都可以发送通知。
安卓的推送通知是通过谷歌云消息(GCM)协议发送的。苹果使用苹果推送通知服务(APNS)为 iOS 服务。配置 iOS 的推送通知稍微复杂一些,因为它需要处理证书的问题。然而,如果你是使用证书和分发配置文件的 iOS 开发者,那么你不会对此感到害怕。
Back4App 是一个提供包括推送通知(安卓和 iOS)支持在内的 Parse 服务器托管服务的组织。你可以轻松地针对所有用户或特定用户(细分市场):

如您所见,大多数服务都提供对 Android 和 iOS 以及其他几个平台的支持。可扩展性、支持的平台、定价计划和集成容易程度都是在选择推送通知服务提供商时需要考虑的事项:
| 亚马逊 | 苹果(APNS) | 百度 | 谷歌(GCM) | 微软 | |
|---|---|---|---|---|---|
| 亚马逊 | 支持 | 支持 | 支持 | 支持 | 支持 |
| 微软 Azure | 支持 | 支持 | 不确定 | 支持 | 支持 |
| Firebase | 支持 | 支持 | ? | ||
| Urban Airship | 支持 | 支持 | 支持 | 支持 | |
| 解析服务器 | 支持 | 支持 |
实现
两个平台的方法大致相同。如果用户启动应用,设备和应用将注册以接收推送通知。这将生成一个令牌(或 Android 的可选注册 ID),您可以用它来向该特定设备发送通知,以及针对该特定应用。Android 和 iOS 之间的主要区别在于 iOS 使用默认接收通知的策略,而 Android 使用默认不接收通知的策略。
iPhone 用户将看到一个弹出问题,询问他是否希望允许应用接收推送通知(默认接收)。这是我们注册时操作系统为我们做的事情,如下所示:
对于 Android,我们只需注册设备和应用,我们就会收到推送通知,用户直到收到第一条通知之前不会注意到。在 Android 上,您可以使用设置应用关闭接收推送通知(默认不接收)。
因此,这里有一个 Android Java 示例,展示如何在App类中进行此类注册。GCM_PROJECT_NUMBER指的是 Google 开发者控制台中的项目编号,但我们会稍后讨论:
private GoogleCloudMessaging gcm;
...
String regid = gcm.register(FlavorConstants.PushConfiguration.GoogleConfiguration.
GCM_PROJECT_NUMBER);
Log.i(getClass().toString(), "Obtained RegId from GCM : " + regid);
此外,这里是如何在 iOS(Swift 3.x,iOS 10)的AppDelegate类中完成的。对于 iOS,您还需要在开发者门户中配置一些内容,我们稍后会看到:
func registerForPushNotifications(){
print ("PN - register for PN")
let center = UNUserNotificationCenter.current()
center.delegate = self
center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
if error == nil {
print ("PN - No error")
}
else{
print ("PN - Error ")
}
if (!granted){
print ("PN - Not granted")
}
else{
print ("PN - granted")
}
guard granted else { return }
self.getNotificationSettings()
}
}
func getNotificationSettings() {
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
print("Notification settings: \(settings)")
guard settings.authorizationStatus == .authorized else { return }
UIApplication.shared.registerForRemoteNotifications()
}
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
{
let installation = PFInstallation.current()
installation?.setDeviceTokenFrom(deviceToken)
installation?.saveInBackground()
PFPush.subscribeToChannel(inBackground: "global") { (result, error) in
print("PN - subscribed to global")
}
}
设置
要为您的 Android 应用设置 GCM,您必须访问您的 Google 开发者控制台,您可以在console.developers.google.com/找到它。
在那里,您可以配置您的应用并获取服务器密钥。
要设置苹果推送通知(APNS),您需要访问苹果开发者门户,并在标识符/应用 ID 部分找到您的应用(假设您已经为您的应用创建了一个应用 ID):

点击编辑按钮,滚动到推送通知部分。根据需要点击下载证书按钮或创建证书按钮。
遵循指示。使用keychain应用创建一个 CSR 文件(证书签名请求)。从服务器机器上执行此操作更佳。
将请求文件(CSR)上传到苹果开发者门户:

下载证书(将包含私钥和公钥部分),然后双击安装。在keychain应用中,找到 APNS 证书,并从上下文菜单中选择导出。
为文件提供密码并保存。现在您有一个扩展名为 P12 的文件,您可以稍后将其上传到您的通知服务,例如 Azure 推送通知中心。
以下示例显示了通知中心的部分,您可以在沙盒模式下(仅限开发)上传此证书文件。这种方法对于其他服务也大致相同。它们都需要您上传此文件以实现魔法般的效果:

以下是可以在此配置的所有推送服务的示例:

在决定使用哪种通知服务之后,找到一些好的参考资料(关于该主题的书籍或教程),特别是 iOS 推送通知配置可能有点棘手。
处理传入的通知
如果收到通知,它将在消息传递部分显示,这是操作系统为我们提供的。此外,我们可以定义如何处理它。在 Android 中,我们可以实现一个PushHandler类来消费通知,并使用NotificationCompat构建器为它定义特定的操作。以下是一个 Android Java 示例:
public class PushHandler extends NotificationsHandler {
Context ctx;
@Override
public void onReceive(Context context, Bundle bundle) {
ctx = context;
String nhMessage = bundle.getString("message");
Parcelable parselableObject = bundle.getParcelable("parcel");
consumeNotification(nhMessage,parselableObject);
}
private void consumeNotification(String msg, Parcelable parselableObject) {
Log.i(this.getClass().toString(), "Consume notification");
Log.i(this.getClass().toString(), "Notification msg = "+msg);
if (parselableObject != null) {
Log.i(this.getClass().toString(), "Consume has parcel");
}
displayNotificationMessage(ctx, "Message", msg,msg);
}
public static void displayNotificationMessage(Context context, String title, String contentText,
String tickerText){
displayNotificationMessage(context,title,contentText,tickerText,null);
}
public static void displayNotificationMessage(Context context, String title, String contentText, String tickerText, Parcelable parcelableObject){
...
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Bundle extras = new Bundle();
extras.putParcelable("parcel", parcelableObject);
Notification notification = builder.setContentTitle(title)
.setContentText(contentText)
.setTicker(tickerText)
.setSmallIcon(R.mipmap.appicon)
.setContentIntent(pendingIntent)
.setPriority(Notification.PRIORITY_HIGH)
.setSound(soundUri)
.setVibrate(new long[]{0, 500})
.setExtras(extras)
.build();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notification);
}
对于 iOS,您可以做同样的事情。这是AppDelegate类中的事件处理,它是一个 Swift 4/3.x、iOS 11 的示例(对于 iOS 的早期版本,它以不同的方式工作),并且使用 Parse Server 来传递推送通知。
在这里,我们也可以确定当推送通知到达时应该发生什么(在一定程度上)。完成处理程序确定是否显示通知或徽章,以及是否播放声音:
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to register: \(error)")
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
print ("PN - willPresent")
let userInfo = notification.request.content.userInfo as NSDictionary
let body = notification.request.content.body
for (key, value) in userInfo {
print("userInfo: \(key) -> value = \(value)")
}
if ... {
print ("PN - completion handler silent")
completionHandler([])
}
else{
print ("PN - completion handler alert badge sound")
completionHandler([.alert,.badge, .sound])
}
}
...
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
print ("PN - Did receive")
...
completionHandler()
}
发送通知
要发送通知,您可以使用服务的 Web 界面,或者如果您想以编程方式发送消息,可以使用服务提供的功能。
以下是一个针对 Parse Server(Back4App)的云代码示例。它向所有监听特定频道的设备发送消息。您可以向所有用户发送推送通知,或者您可以设置用于客户分段的频道。您可以设置图标上的徽章数量(仅限 iOS),标题和消息:
Parse.Push.send({ channels: "channel or channels", data: { title: "title", sound: 'default', badge: 2, alert: "message", extraParam: "something" } },
{ success: function () { response.success("ok"); },
error: function (error) { response.success("nok: " + error); },
useMasterKey: true
}); // push send
无论您使用哪种服务,基本的有效负载总是相同的。此外,请注意,您可以使用它发送自定义参数:
data: { title: "title", sound: 'default', badge: 2, alert: "message", extraParam: "something" }
到目前为止,对于推送通知的高级视角,您现在应该有了实现它的概念。要继续这个主题,请查看谷歌和苹果提供的关于此方面的教程。
摘要
在本章中,你学习了牵引力的定义以及为什么它很重要。我们了解到参与度和留存率也是重要元素。我们还看到了不同类型的通知以及每种类型的好处。你可以提醒你的用户关于应用中的特定事件。这将提高留存率。通知还可以帮助你提高应用的认识度,例如,通过请求用户对你的应用进行评分。最后,我们看到了现有的通知服务用于发送推送通知,以及实际为你的 Android 和 iOS 应用实现推送通知机制需要做什么。
在下一章中,我们将探讨可扩展性。一开始,你可能会做一些无法扩展的事情,但一旦你建立了足够的牵引力,就是时候考虑可扩展性策略了。这对于使用后端的应用尤其重要。
第十六章:扩展策略
在本章中,你将了解什么决定了你的应用程序的可扩展性,以及你需要做什么才能让它良好地扩展。你还将了解何时扩展变得重要,以及哪些因素会影响你的扩展策略。当你刚开始时,规模根本不重要。事实上,我们之前确实告诉过你做一些不可扩展的事情。那么,是什么让我们改变了主意?实际上并没有什么。证明你的假设仍然很重要,而且,直到那件事情完成,让你的应用程序扩展将是浪费时间。然而,重要的是你应该考虑你应用程序的可扩展性,以及如果你的应用程序变得非常流行并开始快速增长,你的策略将是什么。现在,如果你的应用程序后端只能处理一百个同时连接是完全正常的。但你的应用程序后端也需要能够处理数千个甚至更多的同时请求。无法快速扩展会导致停机时间,这会导致用户感到沮丧,进而导致高流失率。人们会离开,而不是稳步增长,你短暂的名声也将消失。这将是更大的浪费。因此,我们需要一个计划,而本章将帮助你定义这个计划。
具体来说,在本章中,我们将涵盖以下主题:
-
了解为什么让你的应用程序能够扩展很重要
-
确定何时以及如何扩展你的应用程序,以及分析如何帮助
-
了解你需要做什么才能拥有一个可扩展的后端
让它具有可扩展性,但不要立即扩展
在现实世界中,可扩展性的定义可能因文化而异,但对你来说,重要的是你的应用程序在大多数情况下都是响应的和功能性的。
如果你预见在某个特定时刻有任何问题,那么是时候扩展了;但关键要素是能够快速扩展。确保在势头的时候你能做正确的事情!
因此,你已经开发了一个应用程序,并且它已经在像 Product Hunt 或 Betalist 这样的网站上展示过。你已经有了一些热情的早期用户。作为一个处于早期阶段的初创公司,你不应该过于关心你的应用程序扩展得有多好,但你应该有一个想法,如果你的受众突然比预期的大,你该如何让它扩展。
可扩展性不仅仅是关于你应用程序的后端解决方案。它还涉及到到什么程度可以自动化你的应用程序服务,以及为任何数量的应用程序用户提供服务将有多容易。只有当你的应用程序服务几乎可以 100%自动化时,你才有一个真正可扩展的解决方案。任何需要你个人或其他人的注意的事情都会阻止你的应用程序完全可扩展。你的应用程序需要的支持越多,它的可扩展性就越低。
你应用的扩展性也可能受到应用性质和目标受众的限制。例如,一个游戏应用:Flappy Bird,从定义上讲,可以非常容易地扩展。它没有后端,游戏通过 App Store 或 Play Store 分发。对于像排行榜这样的功能,你可以使用 Google 或 Apple 的服务。你可以相信这些服务是可扩展的。一个社交应用将更难扩展,因为它需要你有一个(复杂的)后端解决方案。尽管它通过商店分发,但你的用户需要能够下载和上传包含文本、图像和视频的数据流。你的服务器应该能够处理这种负载。
所有这些都需要存储在某处,并且需要快速交付。此外,尽管可以大量自动化,但当用户生成的内容出现时,监管变得更加重要。监管需要人工干预,这将对应用的扩展性产生影响。其他应用,如 Uber,会带来其他(非技术性)的挑战。它们需要处理各种法规,这也需要人工交互。任何需要人工交互的事情都可能威胁到你的解决方案的扩展性。一旦你的假设得到证实,你的应用开始增长,那么尽可能自动化你应用中的许多组件就变得非常重要。
如果你需要更多员工,当然可以雇佣更多的人。然而,自动化更好。在本章中,我们将特别关注应用的技術扩展性。当应用的分发由 Play Store 或 App Store 负责时,就不需要制定策略。商店可以像你希望的那样频繁地分发这些应用,而不必担心扩展。嗯,这就是为什么他们要收取 30%(针对付费应用)的原因,对吧?讨论你应用的扩展性是相关的,如果你的应用将使用某种后端。例如,你可能会使用后端来分享故事、图片、视频或其他内容。
假设你已经为你的应用创建了一个初步的 MVP(最小可行产品)。MVP 本身还不是一款应用。它仅仅是为了验证而存在的。想象一下,通过网站或电子邮件,你获得了需要某种处理方式的用户反馈。正如我们在前面的章节中看到的,拥有一个门童服务是完全可行的。你可能需要部分或完全手动处理这个过程。确实,这并不容易扩展,但你为什么要在不知道它是否可行的情况下就自动化这个过程呢?
如果你的 MVP(最小可行产品)按预期工作,它将导致一些满意的客户。你已经验证了你的假设,并可以开始自动化流程。你实际上构建了一个应用并为它创建了后端。你将所有数据(文本、图像和视频)存储在单个服务器上。如果一切顺利,将有更多的满意客户。然后,你的应用被 App Store 收录,或者一个非常有影响力的早期采用者写了一篇关于你的应用的博客,它就火爆了!突然之间,很多人开始使用你的应用,你的服务器(们)冒出了烟。你需要迅速想出解决方案,在事情开始变慢或停止工作之前。你需要防止人们感到失望,否则你的势头就会消失。你可以添加几个额外的服务器并考虑一些智能负载均衡解决方案,但另一方面,如果你从一开始就利用云服务,例如在 Amazon 或 Azure 上运行,你可以省去很多麻烦。
如果你认为它不会那么快,那么考虑这一点:如果你不期望你的应用会突然火爆,那么为什么一开始要构建它呢?即使是宠物项目也可能突然变得非常受欢迎!

可扩展的后端
根据你的具体情况,移动后端解决方案可能需要处理以下情况:
-
数据库和数据库层负载均衡
-
网络服务器和负载均衡
-
减少数据传输量(低带宽支持)
-
媒体存储(图像、视频和音频)
-
内容分发(视频流)
云存储空间现在相当实惠,并且,在大多数解决方案中,你只需点击几个按钮就可以扩展(并且花费一点更多的钱)。所以,为什么不从一开始就使用云服务呢?如果你有技能和时间,你可以构建自己的解决方案,并在(可扩展的)云上使用基础设施即服务(IaaS)解决方案,如 AWS 或 Azure 运行。如果你没有技能或时间,你也可以选择使用移动后端即服务(MBaaS)。后者将不太灵活,成本也会更高,但无论你选择哪一个,这两种服务都将很容易实现可扩展性。
基于云的存储和处理
在云中运行你的应用后端解决方案并存储你的数据,例如在:
-
亚马逊(例如亚马逊云服务(Amazon Web Services)和亚马逊存储服务(Amazon Storage Service,S3))
-
谷歌(App Engine、云存储、云数据存储和云 SQL)
-
Azure(虚拟服务器、数据库、存储和内容分发)
-
Heroku
大多数这些解决方案至少提供以下组件:
-
虚拟服务器
-
数据库
-
媒体存储(图像和视频)
-
内容分发(视频)
影响选择哪种服务的事项包括价格、特定需求、数据库支持、数据库类型(NoSQL 与 SQL)、以及对你或你的团队来说最方便的编程语言。此外,易用性和推送通知服务的定价也是重要的评估因素。你可以使用的编程语言因云解决方案而异。对于 Java 开发者来说,Google App Engine 是一个更好的选择,而.NET 的信仰者最好在 Azure 云中部署他们的解决方案。
大多数云解决方案提供多种编程环境。如果你想在 Heroku 上使用 Java,或者在 AWS 或 Azure 上使用 Node.js,那么你可以这样做。所有解决方案都支持 Java、PHP、Python 和 Ruby 编程语言。Azure 和 Amazon 都支持.NET,但 Azure 可能在这里是首选。除了 Amazon 之外,所有云解决方案都支持 Go:

如果你倾向于选择现成的后端解决方案,例如 Firebase 和 Parse 服务器,请参阅第八章,应用实验的云解决方案。MBaaS 既方便,在某种程度上也具有可扩展性,但便利性是有代价的。你从免费增值计划开始,但当你需要升级到高级计划时,它通常比开发自己的云解决方案更昂贵。另一个陷阱可能是它可能导致比其他情况下更多的供应商锁定。然而,如果你需要额外的数据库或额外的服务器用于存储或处理数据,扩展事物很容易,但这也适用于 IaaS。
从客户端视角看
让我们来看一个例子。从客户端的视角(这里是一个 Android 应用)来看,架构图可能看起来如下所示。从某个端点,API 正在被消费。这将导致接收由 Retrofit 客户端(Android 的 HTTP 客户端)处理的数据(在这个例子中)。它以JavaScript 对象表示法(JSON)格式消费数据,并最终使用 JSON 转换器(如 Gson 库,一个能够对 JSON 数据进行对象映射的库)将数据转换为对象。通常,提供服务的方会提供 SDK,这将使从端点消费数据或向其发送数据更快、更容易。例如,Parser Server SDK 将负责对象映射和与 Parse 服务器的数据同步。正如你所看到的,对于 Android 或 iOS 应用来说,后端的结构和托管位置并不重要。对于客户端来说,重要的是接口,在这个例子中,是一个在请求时提供 JSON 数据的 REST API:

事情并不总是像前面这张图片中那样理想。如果您正在开发一个从原始目的是与网站或其他非移动解决方案一起使用的端点获取数据的移动应用,您可能需要首先创建一个中间件解决方案。移动可扩展性还意味着您需要处理低带宽情况。尽可能限制单次事务中的数据量非常重要。任何不需要立即在您的应用中显示的内容都不应该包含在内。您的应用应下载缩略图而不是下载图片或视频;它应该有一个分页机制(“加载更多”选项),并且数据应针对可能具有低带宽连接的设备进行优化。
以下图片很好地展示了非优化和优化情况之间的差异,适用于移动使用:

与其将整个数据集以大而描述性的名称加载到 JSON 中,您应该只加载尽可能少的数据,并在设备上持久化以用于缓存。即使在低带宽条件下,即使您没有互联网连接,您的应用也将保持响应和可用。为了进一步优化,您的应用应首先检索缩略图。如果用户只看到它的小图片,下载高分辨率图片就没有意义了。此外,您的(中间件)解决方案应允许您的应用分块检索数据。以 Facebook 应用为例。它只加载流的一部分,当您向下滚动时(一些应用在列表底部有“加载更多”按钮),它会加载数据的另一部分。如果您是从零开始构建,并采用移动优先策略,那么这种分页机制是您立即需要的。如果当前的 API 旨在用于非移动用途,您应该考虑首先创建一个中间件解决方案来优化数据流。
一个可扩展性良好的应用会带来改进的用户体验和更好的可靠性,并且将更容易利用特定事件。想想节假日或特定事件,根据应用类型,这些都可能严重影响与您的应用相关的流量量。可扩展的应用后端应该易于扩展,让您在高峰时段/日提供所需的内容。它还应允许您在其他时候缩减规模,以避免在资源未被利用时浪费资源。
您应该知道何时需要扩展或缩减
如果你正确地使用分析工具,你将知道何时升级或缩减你的解决方案。季节性和你应用的本质可以帮助你做出一些预测。在一天中的什么时候或哪些特定事件期间,你的应用会被最频繁使用,或者用户使用应用较少的时候?例如,如果你的应用是一个闹钟,人们在假日季节会较少使用它。此外,如果你的应用与奥运会有关,你可以预期在该活动期间会有峰值使用。在假日,人们在 App Store 上通常会花费更多的钱,导致额外的下载和应用使用。最后,活动,尤其是当你以较低的价格提供你的应用时,将对应用的使用率产生重大影响。其他事件则难以预测。如果你的应用被推荐并每天增长 150%,你最好为此做好准备。
用户数量说明了同时使用应用的用户数量。这个数字对于扩展你的应用后端来说才是真正重要的。你可以有上千万的用户定期使用你的应用,或者有上千万的用户每天使用你的应用。这两种情况是截然不同的。指标可以告诉你特定时间段内用户在应用中平均花费的时间。如果你的应用是国际化的,那么按时区进行细分就很重要了。用户可能会整天使用你的应用,但(也许)在睡觉时不会使用。
无论如何,重要的是要认识到,如果你的应用目前还没有实现扩展或者只支持少量(并发)用户,只要它相对容易扩展,这是完全可以接受的。不要因为你的应用需要可扩展性而进行扩展。你需要准备好在必要时做正确的事情,但也不要在这方面投入过多的精力。完美主义已经扼杀了众多伟大的项目。不要让这种情况发生在你身上。
一个关于应用后端没有实现扩展的真实恐怖故事
即使有缓存并尽量减少数据消耗,低带宽也可能导致用户体验不佳,但有些事情是你无法控制的。另一方面,一个完全过载的后端是你可以控制到一定程度的。你的用户会评判整个应用体验。这就是为什么整个架构都很重要的原因。
这里有一个例子来说明这一点。不久前,我正在为一个知名的国际化电视节目开发 Android SecondScreen 应用。一份保密协议(NDA)阻止我告诉你具体是哪个节目,但这对于故事本身并不重要。无论如何,节目在电视上播出。在家观看节目的观众能够为出现在节目中的各种候选人投票。因此,很容易预测,在节目播出时会有大量流量。所以,当询问开发应用后端的第三方关于他们解决方案的可扩展性时,他们告诉我,他们可以保证至少有 100K 用户可以在观看节目时使用该应用。我没有要求他们是否在他们那里进行了适当的负载测试,这是我的天真。我只是假设他们是一家专业公司。不幸的是,他们并不那么专业。
当节目的新季开始,人们开始首次使用该应用时,在第一次直播期间出现了严重的问题。前 30 分钟一切顺利,大约有 40K 用户在积极投票使用应用。然后,应用在大多数情况下停止工作,投票变得非常困难。原因是后端无法处理大量流量负载。尽管不是前端(应用)而是后端的问题,但从用户的角度来看,是应用本身出了问题。糟糕的性能产生了大量负面评论。尽管下一场直播进行得很顺利,但很难从负面评论中恢复过来。损害已经造成。
后知后觉的船长来帮忙了!
这里是对这个问题的回顾。如果我们有一个证明所承诺内容的适当负载测试,那么这种情况可能可以避免。此外,如果我们能够快速扩展,我们就可以避免很多麻烦。
除非你有一个真正能工作的水晶球,否则预测未来相当困难。据我所知,没有这样的水晶球。因此,始终确保你能快速应对新情况。
你需要为那些你或多或少能预见的情况做好准备。自己去弄清楚,做一些重负载测试。在用户为你做之前,先破坏一些东西。如果你注意到任何问题,那么你需要找到瓶颈,并看看最好的解决方案是什么。
是要扩展规模还是要重构?这是一个问题。
只要知道,扩展规模并不总是正确的答案。如果你的架构不好,你可以添加另一个数据库或服务器,但这只是短期修补,你会浪费硬件资源(和金钱)。如果更好的架构不进行扩展就能带来更好的性能,那么这就是你应该做的。此外,你仍然需要确保你能快速扩展。
将应用程序保持尽可能瘦是一个常见的做法(尽管有一些例外)。让服务器去做所有重活,而不是一个小设备,否则可能会导致电池耗尽和 CPU 使用过重。从这个角度来看,可扩展性通常只适用于后端。
随着您的应用程序用户基础从 10 个用户增长到 100 人,到 1 万,10 万,或 100 万,可扩展性变得越来越重要。以下是一些最佳实践:
-
尽可能保持应用程序尽可能瘦
-
保持简单,不要立即扩展,但要使其可扩展
-
使用云存储和部署
-
考虑首先构建接口(API)
-
通过分析获得深刻的见解非常重要
-
跟随市场,仔细计划您的活动
-
尽可能降低数据流量,并不要传输将不会被利用的数据
-
在可能的情况下使用自动扩展选项
影响您解决方案可扩展性的因素包括以下内容:
-
数据库
-
存储
-
流量平均大小
-
服务器所在区域以及(大多数)用户居住的地方
-
在使用 MBaaS、自行托管解决方案和基于云的解决方案(如 App Engine、Azure 或 Amazon)之间进行选择
自动扩展
如果您选择使用 Azure 作为移动应用程序的后端,您可以使用 Azure 的移动服务。它为您提供了大部分基础设施,包括处理、存储和扩展选项。您可以选择定价层,如免费、基本之一或高级计划之一。以下是从 Microsoft 文档中提供的如何在工作在 Azure 中扩展的示例图片。图片是从经典环境拍摄的,它在“新”门户中看起来略有不同;然而,这里展示的方式更清晰:

包括之前提到的服务在内的大多数 Azure 服务都带有自动扩展功能。该解决方案将根据流量或遵循计划自动扩展或缩减。例如,考虑白天和夜晚的日程安排,周末与工作日的日程安排,或者您在运行活动时的特定时间段。这取决于您的应用程序如何使用,什么最适合您。如果您没有头绪,您可以通过关注统计数据来了解最佳方法。
在亚马逊上,您有更多或更少的自动扩展选项,AWS Mobile Services 可以帮助您更快地构建应用程序。它包括推送通知、用户分析、数据存储和同步选项。它可以在高峰时段(或日子)自动增加实例数量,并在需要较少容量时减少它们,从而通过降低成本来为您节省金钱:

Amazon Cloud Watch 启用自动扩展,这是一项用于 AWS 云资源和应用程序的监控服务。您可以在aws.amazon.com/autoscaling/上了解更多信息。
关于这个主题有一些非常好的书籍,它们可以为你提供关于这里任何 IaaS 的更深入知识。我建议你稍后查看它们。在本章中,我们只是看了看你的选项以及它们如何影响你的策略。
另一篇有趣的阅读材料是:highscalability.com/blog/2016/1/11/a-beginners-guide-to-scaling-to-11-million-users-on-amazons.html。
扩展 MBaaS(如 Firebase)基本上就是选择另一个价格计划。与 Azure、Amazon 和 App Engine 不同,它没有自动扩展选项,并且通常来说,它不太适合支持大量用户。然而,这不应该阻止你使用 Firebase,例如,因为它是一个很好的入门解决方案,更重要的是,它允许你快速验证。此外,如果你以后想从 MBaaS 迁移到 IaaS,你可以使用之前节省的时间。
摘要
在本章中,你了解到了你的应用的扩展策略以及这种策略如何特别适用于你的应用后端。良好的架构和可扩展性,而不是规模本身,是这里的关键要素。
根据定义,将数据存储和处理服务放在云中通常非常可扩展,但具体取决于你的选择,也可能非常昂贵。如果你想使用原本不是为在移动设备上消费而设计的 API 中的数据,你可能需要首先创建一个中间件解决方案。这样你可以确保即使在低带宽条件下,你的应用也能良好运行。最小化数据量和分页可以帮助提高你的应用性能。
云服务提供了便利,但代价也不小。一旦你的应用开始盈利,这不应该成为问题。有许多盈利方式,我们将在下一章中探讨。你需要创建一个付费应用,还是应用内购买能带来更多收入?让我们来看看!
第十七章:盈利和定价策略
在本章中,我们将探讨如何从我们的应用中获得收入。这显然是商业模式画布中最重要的一部分,也是最激动人心的部分。为移动应用赚钱并不容易。尽管如此,人们往往不太愿意在移动设备和应用上花钱,尽管游戏可能是一个例外。幸运的是,有许多其他可能性来构建有利可图的移动应用业务,我们将看到实现这一目标有哪些方法。
我们将探讨多种使你的应用盈利的方式。此外,我们还将检查如果你想要出售你的应用,或者如果你想要在应用内出售产品(也称为应用内购买),一个智能的定价策略会是什么样子。
总结来说,在本章中,我们将涵盖以下主题:
-
查看你可以应用到你的应用中的盈利策略
-
学习定价策略
-
在 App Store 或 Play Store 中找出如何应用定价策略到你的应用列表
-
查看如何在应用内实现购买
盈利策略
你可以使用一些策略来赚钱。你可以出售你的应用,展示广告,使用应用内订阅,或者将用户数据出售给第三方。它们都可能有些棘手,但赚钱始终是一个挑战,你需要找出对你应用来说什么最有效。不要(过于)贪婪。人们已经习惯了似乎一切都可以免费的世界。特别是,如果你计划出售用户数据,你需要有一个良好的计划。
应用盈利的一些策略如下:
-
在 App Store 或 Play Store 中销售你的应用
-
提供一个轻量级和免费的应用版本,并销售你的高级应用
-
在你的应用中展示广告
-
提供一个应用内购买产品以去除广告
-
建立一个免费的应用并提供网页上的高级功能
-
在现实世界中销售产品或服务
-
使你的(用户)数据盈利
-
通过推广你的其他产品或服务之一来利用你的应用创造价值
销售或升级你的应用
在 App Store 或 Play Store 中销售你的应用。这是使你的应用盈利的最明显方式。只有当人们非常了解你的应用的存在和良好声誉,或者当你的应用提供的附加价值非常明显时,这种方法才会有效。在 App Store 的早期,这个问题通过发布两个应用来解决:一个轻量级、免费的版本和一个收费的高级版本。今天,通过使用应用内购买(苹果的术语)来应用免费增值模式已经变得更加普遍。谷歌使用“应用内计费”这个术语来指代 Android 设备。虽然术语不同,但理念是相同的。用户可以免费下载应用,但需要付费来解锁特定的付费内容或功能。由于这种模式的成瘾性,它非常适合游戏,尽管它也可以应用于更严肃的应用。这是推广你的应用和升级高级功能的一个很好的方式。
一旦用户对你的应用产生依赖并决定继续使用,他们可以通过购买来享受其高级功能。你必须记住,只有少数用户会转化为付费客户。平均来说,从免费增值用户到高级用户的转化率最多为 1%到 5%。这不应该成为问题。一些应用的支出通常接近零(游戏),但对于需要托管后端的应用以及需要存储大量文件(视频)的应用来说,这很重要。例如,考虑一个社交应用,每个用户都可以上传或流式传输视频。
通常,云存储的成本并不昂贵,但显然很多用户将需要大量的存储空间。简而言之,如果你的 1%到 5%的用户能够覆盖 100%(高级和免费增值)用户的费用,那么你就安全了:

在现实世界中销售产品或服务
在商店销售你的应用很方便,因为整个付款过程将由苹果或谷歌为你处理。然而,这是一个相当昂贵的过程。他们将为此向你收取 30%的费用。所以,如果你以一美元的价格销售你的应用,你将得到 70 美分,对吗?实际上情况更糟。根据国家/地区,增值税(VAT)和个人所得税将使你的实际收入更低。所以,在 21%的增值税和 30%的个人所得税率下,情况可能如下所示:

除非你搬到像迪拜这样的城市,否则支付税收不是可以完全避免的事情,但你所能做的就是避免 30%的店铺费用。这可能(可能)只在你不销售任何数字产品(内容、功能、游戏关卡或库存)的情况下有效。你需要销售实物产品或现实生活中的服务。
例如,考虑一个停车应用。该应用消除了获取停车票并在时间到期前返回的麻烦,等等。作为这项服务的交换,你每次使用该应用停车时都需要支付额外的费用(荷兰这里为 25 欧分;Parkmobile 应用,2016 年)。所有付款都通过信用卡安排,苹果或谷歌与此无关。
免费提供你的应用并销售你的服务
如果你认为你的应用只是你服务利用的许多渠道之一,那么免费提供你的应用并对你提供的服务收费(例如,在你的网站上)是个好主意。这将有两个好处。首先,它将以积极的方式影响用户的定价感知(因为用户会在网站上而不是在应用上花钱)。其次,你不需要支付 30%给苹果或谷歌。当然,这意味着你需要自己处理付款,或者找到一个支付服务提供商(PSP)来为你做这件事。然而,这无疑会提高你的收入,这当然是好事。
如果你的应用是一个使用后端并且适合与 SaaS(如 CMS)一起使用的应用,你可以在网站上提供你应用的付费功能(更大的屏幕,更多的带宽)。让他们免费使用你的应用,但为访问网站收费:

广告
展示广告是应用盈利最知名的方式。广告对用户来说很烦人,但当你应用免费时,它们是获取收入所必需的。如果用户基数足够大,从应用内广告中赚钱才有意义。据说这是 Flappy Bird 唯一的创收方式,而且显然效果很好。开发者每天从中赚取了 5 万美元。这是一种经常与应用内购买相结合的商业模式。用户可以通过支付小额费用来移除广告。这可能是一次性费用,也可能是每月或每年的订阅。
好的,所以你想要在你的应用中添加一些广告。对于 iOS 和 Android,你可以从多个移动广告网络中选择,每个网络都为你使用的平台提供 SDK。网络将提供广告。你所需做的只是添加 SDK 和几行代码。
网络可能提供多种广告格式和营销类型。最常见的一些列在这里:
移动广告格式:
-
横幅广告(出现在屏幕底部或顶部)
-
插页式广告(全屏)
-
原生(与应用内容无缝集成)
营销类型:
-
每次行动/获取成本(CPA):广告商为特定的行动(联系、注册、提交)付费
-
每次点击成本(CPC):广告商为每次点击广告付费
-
每次展示成本(CPI):广告商为每次展示付费
-
每千次展示成本(CPM):广告商为每 1000 次(估计)展示付费:

一些流行的移动广告网络如下:
-
AdMob(被谷歌收购)
-
Inmobi
-
TapJoy
-
Flurry
-
Kiip
-
MoPub
-
RevPub
-
Smaato
还有许多其他格式!在应用中何时以及如何展示广告要小心。例如,使用原生 Facebook 广告的插页式广告,几乎覆盖整个屏幕,是用户最讨厌的广告形式。对于你的用户来说,最好的展示广告方式可能是屏幕底部的横幅广告。然而,这不一定是你最好的位置。也许全屏广告的转化率会更好。这取决于你应用的本质,也可能从 Android 到 iOS 有所不同。也许你可以进行 A/B 测试,找出最适合你情况的方法。
如果你想要提供一个选项来移除广告,你应该考虑在广告附近放置一个带有明确行动号召的按钮。在你的底部广告横幅上方放置一个“移除广告”按钮怎么样?这样,你通过广告创造收入,并通过人们愿意付费来移除它们创造收入,比如说,0.99 美元:

数据货币化
如果你拥有大量用户,你可以考虑将数据出售给第三方作为一种从你的应用中赚钱的方式。你必须小心这种策略,因为你的用户可能不会喜欢这个选项。始终确保你出售的数据是匿名的,并且再次尝试不要过于贪婪。不要出售用户数据以便以后发送垃圾邮件。
如果你有一个大型用户基础,其中每个用户都有一个丰富的个人资料,那么你可以从这些个人资料中创建细分市场。在第十一章“入职和注册”中,我们回顾了持续入职的过程。建立一个大型用户基础与丰富的用户个人资料相结合,即使你目前没有向第三方出售数据,也会增加你公司和你的应用的价值;它为你提供了将来出售数据的选项。你对用户了解得越多,他们就越有价值。例如,你可以创建一个数据集,包含经常在特定区域特定日期旅行的中年家庭主妇,或者你可以创建一个喜欢听重金属音乐的年轻人的数据集。所有你可以想到的细分市场都可能是有趣的,只要它们产生足够大的数据集。
如果你正在考虑并购策略,那么大量用户可能比应用盈利性更重要。此外,如果你的应用有助于推广或销售其他产品或服务,无论是数字的还是物理的,它都在提供价值。收入将来自产品和服务销售。你的应用,再次,只是支持你的销售策略的一个渠道。
定价策略
让我们假设你想要出售你的应用,或者你想要添加应用内购买。你的策略会是什么样子?你将在什么时候开始收费?从一开始就允许用户下载应用?或者你会提供一个试用期,让用户首先评估你的应用?或者它将是一个具有高级功能的应用,这些功能可以通过应用内购买来解锁?这些问题的答案将取决于你的应用性质、用户所在的地区以及设备操作系统的性质。
价格感知
价格感知是这里的一个重要元素。每个人都知道 99 美分的心理效应。我们知道 0.99 美元只比 1 美元少一美分。然而,它看起来更便宜。应用和游戏也应用了一些基于定价心理学的有趣技巧。其中之一是价格点效应;给定三个产品,包括一个提供最小价值的价格低廉的产品和一个价格荒谬高昂的产品,使得中间价格的产品看起来是最好的交易,即使它的价格高于用户最初打算花费的金额。我们稍后会看到这个的例子。
对于游戏,有趣的可售物品包括额外的生命、金币或关卡。以下是一个 8 球桌球游戏应用可用的产品示例,将价格点理论发挥到极致,您想要一叠、一堆、钱包、藏匿处、一堆还是金币保险库:

对于出售金币的游戏,这种策略效果相当好。在游戏的开始阶段,当玩家还在探索事物并且还没有上瘾的时候(记得 Candy Crush 吗?),有大量的金币或信用点可以花费。通常,玩家可以在游戏中解锁/获得新的信用点;但往往,虚拟宝库的底部被过早地看到。如果是这样的话,对于不耐烦的玩家,有虚拟金币可以救命。通常,只有 1%到 3%的玩家会真正进行购买。这仍然足以使游戏非常有利可图。
对于不是游戏的 App,考虑哪些功能应该是付费的而不是免费的重要。您需要确定在用户的认知中,哪些功能提供了额外的价值。如果不是去除广告的话,那么您的应用应该提供哪些付费功能,哪些功能仍然需要免费提供?您可以进行一些实验来找到这个问题的答案:用户愿意为哪些付费功能付费?
虽然这不是专门针对移动应用的,但有一本关于定价的有趣电子书可以阅读,书名为Don't Just Roll the Dice。为了理解产品定价,这本书帮助您了解一些(但不是太多)经济学。您可以在download.red-gate.com/ebooks/DJRTD_eBook.pdf找到示例和免费 PDF 下载。或者,您也可以在 Google 上搜索它。
您还可以查看这个 SlideShare:
www.slideshare.net/omohout/lean-pricing-startups
首先开发 Android 还是 iOS?
作为一家初创公司,您需要决定首先在哪个平台上进行开发。如果您希望尽可能多地触达受众,那么 Android 可能是您的首选,除非您知道目标受众中 iOS 用户的比例更高。然而,如果您认为通过销售应用或应用内产品进行货币化是最重要的事情,那么 iOS 可能是一个更好的首选。原因在于 iOS 用户比 Android 用户更愿意为应用付费。另一方面,对于后者来说,展示广告似乎效果更好。平均而言,点击率(CTR)在 Android 平台上更好。
应用内购买产品类型
对于 iOS,应用内购买产品有四种类型。iOS 应用内购买产品类型包括:
-
可消耗
-
不可消耗
-
非可再生订阅
-
自动续订订阅:

可消耗产品在过程中被消耗;例如,游戏中额外的生命。不可消耗产品可以一次性购买,并永久解锁功能。订阅可以解锁特定时间内的功能或功能;例如,访问特定(高级)内容。还有两种可用的订阅类型:非可再生订阅和自动续订订阅。
您可以在 iTunes Connect 中设置每种类型的产品。对于每种产品,您可以选择产品 ID、参考名称(用于内部参考)、显示名称、描述名称和价格层级。您还可以在特定价格点销售您的应用或产品。第一层级指的是 0.99 美元的价格;例如,稍后展示的样子。这些都是 Empurror 应用的产品,我们将稍后在本章中对其进行更详细的探讨。
更多信息,请参阅developer.apple.com/in-app-purchase/。
应用内计费
Android 的应用内计费产品也可以是可消耗的、不可消耗的或订阅类型。从高层次来看,没有太大差异。
您只能在通过 Google Play 发布的应用中实现应用内计费。您可以为您的应用内计费指定两种产品类型:管理型应用内产品,和订阅。Google Play 会根据每个用户对您的应用中的应用内产品和订阅进行管理和跟踪。
如果您正在使用应用内计费 API,您也可以在您的应用中消耗管理项目。您通常会实现可购买多次的项目(如游戏货币、燃料或魔法咒语)的消耗。一旦购买,管理项目在您消耗该项目之前不能再次购买。
订阅是在应用内购买中提供的一种产品类型,允许您在您的应用内部向用户销售内容、服务或功能,并采用每月或年度的定期收费。您几乎可以销售任何类型的数字内容,无论是哪种应用或游戏。
要启动购买,您的应用程序会发送一个针对特定应用内产品的计费请求。Google Play 随后处理交易的所有结账细节,包括请求和验证支付方式以及处理财务交易。
当结账过程完成后,Google Play 会将购买详情发送给您的应用程序,例如订单号、订单日期和时间以及支付的金额。在任何时候,您的应用程序都不需要处理任何财务交易;这个角色属于 Google Play。
更多信息,请参阅developer.android.com/google/play/billing/billing_overview.html。
看看应用内购买是如何实现的
由于应用内购买(iOS)通常比应用内购买(Android)的转化率更高,我们将重点查看应用内购买,特别是使用 Empurror 应用案例。
Empurror 案例
Empurror 是我之前开发的一个 iOS 小 SpriteKit 游戏。这是一款关于一只猫(Empurror)和许多小猫从屋顶跳下的非常简单的游戏。在这款游戏中,我们的英雄(玩家)需要捕捉它们所有,才能成功:

这款游戏包含三项应用内购买,都是捐赠,除了展示 Empurror 表示感谢的画面外,没有为游戏添加任何特殊功能。哦,对了,你还可以摸摸它的肚子,让它发出咕噜咕噜的声音。
无论如何,应用内购买视图如下。游戏提供三种产品:慷慨的捐赠(猫粮)、大量的捐赠(一条好看的鱼)和惊人的捐赠(一只巨大的火鸡)。我们添加了这三种类型的捐赠来进行一些定价实验。
第一个重点是中间的那个,大量的捐赠。我们试图让它看起来是最好的交易。如果你喜欢这款游戏,就给那只猫一条鱼吧!惊人的捐赠看起来,嗯,有点太惊人了,显然定价过高。只付 99 美分?你的名字不是斯克鲁奇,对吧?那么,就选择“大量捐赠”吧。
这基本上就是我们在这里试图做的事情。当然,这种定价策略最适合真实的数字激励措施,但你应该明白了:

如果我们开发了一个提供应用内购买的应用,那么我们的移除产品可以遵循相同的策略:中间一个公平的交易,左边一个较小的,右边一个昂贵的,只是为了让中间的那个看起来很棒:
-
移除广告 1 周,费用为 0.99 美元
-
移除广告 1 个月,费用为 1.99 美元
-
移除广告 1 年,费用为 19.99 美元
如果您至少使用该应用程序一年,最好的节省方式将是第三个选项。然而,当选项以我们这样做的方式呈现时,大多数人会被鼓励选择中间选项。这对大多数应用程序都适用,但没有理由不对此策略进行反馈。衡量并找出哪种产品导致最佳的转换。有一些分析工具可以帮助您做到这一点。参见第十三章,Play Store 和 App Store Hacks,以及第十四章,A/B Testing Your App,获取更多信息。
现在,查看代码以了解实现此支付模型需要做什么。以下代码是为 iOS Objective-C 编写的,但如果您想的话,将其转换为 Swift(4)并不困难。对于 Android,事情略有不同,但所有情况下主要思想都是相同的。
您将在 iTunes Connect(或 Google Developer Console)为您的应用程序定义一系列产品,当用户导航到您的内购视图时需要下载这些产品。注意这里对 StoreKit 和 SKProductsRequestDelegate 的导入:
@interface PurchaseViewController : UIViewController <SKProductsRequestDelegate, SKPaymentTransactionObserver>
...
#import "PurchaseViewController.h"
#import <StoreKit/StoreKit.h>
...
/*
4 In-App Purchases
*/
#define kProductTipGenerous @"EMP_TIP_JAR_GENEROUS"
#define kProductTipMassive @"EMP_TIP_JAR_MASSIVE"
#define kProductTipAmazing @"EMP_TIP_JAR_AMAZING"
@implementation PurchaseViewController
...
当视图出现时,我们添加一个事件来衡量转换(我们在这里使用 Flurry),并从商店加载产品,即如果我们被允许这样做的话:
@synthesize scene;
- (void)viewDidLoad {
[super viewDidLoad];
[Flurry logEvent:analyticsPurchaseViewShown];
...
[self loadProductsFromStore];
}
-(void)loadProductsFromStore{
if([SKPaymentQueue canMakePayments]){
NSLog(@"User can make payments");
SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObjects:
kProductColorfulWorld,
kProductTipGenerous,
kProductTipMassive,
ProductTipAmazing, nil]];
productsRequest.delegate = self;
[productsRequest start];
}
else {
NSLog( @"User cannot make payments,
perhaps due to parental controls");
}
}
一旦我们收到响应,我们就可以向用户展示它们,或者,正如这里的情况,启用相应的按钮,允许用户进行购买。对于每个产品,将返回一个产品标识符、一个名称和一个价格:
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
if (self.view == nil){
return;
}
SKProduct *validProduct = nil;
int count = (int)[response.products count];
products = response.products;
if(count > 0){
validProduct = [response.products objectAtIndex:0];
NSLog(@"Products Available!");
...
for (SKProduct* product in products){
[self enableProductPurchaseOption:product];
}
}
else if(!validProduct){
NSLog(@"No products available");
}
}
-(void)enableProductPurchaseOption:(SKProduct*)product{
if ([product.productIdentifier
isEqualToString:kProductTipGenerous]){
[nameGenerous setEnabled:YES];
[priceGenerous setEnabled:YES];
[nameGenerous setTitle: @"Generous donation"
forState:UIControlStateNormal];
[priceGenerous setTitle: product.price.stringValue forState:(UIControlStateNormal)];
}
...
if ([product.productIdentifier isEqualToString:kProductTipAmazing]){
[nameAmazing setEnabled:YES];
[priceAmazing setEnabled:YES];
[nameAmazing setTitle: @"Amazing donation"
forState:UIControlStateNormal];
[priceAmazing setTitle: product.price.stringValue
forState:(UIControlStateNormal)];
}
}
如果用户点击了任何一个按钮(大量捐赠!),购买交易将被启动。有几个交易状态会生成回调。
如果支付成功(SKPaymentTransactionStatePurchased),我们需要通过调用EnablePurchaseProduct方法让应用程序知道要对其做出反应。如果支付失败(SKPaymentTransactionStateFailed),或者发生了其他事件,如果需要,我们也可以对其做出反应:
-(void)purchase:(SKProduct *)product{
if (products==nil || products.count==0){
return;
}
SKPayment *payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
for(SKPaymentTransaction *transaction in transactions){
switch(transaction.transactionState){
case SKPaymentTransactionStatePurchasing:
NSLog(@"Transaction state -> Purchasing");
//called when the user is in the process of
purchasing.
break;
case SKPaymentTransactionStatePurchased:
//this is called when the user has successfully
purchased the package
[self enablePurchaseProduct:
transaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue]
finishTransaction:transaction];
NSLog(@"Transaction state -> Purchased");
break;
case SKPaymentTransactionStateRestored:
NSLog(@"Transaction state -> Restored");
[self enablePurchaseProduct:
transaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue]
finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
if(transaction.error.code ==
SKErrorPaymentCancelled){
NSLog(@"Transaction state -> Cancelled");
}
[[SKPaymentQueue defaultQueue]
finishTransaction:transaction];
break;
default:
break;
}
}
}
如果用户之前购买过非消耗性或仍然有效的商品(比如订阅),则需要提供恢复选项。想象一下用户获得了一台新设备,或者重新安装了应用程序。根据苹果的指导方针(谷歌也有类似的规定),应用程序需要能够恢复之前的购买,如果没有这样的选项,可能不会接受您的应用程序。
应用程序调用restore方法(因为用户点击了恢复按钮,或者类似的操作),这会触发restoreCompletedTransactions方法:
- (void)restore{
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
这就是SKPaymentTransactionStateRestored状态来源的地方。应用程序应该对此做出反应,就像购买成功时的情况一样。除此之外,您还可以向用户提供一些额外的反馈,告知他们高级功能或其他购买已被恢复。
最后,交易完成,paymentQueueRestoreCompleted和TransactionsFinished方法被触发。这个方法可能更适合响应恢复或成功状态:
- (void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentQueue *)queue
{
NSLog(@"received restored transactions: %lu", (unsigned
long)queue.transactions.count);
for(SKPaymentTransaction *transaction in queue.transactions){
if(transaction.transactionState ==
SKPaymentTransactionStateRestored){
//called when the user successfully restores a purchase
NSLog(@"Transaction state -> Restored");
[self enablePurchaseProduct:
transaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue]
finishTransaction:transaction];
break;
}
...
}
}
将定价策略应用于你的商店列表
虽然应用内购买的平均转换率更高,但你也可以立即为你的应用收费。如果你在 App Store 中销售你的应用,那么最重要的问题是选择哪个价格层。你可以尝试了解 App Store 中类似应用的收费情况。例如,检查 App Annie,看看其他应用的表现。使用你的浏览器访问www.appannie.com/apps/ios/top以获取更多信息。一次性收费对于很多人都知道的应用、有良好声誉的应用以及提供内容完全清晰的应用来说效果很好。通常,竞争对手会提供免费的应用,所以你的应用提供的附加价值必须对用户明显。
如果你的应用与知名品牌相关,或者你正在细分市场中运营,那么在用户下载应用之前收费也可能有效。否则,你应该认真考虑免费增值模式,并通过应用内购买来赚钱。
这里是 App Annie(美国市场,2016 年第三季度)显示的顶级付费 iOS 应用的例子。在商店中有许多 Minecraft 克隆应用并不奇怪。Minecraft Pocket 版已经以几乎每份$7 的价格售出了 100 万份!

当然,找到你应用的正确价格点的最佳方式是进行一些测试。从高价开始,如果需要,稍后降低价格:

如果你想要测试较低的价格点是否会增加购买数量,以及你想要测试在什么价格点你的应用收入是最优的,你应该考虑为有限期限提供特别折扣。如果你已经找到了这个价格点,你可以将其永久应用于你的应用。在这里,销售数量并不是最重要的因素。相反,找到能带来最大收入的价格点。例如,假设你为你的应用收费$3.99,你每月可以卖出 10 份。如果你将价格降低一美元到$2.99,你可以卖出三倍的数量。如果你以最低价格$0.99 出售你的应用会发生什么?哇,你卖出了 60 份而不是 10 份:

但当你计算你的收入时,你会发现$2.99 的价格点是你应该选择的:
10 x $3.99 = $39.90
30 x $2.99 = $87.70
60 x $0.99 = $59.40
摘要
在本章中,我们看到了多种使你的应用盈利的方法。拥有大量用户是好的,但拥有大量客户更受欢迎。毕竟,你是在经营一个业务,对吧?
我们看到了销售你的应用和免费增值模式之间的区别,在免费增值模式中,你提供免费的应用,并通过销售高级功能来赚钱。如果你这样做,你的应用在一段时间后对用户来说将更有价值。正因为如此,一小部分用户将转化为付费客户。你的应用可能通过应用内购买策略会更有利可图。
我们研究了定价策略,并看到了如何在 iOS 应用中实现应用内购买的示例。你需要测试哪种策略最适合你的应用。你可以运行一些 A/B 测试,并必须倾听从用户那里得到的反馈。你需要找出根据用户反馈,你应用的哪些高级元素是受欢迎的。你可以查看你应用的评论,并在必要时回复他们的评论。
当你查看应用商店(或 Play Store)中的评论时,特别是负面的评论很有趣。不要因为人们对你的应用所写的内容而感到冒犯。显然,他们认为给你这样的反馈是值得的。如果你回应,不仅是对他们评论的评论,而且通过发布一个新版本来解决他们遇到的问题,你就可以将一个愤怒的用户转变为一个快乐的用户!
你需要通过尽早和频繁发布来缩小反馈循环。你需要的是持续交付策略,这正是你将在下一章中读到的!
第十八章:持续部署
在本章中,我们将了解如何组织一个工作流程,在这个工作流程中,我们将自动化测试和交付您的应用的过程。您可以为应用的临时发布和公共发布都这样做。为了使构建-度量-反馈循环真正为您所用,您需要尽早且频繁地发布。
您可以在构建服务器或另一台专用机器上安装 Jenkins 或 TeamCity,以便在每次新功能可用时构建您的新应用。基本上,就是这样,但还有许多有趣的策略可以考虑。例如,您的分支策略(Git 工作流程)是什么?您想在构建服务器上运行单元测试或 UI 测试吗?您如何支持应用的变体(Android)或目标(iOS)?让我们在本章中找出答案。
我们将探讨各种工具,这些工具可以帮助我们进行应用的临时分发。其中一些工具还可以帮助您将应用部署到 Play Store 或 App Store。
具体来说,在本章中,我们将涵盖以下主题:
-
学习自动化工作流程的好处
-
了解持续集成、持续交付和持续部署的内容
-
了解一个好的分支策略如何帮助您完成任务
-
了解TeamCity和Jenkins
-
查看构建变体或构建目标以支持应用的不同版本
-
检查Gradle如何帮助我们创建不同的构建风味和类型
-
了解如何使用Fastlane、Fabric或HockeyApp分发应用
持续部署 = 持续集成和持续交付
为什么持续集成和持续交付最初很重要?对这个问题的答案有很多。其中之一是您需要尽早获得反馈。由于您还希望确保一定的质量水平,这里可能会有一些摩擦。分发和测试您的应用将花费大量时间,然而,您也需要尽早且频繁地发布。
构建服务器可以帮助您实现这一目标,因为构建服务器可以验证您的代码是否编译成功,以及测试是否仍然通过。此外,它可以将应用分发给测试者或 App 或 Play Store。在特定时间或每次新功能实施时,构建服务器将被触发以执行这些和其他任务。
如果您想设置持续部署环境,就需要有一个智能分支策略。这也可以为您节省很多麻烦。以下是一个这样的环境的例子:

持续集成
通常,此事件将在更改被提交并推送到仓库时触发。构建服务器从特定的仓库和分支获取源代码。它尝试构建代码,并使用例如SonarQube进行自动质量检查(QA)。
SonarQube 是一个测量代码质量的优秀工具。它是一个自动化的解决方案,因此它不能完全取代代码审查,然而,它能够发现可能或可能不会成为您应用程序质量或性能问题的潜在问题。
SonarQube 将负责:
-
架构和设计
-
编码规则
-
重复代码
-
单元测试
-
代码复杂度
-
发现潜在的错误
您可以定义自定义规则或使用适用于超过 20 种编程语言的默认规则,包括您可能用于您的 Android 应用程序的 Java(很快 Kotlin 也将完全支持),Objective-C 和 Swift。您可以在www.sonarqube.org找到 SonarQube。如果 QA 检查成功,那么构建服务器还可以运行单元测试,甚至 UI 测试。
您可以配置构建服务器,使其在特定时间进行每日构建,或者在每次提交新的拉取请求时启动。最佳实践是从开发分支创建每日构建,或者每次您想要为测试人员提供一个临时发布版本时。对于每个新的拉取请求,您可以为特定的功能分支创建一个新的构建(与每个新的提交)。您将在后面的“仓库和 Git 工作流程”段落中了解更多关于分支策略的信息。
持续集成的目的是通过运行自动化测试(单元测试和 UI 测试)尽可能频繁地审查和测试代码。其理念是,如果在整个流程中任何环节失败,您将尽早得到通知。这使您能够在应用程序分发之前进行更改。只有当所有步骤都成功时,应用程序才会分发。如果构建失败,您的团队成员(通常是开发者)将通过电子邮件、Slack 或您使用的任何其他通信渠道得到通知。
持续交付
在此工作流程中,构建和测试的代码作为临时分发提供给测试人员(或测试用户)。他们可以审查应用程序并对其进行一些手动测试。他们可以执行一些功能测试,尽管有很多测试,但并非所有测试都可以自动化。
构建服务器可以通过使用 Fabric、HockeyApp、alpha/beta Play Store 或 iTunes Beta(以前称为 TestFlight)来分发您应用程序的临时版本。您应用程序的部署需要尽可能平滑。Fastlane 这样的工具可以帮助您分发临时版本,并还可以帮助您在 Play Store 或 App Store 上发布您的应用程序。
仓库和 Git 工作流程
构建服务器需要从代码库中检索代码。即使你独自工作,使用代码库也是一个明智的选择。两个知名的基于 Git 的代码库是 GitHub 和 Bitbucket(也称为 Stash)。两者都提供免费和付费计划。GitHub 仅在付费计划中提供私有代码库(见github.com)。私有代码库仅对团队成员可访问。公共代码库对任何人开放。Bitbucket 在免费计划中提供私有代码库,因此让我们在bitbucket.org创建一个 Bitbucket 账户。
下面展示了一个常见的 Git 工作流程。对于每个新功能的开发,都会创建一个功能分支。一旦完成,并通过拉取请求进行代码审查后,功能分支可以被合并到开发分支。
使用智能分支策略,至少可以完成以下两个重要任务:
-
只有经过全面测试并被接受的应用程序版本才能发布
-
热修复可以快速应用,而不会干扰持续集成工作流程
即使你是一个人开发,这也很有意义:

在 dev(或功能)分支上,可以运行单元和 UI 测试。如果所有测试都成功,dev 分支可以合并到 master 分支,并准备好发布。然而,如果应用程序运行时似乎出现了问题,您可以在 master 分支上使用功能分支来应用热修复,而不会干扰新功能的开发。
当然,这只是一个简化的例子,根据您的需求,您可能希望以不同的方式做事。要了解更多关于 Git 工作流程的信息,请查看网站www.atlassian.com/git/tutorials/comparing-workflows或git-scm.com/book/en/v2/Git-Branching-Branching-Workflows。
自动化测试
构建服务器可以为您的应用程序运行单元测试甚至 UI 测试。对于 UI 测试,可以考虑像 Espresso(Android)或 Xcode UI 测试(iOS)这样的工具。如果您正在寻找支持两个平台的工具,可以查看 Appium,例如(适用于 Android 和 iOS)。
当谈到测试时,需要考虑不同的方法。其中一种方法是测试驱动开发(TDD)。如果功能以及所有需求都是已知的,我们可以在开发我们的应用程序之前定义我们的测试。当然,所有测试最初都会失败,但这实际上是一件好事,因为它将设定需要完成的工作大纲,并集中精力确保一切正确。在实现功能的过程中,你的测试将会成功。
浓缩咖啡适合编写简洁可靠的 Android UI 测试。一个测试通常包含点击、文本输入和检查。要了解更多关于 Espresso 或 Appium 的信息,请参阅google.github.io/android-testing-support-library/docs/espresso/和appium.io。
单元测试通常在功能分支上运行,而集成和 UI 测试通常在开发分支上运行。在你通过所有测试之后,你的应用可以被部署并发布给测试用户或最终用户。
Android 应用的持续工作流程示例
一个 Android 应用的即兴分发图可能看起来如下。对于持续集成,在下面的图片中,TeamCity 用于从 Bitbucket 创建的存储库检索应用源代码:

在前面的图中,我们使用TeamCity来指示Gradle构建和签名应用,并创建一个Sonar报告来衡量代码的质量。此外,我们还运行了单元测试和 UI 测试(使用Espresso)。一旦配置完成,TeamCity将负责所有这些步骤。如果它们都成功,那么下一个步骤将上传签名的应用(APK 文件)到HockeyApp,然后它会通知用户有新版本可用。如果你愿意,你也可以使用 Jenkins 作为构建服务器,或者使用 Fabric Beta 代替 HockeyApp。我们只讨论 CI/CD 的亮点。对于构建服务器有一些有趣的书籍。有关更多信息,请参阅www.packtpub.com/。
构建变体
你可能需要交付你应用的多个版本,这并不罕见。实际上,在多个名称下发布你的应用,每个名称都有不同的外观和感觉,这可能是一个明智的选择。这对于针对多个受众群体非常有用。另一个例子是发布一个轻量级和付费(或免费和高级)版本的应用。尽管通常使用风味来定制外观和感觉,但也没有理由不能用它来启用或禁用功能。
除了特定的风味之外,你可能需要创建具有不同配置的构建类型。想象一下一个与后端通信的应用。你可能希望使用与生产环境中不同的端点来测试你的应用。这允许你在不担心会破坏生产数据的情况下安全地测试你的应用:

构建口味这个术语是用于定制的,而构建类型是用于配置目的的。口味和构建类型的组合称为构建变体;嗯,至少对于 Android 和 Android Studio 来说是这样的。如果你有轻量版和完整版的应用,并且需要至少一个配置作为测试端点和一个用于生产,那么总共将有四个变体,例如像这样:

正如我们稍后将会看到的,使用 Gradle 完成这个任务并不困难。我们可以使用多个 Gradle 任务来构建每个变体。
我们可以为我们的 iOS 应用做同样的事情吗?是的,我们可以,但方式略有不同。Xcode 允许你定义多个方案,定义构建目标,这可以与 Android 的构建口味和构建配置进行比较,实际上,它们具有与构建变体相同的目的:

在 Xcode 中,你将拥有四个不同的方案(两个目标乘以两个构建配置):

如果我们使用构建服务器,我们可以使用 Xcode 命令行工具来确定针对哪个构建使用哪个方案。
Gradle 方法
对于 Android,我们可以使用 Gradle 来:
-
确定要使用哪些资源和针对哪个构建口味
-
确定每个构建类型应使用哪些配置参数
-
为每个变体构建应用
-
签署应用
从github.com/mikerworks/packt-lean-mobile-app-development下载或克隆示例项目。
或者,更具体地,查看github.com/mikerworks/packt-lean-android-build-variants。
当我们查看示例 Android 应用的app文件夹中的build.gradle文件时,它有几个部分定义了如何处理不同的产品口味。尽管仅定义口味并保留项目的调试和发布构建类型就足够了,但示例项目中的部分可能有助于检查。
样本项目有蓝色和绿色版本,包含测试和生产端点。每个配置都有一个不同的应用程序 ID 和配置字段。
productFlavors
在productFlavors部分,你可以找到不同的口味:
productFlavors {
flavorBlueTest {
applicationId = "com.coolapp.flavorblue.test"
buildConfigField "String", "api_endpoint ", "\"https://testapi.coolapp.com/\""
}
flavorBlueProd{
applicationId = "com.coolapp.flavorblue"
buildConfigField "String", " api_endpoint ", "\"https:/api.coolapp.com /\""
}
flavorGreenTest{
applicationId = "com.coolapp.flavorgreen.test"
buildConfigField "String", " api_endpoint ", "\"test.api.coolapp.com /\""
}
flavorGreenProd{
applicationId = "com.coolapp.flavorgreen"
buildConfigField "String", " api_endpoint ", "\"api.coolapp.com /\""
}
}
sourceSets
在productFlavors部分,你可以看到每个口味引用哪些源和资源:
sourceSets {
flavorBlueTest {
java.srcDirs = ['src/blue/java']
res.srcDirs = ['src/blue /res']
}
flavorBlueProd{
java.srcDirs = ['src/blue/java']
res.srcDirs = ['src/blue/res']
}
flavorGreenTest{
java.srcDirs = ['src/green/java']
res.srcDirs = ['src/green/res']
}
flavorGreenProd {
java.srcDirs = ['src/green/java']
res.srcDirs = ['src/green/res']
}
}
java.srcDirs和res.srcDirs对象确定特定口味(或口味)所引用的文件夹。
在此项目中,文本(values.xml)和颜色(colors.xml)等资源定义在/src/main/res文件夹下:

如您所见,除了 main 文件夹外,还有两个其他文件夹:blue 和 green。在 blue/res 和 green/res 文件夹下,您将找到覆盖默认资源的文件和值。
例如,main 文件夹中的 color.xml 文件有如下内容:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="colorBackground">#888888</color>
</resources>
例如,您可以看到对于 green 香草,相同的资源文件存在,但这次 colorBackground 的值不同(一个漂亮的绿色):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="colorBackground">#00dd22</color>
</resources>
同样的,对于包含应用程序文本的 values.xml 资源文件也适用。
buildTypes
在 productFlavors 部分,您可以看到特定香草的发布签名配置与 signingConfigs 部分条目的映射,我们将在 buildTypes 部分之后检查:
buildTypes {
release {
productFlavors.flavorBlueTest.signingConfig signingConfigs.flavorBlueTest
productFlavors.flavorBlueProd.signingConfig signingConfigs.flavorBlueProd
productFlavors.flavorGreenTest.signingConfig signingConfigs.flavorGreenTest
productFlavors.flavorGreenProd.signingConfig signingConfigs.flavorGreenProd
}
debug {
testCoverageEnabled = true
}
}
signingConfigs
在 productFlavors 部分,您可以看到我们可以为每个香草使用不同的签名,使用不同的密钥库:
signingConfigs {
flavorBlueTest{
storeFile file('../app/signing/coolapp_flavorBlue.jks')
storePassword 'secretFlavorBlue'
keyAlias 'secretFlavorBlue'
keyPassword 'secretFlavorBlue'
}
flavorBlueProd {
storeFile file('../app/signing/coolapp_flavorBlue.jks')
storePassword 'secretFlavorBlue'
keyAlias 'secretFlavorBlue'
keyPassword 'secretFlavorBlue'
}
flavorGreenTest{
storeFile file('../app/signing/coolapp_flavorGreen.jks')
storePassword 'secretFlavorGreen'
keyAlias 'secretFlavorGreen'
keyPassword 'secretFlavorGreen'
}
flavorGreenProd {
storeFile file('../app/signing/coolapp_flavorGreen.jks')
storePassword 'secretFlavorGreen'
keyAlias 'secretFlavorGreen'
keyPassword 'secretFlavorGreen'
}
}
为了简化,您将在这里看到所有属性,如 storeFile、storePassword、keyAlias 和 keyPassword,这些都指的是密钥库中同等名称的属性。将它们放在单独的签名文件中是一种良好的做法。
在 Android Studio 中,如果您打开构建变体面板,它将看起来像这样:

现在,您只需要告诉 Gradle 构建特定的变体,如下所示:
./gradlew assemblectFlavorGreenTestRelease
./gradlew assemblectFlavorGreenProdRelease
./gradlew assemblectFlavorBlueTestRelease
./gradlew assemblectFlavorBlueProdRelease
打开一个终端窗口以本地构建每个变体。接下来,我们将查看 TeamCity 并了解我们如何使用它来自动构建所有变体。
使用 TeamCity 作为构建代理
可以使用构建服务器,如 TeamCity 或 Jenkins,来自动化这些流程。在我们的示例中,我们将使用 TeamCity,您可以在 www.jetbrains.com/teamcity/download/ 免费下载它。如果您更喜欢 Jenkins,您可以在 jenkins.io 获取它。
在服务器上下载、安装和配置 TeamCity,或者如果只是为了测试目的,可以在您的开发机器上安装。安装 TeamCity 后,您可以启动构建服务器。在 OS X 上,打开一个终端窗口,定位到 teamcity 文件夹的 bin 文件夹(例如,/Users/mike/Dev/teamcity/bin),然后输入以下命令:
m010:bin mike$ sh runall.sh start
启动浏览器并将它指向 http://localhost:8111。等待 TeamCity 的设置完成,然后创建一个新项目,如下所示:

现在我们知道了如何使用 Gradle 构建不同的变体,接下来显示的图片不会太具有挑战性。我们有一个轻量和完整版本。我们希望为每个版本构建两个:一个从测试端点消耗数据,另一个从生产端点获取数据。这将总共产生四个 APK 文件:

现在我们将创建一些构建步骤,使用 Gradle 创建四个 APK 文件,就像我们在本地做的那样。首先,我们需要告诉 TeamCity 应该从哪里获取此特定项目的存储库。对于此项目,我们将为所有口味使用相同的存储库和分支,但对于更复杂的项目,口味和构建类型可能会有所不同。这是因为在一个开发分支上运行您的临时测试,以及在产品分支上运行您的最终测试是有意义的。
定义项目的 VCS 根并选择 Git 作为 VCS 类型。给它一个名称,并选择以下 URL 作为获取 URL:github.com/mikerworks/packt-lean-android-build-variants.git。
您不需要在此处输入凭据(认证方法为匿名),因为此 Bitbucket 存储库具有公开访问权限。
现在您已准备好创建第一个构建步骤。选择“命令行”作为运行类型,因此您可以为构建脚本内容输入与您在本地机器上相同的内容:

对于“自定义脚本”字段,输入./gradlew assembleFlavorGreenTestRelease。
您可以在 TeamCity 中定义额外的构建步骤,例如,运行单元测试、UI 测试、SonarCube QA 检查,以及基本上您可以从命令行自动化的任何其他内容。
自动部署和交付
您的应用程序在构建、签名和测试后需要分发。有多种方法可以做到这一点:
-
自托管网站
-
HockeyApp 或 Fabric 测试版
-
Play Store alpha/beta 或 iTunes beta/TestFlight
自托管
您可以上传已签名的 APK 并将其发布到您自己的网站上。对于 Android,只需托管 APK 即可(尽管您可能需要为 IIS 进行一些额外的配置)。对于 iOS,您可以使用 Over the Air (OTA) 清单分发您的 IPA 文件。如果您选择此选项,您仍然需要注册 UDIDs 并创建相应的临时配置文件。
从一个高层次的角度来看,这种方法看起来是这样的:

您还必须通知您的用户关于网站上有新版本可用。
HockeyApp 或 Fabric 测试版
有许多 SaaS 解决方案可用于分发并通知您的用户新的临时发布。其中之一是 HockeyApp。您可以使用一个 (cURL) 脚本将您的已签名 APK 或 IPA 文件上传到 HockeyApp。HockeyApp 还可以通知您的用户新的构建,并且每个版本都可以包含发布说明,例如,通过添加一个运行此命令的构建步骤:
curl -F "status=2" -F "notify=0" -F "ipa=@//TeamCity/buildAgent/work/<work folder>/app/build/outputs/apk/app-release.apk" -H "X-HockeyAppToken:<your hockey app token>" https://rink.hockeyapp.net/api/2/apps/<app id>/app_versions/upload
使用 HockeyApp,界面将如下所示:

HockeyApp 是一项付费服务,它减轻了您在 iOS 应用程序分发中的配置文件烦恼。Fabric Beta 是另一个您可以用于临时分发的服务。Fabric beta 是一个免费增值服务,并且它的工作方式几乎相同。
Fastlane,alpha/beta Play Store,和 iTunes beta
如果您将 fastlane 与 beta Play Store 或 iTunes beta/Testflight 分发结合使用,那么您可能可以节省一些时间和麻烦。
Fastlane 是将您的应用程序交付到测试或生产环境的一种工具。因为它使用 iTunes beta 进行您的 iOS 应用程序的临时分发,所以它不再需要您事先获取测试用户的 UDID。这种方法的一个缺点是,虽然它是一个临时的 beta 分发,但您的应用程序需要先由 Apple (预-)批准,这会花费更多的时间,直到测试版本对您的测试用户可用。
它将高级视图转换为这个:

fastlane 的路线图看起来像这样。它将负责您分发流程的每个部分。它最初是为 iOS 应用程序分发开发的。
Fastlane 带有各种其他有趣的功能,这些功能将使您的构建自动化生活更加光明,例如:
-
创建(本地化)截图并上传它们
-
向 App Store 发送更新元数据
-
在配置文件中生成和续订推送通知
-
运行测试
Fastlane 也适用于 Android。这可能是自动化构建和发布您的应用程序的最简单方法。您可以在 fastlane.tools 找到 fastlane。
正确设置 CI/CD 需要一些时间(和一些痛苦),但这值得投资!
DevOps
通常,您不仅是开发者,还是运营商。DevOps 文化最常见于初创公司;然而,越来越多的成熟公司正在采用其哲学。DevOps 建立了一种文化和环境,其中构建、测试和发布您的应用程序将快速、频繁且更可靠地发生,这正是我们所希望的。基本上,这个想法是,整个过程将成为从开发到运营(配置、监控和调节)团队的责任。如果在生产中出现故障,您将创建一个热修复,测试它,然后重新发布它。
CI/CD 的持续集成部分特别关注 DevOps 中的开发部分。交付部分更多地关注运维部分。这两个循环可以对应于构建-度量-反馈循环(从更高视角来看):

持续交付和 DevOps 经常一起使用。它们有共同的目标,例如向最终客户提供小而快速的变化,并专注于有价值的方面。CD 和 DevOps 之间的一些区别在于,后者还关注组织变革,以支持涉及到的许多功能之间的良好协作。它要求每个团队成员都具备良好的协作和沟通技巧。随着您的组织和团队开始成长,这一点将变得越来越重要。
CI/CD 和 DevOps 使得分割测试和收集反馈变得更加容易。这种方法将显著促进精益创业方法(从技术角度)的采用。这将导致更好的质量,更高的客户满意度,以及更多(更早!)的发布。
摘要
我们已经了解了 CI 和 CD 是什么,以及它们为您带来的好处。公共或临时的分发可以由构建服务器启动。您可以使用构建服务器,例如 TeamCity 或 Jenkins 来构建和测试您的应用程序。
可以使用 HockeyApp、Fabric Beta 或 Play Store 或 App Store 的测试版程序来分发临时的发布。Fastlane 可以帮助您完成这些和其他任务。到目前为止,您可能已经学到了很多。
CI 和 CD 对于您想要提高和维护代码质量,以及想要优化工作流程来说非常重要。它允许您收集反馈,因为您能够提前和频繁地发布。CI/CD 和 DevOps 文化可以帮助您优化构建-度量-反馈循环。
在下一章中,我们将学习为什么如果您想成功,如果您想作为一个公司生存下去,构建不公平的优势是重要的。
第十九章:建立不公平的优势
仅仅建立一个客户喜爱的优秀应用是不够的。这无疑很重要,但如果你想建立一个能够长期成功的策略,你需要采取一系列策略,这些策略将帮助你建立和巩固市场地位,并限制竞争对手的选择。在本章中,我们将探讨精明的企业家可以用来在他们业务周围建立护城河的各种技术,从而最小化竞争对手攻击的影响。
尤其,我们将探讨以下主题:
-
无形资产,如知识产权(IP)法律和法律保护
-
网络效应和平台效应的好处
-
对垂直市场或垂直市场中的关键关系的控制
-
转换成本和定价策略
-
优质客户服务和客户支持的好处
-
一个良好发展的品牌名称的力量
简介 - 这不仅仅是关于你的应用
你的公司十年后能盈利吗?持久的竞争优势可以使你的公司在面对不可避免的竞争对手、模仿者和衍生品冲击时保持盈利。建立这样的竞争优势,或在你业务周围建立一个“护城河”,对于确保长期盈利和稳定性至关重要。
竞争者可能来自各个方向,因此为了保护你的业务、产品和想法,你需要采取各种策略来防御潜在的攻击者。
发展一个想法,用早期采用者测试它,并对其进行改进是走向持久成功的第一步重要步骤。针对问题的以客户为中心的创新解决方案是成功企业的基石。然而,在你测试并证明你的假设之后,你需要将这个想法的种子在现实世界市场中培养,这可能会非常具有竞争性。
在你的最小可行产品(MVP)证明现实世界的可行性之后,你需要扩大规模并与需要你解决方案的客户进行“土地抢夺”。你的业务增长越多,注意到你的竞争对手就越多;毕竟,市场可见性有助于你的业务扩张,但同时也是竞争的磁铁。一旦你的业务在市场上确立了位置并划定了领土,你需要开始防御这个领土。
竞争优势是你长期防御的最佳手段。接下来,我们将探讨建立这种竞争优势时最有效的策略,这样你就可以保留你辛勤工作所创造的利润。
用无形资产挖掘护城河
无形资产通常指的是以知识产权法、专利和商标形式存在的法律保护。这些是任何在市场上证明有价值的产品的基本防御机制。除非得到保护,否则好的实施将会被盗取,因此尽快考虑你的法律选择至关重要。
用知识产权法保护你的作品
理解知识产权法的工作方式将帮助您了解如何最好地保护自己的作品。了解这些法律的一个额外好处是,您还将了解如何在不经意间跨越知识产权界限:

您应该关心的原因 - 摧毁业务的专利流氓
关于知识产权法的讨论可能看起来与精益开发的主题相去甚远,尤其是对于仍处于 MVP 创建早期阶段的开发者来说。然而,商业世界是残酷的,尤其是在涉及大量资金的情况下。
在科技行业,专利要求和诉讼是司空见惯的,而且众所周知,它们经常被用作对付有前途的初创公司的武器。
加州大学法学院教授罗宾·费尔德曼(Robin Feldman)于 2013 年发表的一篇论文提供了数据,证明了为什么没有任何初创公司应该在没有任何知识产权盔甲的情况下进入市场。根据她对 200 名风险投资家的调查:
-
三分之一的初创公司已经收到专利要求
-
70% 的风险投资支持的初创公司已经收到专利要求
-
100% 的风险投资家表示,“如果一家公司面临现有的专利要求,这可能会在决定是否投资时起到潜在的威慑作用”
她的调查还发现,大多数专利要求并非来自产品所有者或创作者,而是来自主要功能是专利许可或诉讼的实体。这一事实强烈表明,专利诉讼是在幕后竞争集团的背后支持的。显然,知识产权诉讼和专利要求是商业战争中的标准武器。
为了保护自己免受此类攻击,提前规划是值得的。
专利申请和商标注册都需要研究、时间和金钱。很容易找借口并将这些必要性放在一边,但时间越长,风险就越大。接下来,我们将简要概述知识产权法,以便您可以在长期商业计划中为法律策略腾出空间。
知识产权法如何保护您的应用程序和业务
知识产权法实际上并不保护一个想法,它们只保护该想法的实现。以下是一些主要知识产权法如何工作的例子:
-
专利保护新颖的、“非显而易见”的独特流程。它们只涵盖从该想法产生的物理对象或物理设计,而不是该想法本身。软件程序或技术的特定实现,如新颖的应用程序功能,可以受到保护,但一般概念则不能。
-
著作权法保护创意想法的表达,通常以媒体形式;书籍、视频、音乐和源代码都是可以版权的作品。一旦创作,版权作品就受到版权保护。
-
商标保护商品或服务的表示,例如公司名称、操作系统初创公司风格或标志。
-
诸如源代码或可口可乐配方之类的商业机密可以无限期地受到保护。这些秘密不能被故意侵犯,但可以被窃取。
虽然这些知识产权法律是针对侵权和盗窃最知名和常见的防御手段,但它们并不是保护您地位的唯一方法。
如何保护您的知识产权
保护您的应用程序最重要的步骤是确保专利安全。用户界面元素、独特新颖的应用程序功能和软件程序本身都可以申请专利。商标可以用来保护特定的设计元素、整体的设计布局,以及您的应用程序和公司的名称和表达。
在专利要求的情况下,每家公司都必须自己决定如何行动。毕竟,每一次法律斗争都会带来其自身的风险、利益和缺点。Feldman 博士的前期研究发现,对于她调查的大多数参与者来说,专利要求的准备和防御费用超过 50,000 美元。每种情况都是独特的,如果公司收到专利要求,每个公司都应做出自己的决定。
当然,没有专利的另一方面是,另一家公司可以自由地复制、窃取并为其自己申请您的技术专利。因此,第一步是确保您在每一步都保护您的知识产权。
接下来,我们将探讨法律领域的另一个方面:如何将法律作为武器而不是防御手段。
进行法律进攻
虽然这可能对某些人来说是一个令人不快的讨论,但重要的是要重申,商业世界与应用程序实验和开发是不同的游戏。尽管精益方法可以帮助您开发出客户需要和想要的相关产品,但您在进入市场时必须为激烈的竞争做好准备。然而,法律策略是隔离、保护和垄断您市场某些领域的手段之一。
PayPal 的亿万富翁创始人彼得·蒂尔认为,“当你开始创业时,你总是希望追求垄断,并始终避免竞争。”你浪费在与竞争对手竞争和超越他们上的每一分钱,都会减少你用于创新和增长的资金。
虽然我们不提倡窃取知识产权、专利勒索或欺负小公司使其消失,但您当然可以开发出法律机制,阻止竞争对手进入您的领域,并释放公司资源用于其他事情。
下面是一些公司如何使用法律障碍来拓宽其经济护城河的例子:
-
我多年前为一家抵押贷款经纪人培训公司创建的软件,该公司推广了要求每个州进行经纪人认证的州法律,这正是他的公司提供的服务。这是一个明智的策略,产生了非常积极的结果。
-
如前所述,在“鲨鱼池”般的企业世界中,合法地采用某些不受专利或商标保护的未受保护的设计元素或功能是技术上的合法行为。
-
亚马逊,一个在美国乃至全球零售业中决定性地颠覆了行业的垄断者,有着使用法律进攻策略的历史。像许多科技公司一样,它使用专利来维持其竞争优势,并利用法律漏洞在许多州避免征收销售税(从而增加其相对于其他企业的价格优势)。
在法律方面,你能够采取的每一个行动都将帮助你将竞争对手拒之门外。法律在进攻和防御方面都非常有效,但它只是众多工具中的一种。接下来,我们将探讨更多以用户为中心的商业策略,这将进一步巩固你的市场地位,抑制竞争,并最大限度地控制你的市场。
网络效应和平台
当用户数量增加时,产品或服务的价值增加时发生网络效应:

第一种网络效应发生在用户 themselves 为产品或服务增加价值时。例如,Facebook、论坛和搜索引擎等服务的用户生成内容增加了这些服务的价值,有效地将用户转化为资产。
平台效应,有些人认为它是另一种网络效应,指的是当一家公司能够提供平台——一系列服务——而不是仅仅一个产品时,价值的放大。随着更多商业伙伴向平台添加服务,价值增加。
这两种效应在当今的技术行业中都非常明显。
网络效应
为了说明第一种网络效应,我们将考察世界上最大的社交应用和最大的在线零售公司——Facebook 和亚马逊。两者都鲜明地展示了用户如何贡献并放大产品或服务的价值。
检查这两种公司在网络效应中的表现:
-
以 Facebook 为例,使用 Facebook 的人越多,它积累的势头和价值就越大,因为它可以用来连接越来越多的人。这种效应的副产品是,竞争性社交网络的价值降低,这使得转向竞争对手变得更加困难。这种效应,被称为转换成本,将在后面更详细地探讨。
-
在亚马逊的案例中,它在市场上收购的卖家越多,其库存就越大,其定价就越具竞争力,它就越成为人们首选的在线零售店,其市场地位就越稳固。
-
对于这两家公司来说,随着网络效应的增长,口碑营销变得更加有效,从而降低了用户获取成本。
-
使用任何一种服务的人越多,该服务的品牌形象和声誉就越高。
这些只是从网络效应中受益的公司海洋中的两家。无论是设计移动应用还是社交网络,考虑如何将你的用户变成资产,从而增强你最终产品的价值,都是有益的。
平台效应
如前所述,平台效应,另一种网络效应,也发生在更多商业伙伴通过自己的互补产品或服务增强原始服务时。WordPress 和 Windows 提供了如何利用这一效应来扩大你应用城堡护城河的绝佳例子。
这两家公司,尽管提供非常不同的核心产品,但都展示了这一效应的实际应用:
-
Windows,由于其数十年的市场主导地位,几乎锁定了其在 PC 事实上的操作系统地位。在这个过程中,它与一支由 PC 制造商、软件开发者和相关产业组成的军队结盟,这些产业通过提供自己的互补产品和服务,极大地增强了 Windows 的原始服务。
-
WordPress 同样也是一个平台。这个开源内容管理系统,官方上被认为是世界上最受欢迎的,是为了可扩展性而构建的。它允许开发者轻松创建插件、主题和修改。部分得益于这种平台效应,WordPress 的功能得到了飞跃性的增长,进一步放大了其增长,使得其他内容管理系统几乎无法侵犯其领域。
-
在我工作的汽车行业,提供无缝统一一系列产品的软件公司使独立初创公司面临难以成功的困境。
平台效应的实际例子数不胜数。从操作系统到网络浏览器,再到金融软件,从平台效应中受益的软件名单不断延长。有些产品,如 Windows 或 Android,主要是平台产品。其他产品,如 WordPress 或 QuickBooks,提供核心服务,而互补产品使这些服务变得更加稳健。如果你的产品可以从用户网络中受益,或者它可以作为平台被利用,那么你应该将其作为产品设计和市场开发计划的核心部分。
利用垂直市场
在商业中,垂直市场,或称为“垂直”,是一个专门化的细分市场,服务于狭窄的行业或客户群。一家专门为餐厅开发移动销售点软件的软件公司就在垂直市场中运营。一个为纽约业余摄影师提供社交网络的 App 就是另一个例子。
与垂直市场不同,水平市场是通用市场,它们将产品销售给广泛的客户。从技术角度讲,所有企业都在水平方向和垂直方向上运营,尽管程度不同。水平市场的主要优势是它提供了一个比垂直市场大得多的用户基础。另一方面,水平市场更加竞争激烈,并且难以渗透。
正如我们将看到的,利用垂直市场可以给你带来重大的竞争优势,有助于水平扩张,并为你提供一个稳固的经济立足点。
为什么要针对垂直市场?
对垂直市场的访问和控制可能意味着快速增长和蜗牛速度之间的差异。尽管垂直市场有其弱点,如有限的客户基础和随特定行业健康状况波动的财务状况,但它们提供了显著的优势:
-
垂直市场为你提供了一个渠道,你可以以专注的方式销售你的产品并与客户建立关系。
-
尽管一些垂直市场竞争激烈,但其他则不是,这将使你更容易占据主导市场地位。
-
控制垂直市场,本质上,允许你在该市场内创造一个垄断,这保证了收入、客户和经济关系。
-
由于用户基础和行业的特定性,许多业务方面都变得更容易、更经济,从市场营销到用户测试到用户获取。
尽管你应该获得对垂直市场的访问和控制,但这并不意味着你应该在该垂直市场内独家运营。正如我们在第十一章 Onboarding and Registration 中看到的,垄断狭窄市场是向水平扩张迈出的理想第一步。
成功公司如何利用垂直控制
尽管完全控制垂直市场并非易事,但将竞争排除在你的领域之外,在某种程度上,你可以为你的市场设定条款。以下是一些公司如何通过这种垂直控制进行扩展和利用的例子:
-
苹果对其价值链的控制展示了垂直控制或垂直一体化的几乎完整示例。它设计和开发自己的桌面和移动硬件,运行在这些硬件上的操作系统,以及在这一环境中运行的广泛的应用程序和软件产品。
-
一项斯坦福大学的研究发现,医疗保健领域的垂直一体化,以医院和医生实践之间的合同义务的形式,通常会导致更高的医疗保健成本和医院支出——换句话说,增加了医疗保健专业人士的利润。
-
在汽车行业,快速增长的供应商通常是通过 OEM 关系实现的。OEM 背书或推广转化为快速市场增长和更稳固的市场地位。
-
我之前的公司通过与一个广告集团建立关系而迅速增长,该集团给它提供了许多汽车经销商的访问权限。这种增长是立即的,导致业务迅速激增。
垂直控制的最终形式是垂直整合,即公司能够控制自己的供应链。对于绝大多数公司来说,这是不可能的,但你对垂直市场的接触越多,获得经济利益就越容易。
转换成本
转换成本是指客户在转向竞争对手的产品或服务时产生的成本。陡峭的转换成本可以阻止用户离开。根据具体情况,这些成本可能以各种形式出现。以下是影响考虑采用新企业级软件包的公司的一些转换成本类型的示例:
-
直接成本:与研究、评估和谈判这些新软件包价格相关的成本
-
关系成本:习惯于旧产品的团队成员之间的干扰或不满
-
产品相关成本:购买价格、培训成本,以及与原产品解耦相关的财务成本
这些只是与 B2B 产品转换相关的成本的一些例子,但它们往往是最常见的。
维护已获得客户的较高转换成本,同时降低新客户的转换成本,是任何产品策略的重要组成部分。尽管转换成本可能很高,以至于客户实际上被困在船上,但我们将看到这种策略如何适得其反。
如何使用转换成本来提高用户保留率
为了提高你自己的产品的转换成本,请查看前面的列表。考虑你可以故意增加现有客户的这些成本的方法,以阻止他们放弃,同时降低竞争对手的转换成本,以激励他们采用你的产品。以下是一些实际存在的转换成本示例,你可以用这些示例来激发你自己的产品或服务的想法:
-
大型企业软件包,如 InfusionSoft、QuickBooks 或 Salesforce,在各个方面都涉及高昂的转换成本。它们需要大量的研究和评估;它们的学习曲线和培训成本很高,并且可能会对习惯于以不同方式做事的员工造成重大干扰。
-
手机合约是公司如何降低竞争对手的转换成本同时提高自己转换成本的绝佳例子。一旦签订合同,合同取消费用使得客户离开在经济上变得困难。然而,为了激励新客户签约,许多合同为新客户提供大幅折扣的手机。
-
社交应用和大多数其他现代应用显著降低了进入门槛——它们易于使用、免费,并允许即时社交互动。然而,网络效应使得关系转换成本如此之高,以至于几乎不可能进行改变。例如,与朋友或家人的联系丢失,使得许多用户难以离开 Facebook。
这些只是大型企业如何使用转换成本来保持用户在板上的几个例子。更多想法,请检查你所在市场或类似市场中的任何成功科技公司,并思考公司如何保持其现有用户群的转换成本高,然后将这种相同的思考应用到你在市场定位产品的方式上。
如前所述,降低客户从竞争对手那里转换的成本是降低你的产品或服务进入壁垒的一种方法。接下来,我们将探讨如何使用这种策略来加速用户基础的成长并侵蚀竞争对手的领土。
如何降低竞争对手的转换成本
为了让人们更容易从你的竞争对手那里转投,找到方法来中和或降低竞争对手的转换成本。基于之前的例子,我们将探讨上述公司降低竞争对手客户转换成本的一些方法:
-
QuickBooks 采用许多标准技术来简化注册过程并降低成本。为了减轻使用新产品相关的压力和感知成本,QuickBooks 自然提供免费试用。为了降低学习曲线,它提供用户友好的视频以及应用内教程和指南。此外,它明智地利用平台效应;大量的插件和第三方集成使得用户更容易使用客户可能已经订阅的服务。
-
尽管之前提到的取消手机合同费用阻止了许多客户转向其他提供商,但 2 年合同、提前终止费用和前期投资让客户感到被困。弱势运营商利用这种情绪,通过消除登机和离场障碍;客户可以使用自己的手机而不是购买新的手机,他们不需要签署合同,并且可以随时离开。
-
大多数社交应用使用与你在自己的应用中通过精益方法可以采用的相同策略来降低竞争对手的转换成本。也就是说,成功的社交应用非常相关、易用、设计良好且性能出色。所有这些因素都促进了应用的成功首次体验,正如许多开发者所知,这可能是新用户和卸载用户之间的区别。
转换成本以及本节中涵盖的任何其他商业策略:应该围绕用户需要和想要的产品来构建。如果业务变得不平衡,将精力投入到业务战场而牺牲产品和客户,那么产品本身可能会变得薄弱,从而失去市场份额。这使我们想到了另一个以精益为导向的策略,这将帮助你保持对客户以及商业领域的关注。
良好的客户支持
许多新企业往往忽视良好的客户支持。这是不明智的,因为当客户相信你关心他们的成功时,他们就不太可能离开你。
成功的公司长期以来一直认为客户服务和客户满意度对客户忠诚度和利润有直接影响。许多统计数据支持这一观点,即客户服务对每个企业都至关重要,无论大小:
-
坏客户服务的消息传播的人数是好消息的两倍
-
获得新客户至少比保留现有客户贵六倍
-
70%的购买体验基于客户感觉他们受到的待遇
-
盖洛普发现,客户更关心客户服务的质量和全面性,而不是服务的速度
创业公司有很多事情要做,因此客户服务被放在其他问题之后是可以理解的。然而,提供良好的客户服务不是陈词滥调,也不应该成为一种空洞的口号。当你考虑到客户服务对你底线直接的影响时,考虑如何从一开始就提高客户服务是值得的。
正确的客户服务观念
人们普遍认为,客户待遇影响他们对产品、公司和品牌的看法,这影响忠诚度。这种认识导致了“客户体验”这一概念的产生,它可以被设计和改进。然而,完美的客户体验是什么,却有一些争议。
许多企业将重点转向客户满意度,这导致了将客户视为皇室成员或取悦他们的努力。这种迎合方法有几个问题——它基于有统计支持的观念,即客户满意度很重要,但解决方案“取悦”客户,没有科学依据。
不要迎合他们,坚持精益方法并倾听他们的意见。
无论是应用用户还是零售购物者,客户都希望他们的问题得到解决。根据《哈佛商业评论》发表的研究,过度“令人愉悦”的客户服务“并不能建立忠诚度”,而“减少他们的努力——他们必须做的工作以解决问题——才能做到。”他们说,采取这一知识行动,你会提高客户服务,降低客户服务成本,并减少客户流失。
一份提供优质客户服务的方法
在公司的早期阶段,您可能不会有大量的资金。幸运的是,技术允许许多年轻初创公司以 20%的努力实现 80%的结果。以下是一些您可以最大化客户服务努力而不浪费金钱的方法:
-
通过在社交媒体和评论中公开回应来展示您的可用性和关注。如果一个人发表评论,请放心,其他人也有同样的感受。毕竟,研究表明,对于每一个公开发声的人,还有许多保持沉默的人。
-
创建一个在线知识库,以便客户可以快速轻松地找到答案,而无需直接联系您。这将为您和您的用户节省时间。
-
在客户意识到有任何问题之前解决问题。了解分析并倾听客户,以便您可以发现潜在的痛点,解决它们,并在必要时进行修复。
-
在整个周期中保持以客户为中心。与其取悦客户,不如关注他们,解决问题,并始终倾听他们的意见。
总是记住,应用用户是客户,而不是变量或应该被“取悦”的孩子。良好的客户服务将对您的整个业务产生连锁反应。尽管您可能无法衡量这种影响的各个方面,但它可以减轻负面体验并显著提高您品牌的整体用户体验。
成功公司如何利用客户服务来提高利润
高级别的客户服务帮助许多公司获得了上述好处,包括提高客户忠诚度、降低流失率和增加终身价值。以下是一些通过客户服务途径扩大其经济护城河的公司示例:
-
亚马逊的核心原则是客户体验,并且它围绕倾听客户的声音构建了整个业务。根据创始人兼首席执行官杰夫·贝索斯的说法,“如果你在现实世界中让客户不高兴,他们可能会告诉六个朋友,但在网上,每个人都可以告诉 6000 人。”亚马逊商业模式的各个方面,从他们的退货政策到客户支持人员再到他们的产品推荐引擎,都是为了一个目标:让客户满意。
-
2012 年泄露的苹果客户服务培训手册将客户体验放在首位。与其以销售为先的方法不同,据 Gizmodo 报道,“天才培训学生工作手册”是一份详尽的指南,用于了解客户并使他们满意,因为“满意的客户是会购买东西的客户”。这种方法的彻底性清楚地表明,客户体验的任何方面都不应留给偶然。
-
我以前的公司向汽车经销商销售了一种 CMS 软件解决方案,该解决方案提供了一系列附加功能,以提高经销商的客户接触、获取和管理。我们有两个目标:
-
创建易于使用且价格合理的应用
-
总是寻求让客户满意
-
结果是,该公司在其市场内健康成长(没有大量融资)并且拥有极低的流失率。我们从未等待客户来电;我们总是主动提供方法,让他们能够最大化使用我们的产品,从而赚取更多利润。我们不是苹果或亚马逊,但我们遵循同样的原则。
客户满意度是一种情感,因此比像转化率这样的硬指标更难衡量。衡量客户体验、客户忠诚度和其他客户关系指标的商业影响也更为困难。然而,根据可用的研究和世界上一些最成功公司的行为和客户服务记录,显而易见的是,出色的客户服务可以帮助您在客户心中脱颖而出。在本章中,我们将讨论的最后一种策略,即打造强大的品牌,将帮助您在客户心中以及整个市场上脱颖而出。但在那之前,我们将快速查看一些有助于您处理客户支持的工具。
一些优秀的工具可以帮助您处理客户支持。
在撰写本文时,市场上存在数十种客户服务工具。其中许多包括免费试用和免费功能。以下是一些例子:
-
Zendesk (
zendesk.com):这是一个功能强大的客户支持平台,提供某些免费功能。 -
Freshdesk (
freshdesk.com):这也提供免费版本,可能足以满足初创公司和小型企业的需求。 -
Salesforce desk (
desk.com):这是 Salesforce 套件的一部分,对于使用 Salesforce 的公司来说是一个不错的选择。 -
Zoho desk (
www.zoho.com/desk/):Zoho 产品套件的一部分,对于使用 Zoho 的企业来说是一个不错的选择。 -
Conversocial (
www.conversocial.com/):专注于社交和移动应用支持。
这些工具中的绝大多数提供免费试用,甚至提供功能有限的免费计划。大多数这些工具将知识库与基于票务的支持、实时聊天和呼叫中心软件集成。
在评估各种选项时,寻找对您的组织相关的功能。例如:
-
您是否打算在您的应用程序中集成实时聊天支持?
-
将客户支持与第三方工具(如 Zapier)集成是否有益?
-
您是否已经在使用现有的套件,例如 Salesforce、Freshworks 或 Zoho?
-
每个平台提供的 widget 和可嵌入功能有哪些?
这些问题的答案将帮助您筛选市场上大量的客户支持选项,从而缩短您的测试时间。
最后,如果你想与客户保持紧密联系并获得即时反馈,不要忘记探索聊天工具。如今,在你的应用程序中安装与客户支持软件集成的插件非常容易。虽然实时聊天支持可能会根据你业务的大小而变得繁重,但它确实可以缩小你与客户之间的差距。这种实时互动可以提高客户满意度并增强你对客户需求的了解。同样,就像之前列出的专用客户支持工具一样,你有很多选择。以下是一些获奖选项:
-
ZenDesk Chat (
www.zopim.com/):之前被称为 Zopim,该应用程序最近被 ZenDesk 收购,纳入其产品套件。他们提供 14 天的免费试用 -
LiveHelpNow (
www.livehelpnow.net/):这个选项提供免费 30 天试用期,包括视频、定制、移动版本和数据分析 -
WebsiteAlive (
www.websitealive.com/):这个选项为一名用户提供免费版本,并在非工作时间有备份操作员为你解答
一个良好发展的品牌名称的力量
根据尼尔森的调查,对于北美和南美的客户来说,品牌认知是客户购买产品的第二大重要原因。尼尔森的进一步研究表明,品牌认知影响着发达市场和新兴市场的购买决策,大多数人更愿意从他们熟悉的品牌购买新产品。
品牌名称让你的客户和潜在客户记住你,这使得新竞争者更难引起注意。正确的品牌名称可以创造关于你产品的积极感受,并建立一种忠诚度,使得初创公司、新兴公司或现有公司难以竞争。
建立品牌名称可能需要时间和努力,但通过共同努力和战略营销计划,这是可能的。
品牌自己的原因
由于统计数据显示,客户从知名品牌购买的商品比从不知名品牌购买的商品更多,因此很明显,品牌非常重要。虽然这种无形资产可能看起来模糊,甚至比客户服务更难衡量,但对于任何希望从竞争中脱颖而出的企业来说,它都是至关重要的。以下是一些品牌名称可以实现的最重要目标:
-
认知:当客户认出你的品牌时,他们会立即将这个品牌与与品牌相关的一切联系起来。
-
承诺:你的品牌名称传达了你对客户的承诺。它唤起了你的价值主张或独特卖点,并告诉客户在购买你的产品或服务时可以期待什么。
-
信任:品牌名称越强大,该名称就越受信任。信任是客户从他们认识的品牌购买的原因之一:过去的经验和声誉共同激发客户的信任。
-
地位:品牌也传达了地位,这在服装行业中尤为明显。当客户与知名品牌相关联时,他们也与该品牌的地位和形象相关联。
-
忠诚度:随着时间的推移,品牌会在客户中激发忠诚度,这有助于实现本章中提到的其他策略相同的目标:您通过一群忠诚的用户建立安全的市场领域,成功地阻止了竞争对手。
品牌资产,或您品牌的财务价值,可能比客户服务改进的回报率(ROI)更难衡量。然而,其力量是不容置疑的,如果您希望围绕您的城堡建立经济护城河,它是您武器库中的必备工具。
如何建立您的品牌
品牌建设是一个深奥的话题,超出了本书的范围。如果您的预算允许,考虑聘请专家帮助您更全面地发展您的品牌。然而,当您涵盖了这些基本要素后,您就可以开始构建良好品牌的基础:
-
好名字:最好的名字是精心设计的,以唤起某些情感联想。例如,汽车制造商捷豹(Jaguar)故意唤起同名动物。选择一个能够传达您希望传达给客户的情感和身份的名字。
-
视觉识别:您的标志、您的色彩方案以及您在所有存在形式中的视觉设计应与您的品牌身份保持一致,并相互之间保持一致。例如,在您的网站、您的应用程序和您的营销材料中保持相同的方案。
-
信息传递:每个品牌背后都有一个故事。这个故事与您品牌的其他元素相结合,并在您的商业沟通中体现出来,从市场营销到客户服务。
从第二章“精益创业入门”中您创建的商业画布模型出发,利用您公司的使命和目标受众的信息进行外推。找出您希望向受众和世界传达的印象,然后与创意人员合作,开发之前提到的构建块。
监控您品牌在社交媒体和应用程序商店的工具
品牌监控和社交媒体监控工具已经兴起了一段时间,它们有各种各样的形状和大小。有些是免费的,而企业级工具可能和一名员工的工资一样昂贵。以下是一些例子:
-
Hootsuite (
hootsuite.com):这是一个流行的社交媒体管理平台,也监控品牌对话 -
Mention (
mention.com):这将跟踪社交媒体和网络上的关键词或关键词组,以帮助您跟踪您的品牌何时何地被提及 -
Buzzsumo (
buzzsumo.com): 这允许你为关键词、作者、域名和反向链接创建警报 -
SocialOomph (
socialoomph.com): 这是一款包含监控功能的社交媒体管理工具
这些只是写作时的一些更常见的选项,尽管未来几年可能会有更多。预算有限的初创公司可以考虑将免费服务,如上述工具,与自动化服务如 Zapier 和 IFTTT 集成。
在预算有限的情况下建立品牌
预算有限的初创公司可以轻松利用今天快速全球化的自由职业市场,帮助完成任何可想象的服务,从市场研究、虚拟办公室支持、平面设计到文案写作。
Google 可以提供更多选项,但以下是一些开始的方法:
-
Fiverr: Fiverr (
fiverr.com) 是一个以 5 美元为单位提供服务的自由职业市场,大多数服务价格都远低于 100 美元 -
Upwork: Upwork (
upwork.com) 允许你发布项目和预算,然后接收来自自由职业者的报价 -
Freelancer: Freelancer (
freelancer.com) 运作方式类似于 Upwork,你可以创建项目规格和预算,发布该项目,然后在项目过程中与自由职业者紧密合作 -
克雷格列表: 最后,克雷格列表 (
craigslist.org),世界上最大的分类广告网站,允许你直接发布广告并招募自己的独立承包商
这种低成本选项将需要你进行投资,但它们对于自筹资金的初创公司非常有帮助。
评估自由职业者的最佳方式是首先对你需要完成的任务进行一些研究,以便你可以确定该活动的最佳实践。然后,当你进行面试时,你可以询问他们关于最佳实践的问题,看看他们如何回应。如果他们毫无头绪,那么就避开他们。
下一步是进行试点,然后仔细审查质量、及时性、关注细节等方面。如果你喜欢你所看到的结果,那么尝试更大的项目。如果不满意...就撤退。
我雇佣了很多自由职业者。这些简单的规则帮我节省了大量的钱。当然,我不得不先损失一些钱来吸取教训。
以对待你的最小可行产品(MVP)的方式对待品牌:构建、衡量、学习。一旦你有资源这样做,你总是可以不断发展和调整。
品牌案例研究
正确的品牌形象可以让你在竞争对手中脱颖而出,激发信任,并保持你在客户心中的地位。一些品牌做得很好,而另一些则不然。例如,时尚品牌往往非常注重品牌,而科技公司则各不相同。以下是一些关于技术品牌如何在现实世界中发挥作用的指导性例子:
-
苹果:苹果拥有一个从其标志和名称到产品设计再到之前提到的员工培训手册的全面品牌身份。其品牌战略被普遍赞誉为一项非凡出色的成就。一些专家甚至认为,苹果的营销和品牌建设是其成功的关键,而不是其产品。无论如何,苹果的品牌认知度无可否认,并在客户体验的各个方面产生共鸣,因此研究上述品牌要素如何在苹果帝国中普遍存在是值得的。
-
微软:虽然成功的企业是优秀的研究对象,但它们并不总是做得很对。微软的品牌缺乏特色,让人联想到早些年代的品牌,那时的品牌名称更注重功能性而非时尚性。想想通用汽车、国际商业机器公司(IBM)或美国电话电报公司(AT&T)。设计专家唐·诺曼谈到微软时说:“如果你做出每个人都喜爱的产品,你最终会得到一个平淡无奇的产品,每个人都接受但没有人真正喜爱。”同样的话也适用于品牌建设。
-
星巴克:星巴克迅速崛起成为世界上最大的咖啡连锁店之一,这归功于其使命,即提供“尽可能丰富的感官体验。”他们的品牌在其门店中随处可见,从布局到标志,已经深深地印在世界各地咖啡爱好者的心中。
技术公司可能不如服装公司或以品牌为导向的奢侈公司擅长品牌建设,但我们仍然可以从他们的例子中学习。特别是苹果,它展示了许多在其他现代、时尚品牌中发现的成功品牌建设技巧,与“过时”的品牌如微软、惠普或 IBM 形成对比。
最后,让我们记住,你必须从你对品牌、产品和用户的愿景开始。对你品牌提出几个重要问题:
-
质量有多重要?
-
用户体验有多重要?
-
你希望人们如何看待你的产品?
-
你希望与客户建立什么样的关系?
一旦你对你的品牌有了愿景和方向,你就可以在市场上定位自己,并开始推广该品牌。营销是一个庞大的领域,超出了本书的范围,因此建议你联系你网络中的营销人员,阅读基本的营销书籍,或者参加数字营销课程。
摘要
为了让你的应用保持竞争力,尤其是在你拓展到更大的市场时,很明显,它不能仅仅是一个“优秀的应用”。你的业务需要一套全面、周密的策略,以便扩展并保护其在市场中的地位。
如果你想要创建一个持久的应用程序,你必须考虑如何使用之前列出的每一种策略来建立不公平的优势。确定你可以应用的策略,并在产品生命周期的早期尽可能充分利用它们。以下是本章涵盖的策略和策略的简要总结:
-
无形资产:法律保护可以用于防御或进攻。在残酷的商业世界中,你必须为任何可能发生的情况做好准备,特别是如果你的 MVP 证明成功,你的产品开始积累势头。
-
网络和平台效应:连接的用户和商业伙伴不仅仅是客户,它们是随着你的软件增长而增值的资产。利用这一点,并利用这些价值来促进扩张和保护你的领域。
-
利用垂直市场:进入或最好地控制垂直市场,可以使你建立无竞争的交易区域。在垂直市场中建立并维护关系,这样你就可以在特定行业或市场中自由行事。
-
转换成本策略:转换成本可以阻止新用户离开公司,所以尽你所能降低竞争对手的转换成本,同时提高自己的。这样做将提高用户保留率,并使客户更容易进入你的领域。
-
良好的客户支持:在精益方法中,客户被置于核心位置,因此他们也应该在你的商业策略中占据核心位置。良好的客户支持将降低流失率,提升你的声誉,并降低获取成本。
-
品牌的力量:强大的品牌等同于强大的形象。它代表着客户能够与之建立联系并认同的东西,它帮助公司区别于竞争对手。制定有效的品牌策略将使你保持在客户心中的最前沿,建立信任,并培养忠诚感。
尽管这些策略超出了精益方法的范围,但包括它们的理由应该是清晰的:为了成功,一个企业必须务实。企业必须采用实用的商业策略,以帮助他们的产品在现实世界的市场条件下生存。竞争是不可避免的,这就是为什么你必须尽一切可能建立不公平的优势,并为你自己摆好牌局。
第二十章:Flyng 案例研究
Flyng 是一个 iOS 应用程序,它关于约会,但以一种(略微)不同的方式。让我们看看 Flyng 的商业和技术挑战是什么。到目前为止,这本书已经充满了大量的理论。现在,你已经知道了精益创业方法论是什么,以及更具体地说,你可以如何将这种方法应用于移动应用程序开发。
我们看到了许多 iOS、Android 和 Web 应用程序的样本,我们学习了如何在我们早期阶段从用户那里学习,以及如何快速收集反馈,所有这些都无需太多的(技术)努力。
提供各种服务的各种供应商帮助我们做到了这一点。想想看,一个移动后端即服务(MBaaS),比如 Back4App 和 QuickBlox,用户注册工具,比如社交登录和电话号码登录(数字),以及分析服务。
精益创业方法论既不是一种宗教,也不是一个终极目标。绝不!它只是创建具有实际意义和持久性的应用程序的一个好工具。不要浪费你最宝贵的资源(时间!)相反,使用精益方法尽早获取反馈。看看你能否尽早证明你的假设。如果你是对的,就继续前进。如果你的假设被证明是错误的,那么就学习并适应。最好是尽早失败,并构建一个真正有价值且人们真正想要使用的解决方案(一个不同的功能,一个更好的功能,或者另一个应用程序)。
在本书的早期,我承诺给你一些真实世界的例子,现在就是其中一个。这是 Flyng 的案例,这是一个新的社交应用程序,我和我的队友们一起在开发。稍后我会向你介绍他们。
在本章中,我们将涵盖以下主题:
-
调查 Flyng 解决什么问题
-
描述 Flyng MVP 是如何构建的
-
看看我们的 Flyng 假设是什么
-
审查如何衡量用户反馈
-
讨论如何构建 Flyng 的用户基础(鸡生蛋还是蛋生鸡)
Flyng 案例研究总结了你在本书中读到的大部分内容,并涵盖了我们所做的好事和坏事。因此,这个案例研究也成为了团队自身的回顾会议。
在构建我们的 Flyng 最小可行产品(MVP)的过程中,我们已经取得了一些伟大的成就。不出所料,我们也发现了一些需要改进的地方。自从我们开始这个项目以来,我们就一直在使用精益创业方法论,但尽管如此,还有一些事情我们可以做得更好。
正如你将在本章后面读到的那样,我们包含的一个特定功能是基于一个我们没有足够早验证的假设。这个特定的功能几乎没有被使用,但至少在我们发布了许多应用程序版本之前,我们发现了这个问题。除此之外,Flyng 已经取得了成功,并且其用户基础每天都在增长。
这听起来很棒,但 Flyng 是什么?
Flyng 是一个允许你与你个人兴趣相关的学生建立联系的应用。与 Tinder 不同,它不仅仅关于约会。你可以探索诸如冒险、邂逅、关系或派对等类别。除了其他搜索标准外,它还允许你在浏览时指定你确切喜欢的内容。正是这个功能吸引了最多的 Flyng 用户:

该应用还附带其他有趣的功能,例如安全计时器(但这只是一个假设),以及未来的一些有趣游戏。
团队
任何成功应用最重要的成分是团队。它是成功初创企业的关键成分,也是几乎所有风险投资家都感兴趣的事情。当然,Flyng 拥有一个出色的团队。Flyng 团队成员包括:Daniel Guthrie,Mitchell Trulli,以及,并非巧合的是,我(Mike)。
Mitchell Trulli
Mitchell Trulli 负责影响者营销和品牌建设,战略伙伴关系,融资和提案。他拥有金融学 MBA 学位(来自奎尼皮亚克大学),梦想在成功创办一家初创企业后进入风险投资领域。他喜欢旅行和交易,以及夏天在科德角度过。
Daniel Guthrie
Daniel 负责监控增长和数据分析,社交媒体策略,品牌建设,以及运营大使计划。
Danny 和 Mitchell 对初创企业和在科技领域的工作项目充满热情。此外,他们也非常关注大学市场,并学习适应其营销策略。
Mike van Drongelen
Mike 是该应用及其后端的开发者。目前,该应用仅在 iOS 上可用,但 Android 应用很快就会推出。他对用户体验和与应用相关的所有其他事情都感兴趣。Mike 同样也是一个初创企业爱好者,但既然你在读这本书,我想你早已非常了解这一点。
其他贡献者
团队比核心团队更大。有许多其他贡献者和大使!以 Kevin Dalvi 为例。他帮助 Flyng 团队进行用户体验和出色的图形设计。
我们还想要感谢所有我们的测试用户,以及最后但同样重要的是,Flyng 的用户。他们让 Flyng 发展成为现在的样子。如果没有这些人的努力,Flyng 就不会存在。
最小可行产品(MVP)
在 Mitchell 告诉我他的想法后,我非常兴奋,我们很快决定创建我们的第一个最小可行产品(MVP)。从我个人动机的角度来看,我可以告诉你,我一直想创建一个类似 Tinder 风格的应用,而且这个解决方案旨在针对大学,所以我特别感兴趣于这个概念。
让我详细解释一下最后一部分。我的另一个初创企业冒险,Teamspot,是一个在线学习解决方案。这是一个让公司能够在各种学校水平上与学生们相遇的平台,反之亦然。它简化了整个实习的设置和监控过程。
我一直有一个愿景,那就是学习应该是有趣的,而且它远不止是知道和分析事实。它还应该包括社交、协作以及所有创造美好体验的其他方面。如果你剥夺了乐趣,那么学习方面也会停止。而且如果你是初创公司的一员,你应该始终学习和享受乐趣,至少每天一次(甚至可能两次)。
正因如此,我对飞鹰感兴趣。此外,我认为这是一个以精益方式构建应用程序的绝佳机会,这样我就可以将其作为本书的案例研究。这就是你现在读到它的原因。
分布式团队
当米切尔和丹尼尔在美国时,我在荷兰。这并不一定是问题。有一些出色的协作工具可用,而且我们身处不同的时区只需要更多的计划。我的合著者亚当·丹尼斯也在另一个时区。这也很好。
米切尔这样评价我们的分布式团队:
"我们的团队每天使用 Slack 进行沟通;此外,我们预计每周或每两周进行一次 Skype 通话。利用我们拥有的技术,国际工作变得相当容易;此外,迈克对我们的工作时间相当灵活。"
除了 Slack,你还可以使用 BaseCamp 进行团队沟通。这两种解决方案都对分布式和本地团队都适用。
飞鹰的独特卖点
你可能会想知道:“为什么还需要另一个社交/约会应用?飞鹰有什么不同之处?”
当我问米切尔时,他告诉我:
"Tinder 曾被誉为 2017 年第二季度最赚钱的应用。我们认为在线约会市场仍然非常年轻,并且仍在增长。"
为了利用 Tinder(可滑动个人资料)的独特属性,并将其与我们独特的分类方式相结合,我们能够创新这个领域,吸引用户使用我们的应用程序,而不是标准的 Tinder 或 Bumble。
我认为,监控匹配对象以及他们匹配到的类别是我们应用程序最重要的部分。我们的用户将特别挑剔,并期望整个应用程序都围绕这些类别展开。
我还问他为什么飞鹰特别针对大学。米切尔回答说:
"很多人不明白为什么我们针对大学市场,因为它被誉为最难进入的空间之一。我们相信我们对约会应用的独特视角将使我们脱颖而出。此外,我们的过去项目专注于大学市场,我们广泛地了解了如何向他们推广和营销。"
理论上讲,每个企业都有一个(营销)问题和(技术)解决方案组件。我问米切尔,飞鹰想要解决什么问题?
Flyng 解决了人们在当地无法遇到他们想要遇到的人的问题。Flyng 允许他们遇到正在派对、年轻或年长,或者与他们处于相同社交组织的人。这将大大增加他们不打电话而是在现场互动的时间。我们的目标是建立人与人之间的个人联系。
其他社交应用,如 Facebook 和 Snapchat,缺乏有效的发现平台;它们是你在亲自见面后与人沟通的地方。Tinder 和 Flyng 允许你在网上遇到人,这样你就可以在现实生活中与他们互动。
未来,我们计划增加点赞照片、临时分类、基于位置的分类和其他将增加用户参与度和保留度的功能。
我们目前正在努力达到的一个重大里程碑是 40K 月活跃用户(MAU)。一旦我们达到这个水平,凯文将带领米切尔和丹尼尔进行一次旅行,并向我们网络中位于硅谷地区的风险投资家进行路演。
增长用户基础
4 万个月活跃用户听起来并不复杂,但就像每个初创公司一样,Flyng 是从 0 个用户开始的。那么我们是如何让我们的用户基础增长的?
米切尔概述了我们做得相当不错的地方:我们在推出之前就开始了营销。我们希望在 Flyng 推出之前,人们就期待并兴奋地下载这款应用。
这为我们第一天带来了 200-500 个新用户,为我们深入的市场营销策略提供了一个基础。目前,我们使用社交媒体和社交媒体影响者来扩大 Flyng 的用户基础。通过增长黑客策略和与志同道合的组织的合作,我们能够增加下载量并保留用户。
我们最大的挑战是在特定地区增长用户基础。我们的社交增长策略分散,没有像人们希望的那样在特定地理位置上高度关注下载。
约会和配对应用总是在寻找男性和女性之间的良好平衡。最理想的情况是 50/50 平衡,但许多初创公司看到早期采用者往往是男性,这可能是某种原因。对于 Flyng 来说,这似乎也很重要。
米切尔说:我们假设男孩会追求女孩。为了利用这一点,我们主要针对女性进行营销,展示我们的分类将允许她们筛选掉她们不想与之联系的男人,这是其他应用所不允许的。
商业模式
一个令人印象深刻的用户基础可能非常有说服力,但如果我们想让 Flyng 成为一个可持续的业务,我们最好也考虑一下商业模式。
一个空白的商业模式画布正盯着我们。Flyng 的商业模式画布会是什么样子呢?让我们快速迭代画布的所有元素。
客户群体
我们的用户是大学生。目前我们专注于波士顿地区。稍后,我们将扩大到美国,然后最终扩大到全球。
我们的用户并不一定是我们的客户。如果我们知道我们的收入来源,那么我们的客户也可能是广告商,因为他们带来了资金。另一方面,用户通过在应用上花费大量时间为其增加了价值,这是广告商所喜欢的。嗯,有点棘手。目前,让我们将它们两者都添加到画布上。
价值主张
Flyng 提供了什么价值?简而言之,它提供基于类别和故事驱动的针对特定垂直领域(大学)的人与人匹配。关注这一点非常重要。因为我们专注于这个特定的垂直领域,所以我们实际上能够创造价值。通过针对这个特定的利基市场,我们了解用户的需求。我相信你会同意这是一个好的策略,假设你知道 Facebook 的历史。他们不是一开始就关注所有人,而是从关注大学生开始。你的应用可能处于一个完全不同的领域,但从一个相对较小的受众群体或解决一个利基问题开始总是一个好的起点。
客户关系
在线产品,无论是应用还是网站,都会使与客户的联系更加匿名。尽管如此,仍然有方法与他们建立联系,例如通过在 Twitter、Instagram 和 App Store 评论中提供反馈。让用户知道他们的声音被听到是很重要的。
我们还查看 Fabric Answers、Crashlytics 和 iTunesConnect 给我们提供的洞察力。
现在来看特定的客户群体还为时尚早,但当我们扩大规模时,这样做肯定是有意义的。例如,美国的用户和亚洲的用户可能会表现出不同的行为和/或有不同的需求。
渠道
我们(销售)渠道,如前所述,是社交媒体和 App Store。此外,我们使用推送通知消息来通知用户关于应用改进等内容。如果我们的用户基础足够大,我预计我们将针对特定群体来推广特定功能。
收入来源
收入从何而来?当然,收购是一个不错的选择,但现在让我们保持现实。那么,我们的钱将从哪里来?我认为高级功能是一个好主意,但根据米切尔的说法,另一个选择可能是:
在某个类别内的广告,例如在派对类别或赞助类别中放置的啤酒公司的广告。例如,派对类别可能由啤酒公司赞助。其他类别也可能有赞助商。
在应用业务中,达到盈亏平衡点并不困难。正如我们稍后将会看到的,我们的成本将会很低。至于 Flyng 是否会成为一个可持续的业务,这完全是另一个问题。我们将看到未来会带来什么。目前这还不是我们的主要目标。扩大用户基础是我们现在需要做的最重要的事情。
我们在第十七章,货币化和定价策略中看到了这一点。
关键资源
毫无疑问,我们的关键资源是 App Store 以及我们使用的服务,例如 Back4App 托管 Parse Server。我们最宝贵的资源是人力资源:我们的团队和我们的用户。
关键活动
Flyng 的关键活动基本上就是根据共同兴趣匹配人们,并创造一个完美的在线体验。
通过提供这种体验,Flyng 正在增加价值。该应用程序娱乐用户,将人们聚集在一起,在现实生活中享受他们最喜欢做的事情,无论是约会、拥有相同的爱好,还是对相同的体育兴趣。
Flyng 以服务为导向,因此我们在与客户的客户关系上投入了大量资金。我们希望他们知道他们的声音被听到,我们关心他们的体验和反馈。我们使用统计数据来衡量重要的 KPI,如用户转化率、留存率和流失率。
合作伙伴
Flyng 需要像任何其他业务一样拥有合作伙伴。如果我们想让应用程序受到关注,我们需要别人的帮助。社交媒体影响者(如拥有众多粉丝的 Twitter 用户)是我们的合作伙伴。苹果和 App Store 是其中之一。我们的未来广告商和/或购买广告或赞助类别的组织也是我们的合作伙伴。
这就引出了问题:“我们的大使是谁,或者谁可能成为我们的大使?”
这是米切尔给出的答案:为基于约会的社交应用找到品牌大使很困难。一个想法是为每个城市提供一个代码,类似于 Flyng.us/boston,并将报酬分配给当地的影响者。另一个想法是为每个城市创建一个定制代码。
成本结构
我们的应用程序涉及哪些成本?如果不算上我们在 Flyng 上投入的时间,那么只有托管(Back4App)和营销是支出。
平台上的互动越多,对后端的每秒调用次数就越多。托管 Parse Server 的一方,在我们的案例中是 Back4App,提供了一系列计划。每个计划都包含每月的最大请求次数和每秒的最大请求次数。因此,应用程序的用户越多,更重要的是,并发用户越多,我们为托管支付的费用就越多:

我们的营销成本取决于平台和广告的频率。通过仔细测量我们的转化率,我们可以了解我们的支出和新用户数量之间的相关性。
当我们开始运行活动时,我们注意到新用户数量有显著增加。我们还了解到这种效果只持续了很短的时间。前面的图表很好地说明了这一点。
不公平的优势
这个元素出现在样本商业模式画布中,但它包含了一些变体。这可能是 BMC 中最困难的部分。我问米切尔:Flyng 的不公平优势是什么?换句话说:什么阻止了另一个应用构建者复制并推出 Flyng 的概念?
米切尔回答说:由于这个领域已经拥挤着各种主要市场参与者(如 Tinder 和 Bumble)以及大量的小型玩家,对于 Flyng 来说,最重要的是我们与这个领域内的社区/消费者的关系和联系。我们的不公平优势将是我们品牌感知,它能带来更好的联系和约会,这一点得到了用户和我们自己的认可。
太棒了!我们现在已经收集了我们需要的所有信息。如果我们填写 Flyng 的 BMC,它看起来会是这样:

由于书籍的空间有限,以下是画布的正确部分:

获取反馈
因此,我们需要我们商业模式的证据。我们使用什么工具来衡量牵引力、留存率和其他反馈?反馈使我们能够改进应用的功能,并证明我们的假设是对的还是错的。
我们第一次 MVP 的反馈直接来自与用户的互动。
如果用户数量迅速增长,我们需要一些其他工具来获取适当的反馈。
我们从以下来源收集反馈:
-
iTunesConnect 分析数据
-
应用商店评论
-
Fabric 回答,分析数据
-
Fabric 崩溃分析,用于衡量,嗯,崩溃
-
Back4App 数据和统计
-
来自我们测试用户的反馈
这份反馈附带的信息让我们对哪些功能被使用得最多有了很多了解。最重要的是,我们注意到基于类别的浏览技术是我们用户最欣赏的。
未经验证的假设
当我们开始构建 Flyng 时,我们有一些假设,我们的 MVP 证明是正确的。我们有什么完全错误的假设?
米切尔说:通过我们的 MVP 发布,我们能够看到几乎没有任何用户使用我们的安全功能 SAM。遗憾的是,这将会促使我们在未来取消它,也许将其独立成一个项目。

一个僵尸功能
SAM 非常易于使用,或者,嗯,这就是我们以为的。你自己决定吧!
假设你在 Flyng 上遇到了新人。为了安全起见,在你出去约会之前,你使用 SAM 从你的联系簿中选择 1 到 3 个联系人来提醒如果发生任何问题。你开始计时,每 45 分钟你需要检查一次,只是让 Flyng 知道你还安全。当通知出现在你的手机上时,你只需轻触它。如果你没有回应或没有及时回应,你的联系人将通过短信被通知。
只有少数人真正使用 SAM 功能。显然,大学里没有令人毛骨悚然的人(这是另一个假设)。无论如何,我们认为这是一个伟大的概念,但如果没有人使用它,那么我们的用户可能不需要它,或者至少他们不需要在 Flyng 中使用它。
这里唯一的僵尸是一个伟大的想法,它有风险成为活死人的成员:

事实上,反馈和统计数据告诉我们,它几乎没有被使用。我们仍然需要研究人们是否认为这个选项没有用,找不到它,或者认为它对于假设的问题来说太难了。所有这些都需要进一步调查。
目前,我们可以声明,人们想要在约会时有守护者的假设似乎是错误的。就像米切尔说的那样,可能需要将其删除并发展成自己的应用。当然,这个想法假设这个功能试图解决的问题实际上在 Flyng 之外的环境中确实存在。
如果不是呢?那么,这是一个典型的例子,这种浪费本可以通过早期验证来避免。那么,一个更早的 MVP 可能是什么样的呢?也许我们应该尝试通过在线或现实世界的调查来了解女孩(和男孩?)目前在使用约会时面临的问题。
反馈和可操作指标
我们使用的监控工具为我们提供了对我们应用有价值的分析洞察。这些洞察力的挑战是如何将它们转化为可操作的指标。
有一些数字是很好的,但你如何解释它们,使它们成为可操作的指标?哪些 KPI 真正重要?牵引力是一个经常使用的词,但你如何衡量它?如果你认为牵引力是一个定义人们实际使用你应用的程度的数字,那么用户数量是一个有用的数字。或者,是活跃用户数量?活跃用户的定义是什么?或者,新用户数量在这里是重要的数字吗?
要回答这些问题,你必须使事物可衡量,并保持精确。你需要有明确的目标。
假设到年底我们希望拥有 10 万新用户。这是一个明确的目标,只要它是相对现实的,就是一个好的目标。最终,真正的牵引力是通过实际收入来证明的,但在 Flyng 的情况下,这将是以后的事情。
使用相同的工具,我们还可以衡量留存率。有多少用户在一周后、一个月后或一年后仍在使用该应用?

如果留存率低,我们需要做什么来让用户留在应用中?我问米切尔,我们是否可以说目前可用的分析是可操作的指标。我还想知道我们是否需要额外的资源或工具来衡量我们的用户。
米切尔说:“我们目前拥有的分析数据很好地代表了我们所证明的早期市场验证。我们的营销努力一直不稳定;到目前为止,我们连续的广告支出天数最多只有 7 天。
我们经常监控从社交媒体、私信、帖子评论和其他用户互动中获得的反馈,以了解我们的用户应用是否崩溃,他们希望看到哪些功能,等等。
我们收到的最有趣的反馈来自实际使用过该应用并遇到与他们互动的人的用户。他们告诉我们,类别允许他们以不同的方式规划和互动。例如,在派对类别中相遇的人能够在派对上建立联系。”
听到我们最好的反馈来自与用户的直接互动,这很有趣。这不应该是一个真正的惊喜,但重要的是要知道,直接反馈比单纯的分析数据更宝贵:

分割测试
Flyng 的哪些功能可能是分割测试的完美候选人?
米切尔说:测试不同类型的类别对于分割测试来说是非常理想的。例如,为了测试由创建与夏日相关的海滩日类别所引起的接受度和互动,我们可以在我们认为对我们的研究测试具有战略意义的海滨地区创建它。
是的,我认为进行一些 A/B 实验是值得的,不仅是为了应用,也是为了应用商店的列表。由于最近推出了应用商店优化(ASO)技术,包括应用商店分割测试,我很想尝试看看它们是如何工作的,以及它们是否可以帮助我们改进我们的应用。
视野
没有愿景就没有目标,所以我很好奇团队对 Flyng 的雄心壮志。我问米切尔:你认为 Flyng 一年后和三年后的未来会是什么样子?Flyng 会是一个可持续的业务吗?它会赚很多钱吗?它会吸引投资者吗?它是否以其他方式对商业或社会做出贡献?
Flyng 的动态使其成为一个很好的盈利产品。类别卡片可以通过多种方式赞助。首先,一个原始类别可以由一家公司代言。例如,学生运动员类别可以由我们网络中的公司www.thetailgateseason.com赞助。出现在页面顶部附近的公司将收取溢价,而较低位置的公司将具有最佳价值。
也可能有有限的赞助类别。这些类别可以是互动的,以进一步拥抱通过其类别线了解其他个人资料的价值。例如,假设 Marvel 正在寻找宣传一部新的复仇者联盟电影。我们可以运行一个赞助的、有限时间的类别,类似于投票。用户可以选择他们最喜欢的超级英雄,并可以与类似粉丝建立联系。如果实施得当并投入时间,这些广告不会被视为侵扰性,并且会增强用户体验。
在我们的社交聚会应用程序中拥有类别的好处之一是使用它们来区分广告放置的位置。在我们的领域中的传统应用程序中,只有一个巨大的类别。如果 Bud Light 只想向对派对感兴趣并积极参与的人进行广告宣传,这些应用程序就无法满足 Bud Light 的需求。在 Flyng 的派对类别中,我们可以向可能对其产品感兴趣的用户展示广告。广告将具有相关性,这将使用户和 Bud Light 都感到高兴。
技术考虑
由于这本书主要是一本关于精益创业方法的实用指南,我们将探讨 Flyng 技术的亮点。我们无法透露太多,但足以让你有个大致的了解。
该应用程序是为 iOS 平台构建的,但也计划推出 Android 版本。采用 iOS 首先策略的主要原因是因为主要受众是波士顿地区的大学。如果我们开始在欧洲推出,我们可能首先采用 Android 策略。
该应用程序是用 Swift 3.0 构建的,并将未来迁移到 Swift 4。它从位于 Back4App 的 Parse Server 获取数据。此外,它还使用 QuickBlox 进行聊天技术。代码已经以这种方式结构化,使得在一种 mBaaS 和另一种之间切换相对容易。
我们的技术堆栈包括以下内容:
-
Xcode
-
Swift 4.0
-
Back4App、Parse server、PLQ 和 Cloud code
-
Amazon
-
QuickBlox
-
Twillio
-
APNs、徽章、匹配消息和消息
Back4App 上托管的 Parse server
我们在使用 Parse Server 作为后端解决方案时不得不处理一些限制,但另一方面,它也使我们能够快速开发应用程序。这样我们就可以特别关注前端(应用程序)。
这里是一个位于 Back4App 的匹配集合过滤器的示例:

该应用程序已经设置好,以便可以轻松切换到另一个 Parse Server 或甚至是一个定制的后端 API。
实时数据
除了个人资料和媒体数据外,我们还需要为应用程序的聊天功能提供实时数据。
我们曾经使用 parse live queries 进行聊天技术,但我们发现 QuickBlox 是这类事情更值得信赖的服务。对于两个不同的后端解决方案,为单个用户进行身份验证有点困难,但最终完成起来并不真的那么难。
这是 QuickBlox 控制台的示例。该服务支持许多其他功能,但我们只是用它来实现聊天功能:

其他依赖项
我们使用 Twillio 发送用于 SAM 功能的短信。对于入职或特定于登录/注册的过程,我们要求用户使用他们的 Facebook 账户注册。
如果没有 Facebook 账户,Flyng 的入职过程会很困难。你无法在用 Facebook 账户登录之前继续。根据我们在第十一章[774e65d5-5ac0-4ade-9f9e-cffb2a911441.xhtml]“入职和注册”中讨论的内容,这意味着我们在入职方面有一点点高的门槛要克服。
在不了解任何关于应用的情况下,你需要注册,如果你没有 Facebook 账户,你就无法继续。虽然我不想为所有应用推荐这种策略,但对于像 Flyng 这样的约会应用来说,它效果很好。对于这类应用,避免虚假用户和避免不完整数据非常重要。从 Facebook 获取的数据帮助我们个性化应用,在注册后立即显示你的名字和头像。
我们可能还需要提供其他社交登录选项。由于该应用的目标是年轻人,我们可能还需要提供使用 Twitter、Snapchat 或 Instagram 账户注册的方式。
了解我们还做了什么来避免虚假资料也很有趣,那就是使用面部识别技术。使用 iOS SDK,验证一个或多个面部是否出现在上传的图片上相当容易。经过测试,我们发现它还能区分面部与卡通、动物图片和绘画。至少,它可以防止我们拥有显示不相关图像的资料头像,比如壁纸、日落,甚至更糟糕的。
如你所见,我们使用 CocoaPods 添加了一些第三方依赖项,例如 Parse 和 QuickBlox SDK。如你所见,我还使用了 Facebook 和 Crashlytics 作为参考:
target 'flyng' do
use_frameworks!
pod 'Fabric'
pod 'Crashlytics'
pod 'Cartography'
pod 'Parse'
pod 'ParseFacebookUtilsV4'
pod 'ParseLiveQuery'
pod 'JSQMessagesViewController'
pod 'QuickBlox'
查询
数据消耗依赖于几个直接查询,但对于更复杂的需求,已经使用了云代码解决方案。这些云代码解决方案是基于 JavaScript 的,并且与 Parse 服务器提供的 REST API 功能密切相关。
为了简化,它托管在 Back4App 上,但几乎没有阻止我们未来托管一个或多个 Parse 服务器。当然,在这种情况下,我们需要处理推送通知、平衡和扩展以及其他事情,但你应该明白这一点。如果需要立即扩展,它允许我们实现可扩展性。
当你查看应用的 Swift 代码时,你会注意到为客户端定义了许多方法。它们作为协议提供,这使得我们可以在不费太多力气的情况下切换到另一个后端解决方案。
只为了给你一个概念,这里展示了其中一些可用的方法:
import UIKit
protocol RepositoryProtocol {
func authenticate (handler: RepositoryResultDelegate, request: AuthenticateRequest)
...
func getProfile (handler: RepositoryResultDelegate, request: GetMyProfileRequest)
func getCategories (handler: RepositoryResultDelegate, request: GetCategoriesRequest)
func getCandidates (handler: RepositoryResultDelegate, request: GetCandidatesRequest)
func getMatchList (handler:RepositoryResultDelegate , request: GetMatchListRequest)
func pushMessage (handler: RepositoryResultDelegate, request: PushRequest)
...
}
复杂操作
初看之下,似乎很容易判断两个人之间是否有匹配。但对于一个应用来说,这是一个复杂的操作。想象一下,你喜欢一个特定的个人资料。首先,我们需要将这个事实添加到你的浏览历史中,因为你不希望看到你已经看过的个人资料。我们还会跟踪你喜欢的人。稍后,当他们也喜欢你时,这就会导致匹配。我们希望为我们的用户提供尽可能多的匹配,因此我们需要确保你首先看到那些确实喜欢过你的人的个人资料。
如果你喜欢某人,我们需要运行一个查询来告知我们你是否之前也喜欢过这个人。如果是的话,就会添加一个匹配条目,并且我们需要通知你和你的匹配对象。让我们发送一个推送通知来告知你的伴侣,并将我们刚刚创建的匹配结果返回给你以通知你。太好了,有新情况发生了。徽章,出现在应用图标上(在匹配标签页),需要增加。然而,在我们这样做之前,我们需要弄清楚你和你的伴侣各自有多少新的匹配(和消息)。简而言之,这个操作是云代码解决方案的完美候选。
存在于 Parse Server 上的函数将为我们做大量工作。这是有道理的,因为服务器有更多的计算能力,这样我们也能避免从设备向服务器发送太多数据,反之亦然。这就是我们如何保持可扩展性的方式。
从应用的角度来看,这只是一个提供正确数据和消费服务器上云函数产生的结果的问题。例如,以下是调用云函数的方式:
func getCandidates (handler: RepositoryResultDelegate, request: GetCandidatesRequest){
let params =
[
"myId": request.profileId,
"fromAge": myProfile.CriteriaAgeFrom,
"toAge" : myProfile.CriteriaAgeTo,
"gender" : myProfile.CriteriaGender,
"maxDistance" : myProfile.CriteriaMaxDistance,
"category": request.categoryId,
"skip": request.skip,
"limit" : request.limit
]
PFCloud.callFunctionInBackground("getCandidates", withParameters:
params as [NSObject : AnyObject], block: { (object, error) in
...
推送通知
在第十五章“增长吸引力和提高留存率”中,你可以找到更多关于显示推送通知所需实现的信息。对于这个案例研究,了解以下情况很有趣:像 Back4App(还有 Sashido 和其他几个)这样的服务不仅允许你托管 Parse Server,还处理为应用设置推送通知的麻烦。
对于我们的应用,我们使用远程推送通知来显示消息并更新徽章图标。每当有新的匹配或新的消息时,我们都会通知用户。如果这种情况经常发生,留存率就会自然增长。此外,我们还使用本地(计划中的)通知来实现 SAM 安全功能。
崩溃报告
我们在发布每个候选版本之前都会进行测试,但即便如此,在野外使用时仍然可能发生崩溃。如果发生这种情况,Crashlytics 就会提供帮助。它易于实现,并且能为你提供大量关于崩溃的洞察(包括堆栈跟踪):
func application(application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
...
Fabric.with([Answers.self, Crashlytics.self])
在以下示例中,您可以看到崩溃次数是如何自由地下降到一个不可接受的水平。我们定位了问题并发布了新版本。这导致无崩溃用户数量上升,几乎达到 99%甚至更高。几乎不可能让每个人都满意。您的应用程序及其运行的操作系统可能会产生巨大影响。对于 iOS,只有有限数量的不同设备,并且高比例的无崩溃用户当然应该是可能的。此外,大多数设备都将使用 iOS 的最新版本。
注意,这对于 Android 应用程序可能不同。您可以预期您的 Android 应用程序的无崩溃用户比例较低。这是因为有许多不同的设备、版本和操作系统。例如,有带有一个/两个/没有摄像头的设备。有三星或华为版本的 Android 版本,每个版本都略有不同。而且,您需要支持从 Android 版本 4 到版本 8 的情况并不少见。测试每个变体几乎是不可能的。您别无选择,只能专注于前 10 款最受欢迎的设备,并希望它们也能在其他设备上运行良好:

我们还使用 Fabric 来衡量应用程序的使用情况,例如测量在一定时间内注册了多少人:
AnalyticsUtil.logEvent(AnalyticsUtil.eventSignupFacebook)
static func logEvent(event: String){
...
Answers.logCustomEventWithName(event, customAttributes: nil)
}
发布
我们发布了几次版本,许多用户给应用程序评了 5 星。当然,我们也收到了一些负面评论。我们最感兴趣的是这些用户。当你这么想的时候,负面评论者是有价值的,因为他们遇到问题时,他们足够关心应用程序,以至于会向我们报告问题。这里的挑战是将这位愤怒/不满意的客户转变为大使。我们总是可以通过确保我们倾听用户并解决他们遇到的问题来开始这次对话。应用程序中真的有 bug 吗?应用程序中有什么解释不清或不明确的地方?让我们联系用户进行对话,找出答案!

摘要
在本章中,我们提供了一个广泛的案例研究,展示了书中讨论的大部分内容。我们了解了飞行的应用程序,包括我们做得好和不好的地方。我们看到了最初的假设是什么,以及我们如何收集反馈。尽早证明您的假设很重要。正确验证它们也很重要。如果不这样做,可能会导致时间的浪费。这正是我们看到的 SAM 功能发生的情况。也许它只需要一个小转变就能成功,这需要一些新的实验。所有这些也许都可以应用到您的应用程序上。
截至目前,飞龙(Flyng)仍在不断发展。这场冒险仍在进行中,我们每天都在构建、测量和获取反馈。有时这会很艰难;但鉴于团队的积极精神,我们将继续前进。我不知道这次冒险将走向何方,但有一点我可以肯定。无论成功与否,我们都从大量的反馈、奉献,以及,嗯,可能还有一点运气中学习到了很多。
你也可以做到这一点!保持专注。不要经常拖延。每天学习。尽早失败。持续努力。现在,一切取决于你!祝你好运!
附录
阅读书目和参考文献
-
《Azure IoT 开发食谱》 由 Yatish Patil 著
-
《商业模式画布》 由 Alexander Osterwalder 和 Yves Pigneur 著
-
《跨越鸿沟》 由 Geoffrey a Moore 著
-
《客户开发》 由 Steve Blank 著
-
《使用 Docker 和 Jenkins 进行持续交付》 由 Rafał Leszko 著
-
《持续集成、交付和部署》 由 Sander Rossel 著
-
《不要只是掷骰子》 由 Neil Davidson 著
-
《设计模式》 由 Ralph Johnson 著
-
《上瘾:如何构建习惯形成的产品》 由 Nir Eyal 著
-
《实施 Azure 解决方案》 由 Florian Klaffenbach, Jan-Henrik Damaschke, 和 Oliver Michalski 著
-
《Jenkins 2.x 持续集成食谱 - 第三版》 由 Mitesh Soni 和 Alan Mark Berg 著
-
《精益创业》 由 Eric Ries 著
-
《精益用户体验》 由 Jeff Gothelf 和 Josh Seiden 著
-
《精益分析》 由 Alistair Croll 和 Benjamin Yoskovitz 著
-
《精益用户体验:应用精益原则提升用户体验》 由 Jeff Gothelf 与 Josh Seiden (以及 Eric Reis, 系列编辑) 著
-
《学习 DevOps:持续交付更好的软件》 由 Joakim Verona, Michael Duffy, 和 Paul Swartout 著
-
《学习 Microsoft Azure 存储》 由 Mohamed Waly 著
-
《克服团队五大功能失调》 由 Patrick Lencioni 著
-
《运行精益》 由 Ash Maurya 著
-
《Azure 的稳健云集成》 由 Mahindra Morar, Abhishek Kumar, Martin Abbott, Gyanendra Kumar Gautam, James Corbould, 和 Ashish Bhambhani 著
-
《重做》 由 David Heinemeier Hansson 著
-
《扩展精益》 由 Ash Maurya 著
-
《从为什么开始》 由 Simon Sinek 著
-
《创业者的操作手册》 由 Steve Blank 和 Bob Dorf 著
-
《精益创业者》 由 Brant Cooper 和 Patrick Vlaskovits 著
-
《牵引力》 由 Justin Mares 和 Gabriel Weinberg 著
-
《凤凰项目》 由 Gene Kim, Kevin Behr, 和 George Spafford 著
-
《目标:持续改进的过程》 由 Eliyahu M. Goldratt 著
-
《团队的五大功能失调》 由 Patrick Lencioni 著
-
《用户体验要素》 由 Jesse James Garrett 著
-
《启示的四个步骤》 由 Steve Blank 著
-
《用户体验:简易火箭手术》 由 Steve Krug 著
-
《用户体验:别让我思考》 由 Steve Krug 著
-
《用户体验:简单易用》 由 Giles Colborne 著
-
《价值主张设计》 由 Alex Osterwalder, Yves Pigneur, 以及其他人 著



浙公网安备 33010602011771号