Cloudflare Workers 处理函数计算中的 CPU 性能问题

<p>原文: <a href="https://blog.cloudflare.com/unpacking-cloudflare-workers-cpu-performance-benchmarks/">https://blog.cloudflare.com/unpacking-cloudflare-workers-cpu-performance-benchmarks/</a></p> <p>原文主要讲述了 Cloudflare Workers 和 Vercel 在 CPU 性能方面的一些对比, 在应用上的重点是 React SSR 类应用的 TTFB 测试.</p> <p>其中我认为的一些关键点是:</p> <ol> <li>函数计算的调度问题 (非 CPU 计算消耗).</li> <li>Node.js 对 V8 调参导致的性能问题.</li> <li>代码中处理 buffer 不当导致的内存占用及后续 GC 的问题.</li> <li>Node.js 的非 Web 标准化问题, 比如 Streams API.</li> <li>Cloudflare Workers 团队在解决自己问题的过程中如果发现了生态问题, 甚至竟品问题, 也期望一并解决.</li> </ol> <p>我们的核心业务均由函数计算承担, 在此处有许多经验. 函数计算中的几大时间消耗为:</p> <ol> <li>调度时间</li> <li>(可能) 冷启动时间</li> <li>执行时间 (被计算为 CPU 消耗)</li> </ol> <p>一般来说, “执行时间” 与函数计算无关. 函数计算需要重点考虑的, 是 “调度时间” 和 “冷启动时间”.</p> <p>作为用户, 一些配置会影响到调度时间, 比如使用什么操作系统, 是否要接入 VPC 等.</p> <p>想要优化冷启动时间, 则应该将重点放在 “架构” 上. 一般来说, 解释型语言的冷启动时间会小很多. 比如函数计算一般使用 Python, JavaScript, 而不使用 Java.</p> <p>另外一种优化就是 “预热”, 可以理解为提前启动. 但是预热是有成本开销的, 并且我认为预热是有悖于函数计算模式的. 我更倾向于减少冷启动时间, 而不是预热.</p> <p>Cloudflare Workers 针对调度问题的优化, 是所有用户乐于看到的. 加量不加价, 并且默认生效, 用户无需任何额外配置.</p> <p>Node.js 的非 Web 标准化问题, 就是我们几年前选型 Deno, 而非 Node.js 的关键原因. 即便我们不是全栈团队, 也希望在 JS 领域, 技术栈尽量统一, 减少不必要的消耗.</p> <p>最后, 看到问题就想要去解决, 无论这个问题是否影响到自身利益, 这不仅是工程师应该有的素质, 也是每一个人应该有的素质. 就像走路时如果看到了脚边的垃圾, 可以顺手捡起来扔到垃圾箱中.</p> <p>不是鼓励大家无偿奉献, 而是举手之劳, 何乐而不为? 每个人多付出 1%, 就会让整个世界进步不只 100%.</p>

2025/10/16
阅读更多

Deno Fresh 2.x 支持 Vite

<p>Update:</p> <ul> <li>目前 Fresh 文档默认的版本已经是 2.x.</li> </ul> <hr /> <p>在许多前端项目中, 都使用 Vite 处理构建流程.</p> <p>对于 Deno 团队来说, Node.js 生态下的项目, 如 ESLint 等一直是受到排斥的. 基于零配置易用性及性能考虑, Deno 会在相关领域重做一套工具, 比如 deno lint, fmt.</p> <p>不过随着 Deno 对 Node.js 兼容性的增强, Deno 团队对 Node.js 生态也越来越包容.</p> <p>现在, Deno 官方项目 Fresh 会主动集成 Vite (而不是 deno compile 或者刚刚恢复的 deno bundle).</p> <p>官方 Blog 文章: <a href="https://deno.com/blog/fresh-and-vite">Fresh 2.0 Graduates to Beta, Adds Vite Support</a></p> <p><code class="language-plaintext highlighter-rouge">deno compile</code> 一直没有实现一键打包 Deno Fresh 项目. 或许跟 Fresh 特殊的路由策略有关.</p> <p>但是 Vite 是支持在编译时处理动态路由并且打包的, 也支持代码分割.</p> <p>在官方文章中, 主要介绍了下面几个功能:</p> <ol> <li>借助 Vite 的 岛内热加载, 而不是全页热加载.</li> <li>借助 Vite 的 服务器代码打包, 加快启动时间.</li> <li>借助 Vite 的 React 别名.</li> <li>回归的 <code class="language-plaintext highlighter-rouge">Head</code> 组件</li> </ol> <p>Fresh 2.0 正式进入 beta, 不再会有重大变动. 现在就可以尝试了.</p>

2025/9/3
阅读更多

TypeScript 使用 Go 进行了重构

