1

This post assumes, that dtos on the UI side (SPA) could be viewed as business objects in almost all cases - except that the business logic is missing. I'm fully aware that a dtos first responsibility is to represent data that was send over the net. In a lot of cases though these object are almost identical to business objects and I don't like to copy data from one class into another. That's why I asked myself: Why not extend it via prototype chain? But I was wondering if this is considered bad practice and if so why? Because with TS, you could make this type safe and the approach is also efficient: No needles copying required.

Details: Imagine the typical SPA app: You fetch a bunch of objects from a remote API and display it. You have some business logic that belongs to these objects. Without the wire in between, it would only be natural to put this logic inside the same class as the data.

The first idea to solve this problem is to write helper function which take the dto as a first parameter:

function logic(dto) {
  // do some magic with dto.data
}

And calling them: logic(dto). In JS you can of course get a little bit further: This is something that can be specified during a call, so you could do the following:

function logic(this: DTO): void {
  // do some magic with this.data
}

And then calling it: logic.call(dto);.

Now to extend on this, you could also "simply" change the prototype chain of these dto objects. You would implement a class, like usual with all the logic you need. Then, after receiving all dtos, you change the prototype of this objects to the class you implemented, thus making these objects business objects.

6
  • If I remember correctly, browsers are eliminating mechanisms by which you can modify the prototype chain. This is due to security concerns. Imagine a man-in-the-middle attack involving the runtime modification of how JavaScript resolves identifiers? I wouldn't want to be the one fixing that. May 4, 2023 at 18:07
  • Maybe what I'm thinking of is explicitly setting the __proto__ property of an object to change the inheritance hierarchy. May 4, 2023 at 18:08
  • 1
    You could use Object.setPrototypeOf, but read the warning at MDN very carefully. May 4, 2023 at 18:11
  • The objects are serialized from Axios and I have to check if there is a possibility to manipulate the JSON de serialization logic. Since I want to prevent any copying I don't wan't to use Object.assign the only option I see to implement this Idea is the usage of Object.setPrototypeOf - even if it has performance implications.
    – morpheus05
    May 4, 2023 at 20:54
  • Trying to inject logic into deserialized objects is as frequently requested as it is useless. I've never seen it applied but that it results in confusion, bugs, and encourages people to not learn the language. If anything, TypeScript makes this worse because newcomers tend not to understand the structural nature of class instance types. Keep it simple and avoid the pain of trying to make JavaScript and TypeScript something they are not. Jul 14, 2023 at 2:28

2 Answers 2

3

This post assumes, that dtos...

Let us start exactly here. DTO is just a pattern. It is used often, but it doesn't mean it has to used in the particular application. You decide for every application separately, if you need DTOs for this particular application.

If you really see the reasons to use DTOs for a particular application, then changing prototype will contradict to these reasons and you will not reach the goals you wanted to reach with DTOs. Thus you will not want to change prototype.

If changing prototype would not have any negative impact on the application, then there is no reason to use DTOs in this application. Thus you remove DTOs and there is no need any more to change prototype.

Architecture is not a religion. Check every assumption. Check every architectural decision.

7
  • The question is not so much if you call a de serialized object from a JSON response a dto or "an-object-from-the-wire". The question is: Is it ok to manipulate the prototype chain of such an object that I de serialized from JSON? If you call the result of such an operation a dto or something else is not the point for this particular discussion... I agree that architecture is not a religion and you have to decide for your particular application what's best.
    – morpheus05
    May 4, 2023 at 21:00
  • 1
    @morpheus05: The question about prototype cannot be answered before you explain the reasons why you have DTOs. What exactly are these reasons? If all attributes of objects in DB and in DTOs are the same, then you don't need DTOs. If there are reasons to have DTOs (e.g. you want to separate REST layer from the business logic layer, or you validation of DTOs, etc.), then changing prototype will break these reasons. So, please answer, why do you have DTOs at all?
    – mentallurg
    May 4, 2023 at 21:37
  • 1
    A) How would you name an object you parse from a JSON response? - You first name, then parse. If you need DTOs, this can be DTO. If you don't use DTO layer, this can be BO. As I said, first decide if you need DTOs.
    – mentallurg
    May 4, 2023 at 22:34
  • 1
    B) "for that case where they are not you introduce dtos into your application" - Do you mean, there are DTOs and it was not your decision, and you cannot change it? If yes, then again, first ask what is the reason for DTOs. If there is a reason, then changing prototype can break it. If there is no reason, don't use DTOs.
    – mentallurg
    May 4, 2023 at 22:37
  • 1
    We cannot discuss abstract cases, with unknown reasons for particular decisions. That's why please be specific. Describe a specific case (or few specific cases, each separately), explain what were the reasons to use DTOs. Only then we can proceed to the question about prototypes.
    – mentallurg
    May 4, 2023 at 22:44
1

Changing the prototype for an object in JavaScript means you are modifying the inheritance hierarchy dynamically at runtime. The principle of least astonishment provides the best guidance here. It would be surprising (or astonishing) to modify the prototype chain for every DTO in the application. This is not a common practice, so new developers to the project will have trouble understanding the codebase unless they first understand this design.

You said "Imagine the typical SPA app", but you continue by saying the frontend implements business logic. This immediately raises questions, like "why can't this logic be implemented by the backend?" Be careful that you are not confusing "business logic" with "user interaction logic."

Single page applications tend to implement business logic on the server. The front end is relegated to display logic, user interaction logic, and form validations. If the frontend implements business logic, and the server does not enforce this, then malicious clients can send DTOs to your server with data that violate business rules. Avoid this.

Push as much of the raw business logic into the server as possible. Consider that any logic you implement in the frontend might actually be display logic or user interaction logic. This justifies separate classes, which you might call "components" or "controllers". I don't see why you need to map your DTOs to these kinds of classes. Controllers or components typically encapsulate UI behavior for a certain region of a web page. These classes would use DTOs as a source of data, but that does not mean you need to map your DTOs universally to other classes.

The real issue is not whether you should modify the prototype chain of your DTOs instead of mapping them to separate classes. The real issue is the fact you need specialized classes on the frontend to execute business logic that should be implemented by the backend to ensure malicious clients do not circumvent your business rules.

2
  • You are correct: What I mean by business logic is actually presentation logic relevant for the UI. Imagine a person object containing firstName and lastName and you have to dsiplay name where name = firstName + " " + lastName. It would be nice if such logic is available on the object itself, instead of stand alone functions. My comment about TS is your point about astonishment: The service handling the communication with the backend would return these objects and the "prototype trick" would not be perceivable because the returned object is of the right type.
    – morpheus05
    May 5, 2023 at 14:20
  • @morpheus05, presentation logic typically goes in some kind of view, controller, or utility that a view or controller uses. You might be overcomplicating this. Remember that DTOs exist at the boundaries of an application. Procedural code is perfectly acceptable here. If you want to get fancy, you can create a "presenter" object that takes a DTO to adapt it for the view. May 5, 2023 at 15:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.