HNHacker News
TopNewBestAskShowJobs

sophiabits

259 karma · joined February 13, 2023

sophiabits.com/blog
submissionscomments
sophiabits··on Why AI hasn't replaced software engineers, and won't
> You can't fire Claude if it fucks up

What's the difference between "firing" Claude vs moving to a model from a different provider? The latter seems very analogous to firing an employee for performance and backfilling with someone new.

Re the rest, it's just not my experience that models become incapable of making good decisions in cases where input token count > the context window, but ymmv based on domain.

A very extreme example of this: a couple years ago when GPT 4 was state of the art and the 32K context variant was gated to design partners I worked at an EdTech company in the college admissions space that wanted to produce quarterly reports on student progress for parents. That involved crunching a LOT of data (multiple hours of meeting transcripts per week, very detailed notes about student activities, their general profile - UK and US admissions function very differently!)

It was a difficult problem, but we _did_ manage to produce these reports 4K output tokens at a time at a level of quality that exceeded what humans could do internally, and models+the surrounding tooling have only gotten better since then.

sophiabits··on Now AI agents need what RSS does
TIL you can get RSS feeds for YouTube channels. Thanks for this!
sophiabits··on An Engineer's Post Protesting Laptop Surveillance Is Going Viral Inside Meta
> Selfishly, I don't want my screen scraped because it feels like an invasion of my privacy, [...] But zooming out, I don't want to live in a world where humans—employees or otherwise—are exploited for their training data.

I wonder whether this Meta employee felt the same way about privacy a month ago, before they were personally impacted by this new initiative.

sophiabits··on Postmortem: TanStack NPM supply-chain compromise
I do not envy the position the npm team are in. They removed the ability to unpublish packages as a response to the left-pad incident[1] because it wasn't desirable for individual developers to break downstream dependencies by pulling their package maliciously.

Of course the side effect is that now it's much harder to pull packages for legitimate reasons :/

[1] https://en.wikipedia.org/wiki/Npm_left-pad_incident

sophiabits··on Why TUIs are back
A browser is OOM more expensive to run than a terminal app, regardless of what you're running inside said browser
sophiabits··on Backpacks got worse on purpose
Purchasing power is probably a better metric in a vacuum, but it's hard to analyze accurately

For example, the comment you're citing is claiming that because minimum wage has increased only 3x over the same period of time in which inflation has eroded the relative value of a dollar by 6x, that wages overall have increased at half the rate of inflation. But minimum wage is a measurement of a minimum, while inflation is a measurement of /average/ price increase so they can't be compared 1:1 in this way.

