In the end I also settled on clear module boundaries, but only for languages that have them. Ruby/Rails apps don't have such boundaries (unless you make pure functions as Gems or something) whereas I know Java/Kotlin/Scala can have such enforced boundaries. Same for databases. My day job is on a monolithic app with a main database. Every module/component/whatever has access to all tables and occasional does take advantage of it. Hard to stop when you don't actually work together, on the same team, or even in the same continent.
What's really hard about microservices is that most have no experience writing them to actually be self-sufficient and not have dependent failure modes. The example in the post is a classic, if you have a UserService you're doing it wrong (aka distributed monolith). At most you should have a UserManagementService and every other service should have the minimum information downstream of it that it needs to operate without changes from upstream.