<p>我在 GitHub 上看到了 @ahejlsberg 为 <a href="https://github.com/microsoft/typescript-go">https://github.com/microsoft/typescript-go</a> project 点了 star.</p> <p>在 11 日, TypeScript 官方博客发布了一篇名为 <a href="https://devblogs.microsoft.com/typescript/typescript-native-port/">A 10x Faster TypeScript</a> 的文章, 介绍了微软正在使用 Go 语言重写 TypeScript 编译器, 并取得了显著的性能提升.</p> <p>Anders Hejlsberg 是 TypeScript 的主要设计者, 也是 C# 和 Delphi 的最初设计者. 为了解决性能问题, 他带领的团队没有使用 C# 或者 Rust 等语言, 而是使用了 Go, 在社区中引起了一些质疑的声音.</p> <p>我认为最重要的原因就是新项目是 “port”, 而不是 “rewrite”. 在一众备选项中, Go 的语法是最容易从 TypeScript 迁移过去的.</p> <p>我理解微软开发团队这样的做法, 比如 VS Code 在宣传的时候也会使用 create-react-app 这样的 Facebook 项目来宣传. 可见, 微软想要与技术社区进行融合的意愿很强.</p> <h2 id="为什么选择-go">为什么选择 Go?</h2> <p>根据 TypeScript 官方博客 <a href="https://devblogs.microsoft.com/typescript/typescript-native-port/">A 10x Faster TypeScript</a> 的介绍, 微软选择 Go 语言进行编译器移植的原因主要包括:</p> <ol> <li><strong>可维护性</strong>: Go 语言拥有高效且易于理解的垃圾收集器, 简单易学的语法以及良好的 开发者生态系统, 使得维护大型代码库更加容易</li> <li><strong>性能优势</strong>: Go 编译器的多方面优化使其非常适合构建编译器这类程序, 并且与 JavaScript 版本相比, 能够显著提高编译速度</li> <li><strong>跨平台能力</strong>: Go 的原生编译特性让 TypeScript 编译器能够轻松构建为适用于 各种操作系统的单一二进制文件</li> <li><strong>开发效率</strong>: Go 语言的错误处理模式, 简单的语法和快速的编译时间, 让开发团队能够快速迭代和实现功能</li> </ol> <p>C/C++ 的跨平台能力较差, 比如不支持简单编译为各个平台的单一二进制文件. 而 Rust 的内存安全模型过于复杂, 不适合作为 port 项目. C# 应该更多是语言特性上与 TypeScript 有区别, 严格的 OOP 风格不适合作为 port.</p> <h2 id="当前进展与兼容性">当前进展与兼容性</h2> <p><a href="https://github.com/microsoft/typescript-go">repo</a> 的 init commit 是 2024-10-01 <a href="https://github.com/microsoft/typescript-go/commit/cdcc0cb808d8ad0c91d9520edac3d815bff92514">https://github.com/microsoft/typescript-go/commit/cdcc0cb808d8ad0c91d9520edac3d815bff92514</a>, 仅用大概半年的时间, 就取得了显著的进展, 据说完成了 80% 的代码迁移.</p> <p>根据 GitHub 仓库的 README 文档, TypeScript 的 Go 原生移植版(称为”TypeScript 7”) 目前仍处于积极开发阶段. 当前已完成的功能包括:</p> <ul> <li>程序创建(读取 <code class="language-plaintext highlighter-rouge">lib</code>, <code class="language-plaintext highlighter-rouge">target</code>, <code class="language-plaintext highlighter-rouge">reference</code> 等配置)</li> <li>解析/扫描(读取源文本并确定语法结构)</li> <li>命令行和 <code class="language-plaintext highlighter-rouge">tsconfig.json</code> 解析</li> <li>类型解析和类型检查</li> </ul> <p>为了实现迁移, 微软会在 TypeScript 6 (仍然是 TypeScript) 的时候, 做一些功能调整, 以保证将来发布 TypeScript 7 (Go 版本) 时大家可以无缝迁移.</p> <p>TypeScript 6 和 TypeScript 7 的 API 是完全兼容的, 所以开发者可以随时升级或降级. 在 TypeScript 7 被完全接受前, TypeScript 6 会继续开发, 以作为备选.</p> <h2 id="社区反应">社区反应</h2> <p>这一项目在公布后引起了开发社区的广泛关注, 截至目前 GitHub 仓库已获得超过 11.9k 的星标. 许多开发者对于提升 TypeScript 性能的前景表示期待, 特别是那些处理大型 代码库的团队.</p> <p>社区讨论主要集中在性能提升, 工具链兼容性以及 <a href="https://github.com/microsoft/typescript-go/discussions/411">为什么选择 Go</a> 而非其他语言 (如 Rust) 上.</p> <h2 id="相关链接">相关链接</h2> <ul> <li><a href="https://devblogs.microsoft.com/typescript/typescript-native-port/">A 10x Faster TypeScript</a></li> <li><a href="https://github.com/microsoft/typescript-go">GitHub 仓库: typescript-go</a></li> </ul>

2025/3/13
阅读更多

JS 中的链式调用

<h2 id="数组中的链式调用">数组中的链式调用</h2> <div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">numbers</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">];</span> <span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">numbers</span> <span class="p">.</span><span class="nx">filter</span><span class="p">(</span><span class="nx">n</span> <span class="o">=&gt;</span> <span class="nx">n</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="c1">// 过滤偶数</span> <span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">n</span> <span class="o">=&gt;</span> <span class="nx">n</span> <span class="o">*</span> <span class="mi">2</span><span class="p">)</span> <span class="c1">// 每个数乘以2</span> <span class="p">.</span><span class="nx">reduce</span><span class="p">((</span><span class="nx">sum</span><span class="p">,</span> <span class="nx">n</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">sum</span> <span class="o">+</span> <span class="nx">n</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="c1">// 求和</span> </code></pre></div></div> <p>但是仅限于数组, 如果想要在其他对象上实现链式调用, 就需要自定义方法.</p> <h2 id="多变量链式调用">多变量链式调用</h2> <p>为了可以对任何数据使用自定义方法, 我们可以这样做:</p> <div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">add</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">x</span> <span class="o">+</span> <span class="nx">y</span><span class="p">;</span> <span class="p">}</span> <span class="kd">function</span> <span class="nx">multiply</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="nx">y</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">x</span> <span class="o">*</span> <span class="nx">y</span><span class="p">;</span> <span class="p">}</span> <span class="kd">let</span> <span class="nx">num</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="kd">let</span> <span class="nx">num2</span> <span class="o">=</span> <span class="nx">add</span><span class="p">(</span><span class="nx">num</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span> <span class="kd">let</span> <span class="nx">num3</span> <span class="o">=</span> <span class="nx">multiply</span><span class="p">(</span><span class="nx">num2</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span> <span class="kd">let</span> <span class="nx">num4</span> <span class="o">=</span> <span class="nx">add</span><span class="p">(</span><span class="nx">num3</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">num4</span><span class="p">);</span> <span class="c1">// 13</span> </code></pre></div></div> <p>这种做法的缺点是额外增加了许多变量, 为了这些变量要进行许多不必要的命名.</p> <h2 id="多函数嵌套链式调用">多函数嵌套链式调用</h2> <p>为了避免不必要的命名, 我们可以直接调用:</p> <div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">add</span><span class="p">(</span><span class="nx">multiply</span><span class="p">(</span><span class="nx">add</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">),</span> <span class="mi">2</span><span class="p">),</span> <span class="mi">3</span><span class="p">);</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">result</span><span class="p">);</span> <span class="c1">// 13</span> </code></pre></div></div> <p>可是这样做后, 代码的可读性很差.</p> <h2 id="对象方法链式调用">对象方法链式调用</h2> <div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nx">Calculator</span> <span class="p">{</span> <span class="kd">constructor</span><span class="p">()</span> <span class="p">{</span> <span class="k">this</span><span class="p">.</span><span class="nx">value</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="nx">add</span><span class="p">(</span><span class="nx">n</span><span class="p">)</span> <span class="p">{</span> <span class="k">this</span><span class="p">.</span><span class="nx">value</span> <span class="o">+=</span> <span class="nx">n</span><span class="p">;</span> <span class="k">return</span> <span class="k">this</span><span class="p">;</span> <span class="p">}</span> <span class="nx">multiply</span><span class="p">(</span><span class="nx">n</span><span class="p">)</span> <span class="p">{</span> <span class="k">this</span><span class="p">.</span><span class="nx">value</span> <span class="o">*=</span> <span class="nx">n</span><span class="p">;</span> <span class="k">return</span> <span class="k">this</span><span class="p">;</span> <span class="p">}</span> <span class="nx">getValue</span><span class="p">()</span> <span class="p">{</span> <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">value</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="kd">const</span> <span class="nx">calc</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Calculator</span><span class="p">();</span> <span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">calc</span> <span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> <span class="p">.</span><span class="nx">multiply</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="p">.</span><span class="nx">getValue</span><span class="p">();</span> <span class="c1">// 13</span> </code></pre></div></div> <p>但是需要额外新增对象, 并且许多时候函数作为方法并不合适.</p> <h2 id="promise-中的链式调用">Promise 中的链式调用</h2> <p>为了解决上述问题, 我们可以使用 Promise 的链式调用:</p> <div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="k">await</span> <span class="nb">Promise</span><span class="p">.</span><span class="nx">resolve</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">x</span> <span class="o">=&gt;</span> <span class="nx">add</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span> <span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">x</span> <span class="o">=&gt;</span> <span class="nx">multiply</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span> <span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">x</span> <span class="o">=&gt;</span> <span class="nx">add</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span> <span class="mi">3</span><span class="p">));</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">result</span><span class="p">);</span> <span class="c1">// 13</span> </code></pre></div></div> <p>并且这种做法可以仅仅使用匿名函数, 不使用函数, 在一些小变动的时候很方便:</p> <div class="language-ts highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="k">await</span> <span class="nb">Promise</span><span class="p">.</span><span class="nx">resolve</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">x</span> <span class="o">=&gt;</span> <span class="nx">x</span> <span class="o">+</span> <span class="mi">5</span><span class="p">)</span> <span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">x</span> <span class="o">=&gt;</span> <span class="nx">x</span> <span class="o">*</span> <span class="mi">2</span><span class="p">)</span> <span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">x</span> <span class="o">=&gt;</span> <span class="nx">x</span> <span class="o">+</span> <span class="mi">3</span><span class="p">);</span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">result</span><span class="p">);</span> <span class="c1">// 13</span> </code></pre></div></div> <p>目前这是我最常用的方法. 但是缺点是强制将代码转为了异步.</p> <h2 id="js-pipe-operator-管道操作符-提案">JS Pipe Operator (管道操作符) 提案</h2> <p><a href="https://github.com/tc39/proposal-pipeline-operator">https://github.com/tc39/proposal-pipeline-operator</a></p> <p>参考了几种语言的语法:</p> <ol> <li>Hack</li> <li>F#</li> </ol> <p>另外, 许多其他语言也有类似语法, 比如 Elixir.</p>

