sábado, 18 de enero de 2020

Capítulo 26: El componente principal - Clean Architecture


En cada sistema hay al menos un componente que crea, coordina y supervisa a los otros. Yo llamo a este componente «Main».

El último detalle

El componente «Main» es el último detalle, la política más baja. Este es el punto de entrada inicial al sistema. Nada que no sea otra cosa que el sistema operativo depende de este. Su trabajo es crear todas las factorías, estrategias y otras facilidades globales para más tarde tomar el control sobre sobre las porciones abstractas de alto nivel del sistema. 

Es en este componente «Main» donde las dependencias se deberían inyectar por un framework de inyección de dependencias. Una vez que estas están inyectadas en «Main», este debería distribuir aquellas dependencias normalmente sin usar el framework.

Piensa en el «Main» como en el más sucio de todos los componentes sucios.

Considera el siguiente componente «Main» de una versión reciente de «Hunt the Wumpus». 

Se puede apreciar como este carga todas las cadenas que no se quiere conocer sobre ellas en el cuerpo principal del código.

public class Main implements HtwMessageReceiver {
private static HuntTheWumpus game;
private static int hitPoints = 10;
private static final List<String> caverns = new ArrayList<>();
private static final String[] environments = new String[]{
"bright",
"humid",
"dry",
"creepy",
"ugly",
"foggy",
"hot",
"cold",
"drafty",
"dreadful"
};
private static final String[] shapes = new String[] {
"round",
"square",
"oval",
"irregular",
"long",
"craggy",
"rough",
"tall",
"narrow"
};
private static final String[] cavernTypes = new String[] {
"cavern",
"room",
"chamber",
"catacomb",
"crevasse",
"cell",
"Tunnel",
"passageway",
"hall",
"expanse"
};
private static final String[] adornments = new String[] {
"smelling of sulfur",
"with engravings on the walls",
"with a bumpy floor",
"",
"littered with garbage",
"spattered with guano",
"with piles of Wumpus droppings",
"with bones scattered around",
"with a corpse on the floor",
"that seems to vibrate",
"that feels stuffy",
"that fills you with dread"
};

Aquí está la función «Main». Se puede observar como esta usa la «HtwFactory» para crear el juego. Esta pasa el nombre de la clase «htw.game.HuntTheWumpusFacade», porque esta clase es incluso más sucia que «Main». Esto previene cambios en esa clase de manera que «Main» No tenga que recompilar/desplegar.

println("Health: " + hitPoints + " arrows: " +
game.getQuiver());
HuntTheWumpus.Command c = game.makeRestCommand();
System.out.println(">");
String command = br.readLine();
if (command.equalsIgnoreCase("e"))
c = game.makeMoveCommand(EAST);
else if (command.equalsIgnoreCase("w"))
c = game.makeMoveCommand(WEST);
else if (command.equalsIgnoreCase("n"))
c = game.makeMoveCommand(NORTH);
else if (command.equalsIgnoreCase("s"))
c = game.makeMoveCommand(SOUTH);
else if (command.equalsIgnoreCase("r"))
c = game.makeRestCommand();
else if (command.equalsIgnoreCase("sw"))
c = game.makeShootCommand(WEST);
else if (command.equalsIgnoreCase("se"))
c = game.makeShootCommand(EAST);
else if (command.equalsIgnoreCase("sn"))
c = game.makeShootCommand(NORTH);
else if (command.equalsIgnoreCase("ss"))
c = game.makeShootCommand(SOUTH);
else if (command.equalsIgnoreCase("q"))
return;
c.execute();
}
}

Observe también cómo «main» crea el flujo de entrada y contiene el bucle principal del juego, interpretando la entrada simple de comandos pero delegando todos los procesos a otros componentes de alto nivel. 

Finalmente, observe que el «main» crea el mapa.

private static void createMap() {
int nCaverns = (int) (Math.random() * 30.0 + 10.0);
while (nCaverns-- > 0)
caverns.add(makeName());
for (String cavern : caverns) {
maybeConnectCavern(cavern, NORTH);
maybeConnectCavern(cavern, SOUTH);
maybeConnectCavern(cavern, EAST);
maybeConnectCavern(cavern, WEST);
}
String playerCavern = anyCavern();
game.setPlayerCavern(playerCavern);
game.setWumpusCavern(anyOther(playerCavern));
game.addBatCavern(anyOther(playerCavern));
game.addBatCavern(anyOther(playerCavern));
game.addBatCavern(anyOther(playerCavern));
game.addPitCavern(anyOther(playerCavern));
game.addPitCavern(anyOther(playerCavern));
game.addPitCavern(anyOther(playerCavern));
game.setQuiver(5);
}
// much code removed…
}

La clave aquí es que «Main» es un módulo de bajo nivel sucio en el círculo más exterior de la arquitectura limpia. Carga todo para el sistema de alto nivel y para más tarde cederle el control. 

Conclusión

Se puede considerar a «Main» como un plugin a la aplicación, un plugin que establece las condiciones iniciales y configuraciones, encontrando todos los recursos exteriores y cediendo el control a las políticas de alto nivel de la aplicación. Desde que este es un plugin, es posible tener varios componentes «Main», uno por cada configuración de tu aplicación.

Por ejemplo, tú podrías tener un plugin «Main» para el entorno de desarrollo, otro para el de test y otro para producción. Se podría tener un plugin para cada país que se despliegue o cada jurisdicción o cada cliente.

Cuando se piensa en «Main» como un componente plugin, ubicado detrás de  un límite arquitectónico los problemas de configuración se resuelven más fácilmente.


No hay comentarios:

Publicar un comentario