The housing argument also seems odd. In New Zealand (where I'm from -- I'm not familiar with the US' housing market, so the commenter could be right about that geo!) house prices have increased by far more than 20x since the 70s, but the houses available are of substantially higher quality due to improved regulations (e.g. all newer homes are subject to healthy homes rules which mandate insulation) so just comparing inflation-adjusted home prices vs income doesn't tell the full story

(Aside from that, a whole heap of items like food, electronics, transportation are all both far cheaper AND higher quality today than in the 70s)

sophiabits··on When does MCP make sense vs CLI?
> the MCP server is automatically launched when the Agent loads that skill

The main problem with this approach at the moment is it busts your prompt cache, because LLMs expect all tool definitions to be defined at the beginning of the context window. Input tokens are the main driver of inference costs and a lot of use cases aren't economical without prompt caching.

Hopefully in future LLMs are trained so you can add tool definitions anywhere in the context window. Lots of use cases benefit from this, e.g. in ecommerce there's really no point providing a "clear cart" tool to the LLM upfront, it'd be nice if you could dynamically provide it after item(s) are first added.

sophiabits··on Claude Code 2.0
Comments are often the best tool for explaining why a bit of code is formulated how it is, or explaining why a more obvious alternate implementation is a dead end.

An example of this: assume you live in a world where the formula for the circumference of a circle has not been derived. You end up deriving the formula yourself and write a function which returns 2piradius. This is as simple as it gets, not hacky at all, and you would /definitely/ want to include a comment explaining how you arrived at your weird and arbitrary-looking "3.1415" constant.

sophiabits··on Structured Outputs in the API
I’ve especially noticed this with gpt-4o-mini [1], and it’s a big problem. My particular use case involves keeping a running summary of a conversation between a user and the LLM, and 4o-mini has a really bad tendency of inventing details in order to hit the desired summary word limit. I didn’t see this with 4o or earlier models

Fwiw my subjective experience has been that non-technical stakeholders tend to be more impressed with / agreeable to longer AI outputs, regardless of underlying quality. I have lost count of the number of times I’ve been asked to make outputs longer. Maybe this is just OpenAI responding to what users want?

[1] https://sophiabits.com/blog/new-llms-arent-always-better#exa...

sophiabits··on New LLMs aren't always better
I wanted to document a particular genAI antipattern which I've seen a few times now.

LLMs are theoretically pretty fungible, because you send English and get English back--but in practice you still need to do some amount of technical due diligence before swapping model. These things are benchmarked on tasks which rarely resemble your specific use case. Blindly swap models at your own risk!

Something that has become very clear since the advent of GPT-3.5 is that LLMs are far from magic, and using them does not remove the need for good engineering fundamentals. It's important to have a solid eval suite so you can quickly benchmark your system against different LLMs, because the APIs we're all building on are constant moving targets.

sophiabits··on Anti-patterns in event-driven architecture
Even with this setup in place you need a heightened level of caution relative to a monolith. In a monolith I can refactor function signatures however I desire because the whole service is an atomically deployed unit. Once you have two independently deployed components that goes out the window and you now need to be a lot more mindful when introducing breaking changes to an endpoint’s types
sophiabits··on Breaking up is hard to do: Chunking in RAG applications
Not sure what the situation is like now, but we stopped using LangChain last year because the rate of change in the library was huge. Whenever we needed to upgrade for a new feature or bug fix we’d be 20~ versions behind and need to work through breaking changes. Eventually we decided that it was easier to just write everything ourselves.

This is from the first half of 2023 or so; maybe things are more stable now, but looks like the Python implementation is still pre-v1.

sophiabits··on Garbage collect your technical debt (2021)
The other possibility (which is common in startups) is that often the “right way” is different depending on the scale of the system you need to design for. In cases like this you end up with technical debt a year down the line, but at the time the feature was shipped the engineering decisions made were extremely reasonable.

I’ve seen a few colleagues jump to writing off all technical debt as being inherently bad, but in cases like this it’s a sign of success and something that’s largely impossible to avoid (the EV of building for 10-100x current scale is generally negative, factoring in the risk of the business going bust). There’s a kind of entropy at play here.

Big fan of tidying things up incrementally as you go [1], because it enables teams to at least mitigate this natural degradation over time

[1] https://sophiabits.com/blog/be-a-tidy-kiwi

sophiabits··on Garbage collect your technical debt (2021)
Big fan of this. Here in New Zealand we have a slogan “be a tidy kiwi” that encourages people to pick up their litter and be good stewards of for our natural environment

Imo the same mentality is good to have in software, and I’ve always appreciated being in a team that makes codebase improvements alongside feature additions. It makes things a lot more pleasant

sophiabits··on What can LLMs never do?
This already exists (in a slightly different prompt format); it's the underlying idea behind ReAct: https://react-lm.github.io

As you say, I'm skeptical this counts as AGI. Although I admit that I don't have a particularly rock solid definition of what _would_ constitute true AGI.

sophiabits··on TypeScript: Branded Types
This sounds like an argument against TypeScript in general, no?

e.g. If I am parsing a string to a number via Number.parseInt, I don’t need a “: number” annotation because I can just call the variable “myNumber” and use that.

Branding a string is in many ways an extension on the idea of “branding” my “myNumber” variable as “: number” rather than leaving it as “: any”. Even if the TS type system is easy to bail out of, I still want the type annotations in the first place because they are useful regardless. I like reducing the number of things I need to think about and shoving responsibility off to my tools.

sophiabits··on TypeScript: Branded Types
Happens a lot with junction tables ime. e.g. At my last job we had three tables: user, stream, user_stream. user_stream is an N:N junction between a user and a stream

A user is free to leave and rejoin a stream, and we want to retain old data. So each user_stream has columns id, user_id, stream_id (+ others)

Issues occur when people write code like the following:

streamsService.search({ withIds: userStreams.map((stream) => stream.id), });

The issue is easily noticed if you name the “stream” parameter “userStream” instead, but this particular footgun came up _all_ the time in code review; and it also occurred with other junction tables as well. Branded types on the various id fields completely solve this mistake at design time.

sophiabits··on Adding type safety to object IDs in TypeScript
Type-prefixed IDs are the way to go. For completeness it's worth noting that the first example using the `string | 'currentNode'` type can be slightly improved in cases where you _do_ want autocomplete for known-good values but are still OK with accepting arbitrary string values:

  type Target = 'currentNode' | (string & {});
  const targets: Target[] = [
    'currentNode', // you get autocomplete hints for this!
    'somethingElse', // no autocomplete here, but it typechecks
  ];
sophiabits··on Show HN: Open-source x64 and Arm GitHub runners
There’s a French think tank called “The Shift Project” which actually produced a report estimating CO2 impact of data transfer a few years ago [1]!

The numbers are obviously very rough; there’s a LOT of factors to consider and which vary from one node to another. But the methodology is quite comprehensive, e.g. they factor in power consumption of the end user’s device while waiting for the data to transfer over the wire

Green software engineering is interesting to me because it seems like a good way to impact greenhouse gases _without_ requiring consumers to change anything about their lifestyle (which is the hard part of climate change…) There’s a cool presentation from Rasmus Lerdorf from around the time when PHP7 released where he estimated a 50% adoption rate of PHP7 would result in a saving of 3.5B kg CO2/year iirc, purely because of the compute efficiency gains from PHP6 -> PHP7.

I used their numbers to calculate that swapping our CI/CD clones at my day job over to shallow clones saved (maybe) 5.5 kg/week of CO2 emissions [2]. Not quite as impressive as the PHP7 figures, but I still think it’s kinda neat.

[1] https://theshiftproject.org/en/lean-ict-2/

[2] https://sophiabits.com/blog/the-cost-of-bandwidth

sophiabits··on Does your test suite account for weak transaction isolation?
The problem is that you don’t really know if your mock accurately implements the behavior of the database. The only way you could verify the mock behaves correctly would be to run the mock and a real database instance through a set of tests to verify they both implement different isolation levels identically.

At that point—why bother with the mock at all? Cutting out the intermediary and running integration tests of your application against a real database will be faster.

You can’t use SQLite here either because all SQLite isolation levels are serializable anyway, which is _very_ different from how PostgreSQL works. Testing against SQLite could end up giving you a false sense of security that your code is safe against race conditions, whereas in reality it’s vulnerable when connected to a PostgreSQL server because of the difference in default isolation levels

At this level of testing detail the only real option is to test against a real database that matches what you’re running in production. Otherwise you’re just testing a mock.

sophiabits··on Pushing ChatGPT's Structured Data Support to Its Limits
Yeah, the folks working on aider (AI pair programming) [1] found that these kind of tricks reduced performance for them.

I’m pretty confident there will be situations where you can measure a statistically significant performance improvement by offering a tip or telling the model you have no hands, but I’m not convinced that it’s a universal best practice.

A big issue is that a lot of the advice you see around prompting is (imo) just the output of someone playing with GPT for a bit and noticing something cool. Without actual rigorous evals, these findings are basically just superstitions

[1]: https://aider.chat/docs/unified-diffs.html

sophiabits··on Ask HN: How do I train a custom LLM/ChatGPT on my own documents in Dec 2023?
Yeah +1

We originally started out building features with LangChain (loading chains from YAML sounded good—it felt like it would be easy to get non-engineers to help with prompt development) but in practice it’s just way too complicated. Nice idea, but the execution feels lacking.

It also doesn’t help that LangChain is evolving so rapidly. When we first started using it a lot of code samples on the internet couldn’t be copy/pasted because of import paths changing, and at one point we had to bump by ~60 patch versions to get a bug fix, which was painful because it broke all kinds of stuff

sophiabits··on SQL as API
Instead of inventing your own DSL for filtering, there are also some well-specified standards.

ODATA [1] is probably the main one, and it’s adopted by e.g. Microsoft’s Azure APIs. JSON:API [2] is another, although I’ve never seen it used anywhere personally.

They’re both pretty heavy specifications so I’ve never bothered implementing anything that 100% follows them. But I have picked bits and pieces from time to time—in particular ODATA’s idea for filtering is nice and comprehensive imo, and there are a number of libraries in various languages which handle parsing its filter strings into structured data.

[1] https://www.odata.org/ [2] https://jsonapi.org/

sophiabits··on 10k Bounty for Rewriting Prettier in Rust
There’s a project called “dprint” which you can use in the interim if Prettier is a bottleneck :) It’s a Rust-based code formatting platform with a Prettier plugin (among others). It’s a lot faster than running Prettier directly [1]

