返回站点目录

Jacky's Blog

https://jw1.dev

该站点暂未提供站点简介,可继续查看文章聚合、状态检测与相关资源入口。

综合

状态

状态正常

Did You Come Alone?

2026/07/20 00:00 · Jacky Wong

“Did you come alone?” the receptionist asked while I was checking in. I paused for a second and said, “Yes.” It was a very easy question, since there was only one name on the booking and no one was standing behind me, but for some reason, that question made me think of my friends. I came to Shandong for a six-day solo trip, and I still don’t really know why I chose this place. Qingdao and Weihai sounded interesting, driving along the coast sounded fun, and that was pretty much it. I was excited at first: I landed, picked up the rental car, played Afro House, and started driving. I didn’t need to wait for anyone or ask where they wanted to go, I could wake up whenever I wanted and change the plan at any time. I usually enjoy spending time alone, so I thought I would be good at travelling alone too... I mean, what could go wrong? Until I found something fun and had no one to share it with. I wanted to post on WeChat Moments, but I didn’t want my parents to know any of it. I wanted to post Instagram Stories or send everything to my friends, but I was also worried that I was sharing too much and becoming annoying, so I took a lot of photos and videos and kept most of them to myself. Eating alone also sucked. I saw a lot of food I wanted to try, but there was no way I could finish all of it, and even when I ordered less, I still had leftovers. Sometimes I packed them back to the hotel, but cold food usually tasted bad, and not every hotel had a microwave. I brought my camera too, and I did shoot with it a little, mostly around the beer street in Qingdao, but those photos are still sitting on the SD card, since I never felt like importing them, let alone editing or posting them. I later realized why: I don’t just like taking photos of my friends, I like taking photos when my friends are around. They might be in the frame, looking stupid or looking cool, or they might not be in it at all, but what matters is that the photo means something to us. Without that, buildings and the sea were just buildings and the sea, not worth the effort of opening Lightroom, and the camera was pretty much just extra weight in my bag. I still took photos and videos with my phone while driving, which I knew was dangerous and stupid, but if I didn’t record anything, it felt like I came all this way for nothing. I stayed in Yantai for 2 nights, and it kept raining. Actually, I didn’t get a single proper sunny day during the whole trip, every beach I went to had the same grey sky, with broken shells and random trash all over the sand, not even close to the beaches in Haikou, Sanya or Pattaya. Qingdao beer wasn’t as good as I expected either, and at that point, staying in Shanghai and playing pool or watching a movie with my friends sounded much better. At night, I was lying on the hotel sofa, imagining the exact same evening with someone else there. We probably wouldn’t have done anything special, maybe ordered some food, watched something stupid, or just sat there doing nothing. The rain, the hotel, and Yantai would have been exactly the same, I just wouldn’t have minded any of them as much. Weihai didn’t look any better at first. When I arrived at the Blueways shipwreck, the fog was so heavy that I could barely see the sea, and I thought I had come all this way for nothing again. But after waiting for around two hours, the sun finally came out, the fog slowly cleared, and I could finally see the ship. I took a few photos I liked, and below is my favourite one, which made Weihai the best part of the trip. ![The Blueways shipwreck in Weihai, with seagulls overhead]( ) So the trip wasn’t completely bad, I was still curious about the world, and maybe I still like being alone, I just don’t like doing everything alone. Almost every day during the trip, I had the same thought: I wish those idiots were here.

Problems with Vibe Coding pt.2

2026/04/18 00:00 · Jacky Wong

