Sensei Característica destacada: Ámbito de la biblioteca

Publicado el 09 de junio de 2021
por Nick Van Haver
ESTUDIO DE CASO

Sensei Característica destacada: Ámbito de la biblioteca

Publicado el 09 de junio de 2021
por Nick Van Haver
Ver recurso
Ver recurso

Gestionar las dependencias con flexibilidad

La funcionalidad Scope de Sensei siempre ha sido una de las favoritas de los desarrolladores. Con la posibilidad de ampliar o limitar el alcance de la aplicación de una receta, los equipos de desarrollo han podido personalizar su uso para proyectos individuales y verticales dentro de sus organizaciones, lo que permite a los desarrolladores personalizar su experiencia.

Y, como es lógico, está en el centro de los procesos de innovación continua de Sensei. Durante una sesión de brainstorming de innovación sobre la ampliación del "alcance" (sí, un juego de palabras), surgió una pregunta: 

"Estaba intentando crear una receta para ... pero desde la versión x, el framework ha dejado de lado la función. No estoy seguro de que siga siendo útil crear una receta. ¿Qué opinas?"

Por supuesto, no es la primera vez que dudamos en crear una receta. Aunque la receta podría considerarse como una información redundante, creemos que es valioso crear algo que sea aplicable a un número limitado de versiones de la dependencia en cuestión. Y por ello, creamos el ámbito de la Biblioteca.

El alcance de la biblioteca nos permite comprobar si una dependencia está presente en el proyecto y aplicar condicionalmente las recetas de Sensei . Esto proporciona una gran flexibilidad cuando los equipos navegan por el código heredado y las dependencias.

Muchos de ustedes deben conocer el ámbito de la Biblioteca que ya está disponible en la Configuración General. ¿Qué es esto? Hemos habilitado el ámbito de la biblioteca para que esté presente en YAML, al igual que la búsqueda. Esto crea una mejor experiencia para el usuario y no rompe el flujo al crear la receta, que de otra manera tendría que navegar a la Configuración General y volver a actualizar los metadatos. Más de estos ámbitos llegarán a YAML pero hemos empezado con el Ámbito de la Biblioteca.

Así que vamos a profundizar un poco más en su funcionamiento con un ejemplo.

Alcance de la biblioteca aplicado a hibernate-jpamodelgen

Imagina el siguiente caso: 

Queremos crear una API REST de Spring Web que nos permita consultar algunos datos. De acuerdo con las mejores prácticas, creamos un modelo para la entidad que queremos consultar. A continuación, añadimos una dependencia a Hibernate ORM, para no tener que manipular la estructura de la base de datos. El ORM se encarga de eso por nosotros. También necesitamos crear un servicio que proporcione los datos de la capa de acceso a datos (repositorios CRUD y demás) al controlador. Por último, creamos la clase del controlador para nuestra API, donde expondremos las consultas permitidas como endpoints.

Para evitar tener que exponer diferentes endpoints para cada campo que pueda ser consultado, optamos por utilizar las especificaciones de JPA 2. Para ello, creamos una especificación en el controlador a partir de la URL de la petición. Esta especificación describe cómo deben ser las entidades que buscamos. En la propia clase `Specification`, implementamos el método `toPredicate` para indicar cómo se puede validar la especificación.

Pero nos encontramos con un problema en el método `toPredicate`. Para construir el predicado, necesitamos conocer los nombres de las columnas de la base de datos para comparar. Pero como estamos utilizando un ORM, no tenemos estas columnas presentes en un modelo separado. Por lo tanto, el generador de metamodelos de JPA 2 de Hibernate viene al rescate. Esto nos ayudará a generar un metamodelo para las entidades que le hemos pedido que maneje. Estos metamodelos nos permiten referenciar los nombres de las columnas como propiedades en lugar de codificarlos.

Creación de la receta Sensei

Ahora que tenemos los metamodelos generados, queremos darles un buen uso. Sensei puede ayudar a cualquier persona que trabaje en el proyecto recordándole que debe utilizar el metamodelo, asegurándose de que los nombres de las columnas no estén codificados en ninguna parte. Así que vamos a ponerlo en práctica.

Para empezar, echamos un vistazo al método `toPredicate`.

Método To Predicate

Este predicado básico sólo comparará el nombre de nuestra entidad. Podemos ampliarlo utilizando cláusulas `y`, pero para el propósito de esta receta, esta "simple" comprobación será suficiente.

Para el componente de búsqueda de la receta, queremos llamar al método `get()` del parámetro raíz, por lo que seleccionamos la opción `methodcall` del desplegable. A continuación, queremos limitar la búsqueda a una llamada al método con el nombre `get` cuya firma está declarada en la interfaz `Path` del paquete `javax.persistence.criteria`. Como el método ha sido sobrecargado, también necesitamos decirle a la búsqueda que nuestra receta sólo se aplica a la variante que toma una sola cadena como argumento. Para solucionar el problema de tener los nombres de las columnas en el código deberíamos utilizar un argumento de tipo `SingularAttribute` en su lugar, el mismo tipo que proporciona el generador del metamodelo.

