سؤال

I've to implement some Backend Webservices, which provide a given, final JSON structure, which is allready in use on the FrontEnd side. This structure doesn't match the database structure, so I have to convert the database entities to the needed serialization format.

It's a service on demand, that means the backend services has to determine and calculate the situation based on a user given time. So i cannot return the selections from the repository directly to the user, instead I need some additional layers for the business code (determining and calculation the situation on time X).

Here are my database tables

entry
-------------
  id int (PK)
  result_id (FK)
  ...

result
-------------
  id int (PK)
  t1 double precision
  t2 double precision
  t3 double precision
  t4 double precision
  total double precision

The response has to look like that:

entry: {
    id: x,
    currentResult: {
        id: x,
        t1: xx.xxx,
        t2: xx.xxx,
        t3: xx.xxx,
        t4: xx.xxx,
        total: xx.xxx
    },
    lastResult: {
        id: x,
        t1: xx.xxx,
        t2: xx.xxx,
        t3: xx.xxx,
        t4: xx.xxx,
        total: xx.xxx
    }
}

So here my questions:

At the moment I select all needed data into DTO's, not into the entity records. The DTO's have already the structure of the output format (e.g. EntryDto has already current and last lap, which isn't possible in the Entry-Entity). Now all calculations will be made directly in the DTO (which is actually wrong, because it should be responsible only for transfering the data). This approach works good, and for me the code has a clean structure, because the business code is completely in the DTO (which however is wrong).

If i wanna be some for conform to good practices, I have to move the business code into another layer. But what layer should be responsible for that?

  • Entity: It's not the right spot, because some related properties which are needed for the calculations are only present in the DTO.
  • DTO: All properties for the calculations are given, but the DTO shouldn't be so complex with the amount of methods / business logic.
  • ?

Would be the following a better solution?

  • Entity entry is only responsible for database internals (joins,...)
  • Repository selects data directly into new layer EntryBo (EntryBusinessObject) by constructor expression. All calculations will be made in those BO's.
  • After all calculations were made transform the BO's into DTO's and finalize the response

Note: The above project is only a light example. Please no notes on that, only on the given problems.

هل كانت مفيدة؟

المحلول

I'd consider a top-down approach. What kind of code would you like to see in the top level method of the service? I'd prefer seeing a short list of steps needed to fulfill the service request.

It seems you have two important steps. First you need to fetch data from the database. Then you need to map the data to the response model. If mapping data is indeed an important step, then it's best to make it clear and visible in the top level method.

Something like

public SomeResponse someServiceMethod(SomeRequest request) {
    SomeEntity entity = repository.fetchSomeEntity(request.getId());
    SomeResponse response = responseMapper.map(entity);
    return response;    
}

would be nice and easy to read. You could write that as a one-liner too, but I'd prefer very short and simple lines here. You want to express the order of actions as clearly as possible.

If you have to process a complex request, then you could have a requestMapper as well:

public SomeResponse someServiceMethod(SomeRequest request) {
    SomeQueryParam param = requestMapper.map(request);
    SomeEntity entity = repository.fetchSomeEntity(param);
    SomeResponse response = responseMapper.map(entity);
    return response;    
}

If you have some methods that need complex processing before mapping results to the response model, you could make that clear as well:

public SomeResponse someServiceMethod(SomeRequest request) {
    SomeEntity entity = repository.fetchSomeEntity(request.getId());
    SomeResult result = someComplexCaseHandler.process(entity);
    SomeResponse response = responseMapper.map(result);
    return response;    
}

I'd avoid trying to build a rich model of business objects with complex behavior and dependencies inside such service unless there's a lot of complex business logic to handle. If it's mostly just about handling requests, accessing a database and converting data back and forth, then make it as clear and simple as possible right from the top level. Hide details but do not hide important steps. Use object orientation as a tool, not as a goal.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى softwareengineering.stackexchange
scroll top