2025 08 05 HackerNews

2025-08-05 Hacker News Top Stories #

  1. Perplexity 被发现使用隐蔽爬虫规避网站的不爬取指令,Cloudflare 已采取措施移除并限制其行为。
  2. 现代 Node.js 倡导使用 ES 模块、内置 Web API 和测试框架等功能,以提升开发体验和效率。
  3. 作者花费六年时间建造了一个 1000 像素的木制显示屏,展示了极具创意的项目和坚持精神。
  4. 撰写设计文档时需包含清晰的结构、问题陈述、目标、需求等内容,图片比文字更具说服力。
  5. Mastercard 否认对 NSFW 游戏下架负责,但其规则可能导致支付处理器主观判断并采取行动。
  6. 求职者对 AI 面试官的使用表示反对,认为这是对求职过程的侮辱,而招聘方则认为其提高了效率。
  7. 特斯拉在 Autopilot 致命车祸案件中被指控隐瞒数据并误导警方,以规避责任。
  8. PDF 解析面临交叉引用表等挑战,现实中的复杂性使得解析器需要处理多种异常情况。
  9. 现代设备的过多噪音提醒引发不满,呼吁设计更安静的通知机制,尤其是在紧急情况下。
  10. 类型化语言如 TypeScript 和 Rust 更适合与 AI 工具配合使用,提供更高的安全性和效率。

Perplexity is using stealth, undeclared crawlers to evade no-crawl directives #

https://blog.cloudflare.com/perplexity-is-using-stealth-undeclared-crawlers-to-evade-website-no-crawl-directives/

Cloudflare 发现了一个名为 Perplexity 的 AI 驱动问答引擎正在使用隐蔽的爬虫技术来规避网站的禁止爬取指令。尽管 Perplexity 最初使用其声明的用户代理进行爬取,但当遇到网络封锁时,他们会隐藏爬取身份,试图绕过网站的偏好设置。Cloudflare 观察到 Perplexity 反复修改用户代理和源 ASNs 来隐藏爬取活动,同时忽视或有时甚至不获取 robots.txt 文件。

互联网在过去三十年中迅速变化,但信任始终是其基础。爬虫应该透明、有明确目的、执行特定活动,并最重要的是遵循网站的指令和偏好。基于 Perplexity 的行为与这些偏好不兼容,Cloudflare 已将其从验证机器人列表中移除,并在管理规则中添加了阻止这种隐蔽爬取行为的启发式规则。

Cloudflare 通过创建多个新域名进行测试,这些域名尚未被任何搜索引擎索引,也未公开可访问。他们实施了 robots.txt 文件,指示任何尊重的机器人不要访问网站的任何部分。通过向 Perplexity AI 提出问题,发现 Perplexity 仍能提供有关这些受限域名上托管的确切内容的详细信息,这是出乎意料的,因为他们已经采取了所有必要的预防措施来防止这些数据被爬虫检索。

Cloudflare 观察到 Perplexity 使用的不仅是其声明的用户代理,还包括一个通用浏览器,旨在模仿 macOS 上的 Google Chrome,当其声明的爬虫被封锁时。这两种爬虫都试图访问内容进行抓取,违反了 RFC 9309 中概述的网络爬取规范。这种未声明的爬虫使用了多个不在 Perplexity 官方 IP 范围内的 IP,并在响应限制性的 robots.txt 政策和 Cloudflare 的封锁时轮换这些 IP。除了轮换 IP 外,还观察到来自不同 ASNs 的请求,试图进一步规避网站封锁。这种活动在成千上万的域名和每天数百万个请求中被观察到。Cloudflare 使用机器学习和网络信号的组合来识别这个爬虫。

值得注意的是,当隐蔽爬虫成功被封锁时,观察到 Perplexity 使用其他数据源(包括其他网站)尝试创建答案。然而,这些答案不够具体,缺乏原始内容的细节,反映出封锁已经成功。

与上述行为相比,互联网对良好爬虫的行为表达了明确的偏好。所有善意的爬虫都应该:诚实地识别自己,使用独特的用户代理,声明 IP 范围列表或 Web Bot Auth 集成,并在出现问题时提供联系信息;不要过度流量,抓取敏感数据,或使用隐蔽手段试图躲避检测;服务一个明确的目的,无论是为语音助手提供动力,检查产品价格,还是使网站更易于访问,每个机器人都有存在的理由,目的应该清晰、精确定义,并且网站所有者可以公开查找;为不同活动使用不同的机器人,这使得网站所有者可以决定他们想要允许哪些活动,不要强迫网站所有者做出全有或全无的决定;遵守规则,即检查并尊重网站信号,如 robots.txt,保持在速率限制内,永远不要绕过安全保护。

OpenAI 是遵循这些最佳实践的领先 AI 公司的示例。他们清楚地概述了他们的爬虫,并为每个爬虫的目的提供了详细解释。他们尊重 robots.txt,不试图绕过 robots.txt 指令或网络级封锁。ChatGPT 代理使用新提出的开放标准 Web Bot Auth 签署 http 请求。当 Cloudflare 用 ChatGPT 进行上述相同测试时,发现 ChatGPT-User 获取了 robots 文件,并在被禁止时停止了爬取。没有观察到来自其他用户代理或第三方机器人的后续爬取。当我们从 robots 条目中移除禁止指令,但向 ChatGPT 呈现封锁页面时,他们再次停止了爬取,没有看到来自其他用户代理的额外爬取尝试。这两种情况都展示了对网站所有者偏好的适当响应。

Cloudflare 的所有未声明爬取活动都被其机器人管理系统评分为机器人,并且无法通过管理挑战。任何已经设置现有封锁规则的机器人管理客户已经受到保护。不想封锁流量的客户可以设置规则来挑战请求,给真正的人类一个继续的机会。有现有挑战规则的客户已经受到保护。最后,Cloudflare 在管理规则中添加了隐蔽爬虫的签名匹配,以阻止 AI 爬取活动。这个规则适用于所有客户,包括免费客户。

自从 Cloudflare 宣布内容独立日以来,内容创作者和发布者对他们的内容如何被访问有了更多的控制。今天,超过两百五十万个网站选择完全禁止通过 Cloudflare 的管理 robots.txt 功能或管理规则阻止 AI 爬虫来训练 AI。每个 Cloudflare 客户现在都能够根据他们的业务目标选择性地决定哪些声明的 AI 爬虫能够访问他们的内容。


HN 热度 910 points | 评论 526 comments | 作者:rrampage | 10 hours ago #

https://news.ycombinator.com/item?id=44785636

  • 用户请求网站时应展示内容,使用软件修改内容是用户的选择,网站不应干涉。
  • 使用 LLM 总结内容因为广告和 JavaScript 等问题导致内容难以使用,LLM 访问网站应与浏览器访问网站处于相同法律类别。
  • 有些商店不允许 Instacart 或 Postmates 购物者,他们不希望第三方服务在他们的商店内运营。
  • 可以发送个人购物者而不被察觉,但大量发送会导致商店因真实买家无法进入而感到烦恼。
  • 代理代表他人明确请求可能是合理的,但非明确请求的爬取行为较难辩护。
  • Hacker News 希望用户访问网站参与讨论,而不是通过 AI 获取信息摘要。
  • 网站运营者希望人们访问他们的内容,但不希望 AI 公司抓取他们的网站用于训练数据。
  • 通过法律和技术手段防止人们下载页面并用于训练数据。
  • 即使网站有 robots.txt,也无法阻止人们阅读内容并描述它。
  • AI 公司使用大量带宽,应该被阻止或重税。
  • 人们不应该因为使用内容训练 LLM 或建立搜索索引而受到限制,这会侵犯阅读自由。

Modern Node.js Patterns #

https://kashw1n.com/blog/nodejs-2025/

Node.js 自早期以来经历了显著的变革。如果你已经编写了几年的 Node.js 代码,你很可能亲眼目睹了这一演变——从以回调为主、CommonJS 主导的格局,到今天清洁、基于标准的开发体验。