So, last time I said vibe coding makes me stop thinking, guess what? In certain cases, things are even worse. ## There is no flow state Normally, when I go "cave mode", a programming session looks like this: ![A flow diagram showing a rough mental model leading to code, refine, and ship, with a sharper mental model feedback loop returning from refine toward the earlier stage.]( ) One context, one head, uninterrupted flow. Now, with vibe coding, it looks like this: ![A flow diagram showing write prompt leading to wait, then review, with a loop through argue or re-prompt before moving on to ship.]( ) In cave mode, building the mental model doesn't really stop at the rough mental model. I start with one, sure, and when I get stuck I go back to it. But I never leave the context. Every line I write tests an assumption, every edge case sharpens the mental model a bit more. Building the mental model and coding are the same thread. Vibe coding cuts that thread. I'm not the one typing, so the only window where my mental model can grow is the plan. After that the agent goes off and writes in my name, and my understanding just stops while the codebase doesn't. ## The plan can't see what matters On small and contained work, AI really is faster, but on anything inside a big monolith, the speedup vanishes and the work just changes shape: the part where I build the mental model is gone, replaced by review, argue, and frankly, cursing the shit out of it. Devs know 🤷‍♂️. Like I said in pt.1, plan mode isn't upfront thinking. On the surface it looks like it is, the agent reads some files, gives me a plan, I approve, then I grab a coffee or something and let it cook, chill as fuck, right? But that plan was built from whatever fit in the context window, and even today's LLM context windows are still severely limited. They can't hold a whole codebase, not to mention that some coding agents tend to load even less. So the plan can't see the invariants in my head, the reasoning buried in commit messages, the constraints discussed in Lark threads months ago. Once I approve, a wrong premise could quietly become the foundation. ## And review won't save you ``` src/api/handlers/orders.ts | 892 +++++++++++++++++++++++----------- src/services/inventory.ts | 421 ++++++++++++++++++++-------------- src/db/migrations/0042_orders.sql | 287 ++++++++++++++++++++ src/components/Dashboard.tsx | 248 +++++++++++++++-------- ... 138 files changed, 4577 insertions(+), 3212 deletions(-) ``` That's what every argue cycle later is trying to correct, and the cost is higher than it looks, because I can't build the mental model at the same time. Prompt-writing and problem-modeling fight for the same brain space. Writing a prompt pulls what's in my head out into words, while building a mental model pulls the problem in. I can't do both at once, and every prompt-wait-output cycle wipes out a bit of the mental model I was holding. And even if the mental model is somewhat clear, on a large codebase or a huge monolith, I probably won't review the code line by line, in most cases, I won't even look at a single line, yet still hope that everything is working as planned. Then I deliver it to the test team, and there goes another nightmare. ## AI is a junior, and stays a junior It clicked when I started thinking of AI as a junior. Except this junior writes way more lines than any human, never asks when in doubt, makes things up confidently, doesn't remember what I taught yesterday, and doesn't reflect on mistakes. Teaching a junior is tiring, but at least it goes somewhere. They grow up, and after a year they're part of the system rather than a load on it. Teaching AI goes nowhere: every session starts cold, every fix gets re-broken next week, and the review load that would normally spread across ten juniors all lands on one senior. ## The team ceiling becomes the AI ceiling If the senior is the only one still holding the mental model, and the senior gets ground down by argue-loops, the team's correction capacity drops to whatever the AI itself can do. Which is: surface-level pattern matching on whatever happens to be in the context window. AI doesn't see invariants. It can't see why a try/catch was added after an incident like 2 years ago, or why a field is non-nullable because a downstream pipeline crashes if it isn't, or why two endpoints exist for what looks like the same data because one is for one client and the other is for another client. These invariants live in heads, in Lark, in commit messages, in the people who left last quarter. AI plans look reasonable and miss them anyway. Then the plan gets approved, shipped, and rewritten three months later by a different agent that also doesn't see them. ![A screenshot of a large system diagram with many service nodes and connections, representing the kind of real-world complexity a plan is supposed to account for.]( ) I've watched modules go through three "definitive" rewrites in a year for this exact reason. Every rewrite was locally correct, every rewrite was globally wrong, and none of them talked to each other. --- ## We're trapped The cost of vibe coding isn't the bad code it produces, bad code is recoverable. The cost is what happens to me while supervising it. Reflection time gets eaten, mental models stop forming, and six months in the senior is busier and producing shallower work, while the team's actual ceiling is silently dropping toward the coding agent's. I know there's a balance to strike with this stuff, and I just need time to find it.

