Let's say there's the class Book, with different models in different endpoints:

Endpoint A (consumer):

class Book{
  Map<string,string> chapterName_content
}

Endpoint B (provider):

class Book{
  string [] chapterNames
  string [] content
}

Let's also assume that these are the structures that make the most sense within each endpoint, so changing them is not recommended.

Since the conversion is a direct one, I do not see the need to use Mapper classes or anything of the kind. To me the answer would be to create a DTO on Endpoint A that already does the mapping as such:

class BookDTO{
  string [] chapterNames
  string [] content
  
  public Book toBook()      
  public string toJson() 

  static BookDTO fromBook(Book book)
  static BookDTO fromJson(string jsonRepresentation)
}
  

Is not using an external class for the mapping a bad practice?

有帮助吗?

解决方案

This depends heavily on the context of the system or project in stake:

  • If the DTO and the conversion/parsing code will expected to be under maintenance of the same programmer (at least, for a longer period), and

  • if the number of different conversions will expected not to be not more than the two shown in the example

  • if the number of DTOs are expected to stay so few that writing such individual conversion methods manually for each DTO is more efficient than creating a generator based on meta data/reflection, or more efficient than using some automapping tool,

then go ahead, leave the methods inside the DTO, as shown in the example. However, if one of the conditions above is violated, I would either introduce separate mapping classes, or go a step further and look for a more generic solution like the ones scetched in the third bullet point.

So in short, know your context - there is nothing like a "best" or "bad" practice without any context.

其他提示

  • What happens when you add a new member to the DTO?
  • What happens when you delete a member from the DTO?
  • What happens when you re-organise the DTO?

Will the Object be responsible for reading the old, and the new formats?

  • How will it handle data that it can no longer hold?
  • How will it fill in the blanks from older formats?

What you are breaking is the Single Responsibility Principle.

Now I am not evangelical about this. Having a DTO mixed with serialisation capabilities will work, it is a solution, and for small projects/early in a project it can make sense.

However as a long-term solution, particularly as the project matures and the DTO changes, it is a bad solution.

SRP points the main problem out as being one of usage and reading. Eg: you go to a book to deal with book related actions such as chapters. This assists usage by keeping the components tightly focused (aka cohesive). This then falls out into legibility as it reduces the amount of noise that has to be dealt with in understanding a piece of code.

Another principle being broken is that of coupling and Shearing Layers. This focuses on what changes and when. When you change a piece of behaviour in the DTO, it doesn't necessarily change the serialisation. Similarly new/updated serialisations have little effect on the DTO itself. Thus they are not highly correlated, and as such tend to change at different rates.

By coupling these two different shearing layers together you maximise how brittle the code is, increase the likelyhood of merge conflicts (due to multiple parallel commits), and make investigating the change history that much more difficult.

Adding relevant behavior to objects is usually a good idea. However, let's take it a step further. Why have the DTO in the first place? You just as well could add toJson() to the actual Book.

With that, you eliminate a class, you localize any potential changes of the Book to a single class, you don't need the method toBook(), etc. You get a lot of potential benefits, depending on the exact context of course.

I would argue that using an external class for conversion is the bad practice. That external class would need to know everything about this class, so essentially that would be a really tightly coupled class. That means any changes will likely impact both. That's usually not what we want.

许可以下: CC-BY-SA归因
scroll top