jueves, 25 de enero de 2018

Regla N°16 de la Ingeniería de Software: Por defecto todo es privado (principio de ocultación)


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.

No hay comentarios:

Publicar un comentario