Live data from Hacker News

Write libraries instead of services, where possible

catern.com

91–100 of 181 posts

Re: Write libraries instead of services, where possible

#91
post #27

It's all fun and games until you hit version n+1 or n+2, and often realize how slow many customers are to upgrade the library. Then there are the potential conflicts in your own dependencies. And let's not forget the occasional breaking change you introduced. You are now sacrificing the money saved by not hosting to maintain what will likely be a growing matrix of possible versions, underlying assumptions, and my per…

> It's all fun and games until you hit version n+1 or n+2, and often realize how slow many customers are to upgrade the library.

Given how frequently needless breaking changes are made, or features are removed and paywalled, I would consider this a feature rather than a bug. Sometimes I have higher priorities than working to support someone else's breaking changes.

Two years ago, I was using an official library for interfacing with a video chat service, and they decided to break the underlying API without updating their library, so I had to rewrite the library myself.

Re: Write libraries instead of services, where possible

#92
> By library, I mean any software that can be run by the user: shared objects, modules, servers, command line utilities, and others. By service, I mean any software which the user can't run on their own; anything which depends (usually through an API) on a service provider for its functionality.

These seem to be odd definitions and they make the article hard to reason about.

Re: Write libraries instead of services, where possible

#93
> By library, I mean any software that can be run by the user: shared objects, modules, servers, command line utilities, and others. By service, I mean any software which the user can't run on their own; anything which depends (usually through an API) on a service provider for its functionality.

this definition makes (open source) self-hosted services libraries too, and so i think it’s wrong and unusable. the distinction between a library and a service is clear enough and colloquial at this point that a redefinition probably obscures rather than clarifies. a library isn’t runnable (~has no binary), a service is runnable (~has a binary)

Re: Write libraries instead of services, where possible

#94

Earlier quoted context omitted.

In my experience a new micro-service considered the default option for anything which could be done as a micro-service nowadays. Library API design is the lost art (almost). And the choose is not always obvious for non-technical reasons. Consider a following example: you have 3 micro-services X, Y, Z which need to interact with a platform G but this interaction requires non-trivial chunk of code. It can be done as a…

This is making technology objectively worse to solve people problems, and this only expands. More software needs iron clad leadership and control. Any organization that lacks this can’t help but produce shit software. There has to be a single person with real decision making power than can force upgrades and prioritization of work, and they need to be able to axe people or teams who can’t hack it.

OK but most business compete in a market. And the people they employ are in a labour market.

It seems that worse is better.

What we see is just another manifestation of the current economic paradigm. Waste is winning.

Making too many pairs of jeans so we burn tons of perfectly good new pairs daily wins.

Throwing hundreds of engineers on problems bashing out hundreds of thousands of lines of code sending megabyte messages between dozens of service instances in multiple kubernetes clusters appear to be a winning move. Otherwise someone would beat them, right?

Re: Write libraries instead of services, where possible

#95
post #29

I don't get it. Can anyone kindly share where this practice can be applied to a commercial software? I am struggling to wrap my head around "how run by user" works where they are using a commercial software service.

There's some confusion in this thread between "service" as out-of-process functionality called via IPC or over the network, and "service" as something done by a service-provider for money, such as emptying your bins.

Re: Write libraries instead of services, where possible

#96

Earlier quoted context omitted.

If you can maintain a stable service API, why can't you maintain a stable library API? I don't see any inherent reason why it should be easier to change the behavior of a service rather than a library.

Because if you ship code to users (library), you lose control. You may want to change something, but your users will just tell you to go pound sand. Conversely, if you keep the implementation on your side (service), you get to control how things work and when things change, and your users don't have a say in this. It's an ownership and control issue.

I don't see the issue here. If I release my_fancy_lib 2.0.0, and I have users who only ever want to stay on the last 1.x release, that's fine. It's no skin off my nose if users choose to stay on an old version forever.

Re: Write libraries instead of services, where possible

#97
post #39

Services usually depend on databases. Libraries usually don’t. Either you need to support every storage backend your users might have, require them to write an integration layer from your generic hooks, or expect them to provision and manage new storage when using your library. In any case you are asking them to do a lot more work (manage the data) and in some sense breaking encapsulation by making them responsible f…

This shows that we lack good abstractions over storage.

Cloud providers are (counter to intuition about their lock-in incentives) improving the space of this. Lots of tools now allow configuring storage by just pointing to various cloud stores, most often a S3 compatible api, not exclusively though.

K8s PersistentVolume is another decent shot at storage abstraction, only a bit raw.

Finally, more and more tools expect you to have a Postgres they can plug into as backend.

All above assumes you want to treat the library data as a big unknown blob. Once data start being corrupted and need bespoke repair, things are less fun. Access and retention is another fun rabbit hole.

Data is complicated.

Re: Write libraries instead of services, where possible

#98
post #85

I think this is roughly true, but at a BigCo it’s not really feasible/easy unless you have a monorepo or otherwise extremely good build/integration tooling to deal with many repos (though Go can sort of deal with this) The issue is coordinating changes (and, god help you, library releases) across repos is often an utter nightmare with multiple PR/merge builds

> it’s not really feasible/easy unless you have a monorepo or otherwise extremely good build/integration tooling to deal with many repos[...] The issue is coordinating changes [...] across repos is often an utter nightmare with multiple PR/merge builds

