Comunidad y proyectos de código abierto

Participar en un proyecto de código abierto es similar a cuando empezamos en un nuevo empleo o debemos trabajar en algún viejo software de la organización: Un montón de código que alguien más escribió; sabemos que hace algo pero no el cómo; los requerimientos (issues, bugs) pueden o no ser claros; etc. Por encima de todos los tecnicismos (ver las pruebas, la documentación, el código, debug, etc.) acudimos a la interacción con el otro: ¿Venga, usted sabe qué hace este servicio? Este dialogo puede verse afectado por las dinámicas y las herramientas que se emplean terminando así en la frustración y deserción de nuevos ayudantes en el proyecto.

Hace unos días que empecé como aprendiz en el programa de mentores de F#  para contribuir en proyectos de código abierto. Una iniciativa bastante interesante y una experiencia positiva para maestros y principiantes, creo. Alan, mi mentor, y quien ya ha escrito sobre este proceso pensó que lo mejor sería programar en pareja: una llamada y compartir pantallas. Lo que considero una estrategia acertada para ayudar a los contribuidores novatos a involucrarse y mantenerse motivados en estos proyectos con un plus de red social y construcción de comunidad. Alguien que ya conoce algo sobre el proyecto en particular, y sobre las dinámicas y herramientas usadas en general puede orientar a los interesados no a manera de tutorial en blog, video o webcast sino como un dialogo de saberes más personal y constructivo que leer los comentarios y ver el avatar del otro.

Participar de procesos como este y con estrategias como esta son enriquecedoras en varios aspectos, en mi caso particular, por ejemplo, darme cuenta de lo oxidado que está mi inglés conversacional, no lo practico mucho y creo que puede convertirse en un dolor de cabeza. La barrera del idioma hace más grande la timidez y aunque la combata con brownies cósmicos al postre la conversación no va igual. Pero esto no debe ser visto como un problema sino una oportunidad para mejorar, somos personas con intereses en común en un proceso comunitario en el que los obstáculos solo pueden terminar empoderando a los individuos.

En mi opinión, participar en proyectos de código abierto es más que escribir código y hacer pull requests, es una construcción comunitaria en la que, además de hacer un producto de software, se crea comunidad: individuos e interacciones.

Anuncios
Comunidad y proyectos de código abierto

Operaciones con conjuntos y tipos de datos algebraicos

En algún momento de su desarrollo el sujeto empieza a agrupar elementos que tienen características en común, tal vez ocurre en el instante mismo en que es enfrentado al orden de lo simbólico, al lenguaje: “La vaca hace muuu”. Este ejercicio de clasificación nos permite describir la realidad, así sabemos, por ejemplo, de los perros y los gatos; y los animales; y los vertebrados. Mas tarde, en alguna clase de matemáticas, se pintan figuritas entre círculos y se explican algunas reglas para realizar las asociaciones que usamos en nuestro lenguaje natural: de la intersección entre las plantas y los alimentos obtenemos las verduras (?).

Algunos lenguajes de programación tienen un tipo de dato compuesto muy versátil que permite crear nuevos tipos combinando otros. Cuando hablamos de estos tipos nos referimos, así como en los conjuntos, a todos los posibles elementos que agrupamos bajo una etiqueta. Los tipos pueden ser combinados con otros haciendo uso de las operaciones de unión y producto cartesiano, así nos encontramos con los union types y los product types respectivamente.

La unión establece que “Un elemento x pertenece a la unión de los conjuntos A y B si, y sólo si, x pertenece al conjunto A o (∨) x pertenece al conjunto B”. Para crear tipos usando la operación de unión, es decir, los union types, cambiaremos el O por el símbolo |, al menos en haskell y f#. Tomemos el ejemplo que encontramos en la wikipedia: La unión de personas que juegan al fútbol y de personas que juegan al baloncesto serían las personas que juegan a fútbol o baloncesto.

data JueganFutbolOBaloncesto = Futbol Persona | Baloncesto Persona

Los conjuntos de las personas que juegan fútbol y el de los que juegan baloncesto son representados con los constructores (data constructor) Fútbol y Baloncesto respectivamente, estos no son nuevos tipos por lo que no podemos hacer algo como

foo :: Futbol -> String

En su lugar usamos el pattern matching para saber si un elemento pertenece al constructor fútbol o baloncesto.

foo :: JueganFutbolOBaloncesto -> String
foo Futbol p = nombre p
foo Baloncesto p = nombre p

