Esta semana me paso algo que definitivamente creo que merece una nueva regla. Me
encontraba con la necesidad de modificar la implementación de una funcionalidad
dentro de un componente de uso común, el motivo es porque se comportaba de forma
errónea. Hasta allí todo era normal, una modificación de un componente que no debiera
impactar en absoluto al comportamiento ni a la implementación de los sistemas que
lo consumen. Cuando me di a la tarea, apareció una variable pública dentro de la
clase, que además era parte fundamental de la implementación… y allí comenzaron
todos los problemas.
El hecho que estuviera pública la variable implicaba que cualquier cambio hacia
la misma afectaría a los módulos que ajenos al sistema que la consumieran (y en
este caso así era). La funcionalidad estaba horriblemente implementada (y era incorrecta),
y la variable francamente era innecesaria, sin embargo debiera mantener compatibilidad
con la multitud de sistemas que la usaban. Aquí había dos opciones, mantener la
variable y de alguna forma modificar a funcionalidad para que la sigan usando en
los mismo términos (cosa que se me hacía un malabarismo completamente innecesario
y perjudicial, a la vez que chapucero) o rediseñar la funcionalidad y solicitar
a todos los sistemas que se adecuaran a ella, con lo que implicaba coordinar una
liberación múltiple de sistemas. Una tercera opción es mantener los dos componentes
productivos, el que tiene el error y el que no, pero eso implicaría un doble mantenimiento
en supuesto caso que hubiera que mover nuevamente el componente.
Intentando comprender que motivos tenía el programador para crear un variable (que
claramente tiene un ámbito privado), como publica, me doy cuenta que se comparte
entre dos módulos del mismo componente, esto de por si era innecesario, pero no
solo no se redujo el ámbito de la variable al nivel del componente, si no que se
hizo totalmente pública.
He observado que esto es un problema muy común de muchos programadores noveles,
escriben la palabra "public" por inercia al momento de crear una nueva funcionalidad,
sin pararse realmente a pensar que están haciendo, y solo cuando lo meditan bien
escriben "privado". A veces no se dan cuenta de esta circunstancia, otra veces piensan
que es más sencillo, si todo es público, a veces incluso piensan que le dan cierto
sentido de "libertad", cuando lo que se hace abrir puerta al desastre (la “libertad”
la da en todo caso, compartir el código fuente, no habilitar métodos privados como
públicos).
La verdad es que se lo único que se está haciendo es romper el "principio de ocultación".
El principio de ocultación indica que cualquier implementación interna de una clase
debe estar oculta para los consumidores, no debiera mostrarse variables de ningún
tipo, si no que la interacción y la modificación de la instancia de una clase se
hacen mediante mensajes (representados genialmente a través de métodos, o propiedades).
Generalmente esto se consigue mediante el encapsulamiento, agrupar dentro de la
clase todo lo que le de identidad como tal (tanto funcionalidad, como datos), y
solo exponer los mensajes necesario para interactuar con ella.
Partamos de una clase que tiene todo privado. Ok… ese tipo de clase no sirve de
nada, puesto que necesita comunicarse con el exterior, o más bien el exterior necesita
comunicarse con ella para que sea útil, eso es porque la clase tiene una responsabilidad
(debemos asegurarnos que solo y exclusivamente tenga una). Debemos asegurarnos de
exponer solo los métodos (o propiedades), mínimas indispensables para poder comunicarse,
cuanto menos sean mucho mejor será.
Con esto estoy garantizando otro principio, que es el del desacoplamiento. Esto
es que las clases dependan muy poco entre ellas y de sus implementaciones particulares,
de forma que pueden ser sustituidas fácilmente por otro tipo de la implementación,
o incluso con otras clases, sin mayor impacto en sus consumidores. Esto era imposible
en mi escenario, el hecho que los sistemas usaran una variable pública implicaba
que dependía mucho de cómo internamente se usaba ese variable, impidiendo cualquier
sustitución, con los que estaban demasiado acoplados.
Existen los siguientes grados de ocultamiento (en la mayoría de los lenguajes):
-
Privado: El más restrictivo. Cuando más privado sea todo más desacoplado será, Solo la misma clase puede usar un método privado.
-
Protegido: Solo puede usarlo la misma clase o sus descendientes. Por lo que por lo menos garantizamos que no hay un consumo indeseado desde el exterior de clase. Si no hay algún motivo para hacerlo protegido, debiera seguir siendo privado, es más fácil cambiar un método de privado a protegido, que al revés.
-
Interno: Aquí entramos un poco un terreno más público. Indica que todos los módulos (clases) que pertenezca al mismo componente, podrán usar el método, en este escenario seguimos teniendo el control de lo que es público y privado, ya que siguen siendo llamadas que ocurren en el interior de nuestro componente.
-
Público: Aquí ya estamos en el ámbito publico totalmente, cualquiera podría usar el método o la variable en cualquier momento y forma, con lo que sí está mal expuesta (como nuestro caso), los métodos que la implementan lo harán de forma incorrecta, dificultando el poder reemplazar el componente por otro más optimo debido al acoplamiento sufrido.
-
Amistoso "friendly”: Este es algo curioso, es cuando un componente tiene “derecho” de acceso a un método privado de otro componente. Tenemos en este caso dos componentes que no tienen nada que ver entre ellos y sin embargo uno puede acceder a los métodos privados del otro. Aquí hay un problema de cohesión, debido a que si es realmente necesaria la “amistad” seguramente debieran ser el mismo componente y no dos componentes separados. Además hay un problema de acoplamiento debido a que estamos haciendo que un componente que no tiene nada que ver con otro, conozca detalles de su implementación interna.
En definitiva debemos usar el modificador más restrictivo siempre e ir haciendo
publico según tengamos la necesidad, cuestionándonos siempre si realmente es necesario
el cambio. Esto reducirá el acoplamiento de los componentes y nos facilitara el
mantenimiento en nuestros sistemas.