《独立开发者的商业指南·资本与退出》4.2 买方如何看独立开发者资产

买方在尽调里反复问的只有五件事:收入可预测性、客户集中度、创始人依赖、技术债与合规瑕疵。本节用 Tidecast、Nord 与 LedgerLite 各暴露一项,并把五项关注写成折价模型:创始人依赖单独就能压价 20%,五项合并后 LedgerLite 从 768,768 美元降到 561,969 美元。

以下情境为教学假设,人物与数字不代表经核实的真实案例。

卖方看自己的生意,看到的是一段经历:做了多久、解决了什么问题、用户怎么反馈。买方看到的是一组可验证的风险:收入明年还在不在、客户会不会走、创始人离开后谁能接手、代码能不能维护、授权和合规有没有硬伤。同一份资产,在两种视角下不是同一个价格。买方不是故意挑毛病,他是在用自己的钱为不确定的未来定价。

这一节把买方的视角拆成五个问题,每个问题对应一类证据和一种折价方式,再用三个案例各暴露一项:Tidecast 暴露收入可预测性,Nord 暴露客户集中度,LedgerLite 暴露创始人依赖。最后把五个问题合并成一个可计算的折价模型,用 LedgerLite 的 768,768 美元锚算出 561,969 美元的调整价,并说明 20% 的创始人依赖折扣是怎么来的。

五个问题不是并列的。收入可预测性和客户集中度决定「钱能不能继续进来」,创始人依赖和技术债决定「生意能不能被接手」,合规瑕疵决定「接手后会不会突然赔一笔」。买方通常按这个顺序问:先看收入,再看人,再看代码和文件。顺序反了,会在还没确认收入可持续时就开始谈技术细节,浪费双方时间。

五个问题,五张证据

关注点买方在问什么需要的证据典型折价方式案例反例
收入可预测性明年的收入能不能重复按月收入、流失率、续约率、季节性、渠道分布用更低的倍数或更高的折现率Tidecast:买断制、Q4 占 38%、Steam 占 80%
客户集中度少数客户走了会不会伤筋动骨前 5 大客户占比、合同期限、转介绍来源对集中部分打折,或要求 earn-outNord:前 3 家 48%、转介绍 55%
创始人依赖创始人离开后业务会不会停文档、账号权限、值班安排、交接计划扣替换成本,或要求创始人留任LedgerLite:260 家客户、一人负责工程与支持
技术债代码能不能被第二个人维护代码审计、测试覆盖、部署流程、依赖清单扣修复成本,或放入托管Tidecast:14 个月一人开发,平台 SDK 绑定
合规瑕疵有没有会突然变成账单的硬伤授权链、隐私政策、DPA、保险、主体资质交割前 cure,或赔偿上限、专项托管Tidecast:音乐买断授权不得转授权

这张表的每一行都能变成一个问题、一份材料和一笔钱。买方不会因为「感觉不错」就放弃证据;他会在数据室里找对应的文件,找不到就按最坏情况假设。卖方觉得「大家都知道」的事情,在买方眼里等于没有发生。折价不是因为买方苛刻,而是因为无法验证的风险只能用价格来覆盖。

收入可预测性:Tidecast 的买断制

Tidecast 的年净得是 138,171 美元,年销 9,600 份,标价 19.99 美元,Steam 占销量 80%,Q4 占全年销量 38%,12 月一个月 2,400 份,是月均 800 份的 3 倍。买方看到这组数字,第一反应不是「年收入 138,171 美元」,而是「如果今年 Q4 少卖 20%,年收入会掉多少」。Q4 占 38%,少 20% 就是全年少 7.6%,约 10,500 美元;如果 Steam 同时调整推荐算法,跌幅会更大。

买断制游戏的收入不是合同收入,而是一次次销售的集合。买方会要求按月、按渠道、按退款率拆开看,还会问:Wishlist 转化率是多少、首发窗口占多少、有没有续作或 DLC 计划、平台分成和退款政策有没有变化。它不是在否定游戏的质量,而是在判断「明年的 138,171 美元有多少能重复」。对订阅生意,买方问的是流失率;对买断制游戏,买方问的是「下一款什么时候出」。没有下一款,收入曲线就是一条已经开始的衰减曲线。

