franciscogazitua / IIC2113-2024

Consultas sobre el proyecto en las Issues
2 stars 0 forks source link

Clean code: sobre el uso de métodos privados en paradigma de EDD #26

Open Dafnemami opened 2 months ago

Dafnemami commented 2 months ago

Holis!,

Haciendo la entrega me surge la duda si está estrictamente prohibido que las clases bajo el paradigma de EDD tengan métodos privados. Esto pensando en qué veo cierto caso, en mi código de clase Unit/Character, en que necesito preparar ciertos datos antes de retornarlos. Ejemplo: un método público que llama a uno privado. Es eso posible?

La segunda duda que me surge es respecto es si además estos métodos públicos de la EDD son meramente para mostrar los atributos de forma más fácil, como se hace referencia en la cápsula, o si se puede también realizar cálculos dentro de ellos como por ejemplo para calcular el daño que una unidad le inflige a otra. Sumo a la pregunta, que no me hace sentido la definición de método abordada en la cápsula, porque me estaría sugiriendo dos formas de acceder a un atributo.

Gracias 🙉 🙉 🙉 🙉

franciscogazitua commented 2 months ago

Hola

Si bien nada esta estrictamente prohibido mientras tenga una muy buena razón para existir en tu código, la creación de híbridos no es estrictamente necesaria (y será penalizada) en este proyecto.

Para entender esto, es importante entender el como queremos comunicar la información de nuestras clases a distintas clases que las usan. Generalmente, queremos esconder la implementación de nuestras clases y exponer solo abstracciones que nos permitan trabajar con nuestros datos. Esto no es lo mismo que esconder nuestra implementación con getters y setters, sino que implica diseñar nuestra solución de tal manera que otras partes de nuestro código no dependan de la representación concreta de nuestros datos. En efecto, una clase que expone todos sus atributos con getters y setters sigue siendo una Estructura de Datos.

Imagen de WhatsApp 2024-04-17 a las 08 05 51_b8eadbe0

Ahora, la distinción más importante entre el paradigma orientado a objetos y el paradigma orientado a estructuras de datos es que ambas estructuras son las opuestas de la otra. Los objetos esconden su implementación mediante abstracciones, mientras que las estructuras de datos exponen su implementación. Dado que una estructura de datos quiere exponer su implementación, no debería tener métodos complejos, ya que estos cumplen la función de esconder la implementación mediante abstracciones.

Imagen de WhatsApp 2024-04-17 a las 08 05 51_be4142f0

Si bien, tiene mucho sentido que la clase Unit sea una estructura de datos, no tiene mucho sentido que esta estructura haga operaciones complejas sobre sus datos, porque su objetivo sería exponer estos datos para que otras clases puedan trabajar con estos (lo que incluye hacer operaciones complejas con estos).

Cuando tomes la decisión de si una clase debiese ser una estructura de datos o un objeto, recuerda que es importante entender las ventajas de cada una de estas estructuras y como estas se relacionan. En particular, creo muy importante la siguiente parte del libro:

Imagen de WhatsApp 2024-04-17 a las 08 05 51_bf57a9d8

Dado lo anterior, si tu clase Unit expone su implementación, pero al mismo tiempo la esconde mediante funciones, esta caería en al categoría de hibrido. Es importante evitar construir híbridos porque estos combinan las peores partes de los paradigmas orientados a objetos y orientados a estructuras de datos:

Imagen de WhatsApp 2024-04-17 a las 08 05 50_6b3d908b

En resumen, no crees híbridos, no solo se considerará descuento por estos, sino que también hará que sea más difícil para ti escalar tu solución en las siguientes entregas.

Saludos,

cahinostroza commented 2 months ago

Bueno, después de la cátedra que dió @franciscogazitua, sólo me queda agregar que si puedes tener métodos privados en una EDD, la parte clave es cómo son esos métodos. El libro nos dice que una EDD no debe tener "meaningful functions", a esto se refiere con lógica de negocio y en este caso en particular, con lógica del juego.

cahinostroza commented 2 months ago

Por lo tanto, puede que haya un caso en que haga sentido tener un método privado en una EDD, pero por lo general no.

Dafnemami commented 2 months ago

Hola @franciscogazitua, @cahinostroza . Muchas gracias ambos por sus respuestas, se complementaron bacán!

Sigue siendo confusa para mi cierta idea: Las EDD tienen sus atributos públicos. Entonces, cada vez que por alguna razón algún método -público- lo muestre, cómo puedo manejar ese caso? Pensando que quiero asegurar solo una forma de acceder al atributo. Forma 1: Hago el atributo privado (mal porque es una EDD) Forma 2: No hacer ese método (mala idea también jajaja)

Saludos!

cahinostroza commented 2 months ago

Una EDD no necesariamente debe tener sus atributos públicos, puedes exponer su datos a través de métodos públicos. Por ejemplo: image

