Artículo
· 27 abr, 2023 Lectura de 8 min

Cómo mantener contenta a la API: limpieza de las utilidades SQL

Con IRIS 2021.1, realizamos una importante revisión de nuestra API de utilidades SQL en %SYSTEM.SQL. Sí, eso fue hace algún tiempo, pero la semana pasada un cliente hizo unas preguntas sobre ello y entonces @Tom Woodfin me empezó a presionar un poco ;-) para que describiera con más detalle en la Comunidad de Desarrolladores las razones de estos cambios. ¡Así que allá vamos!

A principios de 2020, la API %SYSTEM.SQL pasó de ser un útil envoltorio de clases alrededor de unas rutinas clave a un gran número de puntos de acceso no tan coherentes para diversas funcionalidades relacionadas con SQL. Eso no debería sorprendernos, ya que el motor SQL de IRIS (y antes el motor SQL de Caché) creció mucho en funcionalidades y facilidad de uso. Como nos preocupamos mucho por la compatibilidad con las versiones anteriores, casi todos los cambios de la API fueron una incorporación neta, un nuevo método o una extensión de la estructura de un método. En algunos casos, este objetivo de compatibilidad con las versiones anteriores significó que el intento de simplificar las cosas mediante la eliminación de un argumento de métodos (para algo que ahora estaba automatizado) se diluyó al eliminar el argumento en la clase de referencia, pero dejándolo en su lugar para no alterar el código que lo utilizaba. En otras palabras, la API comenzó a parecerse a un famoso plato italiano que no es una pizza.

Si a estas alturas piensas: "¡Qué lío has hecho, eso nunca nos pasaría a nosotros!" - puedes dejar de leer aquí. 

... Creo que aún sigues ahí :-)

Probablemente sea justo decir que este tipo de crecimiento orgánico es inevitable y, en cierto modo, no necesariamente negativo, ya que significa que progresas y te preocupas por tus usuarios, ya que no destruyes su código al adaptar la API entre cada versión. Pero en algún momento hay que sacar la escoba y limpiar. Y eso es lo que hicimos en 2020.3 con las herramientas SQL de IRIS.

Ordenando las cosas

El primer problema que queríamos resolver era la gran cantidad de métodos, que eran demasiados para que una sola API fuera manejable. Así que empezamos por dividir la clase en una serie de clases API más pequeñas y más centradas en el paquete %SYSTEM.SQL, lo que significaba que podríamos conservar la agradable sintaxis abreviada de $SYSTEM.

  • SYSTEM.SQL.Functions – por si no lo sabes, %SYSTEM.SQL tiene equivalentes en ObjectScript para todas las funciones escalares simples de IRIS SQL, como %SYSTEM.SQL.ABS().
  • SYSTEM.SQL.PTools – las Herramientas para analizar rendimiento son un grupo de utilidades para analizar en profundidad el rendimiento de las consultas individuales. Este avanzado conjunto de herramientas lo utilizan principalmente el servicio de Soporte de InterSystems y los clientes más experimentados, pero es una API muy potente y bien documentada, por lo que merece la pena echarle un vistazo si necesitas resolver esa dichosa consulta
  • %SYSTEM.SQL.Schema – la verificación de la existencia de tablas, la importación o exportación de sentencias DDL y otras funciones para consultar o modificar objetos del esquema ahora están aquí.
  • %SYSTEM.SQL.Security – agrupa los puntos de acceso ObjectScript para los comandos GRANT y REVOKE
  • %SYSTEM.SQL.Statement – como probablemente sabrás, InterSystems IRIS incluye una completa gestión y almacenamiento de sentencias SQL. Esta clase agrupa métodos para administrar el contenido del Índice de sentencias, como importar y exportar planes, así como freezing y thawing, si se quiere forzar el uso de alguna en particular.
  • %SYSTEM.SQL.Stats.Table – Aquí es donde puedes recopilar estadísticas de las tablas y, opcionalmente, anularlas, importarlas o exportarlas. Es un nivel más profundo que los demás, ya que hay otros elementos sobre los que nos gustaría recopilar y gestionar estadísticas en el futuro.
  • SYSTEM.SQL.Util – No todo encaja en un cajón temático limpio, así que aquí es donde ponemos los restos: la funcionalidad que queríamos conservar de %SYSTEM.SQL, pero para la que no encontramos un lugar más adecuado. Solo un número muy reducido de tareas extremadamente comunes, como %SYSTEM.SQL.Explain(), se quedaron en la clase de nivel superior.

Por supuesto, todavía nos preocupamos por los usuarios con un código que llama a los puntos de acceso preexistentes, por lo que hemos dejado todos los métodos originales en la clase %SYSTEM.SQL y los hemos marcado como internos y obsoletos usando palabras clave para los métodos, dejando una nota sobre la nueva ubicación preferida de la función.

