Blog ·
Un acceso directo es una referencia, no un derecho
Seis tarjetas para el panel de inicio y accesos directos que solo se muestran si quien mira aún puede ver el destino hoy. Dos hallazgos de una prueba real.
Por Provibr
El panel de inicio de un panel de alojamiento es la pantalla que todo el mundo ve primero y sobre la que casi nadie tiene una opinión hasta que le queda mal. La petición era modesta: que la gente pueda añadir tarjetas, y que pueda colocar accesos directos a un servidor o a una integración a los que vuelve una y otra vez.
Las peticiones modestas son donde se esconden las decisiones interesantes, porque un acceso directo es una preferencia guardada que apunta a un objeto real con permisos reales. Torcer esa relación es la manera de que un panel acabe enseñando a alguien una máquina de la que lo apartaron hace tres meses.
Seis tarjetas, ninguna migración, y nada llega sin pedirlo
Hay seis tarjetas añadibles: una lista de agentes, una lista de servidores, una lista de integraciones, una lista de tiques, el saldo y un acceso directo. Las seis son de media anchura, porque son resúmenes uno al lado del otro y no algo que necesite la fila entera.
La disposición se guarda como JSON, y esta ronda no añadió ninguna migración. Es una decisión y no un olvido. Una entrada era un identificador y un indicador de oculta; ahora lleva además un identificador de instancia y una configuración por tarjeta. Una fila antigua se lee limpiamente en la forma nueva, con el identificador de instancia completado a partir del de la tarjeta y la configuración vacía, y una prueba comprueba justo eso: una disposición antigua se lee como las mismas tarjetas en el mismo orden. Aquí una migración solo pondría una marca de tiempo en el diario, y una marca de tiempo que después resulta demasiado alta es un problema de verdad para la ronda siguiente.
La segunda regla es que una tarjeta opcional nunca aparece sola. Hay un bucle que añade las tarjetas que una disposición no menciona, para que una tarjeta fija nueva aparezca en todas partes, y ese bucle cubre a propósito solo las fijas. Si una opcional participara, «añadir» dejaría de ser una acción y cada panel de inicio del producto crecería en cada publicación con una tarjeta que nadie pidió.
Qué tarjetas faltan es tan decisión como cuáles están. La supervisión y las copias de seguridad existen en el código tras banderas de despliegue apagadas, así que una tarjeta para ellas sería una tarjeta sin usuarios. La actividad reciente se quedó fuera porque ya existe como tarjeta fija.
Dos mitades de una regla
En la disposición guardada de una persona, un acceso directo no es más que una clase y un identificador. Todo lo que llega a la pantalla, el nombre, el estado, el enlace, se vuelve a obtener en cada carga con los permisos de quien mira en ese momento. Esa regla tiene dos mitades y las dos hacen falta.
La primera es el módulo. Un miembro que pierde el módulo de agentes deja de ver su acceso directo a un agente, aunque siga en su disposición. Esta puerta conoce además las superficies, así que en el dominio de marca propio de un cliente, donde la facturación no existe siquiera, el acceso directo al saldo desaparece por construcción y no por una segunda regla escrita a propósito.
La segunda es la consulta del objeto. El identificador de organización está en cada WHERE, el filtro de borrado suave al lado, y en un servidor el alcance de servidores de ese miembro al lado de eso. Un servidor nunca asignado a un miembro no existe para ese miembro, y eso tiene que valer también para un acceso directo que creó cuando todavía podía verlo.
La tarjeta de acceso directo es además la única sin módulo y la única que puede existir más de una vez. Es correcto y no descuidado: un acceso directo no es una pantalla propia, es una referencia a una pantalla que ya lleva su propio derecho. Si la clase de tarjeta llevara un módulo, alguien con ese módulo podría ver un acceso directo a algo que no puede abrir.
Módulo perdido y objeto perdido son sucesos distintos
Dos cosas que en pantalla se ven iguales reciben tratos opuestos.
| Qué ocurrió | Qué ve quien mira |
|---|---|
| Se retiró el módulo | La tarjeta desaparece sin una palabra, y vuelve con el módulo |
| No se encontró el destino | Una tarjeta que dice que ya no existe, con un botón para quitarla |
Lo primero es silencioso porque el acceso directo no es la historia. Si cambió el papel de alguien, el acceso directo ausente es un síntoma, y anunciarlo en el panel de inicio sería ruido encima de un cambio que ya conoce. Además vuelve intacto en cuanto vuelve el módulo, y eso solo es posible porque no se borró nada.
Lo segundo es ruidoso porque quien lo usa no hizo nada mal y le quitaron algo. A propósito no es un 404 ni un mensaje de error: solo una tarjeta que nombra la situación y ofrece limpiarse sola.
Mostrar con tolerancia, no limpiar al borrar
La alternativa evidente es quitar los accesos directos cuando se borra su destino. No lo hicimos, y el razonamiento merece anotarse porque la decisión contraria sí se tomó en otro punto de la misma base de código: cuando un miembro abandona una cuenta, su disposición guardada se olvida de verdad, porque esa fila no toca ninguna cascada y si no se quedaría para siempre en una cuenta a la que nunca vuelve.
Aquí la balanza cae del otro lado, por tres motivos.
Desaparecer tiene más causas que borrar. Un miembro pierde un módulo, cambia su alcance de servidores, mira en un dominio de marca. Ninguna rutina de limpieza atrapa esas tres, así que la vía tolerante tiene que existir igualmente, y un segundo mecanismo pasa a ser solo un sitio que puede desfasarse.
La disposición se guarda por persona. Un servidor borrado obligaría a reescribir el JSON de cada miembro de la organización, dentro de una transacción en la vía de borrado. Eso es amplificación de escritura en una vía caliente a cambio de una preferencia de pantalla.
Y no hay nada que proteger. La fila guardada es un UUID de un objeto de la propia organización y nada más. No filtra nada, no crece, y quien la tiene ve enseguida que puede irse.
La prueba de extremo a extremo es tosca a propósito. Después de un borrado suave, el servidor no vuelve, y su nombre no aparece en ningún punto de la salida. Un miembro sin el módulo de agentes no obtiene ni agente ni integración, y el selector no se los ofrece. Un alcance de servidores vacío da cero filas y no todo.
Dos hallazgos que solo dio una prueba real
Los dos defectos reales de esta ronda eran invisibles para las pruebas unitarias, y los dos costaron unos diez segundos en cuanto hubo algo real en marcha.
El selector tiene un campo de búsqueda, y buscar integraciones rompía el selector entero con un error de base de datos. El motivo es que la columna del tipo de integración es un tipo enumerado de Postgres, y para un enumerado no existe operador de patrón que ignore mayúsculas: la consulta devolvió 42883 operator does not exist, y como esa consulta alimentaba todo el selector no se mostraba absolutamente nada. Convertir la columna a texto lo arregla. Ninguna prueba unitaria con un ejecutor simulado lo habría visto, porque una simulación no tiene tipos.
El segundo salió del barrido de accesibilidad. Una baldosa de acceso directo es un nombre, un estado y una clase, y el conjunto se puede pulsar. La primera versión metía todo eso en un mismo enlace, y la auditoría señaló una diferencia entre el nombre accesible y la etiqueta visible, porque el texto oculto cuenta para el nombre accesible. La baldosa es ahora un contenedor corriente con un enlace que lleva solo el nombre y una superficie de pulsación absoluta y vacía que recoge el clic. Eso trajo un segundo problema menor: la clase de recorte sobre el enlace recortaba esa superficie a la anchura del texto, con lo que la mayor parte de la baldosa dejó de poder pulsarse. El recorte se mudó a un elemento interior y la cobertura se midió en vez de suponerse.
Lo que anotaríamos
- Guarde una referencia, resuelva un derecho. En la preferencia va un identificador. Lo que llega a la pantalla se obtiene cada vez con los permisos de quien mira.
- Una columna sin esquema es una migración que no hace falta escribir. Pero solo si puede demostrar que la forma antigua se relee idéntica, y eso es una prueba.
- Opcional significa a petición, para siempre. Una tarjeta que aparece sola convierte «añadir» en una palabra sin sentido.
- Distinga borrado de inalcanzable. En pantalla se ven igual y merecen el trato contrario: silencio para uno, una explicación para el otro.
- No limpiar puede ser la elección más fuerte. Si el mismo síntoma tiene causas que su limpieza no ve, la vía tolerante debe existir igualmente, y la limpieza pasa a ser solo una segunda cosa que mantener a la par.
- Ponga la cosa en marcha. Un enumerado sin operador de patrón y un enlace que recorta su propia zona de pulsación se ven al instante en un navegador y no se ven en absoluto en una batería de pruebas sin base de datos.
Para que quede claro qué es esto: las tarjetas descritas aquí están en producción para toda cuenta. Varias cosas no están probadas. La reordenación con el ratón no se accionó, las tarjetas de supervisión y copias de seguridad tras bandera no existen, así que su vía de código no se recorrió nunca, el dominio de marca se revisó en una consulta y no en un navegador, y una tarjeta recién añadida solo aparece tras la ronda siguiente del servidor.
Del trabajo de plataforma de Provibr. Qué ve y qué no ve un cliente de nuestro cliente en un panel de marca está en paneles de marca blanca: lo que ve el cliente, y por qué una pantalla de resumen nunca reescribe en las tablas que lee está en proyectar, nunca sustituir.