En la misma pagina dice “El producto cartesiano de dos conjuntos A y B es el conjunto C, C = A × B, donde los pares ordenados (a,b) están formados por un primer elemento perteneciente a A y (∧) un segundo elemento perteneciente a B”. Los tipos que se crean usando la operación de producto, es decir, los product types, contienen los elementos ordenados (n-tupla) de la combinación de los conjuntos operando. Veamos, de nuevo, el ejemplo de la wikipedia: “El producto cartesiano de A={2,3} y B={a,b,c} es A×B={(2,a),(2,b),(2,c),(3,a),(3,b),(3,c)}”

type C = (Int,Char)

El tipo C = Int x Char. Podemos entonces definir un nuevo tipo Persona que contiene todos los valores del tipo Nombre y todos los valores del tipo Apellido

type Persona = (Nombre,Apellido)

También es posible definir “nombres” para los elementos de una tupla, estos los conocemos como records.

data Persona = Persona { nombre :: Nombre
 , apellido :: Apellido
 }

Podemos combinar los union types y los product types para expresar casos como, por ejemplo: Una persona tiene un nombre y un apellido y un peso en libras o en kilogramos. Los y los representamos con tuplas o con records y los o con el union type

data Peso = Lb Int | Kg Int
data Persona = Persona { nombre :: String
 , apellido :: String
 , peso :: Peso
 }

y su uso

pepito = Persona {nombre="Pepito", apellido="Perez", peso= Kg 80}

Tener claro de donde vienen estos tipos de datos nos ayuda a entender no solo de donde viene ese extraño nombre sino que puede resultar útil en el momento de razonar sobre los tipos que creamos para modelar soluciones.

Hasta el próximo post.

Operaciones con conjuntos y tipos de datos algebraicos

Sobre los técnicos en programación de software y los pegadores de ladrillos

Con este son ya diez los años que llevo escribiendo código. Diez años no son nada. Los años los inventamos nosotros, pero ¿y el tiempo? ¿y la muerte?. 10 es un signo, pero ¿y el número? ¿y las matemáticas? Debido a ese extraño valor simbólico que damos al aniversario reflexioné sobre algunos momentos clave en este primer decenio. Empecé por el técnico laboral en programación de software y no tardé en fijar mi atención en lo malo que había sido, o al menos, en lo mal orientado que estuvo. Ahora dudo de la dificultad de comunicación entre industria y academia, ahora creo que en la instrucción de estos técnicos se refleja, no lo malo, si no lo poco que se entiende este oficio desde el mismo mercado laboral.

Una vez un amigo me contó, exaltado, que un dirigente de una organización se había referido a su equipo de desarrollo como pegadores de ladrillos -no recuerdo haciendo referencia a qué pero ahora no es importante- y cómo él había refutado esa posición y defendido al gremio de las punzantes opiniones de un insípido dirigente que levitaba con el poder de su cargo. Lo relevante de su relato no es la posible tensión ideológica en la comparación de los oficios pues el capitalismo no distingue eso, lo interesante es la analogía misma con el gremio de la construcción pero no al nivel de los respetados arquitectos y las complicadas arquitecturas, sino al nivel de los obreros, los maestros y sus ayudantes.

Muchos barrios de la ciudad han sido levantados por sus habitantes, levantando desde la maleza que cubría los terrenos. En la construcción de una vivienda participaba más de una familia donde algún familiar era o conocía a un maestro, también vecino de estos porque todos apenas llegaban. Entre muchos maestros dieron cara e identidad a barrios enteros con la práctica de su saber popular, ajustándolos a las necesidades reales de sus habitantes, es decir, ellos mismos, la comunidad. Para llegar a ser maestro de obra se empieza por ayudante, en ocasiones de algún familiar, ayudando, por ejemplo, a subir y bajar material y escombro; a mezclar; pegar ladrillos; etc. Saber cómo levantar una casa es algo que el ayudante aprenderá en un número indeterminado de construcciones y con un número indeterminado de maestros.

Related image

Viendo el pensum del técnico en programación de software en las páginas de varias instituciones se evidencia el mismo error: se espera que en dos años de instrucción el sujeto sepa lenguajes de programación, bases de datos, dispositivos móviles y hasta “Desarrollar aplicaciones complejas utilizando bases de datos”. Plantear un programa así es desconocer las necesidades de la industria, aún muy joven en el país. La orientación que se debe dar a un técnico en programación de software es similar a la de los ayudantes de construcción.

Los maestros de los que hablo aquí no recibieron una y otra vez, en distintos niveles académicos, la instrucción y la practica de cómo hacer una casa. Primero se aprende cuanto pesa un bulto de arena, cuanto esfuerzo cuesta moverlo. Se acude tanto a la ceremonia de la praxis que cuando el ayudante es ya un maestro sabrá, con un movimiento rápido del metro, cuantos viajes de arena necesita para iniciar una obra.