这些变化不仅仅是表面的;它们代表了我们如何进行服务器端 JavaScript 开发的一个根本转变。现代 Node.js 拥抱网络标准,减少外部依赖,并提供更直观的开发体验。让我们探索这些转变,并了解为什么它们对 2025 年的应用程序至关重要。

  1. 模块系统:ESM 成为新标准 模块系统可能是你会注意到的最大变化。CommonJS 为我们服务得很好,但 ES 模块(ESM)已经成为明显的赢家,提供了更好的工具支持和与网络标准的一致性。

旧方式(CommonJS): 让我们看看我们以前是如何构建模块的。这种方法需要显式导出和同步导入:

// math.js
function add(a, b) {
  return a + b;
}
module.exports = { add };
// app.js
const { add } = require('./math');
console.log(add(2, 3));

这种方法工作得很好,但它有局限性——没有静态分析,没有摇树优化,并且它没有与浏览器标准保持一致。

现代方式(带有 Node:前缀的 ES 模块): 现代 Node.js 开发采用 ES 模块,一个关键的补充是——node:前缀用于内置模块。这种明确的命名防止了混淆,使依赖关系变得清晰:

// math.js
export function add(a, b) {
  return a + b;
}
// app.js
import { add } from './math.js';
import { readFile } from 'node:fs/promises';
// 现代node:前缀
import { createServer } from 'node:http';
console.log(add(2, 3));

node:前缀不仅仅是一种约定——它是一个明确的信号,向开发者和工具表明你正在导入 Node.js 内置模块,而不是 npm 包。这可以防止潜在的冲突,并使你的代码更明确地表达其依赖关系。

顶级等待:简化初始化 最具变革性的特性之一是顶级等待。不再需要将整个应用程序包装在一个异步函数中,仅仅为了在模块级别使用 await:

// app.js - 无需包装函数即可进行清晰的初始化
import { readFile } from 'node:fs/promises';
const config = JSON.parse(await readFile('config.json', 'utf8'));
const server = createServer(/* ... */);
console.log('App started with config:', config.appName);

这消除了我们以前随处可见的立即调用的异步函数表达式(IIFE)的常见模式。你的代码变得更加线性,更容易理解。

  1. 内置 Web API:减少外部依赖 Node.js 在很大程度上拥抱了网络标准,将 Web 开发人员已经熟悉的 API 直接带入运行时。这意味着更少的依赖和跨环境的更多一致性。

Fetch API:不再需要 HTTP 库依赖 还记得每个项目都需要 axios、node-fetch 或类似的库来进行 HTTP 请求吗?那些日子已经过去了。Node.js 现在原生包含了 Fetch API:

// 旧方式 - 需要外部依赖
const axios = require('axios');
const response = await axios.get('https://api.example.com/data');
// 现代方式 - 内置的fetch具有增强功能
const response = await fetch('https://api.example.com/data');
const data = await response.json();

但现代方法不仅仅是替换你的 HTTP 库。你获得了内置的超时和取消支持:

