You are viewing archived messages.
Go here to search the history.

ruru4143 2025-09-16 15:01:42

Introducing the HandAxe Collections Pattern Language is a abstract rundown on all operations you can have on common collection types. The switch to edges instead of indices is really nice.

Sadly this is the only public artifact of this project

📝 Introducing the HandAxe Collections Pattern Language - Strange Loop

Strange Loop is a conference for software developers covering programming langs, databases, distributed systems, security, machine learning, creativity, and more!

misha 2025-09-18 07:11:11

Please, share your favorite resources about approaches to versioning of APIs, DB schemas, code libraries etc.

Versions rollout, support, and deprecation still feel unsolved and ad-hoc.

Marek Rogalski 2025-09-18 07:36:49

Very true. That's why static linking (modular monoliths) are so much nicer to work with.

Here is a fun idea: separately built pieces of code often lead to incompatibility and bugs when they exchange data whose schema has changed. Would it be possible to keep the data distributed but send code as messages (as opposed to keeping the code distributed and sending data as messages).

misha 2025-09-18 07:40:57

was hoping for approaches within traditional architectures 😅 e.g. blog.datomic.com/2017/01/the-ten-rules-of-schema-growth.html but, say for SQL databases.

For scenarios where 1 field is no longer enough for <feature> and second is added, but prev api version still needs to be online, etc.

misha 2025-09-18 07:45:02

a catalog of such scenarios would help too

George Campbell 2025-09-18 10:01:33

TL;DR: versión 1 and 2 of a library should packaged as deferent dependencies that can be loaded into the runtime at the same time to make migrations possible earlier.

jolynch.github.io/posts/semver_considered_harmful

misha 2025-09-18 11:40:05

Libraries are the easiest case of all, especially pure ones.

Just(?) make runtime names be different between versions, eg. don't reuse java class names between versions, so many of those could coexist within the same runtime.

Not pure (with some singletons or other equivalents of shared state) are not so trivial though.

Tom Larkworthy 2025-09-18 11:53:12

libraries -> semver

APIs -> never deprecate, append only. Add route prefix v1/ v2/ etc. for breaking changes. I like the Google API Design guide, but also the Zalando one.

DBs -> Expand - contract pattern -> Alembic or something similar to remember where we are. Zillions of articles on the expand and contract pattern, I feel that is well trodden best-practice, which also applies to infra changes.

misha 2025-09-18 13:09:39

semver sucks

never deprecate api - not viable in the slightest

misha 2025-09-18 13:14:13

"expand and contract pattern" just means "keep several versions alive simultaneously, sometimes deprecate old ones". zero specifics.

George Campbell 2025-09-18 14:24:33

This is an overview of how we did hundreds of database migrations while minimizing client burden.

image.png

Jari 2025-09-18 14:25:35

For APIs, I think server should return api version number and client should know how to use it. jarirajari.wordpress.com/2022/02/08/api-design-fundamentals

📝 REST API Design Fundamentals

This post addresses the fundamental API design problems and gives solutions to them. The often presented problems are: API / schema versioning during API evolution RESTful way to design nested Reso…

Daniel Buckmaster 2025-09-18 15:08:41

This is my personal canonical text for web API versioning stripe.com/blog/api-versioning

📝 APIs as infrastructure: future-proofing Stripe with versioning

APIs as infrastructure: future-proofing Stripe with versioning

Jared M. Smith 2025-09-18 17:02:31

Are you specifically looking for external-facing versioning? For internal, my favorite technique is live code generation with a compiled language, where I can quickly see what I’ve broken.

If I didn’t have legacy architecture, and could follow that concept all the way through, I’d reach for Lamdera: dashboard.lamdera.app/docs/overview. Then all API changes and migrations become type-safe mappings. Obviously that doesn’t work for everything, but it’s powerful when you go all-in.

Libraries are the easiest case of all, especially pure ones.

Elm has spoiled me to everything else. 😊

misha 2025-09-18 17:46:06

Not only external-facing one. But external is the hardest, because it is a superset of all others, and has all the problems, smaller pieces might not have: shared global state across versions (db), unknown open set of clients spread across time (you never know if 4yo client will call some endpoint within next 5minutes), etc. (actually, what else?).

On the day job, I need to figure out cheapest 80% solution to at least detect (if not enforce) backward compatibility breakage, balancing dev speed vs. support burden.

In my after hours project (think unisonlang, but retrofit, not green field), I need to figure out how "library release artifacts" look like across the versions, so those would cooperate with the rest of similar libraries or projects.

