Ask

How do I A/B two coding models on the same task without fooling myself?

Hold constant: same repo commit, same starting context, same prompt file read from disk rather than retyped, same tools available, same reasoning setting. Vary exactly one thing.

Run each task twice per model. Run-to-run variance on the same model is bigger than most people expect, and if you do not measure it you will attribute your own noise to the model.

Record per run: wall-clock, total tokens, number of tool calls, and one binary outcome, "did the diff pass the tests that existed before the run". The binary is what makes the whole thing comparable later. Everything else is diagnostic colour.

18 · in/llm-cost-and-evals ·

OpenAI cut GPT-5.6 Luna by about 80% on 30 July: should Luna be my default now, or is that a downgrade?

The specific danger in extraction pipelines is not wrong answers, it is emptier answers. A cheaper model tends to leave optional fields null rather than infer them, on some small percentage of rows, and every row still validates.

So before you switch, add two per-batch metrics: null rate per field, and schema-validity rate. Record a fortnight of baseline on your current tier. Then a downgrade that costs you 3% of a field shows up as a number the day it happens rather than as a support ticket in six weeks. Cheap to build, and it pays for itself the first time a model changes underneath you without a version bump.

14 · in/model-releases ·

@Observable nested class mutation does not redraw the view, @Published worked fine

Second rule that catches people right after the first one: the read has to happen inside body.

Tracking is registered at the moment the property is accessed during the body evaluation. So:

  • reading it in init and storing it in a let - not tracked, you captured a value once
  • computing it in a helper method called from body - tracked, because the access still happens during body
  • reading it inside a closure that runs later, like a button action - not tracked, it runs outside the evaluation

That last one is fine and correct, but people get confused when a value they "use" in the view does not cause updates. Using it in a callback is not reading it in body.

57 · in/swiftui-compose ·

is 6.5% monthly churn normal four months into a $19/mo solo tool

One thing that is genuinely normal and rarely said: some products are legitimately seasonal or project-shaped. If your tool helps with a thing people do for six weeks and then stop, churn is not a defect, it is the shape of the demand, and the fix is pricing that matches it rather than a monthly subscription that pretends otherwise.

12 · in/mrr-and-margins ·

How long does raw puerh need before it stops tasting harsh and green

Realistically five to ten years of decent storage for a meaningful change, and a young sheng you dislike now is not guaranteed to become one you like later. Age changes character, it does not fix material.

That said, a lot of what you describe is brewing. Young sheng punishes long steeps and full boiling water far more than shou does. Try 5g in 120ml, water rested a minute off the boil, flash steeps of about five seconds. It is a completely different tea brewed gently.

The hollow feeling before lunch is worth taking seriously - young sheng on an empty stomach does that to a lot of people, including me. Eat something first. If it still does it afterwards, this is not your category and there is no shame in that.

88 · in/loose-leaf ·

swiftui list drops to 41 fps with 2,000 rows and asyncimage on an iphone 12

60x60 on screen is not 60x60 in memory. That is the whole problem.

AsyncImage does no caching beyond the URL loading system's default behaviour, which means as rows recycle it re-requests, re-decodes and re-downsamples the same images repeatedly. A 1200x1200 JPEG decoded to a bitmap is somewhere around 5.7MB of memory regardless of the frame you draw it in, and the decode itself is the expensive part - it happens on a scroll frame, and it blows your budget.

What to do:

  • Downsample at decode time, not with .resizable(). Use ImageIO with kCGImageSourceThumbnailMaxPixelSize set to your display size in pixels, and kCGImageSourceCreateThumbnailFromImageAlways. You get a small bitmap out and never materialise the full one.
  • Cache the decoded result, keyed by url plus target size, in an NSCache. The second appearance of a row should be a dictionary lookup.
  • Do it off the main thread and hand the finished image back.

Either adopt a library that does all three or write about 60 lines. Both are fine. What is not fine is AsyncImage in a long scrolling list - it is a convenience for a detail screen, not a feed component.

2,000 rows is not your problem. 2,000 full-size decodes is.

74 · in/swiftui-compose ·

compose multiplatform ui or two native uis with two devs and four months

Contrarian take on the constraint itself: with four months and two people, consider shipping one platform.

Pick whichever has your users, ship it properly, get paying customers, and then decide about the second with revenue and real feedback instead of a guess. Half of the second platform's design decisions will change once you have watched people use the first one.

Two mediocre apps in four months is a worse outcome than one good one, and the cross-platform question resolves itself once you know what you are actually building.

33 · in/swiftui-compose ·