2009-06-20 10 views
9
procedure MyProc(Eval: Boolean); 
begin  
    if not Eval then 
     Exit; 
    /* do stuff */ 
    /* do more stuff */ 
end; 

O¿Cuál es la mejor opción?

procedure MyProc(Eval: Boolean); 
begin 
    if Eval then 
     begin 
     /* do stuff */ 
     /* do more stuff */ 
     end; 

    /* no Exit needed, but now we got what I think unpleasing code: 
    having a indentation level and a begin-end statement */ 
end; 
+9

¿Por qué no haces cosas y más cosas en tu función y luego pones la instrucción if alrededor de la llamada a la función? ¿O me estoy perdiendo algo aquí? –

+0

Tomás, podrías haber ganado puntos ... Este comentario es tan bueno como una respuesta. Y ya ha sido votado por unos pocos ... –

+0

Thaks Thomas formándose! Bueno, sé que rompe la cohesión, pero digamos que los dos stufs manejan dos dominios muy diferentes, por lo que no podemos bloquearlo en una nueva función. –

Respuesta

1

¿Puedo alegar que si utiliza el segundo formulario, no agrega un nivel de sangría gratuito? Así insrtead de:

procedure MyProc(Eval: Boolean); 
begin 
    if Eval then 
     begin 
     /* do stuff */ 
     /* do more stuff */ 
     end; 

    /* no Exit needed, but now we got what I think unpleasing code: 
    having a indentation level and a begin-end statement */ 
end; 

dicen:

procedure MyProc(Eval: Boolean); 
begin 
    if Eval then 
    begin 
     /* do stuff */ 
     /* do more stuff */ 
    end; 

    /* no Exit needed, but now we got what I think unpleasing code: 
    having a indentation level and a begin-end statement */ 
end; 
+0

Ninguna crítica fue pensada. El punto es que muchas personas usan niveles de indentación innecesarios, y es un gran dolor. Hay un estilo de innovación C muy horrible que es algo similar al primer ejemplo y necesita ser pisoteado. –

+0

@Neil Butterworth: Guau, fue un error de formación, lo siento. No soy muy hábil con el editor de respuestas ni con mi inglés, pero de todos modos tenemos que identificar el/* do stuff */y/* hacer más cosas * –

16

hay casos en que cualquiera de los métodos es apropiado. Típicamente, sin embargo, el primero ofrece un código más legible y un mejor flujo de control. No estoy muy familiarizado con la programación de Delphi, pero en C# siempre trato de usar el primero cuando sea posible. Por lo que veo, no veo ninguna razón para que el enfoque sea diferente en Delphi.

por mencionar algunas de las ventajas:

  • No hay necesidad de sangrar código subsiguiente.
  • Más fácil de extender a múltiples condiciones. (Sólo tiene que añadir adicional si los estados en lugar de operadores lógicos, lo que hace las cosas más claras de la OMI.)
  • La idea de que está "optar por" del método en lugar de optar en es estéticamente más agradable, ya que el siguiente código debe ser ejecutado en el caso "normal".

Aún así, hay situaciones donde la segunda opción es más apropiada. En particular, cuando el método debe dividirse en subsecciones (aunque esto a menudo es una señal de que necesita refactorizar).

10

Creo que esto es una cuestión de preferencia. Sin embargo, si tiene una serie de comprobaciones que debe realizar antes de realizar el "trabajo real", entonces la primera forma (IMO) se ve más ordenada y es más fácil seguir el flujo. Por ejemplo:

procedure MyProc(Eval: Boolean); 
begin 
    if not Eval then 
     Exit; 
    if not Eval2 then 
     Exit; 
    /* do stuff */ 
    /* do more stuff */ 
end; 

v.s.

procedure MyProc(Eval: Boolean); 
begin 
    if Eval then 
    begin 
     if Eval2 then 
     begin 
      /* do stuff */ 
      /* do more stuff */ 
     end; 
    end; 
end; 
+0

El segundo ejemplo no es el mejor, ya que puede usar operadores lógicos para simplificarlo. – Noldorin

+0

@Noldorin: Punto justo, pero no quería complicar demasiado el ejemplo. Sin embargo, puede imaginar escenarios en los que 'Eval2' es una secuencia de declaraciones más compleja que no se puede combinar trivialmente con la verificación 'Evaluar'. – DaveR

+0

Sí, eso es justo. Estoy muy de acuerdo con su punto general. – Noldorin

4

Hay los que argumentan que sólo debe tener un punto de salida en su función, pero no estoy en ese campo.

Suelo utilizar múltiples devoluciones y que no afecta a la legibilidad de las funciones corto bien pensadas así que diría que ir a por lo que cree que es el más fácil de leer.

He tenido gente refactorizar código que he escrito para seguir las "reglas" y casi siempre de Terminé con una ciénaga de código ilegible debido principalmente a la sangría excesiva. Deberían haberlo dejado o haberlo hecho correctamente, dividiéndolo en más funciones.

