Dragon Ball Clean Code - El código se lee de arriba a abajo
Cuidar que el orden de las funciones sea lo más secuencial posible respecto a su ejecución.
Otro de los consejos de Clean Code que nunca se me habría ocurrido y que cuando probé le encontré mucho valor.
Si somos cuidadosos con que las funciones sean más pequeñas, más semánticas, que hagan una sola cosa… veremos como el número de funciones de nuestras clases se multiplica, así que conviene cuidar la organización del conjunto.
Comienza la aventura!
El Dr Brief está ya un poco hasta la gorra de esta refactorización :o) pero no puede dejarlo a medias así que (Recordemos a qué nos enfrentábamos)
public class GravityManager {
public void mainProcess() {
... /* Código ya refactorizado */
EmergencyListener emergency = new EmergencyListener();
emergency.setExplosionDetection(true);
VitalSignalsMonitor vsm = new VitalSignalsMonitor();
HeartBeatMonitor hbm = vsm.getHeartBeatMonitor();
hbm.setMinimumTo(40);
hbm.setMaximumRo(300);
vsm.startHeartBeatMonitor(hbm);
vsm.startBreathingMonitor();
emergency.setVitalSignalsMonitor(vsm);
Contacts contacts = AdressBook.getContacts();
Contact bulma = contacts.getContactByName("Bulma");
emergency.setEmergencyPhoneNumber(bulma.getPhoneNumber());
emergency.startListen();
LightsController lights = new LightsController();
if (gravityMultiplier > 50) {
lights.setColorTo(Colors.RED);
}
TrainingRobotsCollection robots = TrainingRobots.invokeRobotsOfType("Killer Robot").multiplyBy(30);
robots.build();
robots.attack();
}
}
Ya tenía el tema enfocado de antes:
private void initGravitySystem() {
boolean isNewGravitySet = setNewGravity();
if (isNewGravitySet) {
giveFeedbackWhileSettingGravity();
startEmergencyService(); // TODO: Seguimos por aquí
//setRoomAmbient();
//startTrainingSet();
}
}
Como el EmergencyListener
tiene interacción con varias cosa, lo promovió a propiedad de clase.
Creó algunas constantes de cara a hacer métodos más genéricos. Por ejemplo, si dejaba hardcoded el nombre de “Bulma” como contacto de emergencia, si luego esto se lo vende a otros Saiyans, sería más difícil parametrizar el programa. No era un refactor definitivo para abordar ese caso, pero iba a un escenario mejor.
public class GravityManager {
float planetGravity = 0.0f;
float targetGravity = 0.0f;
EmergencyListener emergency;
private static final Integer HEART_BEAT_MIN = 40;
private static final Integer HEART_BEAT_MAX = 300;
private static final String EMERGENCY_CONTACT_NAME = "Bulma";
...
private void initGravitySystem() {
...
startEmergencyService();
...
}
}
private void configureHeartBeatMonitor(HeartBeatMonitor heartBeatMonitor, heartBeatMin, heartBeatMax) {
heartBeatMonitor.setMinimumTo(heartBeatMin);
heartBeatMonitor.setMaximumTo(heartBeatMax);
vitalSignalsMonitorvsm.setHeartBeatMonitor(heartBeatMonitor);
}
private PhoneNumber getEmergencyPhoneNumber(String emergencyContactName) {
Contacts contacts = AdressBook.getContacts();
Contact bulma = contacts.getContactByName(emergencyContactName);
return bulma.getPhoneNumber();
}
private void startEmergencyService() {
this.emergency.setVitalSignalsMonitor( getVitalSignalsMonitor() );
this.emergency.setEmergencyPhoneNumber( getEmergencyPhoneNumber(EMERGENCY_CONTACT_NAME) );
this.emergency.startListen();
}
private VitalSignalsMonitor getVitalSignalsMonitor() {
VitalSignalsMonitor vitalSignalsMonitor = new VitalSignalsMonitor();
configureHeartBeatMonitor( vitalSignalsMonitor.getHeartBeatMonitor(), HEART_BEAT_MIN, HEART_BEAT_MAX);
vitalSignalsMonitor.startHeartBeatMonitor();
vitalSignalsMonitor.startBreathingMonitor();
return vitalSignalsMonitor;
}
Descansado por avanzar otro pasito en el refactor, hizo una nueva lectura del código antes de comitearlo…. Uhm… algo no le gustaba, era como que no era fácil o natural de leer. ¿Por qué? ¿Cómo podían ser difíciles de leer 3 funciones de 3 líneas y 1 de 5 líneas?
Y de repente lo vió. NO HABÍA CUIDADO EL ORDEN DE LAS FUNCIONES
Empezabas a leer el código y startEmergencyService
es la tercera función desde el momento que se llama. Qué confuso, no sería ideal que estuviera justo debajo?
Pero es que el resto era tanto o más descorazonador.
La siguiente función sí estaba justo debajo getVitalSignalsMmonitor
, pero después configureHeartBeatMonitor
estaba arriba de todo y luego… ¿por dónde seguía? había que volver a startEmergencyService
que no estaba al inicio, pese llamarse start
poner foco en cual era la siguiente función getEmergencyPhoneNumber
y de nuevo, estaba declarada antes que start
.
Tratemos de identificar cómo leerían nuestros ojos este código:
/*L:10*/ initGravitySystem()
/*L:12*/ startEmergencyService()
/*L:30*/ this.emergency.setVitalSignalsMonitor( getVitalSignalsMonitor() );
/*L:35*/ getVitalSignalsMonitor()
/*L:37*/ configureHeartBeatMonitor( vitalSignalsMonitor.getHeartBeatMonitor(), HEART_BEAT_MIN, HEART_BEAT_MAX);
/*L:31*/ this.emergency.setEmergencyPhoneNumber( getEmergencyPhoneNumber(EMERGENCY_CONTACT_NAME) );
/*L:23*/ private PhoneNumber getEmergencyPhoneNumber(String emergencyContactName) {
/*L:29*/ startEmergencyService()
/*L:10*/ initGravitySystem()
/*10->12->30->35->37->31->23->29->10*/
Sí, tenía mil atajos en su IDE para moverse efectivamente por el código. Pero estamos hablando de una cantidad de código que cabe perfectament en la pantalla sin hacer Scroll ¿tenía que invertir tal cantidad de clicks y esfuerzo mental para moverse en un bloque de apenas 20 líneas?
Se dispuso a arreglar aquello.
public class GravityManager {
float planetGravity = 0.0f;
float targetGravity = 0.0f;
EmergencyListener emergency;
private static final Integer HEART_BEAT_MIN = 40;
private static final Integer HEART_BEAT_MAX = 300;
private static final String EMERGENCY_CONTACT_NAME = "Bulma";
...
private void initGravitySystem() {
...
startEmergencyService();
...
}
}
private void startEmergencyService() {
this.emergency.setVitalSignalsMonitor( getVitalSignalsMmnitor() );
this.emergency.setEmergencyPhoneNumber( getEmergencyPhoneNumber(EMERGENCY_CONTACT_NAME) );
this.emergency.startListen();
}
private VitalSignalsMonitor getVitalSignalsMonitor() {
VitalSignalsMonitor vitalSignalsMonitor = new VitalSignalsMonitor();
configureHeartBeatMonitor( vitalSignalsMonitor.getHeartBeatMonitor(), HEART_BEAT_MIN, HEART_BEAT_MAX);
vitalSignalsMonitor.startHeartBeatMonitor();
vitalSignalsMonitor.startBreathingMonitor();
return vitalSignalsMonitor;
}
private void configureHeartBeatMonitor(HeartBeatMonitor heartBeatMonitor, heartBeatMin, heartBeatMax) {
heartBeatMonitor.setMinimumTo(heartBeatMin);
heartBeatMonitor.setMaximumTo(heartBeatMax);
vitalSignalsMonitorvsm.setHeartBeatMonitor(heartBeatMonitor);
}
private PhoneNumber getEmergencyPhoneNumber(String emergencyContactName) {
Contacts contacts = AdressBook.getContacts();
Contact bulma = contacts.getContactByName(emergencyContactName);
return bulma.getPhoneNumber();
}
Mucho más natural, veamos qué harían nuestros ojos si leemos secuencialmente:
/*L:10*/ initGravitySystem()
/*L:12*/ startEmergencyService()
/*L:13*/ this.emergency.setVitalSignalsMonitor( getVitalSignalsMonitor() );
/*L:23*/ getVitalSignalsMonitor()
/*L:25*/ configureHeartBeatMonitor( vitalSignalsMonitor.getHeartBeatMonitor(), HEART_BEAT_MIN, HEART_BEAT_MAX);
/*L:14*/ this.emergency.setEmergencyPhoneNumber( getEmergencyPhoneNumber(EMERGENCY_CONTACT_NAME) );
/*L:38*/ private PhoneNumber getEmergencyPhoneNumber(String emergencyContactName) {
/*L:12*/ startEmergencyService()
/*L:10*/ initGravitySystem()
/*10->12->13->23->25->14->38->12->10*/
Es complejo ejemplificarlo por escrito, lo mejor es probar a leer los 2 códigos y darse cuenta uno mismo.
Ponlo a prueba y te sorprenderás.
Agradecimientos
Gracias a mis compañeros y compañeras de Basetis por el acceso a este libro y la flexibilidad para escribir este contenido que comparto con vosotras.