这解释了为什么 Tidecast 的合理锚是 1.8× 收入,而不是 LedgerLite 的 3.2× ARR。倍数差不是游戏生意「低一等」,而是收入的可重复性不同:订阅收入有合同和续费,买断收入依赖每一次新销售。买方愿意为可重复的收入付更高的倍数,因为他在买未来;他为一次性收入付更低的倍数,因为他在买库存。

客户集中度:Nord 的前三家客户

Nord Studio 年收入 154,320 美元,咨询服务占 72.7%,前 3 家客户占 48%,转介绍占 55%。这三个数字放在一起,买方会看到一个高度依赖少数关系的生意:近一半收入来自三家公司,超过一半的新客户来自现有关系,而咨询合同大多按项目签、按验收付款。买方会问:这三家客户的合同还有多久、续约率是多少、如果最大的客户换采购负责人,收入会怎样、转介绍是书面协议还是口头默契。

客户集中度本身不是罪。早期服务生意几乎必然集中,问题在于集中度有没有被合同和流程接住。如果前 3 家客户有多年合同、明确续约条款、服务已经产品化,买方可以把集中度当成「深耕细分市场」的证据;如果客户关系挂在合伙人个人身上、没有书面转介绍协议、交付物归属不清,买方就会把 48% 的收入当成高风险收入,要求打折或 earn-out。Nord 的 4.5× SDE 标准锚被下调到 3.0× SDE = 102,960 美元,服务收入占 72.7% 和两位合伙人依赖是主要原因,客户集中度是同一件事的另一面。

买方处理集中度的方式通常不是「一刀切打五折」,而是分层:对前 3 家客户对应的收入用更低倍数,对分散的订阅收入用正常倍数。如果前 3 家占 48%,买方可能只对这部分收入打 30%–50% 的折扣,而不是对全部收入打折。这样算出来的价格比「整体打五折」高,但比「完全不折」低。卖方要做的不是否认集中度,而是把客户关系从「合伙人的关系」变成「公司的合同和流程」,让买方能看到续约的证据。

创始人依赖:LedgerLite 的一人公司

LedgerLite 有 260 家付费客户、ARR 240,240 美元、毛利率 84.2%,数字看起来像一台健康的订阅机器。但买方翻开组织架构,看到的是一个人:创始人写代码、做支持、谈销售、处理账单,外包只负责零散工作。买方会问:如果创始人明天不能工作,服务能撑几天、谁能部署、谁能回复工单、谁能处理退款和合规请求、代码和账号的权限在谁手里。这些问题的答案,决定买方是在买一门生意,还是在买一份需要创始人继续上班的工作。

创始人依赖的折价不是情绪化的。买方会算替换成本:招一个能接手全栈的工程师要多久、要多少钱、前三个月能承担多少工作、需要多少文档和交接、如果找不到人要不要让创始人留任。以 LedgerLite 为例,假设替换一名全栈工程师的年成本是 80,000–120,000 美元,招聘和 ramp-up 需要 3–6 个月,交接期还要创始人投入 20%–30% 的时间;这些成本加在一起,足以让买方在 768,768 美元的锚上要求两位数的折扣。下一节会把 20% 的折扣算出来。

创始人依赖也不是只能折价。卖方可以提前把「人」变成「系统」:写运行手册、把部署做成一条命令、把支持问题分成可路由的类别、把账号权限交给多人、找一名兼职运维或支持。这些动作不会让创始人变得不重要,但会让买方相信「换一个人也能转」。折价的大小,取决于买方相信的是「创始人必须留下」还是「创始人可以交接」。

技术债:三个人都绕不开的代码审计

三个案例都没有专门的工程团队,技术债的表现不同,买方的问法相同:这段代码第二个人能不能维护。Tidecast 是 14 个月的一人开发,代码、美术、音乐和平台 SDK 绑在一起,买方会问哪些模块依赖平台接口、升级平台 SDK 要多久、有没有自动化构建和存档兼容测试。LedgerLite 是一人 SaaS,260 家客户共用一套代码,买方会问测试覆盖、数据库迁移、支付回调、权限模型和备份恢复。Nord 是服务加产品混合,买方会问客户定制代码和产品代码有没有分开、交付物归属是否清晰、复用资产能不能从客户项目里拆出来。