Problems with Vibe Coding

2026/03/25 00:00 · Jacky Wong

The more I use coding agents at work, the more I notice one thing: they make you stop thinking too early. I am not saying that we should avoid using coding agents. I use these mfs a lot for bug fixes, rushed features, and dirty work. The speedup is real, and kinda insane, but something feels off. ## "Code first, think later" In traditional development, the order is pretty clear. You think about the interface, the data structure, boundary cases, and tests first, and then you write code. Slower, definitely, but at least you have a whole picture in your head and a much better chance of knowing why the thing works. Now it is the opposite. You ask a coding agent to build on top of an existing project, and let me guess, the prompt is gonna be something like: > "Hey my boss just told me to do this, implement it." Then you drop in some markdown or whatever docs look like a feature request, wait for a while, and boom, the page renders, the API responds. It works. Once it works, you probably will not step back and look at the whole thing the coding agent just generated. Then these kinda so-called feature requirements or bug fixes keep coming one by one, again and again, and congrats, now you have a "shit mountain". | Code base size | Human-led AI coding | Pure vibe coding | | --- | --- | --- | | Very small | 12 | 7 | | Small | 22 | 12 | | Medium | 32 | 24 | | Large | 42 | 56 | | Very large | 52 | 94 | ## Plan mode != Upfront thinking Upfront thinking is not just writing a todo list or turning on plan mode in a coding agent. Real upfront thinking is modeling. What is the core object? Which values are real state and which are derived? Where is the module boundary? If we get three similar requirements next month, can this shape absorb them? At which layer should the tests exist? And at which point will this system break? This part is not sexy. It kills your brain cells like hell, and it will not show up in a weekly report. But it is what makes engineering hold up over time. ## Technical debt, still paid by humans Current coding agents are pretty much all LLM-based. They all have context limits, which means they forget things. Today you patch a module and push with one commit that looks like `+18914 / -7986`. Tomorrow you say, "we can clean it up later." But cleanup rarely happens, especially when you are working in a team. The same module might even get reused by other humans or coding agents in no time. And nobody will know why something exists or why a simple refactor breaks everything after just a few weeks. Then you start using a coding agent to debug it. It reads the git history, sees the commit author, and says, "huh, it was you!" 🤡 Nah fuck off. ## Old-school still teaches I keep seeing people online claiming that zero basics and a few weeks of vibe coding are enough to build production-ready apps. Some even have the nerve to walk into interviews like that 🤷. I do not deny that people learn fast, but getting something to run and building a system are two different things. Interface design, data modeling, complexity control, and technical debt intuition haven't really become outdated. If anything, they matter even more now. Implementation is cheaper. So the decisions that keep a system clean are more valuable. Coding agents can write a lot of code, but they do not know what to keep simple, what to not do, and what will be painful to change later. ## Final thoughts I will keep using these tools. They are too useful to ignore. But the easier it becomes to say "just make it work first", the more I need to remind myself not to skip the thinking part.

可能是最后一次更换博客引擎

2026/03/18 00:00 · Jacky Wong

