faywong 发布的文章

注:本文翻译自保罗·格雷厄姆(Paul Graham)26 年 6 月 10 日应牛津大学的学生社团邀请所做的一次演讲:https://paulgraham.com/earn.html

中文翻译

既然这里显然是“未来首相的俱乐部”(注:牛津辩论社常出英国首相),那我打算跟你们聊聊一件如果能有更多政治家理解就好了的事情:我要告诉你们,人们是如何成为亿万富翁的。我希望这不仅对打算步入政坛的人有用,你们中那些当不上首相的人,也可以去成为亿万富翁。

我之所以了解这个领域,是因为 21 年前,杰西卡(Jessica)和我共同创立了一个叫 Y Combinator(YC)的机构。如果你没听说过 YC,它介于投资公司和创业者学校之间。自 2005 年创办以来,我们已经资助了大约 6500 家公司。

创办一家成功的初创公司是成为亿万富翁最常见的方法,因此在过去的 21 年里,我实际上一直在训练人们如何成为亿万富翁。到目前为止,我们培养的人里大约有 30 位已经做到了,而且还有更多人正在路上。

所以,你可以想象上个月当听到一位美国政治家声称“不可能靠自己赚到十亿美元”时,我是多么震惊。我的感觉就像一个花样滑冰教练听到有人说“不可能做出三周半跳”一样。这当然是可能的。虽然很难,但绝对可能。

当然,她并不是说不可能“变成”亿万富翁(这显然是可能的),也不是在探讨收入与资本利得之间的区别,她不是在谈论会计层面的问题。她的意思是,如果不做坏事、不以某种方式欺诈,你就不可能变得那么富有。

几天后,我和一位我资助过的初创公司创始人聊天。像往常一样,我一见面就问她的月增长率是多少。她说:“上个月 93%。”我向她指出,这意味着她的个人净资产也在以每月 93% 的速度增长。她正在以一种惊人的速度变得富有。然而,她并没有做任何坏事。她的初创公司之所以增长如此之快,完全是因为用户热爱她所构建的产品。

她能从自身的经历中感受到那位政治家有多么错误。她没有剥削任何人。恰恰相反,她的初创公司之所以能如此疯狂地增长,是因为她和联合创始人一直在拼命工作让用户开心,结果用户不断向朋友推荐。而这就带来了指数级增长(Exponential growth)。

那天晚些时候,我在网上传播了她的案例,有人回复说:“拥有几百万资产且每月增长 93%,与成为亿万富翁之间有着天壤之别。”

我猜很多人都会同意这句话。但事实证明,这句话不仅是错的,而且错得极具启发性。

所以,我想请大家帮个忙。请拿出你们的手机,计算一个数字。我知道这看起来有点刻意,但我保证这会对你们有用。我要让你们做一遍我作为投资人最常做的计算,这段经历会让你真正明白初创公司的本质。

如果我们用最保守的方式来解读那句话,假设“几百万”指的是 2000 万,那么她的公司需要增长 500 倍才能让她成为亿万富翁。现在我们来计算一下,以每月 93% 的速度增长,需要多少个月才能增长 500 倍?

我们需要计算以 1.93 为底,500 的对数。最简单的方法是打开 Google 搜索,直接在搜索框里输入:log(500, 1.93)。如果你输对了,得到的答案大约是 9.45。

也就是说,从 2000 万资产出发,保持 93% 的月增长率,只需要 9.5 个月 就能变成亿万富翁。几百万和十亿之间,其实并没有天壤之别。它们之间只隔了九个半月。

现在你知道为什么我每次见到创始人,问的第一件事永远是他们的增长率了吧。

但我不想让人指责我使用不切实际的数字。那我们用一个更保守的增长率,看看每月增长 15% 会发生什么。这个速度一点也不罕见,我经常遇到每月增长 15% 的初创公司。

如果你的收入每月增长 15%,5 年后你会赚多少钱?我们需要计算 1.15 的 60 次方(因为 5 年是 60 个月)。在 Google 里输入:1.15^60。答案大约是 4384。