技术债的折价方式通常是「修复成本 + 风险溢价」,而不是按代码行数算。买方会请第三方做代码审计,给出一个修复清单和估算工时,再把工时折算成钱。如果技术债集中在核心路径,买方可能要求放入托管或设置赔偿上限;如果技术债只是工具链老旧,买方可能只在价格上做小幅调整。对独立开发者,最容易被低估的技术债不是「代码写得丑」,而是「只有一个人知道怎么部署、怎么回滚、怎么恢复数据」。

合规瑕疵:Tidecast 的音乐授权

Tidecast 的 IP 组合包括代码、美术、音乐和商标,其中音乐是买断授权,不得转授权。买方在尽调时会问:这份授权能不能随资产一起转、授权方是否同意控制权变更、如果买方把游戏移植到新平台,授权覆盖不覆盖、如果原授权方破产,权利还在不在。如果答案是否定的,买方要么在交割前重新谈授权,要么把这块资产从交易里剔除,要么设置专项托管。合规瑕疵的特点是「二值」:能 cure 就是交割条件,不能 cure 就是价格调整或退出。

LedgerLite 在合规上相对干净:企业订阅协议、DPA、网络安全险 1,000,000 美元都有书面落点。这不代表它没有合规风险,而是风险可以被第三方复核:数据怎么处理、泄露怎么通知、赔偿上限在哪里、保险赔多少。Nord 的合规瑕疵不在隐私,而在治理:两位合伙人各 50%、无期权池、无书面退出条款,买方会问「如果一位合伙人不同意出售,交易还能不能完成」。合规问题不总是法律问题,有时是治理结构问题;买方买的不是一份合规证书,而是一个能完成交割的结构。

创始人依赖如何压价

把五个问题变成价格,需要一个可复算的模型。模型不需要预测真实买方的心理,只需要把「问题有多严重」和「这个问题最多值多少折扣」分开。前者是 severity,用 0–100% 表示;后者是权重,用基点表示。两者相乘得到每个问题的折扣贡献,五项相加得到总折扣,再设一个上限,防止折扣超过买方的承受范围。

先看创始人依赖。把「创始人完全不可替代」设为 severity 100%,权重设为 20%,那么单独这一项就贡献 20% 的折扣。LedgerLite 的锚是 768,768 美元,20% 折扣是 153,754 美元,调整价是 615,014 美元。这个数字的含义不是「买方一定会压 20%」,而是「如果创始人依赖是唯一问题,且严重程度拉满,买方在价格上需要看到 20% 的安全垫才会继续谈」。真实交易里,买方可能用留任协议、earn-out 或托管替代一部分折扣,但经济逻辑相同:创始人越难替代,卖方越要用价格或时间来补偿。

关注点LedgerLite 的 severity权重上限折扣贡献
收入可预测性25%8%2.0%
客户集中度30%8%2.4%
创始人依赖100%20%20.0%
技术债30%5%1.5%
合规瑕疵20%5%1.0%
合计46% 上限26.9%

五项合并后,LedgerLite 的总折扣是 26.9%,调整价是 768,768 × (1 − 26.9%) = 561,969 美元,折扣金额 206,799 美元。计算过程是:2.0% + 2.4% + 20.0% + 1.5% + 1.0% = 26.9%;768,768 × 26.9% = 206,798.6,四舍五入 206,799;768,768 − 206,799 = 561,969。这个价格仍然高于个人买家的 360,360 美元,也高于财务买方的 648,648 美元打 26.9% 后的 474,162 美元;它说明创始人依赖虽然重,但没有把 LedgerLite 打到「只能卖给个人」的区间。

模型里的权重是教学假设,不是行业标准。收入可预测性和客户集中度各 8%,创始人依赖 20%,技术债和合规各 5%,合计上限 46%,再设 40% 的总折扣上限。上限的作用是防止五项同时拉满时算出 46% 的折扣——现实中,买方在折扣超过 40% 时通常不会继续压价,而是直接放弃或要求重组交易。代码会返回「是否触顶」,让读者知道这个价格是模型算出来的,还是被上限截断的。