Es más útil para el equipo contar con alguien que sepa automatizar tareas con, por ejemplo, bash o que domine git a estos técnicos que saben hacer un crud. El perfil de nuestros técnicos, como el de un ayudante de construcción, debe ser el de un facilitador para el equipo, con dominio de varias herramientas. Alguien que tiene lista la mezcla de arena y cemento cuando empieza la construcción.

Introducir un perfil como este, un automatizador entrenado para que los programadores no se ocupen, por ejemplo, de un script de compilación y despliegue automático en la industria sacudiría a más de un equipo de programadores e ingenieros obsoletos que, por estar pensando si mejor en blanco o en negro, siguen compilando en la máquina del único cuyo usuario tiene acceso al servidor que también tiene instalado Visual Studio, por si es necesario… Ese es el estado de nuestros equipos de desarrollo. Por eso, no es de extrañar que demanden de la academia lo que no necesitan: más jóvenes que arrastren y suelten botones en una pantalla.

Es común que las discusiones sean del orden de si microservicios o monolítico, ¿y nosql? ¿si redis? ¿y el performance? pero nunca una sobre una estrategia de integración continua consensuada, y como se desconoce, obvio, nadie sabe implementarlo.

La instrucción de estos técnicos es mucho más sencilla, es realmente una instrucción de técnica, de repetición, como una kata, se usa una y otra vez la herramienta hasta que se domina. Conociendo, por ejemplo, un sistema de control de versiones, lo que es un compilador y sabiendo hacer un script de compilación, entonces si pensamos en escribir código, en aprender un estilo ya sea en la practica o en un siguiente nivel académico.

En el desarrollo de software le hemos puesto etiquetas a situaciones comunes con la construcción: el segundo piso de una casa lo nombraríamos feature y a un piso desnivelado le diríamos bug. Conocer e identificar estos artefactos, saber, por ejemplo, qué es y cómo se redacta una historia de usuario en determinadas herramientas facilitará la integración de los técnicos en el equipo, para esto no es necesario saber qué es el polimorfismo, solo distinguir una situación y usar una herramienta para documentarlo. Es necesaria la comunicación: son más los equipos que fallan por sus individuos e interacciones que por las herramientas y los procesos.

Ser productivo en un lenguaje de programación es fácil, pero solucionar problemas reales construyendo un producto de software no lo es tanto. Para esto es necesario participar en varios proyectos, en varios equipos, conocer e ir creando un estilo propio, un estilo definido por las necesidades y restricciones propias de las organizaciones y las verticales de negocio en las que hemos intervenido.

Nuestro oficio no es el de científicos de la computación, aunque obvio que hay ciencia en esto como en saber levantar las columnas de una vivienda. Hay que bajar la programación de software al servicio de la practica y elevar su enseñanza a ciencia, como la ciencia que existe en enseñar a alguien a construir una casa.

Debemos reconocer en los procesos de aprendizaje de oficios milenarios, como el de la construcción, aspectos y técnicas que nos pueden ser útiles. Este es un oficio joven aún y ya nos hablan de un deficit de programadores. Tal vez es el momento preciso para replantear entre academia e industria lo que significa para una sociedad como la nuestra los programadores de software.

Sobre los técnicos en programación de software y los pegadores de ladrillos

