

Discover more from La Naturaleza del Software
Es complicado diseñar software.
Me encanta pensar en el software y lo que va a hacer. Entender los requisitos y plasmarlos en código.
El problema es cuando manejas muchos paradigmas y sabes cómo hacer las cosas de modo poco convencionales. Lo que funciona genial en un entorno, se vuelve algo complicado en otro.
Hace un tiempo diseñe un servicio y se me ocurrió usar en la implementación un patrón que se usa en Elixir llamado token pattern.
En Elixir tu haces:
output = input
|> phase1()
|> phase2()
|> phase3()
Esto es muy poderoso si quieres modelar un flujo. Pero ¿qué pasa si hay un error entre medio? O sin quieres seguir con phase 2, a pesar de que haya errores en phase 1. Además te gustaría guardar el estado del proceso para reportarlo al final de phase 3.
El patrón token ayuda en eso, porque cada etapa agrega al output el estado de cada procesamiento, y si hay errores los acumula en un atributo del token, el que puede ser usado en estados intermedios, o reportados al final, la idea es no cortar el proceso, y hacerse cargo al final. El código queda limpio, y si hubo errores la variaba output lo refleja en algún atributo (algo así como output.errors).
Quise hacer lo mismo en Go, pero por diversas razones, entre ellas las normas de programación usadas por mi organización, terminé escribiendo algo así:
c := NewTokenPatternLikeStruct(...)
err, out1 := c.phase1(input)
if err != nil {
// tratar el error
}
err, out2 := c.phase2(out1)
if err != nil {
// tratar el error
}
err, out3 := c.phase3(out2)
if err != nil {
// tratar el error
}
if len(c.internal_errors) {
// tratar errores del proceso
}
return c.result, nil
Lo que es horrible. El estado finalmente se debe guardar en una struct, que es la forma de implementar objetos en GO. Y todo esto lleva a una serie de efectos laterales dentro del código, y un montón de etcteras. El resultado es que algo que era fácil de entender en Elixir se vuelve confuso en Go.
El problema es que cuando diseñamos software las herramientas en que plasmaremos ese diseño no son neutras. Un patrón funcional puede ser emulado en teoría en cualquier lenguaje, pero a costa de saltarse convenciones típicas de ese lenguaje. O requiera esfuerzos adicionales para emular el comportamiento.
Así que la lección, al menos para mi, es que en software, el diseño sí debe preocuparse de los detalles de la implementación.
Quizás por eso es que prefiero escribir código, que dibujar cajitas. Y por eso cuando las hacía de arquitecto los ingenieros me odiaban tanto 🤣.
Diseñar vs construir software
Lo que siempre vale la pena diseñar es la interacción entre distintos sistemas. En ese caso el diseño es además una herramienta para ponerse de acuerdo.
Pero para cuestiones internas, casi siempre es más rápido programar directamente. A lo más hacer bosquejos rápidos para orientarse o comunicarse con el equipo.