时间线还是值得记一下: - 2017 年,PHP - 2018 年,Jekyll - 2019 年,Hexo - 2024 年,Astro - 2026 年,Self-Built 这件事其实也不是突然发生的。最近几个月,如果你能看到这个博客仓库的提交记录,大概能看出来我一直在删东西:删不必要的样式,删不必要的依赖,删不必要的中间层,上周甚至连 Tailwind 也一起剔掉了(支持裁员 🤡)。 结果删到最后,我发现最大的那层反而还在,就是框架本身。既然都已经做减法做到这里了,那继续在框架上修修补补就没什么意思了,干脆把框架也干掉。 于是我的博客从 Astro 换成了自建引擎,底层是 Bun。 ## 性能 让 Astro 版本和现在这套引擎在同一台机器上跑同样的 build,对比结果: | Metric | Astro | Self-Built | Delta | | --- | --- | --- | --- | | node_modules | 461 MB | 243 MB | -47% | | Build Time | 12.1s | 702ms | -94% | | Build Output | 1.9 MB | 1.8 MB | -4% | | Homepage Size (brotli) | 17.9 KB | 9.7 KB | -46% | | Homepage Files | 5 | 3 | -40% | 本地构建之前是1.6秒,后来我又把 HTML 压缩整个拿掉了,结果是构建出来的 HTML 体积涨了 3.5%,全局构建时间从 1.6 秒降到了 700 毫秒左右。如果把 Shiki 也完全抽掉,构建时间会变成 110ms 左右(对比Astro减少了99%的构建时间),但是那样的话博客就没有好看的代码高亮了,700ms 的构建时间完全可以接受(傲娇脸)。Cloudflare Workers 上,Astro 版本的 build stage 大约要 28 秒,现在这套自建引擎只要 2 秒。 `package.json` 里的依赖条目也少了挺多。`dependencies + devDependencies` 从 `25` 个降到 `11` 个;如果只看运行时 `dependencies`,则只有3个,有两个甚至和前端不相关。 ```json { "dependencies": { "@upstash/qstash": "^2.9.0", "@upstash/redis": "^1.36.1", "pangu": "^7.2.0" }, "devDependencies": { "@biomejs/biome": "^2.3.13", "@types/bun": "^1.3.5", "chalk": "^5.6.2", "dotenv": "^17.2.3", "enquirer": "^2.4.1", "markdown-it": "^14.1.0", "shiki": "^4.0.2", "wrangler": "^4.70.0" } } ``` 这些数字说明了一件很直接的事:Astro 在我的博客上做了太多我根本不需要的工作。 新的引擎其实很简单:`markdown-it` 负责解析 Markdown,`shiki` 负责代码高亮,模板函数负责拼页面,`Bun.serve()` 负责本地开发,构建脚本负责输出静态文件。没有 Vite,没有 Rollup,没有 hydration,也没有额外的内容系统。 还有一个很实际的变化是,构建产物终于变得可预测了。以前首页表面上看也就一个页面,但背后还有 island runtime、renderer chunk、共享 chunk 这些东西,真实体积并不总是直观看得出来。现在这套就直接多了,首页就是明明白白的 HTML、CSS 和 JS 三个文件,没有别的 runtime 藏在后面。 这次顺手还解决了一个 Astro 时代一直很别扭的问题,就是 `atom.xml`。以前 MDX 正文并不能很自然地直接流进 feed 里,结果 feed 一直是一条额外维护的支线:自定义组件要手工转,HTML 要额外清洗,URL 要额外补。现在,正文本身就是 Markdown,feed 直接吃 Markdown,只有遇到自定义内容块时才退化成 Markdown 友好的版本。页面怎么渲染,feed 怎么降级,都是同一层解释器在决定,而不是正文一套逻辑,RSS 再偷偷长出一套逻辑。 ## 动机 我越来越明显地能感觉到:AI 已经在改变抽象层的成本结构。过去很多框架提供的工程收益,在博客这种低复杂度场景里,开始没有以前那么划算了。 这次重构本身,主要也是 Codex 做完的。它花了大概 3 个小时,把整个站点从头到尾重写了一遍。源码层面的变更大概是新增了 `6888` 行代码,删除了 `6344` 行代码。这件事让我重新想了一遍框架的价值。过去这笔交易是成立的:用一点性能,换一套更容易维护的工程结构,模板系统、组件模型、路由约定、内容 schema,这些东西本质上都是为了帮助人更稳定地理解和修改代码。 但 AI coding 打破了这里的平衡。对 Codex 这类 coding agent 来说,一个手写的 HTML 模板函数并不比一个 Astro 组件更难理解。它可以直接顺着 Markdown、模板、样式和脚本一路往下读,再改具体环节。很多原本为了“降低人类维护成本”而存在的抽象,在这种场景下没有以前那么必要了。 但是这不等于框架没用了。恰恰相反,有了 AI 之后,我反而觉得框架真正该解决的问题更清楚了:不是继续发明一套更花哨的模板语法,而是把边界、约束、验证、缓存、产物组织这些事情做扎实。语法糖 AI 可以学得很快,但边界不清、产物不可预测、降级全靠补丁,这些才是真问题。复杂应用、多人协作、长生命周期产品,框架依然值钱。 ## 最后 所以这次大概真的不用再换了,系统已经简单到不太值得继续折腾,接下来真正应该花心思的,就是博客内容了。 最后请欣赏这曼妙的build输出 ⚡: ![video]( )