[F#] Free monad interpreter, DSL y DDD

Hace ya poco más de dos años leí éste post, pero, en aquel momento no le encontré tanta utilidad (más por ignorancia que por otra cosa) y dejé el tema ahí, como algo interesante que, por lo pronto, no usaría en F#. No fue si no hasta finales del año pasado, leyendo otro articulo o una pregunta en SO (no recuerdo) donde se mencionó el termino Free Monad Interpreter que vi relacionados varios conceptos y tuve uno de esos momentos mentales

happy excited shocked awesome surprised

He dudado en escribir esta entrada porque aún hay detalles que se escapan a mi entendimiento y experiencia, pero sé que al escribirlo lo entenderé, al menos, un poco mejor, así que aquí va.

Lenguaje Ubicuo

Siempre que se habla de DDD se habla del lenguaje ubicuo que, cómo Martin Fowler lo expone, “es el término que Eric Evans usa en DDD para la práctica de construir un lenguaje común y riguroso entre desarrolladores y usuarios.” (traducción propia). En mi experiencia personal, y hablando desde la perspectiva del código en lenguajes imperativos (C# en mi caso particular), la construcción de éste lenguaje se limita a la representación en clases y métodos bien nombrados, “nutriéndolo”, el modelo de dominio, para que no sea anémico y que, cuando el usuario diga algo en su lenguaje natural seamos capaces de mapearlo a ésta representación nuestra. Pero lo que veo ahora es que este lenguaje natural puede ser también el lenguaje en el que se representen los requerimientos en nuestro código. Podemos traducir este lenguaje ubicuo a un DSL o mini-lenguaje que nos permitirá no traducir si no casi transcribir los requerimientos en nuestro código.

Free Monads

De nuevo esa extraña palabra aparece, pero en esta ocasión, no está sola. Qué es un Free Monad, teóricamente hablando (teoría de categorías y demás), se escapa de mi conocimiento. Pero me he hecho una imagen practica basada, como raro, en blogs y respuestas en SO. “Un Free Foo pasa a ser la cosa más simple que satisface todas las leyes del ‘Foo‘. Es decir que satisface exactamente las leyes necesarias para ser un Foo y nada extra.”1 esto es, el Free Monad es un monad (cumple sus leyes), pero no realiza ningún calculo, definiendo así nada más los contextos a computar2  En esta parte de quien y cómo computa (con qué monad) estos contextos es, cómo yo lo veo, donde viene la parte de los interpretadores del titulo de esta entrada. Gabriel Gonzalez tiene un excelente articulo explicando precisamente por qué importan los Free Monads, inicia su entrada de manera triunfal (traducirlo, pienso, lo arruinaría):

Good programmers decompose data from the interpreter that processes that data. Compilers exemplify this approach, where they will typically represent the source code as an abstract syntax tree, and then pass that tree to one of many possible interpreters.

Entre las ventajas de esta separación está la posibilidad de crear varios interpretadores separando así las acciones puras de las impuras (IO) y facilitando así las pruebas a nuestro código.

Implementación en F#

Sabemos que en F# existe el concepto de computation expressions y hasta donde sé no hay un computation expression para los Free Monads. Mostrar aquí su implementación dese cero sería caer en el error de la mera traducción del articulo mencionado al inicio de esta entrada. Por lo que espero que el lector se tome su tiempo para entender lo que allí se expone pues ese mismo código será empleado para desarrollar mi ejemplo.

Supongamos ahora un caso de uso como el siguiente: En el registro de nuevos usuarios se debe validar que la contraseña tenga una longitud mayor a seis y que el usuario no exista. Si se cumplen estas condiciones se registra el usuario, de lo contrario se muestra un mensaje indicando el error.

Con esta información procedemos a crear los tipos correspondientes

type User = {
    username : string
    password : string
}

type Error = string

Ahora definimos las acciones que se detallan en el caso de uso, esto es, consultar si el usuario existe, crear un usuario y notificar al usuario:

type UseCase<'a> =
    | Notify of Error * 'a
    | UserExist of User * (bool ->  'a)
    | Register of User * 'a

let mapUseCase (f : 'a -> 'b) (useCase : UseCase<'a>) : UseCase<'b> =
    match useCase with        
        |  Register (user, value) -> Register (user, f value)
        |  UserExist (user, fn)  -> UserExist (user, f << fn) 
        | Notify (message, v) -> Notify (message, f v)

Puede surgir la inquietud de por qué la validación no hace parte de este conjunto de acciones. Si bien podemos agregarla y trabajar con ella esta validación no presentaría ningún cambio entre los interpretes que ya veremos. Esta validación puede hacer uso del Option o bien de una monad Result<success,error> pero no cambiará el cómo es interpretada (puro/IO).

En el código del Free Monad solo he renombrado el código del ejemplo del post mencionado:

type FreeUseCase<'a> =
    | Pure of 'a
    | Free of UseCase<FreeUseCase<'a>>

let rec bind (f : 'a -> FreeUseCase<'b>) (useCase : FreeUseCase<'a>) : FreeUseCase<'b> =
    match useCase with
        | Pure value -> f value
        | Free t -> Free (mapUseCase (bind f) t)

let liftF (useCase:UseCase<'a>) : FreeUseCase<'a> = Free (mapUseCase Pure useCase)

let (>>=) = fun useCase f -> bind f useCase

let (>>.) = fun t1 t2 -> t1 >>= fun _ -> t2

Las funciones “elevadas” que nos permitirán construir el DSL:

let register (user : User) : FreeUseCase<unit> = liftF (Register (user, ()))
let notify (message : Error) : FreeUseCase<unit> = liftF (Notify (message, ()))
let userExist (user : User) : FreeUseCase<bool> = liftF (UserExist (user, true |> (=)))

Con este código ya podemos traducir el requerimiento y quedaría algo como:

let createUser' user = 
    userExist user
    >>= fun exists -> 
        if exists then 
            validatePassword user.password 
            |> function
            | Some _ -> register user
            | None -> notify "invalid password"
        else
            notify "username already exists"

Aquí se hace notoria, en mi humilde opinión, una de las limitaciones de F# al no poder generalizar los monads (polimorfismo de orden superior) y poder aplicar el fmap entre estos.

Vemos que los nombres de las funciones se corresponden con las acciones indicadas por el usuario, pero puede resultar confuso tantos símbolos indicando el flujo del programa, para esto podemos crear un computation expression y expresarlo de manera imperativa, más similar al lenguaje ubicuo. El computation expression quedaría, de nuevo tomando el código del ejemplo anterior, algo como:

type UseCaseBuilder() =
    member x.Bind(term, f) = bind f term
    member x.Return(value) = Pure value
    member x.Combine(term1, term2) = term1 >>. term2
    member x.Zero() = Pure ()
    member x.Delay(f) = f()
let usecase = new UseCaseBuilder()

Y su uso:

let createUser user = usecase {
    let! exist = userExist user
    if (not exist) then   
        match (validatePassword user.password) with
        | Some _ -> do! register user
        | None -> do! notify "invalid password"
    else
        do! notify "username already exists"
}

Ahora bien, como decíamos en la definición de los free monad hace falta el monad que reduzca (compute) estas expresiones, para ello vienen los interpretadores. En nuestro caso usaremos dos, uno puro, usando la monad List y uno impuro, usando IO (printfn).

let rec interpretIO (useCase:FreeUseCase<'a>) : 'a =
    match useCase with
        | Free (Register (user, next)) -> 
            printfn "User: %s Pass: %s" user.username user.password
            interpretIO next
        | Free (UserExist (user, fn)) -> 
            // should be from DB, u know... 
            interpretIO (fn (pureExist user.username))
        | Free (Notify (error, next)) -> 
            printfn "Error: %s" error
            interpretIO next
        | Pure a -> a

let rec interpretPure (acc : string list) (useCase:FreeUseCase<'a>) : string list =    
    match useCase with
    | Free (Register (user, next)) -> 
         interpretPure ((sprintf "User: %s Pass: %s" user.username user.password) :: acc) next
        | Free (UserExist (user, fn)) -> 
            interpretPure acc (fn (pureExist user.username))
        | Free (Notify (error, next)) ->             
            interpretPure ((sprintf "Error: %s" error) :: acc) next
    | Pure a -> acc

Con esta flexibilidad podemos probar con el interprete puro, y hacer pruebas de integración con otro interprete…

> interpretPure [] (createUser {username = "nicolas"; password = "123456"});;
val it : string list = ["User: nicolas Pass: 123456"]
> interpretPure [] (createUser {username = "hugo"; password = "123456"});;
val it : string list = ["Error: username already exists"]
> interpretPure [] (createUser {username = "nicolas"; password = "123"});;
val it : string list = ["Error: invalid password"]

Haskell Bonus

En el mismo blog hay un ejemplo usando haskell, mucho más sencillo y limpio que el de F#. Yo hice un gist para mostrar su uso interactuando con otra monad.

Conclusiones y apuntes finales

  • Al ser F# un lenguaje funcional no puro, implementar técnicas como esta permite una separación que, si bien requiere atención por parte del programador, hace que se vea más clara la intención de dicha separación.
  • En esto de la construcción del DSL he intentado, sin mucho éxito, crear funciones y combinadores de la forma si – entonces – cuando que permitan una lectura del código como si fuera lenguaje natural. La mejor aproximación ha sido con el do notation/computation expression.
  • ¿Recuerdan CQS/CQRS? van bien de la mano. Aquí un post explicando cómo

El código completo de este post está en este gist

Referencias y enlaces de interés

1 Traducción de un fragmento de esta respuesta de Kmett en SO

2 Este hilo en general y esta respuesta en particular han sido usados para construir la definición que intenté presentar

What is the “Free Monad + Interpreter” pattern?

Puede ser que esto termine siendo una sobre ingeniería, claro esta. When would I want to use a Free Monad + Interpreter pattern?

Un post muy similar a este, con base de datos y todo

[F#] Free monad interpreter, DSL y DDD

[F#] ¿Y para qué me sirven los functors y las monads?

El sábado pasado tuve la oportunidad de asistir a un meetup de programación funcional donde hubo dos charlas muy entretenidas: En una se habló de elm y todas sus bondades en el desarrollo font-end, una introducción a su sintaxis, a sus herramientas y ecosistema. Y en la segunda una introducción a Monads y Functors pasando, claro, por algo de teoría de categorías e intentando aterrizar estos conceptos en Scala. Ha sido sin duda un espacio genial que se prestó para discusiones muy interesantes, muchas preguntas y varias ideas! Personalmente la pasé muy bien y me gustó el hecho que al final se terminó construyendo conocimiento entre todos.

Mientras discutíamos sobre esas dos extrañas palabras e intentábamos llegar a un consenso alguien levantó la mano y dijo algo como: “Y bueno, ¿eso a mi para qué me sirve?” Yo intenté explicar su utilidad cómo ahora la entiendo (antes lo entendía diferente y tal vez mañana lo vea con otros ojos) pero decidí que esta vez voy a escribirlo para que no se me olvide.

Antes de empezar

Antes de continuar quiero aclarar que este no será otro articulo más intentando explicar que son las monads, en serio, no estaría bien como primer post, dejémoslo en que son burritos, solo por ahora. Aquí solo quiero plasmar para qué sirven con un ejemplo de código en F#, y ese “para qué sirven” se limitará a ver un par de funciones que definen a los functores y a las monads. Ni más ni menos.

Empezando

Lo más interesante del asunto es que, si vienes de lenguajes como C#, probablemente ya hayas usado functores y monads sin saberlo, y de paso ya conozcas su utilidad. Es el caso del IEnumerable<T> que implementa el functor a través del método de extensión Select, si, el Select es el map que define a los functores y el método SelectMany, que es el bind, o una de las propiedades de las monads. Hablando así de seguro sonarás interesante y tengas éxito con l@s chic@s pero, para no enredarme con términos matemáticos (si, sé que son importantes, pero los dejaremos de lado por hoy) pienso en lo que muchos llaman el monad x, monad y, como amplificadores de tipos, si, las Listas, el Maybe, el Either los veo como amplificadores de tipos. Que si vienes de C# lucen como los genéricos, y si has visto algo de Haskell verás todas estas instancias son polimórficas. Estos amplificadores de tipos, en palabras más simples, pueden ser vistos como contextos, envoltorios o cajas, y como sé que algunos entendemos más con dibujos aquí hay una excelente explicación de manera grafica (también disponible en español).

Composición

De pronto el panorama esté un poco más claro con los dibujitos de la explicación grafica, pero, si aún no se le ve la utilidad, me atrevería a decir que está en la composición y en la eliminación de mucho ruido, que al final nos lleva a un código hermoso.

Veamos ahora un ejemplo, supongamos que tenemos las siguientes funciones:

    // From bd or http service... No IO monad here, plz 😛
    let findInvoice id =
        if id % 2 = 0 then Some {tax = 1.5; price = 200.0; date = DateTimeOffset.UtcNow}
        else None 

    // Based on invoice month, get a money value
    let calculateSomethingWithInvoice invoice =
        if invoice.date.Month > 9 then invoice.price * invoice.tax
        else 0.
    
    // Based on a money value, calculate yet another tax... you know, more TAXES!
    let calcOtherTax (finalValue : float) =
        if finalValue > 0.0 then Some (600. / finalValue)
        else None

El ejemplo es sencillo y hace uso de otro amplificador, el Option.

De manera breve: Una función obtiene de una BD una factura, la factura puede o no existir, por lo que se retorna un Option (Some o None). Hay una función que calcula algo con esa factura, ojo, con la factura NO con un Option<Factura> y retorna un valor monetario. Finalmente hay una función que, a partir de un valor moneda calcula algún impuesto, pero como el calculo de este impuesto implica una división sobre el valor de entrada somos muy cuidadosos y retornamos un valor moneda amplificado esto es, algo como un Option<moneda>, es decir, si el valor de entrada es cero la salida será None.

A la hora de usar estas funciones podemos hacerlo à la imperativa, algo como:

    let invoice = findInvoice 1

    let moneyValue = 
        if invoice = None then None 
        else Some (calculateSomethingWithInvoice (invoice.Value))

O a un estilo más à la F#:

    let moneyValue = 
        (findInvoice 1)
        |> function 
        | Some i -> Some  (calculateSomethingWithInvoice i)
        | None -> None

Pero ahora que sabemos que los functores nos permiten hacer este map, sacando el valor amplificado, aplicar la función y volviéndolo a poner dentro del envoltorio, podemos usar algo como:

    let moneyValue = findInvoice 1 |> Option.map calculateSomethingWithInvoice

O podemos crear un operador para que se vea à la Haskell (pero no se puede usar $)

    let (<%>) = Option.map
    let moneyValue = calculateSomethingWithInvoice <%> findInvoice 1 

Ahora nos falta calcular el valor del impuesto. Esta función recibe el valor monetario PERO retorna un valor amplificado (Option<Moneda>) por lo que al usar el map del functor obtendríamos el option de un option (Option<Option<Moneda>>). Aquí es donde nos es útil el bind de las monads! Esta es un poco más enredada y, para ahorrarme un párrafo entero, es mejor volver a ver los dibujitos.

    let moneyValue = calculateSomethingWithInvoice <%> findInvoice 1 
    let taxValue = moneyValue |> Option.bind calcOtherTax

Igual, podemos crear un operador à la Haskell y hacerlo todo en una línea

    let (>>=) = Option.bind
    let tax = calcOtherTax >>= (calculateSomethingWithInvoice <%> findInvoice 1)

O, por qué no, podemos crear una nueva función usando estas tres, algo como:

 
    let getTaxByInvoiceId id = calcOtherTax >>= (calculateSomethingWithInvoice <%> findInvoice id)

Conclusión

  • Si estás en Bogotá: pendiente de este meetup!. Si no estás en Bogotá: busca uno en tu ciudad, seguro hay uno!
  • Tal vez ya habías usado functores y monads pero no lo sabías.
  • No hace falta estar en la Nasa para usarlos en tu código día a día.
  • Cuando tengas un tiempo revisa teoría de categorías para no decirles ni amplificadores de tipos ni monads a los tipos a los que hoy les decimos monads

Espero les sea de utilidad

Hasta el próximo post

[F#] ¿Y para qué me sirven los functors y las monads?

[ASP.NET Web API] Autenticación basada en tokens y líos con el CORS

No era la primera vez que implementaba este tipo de autenticación en un proyecto de ASP.NET Web Api + ASP.NET MVC + OWIN y ya sabía (o al menos creo saber) los retos de trabajar con estos pipelines, digo, líneas como config.SuppressDefaultHostAuthentication(); en el  WebApiConfig hacen su magia, conocí la clase OAuthAuthorizationServerProvider y en su momento dejé en mis favoritos entradas como esta como fuente de consulta. Con el tema de CORS creí que todo estaba resuelto con el uso del atributo EnableCors que hizo esto más sencillo.

La semana pasada este requerimiento surgió de nuevo pero con un componente adicional: El token es solicitado en un cliente desde otro dominio. De entrada parece que nada cambia, pero si que lo hace, o al menos si hay que agregar unas cuantas líneas. Sabía que en mis favoritos aún estaban los enlaces a las fuentes que había usado como referencia en implementaciones anteriores, así que volví a consultar una serie de tutoriales muy, muy completos de este blog. Y por primera vez me percaté que existen dos “enable cors”! (o algo así) uno a nivel del pipeline de OWIN y el que siempre uso en Web API. El que siempre uso, el de Web API, viene en el paquete Microsoft.AspNet.WebApi.Cors y el que no conocía, el de Katana, viene en el paquete Microsoft.Owin.Cors.

¿Qué diferencia tienen WebApi.Cors y Owin.Cors?

No encontré nada en la documentación oficial, pero viendo el nombre, entendiendo algo de OWIN y habiendo usado Katana, se puede suponer que el primero es solo para el Framework Web API y lo que hay en el, es decir, los ApiControllers. El segundo es un middleware que agrega soporte para el resto del pipeline, como el middleware para generar los tokens! Igual apliqué un poco de GOD (google oriented development) y encontré una explicación similar en Stack Overflow.

¿Y cómo se usan los dos?

Lo primero que hice, desde el desconocimiento, fue agregar en el Startup la línea app.UseCors(CorsOptions.AllowAll); y en el momento de probar surgió el primer error, error que rompe la parte que ya funcionaba (mensaje en la consola de Chrome):
Control-Allow-Origin' header contains multiple values 'https://foo.com, https://foo.com', but only one is allowed. Origin 'https://foo.com' is therefore not allowed access. ¡Y tiene todo el sentido! pues en dos puntos del pipeline estamos agregando estas cabeceras.

Una solución puede ser quitar la configuración del CORS en el WebAPIConfig, es decir, la línea config.EnableCors(); y dejar que el OWIN se configure global con con Katana. ¡Pero no me gusta! no me gusta por el AllowAll (least privilage), aunque parece claro que se puede cambiar (más sobre esto a continuación), y porque se supone que la configuración del CORS de Web API es para el Framework! digo, por algo existe, no?

Como el único  lugar donde necesito el CORS es en el endpoint que genera el token, pensé que era más fácil y mejor quitar el UseCors() del Startup y agregar las cabeceras directamente en el response, sabía que no podía ser el primero que hacía esto y así fue, la segunda solución la encontré en Stack Overflow y pasa por sobrescribir el método MatchEndpoint del OAuthAuthorizationServerProvider, yo terminé con una implementación como la siguiente:

        private static void SetOriginHeaders(IOwinContext context)
        {
            if (!context.Response.Headers.Keys.Contains("Access-Control-Allow-Origin"))
                context.Response.Headers.AppendCommaSeparatedValues("Access-Control-Allow-Origin", "https://localhost:44369");
            if (!context.Response.Headers.Keys.Contains("Access-Control-Allow-Headers"))
                context.Response.Headers.AppendCommaSeparatedValues("Access-Control-Allow-Headers", "Accept", "Content-Type", "Authorization", "Cache-Control", "Pragma", "Origin");
            if (!context.Response.Headers.Keys.Contains("Access-Control-Allow-Methods"))
                context.Response.Headers.AppendCommaSeparatedValues("Access-Control-Allow-Methods", "GET", "POST", "PUT", "DELETE", "OPTIONS");
        }

        public override Task MatchEndpoint(OAuthMatchEndpointContext context)
        {
            if (context.IsTokenEndpoint &&
                (context.Request.Method.Equals("OPTIONS", StringComparison.InvariantCultureIgnoreCase)
                || context.Request.Method.Equals("POST", StringComparison.InvariantCultureIgnoreCase)))
            {
                SetOriginHeaders(context.OwinContext);
                context.MatchesTokenEndpoint();
                //context.RequestCompleted();
                return Task.CompletedTask;
            }

            return base.MatchEndpoint(context);
        }

        public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            context.Validated();
        }

        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {		
            //Se valida el usuario...

            SetOriginHeaders(context.OwinContext);
        }

Con el código anterior funciona sin problemas, pero nuevamente pensé: ¡Esto debe poderse hacer desde el middleware!

Configurar el Owin.Cors

Después de dar muchas vueltas llegué a esta solución, que ahora me parece muy sencilla y obvia. Se puede crear una instancia de CorsOptions y usar un PoliciResolver, que no es más que una función que permite tener acceso a la información del request (IOwinRequest) y retornar un objeto que encapsula los Headers HTTP en cómodas propiedades. El código del Startup se así (el orden de los middlewares SI altera el resultado):

    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseCors(new CorsOptions
            {
                PolicyProvider = new CorsPolicyProvider
                {
                    PolicyResolver = PolicyResolver
                }
            });
            ConfigureAuth(app);
        }

        private static Task<CorsPolicy> PolicyResolver(IOwinRequest request)
        {
            if (request.Path.Value == "/api/token")
            {
                //Estos valores pueden ser recuperados de un archivo de configuracion
                var corsPolicy = new CorsPolicy
                {
                    Headers = { "Accept", "Content-Type", "Authorization", "Cache-Control", "Pragma", "Origin" },
                    Methods = { "POST", "OPTIONS" },
                    Origins = { "https://localhost:44369" }
                };
                return Task.FromResult(corsPolicy);
            }
            return Task.FromResult<CorsPolicy>(null);
        }
    }

Conclusiones

  • Existe un middleware de Katana que habilita CORS en todo el pipeline de OWIN, Microsoft.Owin.Cors
  • Owin.Cors y WebApi.Cors pueden existir en el mismo proyecto
  • El OAuthTokenProvider no hace parte de WebApi, por eso se necesita el Owin.Cors

Referencias y enlaces de interés

Espero les sea de utilidad.

Hasta el próximo post.

[ASP.NET Web API] Autenticación basada en tokens y líos con el CORS

[Evento] Dando un giro a nuestra arquitectura, de capas a verticales

En el tiempo que llevo desarrollando software para empresas he notado que, sin importar el negocio, todas las soluciones terminan siendo similares en su diseño, ¡sí! siempre se termina con algo en capas, con toneladas de abstracciones e indirecciones muchas veces innecesarias que terminan haciendo más complicado el desarrollo, evolución y mantenimiento de estas soluciones. Este ha sido el tema de conversaciones y cervezas con mi amigo Jhonnys, un loco con el que he trabajado implementando varios proyectos con este diseño “tradicional”, analizando las ventajas, desventajas y ahora cómo mejorar.

En una de esas conversaciones y con la pretensión de aportar algo a la comunidad, hemos decidido abrir un espacio para mostrar una forma diferente de trabajar, verticales en lugar de capas horizontales. No es algo de nuestra invención, pero hemos tenido la oportunidad de trabajar y aplicarlo en algunos proyectos con muy buenos resultados.

Nuestra idea es compartir, de manera practica, nuestras inconformidades y preocupaciones con estos diseños tradicionales (tradicionales al menos en el mundo de las empresas colombianas que usan .NET), escuchar opiniones al respecto y compararlas con el diseño en verticales.

El evento lo haremos de manera presencial y gratuita con la comunidad de C# Colombia, serán cuatro sesiones para compartir conocimiento y mejorar entre todos.

Toda la información de fechas y registro la podrán encontrar en el meetup de la comunidad.

Nos vemos.

[Evento] Dando un giro a nuestra arquitectura, de capas a verticales