三案例的折价对照

把同一套权重套到三个案例,得到不同的折扣结构。三个案例的锚不同:LedgerLite 用 3.2× ARR = 768,768 美元,Tidecast 用 1.8× 收入 = 248,708 美元,Nord 用已经下调过的 3.0× SDE = 102,960 美元。Severity 是教学设定,用来展示「同样五个问题,在不同生意里重量不同」。

案例锚最高贡献项总折扣调整价
LedgerLite768,768创始人依赖 20.0%26.9%561,969
Tidecast248,708创始人依赖 18.0%32.7%167,380
Nord102,960创始人依赖 16.0%31.5%70,528

Tidecast 的总折扣 32.7% 高于 LedgerLite,主要因为五项 severity 分别是 80%、60%、90%、30%、40%:买断制加 Steam 80% 让收入的可重复性成为最大问题,音乐授权不得转授权又增加一层合规折价。Nord 的总折扣 31.5%,五项 severity 是 60%、90%、80%、40%、30%;客户集中度贡献 7.2%,是第二高项,仅次于创始人依赖的 16%。LedgerLite 的总折扣最低,但绝对折扣金额最大:206,799 美元,因为它的锚最大。百分比和金额要分开看,否则会误判「谁的资产更差」。

三个案例的最高贡献项都是创始人依赖,这不是巧合。独立开发者的资产天然与创始人绑定:一人公司没有第二个人能接手,两人公司少一个人就少一半产能。买方的第一反应不是「这家公司有什么」,而是「创始人走了还剩什么」。把创始人依赖从 100% 降到 50%,LedgerLite 的总折扣会从 26.9% 降到 16.9%,调整价从 561,969 美元升到 638,846 美元;这就是为什么交接文档、运行手册、第二负责人这些「不产生收入」的动作,在出售时能变成价格。

写成代码:buyer-view.ts

下面的 buyer-view.ts 把五个关注点、权重、severity 和折扣上限写成一个函数。evaluateBuyerView 要求恰好五个关注点,每个 severity 在 0–100% 之间,权重固定为 8%、8%、20%、5%、5%;五项贡献相加后与上限取小,再从中扣除。它返回调整价、折扣金额、总折扣、实际折扣、是否触顶,以及贡献最大的关注点。这样一张表就能回答两个问题:这个价格是被哪个问题压下来的,以及压价有没有触顶。

代码把「创始人依赖 20%」写成权重,不是写死一个折扣。如果 severity 是 50%,贡献就是 10%;如果 severity 是 100%,贡献才是 20%。这种写法让读者可以调整自己的判断,而不是接受一个拍脑袋的数字。权重和上限是教学假设,代码的注释里写明了这一点;真实交易中,买方会用尽调证据和自己的模型,不会用这本书的权重。

// file: src/capital/buyer-view.ts
// tier: L1
// verify: node --test test/capital/buyer-view.test.ts

import { type Cents } from "../core/money.ts";
import { type Bps, applyRate } from "../core/rate.ts";
import { type Result, fail, ok } from "../core/result.ts";

export type ConcernKey =
  | "revenuePredictability"
  | "customerConcentration"
  | "founderDependence"
  | "techDebt"
  | "compliance";

export const CONCERN_ORDER: ConcernKey[] = [
  "revenuePredictability",
  "customerConcentration",
  "founderDependence",
  "techDebt",
  "compliance",
];

/**
 * Maximum discount contribution at full severity (10000 bps). These weights
 * are teaching assumptions: they make the arithmetic explicit, not a claim
 * about how any real buyer prices a business. Founder dependence is the
 * single largest line because a one-person business cannot be separated from
 * its operator by signing a document.
 */
export const CONCERN_WEIGHT_BPS: Record<ConcernKey, Bps> = {
  revenuePredictability: 800,
  customerConcentration: 800,
  founderDependence: 2000,
  techDebt: 500,
  compliance: 500,
};

export const DEFAULT_CAP_BPS: Bps = 4000;

