¿Cómo prevenir hendiduras profundas? [cerrado]
https://softwareengineering.stackexchange.com/questions/2204
-
16-10-2019 - |
Pregunta
¿Qué pasos y medidas puedo tomar para prevenir hendiduras profundas en mi código?
Solución
hendidura profunda es general no es un problema si cada función / método en su programa hace una y sólo una cosa. En ocasiones, podría que sea necesario condicionales nido unos niveles de profundidad, pero honestamente puedo decir que sólo he escrito código profundas aberturas un puñado de veces en más de 12 años de codificación.
Otros consejos
Lo mejor que puede hacer es extracto de métodos:
int Step1(int state)
{
if (state == 100)
{
return Step2(state);
}
else
{
return Step3(state);
}
}
int Step2(int state)
{
if (state != 100)
{
throw new InvalidStateException(2, state);
}
// ....
}
Tal vez usted podría considerar cláusulas de guardia ?
en lugar de
public void DoSomething(int value){
if (someCondition){
if(someOtherCondition){
if(yetAnotherCondition){
//Finally execute some code
}
}
}
}
Do
public void DoSomething(int value){
if(!(someCondition && someOtherCondition && yetAnotherCondition)){
return;
//Maybe throw exception if all preconditions must be true
}
//All preconditions are safe execute code
}
Si alguna vez tienes la oportunidad me gustaría que recomiendo leer el código completo de Steve McConnell. Él tiene un montón de buenos consejos sobre estos temas.
Para más información sobre "cláusulas de guardia" ver: https: // sourcemaking .com / refactorización / replace-anidado-condicional-con-guardia-cláusulas
Invertir sus if
s.
En lugar de:
if (foo != null)
{
something;
something;
if (x)
{
something;
}
something;
}
else
{
boohoo;
}
Me gustaría escribir:
if (foo == null)
{
boohoo;
return;
}
something;
something;
if (x)
{
something;
}
something;
Lo mismo se aplica a los bloques if
-else
. Si else
es más corto / menos anidada, a continuación, revertirlas.
Comprobar los valores de los parámetros en un solo lugar
Comprobar todos los parámetros para los valores ilegales en cuanto introduce su método, a continuación, proceder a sabiendas de que estás a salvo. Se convierte en un código más legible, pero también le ahorra apilando bloques condicionales más adelante y la difusión de estos controles en todo el subprograma.
Por lo general, he visto que el código profundas aberturas suele código problemático. Si se enfrentan a este problema, a continuación, dar un paso atrás y evaluar si su función es hacer demasiadas cosas.
Al mismo tiempo, para responder a su pregunta, si hay una necesidad de una hendidura que en el fondo, sugeriría que usted permite que sea allí. Por la sencilla razón de que en dicho código, la sangría le ayudará, ya que probablemente será un largo trozo de código es.
Salto de componentes (especialmente repetidas unos) hacia fuera en funciones separadas (esto es más fácil si sus Apoya lengua cierres) anidado o reemplazar una serie de bucles anidados con una recursividad.
Además, guión dos espacios en lugar de cuatro.
No veo hendiduras profundas como un problema categórica a ser eliminado (ni veo refactorización como la verdadera respuesta para todo).
Por lo general en lugar de ifs anidados, me gusta escribir los enunciados lógicos:
if (foo && bar && baz)
en lugar de
if foo
if bar
if baz
Yo no lo creía yo, pero de acuerdo con el Código Completa este es un lugar apropiado para su uso break
(si su equipo está a bordo). Me imagino que esto es más aceptable con los programadores de C ++, sin embargo, cuando se utiliza en break
declaraciones switch
lo que es con los programadores de Delphi, donde break
sólo se utiliza cuando no se siente como escribir un bucle while
.
La sangría es realmente una lucha a pensar, en efecto. Lo que he aprendido a hacer es dividir el método en pedazos en primer lugar, a continuación, utilizar un truco raro para saltar cada siguientes piezas si una pieza no. He aquí un ejemplo:
En lugar de:
{if (networkCardIsOn() == true)
{if (PingToServer() == true)
{if (AccesLogin(login,pass) == true)
{if (nextCondition == true)
...
}
}
}
Actualmente escribo:
{vbContinue = true;
if (vbContinue) {
vbContinue = networkCardIsOn();
if (vbContinue == false) {
code to Handle This Error();
}
}
if (vbContinue) {
vbContinue = PingToServer();
if (vbContinue == false) {
code to HandleThisError2();
}
}
if (vbContinue) {
vbContinue = AccesLogin(login,pass);
if (vbContinue == false) {
HandleThisErrorToo();
}
}
...
Esto tiene parecer extraño para mí en un principio, pero desde que uso esto, el costo de mantenimiento se ha dividido por la mitad, y mi cerebro es más fresco al final del día.
De hecho, la ganancia introducida por esta "técnica" es que la complejidad del código está muy dividida porque el código es menos denso.
Mientras lee el código, usted no tiene que recordar nada acerca de las últimas condiciones:. Si su son en ese punto X en el código, los pasos anteriores se pasan y han tenido éxito
Otra ganancia es que "ruta de escape y la condición" de todos aquellos anidada "if-else" se simplifica.