Now, in order to apply this ideas to a higher level of design, i.e communication between microservices, we need to apply the same principles. Reduce expensive calls by sending all data required to a function at the same time, let the backend do the work, precompute/prefetch data that will make work easier later...
Good advice in general. For me the highlight is that this approach can only be applied when we design and adapt our microservices to our computational needs instead of business. I still see a lot of gurus giving talks about splitting microservices in "business needs" and saying that anything else is a bad practice. Hold on, there is no silver bullet in engineering. Maybe the business logic is easy to understand, but this system design will make the system impossible (yes) to optimize in the future without a full re-write. And the same idea applies to low level design. Everything is a trade-off.
My approach is to design the public API following domain/business principles so it's easy to understand and implement. A la DDD and others if you want to call them something. But I want my backend to be flexible and designed around the REAL engineering requirements. If my `/api/foo/bar` is an async batch process that needs to be cached and my `/api/foo/baz` is a complex sync process, then `bar` and `baz` are two completely monsters. I don't want to have a `foo` service to handle both use cases. Having a `foo` service just because it's a business concept will cost you hours and money.