So any strategies, tactics, povs, tips and tricks, gotchas, usecases, – help, at least to map out the problem/solution space, before grounding onto particular tech stack.

misha 2025-09-18 17:50:25

re: semver sucks

and about decomposition of "change" into backward in/compatible ops

here:

spec – roughly json schema, but for clojure data and fns,

clojure – lisp on jvm

maven – the packages repository for jvm langs

youtube.com/watch?v=oyLBGkS5ICk

misha 2025-09-18 17:51:19

re: stripe's runtime api response migrations: inkandswitch.com/cambria

📝 Project Cambria: Translate your data with lenses

Changing schemas in distributed software is hard. Could adopting bidirectional lenses help?

Tom Larkworthy 2025-09-18 18:40:52

expand and contract is quite clear prisma.io/dataguide/types/relational/expand-and-contract-pattern. You add expressibity (new structure), migrate the usage, then contract expressivity (remove the old). If you want to deprecate an API its the same thing except the migrating the usage involves telling every caller to stop using the old API which is not practical for public APIs.

At Google it was common to find the V1 proto was transforming to the V2 proto and then just calling the internal v2 handler. v1 was never deprecated, but there was not 2 business logic handlers. Its not always possible to nest, depending on how bad you messed up the v1 design. I always work from the assumption you can never deprecate an API if it is public. Internal APIs => expand and contract.

Google API guide prohibits removing fields from protos, and the modern gRPC removed required fields because they prevent future migrations. Every long lived proto message is stacked with deprecated fields, but they are at least costless on the wire.

A fancy DB migration technology I keep staring lustfully at is pgroll.com/blog/introducing-pgroll-zero-downtime-reversible-schema-migrations-for-postgres but I have never used it (its docs even say it implements expand and contract).

📝 Using the expand and contract pattern | Prisma's Data Guide

In this article, we introduce the expand and contract pattern to help migrate data and clients to a new schema.

Bill Mill 2025-09-19 01:07:57

“never deprecate API” worked very well for the team I used it on for a large project that had a high request load and a low error rate, for whatever that experience is worth

Not saying you need to use it, but i think dismissing it out of hand is unwise

misha 2025-09-19 16:06:29

killedbygoogle.com :))

There are plenty of business situatoins where "never deprecate an api" is just not an option.

Even from mechanical new-data-required point of view (legal, financial, regulation, gov id auth, etc.), not to mention all the flavors of "we can't afford to spend time on it, so iphone4 support goes bye bye". E.g. not everything has sensible (legally viable) defaults to upgrade v1 req to v2 req to return v2 resp.

"you should have never screwed up v1" – not a strategy.

"I've never had a use case where I needed to deprecate things" – not a tactic.

"never deprecating things costs you nothing (or is always 1) affordable 2) by you)" – is just not true.

"you screwed up your architecture, and now versioning is a mess. just file for bankruptcy, or start over" – rarely an option.

--

anyways, reading through the linked articles, thanks!

misha 2025-09-19 16:11:47

some of "graceful" deprecation tactics:

Bill Mill 2025-09-20 02:14:23

I wrote about our model here: notes.billmill.org/blog/2024/06/Serving_a_billion_web_requests_with_boring_code.html

A more careful phrasing of “never deprecate API” in the sense I mean it here is “only make backwards-compatible changes, and if you ever want to remove a response field or API endpoint, deprecate it, wait a long time, and then remove it if metrics tell you nobody is using it”

I don’t think that prevents having a v2 of your API, but the one I wrote about there is still on v1 7 years and 10s of billions of requests later

misha 2025-09-20 08:48:13

Nitpicking here, but I think this is very important within this topic: you can't always "only make backwards-compatible changes".

(you, gov, payment processor) need a new field? – breaking change.

This is not only skill or desire issue, it is not always within your (service) control.

Yeah, you can try to preserve structure, but sooner or later the only sensible backward-compatible response you would be able to give is "sorry, no, upgrade".

Yes, api stays online, yes, response adheres schema, but actual feature workflow this api call is part of – no longer useful because it is just a dead end.

And I am not sure I would always(ever?) choose this dead end over 404 "api no longer available", as 404 at least does not give me hope "sorry no" is temporary (human is not always in the loop to read human readable error message to detect meaning change without response structure change, e.g. [200 "result"] vs [200 "sorry, no, upgrade"]).

misha 2025-09-20 09:04:16

Once a field was exposed in the public API, it would be exposed forever unless it became a security problem

Nitpick: you mention 1 reason to remove field yourself: security.

