"That said, best thing you can learn in your programming career is to get rid of "Customer" classes (or whatever the equivalent is for your particular problem). A customer is a unique entity represented by an ID, a private key if you will, which links data in various systems."
What methods should it have? What does a Customer do exactly? Or is it just a POD which simply stores customer data? If so which data? Does it mix authentication information with the user's purchase history? Maybe not that but what about the user's little Avatar in the UI?
The answer is none of the above, the single responsibility of the Customer class is to identify a user, that's it. In the end that's just a number, no need for a class. The purchase history of a user is only relevant to the system that manages the purchase history. The avatar is only relevant to the UI. The authentication information to the authentication service.
A Customer is not in and of itself an "entity" of some sort with associated behavior in the OO sense. But you see this all the time with companies trying to model these taxonomies of their business as class hierarchies.
It's an unhelpful practice that imposes a structure on your code that's not relevant in a any way to the actual functionality of your software.
But I cannot fully comprehend in which scenarios this would be a clear winner and which it would add too much overhead. There is something to it though, so thanks for opening my eyes.
Smalltalk style OOP has its own issues, but there's lots of good aspects to it and you really have to experience Smalltalk as a complete system to really get it, it's nothing like Simula/C++/Java-style OOP.
That said, best thing you can learn in your programming career is to get rid of "Customer" classes (or whatever the equivalent is for your particular problem). A customer is a unique entity represented by an ID, a private key if you will, which links data in various systems.
Need to split some part of your codebase that handles authentication into a separate microservice for whatever reason? No problem, the same key can be used to refer to data in that system.
Your program magically becomes more modular, more maintainable, easier to understand, and more performant, all in one go.
Use OOP when you need an abstract interface to something that can be implemented in various different ways, e.g. data structures or plugin systems, stuff like that. Any time I see "PODs" full of getters and setters I cry on the inside (and sometimes on the outside).