2025/1/14
阅读更多

Flutter Web 开发注意事项

<h2 id="注意事项">注意事项</h2> <ol> <li>为了更好支持 web WebAssembly, 建议 Flutter 版本 &gt;= 3.24.</li> <li>可以使用 <a href="https://flutterweb-wasm.web.app/">https://flutterweb-wasm.web.app/</a> 测试 Flutter Web 的性能.</li> <li>目前默认使用 canvaskit 渲染, 性能较差. 如果使用 wasm 构建, 则使用 Skwasm 渲染.</li> <li>Safari 17.5, Firefox 133 目前渲染目前会回退到 canvaskit, 性能较差.</li> </ol> <h2 id="编译参数">编译参数</h2> <p><code class="language-plaintext highlighter-rouge">flutter run</code> 和 <code class="language-plaintext highlighter-rouge">flutter build web</code> 命令的参数:</p> <ul> <li><code class="language-plaintext highlighter-rouge">--wasm</code> 使用 wasm 的方式构建 <ul> <li>如 <code class="language-plaintext highlighter-rouge">flutter run -d chrome --wasm</code></li> <li>如 <code class="language-plaintext highlighter-rouge">flutter build web --wasm</code></li> </ul> </li> </ul> <h2 id="包">包</h2> <p>参考 Flutter 文档: <a href="https://docs.flutter.dev/platform-integration/web/renderers">https://docs.flutter.dev/platform-integration/web/renderers</a>, 开发时不建议使用的包有:</p> <ol> <li><code class="language-plaintext highlighter-rouge">dart:html</code>, 建议使用 <code class="language-plaintext highlighter-rouge">package:web</code> 替代. 以使用 WebAssembly 方式构建.</li> <li><code class="language-plaintext highlighter-rouge">dart:js</code>, 建议使用 <code class="language-plaintext highlighter-rouge">dart:js_interop</code> 替代. 以使用 WebAssembly 方式构建.</li> <li><code class="language-plaintext highlighter-rouge">dart:js_util</code>, 建议使用 <code class="language-plaintext highlighter-rouge">dart:js_interop</code> 替代. 以使用 WebAssembly 方式构建.</li> <li><code class="language-plaintext highlighter-rouge">package:js</code>, 建议使用 <code class="language-plaintext highlighter-rouge">dart:js_interop</code> 替代. 以使用 WebAssembly 方式构建.</li> </ol>

2024/12/31
阅读更多

软件架构与实验艺术