Una molestia en particular que veo es la talla de la "else" en:

if (some condition) 
    return false; 
else 
    keep going; 

¿Creen que el flujo de control de alguna manera va a escapar de la cláusula "then"?

+0

Acepto que el estilo de código a menudo se exagera. –

3

Uso la primera forma mucho. Es una programación literal de precondiciones, especialmente porque cuando el código se inserta entre las comprobaciones reales en el segundo ejemplo, las condiciones exactas son menos claras.

Trato de limitar el uso de EXIT a la primera condición, compruebe parte del procedimiento, para evitar demasiados espaguetis, pero creo que la primera forma es más limpia que los aros para saltar y preservar ese punto de salida.

Y parece que se usa mucho, teniendo en cuenta el hecho de que la salida (returnvalue) se añadió en D2009 (y FPC tenerlo durante una década)

0

La realidad es que esto es demasiado simple ejemplo para prevaricar en . Elegirá su enfoque de acuerdo con su convención existente, y este ejemplo es demasiado directo para tomar una decisión sobre la convención. Lo que es más interesante es qué hacer con las múltiples opciones de get-out-now y las declaraciones IF anidadas: es un área gris real.

¿Cuál es mi convención? Ah ... soy pragmático, no tengo reglas. Si es posible saltar por la ventana en las primeras líneas, lo tomo, porque no tengo que recordar cada vez que edito el código que alguna "llamada a función no correspondida" podría estar activa en cualquier momento durante la función.

Con el tiempo, esta función será moldeada y amasada por errores y mejoras. Es más probable que presente un nuevo error con este último enfoque que el anterior, porque la salida rápida es obvia al principio, en su cara, y no necesita preocuparse por eso "olvidado" 50 líneas de la función . En mi experiencia de introducción de errores, por supuesto.

Esta es una llamada más difícil si configura las cosas y tiene que derribarlas, ya que saltar puede obligarlo a hacer malabares con 17 estados de Schrodinger en su cabeza al hacer cambios.

+0

Creo que una docena de declaraciones anidadas normalmente significa código sin cohesión, por lo que tenemos que refactorizarlo, al menos para ser más legible. –

+1

"una llamada más difícil si configuras las cosas y tienes que derribarlas ya que saltar puede obligarte a ..." - no, en realidad no. Como las excepciones pueden hacer que el código salga prematuramente de todos modos, el derribo debe codificarse utilizando el recuento de referencias final o automático. Si funciona correctamente con excepciones, funcionará con exit también. – mghie

+0

mghie - verdadero solo si la salida es una excepción, y no me gusta usar excepciones para modelar cada salida de código, además de que mi "derribo" no significa necesariamente objetos. también depende de si su idioma tiene excepciones, p. Los usuarios de vba son un poco cortos en esto. Sé que la pregunta es Delphi, pero funciona como una pregunta general, que es cómo me acerqué. También tengo que trabajar en otro entorno que no tenga excepciones y soporte de funciones deficiente, por lo que me ocupo de esto todo el tiempo. No tengo una regla rápida, simplemente implemente lo que parece correcto en ese momento. –

0

En mi opinión, tampoco es la respuesta correcta.

La solución correcta sería incluir solo las partes "hacer cosas" y "hacer más cosas" en el procedimiento. A continuación, ajuste la llamada a procedimiento en una instrucción if, solo llamándola cuando sea necesario.

Si, como dices en tu comentario, que "hacer cosas" y "hacer más cosas" cubren dos dominios diferentes, entonces tal vez quieras dos procedimientos: uno para "hacer cosas" y otro para "hacer más cosas" . Si realiza los dos procedimientos juntos lo suficiente, también puede incluir un tercer procedimiento que simplemente llame a los otros dos procedimientos.

+0

@Thomas: ¡Tiene sentido! Pero a veces, tenemos cosas tan complejas que parece bueno encapsularlo en muchos pequeños trozos, como procedimientos, funciones o "consultas", pero, por otro lado, parece peor si se lo granula demasiado, incluso si de esta manera se rompe la cohesión. regla. –

+0

Mientras el código no sea tan granular que se vuelva difícil de entender, está perfectamente bien. Además, una sola función nunca debe realizar dos tareas distintas. –

2

creo que los puntos de salida menos un segmento de código tiene el mejor por lo que es más fácil de leer y entender. Observar es peor que depurar la función de 100 líneas de otra persona y descubrir que hay 12 situaciones diferentes salpicadas en su interior que pueden hacer que vuelva temprano.

+0

@Hardwareguy: estoy totalmente de acuerdo con usted. Un artefacto de código debe tener solo un punto de salida, ya que cuando las cosas van mal, obtenemos una excepción. –

3

Prefiero:

if not Eval then Exit; 

porque el código es el más limpio de esa manera.

Cuestiones relacionadas