export type Concern = {
  key: ConcernKey;
  severityBps: Bps;
};

export type BuyerViewInput = {
  anchorCents: Cents;
  concerns: Concern[];
  capBps: Bps;
};

export type BuyerView = {
  anchorCents: Cents;
  adjustedCents: Cents;
  discountCents: Cents;
  grossDiscountBps: Bps;
  appliedDiscountBps: Bps;
  capped: boolean;
  topConcern: ConcernKey;
  topConcernContributionBps: Bps;
};

function isConcernKey(value: string): value is ConcernKey {
  return (CONCERN_ORDER as string[]).includes(value);
}

/**
 * Applies the five buyer concerns to an anchor price. Severity is expressed
 * in basis points so a partly mitigated concern can be scored without a new
 * scale. The total discount is capped: beyond the cap the buyer usually walks
 * away or restructures the deal instead of asking for a lower headline.
 */
export function evaluateBuyerView(
  input: BuyerViewInput,
): Result<BuyerView> {
  if (!Number.isInteger(input.anchorCents) || input.anchorCents <= 0) {
    return fail("anchor price must be a positive integer amount in cents");
  }
  if (
    !Number.isInteger(input.capBps) ||
    input.capBps < 0 ||
    input.capBps > 10000
  ) {
    return fail("discount cap must be between 0 and 100%");
  }
  if (input.concerns.length !== CONCERN_ORDER.length) {
    return fail(
      `expected ${CONCERN_ORDER.length} concerns, got ${input.concerns.length}`,
    );
  }

  const seen = new Set<ConcernKey>();
  let grossDiscountBps = 0;
  let topConcern: ConcernKey = CONCERN_ORDER[0];
  let topConcernContributionBps = -1;

  for (const concern of input.concerns) {
    if (!isConcernKey(concern.key)) {
      return fail(`unknown concern ${concern.key}`);
    }
    if (seen.has(concern.key)) {
      return fail(`duplicate concern ${concern.key}`);
    }
    seen.add(concern.key);
    if (
      !Number.isInteger(concern.severityBps) ||
      concern.severityBps < 0 ||
      concern.severityBps > 10000
    ) {
      return fail(`concern ${concern.key} severity must be between 0 and 100%`);
    }
    const contributionBps = Math.round(
      (concern.severityBps * CONCERN_WEIGHT_BPS[concern.key]) / 10000,
    );
    grossDiscountBps += contributionBps;
    if (contributionBps > topConcernContributionBps) {
      topConcern = concern.key;
      topConcernContributionBps = contributionBps;
    }
  }

  for (const key of CONCERN_ORDER) {
    if (!seen.has(key)) {
      return fail(`missing concern ${key}`);
    }
  }

  const appliedDiscountBps = Math.min(grossDiscountBps, input.capBps);
  const adjustedCents =
    input.anchorCents - applyRate(input.anchorCents, appliedDiscountBps);

  return ok({
    anchorCents: input.anchorCents,
    adjustedCents,
    discountCents: input.anchorCents - adjustedCents,
    grossDiscountBps,
    appliedDiscountBps,
    capped: grossDiscountBps > input.capBps,
    topConcern,
    topConcernContributionBps,
  });
}

把 LedgerLite 代进去:创始人依赖 severity 100%,单独贡献 20%,调整价 615,014 美元;五项 severity 分别为 25%、30%、100%、30%、20% 时,总折扣 26.9%,调整价 561,969 美元。Tidecast 的五项 severity 是 80%、60%、90%、30%、40%,总折扣 32.7%,调整价 167,380 美元。Nord 是 60%、90%、80%、40%、30%,总折扣 31.5%,调整价 70,528 美元。代码返回的 topConcern 在三案例里都是 founderDependence,capped 都是 false;如果五项全部拉满,总折扣 46%,会被 40% 的上限截断,capped 变成 true。

折价模型不能替代尽调。它只是把「买方在意什么」变成可计算的量,让卖方在谈判前知道自己最弱的一环值多少钱。真正的尽调会看合同、账、代码、授权和客户访谈,任何一项都可能推翻模型里的 severity。下一节会把尽调拆成财务、客户、技术三块,分别对应五个问题里的不同证据。财务尽调的清单见 6.1 财务尽调 ,客户尽调见 6.2 客户与合同尽调 ,技术与 IP 尽调见 6.3 技术与知识产权尽调 。