<blockquote> <p>:bulb: 原文链接: <a href="https://www.infoq.com/articles/architecture-experimentation/">https://www.infoq.com/articles/architecture-experimentation/</a></p> </blockquote> <p>在软件架构领域, 我们经常会做出许多决策. 有些决策会带来积极的影响, 而有些则会产生消极的后果. 在做出这些决策时, 我们往往会陷入两难境地:</p> <ol> <li>我们希望做出正确的决策</li> <li>我们无法预知未来</li> </ol> <p>这就像是在玩一个概率游戏. 我们可以通过研究, 分析和经验来提高做出好决策的概率, 但我们永远无法完全确定某个决策就一定是正确的.</p> <h2 id="通过实验来验证决策">通过实验来验证决策</h2> <p>在这种情况下, 唯一合理的方法就是通过实验来验证我们的决策. 这意味着:</p> <ul> <li>承认我们可能会犯错</li> <li>设计实验来测试我们的假设</li> <li>收集数据来验证决策的效果</li> <li>准备好在需要时调整或改变方向</li> </ul> <p>让我给您举个例子. 假设您正在开发一个新的在线零售平台, 需要决定使用哪种数据库技术. 您可能会考虑:</p> <ul> <li>关系型数据库(如 PostgreSQL)</li> <li>NoSQL 解决方案(如 MongoDB)</li> <li>分布式数据存储系统</li> </ul> <p>与其仅仅基于理论讨论做出选择, 不如设计一些实验来测试每种选项在您的具体场景中的表现.</p> <h2 id="最小可行架构mva">最小可行架构(MVA)</h2> <p>最小可行架构(MVA)是一个重要概念, 它强调:</p> <ol> <li>从最简单的可工作方案开始</li> <li>通过实验逐步验证和改进</li> <li>在实际使用中收集反馈</li> <li>根据反馈调整架构决策</li> </ol> <p>MVA 与最小可行产品(MVP)的理念相似, 但关注点是技术架构而不是业务功能.</p> <h2 id="实验的重要性">实验的重要性</h2> <p>在软件开发中, 每个产品发布实际上都是一系列实验的集合. 这些实验不仅关于产品功能, 还包括:</p> <ol> <li><strong>技术可行性</strong> - 选择的技术方案是否真的能够实现预期目标</li> <li><strong>可维护性</strong> - 系统是否容易维护和更新</li> <li><strong>可扩展性</strong> - 系统能否应对增长需求</li> <li><strong>运营成本</strong> - 解决方案在财务上是否可持续</li> </ol> <h3 id="实验设计的关键要素">实验设计的关键要素</h3> <p>好的架构实验应该包含以下要素:</p> <ol> <li><strong>明确的假设</strong> <ul> <li>清晰陈述我们认为会发生什么</li> <li>为什么我们认为会这样</li> <li>这些假设基于什么依据</li> </ul> </li> <li><strong>可测量的目标</strong> <ul> <li>具体的性能指标</li> <li>明确的成功标准</li> <li>可量化的结果</li> </ul> </li> <li><strong>实验方法</strong> <ul> <li>如何进行测试</li> <li>需要收集什么数据</li> <li>如何收集这些数据</li> </ul> </li> <li><strong>风险控制</strong> <ul> <li>失败后的回退方案</li> <li>对系统其他部分的影响评估</li> <li>如何隔离实验的影响范围</li> </ul> </li> <li><strong>时间框架</strong> <ul> <li>实验持续时间</li> <li>关键时间节点</li> <li>评估周期</li> </ul> </li> </ol> <h3 id="实验的实际案例">实验的实际案例</h3> <p>让我们看一个具体的例子:</p> <p>假设一个团队正在考虑将单体应用迁移到微服务架构。他们可以这样设计实验:</p> <p>实验名称:核心功能微服务迁移测试</p> <p>假设:</p> <ul> <li>将订单处理模块拆分为独立微服务将提高系统扩展性</li> <li>服务间通信不会显著影响性能</li> </ul> <p>测试方法:</p> <ol> <li>选择一个非关键时段</li> <li>将订单处理模块拆分为独立服务</li> <li>部署到生产环境的隔离区域</li> <li>使用影子流量进行测试</li> </ol> <p>成功标准:</p> <ul> <li>响应时间不超过现有系统的 120%</li> <li>系统资源使用率保持在可接受范围</li> <li>服务间通信延迟低于 50ms</li> </ul> <p>回退计划:</p> <ul> <li>保留原有系统运行</li> <li>准备快速切换回原架构的脚本</li> <li>预设故障转移机制</li> </ul> <h3 id="实验的陷阱">实验的陷阱</h3> <p>在进行架构实验时,需要注意避免以下常见陷阱:</p> <ol> <li><strong>范围过大</strong> <ul> <li>试图一次性解决太多问题</li> <li>实验周期过长</li> <li>难以确定具体问题的根源</li> </ul> </li> <li><strong>指标模糊</strong> <ul> <li>成功标准不够具体</li> <li>缺乏量化指标</li> <li>难以做出客观评判</li> </ul> </li> <li><strong>忽视成本</strong> <ul> <li>未考虑实验失败的代价</li> <li>忽视长期维护成本</li> <li>低估迁移成本</li> </ul> </li> </ol> <h2 id="实验驱动的架构演进">实验驱动的架构演进</h2> <h3 id="渐进式变更">渐进式变更</h3> <p>在进行架构演进时,采用渐进式的变更策略非常重要:</p> <ol> <li><strong>小步快跑</strong> <ul> <li>将大型变更分解成小的、可管理的步骤</li> <li>每个步骤都可以独立验证</li> <li>降低每次变更的风险</li> </ul> </li> <li><strong>持续验证</strong> <ul> <li>在每个阶段收集反馈</li> <li>及时发现问题并调整</li> <li>建立度量标准来评估进展</li> </ul> </li> <li><strong>保持可逆性</strong> <ul> <li>确保每个变更都是可回退的</li> <li>维护多个系统版本的能力</li> <li>准备应急方案</li> </ul> </li> </ol> <h3 id="实验的生命周期">实验的生命周期</h3> <p>一个完整的架构实验生命周期包括:</p> <ol> <li>规划阶段 <ul> <li>定义实验目标</li> <li>设计实验方案</li> <li>确定评估标准</li> </ul> </li> <li>准备阶段 <ul> <li>搭建测试环境</li> <li>准备监控工具</li> <li>建立基准数据</li> </ul> </li> <li>执行阶段 <ul> <li>实施变更</li> <li>收集数据</li> <li>监控系统</li> </ul> </li> <li>评估阶段 <ul> <li>分析结果</li> <li>总结经验</li> <li>决定下一步</li> </ul> </li> <li>调整阶段 <ul> <li>根据结果优化</li> <li>扩大或缩小范围</li> <li>准备下一轮实验</li> </ul> </li> </ol> <h3 id="实验文化的建立">实验文化的建立</h3> <p>要在团队中建立良好的实验文化:</p> <ol> <li><strong>鼓励创新</strong> <ul> <li>接受失败作为学习的一部分</li> <li>奖励大胆尝试</li> <li>分享经验教训</li> </ul> </li> <li><strong>数据驱动</strong> <ul> <li>基于事实做决策</li> <li>建立度量体系</li> <li>重视客观反馈</li> </ul> </li> <li><strong>持续学习</strong> <ul> <li>定期回顾实验结果</li> <li>记录和分享知识</li> <li>调整实验方法</li> </ul> </li> </ol> <h3 id="实际案例研究">实际案例研究</h3> <p>让我们看一个更详细的案例:</p> <p>案例:缓存层改造实验</p> <p>背景:</p> <ul> <li>现有系统使用单机缓存</li> <li>随着用户增长,出现性能瓶颈</li> <li>考虑迁移到分布式缓存</li> </ul> <p>实验设计:</p> <ol> <li>第一阶段:小规模测试 <ul> <li>选择非核心业务模块</li> <li>部署分布式缓存集群</li> <li>监控性能和稳定性</li> </ul> </li> <li>第二阶段:负载测试 <ul> <li>模拟生产环境负载</li> <li>测试故障转移</li> <li>评估运维复杂度</li> </ul> </li> <li>第三阶段:灰度发布 <ul> <li>逐步迁移业务模块</li> <li>观察系统表现</li> <li>收集用户反馈</li> </ul> </li> </ol> <p>评估指标:</p> <ul> <li>缓存命中率</li> <li>响应时间</li> <li>系统资源使用</li> <li>运维成本</li> </ul> <h2 id="长期架构演进">长期架构演进</h2> <h3 id="平衡短期与长期目标">平衡短期与长期目标</h3> <p>在进行架构实验时,需要考虑:</p> <ol> <li><strong>短期收益</strong> <ul> <li>立即可见的性能提升</li> <li>快速解决当前问题</li> <li>用户直接感受的改进</li> </ul> </li> <li><strong>长期影响</strong> <ul> <li>技术债务的累积</li> <li>维护成本的变化</li> <li>未来的扩展性</li> </ul> </li> <li><strong>权衡因素</strong> <ul> <li>开发速度 vs 代码质量</li> <li>创新 vs 稳定性</li> <li>灵活性 vs 复杂度</li> </ul> </li> </ol> <h3 id="持续改进的策略">持续改进的策略</h3> <p>为确保架构能持续演进:</p> <ol> <li>建立反馈循环 <ul> <li>监控系统性能</li> <li>收集用户反馈</li> <li>分析运营数据</li> </ul> </li> <li>定期评估 <ul> <li>架构审查会议</li> <li>性能基准测试</li> <li>技术栈评估</li> </ul> </li> <li>适应性调整 <ul> <li>根据业务需求调整</li> <li>采纳新技术</li> <li>淘汰过时组件</li> </ul> </li> </ol> <h3 id="常见陷阱和解决方案">常见陷阱和解决方案</h3> <p>在长期架构演进中常见的问题:</p> <ol> <li><strong>过度工程</strong> <ul> <li>问题:构建超出实际需求的复杂系统</li> <li>解决:坚持”足够好”原则,循序渐进</li> </ul> </li> <li><strong>决策惯性</strong> <ul> <li>问题:因为历史原因继续使用次优方案</li> <li>解决:定期重新评估决策,保持开放心态</li> </ul> </li> <li><strong>忽视维护性</strong> <ul> <li>问题:只关注功能实现,忽视后期维护</li> <li>解决:将可维护性作为架构决策的关键指标</li> </ul> </li> </ol> <h3 id="文档和知识管理">文档和知识管理</h3> <p>保持良好的文档习惯:</p> <ol> <li>决策记录 <ul> <li>记录重要决策的原因</li> <li>记录被否决的方案</li> <li>保存相关讨论内容</li> </ul> </li> <li>实验日志 <ul> <li>详细的实验过程</li> <li>数据收集方法</li> <li>结果分析</li> </ul> </li> <li>经验教训 <ul> <li>成功和失败的案例</li> <li>意外情况的处理</li> <li>改进建议</li> </ul> </li> </ol> <h3 id="团队协作">团队协作</h3> <p>有效的团队协作对实验成功至关重要:</p> <ol> <li><strong>沟通机制</strong> <ul> <li>定期架构讨论会</li> <li>技术评审流程</li> <li>知识分享会议</li> </ul> </li> <li><strong>角色分工</strong> <ul> <li>实验负责人</li> <li>监控人员</li> <li>评估团队</li> </ul> </li> <li><strong>决策流程</strong> <ul> <li>提案机制</li> <li>评审流程</li> <li>实施审批</li> </ul> </li> </ol> <h2 id="结论与展望">结论与展望</h2> <h3 id="实验驱动的架构方法总结">实验驱动的架构方法总结</h3> <p>成功的架构实验方法建立在以下基础之上:</p> <ol> <li><strong>实验思维</strong> <ul> <li>承认不确定性的存在</li> <li>愿意通过实验来验证假设</li> <li>对失败保持开放态度</li> </ul> </li> <li> <p><strong>系统方法</strong></p> <ul> <li>明确的实验流程</li> <li>可靠的数据收集</li> <li>客观的评估标准</li> <li>完善的反馈机制</li> </ul> </li> <li><strong>持续改进</strong> <ul> <li>不断优化实验方法</li> <li>积累经验教训</li> <li>调整决策流程</li> </ul> </li> </ol> <h3 id="未来趋势">未来趋势</h3> <p>架构实验在未来可能的发展方向:</p> <ol> <li><strong>自动化实验</strong> <ul> <li>自动化测试和部署</li> <li>AI 辅助决策</li> <li>智能监控和分析</li> </ul> </li> <li><strong>混沌工程</strong> <ul> <li>主动故障注入</li> <li>弹性测试</li> <li>系统边界探索</li> </ul> </li> <li><strong>实验工具链</strong> <ul> <li>集成的实验平台</li> <li>可视化分析工具</li> <li>协作决策系统</li> </ul> </li> </ol> <h3 id="最佳实践建议">最佳实践建议</h3> <p>给架构师和开发团队的建议:</p> <ol> <li>开始时要小 <ul> <li>从小规模实验开始</li> <li>逐步增加复杂度</li> <li>积累经验和信心</li> </ul> </li> <li>保持警惕 <ul> <li>持续监控系统</li> <li>注意早期警告信号</li> <li>及时调整方向</li> </ul> </li> <li>分享知识 <ul> <li>记录和分享经验</li> <li>建立知识库</li> <li>促进团队学习</li> </ul> </li> </ol> <h3 id="结束语">结束语</h3> <p>架构实验不是一次性的活动,而是持续改进的过程。成功的关键在于:</p> <ul> <li>建立正确的实验文化</li> <li>采用系统的方法论</li> <li>保持学习和适应的能力</li> <li>重视团队协作和知识共享</li> </ul> <p>通过实验驱动的方法,我们可以:</p> <ol> <li>降低架构决策的风险</li> <li>提高系统的可靠性</li> <li>促进团队的成长</li> <li>推动技术的创新</li> </ol> <p>最终,架构实验的目标是帮助我们构建更好的系统,为用户创造更大的价值。</p> <h3 id="参考资料">参考资料</h3> <ul> <li>相关书籍和文章推荐</li> <li>实用工具和框架</li> <li>案例研究和最佳实践</li> <li>社区资源和讨论组</li> </ul> <p>这就是全文的完整翻译. 这篇文章深入探讨了软件架构中实验的重要性, 以及如何通过系统化的方法来进行架构实验和演进. 希望这个翻译对您有帮助!</p>