Configurar los criterios de búsqueda de la receta

La receta que hemos creado hasta ahora se activará en cualquier base de código que utilice la interfaz `Path` de JPA 2, independientemente de que la base de código esté configurada para utilizar el generador de modelos de Hibernate. Si esta librería está presente en el proyecto, queremos indicar al usuario que debe ser utilizada, por lo que añadimos un ámbito de librería a la receta.

Limitar el alcance de la búsqueda de esta receta

Y finalmente, nuestra receta está lista.

Método de la receta de prueba

Con esta receta, cualquier ocurrencia de `Path#get` que utilice un valor de cadena como argumento será marcada. Como puede ver en el código de ejemplo resaltado en la captura de pantalla anterior, esta receta sigue funcionando cuando el nombre literal del nombre de la columna se almacena en una variable intermedia.

Nota - También podemos invertir el ámbito de la biblioteca para manejar el caso de que la biblioteca no esté disponible, anteponiendo una cláusula `not` al ámbito.

Conclusión:

Como hemos visto en el ejemplo anterior, esta nueva característica nos permite crear recetas más útiles al aplicarlas en función de la presencia de dependencias en el proyecto. Para mejorar aún más su potencia, hemos incluido más opciones de las que se mostraban en el ejemplo, como por ejemplo no sólo comprobar si la dependencia está presente, sino también aplicar condiciones a la versión específica de la dependencia. 

Los principales casos de uso que vemos para esta función son evitar que las recetas proporcionen información duplicada, detectar problemas relacionados con versiones específicas de dependencias, pero también realizar migraciones de una versión de dependencia a la siguiente. Estamos deseando que nos cuentes qué usos ves para esta función.

Como en el caso de todas las funciones de Sensei , en la documentación de referencia encontrará más información sobre el alcance de la biblioteca.

Ver recurso
Ver recurso

Autor

Nick Van Haver

¿Quieres más?

Sumérjase en nuestras últimas ideas sobre codificación segura en el blog.

Nuestra amplia biblioteca de recursos tiene como objetivo potenciar el enfoque humano de la mejora de la codificación segura.

Ver blog
¿Quieres más?

Obtenga las últimas investigaciones sobre la seguridad impulsada por los desarrolladores

Nuestra amplia biblioteca de recursos está repleta de recursos útiles, desde libros blancos hasta seminarios web, que le ayudarán a iniciarse en la codificación segura orientada a los desarrolladores. Explórela ahora.

Centro de recursos

Sensei Característica destacada: Ámbito de la biblioteca

Publicado el 09 de junio de 2021
Por Nick Van Haver

Gestionar las dependencias con flexibilidad

La funcionalidad Scope de Sensei siempre ha sido una de las favoritas de los desarrolladores. Con la posibilidad de ampliar o limitar el alcance de la aplicación de una receta, los equipos de desarrollo han podido personalizar su uso para proyectos individuales y verticales dentro de sus organizaciones, lo que permite a los desarrolladores personalizar su experiencia.

Y, como es lógico, está en el centro de los procesos de innovación continua de Sensei. Durante una sesión de brainstorming de innovación sobre la ampliación del "alcance" (sí, un juego de palabras), surgió una pregunta: 

"Estaba intentando crear una receta para ... pero desde la versión x, el framework ha dejado de lado la función. No estoy seguro de que siga siendo útil crear una receta. ¿Qué opinas?"

Por supuesto, no es la primera vez que dudamos en crear una receta. Aunque la receta podría considerarse como una información redundante, creemos que es valioso crear algo que sea aplicable a un número limitado de versiones de la dependencia en cuestión. Y por ello, creamos el ámbito de la Biblioteca.

El alcance de la biblioteca nos permite comprobar si una dependencia está presente en el proyecto y aplicar condicionalmente las recetas de Sensei . Esto proporciona una gran flexibilidad cuando los equipos navegan por el código heredado y las dependencias.

Muchos de ustedes deben conocer el ámbito de la Biblioteca que ya está disponible en la Configuración General. ¿Qué es esto? Hemos habilitado el ámbito de la biblioteca para que esté presente en YAML, al igual que la búsqueda. Esto crea una mejor experiencia para el usuario y no rompe el flujo al crear la receta, que de otra manera tendría que navegar a la Configuración General y volver a actualizar los metadatos. Más de estos ámbitos llegarán a YAML pero hemos empezado con el Ámbito de la Biblioteca.

Así que vamos a profundizar un poco más en su funcionamiento con un ejemplo.

Alcance de la biblioteca aplicado a hibernate-jpamodelgen

Imagina el siguiente caso: 