这意味着在 5 年内,你的初创公司收入将增长 4384 倍。如果你现在每个月赚 1 万美元,5 年后你每个月将赚大约 4400 万美元,也就是年收入 5.26 亿美元。到那个时候,如果你持有创始人通常持有的股份比例,你就是亿万富翁了。

在现实世界中,增长率往往会逐步放缓。一家非常成功的初创公司可能在第一年增长超过 15%,而在第五年低于 15%。但最终你到达的目标位置是差不多的。如果你在 20 岁出头开始创业,30 岁时成为亿万富翁是完全可能的。虽然很难,但绝对可能。

我之所以想让你们亲自动手计算,是因为只有这样你才能真正体会到人们为什么去创业。指数级增长就像魔法一样,它能创造出看似不可能的结果。 这也是为什么有些政治家不信任它的原因。他们不懂指数增长的数学逻辑,所以当看到别人变得在他们眼里“不可能”这么富有的时候,就主观认为这其中一定有欺诈。

但现在,通过亲自动手算账,你至少明白了要成为亿万富翁并不需要欺诈。你亲眼看到,这个公式里只有两个数字:增长率,以及 增长持续的时间。如果说不作弊就不可能赚到十亿,那么这两个数字里哪一个是靠作弊实现的?

在不作弊的情况下达到每月 15% 的增长,这绝对不是不可能,初创公司经常做到。而你能在这个速度上维持多久,取决于市场规模的大小。显然,要想增长 4000 倍,市场就必须存在至少 4000 倍的潜在需求。但你需要的也就只有这些了。试问,你怎么可能通过欺诈来扩大整个市场的规模呢?

如果你只是打算当个首相,你现在可以不用听了。我们已经证明了靠自己赚到十亿美元是可能的。因为它只取决于两个数字:一个是初创公司在不作弊的情况下经常能达到的增长率,另一个是作弊根本无法改变的市场规模。

但如果你真的想成为亿万富翁,我们应该更深入地探讨。特别是第一个数字:增长率。要实现每个月持续的增长,你必须做出非常好的东西,好到人们会主动告诉他们的朋友。事实上,这也是为什么我总是先问创始人增长率的另一个原因:它能直接反映出他们是否做对了产品。

那么,你到底该如何做出一个好到让用户向朋友推荐的产品呢?市场经济的残酷之处,也是美妙之处,在于你很难去凭空创造一个客户需要但尚未拥有的东西。一旦某个可以被满足的新需求被发现,人们就会一拥而上。因此,你必须发现一个别人还不知道的需求。

怎么做到这一点?通过自己去切身体会这种需求。

你还年轻,年轻的创始人通常应该做他们自己想要的东西。你还没有足够的经验去了解其他人需要什么。但与此同时,你自身的需求其实蕴含着极其独特的价值,因为你的需求预测了未来的需求。 你正处于人们开始使用新事物的年纪。你和你的朋友现在开始用的东西,十年后所有人都会用。既然你对他人需求的直觉通常很不准,而你自身的需求却是一个极具价值的信号,那么你通常应该倾听后一个信号:做你和你朋友想要的东西。

做你和朋友想要的东西并不意味着你必须做一个大众消费品。也许你和你的朋友是分子生物学家,发现现在可以用 DNA 做一些很酷但被其他人忽略的事情;也许你和你的朋友沉迷于无人机。这个想法最初不需要有广泛的吸引力,它真的只需要吸引你和你的朋友就行。

不要担心第二个数字——市场规模。因为你预测了未来的需求,市场自己会成长。而且你总能顺理成章地扩张到邻近的市场。你需要的只是在“未被满足的需求”这片领土上建立一个滩头阵地,并以此为据点向外扩张。

