[GUÍA] Estrategias de programación

Kr4n3oK

[GUÍA] Estrategias de programación

Hola que tal chavales. Andaba yo picando código, cuando, como de vez en cuando me ha surgido una pregunta interna que seguro muchas veces se os ha ocurrido a vosotros también, y está relacionado con las estrategias de programación. Es decir, como debería ser un bloque de código ya sea por optimización, legibilidad, mantenimiento, extensibilidad, etc,

Por poner un ejemplo bastante sencillo:
Romper ejecución de un bloque

    private openToEditForm (row: Object) {
        if (!row) {
            this.messagePopup.openMessagePopup('Select one table row', 'error', 'To edit first select table row');
            return;
        }
        
this.createForm.setValue(row); this.createForm['toedit'] = true; this.createForm['visible'] = true; }

¿Es correcto romper el condicional de esa manera?, ¿es mejor opción usar el condicional entero con su if..else..?, ¿debería romperse la ejecución usando return?, ¿debería existir este return sin tiparlo?.

CONCEPTO
Entonces mas o menos propongo este concepto a la idea que se me ha venido a la mente y de esta manera, quizás tener una referencia rápida en nuestra querida media vida de buenas prácticas de implementación. Obviamente se que hay libros muy buenos de lectura como Clean Code y personas que se dedican a esta labor como Papa. Vamos al lío pues.

El concepto sería el siguiente. Cada lenguaje es un mundo y por lo tanto, lo que en un lenguaje puede estar bien en términos de optimización, en otro puede no serlo, por ello es importante exponer el lenguaje del que estamos tratando. Por otro lado ya solo creo que nos faltaría el código a analizar.

DINÁMICA
La dinámica que propongo es: crear un nuevo post con el código a analizar, exponer también el lenguaje de programación como he mencionado anteriormente y los post que se refieran a el vayan siempre a través del linkado de mediavida #, para de este modo poder encontrar fácilmente las soluciones propuestas y encontrar una definitiva. Obviamente ni que decir queda, que se pueden poner referencias a otras personas o blogs donde se hable del tema.

ESTRATEGIAS EXPUESTAS
Romper ejecución de if..else con return - TypeScript
Inicialización de variables en clases - TypeScript
Gestionar idiomas en aplicación distribuida - Todos

1
Kr4n3oK

Empiezo yo, sería algo así.

Romper ejecución de if..else con return
TypeScript

    private openToEditForm (row: Object) {
        if (!row) {
            this.messagePopup.openMessagePopup('Select one table row', 'error', 'To edit first select table row');
            return;
        }
        
this.createForm.setValue(row); this.createForm['toedit'] = true; this.createForm['visible'] = true; }
5 respuestas
B

#2

#1Kr4n3oK:

¿Es correcto romper el condicional de esa manera?

Mi respuesta a esta pregunta es Sí, por poder puedes.

#1Kr4n3oK:

¿es mejor opción usar el condicional entero con su if..else..?, ¿debería romperse la ejecución usando return?

La primera Sí y la segunda No

Ambas respuestas las llevo al razonamiento del que return te va a sacar de la función, en el caso que planteas sería correcto porque no hay nada más que hacer en dicha función, pero lo veo una mala práctica ya que mucho casos tu función continuará dependiendo de los resultados de ese if... else...

A parte es más legible con la estructura completa del if... else... es más fácil y ameno de leer se entiende mejor, y es algo que se agradece cuando no es tu código.

PD: Me mola mucho la propuesta, espero que avance y va a favs

1 1 respuesta
Fyn4r

Yo lo que veo es que esa función hace demasiadas cosas.

r2d2rigo

Jesus, cuanta cosa mal en tan pocas lineas.

1 1 respuesta
Kr4n3oK

#3 efectivamente, desde mi punto de vista, por legibilidad simplemente lo recomendado sería usar el condicional entero. He expuesto este ejemplo como caso que veo en muchos proyectos. Personalmente uso el if ese entero.

A ver si alguien más aporta conocimientos.

1 respuesta
Kr4n3oK

#5 Aporta conocimiento, si fuese posible.

B

#6 yo puedo aportar casos cuando veas que el tuyo ha quedado "claro"

1 respuesta
Martita-

#2
El codigo esta bien pero, a mi modo de ver, si me dieran el proyecto, y tuviera que estudiarmelo para seguir con el, si por algun casual, se me pasara ese return, o lo que sea, pensaria que los metodos de abajo los llama independientemente de si el if se cumple o no.

Prefiero un if else de toda la vida.

1 1 respuesta
Kr4n3oK