Queremos crear una API REST de Spring Web que nos permita consultar algunos datos. De acuerdo con las mejores prácticas, creamos un modelo para la entidad que queremos consultar. A continuación, añadimos una dependencia a Hibernate ORM, para no tener que manipular la estructura de la base de datos. El ORM se encarga de eso por nosotros. También necesitamos crear un servicio que proporcione los datos de la capa de acceso a datos (repositorios CRUD y demás) al controlador. Por último, creamos la clase del controlador para nuestra API, donde expondremos las consultas permitidas como endpoints.

Para evitar tener que exponer diferentes endpoints para cada campo que pueda ser consultado, optamos por utilizar las especificaciones de JPA 2. Para ello, creamos una especificación en el controlador a partir de la URL de la petición. Esta especificación describe cómo deben ser las entidades que buscamos. En la propia clase `Specification`, implementamos el método `toPredicate` para indicar cómo se puede validar la especificación.

Pero nos encontramos con un problema en el método `toPredicate`. Para construir el predicado, necesitamos conocer los nombres de las columnas de la base de datos para comparar. Pero como estamos utilizando un ORM, no tenemos estas columnas presentes en un modelo separado. Por lo tanto, el generador de metamodelos de JPA 2 de Hibernate viene al rescate. Esto nos ayudará a generar un metamodelo para las entidades que le hemos pedido que maneje. Estos metamodelos nos permiten referenciar los nombres de las columnas como propiedades en lugar de codificarlos.

Creación de la receta Sensei

Ahora que tenemos los metamodelos generados, queremos darles un buen uso. Sensei puede ayudar a cualquier persona que trabaje en el proyecto recordándole que debe utilizar el metamodelo, asegurándose de que los nombres de las columnas no estén codificados en ninguna parte. Así que vamos a ponerlo en práctica.

Para empezar, echamos un vistazo al método `toPredicate`.

Método To Predicate

Este predicado básico sólo comparará el nombre de nuestra entidad. Podemos ampliarlo utilizando cláusulas `y`, pero para el propósito de esta receta, esta "simple" comprobación será suficiente.

Para el componente de búsqueda de la receta, queremos llamar al método `get()` del parámetro raíz, por lo que seleccionamos la opción `methodcall` del desplegable. A continuación, queremos limitar la búsqueda a una llamada al método con el nombre `get` cuya firma está declarada en la interfaz `Path` del paquete `javax.persistence.criteria`. Como el método ha sido sobrecargado, también necesitamos decirle a la búsqueda que nuestra receta sólo se aplica a la variante que toma una sola cadena como argumento. Para solucionar el problema de tener los nombres de las columnas en el código deberíamos utilizar un argumento de tipo `SingularAttribute` en su lugar, el mismo tipo que proporciona el generador del metamodelo.

Configurar los criterios de búsqueda de la receta

La receta que hemos creado hasta ahora se activará en cualquier base de código que utilice la interfaz `Path` de JPA 2, independientemente de que la base de código esté configurada para utilizar el generador de modelos de Hibernate. Si esta librería está presente en el proyecto, queremos indicar al usuario que debe ser utilizada, por lo que añadimos un ámbito de librería a la receta.

Limitar el alcance de la búsqueda de esta receta

Y finalmente, nuestra receta está lista.

Método de la receta de prueba

Con esta receta, cualquier ocurrencia de `Path#get` que utilice un valor de cadena como argumento será marcada. Como puede ver en el código de ejemplo resaltado en la captura de pantalla anterior, esta receta sigue funcionando cuando el nombre literal del nombre de la columna se almacena en una variable intermedia.

Nota - También podemos invertir el ámbito de la biblioteca para manejar el caso de que la biblioteca no esté disponible, anteponiendo una cláusula `not` al ámbito.

Conclusión:

Como hemos visto en el ejemplo anterior, esta nueva característica nos permite crear recetas más útiles al aplicarlas en función de la presencia de dependencias en el proyecto. Para mejorar aún más su potencia, hemos incluido más opciones de las que se mostraban en el ejemplo, como por ejemplo no sólo comprobar si la dependencia está presente, sino también aplicar condiciones a la versión específica de la dependencia. 

Los principales casos de uso que vemos para esta función son evitar que las recetas proporcionen información duplicada, detectar problemas relacionados con versiones específicas de dependencias, pero también realizar migraciones de una versión de dependencia a la siguiente. Estamos deseando que nos cuentes qué usos ves para esta función.

Como en el caso de todas las funciones de Sensei , en la documentación de referencia encontrará más información sobre el alcance de la biblioteca.

Nos gustaría contar con su permiso para enviarle información sobre nuestros productos y/o temas relacionados con la codificación segura. Siempre trataremos sus datos personales con el máximo cuidado y nunca los venderemos a otras empresas con fines de marketing.

Para enviar el formulario, habilite las cookies "Analytics". Siéntase libre de desactivarlas de nuevo una vez que haya terminado.