你如何获得这样一个点子?答案触及了初创公司最反直觉的特征之一。寻找绝佳创业点子的方法,恰恰是“不要去寻找创业点子”。 如果你有意识地去寻找创业点子,你会变得过于保守。你会主动砍掉那些“异类”。因为最顶级的创业点子在刚开始听起来往往非常愚蠢、毫无意义,如果你带着功利心去寻找,你第一眼就会拒绝它们。而这正是它们之前没有被别人发现的原因。

想想苹果、Facebook 或 Airbnb 在刚开始时看起来是多么糟糕的主意。能有多少人会想要属于自己的电脑?一家公司怎么可能靠让大学生在网上互相窥探隐私来赚钱?谁会愿意花钱睡在别人家地板的气垫床(Airbed)上?我们现在看到了这些想法的结局,所以很容易去“事后诸葛亮”地改写历史,但我清晰地记得,Facebook 和 Airbnb 刚出现时听起来有多么不靠谱。我们当时资助了 Airbnb,甚至当时连我们自己都觉得这个主意很烂。我们之所以资助他们,纯粹是因为我们喜欢这几位创始人。

那么,如何在不刻意寻找的情况下发现创业点子呢?通过和你的朋友一起做一些好玩的项目(Projects)。 这才是最伟大的初创公司的诞生之地。它们最初甚至根本没想过要成为一家公司,只是因为人们觉得“这东西太酷了”所以动手做出来的。苹果、谷歌、Facebook 全是这样开始的,没有一个是奔着开公司去的。

这种方法之所以奏效,原因还是我前面提到的:你在预测未来的需求。所以,如果你只是凭兴趣去做一些你觉得很酷的奇奇怪怪的东西,这些东西实际上绝对不是随机的。

这是人类潜意识比显意识知道得更多的典型案例之一。任何在你的直觉里真正觉得“做出来会很酷”的东西,都有很高的概率能演变成一个伟大的创业点子,无论它听起来多么荒诞不经。在我们 21 年前(2006年)资助的项目里,不可能有比 Justin.TV 听起来更荒诞的公司了:它当时只有一个人(Justin Kan),在脑袋侧面绑了一个摄像头,每天 24 小时直播自己身上发生的一切。但这家公司最终发展得非常好。事实上你可能听过它,只不过它后来改名了,叫 Twitch。

创办一家成功初创公司的核心在于,你要极其深刻地理解某一个用户群体,从而能分毫不差地做出他们想要的东西。如果你年轻,你可以、也应该利用这个诀窍:为你自己做东西。你了解你自己。但这只是更普适的规则的一个特例。只有极其深刻地理解用户,你才能做出他们热爱到忍不住推荐给朋友的产品;而只有这样,你才能获得让初创公司真正成功所需的指数级增长。

在这个世界上,想要变富有还有其他途径,其中有些确实需要去剥削和压榨他人。但创业是实现巨额财富最常见的方式,而如果你想创业成功,其核心秘诀不是剥削,而是共情(Empathy)。 用户真正想要什么?你做点什么能让他们的生活发生巨大的、戏剧性的改善?这种强烈的共情能力,正是我们在创始人身上寻找的特质,也是我们在被录取的创始人身上重点培养的特质。

在你的社会中,人们是如何变富有的,这是理解这个社会最重要的事情之一。你不能让自己的认知被意识形态、电影或者几个世纪前的历史教条所左右。你必须看看眼前的世界,看看现在它究竟是如何发生的。如果你自己想成为富翁,你自然会被迫去理解;所以我不太担心你们。我真正担心的是未来的首相们。你们需要记住今天的演讲。因此,我为你们把核心思想总结如下:

决定一家初创公司能做多大、从而让创始人有多富有的,只有两个数字:增长率,以及 增长持续的时间。你通过做出让用户喜爱到主动推荐的产品来获得第一个数字;你通过身处一个巨大的市场来获得第二个数字。如果你能以指数级的速度在一个大市场中成长,你的公司就会变得极具价值,而作为股东的你就会变得富有。在这个过程中,你不仅不需要去作弊,相反,只要你源源不断地让客户感到快乐,这一切就会自动发生。