2024/12/25
阅读更多

OpenAI 12 Days 总结

<details lang="zh" open=""> <summary>中文版本</summary> <div> <h2 id="section">发布会</h2> <p>OpenAI 最新办了一场 12 天 “发布会”: <a href="https://openai.com/12-days/">https://openai.com/12-days/</a></p> <p>国内文章: <a href="https://www.infoq.cn/article/WXPMviOWQ1LNZhqZC5ZE">https://www.infoq.cn/article/WXPMviOWQ1LNZhqZC5ZE</a></p> <p>总结这几天的内容, 核心为:</p> <ol> <li>ChatGPT Pro 服务, 200 美元/月 (Day 1)</li> <li>正式发布 o1 模型 (Day 1, 9)</li> <li>正式发布 Sora 模型 (Day 3)</li> <li>技术预览 (微调与 o3 模型) (Day 2, 12)</li> <li>更多应用层面的更新 (创作者助手, 苹果集成, 会话整理, 多媒体信息, 搜索, 电话版 ChatGPT 等) (Day 4, 5, 6, 7, 8, 10, 11)</li> </ol> <p>应用层面的创建无疑是收入的一个重要增长点. 但是对于 OpenAI 来说, 应用不是撒手锏, 模型才是.</p> <p>所以这里面除了影响营收的 Pro 版本的收费, Sam 仅参加了模型相关发布 o1, Sora, o3.</p> <h2 id="section-1">模型</h2> <p>感觉有意义的点还不如 Ilya Sutskever 在 NeurIPS 2024 的演讲.</p> <p>不过都在一个发力: <strong>逻辑性</strong></p> <p>AI 的幻觉问题比较严重, 这个问题其实也是 AI 缺乏逻辑性的一个表现.</p> <p>可是人类的神经元就可以让自己有逻辑, 那 AI 为什么不能?</p> <p>这就是 AI 的下一步方向, 不是找更多数据, 而是利用当前数据如何让 “逻辑性” 显现.</p> <p>这种逻辑性, 而非知识性的问题我们也遇到了. 针对一些稍微复杂一点的逻辑问题, 当前主流模型都回答得不好 (应该说不对).</p> </div> </details> <details lang="en"> <summary>English Version</summary> <div> <h2 id="launch-event">Launch Event</h2> <p>OpenAI recently held a 12-day “launch event”: <a href="https://openai.com/12-days/">https://openai.com/12-days/</a></p> <p>Key announcements during these days include:</p> <ol> <li>ChatGPT Pro service at $200/month (Day 1)</li> <li>Official release of o1 model (Day 1, 9)</li> <li>Official release of Sora model (Day 3)</li> <li>Technical previews (fine-tuning and o3 model) (Day 2, 12)</li> <li>More application-level updates (Creator Assistant, Apple integration, conversation organization, multimedia handling, search, phone version of ChatGPT, etc.) (Day 4, 5, 6, 7, 8, 10, 11)</li> </ol> <p>Application-level innovations are undoubtedly an important growth point for revenue. However, for OpenAI, applications are not their trump card - models are.</p> <p>That’s why among all these announcements, Sam only participated in model-related releases: o1, Sora, and o3.</p> <h2 id="models">Models</h2> <p>The meaningful points here are not as significant as Ilya Sutskever’s speech at NeurIPS 2024.</p> <p>However, they all focus on one direction: <strong>logical reasoning</strong></p> <p>AI’s hallucination problem is quite serious, which is actually a manifestation of AI’s lack of logical reasoning ability.</p> <p>Human neurons can enable logical thinking, so why can’t AI?</p> <p>This is the next direction for AI - not finding more data, but utilizing existing data to manifest “logical reasoning”.</p> <p>We’ve also encountered this issue of logical reasoning versus knowledge. Current mainstream models don’t perform well (or more accurately, don’t perform correctly) on slightly more complex logical problems.</p> </div> </details>

