No suelo comentar mucho, pero hay que decir que la presentación del código, cómo cambian las diapositivas y la explicación a medida que va ocurriendo ha sido BRILLANTE.
Que forma tan pro de llevar al siguiente nivel la programación. Es el tipo de formación que deseo para mí. Una vez comprendido lo básico de programación uds son el siguiente paso lógico en nuestra formación.
La expresión regular del email debería ser estática, para no hacer que el motor JS tenga que compilar la misma expresión una y otra vez en cada instanciación de value object
A mi ya de entrada me parece extremadamente raro tener que validar tan profundamente que el email es un email y además validarlo en el momento de su creación y durante el resto de su vida, como si alguien fuese a coger la bdd y a romperla, normalmente yo valido estos inputs lo más pronto posible en el tipico middleware de validación. En clases tan chorras como las que mencionan en sus ejemplos tal vez no es evidente, pero instanciar 150 propiedades (que pueden repetirse si es un array de objetos) de un modelo bien complejo (por ejemplo, nuestro order tiene de todo, cupones, descuentos a nivel de pedido, a nivel de transporte, a nivel de producto, todos los datos de producto congelados el dia de la creación, etc...) no es gratis, es la diferencia entre que una petición gaste 1MB de ram o gaste 10MB, por no hablar de que la ram irá subiendo más rápidamente y hará falta mas GC, si encima esta ram sube tan rapido que no puede limpiarse con 3GC de vida corta (rapido) entraran en el GC de vida larga (lento), además de lo evidente, hacer new es más CPU, en un objeto no es apreciable, en un proceso que use muchos de estos objetos tal vez el tiempo y la ram pasen a ser un problema. Si tuviese que seguir este patrón lo haría solo donde hace falta y solo cuando hace falta, es decir, si me viene de la bdd debería de suponer que la base de datos no está rota, ya que si al guardar has validado no tiene porque romperse mágicamente. Otra cosa que es bastante evidente es la polución que hay en el codigo, cada propiedad tiene la propiedad en la clase, el getter, el setter, la propiedad en los parametros del constructor, la propiedad que setean en el constructor, osea, por cada propiedad vienen a ser tranquilamente 12 lineas de código, que de nuevo, no se aprecia bien dado el tamaño de la clase, pero ya se intuye, con solo 3 propiedades el codigo no les cabe en la pantalla, imaginate el ejemplo anterior, recordemos que tener ValueObjects no es la única manera de hacer una validación, perfectamente si no quieres ensuciar la clase lo puedes sacar fuera con funciones exactamente de la misma manera que los ValueObjects y usarlos cuando hace falta, que no tiene porqué ser necesariamente en el constructor, donde se ejecutará en cada instanciación
@@JorgeDev92 Por eso la programación con paradigma mas funcional está ganando la pulseada, yo ahora estoy explorando la arquitectura vertical slice, donde si bien hay acoplamiento permite generar responsabilidad única por cada funcionalidad que se desarrolle y es mas flexible ya que si hay que aplicar DDD también es posible.
@@lococba84 Hola, me parece super interesante y valido este punto. De casualidad tienes algún ejemplo que puedas compartir para terminar de entenderlo?
Buenas introducción, me ha encantado! la unica pega es que personalmente no me gusta que un value object devuelva excepciones. Ya que imaginemos que incumples varias validaciones con ello dentro de un ValueObject, sólo la primera que ocurra será la que haga early exit del objeto. Vi otro video en el que usabais EITHER como monada y creo que vi otro con Results... si los combinais y haceis un metodo create estático (poniendo constructor a privado), tendríais lo que buscais pero devolviendo "un tipo de resultado que no es una excepción". Eso es muy util por ejemplo cuando has de devolver resultados que no son "totalmente correctos" o "totalmente falsos", por ejemplo imaginad un alta de un usuario en el que faltan ciertos datos del usuario para hacer ciertas operaciones, puedes tener "warnings" para esos casos de uso...
Ahí diferenciamos el tratamiento de validaciones de cara al usuario, como lo sería el formulario que comentas, de lo que entenderíamos cómo garantizar esas reglas de integridad. Es decir, en el punto en el que estamos sí entendemos cómo excepcional que nos llegue un valor incorrecto, pero antes, en la capa del controlador por ejemplo, sí meteríamos las validaciones que comentas enfocadas a mejor UX 👼
Corríjanme si me equivoco pero no que inversión de control es cuando se le pasa el control de las instancias a otro?, generalmente un framework, creo que se refieren a IoC como a inversión de dependencia.
Gracias por el contenido, muy bueno!! Una mejora que veo es no colocar las validaciones y excepciones en el constructor de VO, el constructor debería estar limpio, por lo tanto, crearía un método estático "Create" en el VO donde valido y llamo a mi constructor privado.
Cómo encajan los value objects en un projecto que se maneja por esquemas de validacion? no veo que aporte mucho si al crear o actualizar hacemos pasar el objeto por la validación del esquema completo
Excelente video, primero felicitarlos, una pregunta, que pasa si un value object no solo tiene un value sino más de uno ? es decir por ejemplo el value object credentials en donde tenga userName y userPassword como value object ? es más que pasa si el value userPassword sea otro value object llamada Password
Buen video, sin embargo tengo una duda, cuando la contraseña del usuario debe ser encriptada es una regla del domain, application o infrastructure? El value object para el password del usuario debe validar el raw input o la contraseña ya encriptada?
No entiendo el motivo de no "poder" poner los value objects como los argumentos del ctor. de User. ¿No es un trade-off? ¿O un "depende"? Si p. ej. necesitase especificar la fecha con 3 enteros (día, mes y año), tendría q cambiar la clase UserBirthdate, pero tb User (el ctor.). En cambio, si en el ctor. especifico los value objects, no
tengo una duda respecto al uso del patrón repository, en este caso se llama al repositorio desde la capa de aplicación, yo acostumbro a inyectar el repo en la entidad del dominio y desde ahí hacer el registro.
en el constructor de UserEmail haria la asignacion luego de los ensure, osea: constructor() { this.ensureValueIsDefined(value); this.ensureIsValidEmail(value); this.value = value} ya que utilizan parametros en los ensure. Caso contrario se podrian eliminar los parametros, asignar this.value = value y luego llamar a los ensures sin parametro. Pero el primer caso me gusta mas, no se que piensan uds. Saludos
Hay algo que me gustaria plantear, supongamos que estamos en un contexto de clean-architecture, si tengo validaciones que necesitan usar librerias externas estoy poniendo en mi dominio esas librerias que deberian estar en una capa superior (A menos que armemos alguna interfaz para comunicarnos con esa libreria y que usemos desde la clase de dominio) Otra opcion que yo veo, es crear una clase builder, un UserBuilder que dentro llame a 3 ValidationService (uno para cada property). Luego para solventar que el mail se pueda modificar tendriamos un UpdateUserUseCase, donde un metodo seria updateMail en cual dentro tambien llamaria al mismo ValidatonService Todo esto lo planteo con el objetivo de no llenar mi Clase User con libreria externas, ya que User es de mi dominio
Hola, en mi caso suelo usar interfaces que encapsulen las funciones de la librería en algunos casos (por ejemplo date-fns) y en otros (lodash), acabo metiendo directamente el import en la clase del dominio. La verdad es que si se quiere ser 100% ortodoxo con la clean arch, debería ir todo a infraestructura y usar interfaces para desacoplar de las implementaciones reales, pero muchas veces lo asumo por conveniencia. Asumo el riesgo de no ser 100% ortodoxo y de tener ese acoplamiento que me supone por contra menos trabajo que andar montando una interfaz para una llamada a un método de lodash. Al final estas arquitecturas son una filosofía y si se quiere ser 100% estricto, muchas veces se complica demasiado el asunto o se pierde mucho más tiempo. Aunque más que perder, yo diría que quizás pueda ser empleado de forma más productiva en otra parte de la aplicación, como test unitarios, test integrados, alguna refactorización, etc...si tienes tiempo infinito y estás 100% agusto con lo que tienes, pues ahí a tope con la clean arch siempre.
Donde queda el Principio de Single Responsibility Principle, ahora el User tambien hace validaciones y crea los Object Values, entonces si en el futuro necesitas crear otros Values Objects toca si o si tocar ese código y vaya que problema, y ni que se diga con el Testing, que tal si creas un User_Factory, que cree los values Objects y devuelva una instancia de la clase User si pasan las validaciones, ahi tendrías una clase que haria validaciones y dejarias User para lo que fue creado, no le metes complejidad.
Y para ese "ensureValueIsDefined()" podéis poner como devolución de tipo ": value is string" y un "return true;" para mejorar la inferencia de tipos en hilo.
@@luka4695 Por el narrowing. Al poner "value is string" como tipo de vuelta, cuando usas la función como condicional de bloque, dentro del bloque positivo el valor de la variable que has pasado como 'string | null | undefined' será de 'string'. Se puede hacer un "NotEmptyString" como tipo, pero eso es más avanzado.
Creo que ni bien vi el video me falto costo entrar en ritmo con "userRegistrar" y un metodo "register", tal vez más coherencia con todo ingles o español.
🔥 Buen video, a activar esa cuenta. Me gusta este patrón y lo aplico en mis proyectos tal cual. Pero me he enfrentado al problema de que algunos campos del objeto de dominio son opcionales (se actualizan en flujos posteriores de la aplicación). ¿Cual seria la buena práctica para manejas VO opcionales pero mantener esas validaciones dentro del VO? Recomendaciones?
Lo que yo hago es que el valor del Value Object pueda ser nulo, para que no se rompa las demás validaciones siempre verifico que no sea nulo. Por ejemplo, si el email es opcional en el ejemplo del video quitaría la validación de ensureValueIsDefined y en la validación de ensureIsValidEmail añadiría una verificación de que si value es nulo se omite dicha validación.
Uf, cuantas cosas están mal en este vídeo. Este patrón es también conocido como tipos opacos, muy común en programación funcional. El objetivo de este patrón es sacarle el máximo provecho al compilador; y al organizar el código con los tipos opacos consigues que las validaciones salgan de un montón de lugares (no solo en tu objeto user), quedando solo en el momento de colección de esos datos; que insisto es ante de crear un objeto user. Para ello creas un tipo para un dato concreto y lo usas a lo largo de tu aplicación, no solamente en User. Haciéndolo así permites que el compilador te ayude a detectar muchos problemas en muchos lugares diferentes. Aquí dicen que se crean una clase UserEmail, eso no existe, existe Email, da igual si se usa en User o no; y debe representar un email válido. En cuando a Id, debe ser una clase que valide que sea un uuid válido, y debe recibir como argumento genérico la entidad para la cual se aplica ese Id, de esa forma el compilador puede detectar el que intentes usar un id de una entidad en otra entidad. Si vas a crear una clase con un montón de clases internas solo para evitar llamar una función; y para ello tienes que armar tal lío teniendo que poner getters y setters en todo lados; por favor, no lo hagas, crea tus funciones de validación separadas de User sin más; el código final será más limpio que con estas clases que contienen un valor y que no aportan nada a tu objeto final más allá de complicarlo y de incrementar la presión sobre el recolector de basura. El valor del patrón radica en que los tipos opacos sean de uso extendido en la aplicación y no escondidos dentro una sola clase que nadie puede aprovechar. Estos tipos opacos normalmente los sueles ver con facilidad cuando haces el diseño de tu base de datos.
Eso mismo pense, ya con eso que explicaste se infringe solid especificamente la responsabilidad unica, deberia haber una clase externa que haga validaciones que sea abstracta a user, user es solo una entidad que representa atributos del usuario
Otro comentario, yo soy del mundo java y veo mucho código con el uso excesivo del "this" cuando no es necesario salvo casos especiales (herencias, etc...); en el caso del UserEmail veo que en el constructor usan el "this" para llamar a los métodos ensure, si la cosa funciona como en java yo creo que es una mala costumbre usar el "this" ahí porque se empieza a propagar por todo el código, genera confusión para quien no sabe bien el uso del this, y se termina usando el this para todo como un prefijo que no tiene sentido y se pone "por las dudas" o "porque todo el mundo lo pone". Veo mucho esto, no se que opinan. Saludos.
Por ejemplo también veo lo estan usando en otros métodos de la clase, creo que ahí se puede mejorar la calidad del código, salvo desconozca algo del lenguaje que usan o haya algun patron/principio que me este pasando por alto; en cuyo caso super agradecido si me lo aclaran. Saludos
Iba a preguntar por qué no recibir los value objects desde fuera (yo personalmente le veo más ventajas siempre que se haga bien y sólo para las capas de dominio y aplicación), pero ya veo que lo comentáis en el curso. Así que habrá que activar la cuenta. 😂
TypeScript te lo va a respetar si no haces castings o cosas que no debes, por lo que en la práctica van a ser privados para TypeScript, pero accesibles si no van con el "#".
Bueno si es un patron, pero VO igual DTO, es mejor usar estos objetos planos para la transferencia de datos y no usar modelos de dominios anemicos como la mayoria lo hace.
Código verboso por culpa de Java etc muchos patrones de diseño no son aplicables a programación funcional en lenguajes que realmente soportan ese paradigma como Rust por ejemplo, sinceramente tengo 15 años de exp en Java y en mi día a día tengo que programar así y tienes decenas de saltos para hacer una acción, pero para nada lo recomiendo si no usas Java/Kotlin/Net es overkilling.
No suelo comentar mucho, pero hay que decir que la presentación del código, cómo cambian las diapositivas y la explicación a medida que va ocurriendo ha sido BRILLANTE.
Que forma tan pro de llevar al siguiente nivel la programación. Es el tipo de formación que deseo para mí. Una vez comprendido lo básico de programación uds son el siguiente paso lógico en nuestra formación.
INCREIBLE la calidad del video
Super claro
La expresión regular del email debería ser estática, para no hacer que el motor JS tenga que compilar la misma expresión una y otra vez en cada instanciación de value object
A mi ya de entrada me parece extremadamente raro tener que validar tan profundamente que el email es un email y además validarlo en el momento de su creación y durante el resto de su vida, como si alguien fuese a coger la bdd y a romperla, normalmente yo valido estos inputs lo más pronto posible en el tipico middleware de validación.
En clases tan chorras como las que mencionan en sus ejemplos tal vez no es evidente, pero instanciar 150 propiedades (que pueden repetirse si es un array de objetos) de un modelo bien complejo (por ejemplo, nuestro order tiene de todo, cupones, descuentos a nivel de pedido, a nivel de transporte, a nivel de producto, todos los datos de producto congelados el dia de la creación, etc...) no es gratis, es la diferencia entre que una petición gaste 1MB de ram o gaste 10MB, por no hablar de que la ram irá subiendo más rápidamente y hará falta mas GC, si encima esta ram sube tan rapido que no puede limpiarse con 3GC de vida corta (rapido) entraran en el GC de vida larga (lento), además de lo evidente, hacer new es más CPU, en un objeto no es apreciable, en un proceso que use muchos de estos objetos tal vez el tiempo y la ram pasen a ser un problema.
Si tuviese que seguir este patrón lo haría solo donde hace falta y solo cuando hace falta, es decir, si me viene de la bdd debería de suponer que la base de datos no está rota, ya que si al guardar has validado no tiene porque romperse mágicamente.
Otra cosa que es bastante evidente es la polución que hay en el codigo, cada propiedad tiene la propiedad en la clase, el getter, el setter, la propiedad en los parametros del constructor, la propiedad que setean en el constructor, osea, por cada propiedad vienen a ser tranquilamente 12 lineas de código, que de nuevo, no se aprecia bien dado el tamaño de la clase, pero ya se intuye, con solo 3 propiedades el codigo no les cabe en la pantalla, imaginate el ejemplo anterior, recordemos que tener ValueObjects no es la única manera de hacer una validación, perfectamente si no quieres ensuciar la clase lo puedes sacar fuera con funciones exactamente de la misma manera que los ValueObjects y usarlos cuando hace falta, que no tiene porqué ser necesariamente en el constructor, donde se ejecutará en cada instanciación
@@JorgeDev92 Por eso la programación con paradigma mas funcional está ganando la pulseada, yo ahora estoy explorando la arquitectura vertical slice, donde si bien hay acoplamiento permite generar responsabilidad única por cada funcionalidad que se desarrolle y es mas flexible ya que si hay que aplicar DDD también es posible.
@@lococba84 siempre ha sido el vencedor
eso deberia estar separado en una clase de validacion, por otra parte no se compila sino se interpreta en este caso de js...
@@lococba84 Hola, me parece super interesante y valido este punto. De casualidad tienes algún ejemplo que puedas compartir para terminar de entenderlo?
Buenas introducción, me ha encantado! la unica pega es que personalmente no me gusta que un value object devuelva excepciones. Ya que imaginemos que incumples varias validaciones con ello dentro de un ValueObject, sólo la primera que ocurra será la que haga early exit del objeto. Vi otro video en el que usabais EITHER como monada y creo que vi otro con Results... si los combinais y haceis un metodo create estático (poniendo constructor a privado), tendríais lo que buscais pero devolviendo "un tipo de resultado que no es una excepción". Eso es muy util por ejemplo cuando has de devolver resultados que no son "totalmente correctos" o "totalmente falsos", por ejemplo imaginad un alta de un usuario en el que faltan ciertos datos del usuario para hacer ciertas operaciones, puedes tener "warnings" para esos casos de uso...
Ahí diferenciamos el tratamiento de validaciones de cara al usuario, como lo sería el formulario que comentas, de lo que entenderíamos cómo garantizar esas reglas de integridad. Es decir, en el punto en el que estamos sí entendemos cómo excepcional que nos llegue un valor incorrecto, pero antes, en la capa del controlador por ejemplo, sí meteríamos las validaciones que comentas enfocadas a mejor UX 👼
Me impresiona que todos esto 'modelos' o 'arquitecturas' es hacer lo que has hecho toda la vida solo que alguien le ha puesto un nombre elegante.
Corríjanme si me equivoco pero no que inversión de control es cuando se le pasa el control de las instancias a otro?, generalmente un framework, creo que se refieren a IoC como a inversión de dependencia.
Mejoran con los años... En hora bueno. Me ha servido mucho está clase
Gracias por el contenido, muy bueno!! Una mejora que veo es no colocar las validaciones y excepciones en el constructor de VO, el constructor debería estar limpio, por lo tanto, crearía un método estático "Create" en el VO donde valido y llamo a mi constructor privado.
Cómo encajan los value objects en un projecto que se maneja por esquemas de validacion? no veo que aporte mucho si al crear o actualizar hacemos pasar el objeto por la validación del esquema completo
Excelente video, primero felicitarlos, una pregunta, que pasa si un value object no solo tiene un value sino más de uno ? es decir por ejemplo el value object credentials en donde tenga userName y userPassword como value object ? es más que pasa si el value userPassword sea otro value object llamada Password
Buen video, sin embargo tengo una duda, cuando la contraseña del usuario debe ser encriptada es una regla del domain, application o infrastructure?
El value object para el password del usuario debe validar el raw input o la contraseña ya encriptada?
Grande chicos grandes excelente todo su contenido como siempre
Porque no pasar directamente el objeto usuario al metodo register? Que sucede si son 90 parametros?
No entiendo el motivo de no "poder" poner los value objects como los argumentos del ctor. de User. ¿No es un trade-off? ¿O un "depende"? Si p. ej. necesitase especificar la fecha con 3 enteros (día, mes y año), tendría q cambiar la clase UserBirthdate, pero tb User (el ctor.). En cambio, si en el ctor. especifico los value objects, no
Y que pasa cuando el valueObject es otra clase, por ejemplo Factura -> detalle ?
¿con que programa hacen las presentaciones?
tengo una duda respecto al uso del patrón repository, en este caso se llama al repositorio desde la capa de aplicación, yo acostumbro a inyectar el repo en la entidad del dominio y desde ahí hacer el registro.
en el constructor de UserEmail haria la asignacion luego de los ensure, osea: constructor() { this.ensureValueIsDefined(value); this.ensureIsValidEmail(value); this.value = value} ya que utilizan parametros en los ensure. Caso contrario se podrian eliminar los parametros, asignar this.value = value y luego llamar a los ensures sin parametro. Pero el primer caso me gusta mas, no se que piensan uds. Saludos
Hay algo que me gustaria plantear, supongamos que estamos en un contexto de clean-architecture, si tengo validaciones que necesitan usar librerias externas estoy poniendo en mi dominio esas librerias que deberian estar en una capa superior (A menos que armemos alguna interfaz para comunicarnos con esa libreria y que usemos desde la clase de dominio)
Otra opcion que yo veo, es crear una clase builder, un UserBuilder que dentro llame a 3 ValidationService (uno para cada property). Luego para solventar que el mail se pueda modificar tendriamos un UpdateUserUseCase, donde un metodo seria updateMail en cual dentro tambien llamaria al mismo ValidatonService
Todo esto lo planteo con el objetivo de no llenar mi Clase User con libreria externas, ya que User es de mi dominio
Hola, en mi caso suelo usar interfaces que encapsulen las funciones de la librería en algunos casos (por ejemplo date-fns) y en otros (lodash), acabo metiendo directamente el import en la clase del dominio. La verdad es que si se quiere ser 100% ortodoxo con la clean arch, debería ir todo a infraestructura y usar interfaces para desacoplar de las implementaciones reales, pero muchas veces lo asumo por conveniencia. Asumo el riesgo de no ser 100% ortodoxo y de tener ese acoplamiento que me supone por contra menos trabajo que andar montando una interfaz para una llamada a un método de lodash. Al final estas arquitecturas son una filosofía y si se quiere ser 100% estricto, muchas veces se complica demasiado el asunto o se pierde mucho más tiempo. Aunque más que perder, yo diría que quizás pueda ser empleado de forma más productiva en otra parte de la aplicación, como test unitarios, test integrados, alguna refactorización, etc...si tienes tiempo infinito y estás 100% agusto con lo que tienes, pues ahí a tope con la clean arch siempre.
Donde queda el Principio de Single Responsibility Principle, ahora el User tambien hace validaciones y crea los Object Values, entonces si en el futuro necesitas crear otros Values Objects toca si o si tocar ese código y vaya que problema, y ni que se diga con el Testing, que tal si creas un User_Factory, que cree los values Objects y devuelva una instancia de la clase User si pasan las validaciones, ahi tendrías una clase que haria validaciones y dejarias User para lo que fue creado, no le metes complejidad.
Y para ese "ensureValueIsDefined()" podéis poner como devolución de tipo ": value is string" y un "return true;" para mejorar la inferencia de tipos en hilo.
en que mejoraria poner que devuelva un boolean en un void? que seria mejorar la inferencia?
@@luka4695 Por el narrowing. Al poner "value is string" como tipo de vuelta, cuando usas la función como condicional de bloque, dentro del bloque positivo el valor de la variable que has pasado como 'string | null | undefined' será de 'string'. Se puede hacer un "NotEmptyString" como tipo, pero eso es más avanzado.
@@Paul7Peterson gracias por la data
Creo que ni bien vi el video me falto costo entrar en ritmo con "userRegistrar" y un metodo "register", tal vez más coherencia con todo ingles o español.
🔥 Buen video, a activar esa cuenta. Me gusta este patrón y lo aplico en mis proyectos tal cual. Pero me he enfrentado al problema de que algunos campos del objeto de dominio son opcionales (se actualizan en flujos posteriores de la aplicación).
¿Cual seria la buena práctica para manejas VO opcionales pero mantener esas validaciones dentro del VO?
Recomendaciones?
Lo que yo hago es que el valor del Value Object pueda ser nulo, para que no se rompa las demás validaciones siempre verifico que no sea nulo. Por ejemplo, si el email es opcional en el ejemplo del video quitaría la validación de ensureValueIsDefined y en la validación de ensureIsValidEmail añadiría una verificación de que si value es nulo se omite dicha validación.
Se puede hacer lo mismo con tipos en TS.
type UserId = number & { __type__: 'UserId' }
Uf, cuantas cosas están mal en este vídeo.
Este patrón es también conocido como tipos opacos, muy común en programación funcional. El objetivo de este patrón es sacarle el máximo provecho al compilador; y al organizar el código con los tipos opacos consigues que las validaciones salgan de un montón de lugares (no solo en tu objeto user), quedando solo en el momento de colección de esos datos; que insisto es ante de crear un objeto user.
Para ello creas un tipo para un dato concreto y lo usas a lo largo de tu aplicación, no solamente en User.
Haciéndolo así permites que el compilador te ayude a detectar muchos problemas en muchos lugares diferentes.
Aquí dicen que se crean una clase UserEmail, eso no existe, existe Email, da igual si se usa en User o no; y debe representar un email válido. En cuando a Id, debe ser una clase que valide que sea un uuid válido, y debe recibir como argumento genérico la entidad para la cual se aplica ese Id, de esa forma el compilador puede detectar el que intentes usar un id de una entidad en otra entidad.
Si vas a crear una clase con un montón de clases internas solo para evitar llamar una función; y para ello tienes que armar tal lío teniendo que poner getters y setters en todo lados; por favor, no lo hagas, crea tus funciones de validación separadas de User sin más; el código final será más limpio que con estas clases que contienen un valor y que no aportan nada a tu objeto final más allá de complicarlo y de incrementar la presión sobre el recolector de basura.
El valor del patrón radica en que los tipos opacos sean de uso extendido en la aplicación y no escondidos dentro una sola clase que nadie puede aprovechar.
Estos tipos opacos normalmente los sueles ver con facilidad cuando haces el diseño de tu base de datos.
Eso mismo pense, ya con eso que explicaste se infringe solid especificamente la responsabilidad unica, deberia haber una clase externa que haga validaciones que sea abstracta a user, user es solo una entidad que representa atributos del usuario
Estos manes no saben nada
Lo único que entendí es que eres virgen JuanLuisPanza
Otro comentario, yo soy del mundo java y veo mucho código con el uso excesivo del "this" cuando no es necesario salvo casos especiales (herencias, etc...); en el caso del UserEmail veo que en el constructor usan el "this" para llamar a los métodos ensure, si la cosa funciona como en java yo creo que es una mala costumbre usar el "this" ahí porque se empieza a propagar por todo el código, genera confusión para quien no sabe bien el uso del this, y se termina usando el this para todo como un prefijo que no tiene sentido y se pone "por las dudas" o "porque todo el mundo lo pone". Veo mucho esto, no se que opinan. Saludos.
Por ejemplo también veo lo estan usando en otros métodos de la clase, creo que ahí se puede mejorar la calidad del código, salvo desconozca algo del lenguaje que usan o haya algun patron/principio que me este pasando por alto; en cuyo caso super agradecido si me lo aclaran. Saludos
Gracias por estos videos. 🙋🏽♂
Uaahhhh!!!! !buenisisisisisimo vídeo!!!!!!
Iba a preguntar por qué no recibir los value objects desde fuera (yo personalmente le veo más ventajas siempre que se haga bien y sólo para las capas de dominio y aplicación), pero ya veo que lo comentáis en el curso. Así que habrá que activar la cuenta. 😂
Tú sí que sabes!! 💪
Habria que añadir el hashtag en los private tambien o no seria necesario? Para que sea 100% privado
TypeScript te lo va a respetar si no haces castings o cosas que no debes, por lo que en la práctica van a ser privados para TypeScript, pero accesibles si no van con el "#".
Excelente video, me ayuda un monton!! pregunto sus cursos los tienen para JAVA?
siempre codean en typescript, solo un par de videos lo hace con Java
que fuente y que teman usan en la muestra de codigo?
Aquí toda la info ruclips.net/video/4anod6sSALE/видео.html 🙂
Es mucho más reutilizable, mucho más mantenible y muchísimo más simple, crear validadores externos a los modelos que hacer toda esta liada. 🥺😜🤗
Esto sería el equivalente a crear un tipo personalizado de go y darle métodos
Bueno si es un patron, pero VO igual DTO, es mejor usar estos objetos planos para la transferencia de datos y no usar modelos de dominios anemicos como la mayoria lo hace.
Actualicen Codely Theme para vscode 😢😢😢 he comprado dank mono y luce genial pero podría ser mejor
No conozco como sera en otros lenguajes pero en java nadie trabaja sin usar este patron, de hecho no sabia ni que era un patrón
Código verboso por culpa de Java etc muchos patrones de diseño no son aplicables a programación funcional en lenguajes que realmente soportan ese paradigma como Rust por ejemplo, sinceramente tengo 15 años de exp en Java y en mi día a día tengo que programar así y tienes decenas de saltos para hacer una acción, pero para nada lo recomiendo si no usas Java/Kotlin/Net es overkilling.
Solucion elegante y sin verbosidad? Java Records.
Mucho boilerplate
Estos videos son un crimen, sobre todo para lo que estan aprendiendo, porque empiezan a aprender las cosas mal.
Hola!, para las privadas los uso así:
readonly #id: UserId;