💡 核心思想梳理(Summary of Core Ideas)

保罗·格雷厄姆在这篇最新的演讲稿中,用极其精简的数学和商业逻辑,反驳了“不靠欺诈无法赚到十亿”的传统政治/社会意识形态。其核心论点和干货可以梳理为以下四大支柱:

  1. 财富创造的“两因子”数学公式

格雷厄姆指出,在现代社会中,通过创业合法赚取巨额财富并不神秘,它完全由一个简单的数学模型决定,不涉及任何道德原罪:

$
创业财富
=
月增长率
×
增长持续时间(市场规模)
创业财富=月增长率×增长持续时间(市场规模)$

指数增长的魔力: 哪怕从几百万的微小身家开始,只要能保持高月增长率(如YC常见的 15% - 93%),通过 Google 搜索栏的对数和幂函数计算(如
1.15
60

4384
1.15
60
≈4384 倍),在 5 到 10 年内就能通过复利效应自动滚成十亿美元。许多人对财富的偏见,本质上是因为人类大脑对“指数增长”缺乏直观的数学理解。

  1. 增长的唯一驱动力:用户共情而非剥削

政治家常认为巨富意味着剥削,而格雷厄姆指出,初创公司的增长模型恰恰相反:

增长来自推荐: 能够保持每个月 15% 以上高增长的唯一秘诀,是产品好到让用户感动,从而发生自发的“口碑传播”(Word of Mouth)。
共情(Empathy)是核心: 创业不是掠夺,而是极致的利他与共情——深入洞察某一类人的痛苦,做出能戏剧性改善他们生活的工具。

  1. 如何获得最顶级的创业点子?

不要功利地去“寻找”点子: 带着框框去想点子会让你陷入保守,从而主动放弃那些听起来很蠢、很边缘的“异类点子”。而历史上伟大的公司(如 Apple、Facebook、Airbnb、Twitch)在 Version 1.0 时,听起来都极其荒谬和失败。
和朋友一起做“酷的项目”(Build Cool Stuff): 最好的点子往往起源于几个聪明人聚在一起,不以开公司为目的、纯粹为了好玩而做出来的玩具。

  1. 年轻创始人的“特权外挂”

年轻人缺乏商业经验,无法预测大众或传统企业的需求,但这恰恰是他们的优势:

年轻人的需求预言了未来: 年轻创始人只需要“为自己和朋友解决问题”。因为二十岁左右的年轻人是新技术的先锋消费者,你和身边的极客朋友今天在玩的酷东西,往往就是十年后全世界都在用的主流产品。你自身的需求,就是最精准的未来市场预测器。

最近发现客户端中android4.3上GS4手机上的WebApp应用特别容易crash。分析了源代码之后发现,在ActivityThread中回收内存时会调用EGLImpl里边去,回收RenderThread,进而调用到计算CPU FPS的逻辑,进而crash:

```bash
java.lang.Error: signal 11 (Address not mapped to object) at address 0xbe59dff0 [at libPowerStretch.so:0x2d4c (_ZN11LucidConfig13calcTargetFPSEi+0x1b)]

at system.lib.libPowerStretch_so.0x2d4c(LucidConfig::calcTargetFPS(int):0x1b:0)

at system.lib.libPowerStretch_so.0x2f23(LucidConfig::isLucidActive(bool):0x86:0)
```

因为在问题出在系统层而android应用回收内存这个message是ActivityManager发出,为正常且必要的行为,无法规避。最终选择如下方式将其绕过:

```java
public class H5WebViewRenderPolicy {
public static boolean shouldDisableHardwareRenderInLayer() {
// case 1: samsung GS4 on android 4.3 is know to cause crashes at libPowerStretch.so:0x2d4c
// use GT-I95xx to match more GS4 series devices though GT-I9500 is the typical device
final boolean isSamsungGs4 = android.os.Build.MODEL != null && android.os.Build.MODEL.contains("GT-I95") && android.os.Build.MANUFACTURER != null && android.os.Build.MANUFACTURER.equals("samsung");
final boolean isJbMr2 = Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR2;
if (isSamsungGs4 && isJbMr2) {
return true;
}

return false;
}
}
```
以上定义一个渲染策略类(方便以后维护),针对GS4 + android 4.3这种组合在WebView layer层面关闭硬件加速(这样就不会存在RenderThread,自然也就没法触发上文的crash)。

