Simetría

Palabras clave:
Tiempo aproximado: 2 min.

Lo siento, si alguien espera un post navideño (a pesar de los copitos cayendo por el blog) al estilo retrospectiva o propósitos de nuevo año, que se vaya buscando otro artículo. Creo que soy de esos que no tiene mucho apego por la Navidad. Sin embargo, ¡Feliz paso de año y que el 2011 os trate mejor que el 2010! (A todos, aunque hayamos sido -algo- malos) 🙂

Bueno, al tema.

Picado por no haber podido estar ayer en el codingdojo de @madridrb (la comunidad de Ruby en Madrid a la que, por fin, se acercó mucha gente que conozco), estaba yo practicando la codekata de los números romanos (una parte de ella, realmente, la de pasar a “romano”) y se me ocurrió hacer un pequeño cambio. En vez de usar un java.util.Map (sí, en Java, qué pasa 🙂 ) pensé en usar un array. Pensé que no debería afectarme mucho porque había escrito mi código haciendo mi mejor TDD (lo cuál no quiere decir que lo haga bien).

Para que tengáis una primera imagen de lo que hablo, mi método “String to_roman(int n)” es como sigue:

[embed_snipt:vomnk]

NUMERALS es un Map<Integer,String> ordenado para que “int find_biggest_numeral_that_fits(int i)” sea más fácil (y de paso eficiente). Pero lo que os quiero contar no es si es mejor usar un Map o un array para guardar esta tabla. De hecho, sobre esto se me ocurre otro artículo muy chulo sobre SRP (aunque no pueda superar éste de Hadi Hariri, claro). El caso es que, al cambiar la estructura de datos que soporta esto, mi algoritmo ha tenido que cambiar incluso hasta el método de más alto nivel de abstracción “to_roman”. #FAIL

Recordemos el “Implementation Patterns” que, aunque no lo tengo a mano, recuerdo que hace hincapié en cuidar que nuestros métodos mantengan un nivel de abstracción coherente. En este caso es evidente que estamos llamando a “find_biggest_numeral_that_fits” para abstraernos de los detalles técnicos pero luego, en el mismo “to_roman” usamos NUMERALS para obtener el valor correspondiente. Hemos introducido una asimetría que no es muy dañina (en este caso que el problema es pequeño, que por eso es pequeño, para que podamos practicar sin que nos duela tanto como “en la vida real”).

Al refactorizar he cambiado “find_biggest_numeral_that_fits” por una llamada a “find_biggest_numeral_using_an_ordered_map” y ahí, al cambiar mi solución basada en un array y llamar al nuevo “find_biggest_numeral_using_an_ordered_array” me he dado cuenta de que no he cambiado NUMERALS y que sigue siendo un Map. #FAIL.

He renombrado NUMERALS a NUMERALS_AS_MAP para que sea más evidente y así, he ocultado ese “código feo” en un bonito “String get_numeral(int i)”, lo cuál deja el método “to_roman” mucho más limpio.

[embed_snipt:vonkn]

Por cierto, observad también el leve cambio que he hecho en el orden de la linea 6, donde inicializo el StringBuffer. Me ha parecido que inicializarla “tan lejos” de donde la uso le daba un cierto tufillo que no me gustaba nada. ¿A que se lee mejor ahora? 🙂

Espero vuestros comentarios. Seguro que se puede mejorar mucho aún.

Ea, lo dicho, ¡Feliz 2011!