Una de las ventajas de este enfoque con nuevas clases es que no tenemos que preocuparnos de que lo nuevo se interponga en el camino de lo que ya existe. En la mayoría de nuestras API REST (como /api/deepsee/ y /api/iknow/*), introdujimos un número de versión en la propia URL de la API (por ejemplo, /api/iknow/v1/namespace/domains) para tener en cuenta estos cambios en la API. También probamos brevemente esa idea aquí, pero pensamos que quedaría muy mal en el nombre de una clase y no invitaría a los usuarios a adoptarla en vez del punto de acceso base que ya existe y está obsoleto. Los nuevos puntos de acceso también son un poco más extensos, pero al menos el token extra tiene sentido con respecto a lo que intenta conseguir. De manera implícita, esto significa que suponemos con cierto optimismo que nunca volveremos a tener que cambiar estas API, así que vamos a echar un vistazo al otro cambio importante que hemos hecho: revisar las estructuras de los métodos.

Limpieza profunda

Como hemos descrito en la introducción, no solo veíamos un número desmesurado de métodos, sino que algunos tenían una estructura desmesurada en el mismo método. Algunos buenos ejemplos eran los métodos TuneTable() y Export(), a los que se les agregaron un gran número de indicadores a lo largo de los años. Normalmente, los argumentos más interesantes son los nuevos del final, y habitualmente veía incluso a los desarrolladores más experimentados contar las comas antes de poner ese 1 o 0 para anular un valor (esperamos que decente) predeterminado. Claramente era un área que podíamos mejorar, y así lo hicimos.

La primera pregunta que debemos hacernos es, obviamente, si merecía la pena mantener cada argumento. Algunos han sido superados con el tiempo o por nuevas funcionalidades, y pueden omitirse sin problemas. Después, pusimos los más importantes y obligatorios al principio y agrupamos todos los indicadores opcionales en un nuevo argumento qualifiers, de naturaleza similar a los calificadores utilizados en varios métodos %SYSTEM.OBJ. Admitimos un objeto dinámico o un formato heredado. El primero se puede pasar como una instancia %DynamicObject, o en formato de cadena JSON, como { "silent": 1, "logFile": "/tmp/xyz.log" }. El último utiliza el mismo formato que en %SYSTEM.OBJ usando barras, en el que los calificadores anteriores podrían expresarse como "/silent /logFile=/tmp/xyz.log". Este mecanismo ha sido una excelente forma de ofrecer métodos API fáciles de usar, de documentar y de evolucionar.

Además de cambiar la lista de argumentos, también hicimos otras cosas más sencillas, como un uso más estandarizado de los valores de retorno %Status y los parámetros ByRef. Y por último, pero no por ello menos importante, cambiar los nombres de los métodos para que sean más uniformes y autoexplicativos, a menudo facilitado por el paso a un subpaquete con nombre razonable. ¿Sabrías decir sin mirar si el antiguo método %SYSTEM.SQL.Export() exportaba datos o información del esquema? ¡No tengo nada más que decir!

Pensando en el futuro

¿Ya terminamos? Definitivamente no. Estoy muy agradecido por el tiempo que el equipo ha dedicado a revisar este cambio de especificación, implementación y pruebas, pero cuando lo lanzamos con 2020.3, ya habíamos identificado algunos casos en los que podríamos haber ido un poco más lejos o haber simplificado aún más las cosas. Continuaremos buscando oportunidades de este tipo y, ahora que la mayor parte de esta primera gran limpieza se ha llevado a cabo, podemos impulsar de forma práctica cambios más pequeños que se ajusten a las normas descritas anteriormente.

Si estás buscando una razón por la que antes podías llamar a %SYSTEM.SQL.FreezePlans(1, 3, "MyTable") y ahora se recomienda usar %SYSTEM.SQL.Statement.FreezeRelation("MyTable"), espero que esto te haya sido útil. Si buscabas consejos generales sobre la evolución de la API, espero que al menos esto no te haya parecido una pérdida de tiempo :-) y estaré encantado de escuchar vuestras opiniones sobre cómo lo hicimos y cómo lo haríais vosotros de otra manera. No hay absolutamente ninguna ciencia exacta en lo anterior. Adoptamos un enfoque pragmático, para intentar que las cosas fueran más fáciles de utilizar sin cambiar los métodos por el placer de hacerlo y tratando de economizar en tiempo de desarrollo y pruebas. Esperamos que, con el tiempo, también ahorre tiempo en el aprendizaje y el uso de la API, pero sobre todo, ¡que ahorre el tiempo dedicado a contar las comas!

Comentarios (0)2
Inicie sesión o regístrese para continuar