之后在自定义WebView中利用上以上渲染策略类:

```java
final boolean meetApiLevel11 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
if (H5WebViewRenderPolicy.shouldDisableHardwareRenderInLayer() && meetApiLevel11) {
final View underlyingWebView = webView.getUnderlyingWebView();
if (underlyingWebView != null && webView.getType().equals(WebViewType.SYSTEM_BUILD_IN)) {
try {
underlyingWebView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
} catch (Exception globalException) {
globalException.printStackTrace();
}
}
}
```

更新 2015/2/1
-------------------------------------------------------------
该现象表现在多款三星制造的搭载android 4.3系统的手机上,不仅限于GS4

异常的堆栈如下:

```java
java.lang.IllegalArgumentException: bad parameter
at org.apache.http.client.utils.URLEncodedUtils.parse(URLEncodedUtils.java:139)
at org.apache.http.client.utils.URLEncodedUtils.parse(URLEncodedUtils.java:76)
at android.webkit.AccessibilityInjector.getAxsUrlParameterValue(AccessibilityInjector.java:412)
at android.webkit.AccessibilityInjector.shouldInjectJavaScript(AccessibilityInjector.java:327)
at android.webkit.AccessibilityInjector.onPageFinished(AccessibilityInjector.java:286)
at android.webkit.WebViewClassic.onPageFinished(WebViewClassic.java:4088)
at android.webkit.CallbackProxy.handleMessage(CallbackProxy.java:332)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4829)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:608)
at dalvik.system.NativeStart.main(Native Method)
```
相关的google code android project里边的issue中论述如下:

"
A customer of mine running 4.1.2 just informed me that the issue is still
present! After this issue crashes my app, I have to pop up a dialog
telling them to disable all accessibility services.
Worst user experience ever, but what else can I do.
......
Fixed in an internal build, to be released in the next major release.
......
The bug doesn't occur here in 4.2.1 (Galaxy Nexus, JOP40D).
"

这属于android中最常见的TransactionTooLargeException的后果表现之一。

该问题较多出现在使用PackageManager查询系统的应用的信息,通过Intent来过滤匹配目标应用组件(android四大组件)时,典型堆栈如下:

```java
java.lang.RuntimeException: Package manager has died
at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:78)

......
Caused by: android.os.TransactionTooLargeException
at android.os.BinderProxy.transact(Native Method)
at android.content.pm.IPackageManager$Stub$Proxy.getPackageInfo(IPackageManager.java:1393)
at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:73)
... 17 more
android.os.TransactionTooLargeException
at android.os.BinderProxy.transact(Native Method)
at android.content.pm.IPackageManager$Stub$Proxy.getPackageInfo(IPackageManager.java:1393)
at android.app.ApplicationPackageManager.getPackageInfo(ApplicationPackageManager.java:73)

```
这是Java层的堆栈,原始抛出异常的地方在于文件frameworks/base/core/jni/android_util_Binder.cpp:

```c
case FAILED_TRANSACTION:
LOGE("!!! FAILED BINDER TRANSACTION !!!");
// TransactionTooLargeException is a checked exception, only throw from certain methods.
// FIXME: Transaction too large is the most common reason for FAILED_TRANSACTION
// but it is not the only one. The Binder driver can return BR_FAILED_REPLY
// for other reasons also, such as if the transaction is malformed or
// refers to an FD that has been closed. We should change the driver
// to enable us to distinguish these cases in the future.
jniThrowException(env, canThrowRemoteException
? "android/os/TransactionTooLargeException"
: "java/lang/RuntimeException", NULL);
break;
```
该FAILED_TRANSACTION错误码定义于:
/bionic/libc/kernel/common/linux/binder.h中的BR_FAILED_REPLY