I'm coming up on a year out of $BIG_TECH_JOB (where the idea of a monorepo was horrifying) and transferred to $WAY_SMALLER_NON_TECH_COMPANY_WHO_USES_TECH_JOB (where the enthusiastically use a monorepo), and have been really confused by repeated claims like this. I really feel like I'm missing something here, because lots of obviously-smart-and-experienced folks repeat it. I'd really appreciate it if you could check my understanding and see what I'm missing.

(To be clear, here I'm assuming that a monorepo is a single repository which contains conceptually-distinct-but-related projects - things which _could_ justifiably be their own repos, but which are kept in one repo for reasons of maintenance and managements - and wherein the build system is such that every sub-project within the repo uses the same package dependency tree, i.e. if ProjectA and ProjectB in the monorepo depend on LibraryZ, then the versions of Z that A and B depend on must be identical for any given commit/build. If I've misunderstood that - if that's just straight-up not what a monorepo is, or if it _is_ but with some extra nuance or sauce - then I guess we can short-circuit the response pretty quickly :P )

Here's how a release of a breaking change of a library would work in a polyrepo world:

* I publish v2.0.0 of my library

* Consumers of that library are notified that a new version exists (via automated email notification, Dependabot, whatever) \ * Anyone who _wants_ to update can do so (independently and at their own rate) - anyone who's comfortable staying on the old version can do so

** If we really want to make things easy for consumers, we can make automated PRs against their repos (this would be the "extremely good build/integration tooling to deal with many repos" you refer to, I suspect? Something like Spotify's FleetShift[0]) to make the change - though in practice this is probably way more trouble than its worth, I've only seen it done for serious security vulnerabilities where a) everyone in the whole damn company has to b) upgrade RIGHT THE FUCK NOW.

* Time goes by

* v1.x gets deprecated

* Anyone still using v1.x gets notified that they are using a deprecated version and strongly encouraged to update

* A little more time goes by (not much!)

* Consequences Occur for people still using the old version - this could be a visit from your friendly InfoSec enforcer, or automatically failing builds, or the removal of v1.x from the package repository (which will indirectly cause failing builds), or...

Conversely, with a monorepo, the situation seems to be:

* I publish v2.0.0 of my library

* Every single team whose code is in the monorepo must coordinate to make the changes to consume version 2. This change, by definition, proceeds at the pace of the slowest team - if one of them is underwater on oncall, or has their only competent engineer on PTO, or has some quirk of implementation (or dependency on old feature) which means they can't update for two months, then _the whole dang monorepo_ is staying on version 1 for two months; no ifs, ands, or buts

** But, yes, if you want to a wide-ranging refactoring to change all the in-monorepo consumers to use the new method, then yeah, modern IDEs are going to have _some_ functionality built-in for that within a single repo. But - by virtue of being a breaking change, it's pretty likely that the change-at-call-site is going to be more complex than simply changing the type or name of the method being called. Maybe the returned object needs different methods called on it. Maybe the method requires an extra parameter (which refactoring IDEs can add to the actual callsite, but cannot implement for you _fetching and providing_ that parameter). At this point, either humans are going to have to comb through the changes to finalize them (at which point, you lose the claimed advantages of being in a monorepo where changes can be done by tooling), or you're going to have to implement some sort of code-parsing system to make correct changes throughout (which, again, is approximately equivalent to the automation work required in the polyrepo case)

So: while, yes, it _would_ be a hassle to "coordinate changes across repos" (though _significantly_ less to coordinate across a single repo-to-repo boundary, especially if both are owned by the same team, than it would to coordinate a whole monorepo's worth of interactions), the joy of a polyrepo situation is that _you don't have to_. Consumers can update when they want to, at their own pace - no coordination necessary! So - yes, there will be a greater _volume_ of PRs required in a polyrepo situation, but a) each of them will be way simpler and the total volume of work will be , b) they are independent (so teams who don't want to update do not hold back those who do).

But - people keep saying "it's easier to make wide-ranging changes in a monorepo", so I _must_ be missing something. What is it?

[0] https://engineering.atspotify.com/2023/05/fleet-management-a...

Re: Write libraries instead of services, where possible

#99
post #36
post #27

It's all fun and games until you hit version n+1 or n+2, and often realize how slow many customers are to upgrade the library. Then there are the potential conflicts in your own dependencies. And let's not forget the occasional breaking change you introduced. You are now sacrificing the money saved by not hosting to maintain what will likely be a growing matrix of possible versions, underlying assumptions, and my per…

> It's all fun and games until you hit version n+1 or n+2, and often realize how slow many customers are to upgrade the library. How is that different with services? I don't develop services, but I can imagine that before breaking the services, you have to poll with your biggest customers and you don't break until they are ready to move to the new version. The alternative I can imagine is to keep providing the old se…

You have the same problem with services and libraries when you’re introducing a breaking change. With services you can make non-breaking changes like security patches on the server side, without needing to coordinate with a customer.

Re: Write libraries instead of services, where possible

#100
post #27

It's all fun and games until you hit version n+1 or n+2, and often realize how slow many customers are to upgrade the library. Then there are the potential conflicts in your own dependencies. And let's not forget the occasional breaking change you introduced. You are now sacrificing the money saved by not hosting to maintain what will likely be a growing matrix of possible versions, underlying assumptions, and my per…

Write a library, deploy it as a service if necessary.
Post reply on HN