Programación sin If (básicamente sin condicionales)


He tenido un colega que me dijo que una vez trabajó para una compañía que tenía como política nunca tener condicionales (declaraciones"if" y "switch") en el código y que permitían que todas las decisiones en el código se hicieran usando polimorfismo y (supongo) algunos otros principios OO.

Yo una especie de entiendo el razonamiento detrás de esto, de tener un código que es más SECO y más fácil de actualizar, pero estoy buscando una explicación más profunda de este concepto. O tal vez es parte de un enfoque de diseño más general.

Si alguien tiene recursos para esto o estaría dispuesto a explicar o incluso tener algunos términos más relacionados con esto, puedo usar para encontrar más respuestas, estaría muy agradecido.

Encontré una pregunta en SO que estaba un poco relacionada, pero no estoy familiarizado con C++, así que no entiendo demasiado de las respuestas allí.

(No soy OO guru por cierto, pero puedo manejarlo)

Soy más competente en PHP, y después de eso Python, así que preferiría información que usa esos idiomas.

Actualización: Le pediré a mi colega más información sobre lo que quiso decir exactamente.

Actualización 2015: después de algunos años más de experiencia en programación, ahora veo que el objetivo de esta política era probablemente evitar que los programadores agregaran funcionalidad de manera aleatoria simplemente agregando condicionales (sentencias if) en ciertos lugares. Una mejor manera de extender el software es usar el "Principio Abierto/cerrado" donde el software se extiende mediante el uso de herencia y polimorfismo. Dudo mucho que la política fuera súper estricta en todos los condicionales, ya que es un poco difícil ir completamente sin ellos.

Author: Community, 2011-09-01

6 answers

Hay algunos recursos en el sitio de Anti-IF Campaign, como este artículo.

Creo que es una cuestión de grado. Los condicionales no siempre son malos, pero pueden ser (y con frecuencia son) abusados.

Pensamientos Adicionales (un día después)

Refactorización: Mejorar el Diseño del Código Existente es una buena referencia sobre este tema (y muchos otros). Cubre Reemplazar Condicional con Polimorfismo. También hay uno nuevo., Reemplazar Condicional con Visitante, en el sitio web.

Valoro la simplicidad y la responsabilidad única sobre la eliminación de todas las declaraciones if. Estos tres objetivos a menudo coinciden. Las herramientas de análisis estático que admiten la métrica cyclomatic complexity pueden señalar rápidamente código con condicionales anidados o en serie. Las instrucciones if pueden permanecer después de la refactorización, pero podrían dividirse en métodos más pequeños y/o múltiples clases.

Actualización: Michael Feathers escribió un artículo sobre Programación incondicional .

Este es un tema popular: Phil Haack on Death to the IF statement !

 49
Author: TrueWill,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-04 00:06:17

Después de algunos años de programación vuelvo a mi propia pregunta, cuyo contexto ahora entiendo un poco mejor.

Hay una buena charla de Sandi Metz donde refacciona una bola realmente peluda de declaraciones if a algo menos peludo: https://www.youtube.com/watch?v=8bZh5LMaSmE

 10
Author: Niels Bom,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-13 08:21:42

Leí el post que enlazaste y parece que en su mayoría estaban hablando de eliminar la necesidad de condicionales dentro de una clase, no debe confundirse con todo el código en general. La idea es que si necesita verificar el estado de un objeto (usando un condicional) para determinar si tiene cierta funcionalidad, entonces en realidad tiene dos objetos (uno que admite la funcionalidad y otro que no) y debe definirlos como dos clases relacionadas en su lugar.

 7
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-31 22:38:55

He tenido un colega que me dijo que una vez trabajó para una empresa que tenía como política nunca tener condicionales ("if" y " switch" declaraciones) en el código y que dejan todas las decisiones en el el código debe hacerse usando polimorfismo y (supongo) algún otro OO principio.

Creo que su colega malinterpretó algo o usó las palabras equivocadas para explicarlo. Y no puedes evitar completamente las declaraciones condicionales.