```c
enum BinderDriverReturnProtocol {
BR_ERROR = _IOR_BAD('r', 0, int),

BR_OK = _IO('r', 1),

BR_TRANSACTION = _IOR_BAD('r', 2, struct binder_transaction_data),
BR_REPLY = _IOR_BAD('r', 3, struct binder_transaction_data),

BR_ACQUIRE_RESULT = _IOR_BAD('r', 4, int),

BR_DEAD_REPLY = _IO('r', 5),

BR_TRANSACTION_COMPLETE = _IO('r', 6),

BR_INCREFS = _IOR_BAD('r', 7, struct binder_ptr_cookie),
BR_ACQUIRE = _IOR_BAD('r', 8, struct binder_ptr_cookie),
BR_RELEASE = _IOR_BAD('r', 9, struct binder_ptr_cookie),
BR_DECREFS = _IOR_BAD('r', 10, struct binder_ptr_cookie),

BR_ATTEMPT_ACQUIRE = _IOR_BAD('r', 11, struct binder_pri_ptr_cookie),

BR_NOOP = _IO('r', 12),

BR_SPAWN_LOOPER = _IO('r', 13),

BR_FINISHED = _IO('r', 14),

BR_DEAD_BINDER = _IOR_BAD('r', 15, void *),

BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR_BAD('r', 16, void *),

BR_FAILED_REPLY = _IO('r', 17),

};
```
其原因总结如下,首先Android系统对于Binder IPC每进程的事务buffer上限是1M(为所有Binder事务共享,且不区分目标系统的ram配置等因素),在通过PackageManager中获取系统内应用时,比如应用的Icon是个bitmap,且不同应用所制作Icon的品质(像素数)上差异很大。会占用大量内存导致Binder事务内存超过上限。

Binder事务buffer的尺寸定义在ProcessState.cpp:

```c
#define BINDER_VM_SIZE((1 * 1024 * 1024) - (4096 * 2))
......
ProcessState::ProcessState(): mDriverFD(open_driver()), mVMStart(MAP_FAILED), mManagesContexts(false), mBinderContextCheckFunc(NULL), mBinderContextUserData(NULL), mThreadPoolStarted(false), mThreadPoolSeq(1) {
if (mDriverFD >= 0) {
// XXX Ideally, there should be a specific define for whether we
// have mmap (or whether we could possibly have the kernel module
// availabla).
#
if !defined(HAVE_WIN32_IPC)
// mmap the binder, providing a chunk of virtual address space to receive transactions.
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
// *sigh*
LOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
close(mDriverFD);
mDriverFD = -1;
}#
else
mDriverFD = -1;#
endif
}

LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating.");
}
```
App icon对应的数据模型如下:

```java
class AppInfo {

......

private BitmapDrawable icon

......

}
```
该问题是android系统的限制,只能通过上层来捕获该异常来绕过。当然也不仅限于PackageManager,其他系统服务,应用间的Binder调用也可以带来这一问题。

最后的最后,由于在c++向java层抛出这个异常的场景有多种(见上边c++代码中“FAILED_TRANSACTION”处的注释),所以当你收到了TransactionTooLargeException的时候,不意味着真正的Transaction is Too Large。

最近踩了一个坑,有个非全屏的dialog遮住我的WebApp容器时,WebApp容器中JS代码操纵dom对象显示文本(input框中)巨慢(俗话描述就是“软键盘中输入了字,但是上屏很慢”)。

debug了一天之后发现。在WebView的onPause方法调用后,其内部JS引擎执行JS代码会慢好几倍。所以是否需要跟随Activity的生命周期调用onPause方法需要根据应用场景来区分:

若是应用中严格依赖JS做一些比较紧要的事情,则不应该onPause WebView。否则应该onPause WebView以释放一部分系统资源。