2024/12/22
阅读更多

Deno 使用实践与总结

<details lang="zh" open=""> <summary>中文版本</summary> <div> <h2 id="deno-">Deno 中的依赖管理</h2> <ol> <li>直接使用 import 进行相对路径的文件引用.</li> <li>直接使用 import 进行 HTTPS 绝对路径的文件引用. 2.1. 比如使用 deno.land 的包 (仅限公共包). 2.2. 比如使用 GitHub 的包 (raw.githubusercontent.com). 2.3. 如 <a href="https://esm.sh/">https://esm.sh/</a> 2.4. 如 <a href="https://jspm.org/">https://jspm.org/</a> 2.5. 如 <a href="https://www.skypack.dev/">https://www.skypack.dev/</a> 2.6. 如 <a href="https://www.jsdelivr.com/esm">https://www.jsdelivr.com/esm</a></li> <li>引用 npm 包.</li> <li>引用 jsr 包. (仅限公共包).</li> </ol> <h3 id="jsrio-">jsr.io 包仓库</h3> <p>jsr.io 是 Deno 官方团队开发维护的一个包仓库, 可以同时发布为 Deno 和 Node.js 的包.</p> <p>如果没有 jsr.io, 如果一个包想要同时支持 Deno 和 Node.js, 那么需要维护两套代码.</p> <p>如果不想维护两套代码, 则可以构建时魔改代码, 但会受到许多约束:</p> <ol> <li>转为 Node.js 包的时候移除 <code class="language-plaintext highlighter-rouge">.ts</code> 后缀名.</li> <li>无法添加 deno 依赖.</li> <li>无法添加 Node.js 依赖.</li> </ol> <p>jsr.io 的包可以同时支持 Deno 和 Node.js, 解决了上述痛点. 但是 jsr.io 有两大问题:</p> <ol> <li>jsr.io 不支持 HTTP 绝对路径的文件引用.</li> <li>jsr.io (暂时) 不支持私有包. <a href="https://github.com/jsr-io/jsr/issues/203">https://github.com/jsr-io/jsr/issues/203</a></li> </ol> <h2 id="deno--1">Deno 运行时特点</h2> <h3 id="deno--2">Deno 中的浮点误差</h3> <p>虽然 Deno 的一大核心是 V8 引擎, 但 Deno 的运行时针对浮点计算进行了特殊处理.</p> <p>比如我们要做下面的浮点运算: <code class="language-plaintext highlighter-rouge">1.1 * 100</code></p> <ul> <li>Deno 2.1.4 (since 1.9.2) -&gt; <code class="language-plaintext highlighter-rouge">110</code></li> <li>Chrome 131 (since 90) -&gt; <code class="language-plaintext highlighter-rouge">110.00000000000001</code></li> <li>Node.js v20.11.0 -&gt; <code class="language-plaintext highlighter-rouge">110.00000000000001</code></li> </ul> <p>Deno 的运行时似乎在刻意避免浮点误差.</p> <h2 id="nodejs-">Node.js 兼容性</h2> <p>Node.js 的生态非常庞大, Deno 想要扩大运行时市场份额, 需要为在 Node.js 环境下开发的软件提供兼容性.</p> <p>在 Deno 2.x 版本中, Deno 已经尽量支持了许多 Node.js 的包.</p> <p>但是这种支持仍然有限:</p> <ol> <li>localAddress 参数没有效果. <a href="https://github.com/denoland/deno/issues/24153">https://github.com/denoland/deno/issues/24153</a></li> <li><a href="https://github.com/denoland/deno/labels/node%20compat">更多兼容问题见 issue 列表</a></li> <li><a href="https://docs.deno.com/runtime/reference/node_apis/#partially-supported-modules">Deno 支持不完善的 Node.js 功能</a></li> <li><a href="https://docs.deno.com/runtime/reference/node_apis/#unsupported-modules">Deno 暂不支持的 Node.js 功能</a></li> </ol> <h2 id="deno-api">原生 Deno API</h2> <p>目前 Deno 提供的 API 仍有限, 比如有下面的问题:</p> <ol> <li>网络请求时不支持选择网卡. <a href="https://github.com/denoland/deno/issues/27376">https://github.com/denoland/deno/issues/27376</a></li> <li>不支持 brotli 压缩. (但通过 Node.js 兼容包可实现)</li> </ol> </div> </details> <details lang="en"> <summary>English Version</summary> <div> <h2 id="dependency-management-in-deno">Dependency Management in Deno</h2> <ol> <li>Direct file imports using relative paths.</li> <li>Direct file imports using HTTPS absolute paths. 2.1. Using packages from deno.land (public packages only). 2.2. Using packages from GitHub (raw.githubusercontent.com). 2.3. From <a href="https://esm.sh/">https://esm.sh/</a> 2.4. From <a href="https://jspm.org/">https://jspm.org/</a> 2.5. From <a href="https://www.skypack.dev/">https://www.skypack.dev/</a> 2.6. From <a href="https://www.jsdelivr.com/esm">https://www.jsdelivr.com/esm</a></li> <li>Importing npm packages.</li> <li>Importing jsr packages (public packages only).</li> </ol> <h3 id="jsrio">jsr.io</h3> <p>jsr.io is a package registry developed and maintained by the Deno official team, allowing packages to be published for both Deno and Node.js.</p> <p>Without jsr.io, supporting both Deno and Node.js would require maintaining two separate codebases.</p> <p>To avoid maintaining dual codebases, code could be transformed during build time, but with several constraints:</p> <ol> <li>Removing <code class="language-plaintext highlighter-rouge">.ts</code> extensions when converting to Node.js packages.</li> <li>Cannot add Deno dependencies.</li> <li>Cannot add Node.js dependencies.</li> </ol> <p>jsr.io packages can support both Deno and Node.js, solving these pain points. However, jsr.io has two major issues:</p> <ol> <li>jsr.io doesn’t support HTTP absolute path imports.</li> <li>jsr.io (temporarily) doesn’t support private packages. <a href="https://github.com/jsr-io/jsr/issues/203">https://github.com/jsr-io/jsr/issues/203</a></li> </ol> <h2 id="deno-runtime-characteristics">Deno Runtime Characteristics</h2> <h3 id="floating-point-precision-in-deno">Floating Point Precision in Deno</h3> <p>Although V8 engine is a core component of Deno, the runtime handles floating-point calculations differently.</p> <p>For example, let’s consider this floating-point calculation: <code class="language-plaintext highlighter-rouge">1.1 * 100</code></p> <ul> <li>Deno 2.1.4 (since 1.9.2) -&gt; <code class="language-plaintext highlighter-rouge">110</code></li> <li>Chrome 131 (since 90) -&gt; <code class="language-plaintext highlighter-rouge">110.00000000000001</code></li> <li>Node.js v20.11.0 -&gt; <code class="language-plaintext highlighter-rouge">110.00000000000001</code></li> </ul> <p>Deno’s runtime appears to deliberately avoid floating-point errors.</p> <h2 id="nodejs-compatibility">Node.js Compatibility</h2> <p>With Node.js’s vast ecosystem, Deno needs to provide compatibility for software developed in Node.js environment to expand its runtime market share.</p> <p>In Deno 2.x, many Node.js packages are supported.</p> <p>However, this support is still limited:</p> <ol> <li>localAddress parameter has no effect. <a href="https://github.com/denoland/deno/issues/24153">https://github.com/denoland/deno/issues/24153</a></li> <li><a href="https://github.com/denoland/deno/labels/node%20compat">More compatibility issues in the issue list</a></li> <li><a href="https://docs.deno.com/runtime/reference/node_apis/#partially-supported-modules">Partially supported Node.js features in Deno</a></li> <li><a href="https://docs.deno.com/runtime/reference/node_apis/#unsupported-modules">Currently unsupported Node.js features in Deno</a></li> </ol> <h2 id="deno-api-1">Deno API</h2> <p>Currently, Deno’s API offerings are still limited, with issues such as:</p> <ol> <li>No support for network interface selection in network requests. <a href="https://github.com/denoland/deno/issues/27376">https://github.com/denoland/deno/issues/27376</a></li> <li>No support for brotli compression. (though achievable through Node.js compatibility packages)</li> </ol> </div> </details>

