Reimaginando DTOs en Java

¡Hola, Habr! Les presento a su atención una traducción amateur del artículo “Repensar el DTO de Java” de Stephen Waterman , donde el autor considera un enfoque interesante y no estándar para el uso de DTO en Java.






Pasé 12 semanas en el programa de formación de posgrado de Scott Logic, trabajando con otros ex alumnos en un proyecto interno. Y hubo un momento que me detuvo más que otros: la estructura y el estilo de redacción de nuestros DTO. Esto causó mucha controversia y discusión a lo largo del proyecto, pero al final me di cuenta de que me gusta usar DTO.



Este enfoque no es la única solución correcta, pero es bastante interesante y excelente para el desarrollo con IDE modernos. Espero que el impacto inicial desaparezca y que tú también lo disfrutes.



¿Qué es DTO (objeto de transferencia de datos)?



A menudo, en las aplicaciones cliente-servidor, los datos en el cliente ( capa de presentación ) y en el servidor ( capa de dominio ) se estructuran de manera diferente. En el lado del servidor, esto nos da la oportunidad de almacenar datos cómodamente en la base de datos u optimizar el uso de los datos en aras del rendimiento, mientras que al mismo tiempo participamos en una visualización de datos "fácil de usar" en el cliente y, en el lado del servidor, necesitamos encontrar una manera de traducir los datos de uno formato a otro. Por supuesto, existen otras arquitecturas de aplicaciones, pero nos centraremos en la actual como una simplificación. Los objetos similares a DTO se pueden utilizar entre dos capas de presentación de datos.





DTO — value-object , , . DTO , (Request) , (Response). , Spring.



, endpoint DTO :



// Getters & Setters, ,    
public class CreateProductRequest {
    private String name;
    private Double price;
}

public class ProductResponse {
    private Long id;
    private String name;
    private Double price;
}

@PostMapping("/products")
public ResponseEntity<ProductResponse> createProduct(
    @RequestBody CreateProductRequest request
) { /*...*/ }


DTO?



-, , DTO. .



  • , DTO.
  • JSON, !


. DTO , , , (decoupling) , .



, DTO . DTO API .



API, . (endpoint) . , . price “ ”, price . API , - , .



DTO . DTO , , API . DTO “ ”, — , .



DTO, , .



!



, . . , .



, -. , . Double, BigDecimal.



public enum ProductDTO {;
    private interface Id { @Positive Long getId(); }
    private interface Name { @NotBlank String getName(); }
    private interface Price { @Positive Double getPrice(); }
    private interface Cost { @Positive Double getCost(); }

    public enum Request{;
        @Value public static class Create implements Name, Price, Cost {
            String name;
            Double price;
            Double cost;
        }
    }

    public enum Response{;
        @Value public static class Public implements Id, Name, Price {
            Long id;
            String name;
            Double price;
        }

        @Value public static class Private implements Id, Name, Price, Cost {
            Long id;
            String name;
            Double price;
            Double cost;
        }
    }
}


, enum , ProductDTO. , DTO , (Request) , (Response). endpoint Request DTO Response DTO . Response DTO, Public Private .



. - — , . . , @NotBlank DTO .



DTO . @Value Lombok , .



, , . , DTO.



“ !”



. .



enum ! namespace-, .. DTO ProductDTO.Request.Create. “” , ; enum. () ! namespace- DTO, IDE . , , new ProductDTO() new Create(). , .



— ! . , , .



. , . Lombok . , , DTO . , java . , .



()



DTO. ?





. API , . DTO — IDE . :



@Value public static class PatchPrice implements Id, Price {
    String id;    //    Long;
    Double prise; //    price
}


PatchPrice is not abstract and does not override abstract method getId() in Id
PatchPrice is not abstract and does not override abstract method getPrice() in Price


, , , endpoint .





DTO . . :



private interface Cost {
    /**
     * The amount that it costs us to purchase this product
     * For the amount we sell a product for, see the {@link Price Price} parameter.
     * <b>This data is confidential</b>
     */
    @Positive Double getCost();
}


DTO , .





DTO, . , API, , . , , .



&



: . 4 , , DTO . , “” c DTO. , , . , .



, DTO. @Value public static class [name] implements, . , IDE . ! DTO .



, DTO . . . ctrl + q IntelliJ .





, .. . DTO — , .



, , . , , :



markup = (sale_price - cost_price) / cost_price


java, :



public static <T extends Price & Cost> Double getMarkup(T dto){
    return (dto.getPrice() - dto.getCost()) / dto.getCost();
}


T, . dto Price Cost — , Public (.. Cost). , dto (). .





, DTO. :



  1. API .
  2. .
  3. , , !





PD: Gracias por leer mi primer post sobre Habré hasta el final. Agradecería cualquier crítica sobre la traducción, porque Tuve que desviarme un poco del original por falta de conocimiento y experiencia.




All Articles