Errores mal hechos.
No voy a abrir el saco de excepciones, enums de monadas (rust, elm, haskell) vs tuplas (golang, C, python). Lo voy a cerrar rápido:
- excepciones son mala practica siempre, "checked or unchecked", ambas mal joden la stack.
- devuelve un Result<E, T>, un Option<T> o una tupla (resultado, error) o "a la c", como tu lenguaje lo implemente pero usa el stack bien.
Vengo a comentar el mayor error que veo en producción y me encontré de hecho el otro día en AWS. Los errores que no entiende ni su puta madre. Alguno me dirá que hacer buenos mensajes de error es difícil, como también es difícil hacer documentación clara. Difícil no significa que no se pueda hacer ni que existan ideas esenciales que tenemos que seguir.
Error: que, como, quien, donde, porque
Error: que, como, quien, donde, porque
Error: que, como, quien, donde, porque
El error que me tiraba AWS es curioso porque esta MUUUUY mal a todos los niveles:
An error occurred (AccessDeniedException) when calling the SendCommand operation: User: arn:aws:sts::***:assumed-role/github-backend-lxd/GitHubActions is not authorized to perform: ssm:SendCommand on resource: arn:aws:ssm:eu-west-1::document/AWS-RunShellScript because no identity-based policy allows the ssm:SendCommand action
Error: Process completed with exit code 254.
De nuevo, un claro ejemplo de mucho texto, poco contenido. Me gustaría re-escribirlo y decir, esto debería ser así. Pero el problema de diseño es mas grave.
El problema era que al crear la policy para permitir el SSM Y ADEMAS restringir las instancias para el SCRIPT DE ARRANQUE, al hacerlo todo en un statement, estaba asignando restricciones para todas las acciones, para todas las condiciones. Y esto resulta que no es posible, tuve que hacer 1 policy con 2 statements con restricciones separadas. AWS debería fallar en tiempo de crear la policy pero no lo hizo.
Este es el primer error. Código genérico que re-usan para crear todas las policies que después en runtime falla porque hay un "edge-case" que no han validado o se han dejado. Desconozco si tienen checks para todo, para este caso se ve que no. El error debería haber llegado mucho antes al crear la policy diciéndome, "error en crear policy, no puedes asignar esta restricción de recursos a estas acciones porque no se puede asignar el arranque a restricciones de instancias". Que, como, donde, cuando y porque. En el backend se sabe perfectamente porque eso no esta permitido.
Primer error? Los errores que no deberían haber existido. Por tener una validación mal o un código genérico, he creado código que después puede fallar en runtime. Solución? Si no puedes crear algo incorrecto, lo incorrecto nunca fallara.
Segundo error, no responderme a las 5 preguntas. Atentos a la magia:
- error 400
- error 400, crear policy
- error 400, crear policy, "statement invalido"
- error 400, crear policy, no puedes asignar "esta restricción" a "estas acciones"
- error 400, crear policy, no puedes asignar "esta restricción" a "estas acciones", porque "esta restricción" no es compatible con "esta acción".
Y fijaros que este código es modular y autogenerable para cualquier restricción y acción, así que entiendo que AWS se ha fumado ese error que me paso a mi concreto. Dudo que AWS no tenga validaciones o un parseo de sus statements porque a veces me ha dado algún error.
Y el mismo problema lo encontramos en los logs, he visto millones de lineas de logs que no responden a las 5 preguntas. Y los logs son PRIVADOS, en los logs puedes hacer esto:
- %timestamp%, %env%, %service%, %pod%, error 400, %user_Id%, %request_Id%, crear policy, %policy_id%, no puedes asignar "esta restricción" a "estas acciones", porque "esta restricción" no es compatible con "esta acción" %LINEA_DE_CODIGO_VALIDACION%.
Os pongo otro ejemplo tipico:
- error al crear el stack
- request_id error 400, create_stack, al crear el stack en la region region_id
Y seguramente tu codigo sera algo asi:
fun my_super_code_to_create_stack(stack, region_id):
new_stack, error = internal.create_stack(stack, region_id)
if error: log
else: return new_stack
Que puedo logear? En este ejemplo me falta la request_id no? Pues se la pasamos.
fun my_super_code_to_create_stack(request_Id, stack, region_id):
new_stack, error = internal.create_stack(stack, region_id)
if error: log
else: return new_stack
El aprendizaje con estos dos snippets es simple, el código y las funciones no hacen magia, hacen lo que tu les dices con lo que tu les dices, a veces necesitamos variables para métricas o logs, pásalas a la función, no pasa nada tranquilo, tus 5 strings no van a hacer bottleneck Me encuentro en mucho código que la gente se olvida de pasar las cosas abajo el stack para poder loggear. No seas así y pasa las ids que después te salvaran el culo si algo peta.
Conclusión responder a las 5 pregunta siempre. Si es algo interno mete todos los datos que tengas disponibles. Esto es un log, no una métrica. No seas racano.