A practical macOS setup for Codex CLI and Claude Code notifications, including terminal-notifier, click-to-focus terminal windows, and how to avoid duplicate notifications when you also use Codex App.

Dating App Sucks Pt.2

2026/03/03 00:00 · Jacky Wong

Ok here we go again. I think I've finally figured out the scariest thing about dating apps. They do actually turn finding love into a fucking job search. > Every date feels like a business meeting or something, no sparks, pure cringe. Think about it, we fill out our "resumes" with our best photos and wittiest bios. We list our "desired positions" in the filters. We swipe through "candidates" hoping to get a "decent offer". The whole thing is an HR pipeline with better lighting. But love is the exact opposite of a job search, which follows logic. Love? Personally, I think there is no logic in love. Love is a bias, a fucking tyranny. The bias is that you only want one specific person to do the things literally anyone could do. The tyranny is that you pour all your emotions, irrationally, recklessly, entirely onto another human being. And dating apps have always given me this weird feeling, love obtained through this process feels so bland it's almost offensive. If I were a planet, this whole approach would be like some engineer calculated the perfect speed, angle, and mass, then launched another planet at precisely the right time so we'd form a nice, stable binary star system. How romantic. How efficient, how abso-fucking-lutely dead inside. What I want is a rogue planet hurtling toward me at full speed out of nowhere in the middle of the void. The moment we touch, atoms from two entirely separate worlds are forced into lattices they were never meant to share. Molecular bonds snap, shatter, and reform into something unrecognizable. The pressure breeds temperatures that fuse nuclei into heavy, unnamed elements that no periodic table has ever seen, existing for a few picoseconds before decaying into something else entirely. Oceans of molten rock erupt outward, entire crusts peeled off like skin, shockwaves rippling through mantles at speeds no device could ever measure. What used to be two worlds is now a single, blinding wound in space. Some debris escapes into strange new orbits. The rest? Fuses together so tightly that nothing, not time, not entropy, can pull it apart, until our one last atom is annihilated with the heat death of the universe. I'm not saying dating apps are pure evil, you could still meet someone real on there, the odds exist. But what's truly terrifying about these things is that they teach you how to NOT invest. Everyone on there wants low-risk love. A guaranteed return with minimal downside. But since when has that ever been how love works? I've seen people around me become professional swipers. Always chatting, always got girls around them. And then what? This one's family background isn't great. That one's not pretty enough. Another one said something weird at dinner that gave them the "ick". Next. Next. Next. Bro, stop cos-ing a fucking conveyor belt. Being overly rational in love is a slow way to lose everything. The second anything feels slightly off, they're gone. No friction allowed. But no friction means no sparks either. They end up like the guy in Socrates' wheat field parable, walking through the field, always convinced a bigger stalk is just ahead, waiting, but never actually picking one. And the field does end. It very much does end. Uninstalled.