HirenixProceso de desarrollo y estudio de caso
Motivo
La idea surgió en una Hackaton con Infojobs (Portal de bolsa de trabajo), el concepto era simple pero poderoso. Tenías que crear un producto que estuviera relacionado con Infojobs y que utilizara su API. Sus endpoints te ofrecían tanto consultas a las últimas ofertas de trabajo publicadas, como acceso a información del usuario autenticado (con 0auth).
Objetivos
- Obtener un puntaje de compatibilidad
- Entrevistas simuladas
- Pruebas técnicas
- Autenticación por 0auth
- Descubrir puesto
- Búsqueda sin opciones
Enlaces
Requisitos, limitaciones y obstáculos
- Desarrollar un producto que se relacionara con Infojobs
- 15 días de límite de entrega
- La autenticación solo funcionaba en producción
- Documentación de los endpoints desactualizada
- Tiempo límite de respuesta de Vercel de 60 segundos (ChatGPT en ocasiones tardaba más)
- Políticas CORS solo permitían peticiones desde el backend.
Herramientas Usadas
Diseño
Cuando empezó la hackaton, lo primero que decidí fue que la estética sería futurista, y las principales características estarían relacionadas con IA, pasé horas y horas buscando inspiración en páginas como Behance o Dribbble sin llegar a nada.
Antes de empezar a desarrollarla, preferí primero diseñarla en Figma, esto me ayudó a separar en fases cada proceso, delimitar responsabilidades y dedicarle el tiempo necesario a cada uno.
Después de establecer los objetivos, tenía más claro lo qué quería incluir en la Interfaz de usuario; imágenes generadas por inteligencia artificial. Junto con el concepto futurista, empecé a buscar imágenes en Lexica del tipo Matrix, di con la siguiente.
Color perfecto, nitidez, futurista, era lo que buscaba, así que este fue el punto de partida en el cual giraría toda la estética de la página.
Fuente
La elección de la fuente después de entender el concepto que quería transmitir fue bastante fácil, quería algo futurista o por lo menos moderno, pero sin comprometer la legibilidad. “Be Vietnam Pro” fue una buena elección.
Colores
En cuanto a los colores, la imagen que elegí me los entregó, así que solo tenía que saber contrastarlos y utilizarlos en proporción adecuada.
Al día siguiente ya tenía la sección principal de la landing page, agregué accesos directos en la parte inferior izquierda para que fuera más fácil para los usuarios buscar según el tipo de empleo. También adecué la imagen al fondo y para que los usuarios pudieran ver rápidamente cuál era la intención de la página, agregué ofertas de trabajo.
En lo demás todo es bastante tradicional, el texto principal tiene remarcadas las palabras en las que quiero enfatizar con otro color, la navegación sigue la tendencia con forma de píldora y se queda en la parte superior al hacer scroll.
Nombre y Logo
Cuando estaba buscando nombres, quería alguno que contuviera, ya sea, “jobs”, “hire” o “position”, naturalmente, Hirenix le agrega ese toque futurista, así que me quedé con ese, y debido al parecido de “Hirenix” con “Hexagono”, me basé en esto para hacer el logo.
Una vez que tenía la sección principal lista, las secciones adicionales fueron más fluidas porque ya estaba establecido el concepto que quería transmitir, así que seguí agregando imágenes creadas por AI que tuvieran un toque futurista, finalmente agregué la información restante y terminé las secciones adicionales de la Landing Page.
Sección Explorar
Aún tenía que diseñar la parte funcional de la aplicación, así que decidí hacerla lo más minimalista posible sin comprometer la estética. Llevaba días interesado en hacer algo como lo que hace gmail, sobre separar el contenido principal de las utilidades del usuario y hacer que sobresalga.
La sección “explorar” tiene como objetivo mostrarte aquellas opciones que te ofrece la aplicación para encontrar empleo, como la búsqueda por descripción del empleo y todas las demás características establecidas en objetivos, incluso mostrarte algunas ofertas de trabajo con las que puedes interactuar.
La información del usuario se queda a la izquierda, sería el equivalente a las categorías de correos de Gmail, ahí agregué un campo de búsqueda, para poder buscar con un prompt (por descripción) o por hacer una búsqueda normal, esto con la intención de que en cualquier página, puedas rápidamente buscar el empleo que estés buscando.
Oferta Individual
Teniendo la base de la sección explorar, continué agregando el diseño de las páginas que faltaban, como la oferta individual, en la cual quería ofrecerle al usuario todas las acciones posibles directamente en la oferta.
Esto era sumamente importante para que la interacción del usuario con las características fuera fluido, y no tuviera que navegar entre páginas para usarlas.
Laboratorio
Agrupé las entrevistas simuladas y las pruebas técnicas en esta página, y como los perfiles técnicos suelen ser específicos, añadí opciones con los principales perfiles técnicos del área de la tecnología, estos perfiles fueron seleccionados a partir de la encuesta de desarrolladores de Stack Overflow 2022.
Aquí tomé una decisión de diseño crucial, en la que iré más a detalle en la parte de desarrollo, pero fue el hecho de reutilizar la barra de búsqueda, esta decisión logró que la velocidad de desarrollo y también la del diseño fuera mucho más rápida.
Zona de entrevista
Aunque no todos los usuarios llegan hasta este punto de la aplicación, me apegué a la idea de ofrecerles la mejor experiencia posible. La barra verde que incluye el número de preguntas ayuda a los usuarios a navegar entre las preguntas de la entrevista, si consideran que hay una mejor respuesta, pueden retroceder, o avanzar si quieren dejar una pregunta hasta el final, simplemente haciendo clic al punto de la entrevista al que quieren ir.
Mantuve la vista de los usuarios lo más esencialista posible, solo aquella información directamente relacionada con la entrevista debería estar en esta parte de la aplicación, ¿por qué?, quería encapsular la atención del usuario, ya que estaba simulando una entrevista, no quería que sintieran que estaban rellenando una encuesta o un formulario.
Desarrollo
En este punto ya sabía los objetivos de la aplicación, el concepto, tenía el diseño y solo faltaba traducirlo al código. Sabía que necesitaría una ruta dinámica para cada oferta, también que tendría algunas rutas estáticas, y que sería útil tener estados que perduraran entre navegaciones, empecé a contemplar meta-frameworks como Remix, Next.js o Astro. Next.js fue la mejor opción, tanto por el Server Side Rendering como por los React Server Components, además algo que no había contemplado, es que tendría que utilizar parámetros de consulta para la búsqueda y todo esto ya lo tiene incluido Next.js.
Cuando empecé a desarrollar la aplicación, recién había salido el nuevo App Router de Next.js (la versión 13), hasta ese punto yo solo había desarrollado con el Page Router (versión 12), así que decidí adentrarme en la nueva versión y aprender los React Server Components. Al principio fue un reto, ya que el modelo mental que necesitas para entender los RSC es bastante diferente de lo que habíamos tenido hasta ahora en React y en mi opinión también en el Front end.
Estrategia y estructura
Tenía que ser rápido, lograrlo con una arquitectura limpia y sin comprometer las buenas prácticas, opté por una arquitectura tradicional, basada en la organización de carpetas. Cada carpeta tiene su propia responsabilidad (componentes, utilidades, constantes, servicios, estilos, etc.). Y dentro de esas carpetas se encuentran todos los archivos relacionados con ese contexto.
Debía priorizar las estructuras de datos con la información necesaria que se repetiría en diferentes puntos de la aplicación y separarlas de la lógica de renderizado, de esta forma si quería cambiar un mensaje, una descripción o el texto de un botón que se repetía en diferentes lados, solo lo hacía desde esta estructura.
Este ha sido uno de los proyectos más grandes que he realizado, con más de 55 componentes la organización de estos se complica, así que cuando me di cuenta lo difícil que estaba volviéndose mantenerlos, decidí agruparlos por características, quedando la siguiente estructura.
En cuanto a los estilos, me decanté por módulos de CSS, que ya vienen incluidos en Next.js y evitan que tenga que pensar sobre nombres de clases.
La ubicación de todo lo demás, como las imágenes, fuentes o iconos, los administra Next.js, ya sea en su carpeta /public, o lo hace internamente.
Página de Búsqueda
Cuando empecé a hacer la página “explorar”, el primer reto fue crear la página de búsqueda, tanto para hacer que funcionara los accesos directos de la landing page, como la siguiente sección:
De una vez aproveché para hacer que todas las barras de búsqueda funcionaran. Aquí es donde se presenta una de las principales decisiones de diseño que tomé, la búsqueda podía hacerla por parámetros de consulta y el tipo de empleo simplemente era un filtro, así que, gracias a que la API proveída de Infojobs permitía filtros con parámetros de consulta hacer las consultas por tipo de empleo fue simple:
JobsGrid.jsx
const jobs = [
{
name: 'Desarrollo',
icon: <DeveloperIcon />
},
{
name: 'Diseño',
icon: <DesignerIcon />
},
*/ ...otros empleos */
]
const JobsGrid = () => {
return jobs.map(({ icon, name }) => (
<Link
key={name}
href={`/search?q=${name}`}
>
{icon}
{name}
</Link>
))
}
Como se puede observar, el link está enlazado a una ruta “search”, que es la encargada de gestionar los parámetros de consulta y hacer el fetch de los datos en el lado del servidor (ya que estamos usando React Server Components).
Pero, como los datos se obtienen de forma asíncrona, utilizamos el componente Suspense para mostrar un fallback (en este caso un esqueleto similar a la estructura del HTML) en lo que se hace la petición. Esto le indica al usuario que hay contenido cargando y así evitamos el Cumulative Shift Layout (CLS) lo que le entrega una mejor experiencia al usuario.
Una vez que tenemos la capacidad de leer los parámetros en la página de búsqueda, podemos agregar filtros.
Cada cambio en un filtro navegará a la nueva URL construida con los nuevos parámetros de consulta, se procesan con el componente del servidor y se retornan las ofertas obtenidas que coincide con la consulta.
Busqueda con Inteligencia Artificial
Hasta este punto ya todas nuestras barras de búsqueda funcionaban porque simplemente se convertía lo escrito en el input a parámetros de consulta insertados en la URL. Pero faltaba algo sumamente importante, la búsqueda de inteligencia artificial, para ser más claro, la idea era que si un usuario escribía algo como:
Estoy buscando empleo como Licenciado en Derecho con dos años de experiencia trabando para una inmobiliaria, me gustaría seguir en la misma industria y que el trabajo esté en Tampico.
ChatGPT debería devolver un objeto parecido a:
{
"industry": "Sector Inmobiliario",
"experience": "2",
"role": "Servicios Legales",
"city": "Tampico"
}
Y programáticamente convertirlo a:
https://hirenix.com/search
?q=Servicios+Legales
&industry=Sector+Inmobiliario
&experience=2
&city="Tampico"
Esto funcionó perfectamente, y no tuve problemas de la parte programática, aunque pasé tiempo mejorando el prompt de ChatGPT porque algunas respuestas eran inconsistentes.
Descubre tu puesto
Antes de poder calcular la compatibilidad entre un puesto y un perfil, necesitaba obtener el perfil del usuario, tenía dos opciones:
- Obtener la información del perfil directamente de la cuenta del usuario de Infojobs, a través de este método podía obtener lo siguiente:
- Aplicaciones a puestos anteriores
- Área de interés laboral
- Años de experiencia
- Nivel Educativo
- Pedirle al usuario que contestara una breve encuesta para determinar todo lo anterior.
Desde el punto de vista de la experiencia de usuario, hubiera sido mucho mejor la opción número uno. El usuario solo tendría que iniciar sesión y automáticamente obtendríamos la información de su perfil. Desde el punto de vista técnico hubiera sido más tardado escribir el código que hiciera eso, y como la fecha límite de entrega se estaba acercando, decidí la segunda opción.
Reutilicé el diseño de las entrevistas simuladas y lo adapté para descubrir el puesto, una vez que el usuario finalice las preguntas, ChatGPT se encarga de analizar la información proveída y devuelve un objeto con toda la información ordenada, luego, la guardamos en el navegador del usuario (con localStorage).
Puntaje de Compatibilidad con IA
Con la información del perfil del usuario y un pequeño botón verde en la parte superior derecha de cada oferta, tienes la opción de obtener tu compatibilidad según tu perfil, la comparación se hace a través de ChatGPT y te devuelve un puntaje de compatibilidad del 1-100.
Tiene una pequeña animación que te hace esperar por la respuesta del servidor, cuando llega la respuesta, te muestra el puntaje y puedes hacer hover para ver algunas razones del porqué del puntaje. Las animaciones están enfocadas en la usabilidad de esta aplicación y no en la estética, la transición entre - El signo de interrogación - El spinner de carga - El puntaje, son muy naturales, y no hacen sobrecargan al usuario de información sobre lo que está pasando.
Entrevistas Simuladas y Pruebas técnicas
Uno de los principales dolores de cabeza al desarrollar la aplicación, fue lo lento que es ChatGPT, aun en su modelo 3.5 que se autodenomina rápido, había respuestas que tardaban más de 1 minuto, en desarrollo todo iba genial (sin referirme a las inconsistencias de las respuestas), pero una vez que desplegué la aplicación, Vercel tiene un tiempo límite de respuesta de 10s para las cuentas gratuitas, si quieres una extensión de tiempo, solo podrías lograrlo a través de tu propio backend, o pagar el plan “Pro” para tener hasta un minuto de respuesta. Con suerte no había utilizado este plan antes, y me dieron 14 días gratis para probarlo, suficiente para la hackaton, pero aun así, había veces que las peticiones tardaban más de un minuto.
Como ya tenía la página “Descubrir” desarrollada y tenían básicamente la misma funcionalidad, la reutilice y todo se acopló bastante fácil. Una cosa que agregué fue que al finalizar una entrevista o prueba técnicas, ChatGPT hace una revisión de esta, y te ofrece retroalimentación sobre mejores respuestas a cada pregunta, también te indica qué temas deberías repasar o estudiar.
Como la respuesta de ChatGPT tarda mucho, agregué un “Empty State” con un sticker de infojobs y cosas interesantes sobre el mundo laboral, por ejemplo:
Los estados vacíos mantienen la atención del usuario y evitan que abandonen el proceso mientras la información necesaria aún no llega.
Conclusiones
Hagamos una rápida comprobación de los objetivos que se cumplieron y de los que no.
- ✅ Obtener un puntaje de compatibilidad
- ✅ Entrevistas simuladas
- ✅ Pruebas técnicas
- ✅ Autenticación por 0auth
- ✅ Descubrir puesto
- ✅ Búsqueda sin opciones
En cuanto a la estrategia y buenas prácticas:
- ✅ Arquitectura limpia
- ❌ Componetizar lo suficiente
- ❌ Separar la lógica de los componentes
Lo que aprendí
Conforme se acercaba el tiempo de entrega me di cuenta de que no iba a terminar, así que en la recta final comencé a usar valores hardcodeados, no componetizar lo suficiente y no separar la lógica de los componentes. Esto es algo de lo que no estoy orgulloso de este proyecto, cuando tenía la visión de lo que quería construir, sabía que quería hacerlo de la mejor forma posible, tanto en buenas prácticas como en funcionalidad, y hasta la mitad del proyecto había respetado esos puntos, pero el tiempo y una mala gestión del mismo, me llevó a dejar de hacerlo.
Intentar abarcar mucho en muy poco tiempo, va a causar o que la calidad de cada característica no sea la mejor, o que directamente no agregues todas las funcionalidades que esperabas.
Mientras construía el proyecto, iba agregando nuevas características que no había contemplado en la fase de diseño, en retrospectiva, fue un error. Cuando tienes una idea y no tienes claro ni su alcance ni sus limitaciones, probablemente algo saldrá mal, y cuando el tiempo es un factor determinante en el éxito de un desarrollo, quieres evitar los inconvenientes lo máximo posible.
Qué pude hacer mejor
- Ser realista con el tiempo: Tenía que estudiar la nueva versión de Next.js, aprender sobre los RSC, diseñar, desarrollar, planear y mejorar los prompts de ChatGPT en solo 15 días, fue muy entusiasta de mi parte (por no decir imprudente).
- Dar prioridad a menos características
- Diseño Responsive: Pase tanto tiempo en la parte de diseño y creando características que me olvidé de partes fundamentales como la accesibilidad y el diseño responsivo.
- Debí relacionarme con la nueva versión de Next.js y haberla estudiado antes.
Futuro del proyecto
Aprendí y me divertí muchísimo haciendo este proyecto, aunque creo en las soluciones que ofrece, prefiero dejarlo como lo entregué a la hackaton y quedarme con lo aprendido. Así que no recibirá ninguna actualización en el futuro.
Parece ser que infojobs nos quitó acceso a su API a todos los participantes de la hackaton, por lo que si presentas algún error navegando en la aplicación, te ofrezco una disculpa y te invito a que veas las imágenes que guardé y que están arriba en este mismo artículo.
¡Gracias por leer!