I came across this post (and more like it) claiming extensions to be a good, or at least different, solution for mapping DTO’s.
Are they though? Aren’t DTO’s supposed to be pure data objects? I’ve always been taught to seperate my mappings in special mapping services or mapping libraries like MapStruct and ModelMapper for implementing the good practice of “seperation of concerns”.
So what about extensions?
I think it boils down to where you define the extension functions and how that impacts coupling.
At some level you want to divorce the repository storage of the data from your domain object. Let’s say that the repository changes, and “name” is no longer just “name”, but now “firstName” and “lastName”. The body of your application doesn’t care, or need to know that the repository has changed, as it will still just deal with a name, whatever that is.
So something has to put “firstName” and “lastName” together into a “name”, and it needs to be consistent with how the application has always received it. Is it “Fred Smith”, “Fred, Smith” or “F. Smith”? And who “owns” that logic?
From a coupling perspective, you don’t want the application logic to know anything about the repository or the internal structure of the DTO. On the other hand, you don’t want the repository service layer to know about how the data is going to be used.
Let’s say that you have two different applications that used the “name” field, but in different ways somehow. So the conversion from the two “name” fields into one might be different for each application. Yes, you could argue that recombining them back exactly the way the repository service originally delivered “name” would be transparent to the client applications, but what if the change to the repository was driven by one of those applications needing split data?
That’s usually why you put your adapters in some neutral place, associated with the client application but yet somewhat outside of it.
You could use extension functions to provide the adapter, but you need to make sure that they’re not co-mingled with you application code. Otherwise you’ve just reestablished the coupling between the repository and the application that you where trying to avoid.