The dprint plugin wraps Prettier under the hood so compatibility is good. The perf wins come from formatting files in parallel and incrementally.

[1] https://david.deno.dev/posts/faster-prettier-with-dprint/

sophiabits··on 10k Bounty for Rewriting Prettier in Rust
Adding on to the other comment about CI setups, when I benchmarked removing eslint-plugin-prettier from my work’s ESLint configuration we saw a 37.5% speedup. On our fairly slow CI agents that ended up being pretty significant (~34s per run).

I _wanted_ to drop the plugin and have Prettier automatically run on as a pre-commit hook (as you suggested) but in the end I lost :) We wound up keeping the plugin and eating the slower pipeline time.

Of course there’s more overhead than just Prettier in this case—the ESLint plugin itself will be contributing towards the added runtime!—but depending on your codebase and CI machines, Prettier can definitely slow things down quite a bit. CI taking over a minute or two is a big drag on developer productivity imo.

Ideal world is that everyone is on board with code formatting as a pre-commit task that only touches modified files so it doesn’t bloat CI unnecessarily, but it’s not always possible :(

sophiabits··on Next.Nav: VSCode Extension for Next.js App Router Views
This is pretty cool! App router is pretty hard for me to visualize when looking at a file tree (ditto for SvelteKit—I find it hard to grok all the +page.svelte or page.tsx files)

Visualizing it all as a tree structure feels like an improvement. I’ll definitely give it a spin :)

