Código de repetición vs método multi responsable

11

Intento seguir el Principio de responsabilidad única (SRP) y también omitir las repeticiones de código. Sin embargo, a menudo hay lugares donde hay repeticiones de código que no son más que bloques de invocaciones de código que son resistentes a extraerlas en un método con un nombre al menos significativo:

DoAction1();
DoAction2();

if (value)
    DoAction3();

DoAction4();

¿Cuál es la mejor manera de extraer dicho código en un método y cómo nombrarlo?

yee
fuente
1
¿Por qué son resistentes a ser extraídos en un método significativo diferente?
Chandranshu
Todas las acciones hacen algo no relacionado. Tendría que escribir: void MethodThatDoAction1ThenAction2AndAction3IfValueAndThenAction4(). Prefiero ver más significado en: CodeBlock1().
yBee
44
Entonces es simplemente una cuestión de nombrar correctamente el método extraído, ¿verdad? Me temo que no hay una solución universal y tendrá que hacerlo caso por caso. Si está repitiendo exactamente el mismo fragmento de código en más de 1 lugar, seguramente habrá un significado para sus acciones y tendrá que buscar mucho (puede discutirse) para encontrar ese significado y darle un nombre.
Chandranshu
1
Si te sirve de consuelo, el ganador de Spring para los nombres largos de clase es el AbstractInterruptibleBatchPreparedStatementSetterque es solo un poco más pequeño que tu método.
Chandranshu
1
@Chandranshu Creo que sus comentarios funcionarían bien como respuesta a esta pregunta.
Simon Forsberg el

Respuestas:

13

Creo que es simplemente una cuestión de nombrar correctamente el método extraído. Me temo que no hay una solución universal y tendrá que hacerlo caso por caso. Si está repitiendo exactamente el mismo fragmento de código en más de 1 lugar, seguramente habrá un significado para sus acciones y tendrá que buscar mucho (puede discutirse) para encontrar ese significado y darle un nombre.

Si te sirve de consuelo, el ganador de primavera para los nombres de clase largos es el AbstractInterruptibleBatchPreparedStatementSetterque tiene 49 caracteres.

Chandranshu
fuente
11

En realidad, está sufriendo la tarea más difícil que debe realizar un programador : Naming Things . Perdón por una respuesta tan madura pero no pude resistirme. Puede encontrar que muchas personas sufren de esto , incluso en Internet puede encontrar este tipo de ensayo .

Ahora, si su código repetitivo es todo el resultado de un trabajo y esos métodos no están siendo utilizados por otros métodos, entonces son simplemente métodos de Ayuda y luego el método resultante se puede nombrar como doXXXo makeXXX... Creo que entiende el punto.

Como dijo Chandranshu "Si estás repitiendo [...] este significado y le das un nombre". es al grano y apropiado.

ingrese la descripción de la imagen aquí

Foto cortesía: CodeChef Facebook Page Photo

Anirban Nag 'tintinmj'
fuente
2

Creo que está llevando el principio de repetición del código demasiado lejos. Piense en el punto de evitar la repetición de código. El punto es reducir la cantidad de código que debe verificarse cuando hay un cambio en la lógica, y aumentar la comprensión al factorizar bloques obviamente de intención similar.

Las desventajas de la factorización para evitar la repetición son que si uno de los bloques compartidos tiene que cambiar, ahora necesita una herencia aún más compleja o un cambio entre la implementación estándar y la no estándar.

Por lo tanto, sopese cuidadosamente la posibilidad de que la lógica de incluso uno de estos bloques cambie sin los otros contra los beneficios de comprensión obtenidos al factorizar esta comunidad. Si una implementación puede separarse de las demás, es mejor que simplemente repita el código.

Mientras mantiene este código repetido, a medida que se vuelve más complejo y el dominio de su problema se vuelve más definido, puede encontrar más apropiado factorizar las secciones repetidas, ahora más complejas, pero también más definidas.

Por lo general, trato de mantener la uniformidad del editor de texto durante un tiempo hasta que puedo ver si vale la pena factorizar algo que parece ser repetitivo. Simplemente mantengo la repetición, pero mantengo mi ojo hacia el futuro de ese bloque al mantenerlo textualmente fácil de combinar más tarde.

Gran parte del tiempo, la igualdad y la posible factorización comienzan a disiparse, como reglas comerciales reales, caprichosas y una lógica altamente dependiente, a menudo arbitraria; como lidiar con las rarezas de varias implementaciones de bases de datos comunes (ANSI_NULLS o algo así viene a la mente) se agregan; obligando a lo que parecía una lógica pura a un desorden retorcido, tratando de proporcionar una lógica de decisión razonable y defendible cuando se enfrenta con el desorden del estado de la industria.

Me parece que si la gente tratara de descifrar lo que está tratando de factorizar, tendríamos una biblioteca completa de construcciones sin valor como Do1Then2If2False Do1IfTrueDo2.

Tiene que ser más complejo y más claro que el bloque no va a cambiar para justificar su factorización.

Es software . Puede regresar y editar un par de bloques que son iguales en este momento. Tomará 5 minutos. Y puede ahorrar horas de factorización desperdiciada, y luego horas más de herencia desperdiciada y desarrollo de conmutación, simplemente dejándolo y asegurándose de tener un buen teclado anti-RSI.

Andyz Smith
fuente
Me gusta la parte que extrae la esencia de la repetición de código: para reducir la cantidad de código que debe verificarse cuando hay un cambio en la lógica
yBee
1

Si realmente está siguiendo el Principio de responsabilidad única, entonces este bloque de código debe tener un propósito específico, ¿verdad? De lo contrario, estos métodos estarían en clases separadas.

Entonces, ¿cuál es el propósito de este bloque de código? Determina eso y deberías ser capaz de encontrar un nombre.

Si aún no puede averiguar el nombre de esta cosa, entonces tal vez estos métodos en realidad no estén juntos. Es decir, este bloque de clase / código tiene más de una responsabilidad. En ese caso, refactorizar para dividir las tareas puede revelar un mejor nombre revelador.

Alano
fuente
1

He tenido una situación que puede ser similar a la tuya:

Hay una clase que define la funcionalidad del objeto que representa:

class Functionality
{
protected:
void functionA();
void functionB();
...
void functionZ();
}

Luego hay una clase que define los flujos de trabajo para operaciones de alto nivel que realiza el objeto:

class Workflows: private Functionality
{
    void WorkflowA()
    {
        functionA();

        if (m_bValue) {
            functionB();
        }

        functionC();
    }
    ...
    void WorkflowB();
}

Si se encuentra en una situación similar, identifique qué representan sus clases (en este caso, funcionalidad / flujos de trabajo) y luego nombre los métodos en consecuencia.

Descargo de responsabilidad: los nombres de clase utilizados en este ejemplo son muy inexactos, pero los nombres de los métodos dan una pista. Discreción aconsejada.

dotbugfix
fuente