2024/12/19
阅读更多

Cursor 使用问题

<details lang="zh" open=""> <summary>中文版本</summary> <div> <p>对于中国国内开发者来说, Cursor 尤其好用. 因为通过 Cursor 可以使用多种大语言模型, 并且可以避免自己直接订阅导致封号等风险.</p> <p>但是作为一个文本编辑器, 虽然集成自 VS Code, 但 Cursor 仍有许多基础功能没做好:</p> <ol> <li>同一用户多设备的配置数据同步.</li> <li>第三方软件集成 (如 Fork).</li> <li>macOS 下将 Find 文件或文件夹拖拽到 icon 打开 (系统集成).</li> </ol> <p>许多开发者都有多台开发设备, 大多数开发者希望在多台设备上拥有较为一致的开发体验. VS Code 在这方面做的就很好. 但是 Cursor 无法在统一用户的多台设备上进行配置数据的同步, 扩展也需要分别安装.</p> <p>在第三方软件集成度上, Cursor 也有问题. 以 Fork 为例, 虽然不知道问题是在 Fork 还是在 Cursor 上, 但用户体验上的确不够, 还不如 Zed. 以前 Open in 都不支持 Cursor, 现在 Reveal Line 还是不支持.</p> <p>在 Mac 上不支持将文件夹拖转到 icon 上打开. (以前连文件拖拽打开都不支持)</p> <p>Cursor 还需要把编辑器本身的工作做好啊.</p> </div> </details> <details lang="en"> <summary>English Version</summary> <div> <p>For developers in China, Cursor is particularly useful because it provides access to various large language models while avoiding the risks of direct subscription that might lead to account suspension.</p> <p>However, as a text editor, despite being based on VS Code, Cursor still lacks several basic features:</p> <ol> <li>Configuration data synchronization across multiple devices for the same user.</li> <li>Third-party software integration (such as Fork).</li> <li>Opening files/folders by dragging them onto the icon on macOS (system integration).</li> </ol> <p>Many developers work with multiple devices, and most prefer to have a consistent development experience across all their devices. VS Code handles this well. However, Cursor cannot synchronize configuration data across multiple devices for the same user, and extensions need to be installed separately on each device.</p> <p>Regarding third-party software integration, Cursor has issues. Taking Fork as an example, regardless of whether the problem lies with Fork or Cursor, the user experience is inadequate and inferior to Zed. Previously, “Open in” didn’t support Cursor, and “Reveal Line” still doesn’t work.</p> <p>On Mac, it doesn’t support opening folders by dragging them onto the icon. (Previously, it didn’t even support opening files by dragging)</p> <p>Cursor needs to improve its core editor functionality.</p> </div> </details>

