No dejes que tu código decida

O al menos no lo dejes decidir todo el tiempo 🙂

Una de las cosas más difícil de la Programación Orientada a Objetos es mantener el foco en generar un buen código y no perderse en la tentación de generar un mar de condicionales (a.k.a. if’s). Es este artículo la idea es mostrar al lector que es posible generar código que no contenga condicionales, o sea al menos que sean pocos.

El problema con tener condicionales es que nos genera caminos alternos; cada camino puede tener su propia consecuencia; por lo que cada vez que queremos probar, debemos hacerlo por todos los caminos posibles. Si tenemos condicionales anidados la cantidad de caminos crece aún más, por lo que desde un punto de vista ideal, un código que tenga un solo camino posible es más fácil de probar (manual o automáticamente).

Hoy estábamos agregando sonidos a Jumping Code para Android, juego que estamos desarrollando en PatagonianTech y en uno de los pulls viene el siguiente código :

https://gist.github.com/Gazer/d106ad38b4cd858f279f9aac5a0f586d

Cada vez que saltamos, reproducimos el sonido correspondiente. Pero como somos bueno, dejamos que el usuario pueda prender y apagar el sonido a gusto, porque hay momentos en que uno quiere jugar en silencio :).

El problema con este tipo de aproximaciones suele ser :

  • Por cada evento que produce sonido, tenemos que agregar 4 líneas de código
  • Al utilizar una “Utility class” con métodos estáticos hacemos más difícil la posibilidad de agregar pruebas unitarias.

La solución más elegante, que a mi me gusta aplicar, en estos casos es utilizar un Factory primero para obtener un ‘SoundManager’ y luego tener 2 implementaciones : ‘LoudSoundManager’ y ‘SilentSoundManager’.

En este caso, como estamos con Java en Android, vamos a usar una interfaz para definir al manager genérico :

https://gist.github.com/Gazer/f128117877b82598b52b04d4f411bfdd

Ahora, si queremos reescribir el fragmento original simplemente tenemos que utilizar un SoundManager que nos será dado de alguna manera a determinar :

https://gist.github.com/Gazer/372616b12db49bc3263cc35349e8f060

Si tenemos 10 sonidos, vamos a cambiar 40 líneas de código que contienen if’s, llaves y condiciones por 10 simples llamadas a métodos. Es difícil negar lo útil de esta abstracción :).

Para implementar el loud manager (el que hace ruidos, digamos) podemos hacerlo bien simple reutilizando lo que ya teníamos inicialmente :

https://gist.github.com/Gazer/d405575ef50fee624b0730c830dc8b87

Para cuando no tenemos sonido, podríamos decir que SoundManager es null lo cual es tan malo como el caso inicial, porque tenemos que hacer el if de todos modos y peor aún porque si nos olvidemos estamos en un potencial NPE . Es por eso que lo mejor es aplicar el “Null Object Pattern”, que básicamente consiste en tener una implementación de la interfaz que no haga nada :

https://gist.github.com/Gazer/5c221c5ed446c026b69647836b2dbec0

Por último lo que necesitamos es una manera de obtener el manager correcto según las preferencias del usuario. Podemos hacer algo muy complicado o tener simplemente un “Factory Method” en algún lugar :

https://gist.github.com/Gazer/1ae044ff0a6ec9e2bbea9285b2a8e2d1

Este ejemplo es muy simple, pero multiplicado por cada decisión que hacemos o que dejamos hacer al código, termina en códigos que son difíciles de probar, tanto manual como automáticamente y poco agradables a la vista.

Los patrones son herramientas que como desarrolladores debemos tener presente para aplicarlas según sea necesario, a fin simplificar el código escrito para que sea más claro de entender y más simple de probar.


Existen otras alternativas que no requieren tanta ceremonia de crear una interfaz y dos implementaciones. La solución presentada no es la única ni la mejor. Es responsabilidad de Uds evaluar en cada caso el beneficio y el costo de implementar una posible solución a un problema determinado.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google photo

Estás comentando usando tu cuenta de Google. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s