async function fetchData(url) {
  try {
    const response = await fetch(url, {
      signal: AbortSignal.timeout(5000) // 内置超时支持
    });
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: ${response.statusText}`);
    }
    return await response.json();
  } catch (error) {
    if (error.name === 'TimeoutError') {
      throw new Error('Request timed out');
    }
    throw error;
  }
}

这种方法消除了对超时库的需求,并提供了一致的错误处理体验。AbortSignal.timeout()方法特别优雅——它创建了一个在指定时间后自动中止的信号。

AbortController:优雅的操作取消 现代应用程序需要优雅地处理取消,无论是用户发起的还是由于超时。AbortController 提供了一种标准化的方式来取消操作:

// 干净地取消长时间运行的操作
const controller = new AbortController();
// 设置自动取消
setTimeout(() => controller.abort(), 10000);
try {
  const data = await fetch('https://slow-api.com/data', {
    signal: controller.signal
  });
  console.log('Data received:', data);
} catch (error) {
  if (error.name === 'AbortError') {
    console.log('Request was cancelled - this is expected behavior');
  } else {
    console.error('Unexpected error:', error);
  }
}

这种模式适用于许多 Node.js API,不仅仅是 fetch。你可以使用相同的 AbortController 与文件操作、数据库查询以及任何支持取消的异步操作。

  1. 内置测试:无需外部依赖的专业测试 测试曾经需要在 Jest、Mocha、Ava 或其他框架之间进行选择。Node.js 现在包括一个功能齐全的测试运行器,覆盖了大多数测试需求,无需任何外部依赖。

现代测试与 Node.js 内置测试运行器 内置测试运行器提供了一个干净、熟悉的 API,感觉现代且完整:

// test/math.test.js
import { test, describe } from 'node:test';
import assert from 'node:assert';
import { add, multiply } from '../math.js';
describe('Math functions', () => {
  test('adds numbers correctly', () => {
    assert.strictEqual(add(2, 3), 5);
  });
  test('handles async operations', async () => {
    const result = await multiply(2, 3);
    assert.strictEqual(result, 6);
  });
  test('throws on invalid input', () => {
    assert.throws(() => add('a', 'b'), /Invalid input/);
  });
});

这特别强大的是它如何与 Node.js 开发工作流程无缝集成:

# 使用内置运行器运行所有测试
node --test
# 开发中的监视模式
node --test --watch
# 覆盖率报告(Node.js 20+)
node --test --experimental-test-coverage

监视模式在开发中特别有价值——你的测试在修改代码时自动重新运行,无需任何额外配置,即可提供即时反馈。

  1. 复杂的异步模式 虽然 async/await 并不新鲜,但围绕它的模式已经显著成熟。现代 Node.js 开发更有效地利用这些模式,并将其与新 API 结合起来。

Async/Await 与增强的错误处理 现代错误处理结合了 async/await 与复杂的错误恢复和并行执行模式:

import { readFile, writeFile } from 'node:fs/promises';
async function processData() {
  try {
    // 独立操作的并行执行
    const [config, userData] = await Promise.all([
      readFile('config.json', 'utf8'),
      fetch('/api/user').then(r => r.json())
    ]);
    const processed = processUserData(userData, JSON.parse(config));
    await writeFile('output.json', JSON.stringify(processed, null, 2));
    return processed;
  } catch (error) {
    // 结构化错误日志记录与上下文
    console.error('Processing failed:', {
      error: error.message,
      stack: error.stack,
      timestamp: new Date().toISOString()
    });
    throw error;
  }
}

这种模式结合了并行执行以提高性能,并提供全面的错误处理。Promise.all()确保独立操作同时运行,而 try/catch 提供了一个用于错误处理的单一点,具有丰富的上下文。

现代事件处理与 AsyncIterators 事件驱动编程已经超越了简单的事件监听器。AsyncIterators 提供了一种更强大的处理事件流的方式


HN 热度 813 points | 评论 397 comments | 作者:eustoria | 1 day ago #

https://news.ycombinator.com/item?id=44778936

  • Node.js 的新特性受到 Deno 的启发,允许限制文件系统和网络访问,这是一个优秀的功能。
  • 有人反对在运行时或应用程序中添加此类功能,认为应该在操作系统层面解决这些问题。
  • 有人分享了自己使用 Node.js 替代 cron 的积极经验,认为它更可靠,易于管理。
  • 有人提到,如果操作系统工具不够好,比如 macOS 的文档不足,将这些功能集成到 Node.js 中可以提供跨平台的一致性。
  • 有人指出,操作系统并没有真正解决文件访问控制问题,现代软件安全需要限制权限,减少供应链漏洞。
  • 有人建议使用 FreeBSD 的 Capsicum 或 Linux 的进程挂载命名空间来实现类似的功能。
  • 有人认为,操作系统应该负责域名解析,而不是个别程序,这样可以减少管理员的负担。
  • 有人提出,不是所有 Node.js 开发者都了解或愿意了解底层操作系统,因此 Node.js 提供这样的功能是有益的。
  • 有人质疑,是否需要为每个运行的应用程序创建一个单独的用户,这在本地环境中似乎很麻烦。
  • 有人提到 Windows 也有文件系统权限控制功能,且经过了良好的测试和验证。

Show HN: I spent 6 years building a ridiculous wooden pixel display #

https://benholmen.com/blog/kilopixel/

我花了 6 年时间建造了一个荒谬的 1000 像素木制显示屏 2025 年 8 月 2 日 TL,DR:我建造了世界上最不实用的 1000 像素显示屏,世界上任何人都可以在上面画画。如果你只想玩一下,可以去 kilopx.com。

背后的故事 六年前,我有一个想法,要建造一个大型、低效的显示屏,任何人都可以通过网络界面与之互动。多年来,我一直很喜欢 Danny Rozin 的非传统镜子,并受到一个每小时播放 24 帧的 eInk 电影播放器的启发,让我思考一个可以缓慢组装图像的费力显示屏。 我最终决定做一个 40×25 像素的网格,由一个单一的机制逐个翻转像素。与我们现代显示屏每秒 60 次变化数百万像素相比,一个每分钟只改变一个像素的木制显示屏是创建图像的极其低效的方式。方便的是,40×25=1000 像素,因此得名 Kilopixel,以及六字母域名 kilopx.com。你怎么能退缩呢?这是我拥有过的最好的域名。

所以我开始工作。这个项目包括一切:一个网络应用,一个物理控制器,一个定制的 CNC 构建,生成的 gcode,大量的制造,3D 建模,3D 打印,材料采购——太多东西可以沉迷其中。这是我建造过的最有雄心的项目。

第一个原型:21×3 像素 我的第一个想法是使用一个木制的龙门架,它将沿着某种轨道移动。由于我最习惯使用木材,这是我默认的原型制作材料。然而,我很快转向了挤压铝和 Openbuilds 提供的出色的硬件套件,包括滑轮、龙门架部件、挤压铝和同步带。这与 3D 打印机框架中使用的材料非常相似,并且可以很容易地与现成的步进电机连接。这使我能够构建一个具有 X 和 Y 的龙门架,本质上是一个壁挂式 XY 绘图仪。我的第一个原型使用了两个步进电机,一个 Raspberry Pi,一个 CNC 控制器和一个强大的电源。它允许我生成并向 CNC 控制器发送指令,移动到特定的像素,翻转该像素,并从传感器读取值。它还揭示了我在像素选择和像素操作机制方面的很多问题。

1000 个任何东西都很贵 选择像素是一次真正的冒险。我尝试了乒乓球、泡沫球、弹跳球、木球、3D 打印球、高尔夫球、泡沫球……任何大约 1-1.5 英寸直径的球形物体。我遇到的问题主要是成本(即使是 50 美分的球也是 500 美元的球),重量(同样,一千个这些东西),以及可用性。很长一段时间,我认为乒乓球是我最好的选择,所以我买了几百个,3D 打印了喷漆夹具,并喷漆。我用热钉在每个球上熔化两个相对的孔,这样它们就可以被串起来挂在显示屏上。 乒乓球基本上是苏打罐 你可以站在苏打罐上,只要它没打开。打开罐子,它就很容易压碎。乒乓球也是这样。它们相对坚固,直到你在它们上面熔化两个洞。然后它们可以被变形,这对任何你喷上的油漆都是致命的。而且,它们不仅脆弱,而且便宜的乒乓球大小不一致,当你有一排 40 个球时,半毫米的差距加起来就很大。乒乓球是行不通的。 Nerfed 我下一个尝试的便宜球形像素是泡沫 Nerf 球——比乒乓球小得多,只有鲜艳的颜色。它们接受喷漆还可以,但油漆会随着时间的推移而恶化。 在 Nerf 球上一致地钻孔很困难,它们真的很喜欢抓住电线,很难转动。我努力一致地转动它们,我对鲜艳的颜色也不感兴趣。

我还尝试了弹跳球(钻孔困难,喷漆困难,大小不一致,重),木球(不够圆,喷漆线条不够清晰,重),以及泡沫球(用丙烯酸油漆很难喷漆,而且它们会被喷漆融化)。 转动球体 我有一个想法,使用一个小而慢的电机旋转一个乐高轮子对着乒乓球。我会使用一个反射率传感器来检测它是否显示黑色或白色,并在像素正确旋转后停止。我建模并打印了一个乐高轮子的定制轮毂,几种不同的机制来移动轮子与球体接触,以及一个龙门架的接口。我尝试使用一个电磁铁将电机推入球体,这动力不足,以及一个伺服电机。这两种方法都不太好,我最终决定这种转动球体的方法是一条死胡同。

转向非球形像素 在 2024 年,我与 Side Project 播客的 Joe Tannenbaum 和 Over Engineered 播客的 Chris Morrell 进行了几次富有成效的对话。这些对话帮助我考虑,也许球体不是唯一的选择——我考虑了翻板和发光按钮,然后决定使用一个立方体木制像素。我还决定自己制造像素,因为我在木工车间非常自在。这个决定让我花费了大量的时间,因为做一千次事情需要很长时间,但我对它的操作和外观非常满意。 建造网格 我从早期原型中学到,我需要严格定义一个网格,而不是依赖像素本身来保持间距。那个 40 毫米像素可能是 39.5 毫米,或者是 41 毫米。这种变化在 40 个像素中加起来——你可能在一排的末端偏离 10 毫米。所以在我的(希望是最终的)构建中,我创建了 25 个薄架子,在每个架子上钻了 40 个孔,使用夹具来强制一致的间距,并将像素穿在 40 根金属线上。这是痛苦和耗时的——我把它分成了几周的几个会话。但它确实创建了一个非常可预测的像素网格,并保证了每个像素完全独立于周围的像素移动。 最后,我有了我的第一个千像素显示屏,看起来很有希望!我可以在这里停下来,有一些有趣的墙画——用手在上面挥动感觉很棒。但我们不会停下来!在威斯康星州,我们说向前! 我办公室里的 CNC 机器

多年来,我一直在我的木工车间使用一个爱好 CNC 机器,所以我对 CNC 的基础知识和这个项目的可能性很熟悉。一般来说,CNC 机器是一种接受非常具体的运动指令,这些指令是用一种叫做 gcode 的语言编写的,它使用这些指令移动到某个位置并做一些动作,比如钻一个洞,切割一个凹槽,或者用激光烧。通常使用步进电机,因为它们在接收到 CNC 控制器的电信号时移动非常可预测。常见的爱好 CNC 机器包括激光雕刻机(Glowforge)、铣床(X-Carve)和 3D 打印机。它们都使用运动指令在 X、Y 和 Z 轴上非常精确地移动并在这些坐标处做事。

很容易找到一个基本的 CNC 控制器,可以用于 CNC 铣床、激光雕刻机或绘图仪。这些 CNC 控制器通过 USB/串行接受 gcode,并转动步进电机将机器置于正确的位置。它们通常运行 grbl,这是一个在 Arduino 上运行的开源 gcode 解析器。

Kilopixel 本质上是一个 2 轴机器,使用第三轴作为像素戳动机制。

我将一个 Raspberry Pi 连接到 CNC 控制器,并用它做两件事:查询我的 API 以获取下一个像素,编写适当的 gcode 到达那里,激活像素戳动器,然后读取一个光传感器以确定像素的物理状态。然后它将该状态返回给 API 并继续循环。这是用 Python 脚本运行的,依赖于 pigpio 在 GPIO 引脚上读取光传感器。


HN 热度 648 points | 评论 96 comments | 作者:benholmen | 7 hours ago #

https://news.ycombinator.com/item?id=44787902

  • 该项目非常酷,是令人惊叹的项目,展示了作者六年的辛勤工作。
  • 有人提到自己构建了一个类似的 30 像素显示器,全部是机械式的。
  • 有人建议在完成提交后将“笔”移开,以便拍摄完成的艺术作品的清晰照片。
  • 建议在网站上显示当前进行中的提交的归属,并有一个“历史”画廊用于展示已完成的提交。
  • 有人提到这个刷新率为 370 微赫兹的显示器重新定义了“平静技术”。
  • 有人询问作者是否读过 Amber Case 的《Calm Technology》一书,并询问是否推荐。
  • 有人提到 YouTube 流主摄像头的帧率也是相同的。
  • 这是他们见过的每像素成本最高的显示器,尽管如此,他们非常喜欢这个显示器。
  • 有人提到了 Danny Rosin 的镜子,作为另一种昂贵的像素展示。
  • 有人提到 Mythbusters 可能仍然保持着更换图像速度的记录。
  • 当图像不更换时,显示器几乎没有能耗。
  • 有人提出,这种显示技术可能会取代电子墨水显示技术。
  • 作者表示,这个项目是直接受到电子墨水显示技术的启发。
  • 有人提到构建这个项目的成本和时间成本无法计算,但经验和感觉是无价的。
  • 有人提到可以用更小的木质立方体来降低成本。
  • 有人提出了一个创意,使用灵活的胶棒作为往复戳动机制。
  • 有人建议每个立方体指向一个边缘而不是一个面,以便同时显示两个图像。
  • 有人提到如果牺牲一种颜色,可以使用三角形/棱柱,这样面就可以独立旋转。
  • 有人提到了已经存在的类似概念,用于非像素化图像的旋转面板。
  • 有人提出可以用 RGBK 或 CYMK 来给每个像素立方体的四个面着色,以实现彩色显示。
  • 有人提到可以通过优化加快显示速度,比如整个列或行的优化。
  • 有人提到在观看 YouTube 流时需要登录,这有点烦人。

Writing a good design document #

https://grantslatton.com/how-to-design-document

设计文档的撰写技巧

本文是对 Vik 在社交媒体上提出的关于如何学习撰写设计文档的问题的回应。设计文档是一种技术报告,它概述了在权衡和限制条件下系统的实施策略。

目标 设计文档的目标是说服读者,给定情况下的设计是最优的。最重要的是说服作者自己。撰写设计文档有助于为原本模糊的直觉增加严谨性。写作揭示了你的思考是多么草率(后来,代码会显示你的写作是多么草率)。

组织 良好的设计文档组织和代码组织同样重要。你可能对代码组织有自己的看法。你可能用过“意大利面条代码”来形容组织不良的代码。大多数程序员除非有很多实践经验,否则会写出“意大利面条设计文档”。

以一个常见的代码组织问题为例,新手可能会这样写: terminal.print(“Hello world”) 然后他们决定让文字变红,于是编辑程序为: terminal.print(“Hello world”) terminal.setPrintColor(“red”) 他们困惑为什么没有变成红色。他们还没有内化第一个代码行在第二个之前执行的概念。他们只是得到了一堆代码,期望计算机能按照他们的意愿行事。

新手文档编写者也会犯同样的错误,只是用散文代替了代码。他们得到了一堆句子和段落,期望读者的大脑能按照他们的意愿行事。

如果读者足够聪明,你可能会侥幸成功。就像一个经验丰富的程序员可以在心里解开意大利面条代码。

但一个完美的文档是为了让读者永远不会感到惊讶。读者应该发现每一句话都明显地从前一句中流出。他们应该在读完你的文档后觉得“这完全直截了当,我们为什么还需要开会?”

这会让许多寻求自我肯定的工程师失望。优秀的工程师通常希望人们意识到他们的聪明才智。

但一个好的文档会以一种方式展示问题和心理模型,使得花费数周艰苦思考才想出的解决方案在文档呈现时对读者来说变得清晰。

这也需要对阅读你文档的人的心理有一个良好的模型。你的文档的目标是将他们的思维从当前状态带到一个新的状态,即他们相信你的设计是好的。

你应该预见到有人会有的每一个反对意见,并先发制人地展示为什么它是无效的,以便读者甚至不会想到提出它。

许多工程师在模拟读者思维的起始状态时失败,因此无法将他们带到目的地状态。

编辑 一旦你组织好了信息并正确地布局,下一步就是编辑以缩短篇幅。删除可以删除的每一个词。这样做是因为你的读者的注意力是一种稀缺资源。

除非你是一个非常简洁的作家,否则你几乎总是可以从初稿中削减大约 30% 的长度,而不会牺牲信息。

通过用红笔审阅别人的文档并划掉不必要的词来提高编辑技巧是最容易的方法。你会发现很多。批评别人更容易。

一旦你锻炼了这个能力,你就可以将武器转向自己。将思想提炼到适合 280 个字符的推文限制也是出奇的好练习。

卷 大量的实践是无可替代的。我很感激在 AWS 工作,那里有一个独特的文档写作文化。我在那里写的第一批文档很糟糕,但经过几百份之后,我认为它们相当不错。

对于不熟悉的读者:亚马逊会议以主持人分发副本(历史上是实体的,但自 Covid 以来越来越多地数字化)的散文文档开始。根据重要性,文档是 1-6 页。

会议开始时,每个人都静静地坐着,阅读文档,并在页边用红笔添加注释和问题。看着人们在你花了很多时间打磨的文档上做标记,是一个强大的推动力,让你成为一个更好的作家。

具体建议 这些对我有效,但可能对你无效。

使用短段落 你应该将你的文档视为一系列相互流动的子弹点。也就是说,一个文档可能像这样组织: 观察 A 观察 B 因为 B,想法 C 但问题 D 和 E 观察 F 因此想法 G 和改进 H 每个子弹点都应该是一段可以总结为一句话的段落。它不需要是一句话——必要时你可以详细说明。但是,一旦阅读,读者应该能够在心中将其压缩为一句话。

这与编辑的想法有关,即你的读者的注意力是一种稀缺资源。你的读者在短期记忆中可以处理的信息是有限的。以这种“每段一个想法”的风格写作,允许读者压缩段落,从而消耗更少的这种稀缺资源。

使用附录 如果文档中有一些数字是复杂计算或模拟的结果,不要将其包含在文档正文中。使用脚注,如: 蒙特卡洛模拟[1]显示,由于腐败导致的数据丢失概率小于 1/10^12 然后在附录中更详细地描述模拟。附录不应该是需要阅读以理解文档的主要结论的。它只是为好奇的读者检查你的工作,如果他们想要的话。

编辑示例 这是一个段落,在编辑之前的版本: 每个子弹点都应该是它自己的段落在你的文档中。每个段落都应该可以用一句话来总结。段落实际上不需要是一句话。例如,你可能会包括几句话来真正说明你想传达的整个概念。但是,一旦读者阅读了它,他们应该能够在心中将其压缩为一句话。

这是编辑后的版本,传达了完全相同的信息,但更简洁: 每个子弹点都应该是一段可以总结为一句话的段落。它不需要是一句话——必要时你可以详细说明。但是,一旦阅读,读者应该能够在心中将其压缩为一句话。

祝你写作愉快!


HN 热度 535 points | 评论 134 comments | 作者:kiyanwang | 1 day ago #

https://news.ycombinator.com/item?id=44779428

  • 技术设计文档应包含问题陈述、目标、非目标、功能和非功能需求,功能规格描述系统如何从外部视角工作,技术规格描述内部实现。
  • 第一层应明确识别利益相关者,描述当前情况,并列出考虑过的替代解决方案及未选择的原因。
  • 开发者应在第三层做一些技术设计笔记,最重要的是选择理由。
  • 所有层级都应添加和使用参考,图片比文字更有说服力。
  • 也许还应包含参考实现或形式证明,特别是在讨论安全协议时。
  • 非目标非常重要,设置硬性限制是必要的,否则解决方案空间会压倒性,可能导致项目失败。
  • 设计文档至关重要,写作可以显著提高我们的想法质量。
  • 替换形容词为数据,但现在很多简历充斥着数字,让人难以理解。
  • 如果简历中有“减少 X 百分比”的表述,面试官会进一步询问具体细节。
  • 作为招聘经理,更关注候选人能解决的问题类别和熟练使用的工具/技术,而不是他们声称的成就。
  • 如果简历上的每一行都是业务目标达成,而几乎没有提及技术技能,这可能是低质量简历的标志。
  • 相对于声称能解决的问题,简历上列出已解决的问题更难以夸大。

Mastercard deflects blame for NSFW games being taken down #

https://www.pcgamer.com/games/mastercard-deflects-blame-for-nsfw-games-being-taken-down-but-valve-says-payment-processors-specifically-cited-a-mastercard-rule-about-damaging-the-brand/

信用卡公司对 Steam 和 Itch.io 施加压力,导致这两个平台不得不下架一些成人游戏。Mastercard 发表声明否认对此负责,声称其“允许所有合法购买”通过其系统处理。Mastercard 表示,它没有评估任何游戏或要求游戏创作者网站和平台上的任何活动受到限制,其支付网络遵循基于法治的标准。尽管如此,Valve 和 Itch.io 都明确表示,支付处理器是游戏被下架的原因。

Mastercard 的声明似乎有些奇怪,因为被 Steam 和 Itch.io 移除的内容在某些国家可能违反法律,但在美国是完全合法的。Valve 和 Itch.io 都明确指出,支付处理器是导致游戏被下架的原因。Mastercard 的立场似乎在于其运营结构。Mastercard 网站表示,它既不是发行商(商业银行)也不是收单机构(向消费者提供借记卡或信用额度的银行、信用合作社或其他实体),而是“提供支持交易的技术和网络”。换句话说,Mastercard 不处理支付,而是促进处理支付的系统。

在 Itch.io 的案例中,该平台在其“关于 NSFW 内容的更新”中明确指出,其支付处理器是 Paypal 和 Stripe,而 Stripe 支持包括 Visa 和 Mastercard 在内的多种支付方式,是 Itch.io“暂停使用 18+ 内容支付功能”的支付处理器。同样,Verotel 和 CCBill,这两个最近被 IGDA 推荐为“过度风险规避金融合作伙伴的替代品”,也接受主要信用卡作为支付方式。

Valve 在向 PC Gamer 提供的声明中表示,在移除游戏之前,它曾试图直接与 Mastercard 解决问题,并暗示 Mastercard 至少对结果有间接影响。Valve 代表表示:“Mastercard 没有直接与 Valve 沟通,尽管我们请求这样做。Mastercard 与支付处理器及其收单银行沟通。支付处理器将此与 Valve 沟通,我们回复时概述了 Steam 自 2018 年以来的政策,即试图分发合法分销的游戏。”支付处理器拒绝了这一点,并特别提到了 Mastercard 的规则 5.12.7 和对 Mastercard 品牌的风险。

Mastercard 的规则 5.12.7 涉及“非法或损害品牌声誉的交易”,规定:商家不得向其收单机构提交,客户不得向交换系统提交任何非法交易,或在公司的唯一判断下,可能损害公司商誉或对标记产生负面影响的交易。这包括根据规则,任何“明显冒犯且缺乏严肃艺术价值的产品或服务(例如,通过举例且不仅限于,非自愿性行为的图像、对未成年人的性剥削、非自愿的肢解或身体部位、兽交)或公司认为与标记连接出售不可接受的任何其他材料。”

未能对投诉采取行动的收单机构(提供卡片和信用额度的金融机构)将受到重大处罚,无论是金钱上的还是其他方面的。无论 Mastercard 在这一切中扮演了什么角色,无论是直接还是间接,其“澄清”确实让人觉得压力正在被感受到。从玩家的角度来看,至少这是一件好事:正如其他人所提到的,公众压力运动似乎对澳大利亚反色情斗士集体呐喊有效,他们开始了这一切——不管背后的齿轮如何转动,没有理由认为它不能朝另一个方向工作。


HN 热度 523 points | 评论 520 comments | 作者:croes | 14 hours ago #

https://news.ycombinator.com/item?id=44783566

  • Mastercard 的声明允许所有合法购买,但其规则 5.12.7 却含糊不清,可能导致对某些交易的主观判断
  • 需要国会立法,要求涉及美国金融交易的企业作为“公共承运人”,不得无法院命令歧视或取消任何客户或合法交易
  • 有一项法案几乎完全符合这一要求,目前正在委员会审议中
  • 支付卡网络不应因政治或声誉风险考虑而禁止合规人士获得网络服务
  • 支付处理器可能会以欺诈风险为由调整费率,但需基于实证数据并出于善意
  • Visa 和 MasterCard 的利润率超过 50%,表明可能存在反垄断监管失败
  • 选择不为高风险欺诈服务是支付处理器的权利,但应能在法庭上为这些决定辩护
  • 如果支付处理器错误应用欺诈标准,公司可能会起诉并获胜,迫使其停止错误应用标准
  • 对于只有少数玩家的游戏,Valve 可能没有动力去争取游戏列表
  • 许多公司可能更容易允许支付处理器审查不太赚钱的产品
  • 游戏工作室可能没有资金去打官司以保持产品可用性
  • 支付处理器的阴谋论可能导致游戏工作室成为受害者
  • 需要小心,因为这种做法可能会适得其反,导致一些小众服务提供商不愿服务的事项增长,最终成为需要法律禁止的优先事项
  • 国会中的极左和极右都在推动更多的审查制度
  • 极右要求政府阻止访问他们不喜欢的某些内容,而极左批评那些不够表现出足够道德信号的人,但这并不是审查制度
  • 极左并不是要求在进入公共空间前必须进行土地承认和代词声明,实际上这些要求在真正的左翼空间中很少见
  • 认为自己是左派并且从未关心过这些事情,并不意味着没有左派关心这些问题
  • 极左有大约 50 个不同的利益团体,他们关心不同的宠物问题,程度不一,就像极右一样

Job-seekers are dodging AI interviewers #

https://fortune.com/2025/08/03/ai-interviewers-job-seekers-unemployment-hiring-hr-teams/

人工智能(AI)正在取代人类招聘经理进行工作面试,而候选人对此表示反对。尽管失业,专业人士告诉《财富》杂志,他们拒绝与机器人通话,称这是“额外的侮辱”,并且是公司文化的红旗。尽管如此,人力资源团队表示,这是处理成千上万申请者的唯一方式。

下次你为期待已久的工作面试打扮整齐坐下时,电话那头可能没有人。相反,求职者现在加入 Zoom 会议,只会被人工智能面试官迎接。候选人告诉《财富》杂志,当机器人、无面孔的机器人加入电话时,他们要么感到困惑,要么好奇,要么直接沮丧。

“现在找工作如此令人沮丧和灵魂被抽空,让自己遭受这种额外的侮辱太过分了,”寻找工作已经三个月的资深作家和编辑 Debra Borchardt 告诉《财富》杂志。“几分钟内,我就感觉,‘我不喜欢这个。这太可怕了。’一开始很正常……然后它进入了面试的实际过程,就在那时变得有点奇怪。”

人工智能面试官只是招聘流程中的最新变化,这一流程已经被先进技术颠覆。随着人力资源团队的减少,招聘经理需要审查成千上万的申请者来填补一个职位,他们通过使用人工智能筛选顶级申请者、安排候选人面试和自动发送关于流程下一步的通信来优化工作。对于中层管理者来说,人工智能面试官可能是天赐之物,但求职者将它们视为寻找工作的又一个障碍。

对于一些求职者来说,体验如此糟糕,以至于他们完全放弃了由人工智能进行的面试。候选人告诉《财富》杂志,人工智能面试官让他们感到不被重视,以至于他们宁愿放弃潜在的工作机会,理由是如果人类老板不愿意花时间面试他们,公司的文化不可能很好。但人力资源专家争论相反:由于人工智能面试官可以帮助招聘经理节省第一轮电话的时间,人类在后续过程中有更多时间与申请者进行更有意义的对话。

求职者和人力资源对这项技术的感受截然不同,但有一件事是事实——人工智能面试官不会消失。

“事实是,如果你想找工作,你会经历这件事,”Braintrust 的首席执行官和创始人 Adam Jackson 告诉《财富》杂志,Braintrust 是一家分发人工智能面试官的公司。“如果有很大一部分人完全拒绝这个,我们的客户就不会觉得这个工具有用……这个工具对我们的客户来说会长期表现不佳。我们并没有看到这一点——我们看到的恰恰相反。”

求职者躲避人工智能面试官

社交媒体上充斥着求职者详细描述他们的人工智能面试官经历:描述机器人幻觉和重复问题的机器人,称机器人对话尴尬,或者说与人类交谈相比不那么紧张。尽管招聘经理多么喜欢人工智能面试官,求职者还没有完全接受这个想法。

Allen Rausch,一位 56 岁的技术作家,曾在亚马逊和电子艺术工作,自从两个月前从 InvestCloud 的前一个角色被裁员以来,一直在寻找新的机会。在寻找新机会时,他“吃惊”地第一次遇到了人工智能面试官——更不用说在三个不同的工作中。所有会议将持续长达 25 分钟,并以女性声音的女性卡通形象出现。它询问基本的职业问题,浏览他的简历和工作细节,但无法回答他关于公司或文化的任何问题。

Rausch 表示,他只愿意进行更多的人工智能面试,如果它们不测试他的写作技能,并且在过程中的某个时候保证有人的联系。

“考虑到我对基本申请的回应比例,我认为很多人工智能面试都在浪费我的时间,”他告诉《财富》杂志。“我可能需要某种保证,‘嘿,我们这样做只是为了收集初始信息,我们将在稍后用人类与你面试。’”

虽然 Rausch 经受了多次人工智能面试,但 Borchardt 甚至无法完成一个。这位 64 岁的编辑专业人士说,当机器人面试官简单地浏览她的简历,要求她在每个列出的公司重复所有工作经历时,事情开始走下坡路。电话是冷漠的,令人恼火的,对 Borchardt 来说,相当懒惰。她在不到 10 分钟内结束了面试。

“大概第三个问题后,我就感觉,‘我完了。’我点击退出,”她说。“我不会坐在这里 30 分钟和机器说话……如果人力资源人员甚至不愿意花时间和我说话,我不想为这样的公司工作。”

现在在英国能源公司 Murphy Group 工作的 Alex Cobb,几个月前在寻找新角色时也遇到了人工智能面试官。虽然他对人力资源需要筛选的申请数量表示同情,但他发现人工智能面试官“奇怪”并且在完全评估人类申请者方面最终无效。这种经历让他感到不愉快,以至于 Cobb 在可预见的未来不会追求任何由人工智能监督的面试。

“如果我知道从公司评论或招聘过程中我将使用人工智能面试,我就不会浪费时间,因为我觉得这更多的是节省成本的练习,”Cobb 告诉《财富》杂志。“这让我觉得他们不重视我的学习和发展。这让我开始质疑公司的文化——他们会不会因为已经学会机器人可以招聘人员而在未来裁员?他们还会外包什么?”

人工智能面试官是挤压招聘经理的天赐之物

尽管许多求职者正在远离接受人工智能面试,但招聘经理却张开双臂接受这项技术。很大一部分原因是必要的。

“它们在早期筛选中变得越来越普遍,因为它们可以简化……”


HN 热度 478 points | 评论 733 comments | 作者:robtherobber | 16 hours ago #

https://news.ycombinator.com/item?id=44783155

  • 求职者对 AI 面试官的反感,认为与 AI 对话浪费时间,不如用来申请其他工作或做其他事情。
  • 面试者在面试中编造故事和即兴发挥,导致招聘过程困难重重。
  • 招聘者和求职者都存在问题,招聘过程在技术行业尤其糟糕。
  • 面试中对于“接口”的定义理解不一,可能导致误解和沟通不畅。
  • 面试者建议在被问到模糊问题时请求澄清,以避免给出错误答案。
  • 面试官希望面试者能够对广泛的问题给出广泛答案,展示其知识面。
  • 面试者在面试中可能需要澄清问题,以便给出更准确的答案。
  • 面试者认为对于“接口”的广泛问题,面试官期待面试者能够展示其对各种接口的了解。

Tesla withheld data, lied, misdirected police to avoid blame in Autopilot crash #

https://electrek.co/2025/08/04/tesla-withheld-data-lied-misdirected-police-plaintiffs-avoid-blame-autopilot-crash/

Electrek 网站报道了特斯拉在涉及自动驾驶功能的致命车祸案件中的行为。在这场案件中,特斯拉被判定部分责任,陪审团发现特斯拉在试图将所有责任推给司机的过程中,存在极其误导性的行为。以下是根据庭审记录的详细情况:

  1. 2019 年 4 月 25 日,事故发生后,特斯拉 Model S 在大约 3 分钟内将传感器视频、CAN 总线、EDR 等数据打包成一个“碰撞快照”文件,并上传到特斯拉的服务器,然后删除了本地副本,使得特斯拉成为唯一拥有这些数据的实体。原告聘请的事故重建专家 Alan Moore 通过从自动驾驶 ECU(计算机)中提取的数据,确认特斯拉一直拥有这些“碰撞快照”,但“解除了”与车辆的链接。
  2. 2019 年 5 月 23 日,佛罗里达州高速公路巡逻队(FHP)的杀人案调查员 Riso 寻求特斯拉的帮助,以获取有助于重建事故的遥测数据。他与特斯拉律师 Ryan McCarthy 联系,并询问是否需要传票来获取事故数据。McCarthy 告诉 Riso 不需要传票,并指导他如何写信请求数据,但故意省略了分享碰撞快照的内容。
  3. 2019 年 6 月,当警方试图直接从自动驾驶计算机中收集数据时,特斯拉的行为变得更加欺骗性。Riso 从特斯拉上取下了 MCU 和自动驾驶 ECU,并在特斯拉服务中心与技术人员 Michael Calafell 会面,试图获取数据。然而,Calafell 声称数据“损坏”且无法访问。后来,当原告的法医工程师 Alan Moore 获得访问权限时,发现特斯拉确实在 6 月 19 日启动了计算机,数据是可以访问的。
  4. 从 2019 年到 2024 年,特斯拉在与警方、原告和法庭的沟通中,从未提及其服务器上拥有解释自动驾驶如何看到事故的所有数据。特斯拉在事故发生后几分钟内就在服务器上拥有了数据,但当警方寻求数据时,特斯拉将他们引向其他数据。当警方寻求特斯拉的帮助从计算机中提取数据时,特斯拉错误地声称数据“损坏”。特斯拉还发明了一个不存在的“自动删除”功能来解释为什么最初无法在计算机中找到数据。
  5. 到了 2024 年末,法庭允许原告让第三方专家访问自动驾驶 ECU,尝试访问特斯拉声称现在已损坏的数据。法庭允许法医工程师进行位对位的 NAND 闪存镜像,这是一种完整的、逐扇区复制存储在 NAND 上的数据。

HN 热度 429 points | 评论 202 comments | 作者:Hamuko | 8 hours ago #

https://news.ycombinator.com/item?id=44787780

  • 特斯拉在事故发生后没有将事故数据提供给调查人员,这在道德上是站不住脚的,尤其是他们自己保留了这些数据用于分析。
  • 特斯拉的 Autopilot 在城市街道上使用不当,司机在事故发生时正在超速,并且低头捡手机,同时脚踩油门,导致自动刹车系统被覆盖。
  • 特斯拉隐藏事故数据表明了他们对安全的态度,尽管事故本身并非特斯拉的责任。
  • 特斯拉的营销方式导致人们在不安全的情况下使用 Autopilot,这构成了部分责任。
  • 特斯拉的“全自动驾驶”功能实际上是一种夸大其词的宣传。
  • 飞行员需要经过严格的培训和认证,而特斯拉的 Autopilot 使用门槛过低,且公司在事故调查中采取了阻碍态度。
  • 特斯拉的 Autopilot 系统在司机使用油门时会弹出警告,表明车辆不会刹车。
  • 特斯拉从法庭隐瞒的数据揭示了系统未能发出紧急接管警告,以及在接近 T 型路口时未能自动减速。
  • 特斯拉的 Autopilot 系统与飞机自动驾驶系统不可同日而语,后者有严格的培训和公开的事故调查。
  • 特斯拉的 Autopilot 系统与巡航控制功能存在误导性,可能导致司机误解其功能。
  • 特斯拉的高管如果不想在特定方面显得无能,他们完全有能力改变现状,但他们选择不这么做。

So you want to parse a PDF? #

https://eliot-jones.com/2025/8/pdf-parsing-xref

这篇文章讨论了如何解析 PDF 文件的挑战和复杂性,主要内容可以总结如下:

理想的 PDF 解析流程 #

  1. ** 定位版本头部 **:在文件开头找到版本头部注释。
  2. ** 找到交叉引用(xref)指针 **:定位到指向交叉引用表的指针。
  3. ** 获取所有对象偏移量 **:通过交叉引用表获取各个对象的位置。
  4. ** 构建尾部字典 **:找到尾部字典,它指向目录字典。

PDF 对象简介 #

  • PDF 对象包含一些有效的 PDF 内容,例如数字、字符串、字典等,并且都有自己的对象编号和代数编号。

  • 对象使用 objendobj 标记包围,例如:

16 0 obj 620 endobj

	这表示对象 16(代数 0)包含数字 620。

- PDF 文件实际上是一个对象图,这些对象可以相互引用,通过间接引用来实现。
	

### 定位交叉引用指针



- PDF 文件会声明一个交叉引用表(xref),这是一个指向每个对象存储位置的索引。

- 文件结尾会有一个指向交叉引用的指针,例如:
	```
<<% trailer>>
startxref
116
%% EOF
这表示解析器应跳转到字节偏移量 116 查找 xref 表。

现实世界中的挑战 #

尽管理论上上述过程比较简单,但在现实中,PDF 文件往往并不遵循规范,解析器在解析时会遇到多种问题:

  1. ** 交叉引用指针的问题 **:

    • 指针可能不在文件结尾或最后 1024 字节内,或者拼写错误。
    • 在随机抽样的 3977 个文件中,约 0.5% 存在错误的 xref 声明。
  2. **PDF 内容从非零偏移开始 **:

    • 有些文件在 % PDF 版本头之前会有垃圾数据,导致偏移量错误。
    • 例如,声明的 startxref 指针可能指向不正确的位置,因为前面有多余的字节。
  3. ** 交叉引用指针位于 xref 表中间 **:

    • 指针可能指向 xref 表内容的随机位置,而不是表的开始部分。
  4. ** 交叉引用偏移量错误 **:

    • 即使指针正确,xref 表中的偏移量也可能错误,可能对于某些对象是正确的,但对其他对象则不然。
  5. ** 不良格式的 xref 表 **:

    • 表头后可能没有换行,或者在表中包含了多于声明数量的对象,甚至中间出现垃圾数据。

结论 #

文章总结了根据规范解析 PDF 的理论步骤,并与实际文件的调查结果进行了对比,显示出 0.5% 的错误率。大多数 PDF 查看器(如 PDF.js、Adobe、Sumatra)能够打开这些文件,因为它们的解析器通常扩展了以支持不合规的文件。这表明解析 PDF 文件时,处理不合规情况是不可避免的挑战。


HN 热度 387 points | 评论 204 comments | 作者:UglyToad | 1 day ago #

https://news.ycombinator.com/item?id=44780353

  • PDF 支持任意附加的元数据格式,所有生成 PDF 的程序都应该以机器友好的格式附加相同信息。
  • 从实际角度来看,PDF 解析器经常将名字解析错误,因为文本在 PDF 中的放置方式导致。
  • 解析 PDF 和解析 PDF 内容之间存在巨大差异,PDF 文件基本上是“给定位置的东西”,并非“边界框内的良好格式文本”。
  • 可访问性树可以帮助改善简历解析器的准确性,但并非所有 PDF 渲染器都生成可访问的 PDF。
  • PDF 的使用在很多情况下是对抗性的,例如用于简历以阻止中间人编辑。
  • 红 action 仅通过在内容上画框并不是真正的红 action,这在过去导致了信息泄露。
  • PDF 的卖点是“文档”在任何地方都能正确显示,如果需要访问底层数据,应该单独提供 CSV 或其他格式。
  • PDF 是为人类而非计算机设计的,问题不在于 PDF 本身,而在于它们的用户。
  • 如果解决方案涉及说服 PDF 生产者提供结构化数据,那么最好完全放弃 PDF,只生产结构化数据。
  • 将简历以 PDF 格式发送可以避免黑客攻击和打开攻击的大门。
  • Geoff 问题可以通过不在 PDF 中放入连字来轻松解决,不需要全世界的合作。
  • 改变所有解析器并不实际,Adobe 也无法实现这一点。
  • 如果基于不可见的元数据运行,会导致视觉检查的 PDF 与解析数据不同。
  • 基于元数据运行会打开不同类型的问题,视觉检查的 PDF 与解析数据不同。
  • 许多工具(如 Paperless)会将 PDF 光栅化以避免这些不一致性。
  • 解决方案是创建一个全新的文件格式。
  • 对于扫描的手写文档或类似情况,如果扫描仪/消费级计算机没有完美的 OCR,该怎么办?
  • 理想情况下,PDF 应该包含可访问性和元数据,但现实中很少见,也很难获取这些元数据。
  • XML 的失败是因为它承诺的格式化和转换工具/语言没有实现,而不是因为技术问题。
  • ff 可能被渲染为连字。

Objects should shut up #

https://dustri.org/b/objects-should-shut-the-fuck-up.html

作者拥有一辆双燃料小汽车,使用汽油和 LPG(液化石油气),LPG 价格更便宜,有助于减少汽车相关预算。但当 LPG 油箱快空时,汽车会发出刺耳的响声提醒车主,这令作者感到困扰,尤其是在高速驾驶时。此外,当 LPG 油箱即将耗尽时,汽车的仪表盘会显示全屏警告,而仪表盘底部一直显示 LPG 油箱的当前水平。作者认为,汽车只有在发生严重问题时才应该发出噪音,比如机油水平急剧下降。他不喜欢汽车因为 LPG 油箱只能再行驶约 100 公里而发出警告,尤其是当他的汽油箱还是满的,总共可以行驶约 1000 公里。

作者认为,除了最紧急的情况外,发出噪音应该是默认关闭的,只有用户可以明确授权,而不是所有电子设备默认都发出噪音。作为一名网络安全专业人士,作者拥有的智能设备很少,但他发现自己仍然有一些发出噪音的设备。例如,他的洗衣机在完成一个周期时会发出刺耳的警报,这可以通过一个隐藏的菜单禁用。虽然这种警报可能有助于防止人们忘记正在浸泡的衣服,但警报声音非常大,只持续几秒钟,几乎没用。此外,洗衣机每次转动旋钮或按下按钮时都会发出“哔”声,无法关闭。作者质疑这种设计的必要性,并认为对于视觉障碍者来说,所有按钮都是触摸敏感的,所有音调都相同,除了惊醒或惊吓睡眠中的家庭成员外,毫无用处。

作者还提到了其他家电,如烘干机、炉灶和婴儿监视器,它们都会发出不必要的噪音。他讽刺地想象如果所有物品都发出类似的噪音,生活将变得多么荒谬。幸运的是,并非所有物品都如此糟糕。作者提到了他的洗碗机、冰箱和电子书阅读器,这些设备都没有噪音,或者在需要时发出适当的警告。

最后,作者呼吁设计物品时,应该考虑到通知机制对已经充满通知的现实生活的影响,尤其是在测试这些机制时,应该考虑到它们对睡眠中的婴儿或睡眠不足的人的影响。


HN 热度 266 points | 评论 204 comments | 作者:gm678 | 9 hours ago #

https://news.ycombinator.com/item?id=44786367

  • 安全行业中,尤其是航空领域,“警报疲劳"是一个严重的问题,飞行员的情境带宽有限,应避免不必要的干扰。
  • 有些设备应该有"静噪"开关,以平衡警告飞行员与不干扰他们执行重要任务之间的关系。
  • 频繁发生的事件用语音提示更令人厌烦,而罕见事件用蜂鸣编码提示更令人厌烦,会降低情境意识。
  • 航空业存在"废话 NOTAMS"的问题。
  • 静噪开关可以调整阈值,使低于该阈值的模拟无线电信号被静默,以忽略噪声。
  • 静噪开关设置一个最小值,只有当输入信号高于某个分贝值时才会放大,低于该值的噪声则被静默。
  • 汽车中的前向注意力警告功能令人烦恼,因为它会因为驾驶员未向前看而发出高声蜂鸣并闪烁图标。
  • 欧盟的"安全特性"越来越多地侵入,实际上可能使汽车更不安全。
  • 欧盟要求新车必须有车道辅助功能,并且必须自动开启,使用至少两种方法警告驾驶员:声音、视觉、触觉。
  • 有人认为车道保持辅助功能实际上可能显著降低致命事故,减少约 20% 至 25% 的死亡。
  • 有研究显示,车道偏离警告和预防系统可能减少约 23% 涉及乘用车的致命事故。
  • 有观点认为,车道保持辅助功能可能在统计上减少了事故,但具体到强制性的触觉反馈(如方向盘震动)可能并不总是有益的。
  • 有人认为,车道保持辅助功能在没有中心线的乡村道路上可能会导致安全风险,自动转向可能与迎面而来的大型车辆相撞。

Typed languages are better suited for vibecoding #

https://solmaz.io/typed-languages-are-better-suited-for-vibecoding

Onur Solmaz 在他的博客中讨论了编程习惯的变化,特别是在 Claude Code 推出后,他发现对于新项目,Python 不再是首选语言。他现在更多地使用 TypeScript、Rust 和 Go 这些类型化、编译型语言来管理项目,并且取得了不错的效果。他认为这些语言因为提供了安全保障,更适合于所谓的“vibecoding”。尽管这与他过去总是用 Python“vibe”项目的习惯相反,但现在看起来这是有道理的。

Solmaz 指出,对于一定规模的项目,使用 Claude Code 和 Rust 等工具,他能够比使用 Python 更快更安全地移动,尽管 Rust 是低级语言。这完全是因为 AI 工具的帮助。例如,他在 TextCortex 重构了大量 TypeScript 前端代码。Claude Code 在完成每个任务后运行 tsc,并确保代码在提交前编译通过。这让他的代码改动速度比在 Python 中快得多,Python 不提供编译时的安全保证。他对于在几个小时内创建的 3-5k 行代码差异没有破坏任何东西,甚至提高了稳定性感到惊讶。

Solmaz 承认大型语言模型(LLMs)是有缺陷的抽象,但它们现在足够好,以至于它们解决了 Python 为他解决的问题(快速原型制作),而没有 Python 的缺点(较低的安全保证、慢速、模糊不清)。因此,他预测 Python 在公司中的采用将会减少,特别是在生产部署中,尽管他非常喜欢 Python。

一些人可能会说,即使没有 AI 工具,情况也是如此。对此,Solmaz 回应说,这取决于情况。


HN 热度 256 points | 评论 215 comments | 作者:hosolmaz | 24 hours ago #

https://news.ycombinator.com/item?id=44780878

  • 人们在不熟悉的领域倾向于认为信息源是可靠的,就像作者在不精通的语言中管理项目时感觉良好一样。
  • 使用 Rust 和 Claude 时,由于 Rust 代码编译通过的代码通常效率低下且不美观,Claude 会错误地生成关于 Rust 的信息。
  • LLMs 在生成 Rust 代码方面表现不佳,可能是因为 Rust 代码在训练数据中较少,或者因为 Rust 有许多陷阱和复杂的标准库。
  • 使用 Claude 编写 Rust 代码时,遵循特定提示可以获得较好的结果,例如数据库表的 CRUD 端点创建。
  • 在使用 LLMs 编写 Rust 代码方面,与 Java、Kotlin 和 Swift 相比,效果差不多,但不如 Python。
  • 强类型/静态类型语言通过解析和类型检查快速反馈循环,可以更快地迭代。
  • LLMs 在理解 Rust 语言语义方面存在困难,因为它们不理解 Rust 语言没有某些问题。
  • 可以编写 Rust 中的 use-after-free 错误,尽管它不会编译,但对于非编译程序如 LLM 来说并不重要。
  • Python 的类型检查并不总是容易,即使是人类开发者也会花费大量时间与类型检查器和存根作斗争。
  • 输入对 LLMs 的输出质量有很大影响,通过测试周期、反思产品实现契合度的提示和大量互动可以提高输出质量。
  • 通过访问 MCP 工具,使用 Claude 编写 Rust 代码可以获得很好的体验。
  • 有建议使用静态分析工具来限制 LLMs 编写代码的方式。
  • 程序员本身就是一种静态分析工具,没有它们,LLMs 的输出不会太有用。
  • 已经尝试过使用静态分析工具来限制 LLMs 的输出,但效果不佳。
  • 模型有时需要发出尚未有效的标记,但稍后会变得有效。
  • 原本可以通过访问下一个标记的概率来限制 LLMs 的输出,但由于这容易泄露权重,OpenAI 关闭了这个功能。

Hacker News 精彩评论及翻译 #

Job-seekers are dodging AI interviewers #

https://news.ycombinator.com/item?id=44785645

I did one of these once. Once.

I felt so bad afterwards that I swore them off forever.

It’s not like the ‘interview’ was terrible or anything. I knew it was AI from the start.

It was just that when I got done with it, I realized that I had talked at a computer for ~45 minutes. And, yet again, I was going to be ghosted by the company (I was), and that I was never going to get those 45 minutes back. That was time I could have used to apply for another job, or cook, or sleep, or exercise, or spend time with family. But no, like an idiot, I talked at a bot for that time for literally no reason.

Like, sure maaaaybe the company is going to use it as a screen for ‘real’ people. But the odds that it’s not just another hoop they have for you to jump through are nil. If they send an AI ‘interview’ at you, that’s the exact same as an email requesting yet more portfolio submissions. Pointless.

Balgair

我就做过一次,就那一次。 之后我后悔得要命,发誓永不再碰。 倒不是说这场“面试”有多糟糕,从一开始我就知道那是人工智能。 只不过当我做完的时候,我才意识到自己竟然对着电脑说了大约45分钟的话。 而且,我又得被这家公司“鸽”了(事实也确实如此),而且我的那45分钟再也回不来了。 那段时间我本可以用来申请另一份工作,或者做做饭,或者睡睡觉,或者去锻炼身体,或者陪陪家人。 但可惜啊,我这个傻瓜,就这么对着一个机器人毫无意义地聊了半天。 好吧,也许公司会用它来作为筛选“真人”的工具。但它纯纯就是又一个让你费力跳过去的圈套,这种可能性为零。 如果他们给你发AI“面试”,那和索要更多作品集的邮件,本质上是一码事。毫无意义。


Mastercard deflects blame for NSFW games being tak… #

https://news.ycombinator.com/item?id=44784378

I’m glad the Mastercard-Visa duopoly is finally getting some attention, these companies shouldn’t be allowed to exercise the financial control they do. Payment infrastructure is not a free market - you can’t just choose to pay via some other processor if they turn you down, they ARE the processors. Therefore, they should be under intense scrutiny when they refuse.

cedws

很高兴万事达卡和维萨卡的双头垄断局面终于开始受到关注。这些公司绝不应该被允许实施它们现在所拥有的那种金融控制。支付基础设施并非自由市场——如果他们拒绝为你提供服务,你根本无法选择其他的支付处理方,因为他们就是支付处理方本身。因此,当他们在拒绝时,就应该受到严密的审查。


If you’re remote, ramble #

https://news.ycombinator.com/item?id=44776874

“I see you’ve only had 15 rambles this week”

“Isn’t 15 the minimum?”

“Well, yeah, if you just want to do the bare minimum. But look at Todd over there - he has 37 rambles”

“Well if you wanted people to have 37 rambles why wouldn’t you make that the minimum”

ronbenton

我看你这周才做了15项 15项不就是下限吗? 嗯,是啊,如果你只想做最低要求的话。不过你看托德,他有37项。 如果想让我们做到37项,那为什么不直接设成最低要求呢?