| Yes, others also include: - Proxies that upload/retrieve assets to multiple cloud providers (i.e. upload files to / retrieve from GCS and S3 in case one is down) - A service that screens/transforms attachments/uploads for security before allowing them to reach other services - An API for sending mail/SMS/other contacts via multiple providers to deal with outages to one or more providers. Often, these are before built as libraries and imported into multiple projects which is the wrong approach. Offering up an API for these instead can help decouple. However, the author probably doesn't understand versioning and deprecates or makes breaking changes to APIs and then has to update a bunch of consumers. If you want a decoupled system, you have to not break the system. This is why legacy stuff exists at older companies. Once API v1 of the mail sending service is done and working, there's no reason you need to break it, or add new features, or take it down. Keep it running and also run v2 so that people can use the new features. The author is probably running v1 and v2 out of the same codebase and overwriting the v1 history so they can't maintain it, that's just bad software project management. Maybe the title should switch to: "coordinating a complex architecture is hard, I only build easy stuff" |
This assertion - that it is a wrong approach - is false. And an API call that involves RPC is not necessarily more decoupled than one that doesn't. Coupling is another word for correlation of changes over time. RPC has no necessary implication of reducing this.
What makes the library approach awkward is usually persistence, error recovery and asychronisity, not coupling. The need for things like retries that survive restarts, which means they need persistent queues, even if that's just files in a directory. But none of these things necessarily require service implementation rather than library implementation, not even sandboxed attachment screening - that's a subprocess (potentially farmed out to another box container style, which is a service), not a service in itself.
People have been doing versioning with libraries for decades; there are a lot of different ways to crack that nut, and ignorance isn't an argument either way, because it cuts both ways.
When you have the same job that needs the same kind of queuing, same error recovery, same resource management across different applications or areas of a single big application, that's when it makes more sense to try and package it into a service. Something that is stateful and long running, and not just some code at the end of an RPC. Something that might need very different resource consumption requirements than the calling application - e.g. a CPU intensive operation in an otherwise lightweight app. Something that needs to be scalable independently of other components in the system. That kind of thing.