Hay algo que decir: la proliferación de declaraciones if dentro de OOP puede ser un síntoma de mala programación. Un ejemplo:

No utilice if para comprobar el valor de retorno de la función como una antigua programación al estilo C:

int ret = some_func();
if (ret != null)
   //do something

Esto era típico en el código C, pero con OOP debe usar excepción:

try{
    do_something();
}catch(Exception e){
    e.printStackTrace(); //why I was not able to do something
    handle(e); //there is something else I could do to handle the occurred error
}

A veces si la proliferación de declaraciones está relacionada con un mal diseño. Considere el siguiente ejemplo en Java:

BaseClass base;
if (base instanceof DerivedClassOneFromBase){
    DerivedClassOneFromBase d = (DerivedClassOneFromBase)base;
    d.methodOne();
}else if (base instanceof DerivedClassOneFromBase){
    DerivedClassTwoFromBase d = (DerivedClassTwoFromBase)base;
    d.methodTwo();
}

Este es otro ejemplo de sentencias if malas, probablemente relacionadas con un diseño malo. Si el dos objetos derivados tendrían un método común definido en su clase base BaseClass, el podría haber llamado a ese método en lugar de verificar su tipo de concreto y fundirlos:

base.commonMethod();
 5
Author: Heisenbug,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-31 22:44:31

A veces los condicionales dentro de los métodos son malos, ya que son una señal de que solo está realizando múltiples funciones o métodos de múltiples tipos en el único método.

Si tienes una clase llamada Automóvil y subclases como Automóvil y Bicicleta, y un método como:

drive(Automobile a)
   if (a.isCar)
      // do stuff
   else if (a.isBike)
      // do stuff

Es más probable que hagas algo mal. Incluso si no es un interruptor basado en el tipo, a menudo puede ser incorrecto. Si el método está realizando múltiples funciones dependiendo de alguna variable, a menudo está tratando de hacer más de una cosa y probablemente debería ser separado en múltiples métodos.

Por ejemplo:

save(Car c)
   if (c is new)
      // do some stuff
   else if (c is old)
      // do some stuff

Potencialmente podría dividirse en guardar y actualizar, ya que son dos funciones diferentes. Aunque depende.

Prohibir completamente si las declaraciones serían tontas, ya que tienen muchos casos de uso válidos.

 4
Author: BobTurbo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-01 13:13:33

Evitar condicionales no significa necesariamente que deba hacerlo por polimorfismo o herencia, tome por ejemplo :

Tienes 3 carpetas diferentes para almacenar imágenes subidas, videos subidos y pdf subidos

Puedes escribir código como:

uploadMedia(mediaType){
   if(mediaType == images){
     uploadTo("myProject/images");
   }else if(mediaType == videos){
     upoloadTo("myProject/videos);  
   }else if(mediaType == pdf){
     uploadTo("myProject/pdf");
  }
}

Otra alternativa que la gente podría usar es switch-case:

uploadMedia(mediaType){
         switch(mediaType){
         case : images
         uploadTo("myProject/images");
         break;

         case : videos
         uploadTo("myProject/videos");
         break;

         case : pdf
         uploadTo("myProject/pdf");
         break;
    }
}

Pero entonces puedes evitar totalmente la declaración condicional usando algo como dictionary / hashmap / json (Dependiendo de lo que trabajes con) :

Por ejemplo:

HashMap<String,String> mediaMap = new HashMap<>();

mediaMap.put("images","myProject/images");
mediaMap.put("videos","myProject/videos");
mediaMap.put("pdf","myProject/pdf");

//mediaType can be images/videos/pdf same as keys of mediaMap
uploadMedia(mediaType){
  uploadTo(mediaMap.get(mediaType));
}

Esto es una especie de pseudo código por lo que podría haber errores de sintaxis, pero en general este concepto también es útil para evitar condicionales. También se puede reducir la línea de código.

 0
Author: TGW,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-05 07:39:53