AI 资讯
'We'll fix it later' is a loan. Here's the interest rate
Every time someone on your team says "we'll clean it up later," they're taking out a loan. The problem is that almost nobody checks the interest rate — until it bankrupts an entire sprint. Technical debt is the most-used and least-understood metaphor in software. Used well, the metaphor is genuinely powerful, because debt is exactly the right mental model — including the part everyone forgets: interest. Debt isn't the same as bad code First, a correction. Technical debt isn't just messy or bad code. It's a deliberate or accidental trade: you took a shortcut — skipped the abstraction, hardcoded the value, deferred the test — to move faster now, in exchange for a cost later. Sometimes that's a smart, conscious decision. Shipping today to validate an idea, knowing you'll refactor if it works, is often the right call. The debt isn't the problem; unmanaged, invisible debt is. The interest is the point Here's what the metaphor gets exactly right and most teams ignore. Debt accrues interest . Every feature you build on top of a shortcut is a little harder to build. Every bug in the messy area takes a little longer to fix. The shortcut doesn't cost you once — it taxes every future change that touches it, and that tax compounds. This is why teams mysteriously slow down over time. It rarely feels like a wall; it feels like everything gradually getting harder, estimates creeping up, small changes turning into week-long ordeals. That's compounding interest on debt nobody tracked. I've watched a system's velocity get quietly reclaimed by exactly this, and paying it down deliberately is part of how I approach building things properly . Good debt, bad debt The framework that makes this actionable: Deliberate, prudent debt: "We know the right design, but we're shipping the simple version to hit the deadline, and we'll fix it." Fine — it's a conscious, tracked trade. Accidental, reckless debt: "What's a design pattern?" — debt taken on through inexperience, invisibly, with no plan t
AI 资讯
Clean Code Like a Jedi: The One Principle That Changed My Code Forever
The Quest Begins (The "Why") I still remember the first time I opened a pull request that looked like a novel written by someone who’d had too much coffee. The file was 800 lines long, a single function tried to validate input, fetch data from three different APIs, transform the result, update the UI, and log everything to a console that no one ever looked at. I spent three hours stepping through it with a debugger, only to realize the bug was a typo in a variable name buried three levels deep in a nested if‑statement. When I finally fixed it, I felt like I’d just defeated a dragon… only to discover the dragon had a dozen smaller dragons hiding in its caves. That experience left me wondering: Why does code feel so hard to read, even when it works? The answer wasn’t a fancy framework or a new language feature—it was a simple habit I’d overlooked: making every function do one thing, and do it well . Once I started treating that rule like a sacred oath, the dragons started to shrink, and my code began to feel like a clean, well‑lit hallway instead of a dark, tangled forest. The Revelation (The Insight) The principle is straightforward, yet its impact is massive: each function should have a single responsibility . If you can describe what a function does with a single verb phrase— validateUserInput , fetchUserProfile , renderDashboard —you’re on the right track. If you need an “and” or a “but” in that description, you’ve probably got more than one job packed in. Why does this matter? Readability : A reader can grasp the intent in seconds, not minutes. Testability : Small, focused functions are trivial to unit test. You can mock dependencies and assert outcomes without setting up a whole saga. Debugging : When something goes wrong, the stack trace points you directly to the guilty function, not to a 20‑line monolith where you have to hunt for the offending line. Reusability : A function that does one thing well can be dropped into other parts of the codebase (or even oth
AI 资讯
We Will Get You Through It!
There is a comedy sketch from Bob & Tom that starts with a hilariously impossible promise: overnight delivery by train, from New York to Los Angeles. At one point, someone asks if they can really get a 2,000-pound package across the country overnight by rail. The answer is delivered with absolute confidence: “Norfolk and Waypal, overnight. Absolutely. Positively.” The name is doing some careful work. It lets you hear the phrase that nobody has actually said out loud. No way, pal. When I end up leading a project with six weeks left and something that feels like four months of work to do, I start the internal kickoff by telling the team to go watch that sketch. No other explanation. Just go watch it, then come back. Then I tell them: “Absolutely, positively, we will get you through it. There's Norfolk and Waypal, we are gonna to do it.” That does not mean we are going to do the thing exactly as it was originally promised. It means we are going to get through it. Absolutely. Positively. There is a difference. Laugh at the impossible first I think newer developers especially need permission to laugh at impossible requirements. An 800-pound gorilla from New York to Los Angeles overnight by train is impossible in a way that is easy to laugh at. A project that needs a full cloud environment, API work, a mobile application in the app stores, production deployment, security approvals, and a dozen other things in six weeks? That can feel less funny when it is sitting in your sprint board. But it may be just as impossible if we take the requirements literally. The first danger on a crunch project is shame. A junior developer can look at an impossible deadline and wonder if they are missing something. Maybe everyone else understands how this gets done. Maybe it is a talent problem. Maybe if they just worked harder, they could turn six weeks into twelve. Nope. Sometimes the work is just Norfolk and Waypal . Humor does not solve the problem. It lowers the temperature enough that
AI 资讯
Your `if` statements are a database nobody can query
Somewhere in your codebase there is a line that looks like this: if ( user . plan === ' enterprise ' || user . tenantId === ' acme-corp ' ) { // ... } Nobody remembers who wrote the second half of that condition. It has been there for two years. It is almost certainly still load-bearing. Here is the thing I want to convince you of: that line isn't code. It's data, and it's stored in the worst possible place. Every conditional that encodes a business decision is really a row. It has a condition, an outcome, and a bunch of implicit context about when it applies. You have hundreds of these rows. They're spread across a dozen services, written in four different styles, and there is no way to list them. You have a database. You just can't query it. Five things a database gives you that your code doesn't Once you look at it this way, the problems stop feeling like sloppiness and start feeling structural. There's no schema. One service decides a customer is premium by checking plan === 'premium' . Another checks subscription.tier > 2 . A third checks a flag that was set during a migration in 2023. All three are "the same rule" until the day they aren't, and there's nothing in the system that would notice the drift. There's no way to query it. Try to answer a simple question: what rules are live in production right now? You can't. Someone has to read the source. And grep won't save you, because the interesting conditions are compound, spread across guard clauses, and half of them are expressed as an early return rather than an if . There are no migrations. Changing a rate limit from 100 to 200 requires a pull request, a review, a CI run, and a deploy window. You're pushing a code change through the full pipeline to change a number. It's a schema migration with none of the tooling that makes schema migrations tolerable. There's no audit log. Git tells you who edited the line. It doesn't tell you who decided the rule, when it was supposed to expire, or whether the customer it
AI 资讯
Lean 创始人访谈全记录:当形式化验证遇上 AI,手写数学与软件验证将如何被重塑
https://www.youtube.com/watch?v=KzdYKeAqWhY 题目:《Lean 创始人访谈全记录:当形式化验证遇上 AI,手写数学与软件验证将如何被重塑》 第(一)部分 开场与核心命题:从“测试只能证明有 bug”到“证明可确保无 bug” (0% - 8%) Dijkstra 名言引出形式化验证的根本价值:主持人以 Dijkstra 的名言“程序测试可用于揭示 bug 的存在,但永远无法证明 bug 的不存在”开场,指出 Lean 与形式化证明的意义恰恰在于“证明 bug 不可能发生”。 Lean 的基础定位:Lean 既是一门编程语言(可以写代码),也是一个证明系统(可以对代码写性质并用机器可检查的证明来验证)。它提供绝对正确的保证,并拥有多个独立的检查器。 Lean 应被视为平台:用户可以在 Lean 上写代码、写关于代码的性质命题、并给出证明;本期节目将围绕它如何工作、以及它如何改变数学和软件验证的未来展开,并提出“手写数学是否会终结”这一核心疑问。 第(二)部分 Lean 是什么:编程语言与证明助手的一体两面 (8% - 18%) Lean 的双重身份:Lean 不仅可用于数学证明,也可用于软件验证。基于依赖类型论(Dependent Type Theory)的一族证明助手(如 Rocq/Coq 和 Lean)天然就是“编程语言 + 证明助手”。 软件验证的两种主流路径: • 浅嵌入(Shallow Embedding):通过工具(如把 Rust 翻译到 Lean 的工具)把其他语言映射到 Lean 中进行验证。 • 深嵌入/语义建模:在 Lean 中为 C 语言等编写语义,把 C 程序表示为 Lean 中的数据结构,从而对其陈述性质并进行推理。 具体例子——数组越界验证:以 C 语言访问数组为例,可在 Lean 中把“索引 i 满足 0 ≤ i < 10”写成数学命题;原来的 C 源文件可对应一份“元数据式”的 Lean 证明,由 Lean 逐行检查。 自动化与可维护性:人们会建立自动化框架(如基于前置条件-语句-后置条件的三元组),把证明过程变得更易管理;复杂度是软件验证的大敌,而 AI 的出现让“自动证明”成为可能,但前提是把证明写得模块化以便扩展。 第(三)部分 从“测试套件”到“形式化规格”:为什么规格优于测试 (18% - 28%) 测试 vs. 证明的本质差异:测试套件再全面,也只覆盖了有限场景,角落案例仍可能遗漏;而形式化证明覆盖所有可能情况,真正做到了“bug 的不存在”。 Zlib 压缩库的震撼案例:主持人的同事 Kim Morrison 发起项目,让 AI 把 C 写的 Zlib 压缩库翻译进 Lean,要求通过原测试套件,并证明“压缩后再解压得到原始数据”这一强性质。结果仅用一周就完成了整个形式化,目前只需再做性能优化,且优化不能破坏既有证明。 规格说明(Specification)的成本讨论:写出一份好的规格,工作量因程序而异。一个实用技巧是:先用“低效但正确”的实现作为规格(Spec),再让 AI 生成高效版本并证明其与规格等价。 Jane Street 与工业界实践:Jane Street 等公司已在投资形式化验证,例如对微内核 seL4 的完整验证。过去这类工作在没有 AI 时“手动证明 + 维护证明”的成本极高(往往是写程序本身的 10 倍),而 AI 正在消除这种痛苦——AI 非常擅长撰写和维护形式化证明,即使人已经忘了当初为何这么证。 第(四)部分 Lean 作为编程语言的工程实践与工具链 (28% - 36%) 不仅是证明助手,更是生产级编程语言:AWS 内部有一个约 50 万行 Lean 写的 AI 加速器编译器,主要把 Lean 当编程语言用,顺带获得一些性质证明作为“额外红利”。 工具链体验接近现代语言:构建系统 Lake 相当于 Rust 的 Cargo;编辑器用 VS Code,提供 IntelliSense 等熟悉体验。 Info View——Lean 独有的核心交互界面:屏幕通常一分为二,左侧是代码/证明文件,右侧 Info View 实时显示当前证明目标的状态变化,给用户持续反馈。 Tactic 模式:把证明当成“游戏”:用户通过 by 进入领域特定语言(DSL)来写证明,每一步可简化目标、应用已知引理等,看着目标逐步减少直到归零,过程极具“通关”快感,不少用户戏称自己“沉迷其中”。 第(五)部分 内核信任问题:Lean 自身是否被 Lean 验证? (36% - 42%) 只需信任极小的内核:Lean 整体庞大且规格频繁变动(如简化器的行为不断被用户定制),难以对全部进行形式化;但证明检查的核心——“内核”是可以被规格化的。 多内核策
开发者
The Fix Was Committed. The Old Value Kept Running.
Originally published on hexisteme notes . I deleted three ambient API keys from my shell profile. Then I ran the standard clean-room check — spawn a shell with no inherited environment at all, env -i HOME="$HOME" /bin/zsh -lc 'echo "${VARNAME:-unset}"' , and read unset back for all three. That command doesn't lie: a shell started with an empty environment can only see what the current profile puts there, so if it reports the variable missing, the profile is clean. I closed the loop, reconnected my tools, and moved on. Minutes later I reconnected a review tool I run for cross-vendor sanity checks, and it came back healthy — with eight providers registered, one of them authenticated with a key I had just deleted. Not a cached credential from an old response. A live, working authentication, using a value that no longer existed anywhere on disk. The fix was committed. The old value kept running. Two different questions that sound like one "Did I fix the config?" and "Is the fix in effect?" collapse into a single question in your head, because in the common case they're the same event: you edit a file, the next thing that reads the file gets the new value, done. env -i answers the first question perfectly. It says nothing about the second, because it doesn't test any process that already exists — it only tests a brand-new one, freshly spawned, that has no choice but to read the current profile because it has no environment of its own yet. Every process that was already running before you made the edit is a different story. It read the profile once, at its own startup, copied whatever it found into its own memory, and has not looked at the file since. From that point forward it is not a reader of your shell profile — it is a cache of it. And caches don't invalidate themselves. Finding the actual culprit The process holding the stale value here was the editor I was working in — the same long-lived process that hosts my coding sessions and manages tool connections through M
AI 资讯
Google lowers Gemini 3.7 Flash costs for developers
Google has launched Gemini 3.7 Flash, providing significant updates for coding, automation, and the development of autonomous agents. The company reduced production pricing to help businesses deploy these tools more affordably. This release comes only three weeks after the previous version, signaling a faster pace for developer-focused updates. Accelerated development cycles and cost reduction strategies The introduction of Gemini 3.7 Flash highlights a shift in how technology providers manage their product lineups. Google is prioritizing rapid iteration for its Flash series, which serves as a high-speed tool for developers. This latest version arrived less than a month after its predecessor, showing the company responds quickly to user feedback. Engineers designed this model to handle software engineering tasks and complex, multi-step workflows with higher precision. Pricing for the new model sits at $0.75 per million input tokens and $3.75 per million output tokens. This represents a reduction of approximately fifty percent compared to the prior version. By lowering the financial barrier, Google aims to make large-scale production deployments more sustainable for businesses. The company describes this version as a reliable workhorse capable of following instructions with greater accuracy than previous iterations. While the Flash series moves quickly, the more advanced Pro models follow a different path. These high-end models, designed for the most difficult reasoning tasks, see less frequent updates. During recent financial discussions, leadership at the company did not provide a specific timeline for the next Pro release. This indicates a growing gap between fast, cost-effective models and the slower development of premium intelligence tiers. Industry trends in model tiering Other companies in the industry are following similar patterns by separating their offerings into distinct categories. For example, some competitors have launched high-end variants alongside
AI 资讯
Claude Terminal Hub: stop hunting for folders to resume Claude Code sessions
Every time I went back to an old Claude Code session, the process was the same: open Explorer, remember which folder that project lived in, open a terminal there, type claude --resume <id> from memory or paste it from somewhere. I got tired of it and built Claude Terminal Hub . What it does It's a Windows desktop app, built with Electron, that lists your recent Claude Code sessions from every project on the machine in a single screen. It reads the .jsonl files Claude Code writes to ~/.claude/projects , zero configuration needed. Each session shows an AI-generated title and the last prompt sent, sorted by recent activity. One click on a session opens a terminal panel in the right folder, already running claude --resume . You can keep up to 4 panels open side by side, each one a real PowerShell process via node-pty , not a fake console. Arrow keys, vim , the Claude Code TUI itself, all work normally inside the panel. Under the hood Main process (Node) reads only the first and last KB of each .jsonl file, not the full transcript, to list sessions fast even with a large session history. A narrow contextBridge between main and renderer, no broad IPC surface. React frontend, one xterm.js instance per terminal panel. Each panel spawns a real PowerShell process through node-pty , so shell state, arrow keys, and TUIs behave like a native terminal. Getting it Windows installer ready (NSIS), no admin rights required. Open source on GitHub: https://github.com/obrenoalvim/claude-terminal-hub Does anyone else miss multiplexing Claude Code terminals like this, or already solved it a different way?
AI 资讯
Building Kisan Mitra: How I Built an Ultra-Fast Voice AI for Indian Farmers in 10 Days
From zero to a full-stack, multilingual agricultural voice agent with caller memory, real-time mandi tools, outbound price alert calls, human escalation, and specialist agent handoffs — powered by Murf Falcon & LiveKit. 🌟 The Problem & The Mission In rural India, millions of farmers make critical livelihood decisions every day: When should I harvest? Will it rain before I spray pesticides? Which nearby mandi (market) is offering the best price for my cotton crop? While agricultural data exists across various portals, accessing it through complex web interfaces or text-heavy apps is challenging for farmers out in the field. Voice is the natural, frictionless interface for Bharat. A farmer standing in an orchard or driving a tractor doesn't want to type queries into a search bar; they want to speak naturally in their native language or conversational Hinglish and get instant, reliable answers. For the 10 Days of Voice Agents (VoiceForBharat Edition), I chose the Farm & Field track and built Kisan Mitra (किसान मित्र) — an empathetic, real-time AI voice assistant tailored specifically for Indian agriculture. 🏗️ Architecture & Core Components A production-grade voice agent is fundamentally different from a text chatbot. Latency is the single biggest factor in conversational realism: if the agent takes more than 1–1.5 seconds to reply, the human conversation breaks down. mermaid flowchart LR A[🎙️ Farmer Speaks] -->|Audio Stream| B(Deepgram Nova-3 STT) B -->|Transcribed Text| C(Gemini 2.5 Flash LLM) C -->|Streamed Tokens| D(Murf Falcon TTS) D -->|Real-time Audio| E(LiveKit WebRTC) E -->|Ultra-low Latency Audio| F[🔊 Farmer Hears Answer] C <-->|Tools & Memory| G[(SQLite & External APIs)] The 4 Pillars of the Pipeline: Real-time Transport (LiveKit): Manages ultra-low-latency, bidirectional audio WebRTC streaming and turn detection. Speech-to-Text (Deepgram Nova-3): Accurately transcribes spoken Indian English and accented Hindi. LLM Brain (Google Gemini 2.5 Flash): Handles in
AI 资讯
AI Is Making Programmers Stackless: Engineering Experience Is the New Moat
For years, I thought being a good programmer meant knowing your stack really well. I was a Laravel developer, A React developer, A Node.js developer and A Go developer. And there was some truth to that. I spent years working with Laravel, for example, and naturally became faster at solving problems with Laravel. I know the ecosystem, the common mistakes, the packages, the conventions, and probably a few things that weren't even written in the documentation. My stack became part of my identity as a developer. But I think AI is slowly changing that. Not because frameworks and programming languages don't matter anymore. They obviously do. It's because AI has made moving between them much easier. Today, I can open a codebase written in a language or framework I haven't touched in years, or maybe have never used seriously, and get productive much faster than I could before. I can ask AI to explain the project structure. I can ask it to explain a piece of code. I can ask it to translate something I understand in PHP into Go. I can ask it to help me write tests. I can use it while debugging. I can even ask it why a particular approach might be a bad idea. That doesn't suddenly make me an expert in that technology. But it means I don't need to spend weeks just getting comfortable enough to start solving the actual problem. And I think that's a pretty big change. Your Stack Is Becoming Less Important There was a time when knowing a technology itself was a significant advantage. If you knew Laravel, you had to learn Laravel. If you wanted to learn React, you had to spend time understanding React. If you wanted to work with Kubernetes, good luck. You read documentation, watched tutorials, built things, broke things, fixed them, and slowly built up experience. That's still how you become good. But AI has changed the entry point. The first few hours with a new technology are no longer as painful as they used to be. You can have an AI sitting beside you explaining things as you g
AI 资讯
How to Integrate a Payment Gateway into Your Web App: A Practical Guide
Adding online payments to a web application can make it easier for customers to purchase products, subscribe to services, book appointments, or pay invoices. But payment integration involves more than adding a payment button to a website. A reliable integration needs a payment gateway, backend APIs, secure authentication, payment status handling, webhooks, and proper error management. This guide explains the basic process of integrating a payment gateway into a web application, using Razorpay as an example. 1. Understand How Payment Gateway Integration Works A typical payment flow looks like this: Customer → Web App → Backend → Payment Gateway → Bank/Payment Network The customer starts the payment from your website. Your backend creates the payment order through the gateway. The customer then completes the payment using a supported payment method. After the transaction, your application needs to confirm whether the payment was successful before providing the product or service. A simplified flow is: Customer selects a product or service. Your backend creates an order. The payment gateway generates the required payment details. Checkout opens for the customer. Customer completes the payment. The gateway returns payment information. Your backend verifies the payment. A webhook can update your system about payment events. Your database records the final payment status. The application confirms the order. 2. Choose the Right Payment Gateway Before starting development, compare payment gateways based on factors such as: Supported payment methods Transaction fees API documentation Developer tools Settlement process Refund support International payment support Webhook capabilities Security requirements Customer support For an Indian web application, gateways such as Razorpay can support common payment methods including UPI, cards, net banking, and wallets, depending on the account and applicable availability. The important thing is to choose a gateway that fits your applic
AI 资讯
Notes to Self: The Interview Between an Issue and a Spec
On 1 August I opened an issue that was three sentences long. A hundred and one minutes later the feature was merged, and the document that got it there ran to 457 lines . I didn't write those 457 lines. In fact, I didn't have to write any more documentation, and not because I simply allowed Claude to run amok. Here is the issue in full — control-api#265 , 225 characters: control-api#265 — Manifest-backed dashboard feeds For each dashboard, auto create a manifest keyed by dashboard_id. For each sensor the dashboard uses, tag it to be included in the manifest. When a dashboard definition is updated, add / remove tags from sensors accordingly. From that genesis moment, this is the lifecycle of the issue all the way through to landing: Time (UTC) Event 14:25 Issue #265 opened — 225 characters 14:54 FEAT-0007 spec committed — 457 lines 15:35 Spec merged (PR #266) 15:51 Implementation committed 16:06 Implementation merged (PR #267, 15 files), issue closed The interesting part isn't the speed. It's the step at 14:54 that landed a previously non-existent spec document, and what happened in the twenty-nine minutes before it. The issue was never a specification I often write issues like this one...the way most people write shopping lists. Actuator address is not ensured? Baseline the trace correctly. With the pre-rolls, the frame-rate looks out. They're abbreviated to the point of being cryptic to everyone else. I write them this way deliberately: I'm usually mid-something else when I notice a problem, or have an idea for a better route to the solution. The cost of a full write-up right at that moment would be a fractured sense of flow. As most engineers will tell you, the transitions into and out of flow are the most disruptive parts of their working day. This terse form of issue-writing can be all you need, and it's worth being precise about why it works and the trade-offs it includes. It is not because "the issues are good enough". They aren't. When you pick one of these u
AI 资讯
My Job Hasn't Changed. My Day Has.
Times are changing, my role is changing, my focus is changing, my impact is changing. But in essence – I'm still doing the same. I still build products that drive impact. Only my day-to-day looks completely different. The shift is happening, sooner or later, if you want it or not. Whether or not you can cope, is all up to you. In the past, I was neck-deep in code. That was what the majority of my time consumed. I liked it, building things, building products. These days, that's all done by an endless amount of AI agents. I barely touched any code in the past half year – if not even longer. My focus moved from building products to building my own process The work that used to go into a feature now goes into the process that produces the feature. Instead of losing the first hour of my day to Slack and email, I built a small stack of scheduled agents that hand me a briefing before I even open my laptop ( already wrote about that one ). Instead of reading every pull request line by line, I set up a review loop where agents do the first pass and I stay on the hook for whatever they flag. None of it started as a plan. Each piece started as one specific annoyance I got tired of and fixed. That's the actual mechanism: improve one small thing, it saves you time, you reinvest that time into the next small improvement. Compounding, not a grand strategy. The question I try to ask myself daily is simple: how can I do my job a bit better today than I did it yesterday? Not more. Not faster. Better. I also don't run ten parallel AI workflows across different projects at the same time because someone told me that's what a serious AI-software engineer does now. If I have multiple projects going on, I only focus on one project at a time. That's the amount of mental space I have right now, and I've stopped treating that as a shortcoming. My impact shifted from writing code to making my team better The time that used to go into implementation didn't disappear, it moved upstream. I now sp
AI 资讯
Before You Merge AI-Generated Code, Ask These 12 Questions
I've merged plenty of AI-generated code that was genuinely fine. I've also caught myself almost merging code that looked fine and wasn't, because it read like something a competent person wrote and my brain filled in the rest. Over the last year I've settled into a rough set of questions I run through before approving anything I didn't write line by line myself, generated or not. Here they are, in the order I actually ask them. 1. What problem is this code actually solving? It's easy to review whether code works and skip whether it solves the right thing. AI tends to answer the literal prompt, not the intent behind it. def get_active_users (): return db . query ( " SELECT * FROM users WHERE active = true " ) If "active" was supposed to mean "logged in within 30 days" and not a boolean flag that's rarely updated, this passes every test and still solves the wrong problem. Reviewer tip: Read the original ticket or request before reading the diff. Check the code against the intent, not just the literal ask. 2. Do I actually understand the implementation? Not "does it look reasonable," actually understand it, line by line, well enough to explain it to someone else. Reviewer tip: Try to explain the function out loud in one sentence per major step. If you get stuck anywhere, that's the part you haven't actually reviewed yet, just skimmed. 3. What assumptions is it making? Every implementation bakes in assumptions about the shape of the data, the order things happen in, or what "normal" looks like. function getLatestOrder ( orders ) { return orders [ orders . length - 1 ]; } This assumes orders is sorted chronologically and never empty. Neither assumption is stated anywhere. Reviewer tip: Ask "what does this assume about its inputs that isn't checked anywhere?" Write the answer down, literally, in the PR comment if it matters. 4. What happens with bad input? Bad input isn't an edge case, it's a certainty over a long enough timeline. def parse_age ( value ): return int ( val
AI 资讯
LLM-Generated GraphQL Mocks Arrive at Airbnb and Expedia, While the Spec Lags Behind
Expedia Group has open-sourced mockql-rs, a Rust CLI that fills @mock-annotated GraphQL fields with LLM-generated data at request time. It follows Airbnb's @generateMock in April and a GraphQL Foundation RFC opened in February. All three solve the same problem with different architectures, and two use the same directive name with incompatible semantics. By Steef-Jan Wiggers
AI 资讯
Build Your Agentic Software Factory!
The term software factory is getting a lot of attention right now, and for a good reason. AI coding assistants can generate code much faster than before. But faster coding alone does not mean faster, safer delivery. In many teams, it simply moves the bottleneck to review, testing, deployment, and operations. A software factory is a way to organize the entire software development life cycle as one connected, repeatable system. Think of a car manufacturing assembly line. Each station has a clear job, work moves forward in a predictable order, quality checks happen at the right moments, and the finished product is inspected before it leaves the factory. An agentic software factory applies that same idea to software delivery. AI agents do focused work across planning, coding, testing, deployment, monitoring, and feedback. Humans remain in charge of specifications, security, policies, approvals, and the decisions that should never be delegated blindly. Key Takeaways An agentic software factory coordinates AI agents across the complete software delivery lifecycle. Faster AI-assisted coding can create review bottlenecks unless downstream stages also improve. Humans retain ownership by defining guardrails, specifications, approvals, and security requirements. Workflow orchestration connects context, automation, observability, incident handling, and feedback loops. What Is a Software Factory? A software factory is not just a collection of developer tools. It is an operating model where software delivery is designed as a smooth, observable workflow from idea to production and back into improvement. In a car factory, a vehicle moves through assembly, painting, quality inspection, final assembly, and delivery. People are involved at important checkpoints, but the process does not restart from scratch at every station. It is structured, repeatable, and connected. The same model works for software. In an agentic software factory, the flow can look like this: Requirements and desi
AI 资讯
loveyourclanker.org
I created an open web resource for Software Engineers. https://loveyourclanker.org/ It highlights different patterns we can consciously choose use when interacting with our AI Coding tools (a.k.a 'Agents'... a.k.a 'Clankers') to stay in control, maintain quality and sensibly increase efficiency. I was prompted to do this (no pun intended) by observing some pretty alarming signals coming from this community. Token leaderboards, engineers being encouraged to use tools to "stay current" or "keep up" or "not be redundant", engineers quitting tools entirely to stay sane, engineers leaving social gatherings to get back to their agents, engineers setting up whole systems that automate away human engineers and then calling that "agentic engineering". I'm hoping that if we normalise and share how we use the tools, and show that there are different ways where you maintain more control and agency (... pun?) that it might promote a better If you find it helpful, share. If you disagree or want to contribute, raise a PR or ping me. It's all open and NFP.
AI 资讯
Notify vs Postmark for Transactional Email: Which Is Simpler for a Small Engineering Team?
I'd push back a little on "Postmark is simpler" as a blanket answer, because it depends on which kind of simple you're optimizing for. If you want the fewest new concepts to learn before your first email sends, Notify is simpler — fewer moving parts, no approval step, no server/stream concepts to pick up. If you want a mature, deliverability-focused product with templates built in, and you don't mind a few more concepts to get there, Postmark is genuinely excellent — its reputation in this space is earned, not just marketing. Here's the actual setup for each, side by side, since that's a more useful comparison than either one asserted as "simpler" outright. What "Simple" Actually Means for a Small Team A small engineering team usually means nobody's full-time job is "manage the email provider." In that context, simple should mean: how many new concepts does someone have to learn before this works, not just how polished the product feels once they've learned them. That's the lens worth applying here. What You Actually Set Up, Side by Side With Postmark: Sign up Request approval for production sending — Postmark reviews new accounts manually before you can send real volume, commonly reported to take about 24 hours Create a Server — Postmark's per-app isolation boundary — and name it Verify your domain: add a DKIM record, and if you want proper DMARC alignment rather than just the automatic SPF pass-through Postmark gives you by default through its own Return-Path domain, add a custom Return-Path CNAME too Pick which Message Stream you're sending through — Postmark separates transactional ("outbound") from broadcast streams and enforces that distinction, so this isn't optional Optionally create a Template within that Server if you want reusable content with variables instead of raw HTML per send Call the send API with your Server API Token With Notify: Sign up Verify your domain — SPF, DKIM, DMARC records Get your API key Call the send API That's four concepts versus a
AI 资讯
What a Small-Business CRM Needs Beyond Contact Storage
A contact table is easy to build. A usable CRM is an operations system. The difficult part is not storing a name and email address. It is preserving context as work moves between people, organizations, deals, tasks, notes, imports, reports, and follow-up. That requires deliberate data modeling and product decisions. Model relationships, not isolated records A customer may belong to an organization. An organization may have several contacts. A deal can involve multiple people, tasks, notes, and status changes. If those relationships are flattened into one spreadsheet-like table, duplicate data and contradictory updates appear quickly. Define stable identifiers and explicit relationships early. Treat activity history as a product feature Users need to know what changed, when it changed, and who changed it. Audit history supports troubleshooting and accountability. It also makes bulk operations safer: after an import or mass edit, an administrator should be able to understand the result rather than guessing which rows moved. Decide which actions deserve history, how long it is retained, and who can see it. Avoid collecting sensitive data simply because the schema allows it. Design imports for failure CSV import is where clean demos meet messy reality. A useful import flow should provide: column mapping; required-field validation; duplicate-handling rules; a preview before committing; clear row-level errors; an exportable error report; idempotent or recoverable behavior where practical. Never assume the first row contains perfect headers or that dates, phone numbers, and booleans use one format. Make views part of the workflow Saved filters and views let different roles focus on their work without changing the underlying data. A sales view may emphasize open deals and next actions. An operations view may emphasize overdue tasks. An administrator may need import history and permission context. This is more than UI convenience: it is a way to keep one shared system useful
AI 资讯
Design Notes for a Deterministic C++ Simulation Framework
“Same inputs, same result” sounds like a simple requirement. In a multithreaded simulation, it is an architectural constraint that touches data layout, scheduling, physics, randomness, floating-point behavior, serialization, and debugging. Determinism is valuable for replays, lockstep networking, regression tests, and reproducing hard failures. It does not happen automatically. Define the determinism boundary Start by stating what must match. Do two runs on the same executable and machine need identical results? Across different compilers? Across CPU architectures? Across operating systems? Those are increasingly difficult guarantees. A framework should document the supported boundary rather than using “deterministic” as a universal adjective. Control time Do not feed variable wall-clock deltas directly into a deterministic simulation. Use a fixed simulation step and decide how the renderer catches up or interpolates. Record inputs by simulation tick. If the system pauses or falls behind, handle that condition explicitly instead of silently changing the rules. Make randomness replayable Every pseudorandom decision needs a known generator, seed, and consumption order. A global generator shared by many systems is fragile because adding one random call in an unrelated feature shifts the sequence everywhere. Prefer scoped streams or deterministic derivation by system, entity, and tick where appropriate. Record seeds in test and replay artifacts. Schedule parallel work deliberately Multithreading introduces nondeterministic execution order. If two jobs write shared state, results may depend on timing even when data races are technically avoided. A robust job graph should make read and write sets visible, separate independent phases, and define deterministic merge or reduction rules. Avoid relying on thread completion order. Parallelize work whose outputs can be combined predictably. Keep entity iteration stable Entity-component systems often use dense arrays and swap-rem