2024/12/12
阅读更多

谈 Alex Russell 谈 React

<p>我看了部分 <a href="https://infrequently.org/2024/11/if-not-react-then-what/">Alex Russell 的原文</a>, 完整看了这篇<a href="https://www.infoq.cn/news/Ssc0h0HBY7xkN1uk4P4t">翻译文章</a>.</p> <p>下面是我的一些看法:</p> <h2 id="frameworkism">Frameworkism</h2> <p>Web 开发者并不是主动要被框架束缚, 在前端 (客户端) 开发中, Android, iOS, 微信小程序, 鸿蒙应用等, 都在实现更多前端功能的前提下限制了前端的开发流. 而 Web 自身的设计在相同场景下相比其他前端开发技术栈来说交互严重不足.</p> <p>那我们有交互需求的时候应该怎么办? 直接操作 DOM 太繁琐, 并不是一种现代化的方案, 所以我们在 Web 的基础上需要框架, 而不是直接写 HTML + JS + CSS.</p> <h2 id="why-spa">Why SPA</h2> <p>SPA 不是必要的, 但是 Web 应用而不是 Web 网页是必要的, 因为将 Web 作为应用会让整体前端技术栈层次更清晰. 而 SPA 是实现 Web 应用的一种直观的方式, 与其他端开发的架构变得类似.</p> <p>隔行如隔山, 我相信 Russell 并没有站在一个项目整体的立场, 并且没有考虑许多工程化的概念, 比如 Hydration. Russell 低估了许多应用交互的复杂性.</p> <p>我更倾向于让 Web 承载更多应用的场景, 而不是让 Web 承载更多网页的场景. 许多软件功能都是不必要使用 “系统级别应用” 的, 借由 PWA 等概念, Web 可以承载更多这样的功能.</p> <h2 id="why-react">Why React</h2> <p>不可否认社会上存在许多 “随大流” 的想法. 但 Russell 这篇文章的受众不会是随大流想法. 如果真的没有思考, 是不会去看 Russell 的文章的.</p> <p>那我们为什么使用 React? 简单来说有三点:</p> <ol> <li>React 可以实现我们的需求. React 提供了一套简单的原则, 状态数据 + JSX.</li> <li>React 简单易懂. 在工程上有足够的优势.</li> <li>生态好. 因为 React 有先发优势, 可能也因为 React 在其他方面有优势.</li> </ol> <p>并不是因为:</p> <ol> <li>“Facebook 用了 React, 所以我们用肯定没问题.” React 是 Facebook 的产物, 但是 React 之所以成为一个开源项目, 是因为 React 解决的是一个通用且朴素的问题.</li> <li>“React 是行业标准.” 我们也不认为 React 是标准, 但不可否认 React 对其他许多流行库造成了深远的影响.</li> <li>“React 更容易被招聘.” 一方面, React 并不复杂, 另一方面, React 在我们的环境下并没有明显的招聘优势.</li> </ol> <p>在 Russell 介绍其他框架的时候, 我一开始难以理解 “React, Angular, etc.” 中的 “etc.” 不包含 Vue 等.</p> <p>后来我明白了, Russell 的角度从来都不是 Web 开发者, 而是浏览器. Russell 是为了浏览器在发声, 而不是代表 Web 开发者.</p> <p>Russell 对现代化框架的定义主要围绕在: 技术实现上不要针对老旧的 IE, 不要使用虚拟 DOM, 性能要够好.</p> <p>Russell 没有从 React 的 API 角度说明 React 的 API 设计如何对其他所谓现代化造成的影响, 比如 state 概念, hooks 概念 (当然, hooks 属于一种打补丁的概念, 但是它确实让 React 的 API 变得更好用).</p> <p>作为 Web 开发者, 其实就是希望 React API 可以有一层进行隔离, 让开发者可以尽情做交互, 而不是像使用 C 一样精细化操作 DOM. 这一点上, 其实 Svelte 做的更好, 但是 Svelte 作为框架, 侵入性更强.</p> <p>而 React 作为一个库, 而不是框架, 可以与现有任何 HTML 基础技术栈兼容, 并且渐进式替换.</p> <p>并且, React 与 “core-js, lodash, underscore, polyfills for browsers that no longer exist, userland ECC libraries, moment.js, and a hundred other horrors” 并没有密切的关系, 使用所谓现在框架也会遇到这样的问题. 说白了, 这是开放式的浏览器生态与开发者想要避免 JS 语言历史的坑造成的矛盾, 你不能指望所有用户都用你开发的最新版渲染引擎.</p> <p>React 并不可怕, 对于开发者, 其他渲染库也的确值得看:</p> <ol> <li>Svelte, 强制需要构建.</li> <li>Lit, 以前是 Polymer, Google 的维护不足让开发者跟进困难. (我们曾使用 Polymer)</li> <li>Vue 经过多次大版本变化, 语法经常有破坏性变化, 与 Svelte 类似但独有的语法更多. (我们曾使用 Vue 1.x, 2.x)</li> <li>Solid, 和 React 的语法及特点最像. (我们在部分项目中在尝试 Solid)</li> <li>…</li> </ol> <p>但是如果要用到生产环境, 我还是建议 React.</p>

2024/12/11
阅读更多

推荐订阅

The Art of Chawye Hsu

Recent content on Yuko's Blog

Software Engineer, Hacker & Painter.