What you call API here, seems to mean api response. Adding new fields to existing response is safe (for some formats, like json), keeping old fields is doable and +- cheap.

But API is not only response but a request too: where ignoring incoming args is safe, cheap and easy, but requiring new args is backward incompatible.

A very good break down of this asymmetry is in video linked above: youtube.com/watch?v=oyLBGkS5ICk

Tom Larkworthy 2025-09-20 09:11:14

The old APIs in financial sector are XML based and still work (excluding availability). What they do is start introducing modes, like we will respond with Y if you sent X in the request unless z was present. They are awful to work with but you can work around any problem with an additional logical layer of indirection.

Daniel Buckmaster 2025-09-20 09:29:28

More reading - I've quite enjoyed Phil's work over the years even though I haven't found it so applicable personally. apisyouwonthate.com/blog/api-versioning-has-no-right-way

📝 API Versioning Has No "Right Way"

API versioning is a really difficult topic, and sometimes seen as a merely

religious debate. It’s done differently at different companies, and different

teams within different companies often vary.

Some folks move from approach A to approach B, and when approach B solves their

specific issues they act like

misha 2025-09-20 12:52:24

Tom, the qualifier to "The old APIs in financial sector ... still work" is " some": "some old apis still work".

It is possible to overcome a lot of things, but just not all of them, e.g. due to (lack of) funding or just things being out of your control.

When your transitive dependency disappears, what you gonna do?

docs.stripe.com/payments/older-apis#deprecation-of-the-sources-api

We’ve deprecated support for local payment methods in the Sources API and plan to turn it off.

Again: developers.google.com/google-ads/api/docs/sunset-dates#timetable

Notice how google (you give as a never-deprecate-an-api example) has v19 as the oldest available version in that table 🙂 (and yes, there were at least 18 major versions, and the v1 is just 7 years old), and quote developers.google.com/google-ads/api/docs/sunset-dates#differences_between_deprecation_and_sunset

API endpoints for the sunset versions stop working ** after the sunset dates. The Google Ads API will throw an error if you try to access the API endpoints of the sunset versions.

Meaning even top100 money bag in the world choses to shut down 1yo apis (v19 release February 26, 2025 , shutdown February 2026 )

misha 2025-09-20 12:52:39

"never, unless" is not "never"

Tom Larkworthy 2025-09-20 12:59:00

I think Google ads is a special case

Tom Larkworthy 2025-09-20 12:59:48

On everything I have worked on that did not make sense

misha 2025-09-20 13:01:55

Bill, (some highlights are mine, some - original)

Given that we (tried very hard to) never make backwards incompatible changes to the database, the app s would check at startup that their database schema version number was greater than or equal to the database version number stored in the database, and refuse to start if they were not.

This was > a general pattern > : If an app encountered any unexpected or missing configuration, it refused to start and threw > noticeable > , hopefully clear, > errors > .

:)

Everything is way easier for internal "network of apis and clients", simply because you can have dashboard with all mismatches. "Internal apis" - is an important qualifier to any "never do this" and "easy to do that".

On the other hand:

I use your api. You don't even know this. You shut down v1. My app does not start anymore. You never see this. What do I do? What do you do? :)

misha 2025-09-20 13:04:05

I think Google ads is a special case

it only takes 1 "I just don't wanna" from your transitive api dependency vendor to force you to shut down your v1, not even any legal, math, funding, security reasons.

Bill Mill 2025-09-21 16:05:40

I use your api. You don’t even know this. You shut down v1. My app does not start anymore. You never see this. What do I do? What do you do? :)

It would be a long process of announce a deprecation a long time in advance, add warnings, eventually when it’s close to being shut off do announced intermittent blackouts, then finally shut it off. It would be extremely protracted and painful, but that was appropriate to the API we were building - it was a big commitment

(you, gov, payment processor) need a new [required] field [in the request]? – breaking change.

yes, absolutely! That would be a new endpoint, that is a consequence of this API design. You can add endpoints safely but not add a required field to them. This isn’t a gotcha, that was the design

Joshua Horowitz 2025-09-20 00:25:31

The LIVE Workshop (all about live programming) is free & online this year, and coming up soon. We will be “premiering” presentation videos on Saturday, September 27, after which they will be available to watch on your own time if you prefer. Then, on Saturday, October 4, we will have live (har har) Q & A and discussion over Zoom.

Details are up at liveprog.org. We’re still finalizing schedule, links, etc., but you can read a bit about the 12 exciting projects that will be discussed at the workshop.

I hope some of you can come!