This may be oversimplified advice, but it really boils down to the essence of clean coding: do not create multi-tools. It's what I like to call the Swiss army knife principle:
It's the classic multi-tool, but it's not a great solution for multiple reasons:
- While it has many tools, each tool is inferior compared to the same tool made for a single purpose. A knife is better than a Swiss army knife. A saw is better than a Swiss army saw. This is due to compromises in the design required to fit so many tools onto one object.
- If one of your tools needs upgrading (e.g. they've developed a better bottle opener), you can get your Swiss Army knife upgraded, but you lose all of your tools while in the middle of an upgrade.
- You cannot both give your Swiss army knife to the sommelier to open a bottle of wine and the fromagier to cut the cheese.
This part of the analogy carries over to the field of software. Compromises due to shared design, a single point of failure, ... these are all problematic design approaches.
So why was this knife designed, and still so popular? Because it's easy to carry, and it's considerably harder to carry each individual tool in your pocket at the same time.
But this part of the analogy does not carry over to the field of software. We can build as many classes as we want without struggling to carry them all around.
So let's avoid all of these design issues, since we're not actually solving a problem by trying to mash all of these functionalities into a single class. One class, one tool. Another tool? Another class.
Each view should have its own model, which means that you can tailor each model to specifically contain what it needs, regardless of what another view needs.
The short answer here is to have 3 user DTOs, one to fit each view.
But you seem to want to reuse the same
User. That's actually okay too, but only if the
User DTO is always the same, i.e. contains all of the data that you've put into the class definition. You've already touched on this:
- everytime I need users data, I load all the fields, even the ones I don't need. The problem of this solution is the waste of time and memory.
This approach is much easier to develop, but you're right that it's slightly less performant in terms of database bandwidth.
You have to weigh the loss of bandwidth by loading some data you won't use against the complexities of developing separate DTO classes, mapping all of them, and making sure that your repository interface is still clear enough so your consumers can receive the right type of DTO they need.
This is also very sensitive to needing to be expanded. If tomorrow you have a 4th view that showcases a user, it's likely going to need another subset of data fields, and thus a 4th DTO, mapping, and repository method. But if you had been using a fully fleshed out
User class, you could've reused it for the 4th model since it already contains what you need.
Which is the best solution?
As with most software development issues, there is no one-size-fits-all solution.
If you have a highly trafficked application (let's say Facebook or Twitter) and a significant development budget, those little data optimizations are going to save more than it costs to develop them.
But if you have a smaller development budget and you are not squeezed for performance to this degree, then you have more freedom to waste tiny bits of performance in favor of a much simplified development approach.
As long as the data in question comes from the same table row, without any additional joins or calculations, the cost of adding it is negligible for performance (assuming sensible data columns, not outliers like a giant BASE64 string). When the data is fetched via additional joins, it's usually better to simply fetch this data in a second query than it is to try and develop two queries, one with join and one without.
But you have to weigh your own situtation. How much are you squeezed for performance? How much are you trying to avoid complexity during development?