sophiabits··on You Don't Need UUID
Also as a developer I really dislike UUIDs because the hyphens make it impossible to double-click copy.

It’s a small gripe, but I need to copy IDs multiple times per day and it adds up. Other ID formats like cuid or KSUID don’t have hyphens in their canonical representation, and it makes them far more pleasant to work with

sophiabits··on The HN UI is terrible
A case study: The story goes that Snapchat intentionally made their UI hard to use as a way of filtering out adults. An influx of adults would’ve made their app a lot less “cool” in the eyes of their target audience (teens)

HN’s UI definitely feels to me like it serves a similar purpose, whether intentional or not :)

sophiabits··on A Sneaky Golang Bug
In C++ there’s an attribute called nodiscard which solves this problem assuming the API you’re consuming is written well. When you apply this attribute to a function, the compiler emits a warning when that function’s return value isn’t used by the developer [1].

Lots of other languages take the same approach. Rust’s must_use attribute is basically the same as nodiscard.

It’s a nice way of solving the problem imo.

[1] https://en.cppreference.com/w/cpp/language/attributes/nodisc...

sophiabits··on Ask HN: Could you share your personal blog here?
https://sophiabits.com/blog

I started a few years ago but only found a good rhythm in the past ~year. I am 75% of the way to my (arbitrary) goal of hitting 100k written words.

Lots of posts on architecture, AWS, and performance with a little bit of engineering leadership mixed in.

Some recent posts:

* https://sophiabits.com/blog/understanding-secrets-manager (did you know Secrets Manager “staging labels” can be used to colocate related secrets?)

* https://sophiabits.com/blog/using-terraform-plan-to-write-ia... (write Terraform for your infra without learning Terraform)

* https://sophiabits.com/blog/object-ids-for-humans (ID formats have surprising performance and DX impacts!)

* https://sophiabits.com/blog/evaluating-a-new-technology (my checklist for when a team member proposes adding something new to our tech stack)

RSS: http://sophiabits.com/feed.rss.xml

Page 1 of 3Next →