小结

  • 买方看独立开发者资产,先看五个问题:收入可预测性、客户集中度、创始人依赖、技术债、合规瑕疵。
  • Tidecast 的反例是收入可预测性:买断制、Q4 占 38%、Steam 占 80%,年收入不是合同收入。
  • Nord 的反例是客户集中度:前 3 家占 48%、转介绍占 55%、服务收入占 72.7%,客户关系与合伙人绑定。
  • LedgerLite 的反例是创始人依赖:260 家客户、一人负责工程与支持,买方买到的可能是一份需要创始人继续上班的工作。
  • 技术债的折价按修复成本算,不按代码行数算;合规瑕疵是二值的,能 cure 就是交割条件,不能 cure 就是价格调整或退出。
  • 创始人依赖单独就能压价 20%:LedgerLite 的 768,768 美元锚上折扣 153,754 美元,调整价 615,014 美元。
  • 五项合并后 LedgerLite 折价 26.9%,调整价 561,969 美元;Tidecast 折价 32.7% 到 167,380 美元;Nord 折价 31.5% 到 70,528 美元。
  • 权重、severity 与 40% 上限都是教学假设;模型的价值是让卖方知道最弱的一环值多少钱,不是预测真实报价。

阅读导航:上一节:4.1 战略买方、财务买方与个人买家 · 下一节:4.3 交易流程与时间表 。

常见错误与边界

  1. 把五个问题当成并列。 收入和人决定生意能不能接,技术债和合规决定接手后会不会出事;顺序错了,会在收入还没验证时先谈代码。
  2. 用「大家都知道」代替证据。 买方在数据室里找不到文档,就按最坏情况假设;没有书面记录等于没有发生。
  3. 把客户集中度一刀切。 对集中收入打折,对分散收入用正常倍数,比整体打五折更接近真实谈判;分层比一刀切准确。
  4. 把创始人依赖当成道德问题。 买方不是不信任创始人,而是在计算替换成本;留任协议、交接文档和第二负责人都能降低折价。
  5. 按代码行数算技术债。 修复成本和风险溢价才是买方关心的;代码丑但部署清楚,折价可能小于代码漂亮但只有一个人会部署。
  6. 把合规瑕疵留到交割后。 能 cure 的问题要在交割前 cure;不能 cure 的问题要进入赔偿上限或专项托管,不能只写一句承诺。
  7. 把 20% 当成固定折扣。 20% 是 severity 100% 时的权重;severity 50% 只贡献 10%,不要把上限当默认值。
  8. 忽略折扣上限。 五项拉满时总折扣 46%,但买方通常不会接受超过 40% 的折价,而是直接放弃或重组交易;触顶意味着交易结构要变。
  9. 只看百分比不看金额。 LedgerLite 的 26.9% 是 206,799 美元,Nord 的 31.5% 只有 32,432 美元;百分比说明结构,金额说明谈判空间。
  10. 把模型当尽调。 模型里的 severity 是拍的,尽调里的证据是查的;模型可以帮你排序,不能替代合同、账、代码和客户访谈。

本节的边界是「买方视角与折价模型」:只讨论收入可预测性、客户集中度、创始人依赖、技术债、合规瑕疵五个问题,以及它们如何转成价格折扣,不展开尽调清单、交易结构和合同条款。所有权重、severity、折扣上限和案例数字都是教学假设,不构成投资、税务或法律建议。买方在真实交易中会按自己的模型定价;卖方能用的是把证据准备好,让模型里的 severity 尽量低。估值区间的完整方法见 11.3 估值区间与调整项 ,下一节交易流程见 4.3 交易流程与时间表 。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「books」更多文章

  1. 《移动游戏产品的架构·商业化与发行工程》附录 C 商业化与发行评审清单
  2. 《移动游戏产品的架构·商业化与发行工程》附录 B 双案例商业化事实表
  3. 《移动游戏产品的架构·商业化与发行工程》附录 A 商业化与发行术语速查