在固定价格合同和按工时计费之间做选择,通常被描述成一次关于风险的选择。这个说法本身没错,但紧接着就被处理错了,因为双方都默认风险会消失,而不是只从一方转到另一方身上。 风险不会消失。在固定价格的安排里,供应商承担估算出错的风险,并把这份风险提前算进报出的数字里。在按工时计费的安排里,承担风险的是客户。真正的问题从来不是哪一种方式能消除不确定性,而是哪一方更有条件去管理它,以及为转移风险付出的代价值不值得。 能预判哪种方式管用的检验: 你能不能把“完成”写下来,写到两个人对是否已经达到这个状态能给出一致判断的细致程度?如果能,固定价格是你可以用的选项,而且多半是合理的。如果写不出来,固定价格合同并不会消除模糊,它只是把将来每一次分歧从...
软件开发
关于软件开发的文章、指南和教程,为开发者和企业提供实用知识与技巧。面向开发者与技术团队。
关于 API 版本管理的争论,几乎总是从错误的一端开始:版本号该放在哪里。其实这是整个话题里后果最轻的一个决定。真正要紧的是,究竟哪些变更才需要一个新版本,而大多数团队恰恰在这里判断失误,而且是往掉以轻心的方向失误。他们发布了自认为纯属新增的东西,然后某个客户端就坏了。 有用的思维模型是:你的 API 是一份承诺,规定了调用方可以依赖什么。如果一次变更让一个讲道理的调用方原本依赖的东西失效了,那它就是破坏性的。而调用方依赖的东西,远远多于你的文档明确允许他们依赖的范围。 让所有人都栽跟头的那种变更: 往响应里加一个字段。它只是新增,按理说不可能弄坏一个写得规范的客户端,可它偏偏经常弄坏真实的客户端,因为其中有些客户端会严格校验响应,...
软件 RFP,也就是需求建议书,本来的作用是让不同的供应商变得可以互相比较。可现实中大多数文件恰好起了反作用:它们把解决方案写得足够细,细到把答案的空间捆死,却偏偏漏掉了任何人报价时都需要的那些信息。结果就是五份报价,彼此相差一个数量级,形式上每一份都回应了要求,但没有任何两份在测量同一件事。 常见的解释是供应商在打太极。偶尔确实如此。但更常见的情况是,文件要了一个从它自身内容里根本推不出来的数字,于是每家供应商都用各自不同的假设去填补空白。假设不同,价格自然不同,这里并不存在诚不诚实的问题。 判断你的 RFP 是否有效的检验方法: 两家不同的供应商读完之后,能不能得出实质上相同的范围?如果文件里只写了“用户管理”,没有说明有多少种...
软件维护成本,就是那个把一个成功项目在十八个月之后变成一场难堪谈话的数字。开发阶段有预算、有审批、也如期交付了。可上线之后会发生什么,被一句「支持服务」轻轻带过,然后配上一个有人凭感觉给出的金额,而那个金额几乎每一次都太小。 原因出在结构上,不是谁不上心。开发有一个可以定价的范围。维护没有范围,因为决定它的是还没有发生的事情:某个依赖库爆出漏洞,某个供应商改掉了自己的接口,某个用户碰上了当初谁都没想到的情形。 人人都在引用的经验法则是每年按开发成本的 15 到 20 个百分点计算,而它之所以危险,恰恰是因为它离正确答案不远。 它对的次数多到让人放心,错的时候又总是朝同一个方向错:它低估了缺陷集中冒出来的第一年,而在有合规义务或者外部...
技术尽职调查不是一场代码质量比赛,而为它做准备的团队,往往把时间花在了完全不重要的地方。没有哪个买家是为了给你的抽象层打分才来收购公司的。买方想弄清楚的只有两件事:持有这套系统要花多少钱,以及在钱易手之后,事情可能糟糕到什么程度。 这个视角的转换很重要,因为它会改变你应该优先修哪里。丑陋但能跑、团队看得懂、可以安全修改的代码,只是一条轻微的发现。相反,写得优雅却只有一个人看得懂的代码,是一条严重的发现,而真正会让价格发生变化的,恰恰是后者。 所有问题背后的那个问题: 如果创始工程师在交割后的第二周离职,这套系统还能继续运行、并且继续被修改吗?几乎每一条压低报价的发现,都是对这个问题的具体回答。知识集中在一个人的脑子里、没有文档的部署...
数据库性能的排查工作,通常从有人提议换一台更大的实例开始,又通常以这样一个发现结束:每次加载页面时,有一条查询都在对 400 万行做顺序扫描。瓶颈从来不是硬件,瓶颈是执行计划。 这个模式重复得足够稳定,值得当作默认假设写下来。当应用很慢而数据库又很忙时,原因几乎总是少数几条具体的查询,而不是整体容量不足;把机器换大,只能把问题掩盖到表再次长大的那一刻为止。 动手改之前,先量。 凭猜测去优化一条查询,正是团队花掉整整一周添加索引、结果写入变慢而读取一点没快的原因。任何数据库都能告诉你哪些语句消耗的总时间最多。从那里开始,修掉排在最前面的那条,然后再量一次。这样反复两三轮,事故通常就结束了。 数据库性能始于找出那条查询总时间比最坏单次更...
人们谈论软件测试策略时,几乎总是从覆盖率讲起,而覆盖率恰恰是整个领域里信息量最低的一个数字。一个覆盖率达到九十的代码库,照样可能在最常被走到的路径上把缺陷送进生产环境,因为覆盖率衡量的是测试运行期间哪些代码行被执行过,而不是有没有针对这些行做出任何有意义的断言。 真正信任自己测试套件的团队,并不是覆盖率百分比最高的那一批。他们是这样一群人:当东西真的坏了,测试会红;其余时候,测试保持安静。这个性质比大多数人想象的更难用钱买到。 对任何一个测试都值得问的问题: 如果它失败了,我知道该怎么办吗?因为行为改变而失败的测试,会告诉你一些东西。因为某个实现细节挪了位置而失败的测试,只能告诉你有人做了重构。这样的失败积累到一定数量,团队就不再阅...
金融科技软件开发在报价和排期上,和普通软件开发没有任何区别,直到有人问出那句话:到底谁有资格持有这笔钱。从那一刻起,项目就不再是一道工程题,而变成一道带着工程成分的监管题,你脑中原本的时间表也不再成立。 技术很少是难点。搬运资金是一个已经解决的问题,市场上有成熟的服务商、有文档齐全的接口,还有第一天就能用起来的测试环境。真正拖长金融科技项目的,是牌照上的身份、面向审计要拿得出的留痕义务,以及好几个架构决定其实早已由持牌方替你做完了。 决定你时间表的问题: 你自己持牌,还是以代理身份挂在别人的牌照下运营,抑或完全避开受监管业务?这三个答案会产生长度完全不同的项目,而差距是用等待的月数衡量的,不是用开发的周数衡量的。在做任何范围规划之...
MVP 软件开发出问题的地方是范围会议,不是开发过程本身。有人说出「最小可行产品」这几个字,大家点头认可,接着送来的功能清单里却写着用户账号、后台管理面板、计费、通知、仪表板,还有一个移动应用。那不是最小可行产品。那是一个完整的产品,而它花掉的时间会是你心里那个数字的三倍。 真正造成损害的词是「可行」。多数团队把它读成「好到可以卖给所有人」,可它的本意是「刚好够用来判断到底有没有人想要这个东西」。 最省钱的范围测试: 对每一项功能,问问自己会因为答案不同而做出什么不一样的事。如果一项功能改变不了任何决定,它就不属于 MVP。后台管理面板不会告诉你人们是否想要这个产品;它只会告诉你,等人们想要之后,这个产品会更好管理。把它放到第二步再...
大多数团队把 API 安全当成身份验证问题:发放令牌,在每一条路由上校验它,然后认为事情已经做完了。直到某天,一位测试人员把 URL 里的一个数字改掉,就读到了另一位客户的发票。 「已通过身份验证」和「已获得授权」之间的这道缝隙,正是绝大多数真实 API 泄露事件栖身的地方,而且它并不是扫描器能够稳定发现的那类问题。自动化工具看到一个有效的令牌和一个 200 响应,就报告成功。只有理解你业务规则的人,才会注意到那个响应里装的是别人的数据。 核心区别: 身份验证证明的是谁在调用。授权决定的是这个特定调用方可以看到什么、可以修改什么,而且它必须落实到每一个对象、每一次请求,并在数据层强制执行。几乎所有严重的 API 漏洞,都是第一件事运...