JS: Abstracción de datos

Teoría: Semántica de matrices

En la lección anterior se dijo que un array es la forma más sencilla de representar un punto. Pero, ¿es esta la forma correcta? Vamos a averiguarlo.

Cuando hablamos de las construcciones del lenguaje, además de la sintaxis, siempre debemos tener en cuenta la semántica. Es decir, para qué tareas se utilizan las construcciones del lenguaje. Sin embargo, en la práctica, a menudo se utilizan herramientas de manera incorrecta. Esto lleva a la creación de código que es más difícil de entender y depurar, y por lo tanto, de mantener.

Un array (indexado), en su esencia, es una colección, un conjunto de valores homogéneos que se pueden recorrer y procesar de la misma manera. Además, estos valores no están estrechamente relacionados entre sí y pueden existir de forma independiente. En un array, a menudo (pero no siempre) no hay posiciones fijas para sus valores. O la posición depende de una tarea específica. Aquí hay algunos ejemplos de situaciones en las que los arrays son adecuados:

  • Lista de palabras clave
  • Lista de usuarios
  • Lista de lecciones de un curso
  • Lista de movimientos en una partida de ajedrez (el orden es importante)

En el contexto de nuestra biblioteca gráfica, un array sería adecuado, por ejemplo, para almacenar una colección de puntos o un conjunto de segmentos.

Un punto en sí mismo no es una colección. Es una entidad única, cuyas partes no tienen sentido por sí solas. No se puede establecer un orden entre ellas, a diferencia, por ejemplo, de una lista de usuarios. Y el código que trabaja con un punto específico representado como un array siempre espera que el array esté compuesto por dos elementos, cada uno de los cuales tiene una posición específica. En otras palabras, el array se utiliza como una estructura para describir un objeto compuesto (es decir, uno que se describe no con un solo valor, sino con varios, en este caso, dos números de coordenadas).

En esta situación, es más apropiado utilizar un objeto:

const point = { x: 2, y: 3 };
const symmetricalPoint = { x: -point.x, y: point.y };

El código es un poco más largo, pero la semántica es más importante. Este código es más fácil de entender porque en lugar de las extrañas point[0] o point[1], aparecen construcciones que son completamente comprensibles a primera vista: point.x. Incluso al mostrarlo en pantalla, se entiende de inmediato de qué se trata.

Imagínese cómo se vería la representación de un segmento utilizando arrays. Como un array de arrays:

const point1 = [2, 3];
const point2 = [-8, 10];
const segment = [point1, point2];

// el código es difícil de entender
point1[1];
point2[0];
segment[1][0];

Es imposible entender que esto es un segmento sin entender el contexto. Lo único que ayuda parcialmente es tener buenos nombres de variables, pero eso no es suficiente.

El uso de la estructura de datos correcta (la que se adapta a la tarea) es mucho más importante:

const point1 = { x: 3, y: 4 };
const point2 = { x: -8, y: 10 };
const segment = { beginPoint: point1, endPoint: point2 };

// este código ya es más fácil de entender
point1.x;
point2.y;
segment.endPoint.y;

Recuerde esta regla simple: el código que requiere pensar, como nombres que no dicen nada, malas abstracciones, estructuras de datos incorrectas, dependencia fuerte del contexto, es un mal código (es importante no confundir la facilidad con la simplicidad).

El uso de un objeto también tiene otra ventaja extremadamente importante: la extensibilidad. Un array indexado utilizado como estructura es frágil. No se puede cambiar el orden de los argumentos sin romper todo el código que depende de un orden específico, o se debe reescribir todo. Tampoco es fácil de ampliar: parte del código seguirá funcionando, pero parte puede romperse (por ejemplo, [x, y] = point). En cambio, el uso de un objeto no depende del orden de las claves y ciertamente no depende de su cantidad. En cualquier momento se puede agregar una nueva clave y es muy probable que el programa siga funcionando.

¿Qué otros datos deben representarse como objetos? Cualquier entidad individual:

  • Usuario
  • Curso
  • Lección
  • Pago
  • Partida de ajedrez (además de la fecha, los nombres y el lugar, contiene una serie de movimientos)