#8 Apunta en tu primer comentario a #2 para que se vaya stackeando las respuestas.

Kr4n3oK

#9 Apunta a #2 para stackear respuestas referentes a un problema en particular.

Edit: vamos llegando a una conclusión entonces. De momento gana usar siempre if..else y evitar returns para romper ejecución .

Wasd

#2 A mi personalmente no me gusta cortar ejecuciones a mitad excepto para lanzar excepciones que maneja un error handler o la función invocadora. En este caso, si ese es el tipo de error que se espera de esa función tendría un FormErrorHandler para reutilizar una estructura común que muestre el error en la vista. Si la ausencia de row fuese un comportamiento esperado, haría el if else de toda la vida.

Previo a todo eso, quizá es interesante que directamente no se invoque a esa función si row iguala a false.

Pero bueno, que si algo me han enseñado los años es que este mundillo está lleno de pedantería y gente que te dirá que hagas lo que hagas está mal (como el señor #5, que llevo años leyéndole por aquí y en cuanto veo su avatar ya se por donde irá la respuesta).

Las convenciones entre lenguajes y frameworks muchas veces se contradicen entre ellas, así que tampoco te calientes mucho el tarro.

Al final lo ideal es que hagas codigo rehusable, testeable y que cumplas SOLID en la medida de lo posible. Con eso ya haces mas que la mayor parte de empleados de esta industria xD

Saludos!

1 respuesta
r2d2rigo

#2 Depende mucho de lo que haga la funcion, y sobre todo su extension. Yo soy fan de los early returns en bastantes casos, sobre todo para comprobar funciones iniciales y abortar ejecucion si no se dan unos casos minimos.

En el caso que has puesto pondria un if/else, porque solo estas teniendo un retorno de la funcion; no sale muy a cuenta tenerlo para ese solo caso.

Sin embargo, un retorno temprano es muy util en casos como este:

private openToEditForm (row: Object, editMode: EditMode) {
    if (row == null) {
        throw new NullReferenceException("row cannot be null");
    }
        
if (editMode == EditMode.Rename) { throw new InvalidValueException("Entry renaming is disabled"); } this.createForm.setValue(row); this.createForm['toedit'] = true; this.createForm['visible'] = true; }

Y por supuesto, otras cosas que son cuestionables en el codigo:

  • No llames a la UI directamente dependiendo de tu arquitectura, separalo en capas para evitar interdependencias.
  • Usa setters/getters en vez de poner las propiedades a saco.
  • Usa variables tipadas en vez de magic strings para acceder a las propiedades.

#12 gracias por la parte que me toca, cuando quieras comparamos historico de aportaciones a este foro machote.

1 3 respuestas
Kr4n3oK

#13 Excelente, apunta a #2 si es posible para stackear respuestas.
#13 Perdona, así está bien citado, pues se agrega al stackeo, perdón :D

Wasd

#13 Estoy seguro de que eres un tío de puta madre y que en persona eres mas de ayudar que de criticar, pero eso no quita que yo aquí siempre te haya visto primero lanzando la piedra, y ya luego si eso ayudando (como has hecho en tu comentario, que me ha molado mucho). Si #1 abre un hilo y tu respuesta es la que es de primeras, generas una sensación negativa.

En cuanto a lo de compararnos, no dudo que tu hayas aportado más que yo. En lo que a mi respecta me gusta mantenerme más low profile y soy más de ayudar por privado soltando parrafadas cuando vienen a buscarme, aunque en este caso quería dar mi opinión.

1 1 respuesta
Grise

Interrumpir el flujo del programa es una mala práctica, no solo por limpieza de código si no por rendimiento.

Con los micros actuales ya no es tan problemático, pero aún así si buscas programar un sistema de altas prestaciones la teoría dice que no debes hacerlo. En la práctica la mayoría de nosotros no hacemos programas que tengan una funcionalidad crítica que necesite ofrecer resultados optimizando tiempos al máximo y tiras habitualmente por lo que es más práctico según el momento.

1 respuesta
r2d2rigo

#16 "interrumpir el flujo del programa"? Aqui no estas interrumpiendo nada, tiene (casi) el mismo efecto un if/else que un return. Me parece que te has liado tu solo.

#15 es mas facil trolear que ayudar, menos esfuerzo.

1 respuesta
Grise

#17 Para según que microprocesadores forzar una excepción (como he visto en un ejemplo que has puesto por arriba) para salir de un método o los famosos breaks en los bucles puede penalizar tiempos. Intel y AMD se los comen bastante bien pero si te vas a micros más simple y haces mediciones de tiempos se ve claro.

Kr4n3oK

Chicos vamos a intentar no ensuciar el hilo, lo que tengáis que aportar hacedlo apuntando al post y exponiendo el conocimiento.

7 días después
Flashk

#2 Usar return para romper un flujo en una función si se da x caso suele ser una mala decisión de diseño.

La práctica recomendada de return es usar uno y sólo uno por función y ubicarlo al final del todo. Esto debería ser así, independientemente de que el lenguaje de programación que uses te permita escribir múltiples return en una función.

Si necesitas forzar la salida por un error, entonces deberías usar excepciones.

1 2 respuestas
r2d2rigo

#20 tipico comentario de profesor de carrera que no ha programado fuera de docencia en su vida. Que equivocados estaban cuando me ense;aron asi.

https://softwareengineering.stackexchange.com/a/118793

1 respuesta
Flashk

#21 cuando tengas que depurar clases mal diseñadas, con métodos enormes y con multiples return, me cuentas lo divertido que es perder el tiempo en poner múltiples breakpoints en varios return para controlar por donde está saliendo en cada momento y según cada situación.

Incluso si haces clases pequeñitas y mejor diseñadas, adquirir una convención es algo muy agradecido.

1 respuesta
willy_chaos

Pues yo debido a como esta el codigo en el trabajo hay veces que es infumable con los if-else kilometricos para comprobar ciertos parametros (o meterlos todos es una condicion if ....)

Prefiero mil veces como lo hace r2d2rigo (que al final es lo que hago yo). Porque compruebas que todos los parametros estan bien y cumplen el formato, y si todo es correcto pasas a procesar los datos. Si no, envías a una pantalla de error. De forma que sabes que las primeras partes del codigo son comprobaciones, las segundas son simplemente ejecuciones.

Antes lo hacia con returns pero con el tiempo te das cuenta que es mejor crearte una excepción y propagarla hacia arriba. Ya sera la funcion caller, o el controller quien se encargue de capturar y mostrar un mensaje especifico para el error propagado.

Es igual que cuando haces un for hasta encontrar una condicion: Ejemplo estas buscando en un array de String que una posicion sea igual a un texto (por ejemplo, los roles que dispone una persona).

String[] roles = new String[]{"GUEST", "USER", "PROVIDER", "ADMIN", "OFFICER"};
String texto = "ADMIN";
boolean found = false;
for ( int i = 0; i<roles.length;i++) {
 if ( texto.equals( roles[i] ) ) {
  found = true;
  break;
 }

}

if ( !found ) {
 throw new UserHasNoPrivilegesException("No se disponen de los permisos requeridos para ejecutar esta accion");
}

// Como tiene permisos, ejecutamos las instrucciones correspondientes.
// bla bla bla bla

1 1 respuesta
Lecherito

#22 Y que diferencia hay entre debuggear cuando se hace return a cuando se le da un valor a la variable de la que haras return mas tarde?

1 respuesta
willy_chaos

#24 perder mas tiempo haciendo scroll :D

y si esa variable es un objeto que pasas a otras funciones en el codigo (aunque no la modifiquen) ya tienes que ir mirando que le pasa dentro de esa funcion...

a mi me parece mas interesante hacer el return a la que vea algo que no cuadra ( o si es para control de errores, lanzar exception )

Fyn4r

Lo de tener sólo un return a mi me lo enseñó un profesor de estos que no programó en su vida al salir de la carrera así que nunca lo he tenido muy en cuenta xD

1 respuesta
Kr4n3oK

#20 Porfa, apunta a #2 para que quede reflejado el conocimiento respecto a la práctica.

Por otra parte, si yo añado que en el core de angular por ejemplo, se ve bastante el uso de returns para parar el flujo ante ciertas condiciones que imagino serán establecidas como mínimo para ejecutar un código. Puede quizás ir muy bien en casos en donde después de esa condición se ejecute una gran secuencia de sentencias que consuman bastante, evitando así una carga sin sentido en el sistema.

1 respuesta
Kr4n3oK

Pongo otro

Empiezo yo, sería algo así.

Iniciación de variables en clases
Donde inicializar una variable dentro de una clase. ¿En la misma definición de la variable o en el constructor de la clase?
TypeScript

   export class Clase1 {
       private str: string = '';
       constructor () {
        }
  }

ó

   export class Clase1 {
       private str: string;
       constructor () {
            this.str = '';
        }
  }
1 1 respuesta
HeXaN

#26 Al final todo es el fantasme de los GOTO.

1 respuesta
Fyn4r

#29 Y aún así los GOTO tienen su uso