Dafnemami commented 2 months ago

Ahhh comprendo. Al final el core es que tenga públicos, de alguna forma, todos sus atributos, pero el cómo lo hacemos (si es a través de un método o el atributo mismo) es elección nuestra. Si lo anterior es correcto, creo comprender bacán. Muchas gracias! Me es mucho más claro ahora!!

franciscogazitua commented 2 months ago

Quizas la confusión viene porque estas intentando hacer cosas complejas en tu EDD.

Tiene sentido tener atributos públicos y usarlos en métodos públicos para preparar los datos. En un caso sencillo, podrías tener una EDD con un atributo string X1 y un atributo string X2, si en algun punto necesito retornar un string que use ambas variables, tiene sentido hacer una función pública que haga return $"Tengo {X1} y {X2}". Sin embargo la clase dejaría de ser una EDD si hace cosas más complejas, como, por ejemplo, operar con X1 y X2 para determinar algun elemento del juego.

En ese sentido, estaría mal que una EDD que represente la unidad también calcule el daño que esta realizará. Esto porque calcular el daño depende no solo de los atributos de Unit

siescobedo commented 2 months ago

Entonces una EDD puede "calcular cosas" para entregar data de sus atributos de alguna otra manera con algún método público, pero no se le puede entregar ningún parámetro a sus métodos porque debería poder solo interactuar con sus propios atributos?

Dafnemami commented 2 months ago

Sobre lo primero sofi me parece que no se puede operar de ninguna forma entre los atributos que ya tiene, sino más bien presentarlos de otra forma (como return $"Tengo {X1} y {X2}"). Lo segundo que dices me parece oki, como que probablemente hacer eso implicaría que estaríamos ocupando lógica del juego en la edd que no es la idea.

siescobedo commented 2 months ago

En ese caso, en el ejemplo visto en clases

Screenshot 2024-04-17 122155

Esto es un objeto o una EDD? Ya que en la segunda implementación para mostrar el porcentaje está interactuando con sus atributos, mostrándolos de otra forma.

franciscogazitua commented 2 months ago

Hola

La definición de EDD no tiene nada que ver con la composición los argumentos de sus funciones o con el como esta se construye a nivel de código, sino que tiene que ver con el objetivo de la clase en si. Una EDD expone su estructura interna, permitiendo a otras entidades acceder a sus implementación, mientras que un objeto esconde su estructura interna y provee abstracciones para que otras entidades puedan interactuar con el.

En eses sentido, un objeto es como una caja negra, en el sentido que yo no se que es lo que hace por adentro, solo se cuales son sus entradas y sus salidas. Por otro lado, una EDD es lo contrario, ya que esta me permite acceder a su implementación. En ese sentido, un objeto opera sobre sus datos y expone abstracciones, mientras que una EDD expone sus datos para que otros operen sobre ellos.

Lo anterior no habla de implementaciones especificas en tu código. Podrías tener una EDD con todos sus atributos privados y exponerlos mediante métodos o podrías tener una EDD sin métodos y con todos sus atributos públicos, ambas opciones son válidas.

Como señala @Dafnemami, la idea es que tu EDD no contenga lógica compleja del juego, sino que exponga sus datos para que otros elementos de tu solución puedan ocuparlos para realizar dicha lógica. Si la razón por la que le estas pasando un atributo externo a tu EDD es porque quieres que esta maneje la lógica del juego con estos, entonces tu clase no sería una EDD, sino que sería un híbrido.

En cuanto al segundo ejemplo de la clase (que es el que se discute en el comentario de @siescobedo), este sería un objeto, no una estructura de datos. Esto porque no expone su estructura interna, sino que expone sus datos como una abstracción. Lo bueno de esa implementación es que es irrelevante si Vehicle guarda sus atributos en galones, litros u otra unidad de medida, double GetPercentFuelRemaining() solo expone la abstracción en términos de porcentajes. Esto sería cierto incluso si Vehicle guardara su atributo en porcentaje, lo importante es que la clase que utiliza el método double GetPercentFuelRemaining() no lo puede saber.

Por favor, no entender lo anterior como que siempre es mejor hacer objetos, estructuras que se componen de agrupaciones de datos (como probablemente sería Unit) tienen mucho más sentido como EDD que como objetos.

Lo importante es que sepan como manejar sus estructuras tal que haga su solución fácil de mantener y que separe correctamente sus responsabilidades. Recuerden siempre que una EDD y un objeto responden a necesidades distintas y tienen ventajas y desventajas distintas:

Imagen de WhatsApp 2024-04-17 a las 08 05 51_bf57a9d8

Dafnemami commented 2 months ago

Gracias @franciscogazitua! Me es mucho más clara ahora la flexilibidad de las definiciones.

siescobedo commented 2 months ago

muchas gracias!! me quedo muy claro