Translate

viernes, 5 de agosto de 2022

DevOps como puntapié inicial para tu transformación digital

 Me llego este mail y me resulto interesante, por eso se los comparto : 

miércoles, 3 de agosto de 2022

Mónadas en Cats parte 21

cats.data.State nos permite pasar estados adicionales como parte de un cálculo. Definimos instancias de estado que representan operaciones de estado atómico y las unimos usando map y flatMap. De esta manera, podemos modelar el estado mutable de una manera puramente funcional, sin usar la mutación real.

Reducido a su forma más simple, las instancias de State[S, A] representan funciones de tipo S => (S, A). S es el tipo del estado y A es el tipo del resultado.


import cats.data.State

val a = State[Int, String]{ state =>

(state, s"The state is $state")

}


En otras palabras, una instancia de State es una función que hace dos cosas:

• transforma un estado de entrada en un estado de salida;

• calcular un resultado.

Podemos "ejecutar" nuestra mónada desde un estado inicial. State proporciona tres métodos (run, runS y runA) que devuelven diferentes combinaciones de estado y resultado. Cada método devuelve una instancia de Eval, que State usa para mantener la seguridad de la pila. Llamamos al método de valor como de costumbre para extraer el resultado real:


// Get the state and the result:

val (state, result) = a.run(10).value

// state: Int = 10

// result: String = "The state is 10"

// Get the state, ignore the result:

val justTheState = a.runS(10).value

// justTheState: Int = 10

// Get the result, ignore the state:

val justTheResult = a.runA(10).value

// justTheResult: String = "The state is 10"

Mónadas en Cats parte 20

Los Readers proporcionan una herramienta para realizar inyección de dependencia. Escribimos pasos de nuestro programa como instancias de Reader, los encadenamos junto con map y flatMap, y construimos una función que acepta la dependencia como entrada.

Hay muchas formas de implementar la inyección de dependencia en Scala, desde técnicas simples como métodos con múltiples listas de parámetros, pasando por parámetros implícitos y clases de tipos, hasta técnicas complejas como el patrón cake  y frameworks.

Los Readers son más útiles en situaciones donde:

• estamos construyendo un programa que puede ser fácilmente representado por una función;

• necesitamos diferir la inyección de un parámetro conocido o conjunto de parámetros;

• queremos poder probar partes del programa de forma aislada.

Al representar los pasos de nuestro programa como Lectores, podemos probarlos tan fácilmente como funciones puras, además de obtener acceso a los combinadores map y flatMap.

Para problemas más complicados donde tenemos muchas dependencias, o donde un programa no se representa fácilmente como una función pura, otras técnicas de inyección de dependencia tienden a ser más apropiadas.


lunes, 1 de agosto de 2022

Mónadas en Cats parte 19

cats.data.Reader es una mónada que nos permite secuenciar operaciones que dependen de alguna entrada. Las instancias de Reader envuelven funciones de un argumento, brindándonos métodos útiles para componerlas.

Un uso común para Readers es la inyección de dependencia. Si tenemos varias operaciones que dependen de alguna configuración externa, podemos encadenarlas usando un Reader para producir una gran operación que acepte la configuración como un parámetro y ejecute nuestro programa en el orden especificado.

Podemos crear un Reader[A, B] a partir de una función A => B usando el constructor Reader.apply:


import cats.data.Reader

final case class Cat(name: String, favoriteFood: String)

val catName: Reader[Cat, String] = Reader(cat => cat.name)

// catName: Reader[Cat, String] = Kleisli(<function1>)


Podemos extraer la función nuevamente usando el método de ejecución del Reader's y llamarla usando apply:


catName.run(Cat("Garfield", "lasagne"))

// res1: cats.package.Id[String] = "Garfield"


El poder de Readers proviene de sus métodos map y flatMap, que representan diferentes tipos de composición de funciones. Por lo general, creamos un conjunto de Readers que aceptan el mismo tipo de configuración, los combinamos con map y flatMap, y luego llamamos a ejecutar para inyectar la configuración al final.

El método map simplemente extiende el cálculo en el Reader al pasar su resultado a través de una función:


val greetKitty: Reader[Cat, String] = catName.map(name => s"Hello ${name}")

greetKitty.run(Cat("Heathcliff", "junk food"))

// res2: cats.package.Id[String] = "Hello Heathcliff"


El método flatMap es más interesante. Nos permite combinar Readers que dependen del mismo tipo de entrada. Para ilustrar esto, ampliemos nuestro ejemplo de saludo para alimentar también al gato:


val feedKitty: Reader[Cat, String] = Reader(cat => s"Have a nice bowl of ${cat.favoriteFood}")

val greetAndFeed: Reader[Cat, String] =

for {

greet <- greetKitty

feed <- feedKitty

} yield s"$greet. $feed."

greetAndFeed(Cat("Garfield", "lasagne"))

// res3: cats.package.Id[String] = "Hello Garfield. Have a nice bowl of lasagne."

greetAndFeed(Cat("Heathcliff", "junk food"))

// res4: cats.package.Id[String] = "Hello Heathcliff. Have a nice bowl of junk food."



Log con Aop de Spring boot


Supongamos que queremos logear cada cosa que pasa por cada método de nuestros objetos, para hacer esto podemos utilizar aop. 

Veamos un ejemplo: 

@Aspect

@Configuration

@Order(0)

class LogingAspect {

    private val logger = LogFactory.getLog(LoggingAspect::class.java)


    @Pointcut("execution(public * com.paquete..*(..))")

    fun allControllersMethods() {

    }


    @Around("allControllersMethods()")

    fun profileAllMethods(pjp: ProceedingJoinPoint): Any {

        val method: Method = (pjp.signature as MethodSignature).method


        logger.info("Started ${method.name}")


        try {

            return if (pjp.args != null) {

                pjp.proceed(pjp.args)

            } else {

                pjp.proceed()

            }

        } catch (ex: Exception) {

            logger.error("Error in ${method.name}", ex)

            throw ex

        } finally {

            logger.info( "Finished ${method.name}")

        }

    }

}


Y Listo!!

viernes, 29 de julio de 2022

Crear un proyecto con Sbt y Scala 3


Es muy fácil, mi consejo, instalate sdkman y luego sbt, pero si queres instalarte sbt de una, no hay problema. 

Luego lo que tienes que hacer es : 

> sbt new scala/scala3.g8

Y al toque te pide nombre del proyecto, lo llenas y listo!!

Espero que les sirva. 

jueves, 28 de julio de 2022

Compilar en kotlin


El código fuente de Kotlin normalmente se almacena en archivos con la extensión .kt. El compilador de Kotlin analiza el código fuente y genera archivos .class, al igual que lo hace el compilador de Java. Los archivos .class generados luego se empaquetan y ejecutan utilizando el procedimiento estándar para el tipo de aplicación en la que está trabajando. En el caso más simple, puede usar el comando kotlinc para compilar su código desde la línea de comandos y usar el comando java para ejecutar su código:


kotlinc <source file or directory> -include-runtime -d <jar name>

java -jar <jar name>


El código compilado con el compilador de Kotlin depende de la biblioteca de runtime de Kotlin. Contiene las definiciones de las propias clases de biblioteca estándar de Kotlin y las extensiones que Kotlin agrega a las API estándar de Java. La biblioteca de runtime debe distribuirse con su aplicación.

En la mayoría de los casos de la vida real, usará un sistema de compilación como Maven, Gradle o Ant para compilar su código. Kotlin es compatible con todos esos sistemas de compilación. Todos esos sistemas de compilación también admiten proyectos de lenguaje mixto que combinan Kotlin y Java en la misma base de código. Además, Maven y Gradle se encargan de incluir la biblioteca en tiempo de ejecución de Kotlin como una dependencia de tu aplicación.

miércoles, 27 de julio de 2022

Filosofía de Kotlin


Cuando hablamos de Kotlin, es un lenguaje pragmático, conciso y seguro con un enfoque en la interoperabilidad. ¿Qué significan exactamente con cada una de esas palabras? 

Pragmático: Kotlin es un lenguaje práctico diseñado para resolver problemas del mundo real. Su diseño se basa en muchos años de experiencia en la industria creando sistemas a gran escala, y sus funciones se eligen para abordar los casos de uso que encuentran muchos desarrolladores de software. Además, los desarrolladores tanto dentro de JetBrains como en la comunidad han estado usando las primeras versiones de Kotlin durante varios años y sus comentarios han dado forma a la versión lanzada del lenguaje. Kotlin puede ayudar a resolver problemas en proyectos reales.

Kotlin tampoco es un lenguaje de investigación. No estamos tratando de avanzar en el estado del arte en el diseño de lenguajes de programación y explorar ideas innovadoras en informática. En su lugar, siempre que sea posible, confiamos en funciones y soluciones que ya han aparecido en otros lenguajes de programación y han demostrado ser exitosas. Esto reduce la complejidad del lenguaje y hace que sea más fácil de aprender al permitirle confiar en conceptos familiares.

 Además, Kotlin no impone el uso de ningún estilo o paradigma de programación en particular. A medida que comienza a estudiar el lenguaje, puede usar el estilo y las técnicas que le resultan familiares de su experiencia con Java. Más adelante, descubrirá gradualmente las funciones más potentes de Kotlin y aprenderá a aplicarlas en su propio código, para hacerlo más conciso e idiomático.

Otro aspecto del pragmatismo de Kotlin es su enfoque en las herramientas. Un entorno de desarrollo inteligente es tan esencial para la productividad de un desarrollador como un buen lenguaje; y debido a eso, tratar el soporte IDE como una ocurrencia tardía no es una opción. En el caso de Kotlin, el complemento IntelliJ IDEA se desarrolló al unísono con el compilador, y las características del lenguaje siempre se diseñaron teniendo en cuenta las herramientas.

La compatibilidad con IDE también juega un papel importante a la hora de ayudarte a descubrir las características de Kotlin. En muchos casos, las herramientas detectarán automáticamente patrones de código comunes que se pueden reemplazar por construcciones más concisas y se ofrecerán a corregir el código por usted. Al estudiar las características del lenguaje utilizadas por las correcciones automáticas, también puede aprender a aplicar esas características en su propio código.

Conciso: Es bien sabido que los desarrolladores dedican más tiempo a leer código existente que a escribir código nuevo. Imagina que eres parte de un equipo que está desarrollando un gran proyecto y necesitas agregar una nueva función o corregir un error. ¿Cuáles son tus primeros pasos? Busca la sección exacta del código que necesita cambiar y solo entonces implementa una corrección. Lees mucho código para saber lo que tienes que hacer. Este código puede haber sido escrito recientemente por sus colegas, por alguien que ya no trabaja en el proyecto, o por usted, pero hace mucho tiempo. Solo después de comprender el código que lo rodea, puede realizar las modificaciones necesarias.

Cuanto más simple y conciso sea el código, más rápido entenderá lo que está pasando. Por supuesto, el buen diseño y los nombres expresivos juegan un papel importante aquí. Pero la elección del lenguaje y su concisión también son importantes. El lenguaje es conciso si su sintaxis expresa claramente la intención del código que lee y no lo oscurece con el texto estándar requerido para especificar cómo se logra la intención.

 En Kotlin, todo el código que escribe tiene un significado y no esta ahí solo para satisfacer los requisitos de la estructura del código. Gran parte del código estándar de Java, como getters, setters y la lógica para asignar parámetros de constructor a los campos, está implícito en Kotlin y no abarrota el código fuente.

Otra razón por la que el código puede ser innecesariamente largo es tener que escribir código explícito para realizar tareas comunes, como ubicar un elemento en una colección. Al igual que muchos otros lenguajes modernos, Kotlin tiene una rica biblioteca estándar que le permite reemplazar estas secciones largas y repetitivas de código con llamadas a métodos de biblioteca. La compatibilidad de Kotlin con lambdas facilita el paso de pequeños bloques de código a funciones de biblioteca. Esto le permite encapsular todas las partes comunes en la biblioteca y mantener solo la porción única y específica de la tarea en el código de usuario.

Al mismo tiempo, Kotlin no intenta reducir el código fuente al menor número de caracteres posible. Por ejemplo, aunque Kotlin admite la sobrecarga de operadores, los usuarios no pueden definir sus propios operadores. Por lo tanto, los desarrolladores de bibliotecas no pueden reemplazar los nombres de los métodos con secuencias de puntuación crípticas. Las palabras suelen ser más fáciles de leer que la puntuación y es más fácil encontrar documentación.

Un código más conciso requiere menos tiempo para escribir y, lo que es más importante, menos tiempo para leer. Esto mejora la productividad y permite hacer las cosas más rápido.

Seguro: En general, cuando hablamos de un lenguaje de programación como seguro, nos referimos a que su diseño previene ciertos tipos de errores en un programa. Por supuesto, esto no es un absoluto igualdad; ningún lenguaje previene todos los posibles errores. Además, la prevención de errores generalmente tiene un costo. Debe proporcionar al compilador más información sobre la operación prevista del programa, de modo que el compilador pueda verificar que la información coincida con lo que hace el programa. Por eso, siempre hay una compensación entre el nivel de seguridad que se obtiene y la pérdida de productividad necesaria para realizar anotaciones más detalladas.

Con Kotlin, se logra un mayor nivel de seguridad que en Java, con un costo total menor. La ejecución en la JVM ya proporciona muchas garantías de seguridad: por ejemplo, seguridad de la memoria, prevención de desbordamientos de búfer y otros problemas causados ​​por el uso incorrecto de la memoria asignada dinámicamente. Como lenguaje tipificado estáticamente en JVM, Kotlin también garantiza la seguridad de tipos de sus aplicaciones. Esto tiene un costo menor que con Java: no tiene que especificar todas las declaraciones de tipos, porque en muchos casos el compilador infiere los tipos automáticamente.

Kotlin también va más allá, lo que significa que se pueden evitar más errores mediante comprobaciones en tiempo de compilación en lugar de fallar en tiempo de ejecución. Lo más importante es que Kotlin se esfuerza por eliminar NullPointerException de su programa. El sistema de tipos de Kotlin realiza un seguimiento de los valores que pueden y no pueden ser nulos y prohíbe las operaciones que pueden conducir a una excepción NullPointer en tiempo de ejecución. El costo adicional requerido para esto es mínimo: marcar un tipo como anulable requiere solo un carácter, un signo de interrogación al final:

val s: String? = null

val s2: String = ""

Además, Kotlin proporciona muchas formas convenientes de manejar datos anulables. Esto es de gran ayuda para eliminar los bloqueos de aplicaciones.

Otro tipo de excepción que Kotlin ayuda a evitar es ClassCastException. Ocurre cuando conviertes un objeto en un tipo sin verificar primero que tenga el tipo correcto. En Java, los desarrolladores a menudo omiten la verificación, porque el nombre del tipo debe repetirse en la verificación y en el siguiente lanzamiento. En Kotlin, por otro lado, la verificación y el elenco se combinan en una sola operación: una vez que hayas verificado el tipo, puedes referirte a los miembros de ese tipo sin ningún casteo adicional. Por lo tanto, no hay motivo para omitir la verificación y no hay posibilidad de cometer un error. Así es como funciona esto:

if (value is String) println(value.toUpperCase())

Interoperable: Con respecto a la interoperabilidad, su primera preocupación probablemente sea: "¿Puedo usar mis bibliotecas existentes?" Con Kotlin, la respuesta es: "Sí, absolutamente". Independientemente del tipo de API que la biblioteca requiera que uses, puedes trabajar con ellas desde Kotlin. Puede llamar a métodos de Java, extender clases de Java e implementar interfaces, aplicar anotaciones de Java a sus clases de Kotlin, etc.

 A diferencia de otros lenguajes JVM, Kotlin va aún más allá con la interoperabilidad, lo que hace que llamar al código Kotlin desde Java también sea sencillo. No se requieren trucos: las clases y los métodos de Kotlin se pueden llamar exactamente como las clases y los métodos de Java normales. Esto le brinda la máxima flexibilidad para combinar código Java y Kotlin en cualquier parte de su proyecto. Cuando comience a adoptar Kotlin en su proyecto de Java, puede ejecutar el convertidor de Java a Kotlin en cualquier clase de su base de código, y el resto del código seguirá compilando y funcionando sin modificaciones. Esto funciona independientemente del rol de la clase que haya convertido.

Otra área en la que Kotlin se centra en la interoperabilidad es el uso de las bibliotecas Java existentes en la mayor medida posible. Por ejemplo, Kotlin no tiene su propia biblioteca de colecciones. Se basa completamente en las clases de la biblioteca estándar de Java y las amplía con funciones adicionales para un uso más conveniente en Kotlin. (Veremos el mecanismo para esto con más detalle en la sección 3.3). Esto significa que nunca necesitará envolver o convertir objetos cuando llame a las API de Java desde Kotlin, o viceversa. Toda la riqueza de API proporcionada por Kotlin viene sin costo en tiempo de ejecución.

 Las herramientas de Kotlin también brindan soporte completo para proyectos en varios lenguajes. Puede compilar una combinación arbitraria de archivos fuente de Java y Kotlin, independientemente de cómo dependan entre sí. Las funciones del IDE también funcionan en todos los lenguajes, lo que le permite:

  • Navegar libremente entre los archivos fuente de Java y Kotlin
  • Depurar proyectos de lenguaje mixto y pasar entre código escrito en diferentes lenguajes
  • Refactorizar sus métodos Java y actualice correctamente su uso en el código Kotlin, y viceversa. 



lunes, 25 de julio de 2022

Interceptor de Retrofit

                                                                                                                                                                                                                                                                        

Supongamos que tenemos que enviar en todas las llamadas a web services, un valor o un token o cualquier cosa. 

Lo que podemos hacer con retrofit es un interceptor, este lo declaramos una vez y para todas las llamadas enviarán los valores. Veamos un ejemplo: 

@Component

class RetrofitClient {


    @Value("\${service.url}")

    private lateinit var baseUrl: String


    private lateinit var retrofit: Retrofit


    private lateinit var objectMapper: ObjectMapper


    @PostConstruct

    fun init() {

        objectMapper = ObjectMapper()

            .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

            .registerModule(KotlinModule())


        val client = OkHttpClient.Builder().addInterceptor(EjemploInterceptor()).build()


        retrofit = Retrofit.Builder()

            .baseUrl(baseUrl)

            .client(client)

            .addConverterFactory(JacksonConverterFactory.create(objectMapper))

            .build()

    }


    fun <T> buildService(service: Class<T>): T {

        return retrofit.create(service)

    }


}


class EjemploInterceptor : Interceptor {


    companion object {

        private const val EJEMPLO = "ejemplo"

    }


    override fun intercept(chain: Interceptor.Chain): Response = chain.run {

        proceed(

            request()

                .newBuilder()

                .addHeader(EJEMPLO, "valor a agregar")

                .build()

        )

    }

}


En este ejemplo en todas las llamadas enviarán el valor agregado en el head. Y listo! 

jueves, 21 de julio de 2022

Mónadas en Cats parte 18

El log en un Writer se conserva cuando hacemos map or flatMap sobre él. flatMap agrega los logs del Writer de origen y el resultado de la función de secuenciación del usuario. Por esta razón, es una buena práctica utilizar un tipo de registro que tenga operaciones de adición y concatenación eficientes, como un Vector:

val writer1 = for {

    a <- 10.pure[Logged]

    _ <- Vector("a", "b", "c").tell

    b <- 32.writer(Vector("x", "y", "z"))

} yield a + b

// writer1: cats.data.WriterT[cats.package.Id, Vector[String], Int] =WriterT(

//(Vector("a", "b", "c", "x", "y", "z"), 42)

// )

writer1.run

// res3: (Vector[String], Int) = (Vector("a", "b", "c", "x", "y", "z") , 42)


Además de transformar el resultado con map y flatMap, podemos transformar el log en un Writer con el método mapWritten:


val writer2 = writer1.mapWritten(_.map(_.toUpperCase))

// writer2: cats.data.WriterT[cats.package.Id, Vector[String], Int] = WriterT(

// (Vector("A", "B", "C", "X", "Y", "Z"), 42)

// )

writer2.run

// res4: (Vector[String], Int) = (Vector("A", "B", "C", "X", "Y", "Z") , 42)


Podemos transformar tanto el log como el resultado simultáneamente usando bimap o mapBoth. bimap toma dos parámetros de función, uno para el registro y otro para el resultado. mapBoth toma una sola función que acepta dos parámetros:


val writer3 = writer1.bimap(

    log => log.map(_.toUpperCase),

    res => res * 100

)

// writer3: cats.data.WriterT[cats.package.Id, Vector[String], Int] = WriterT(

//(Vector("A", "B", "C", "X", "Y", "Z"), 4200)

// )

writer3.run

// res5: (Vector[String], Int) = (Vector("A", "B", "C", "X", "Y", "Z"), 4200)

val writer4 = writer1.mapBoth { (log, res) =>

    val log2 = log.map(_ + "!")

    val res2 = res * 1000

    (log2, res2)

}

// writer4: cats.data.WriterT[cats.package.Id, Vector[String], Int] =WriterT(

//(Vector("a!", "b!", "c!", "x!", "y!", "z!"), 42000)

// )

writer4.run

// res6: (Vector[String], Int) = (

//Vector("a!", "b!", "c!", "x!", "y!", "z!"),

//42000

// )


Finalmente, podemos borrar el registro con el método de reinicio e intercambiar el registro y el resultado con el método de intercambio:


val writer5 = writer1.reset

// writer5: cats.data.WriterT[cats.package.Id, Vector[String], Int] = WriterT(

//(Vector(), 42)

// )

writer5.run

// res7: (Vector[String], Int) = (Vector(), 42)

val writer6 = writer1.swap

// writer6: cats.data.WriterT[cats.package.Id, Int, Vector[String]] = WriterT(

//(42, Vector("a", "b", "c", "x", "y", "z"))

// )

writer6.run

// res8: (Int, Vector[String]) = (42, Vector("a", "b", "c", "x", "y","z"))

lunes, 18 de julio de 2022

Cualidades clave de Kotlin


Estáticamente tipado
: al igual que Java, Kotlin es un lenguaje de programación con tipos estáticos. Esto significa que el tipo de cada expresión en un programa se conoce en el momento de la compilación, y el compilador puede validar que los métodos y campos a los que intenta acceder existen en los objetos que está utilizando. Esto contrasta con los lenguajes de programación tipificados dinámicamente, que están presentes en la JVM, entre otros, Groovy, Clojure y JRuby. Esos lenguajes le permiten definir variables y funciones que pueden almacenar o devolver datos de cualquier tipo y resolver las referencias de métodos y campos en tiempo de ejecución. Esto permite un código más corto y una mayor flexibilidad en la creación de estructuras de datos. Pero la desventaja es que los problemas como los nombres mal escritos no se pueden detectar durante la compilación y pueden provocar errores de tiempo de ejecución.

Por otro lado, a diferencia de Java, Kotlin no requiere que especifiques el tipo de cada variable explícitamente en tu código fuente. En muchos casos, el tipo de una variable se puede determinar automáticamente a partir del contexto, lo que le permite omitir la declaración de tipo. Aquí está el ejemplo más simple posible de esto:

val x = 1

Estás declarando una variable y, como se inicializa con un valor entero, Kotlin determina automáticamente que su tipo es Int. La capacidad del compilador para determinar tipos a partir del contexto se denomina inferencia de tipos.

Los siguientes son algunos de los beneficios del tipado estático:

  • Rendimiento: llamar a los métodos es más rápido porque no es necesario averiguar en tiempo de ejecución qué método debe llamarse.
  • Confiabilidad: el compilador verifica la corrección del programa, por lo que hay menos posibilidades de fallas durante el tiempo de ejecución.
  • Capacidad de mantenimiento: trabajar con código desconocido es más fácil porque puede ver con qué tipo de objetos está trabajando el código.
  • Compatibilidad con herramientas: la escritura estática permite refactorizaciones confiables, finalización de código precisa y otras características de IDE.

Gracias a la compatibilidad de Kotlin con la inferencia de tipos, la mayor parte de la verbosidad adicional asociada con la escritura estática desaparece porque no es necesario declarar los tipos explícitamente.

Si observa los detalles del sistema de tipos de Kotlin, encontrará muchos conceptos familiares. Las clases, las interfaces y los genéricos funcionan de manera muy similar a Java, por lo que la mayor parte de su conocimiento de Java debería transferirse fácilmente a Kotlin. Sin embargo, algunas cosas son nuevas.

El más importante de ellos es el soporte de Kotlin para tipos anulables, lo que le permite escribir programas más confiables al detectar posibles excepciones de puntero nulo en el momento de la compilación. 

Otra cosa nueva en el sistema de tipos de Kotlin es su soporte para tipos de funciones. Para ver de qué se trata, veamos las ideas principales de la programación funcional y veamos cómo se admite en Kotlin.

Programación funcional y orientada a objetos: Como desarrollador de Java, sin duda estamos familiarizado con los conceptos básicos de la programación orientada a objetos, pero la programación funcional puede ser nueva para desarrolladores Java. Los conceptos clave de la programación funcional son los siguientes:

  • Funciones de primera clase: Puede almacenar funciones en variables, pasarlos como parámetros o devolverlos desde otras funciones.
  • Inmutabilidad: trabaja con objetos inmutables, lo que garantiza que su estado no puede cambiar después de su creación.
  • Sin efectos secundarios: utiliza funciones puras que devuelven el mismo resultado dadas las mismas entradas y no modifican el estado de otros objetos ni interactúan con el mundo exterior.

¿Qué beneficios puede obtener al escribir código en el estilo funcional? Primero, concisión. El código funcional puede ser más elegante y sucinto en comparación con su contraparte imperativa, porque trabajar con funciones como valores le brinda mucho más poder de abstracción, lo que le permite evitar la duplicación en su código.

Imagine que tiene dos fragmentos de código similares que implementan una tarea similar (por ejemplo, buscar un elemento coincidente en una colección) pero difieren en los detalles (cómo se detecta el elemento coincidente). Puede extraer fácilmente la parte común de la lógica en una función y pasar las partes diferentes como argumentos. Esos argumentos son en sí mismos funciones, pero puede expresarlos usando una sintaxis concisa para funciones anónimas llamadas expresiones lambda:

fun findAlice() = findPerson { it.name == "Alice" }

fun findBob() = findPerson { it.name == "Bob" }

El segundo beneficio del código funcional es el subprocesamiento múltiple seguro. Una de las mayores fuentes de errores en los programas de subprocesos múltiples es la modificación de los mismos datos de varios subprocesos sin la sincronización adecuada. Si usa estructuras de datos inmutables y funciones puras, puede estar seguro de que tales modificaciones inseguras no ocurrirán y no necesita idear esquemas de sincronización complicados.

Finalmente, la programación funcional significa pruebas más fáciles. Las funciones sin efectos secundarios se pueden probar de forma aislada sin necesidad de una gran cantidad de código de configuración para construir todo el entorno del que dependen.

En términos generales, el estilo funcional se puede usar con cualquier lenguaje de programación, incluido Java, y muchas partes del mismo se recomiendan como un buen estilo de programación. Pero no todos los lenguajes brindan el soporte sintáctico y de biblioteca necesario para usarlo sin esfuerzo; por ejemplo, este soporte faltaba en su mayoría en las versiones de Java anteriores a Java 8. Kotlin tiene un amplio conjunto de características para admitir la programación funcional desde el principio. Estos incluyen lo siguiente:

  • Tipos de funciones, que permiten que las funciones reciban otras funciones como parámetros o devuelvan otras funciones
  • Expresiones lambda, que le permiten pasar bloques de código con un mínimo de repeticiones
  • Clases de datos, que proporcionan una sintaxis concisa para crear objetos de valor inmutable
  • Un amplio conjunto de API en la biblioteca estándar para trabajar con objetos y colecciones en el estilo funcional

Kotlin le permite programar en el estilo funcional pero no lo impone. Cuando lo necesite, puede trabajar con datos mutables y escribir funciones que tienen efectos secundarios sin tener que pasar por obstáculos adicionales. Y, por supuesto, trabajar con marcos que se basan en interfaces y jerarquías de clases es tan fácil como con Java. Al escribir código en Kotlin, puede combinar los enfoques funcional y orientado a objetos y utilizar las herramientas más apropiadas para el problema que está resolviendo.

Gratuito y open source: El lenguaje Kotlin, incluido el compilador, las bibliotecas y todas las herramientas relacionadas, es completamente de código abierto y de uso gratuito para cualquier propósito. Está disponible bajo la licencia Apache 2; el desarrollo ocurre abiertamente en GitHub (http://github.com/jetbrains/kotlin), y las contribuciones de la comunidad son bienvenidas. También puede elegir entre tres IDE de código abierto para desarrollar sus aplicaciones de Kotlin: IntelliJ IDEA Community Edition, Android Studio y Eclipse son totalmente compatibles. (Por supuesto, IntelliJ IDEA Ultimate también funciona).

Apis en diferentes lenguajes y frameworks en la plataforma Java


Estoy haciendo una aplicación con n microservicios en n tipos de tecnologías y lenguajes todos en la plataforma Java. 

Los de n tipos de tecnologías es mentiroso solo 2 framework use por ahora Spring boot y micronaut y a decir verdad use un 80% de spring boot pero quiero escribir un post tipo draft, por las dudas si me canso y nunca termino. 

Por ende, vamos a ver como me fue con Spring boot y diferentes lenguajes y luego hablo de micronaut. 

Java: Bueno, esta es la tupla más utilizada y creo que ustedes saben que anda muy bien. No sé si puedo agregar algo más que no sepan. 

Kotlin: Me encanto, por varias razones me parece mejor que java. Kotlin es un lenguaje, muy bueno y muy compatible con java lo que lo hace una opción super fácil de usar y no se sufre nada con la compatibilidad con spring boot. 

Groovy: Igual que Java, no encuentro una buena razón para elegir este lenguaje, esta bueno, pero el tipado dinamico, no ofrece mayor ventaja y si lo usamos con tipando estático, es similar a java o kotlin. 

Scala: Un infierno de incompatibilidad, no le recomiendo utilizar spring boot con scala, tenes que estar siempre cambiando tipos, de tipos de Scala a Java y de Java a Scala. No es una opción práctica...

Clojure: Otro infierno, no solo por los tipos, sino tambien por la generación de clases con anotaciones. Muy trabajoso, al final cuando te funciona una Api, no te acordas para que la querías. 

Micronaut lo utilice muy poco con Groovy y Java y me fue muy bien, casi casi puedo decir que me gusta más que spring boot. Y ahora sigo con Micronaut y Quarkus. 

sábado, 16 de julio de 2022

Por qué usar Kotlin?


El objetivo principal de Kotlin es proporcionar una alternativa a Java más concisa, más productiva y más segura que sea adecuada en todos los contextos en los que se usa Java en la actualidad. Java es un lenguaje extremadamente popular y se usa en una amplia variedad de entornos, desde tarjetas inteligentes (tecnología de tarjeta Java) hasta los centros de datos más grandes administrados por Google, Twitter, LinkedIn y otras empresas. En la mayoría de estos lugares, el uso de Kotlin puede ayudar a los desarrolladores a lograr sus objetivos con menos código y menos molestias en el camino.

Las áreas más comunes para usar Kotlin son:

  • Creación de código del lado del servidor (normalmente, backends de aplicaciones web)
  • Creación de aplicaciones móviles que se ejecutan en dispositivos Android

Pero Kotlin también funciona en otros contextos. Por ejemplo, puede usar Intel Multi-OS Engine (https://software.intel.com/en-us/multi-os-engine) para ejecutar código Kotlin en dispositivos iOS. Para crear aplicaciones de escritorio, puede usar Kotlin junto con TornadoFX (https://github.com/edvin/tornadofx) y JavaFX.1

Además de Java, Kotlin se puede compilar en JavaScript, lo que le permite ejecutar el código de Kotlin en el navegador.

El objetivo de Kotlin es bastante amplio. Kotlin no se enfoca en un solo dominio de problema ni aborda un solo tipo de desafío que enfrentan los desarrolladores de software en la actualidad. En su lugar, proporciona mejoras de productividad generales para todas las tareas que surgen durante el proceso de desarrollo. Y brinda un excelente nivel de integración con bibliotecas que admiten dominios específicos o paradigmas de programación. 

viernes, 15 de julio de 2022

[Whitepaper] Speed vs. Security: Protecting Modern Apps and APIs at the Pace of Modern Business

 

WHITEPAPER

https://interact.f5.com/rs/653-SMC-783/images/WP - Speed vs. Security Protecting Modern Apps and APIs at the Pace of Modern Business - 760x284.png

Hi Emanuel,

Customers, partners, and employees do not just demand the most from your technology-driven services, they expect it. DevOps, microservices, and containers can all help to deliver this much sought-after application agility. In this whitepaper you will learn that by integrating security early into the development process – shifting left – your organization can achieve both application and API agility and security, driving innovation while staying ahead of the competition.

In this whitepaper you will learn:

  • Why traditional security approaches are no longer suitable for your modern apps and APIs
  • Methods hackers use to target web applications, with 40% of attacks coming through APIs
  • How to achieve application speed and agility to ensure your business provides customers with the best possible experience
  • About integrating security early into the development lifecycle and automating policy so your business can remove bottlenecks, support shift left DevOps initiatives, and accelerate app velocity

martes, 12 de julio de 2022

Mónadas en Cats parte 17

cats.data.Writer es una mónada que nos permite llevar un registro junto con un cálculo. Podemos usarlo para registrar mensajes, errores o datos adicionales sobre un cálculo y extraer el registro junto con el resultado final.

Un uso común para Writers es registrar secuencias de pasos en cálculos de subprocesos múltiples donde las técnicas de registro imperativas estándar pueden generar mensajes intercalados de diferentes contextos. Con Writer, el registro para el cálculo está vinculado al resultado, por lo que podemos ejecutar cálculos simultáneos sin mezclar registros.

Un Writer[W, A] tiene dos valores: un registro de tipo W y un resultado de tipo A. Podemos crear un Writer a partir de valores de cada tipo de la siguiente manera:


import cats.data.Writer

import cats.instances.vector._ // for Monoid

Writer(Vector("It was the best of times","it was the worst of times"), 1859)

// res0: cats.data.WriterT[cats.package.Id, Vector[String], Int] = WriterT(

// (Vector("It was the best of times", "it was the worst of times"), 1859)

// )


Tenga en cuenta que el tipo informado en la consola es en realidad WriterT[Id, Vector[String], Int] en lugar de Writer[Vector[String], Int] como cabría esperar. En el espíritu de la reutilización de código, Cats implementa Writer en términos de otro tipo, WriterT. WriterT es un ejemplo de un nuevo concepto llamado transformador de mónadas, que trataremos más adelante

Tratemos de ignorar este detalle por ahora. Writer es un alias de tipo para WriterT, por lo que podemos leer tipos como WriterT[Id, W, A] como Writer[W, A]:

type Writer[W, A] = WriterT[Id, W, A]

Para mayor comodidad, Cats proporciona una forma de crear Writers especificando solo el registro o el resultado. Si solo tenemos un resultado, podemos usar la sintaxis pure estándar. Para hacer esto, debemos tener un Monoid[W] en el alcance para que Cats sepa cómo producir un registro vacío:

import cats.instances.vector._ // for Monoid

import cats.syntax.applicative._ // for pure

type Logged[A] = Writer[Vector[String], A]

123.pure[Logged]

// res1: Logged[Int] = WriterT((Vector(), 123))

Si tenemos un registro y ningún resultado, podemos crear un Writer[Unit] usando la sintaxis tell de cats.syntax.writer:

import cats.syntax.writer._ // for tell

Vector("msg1", "msg2", "msg3").tell

// res2: Writer[Vector[String], Unit] = WriterT(

// (Vector("msg1", "msg2", "msg3"), ())

// )

Si tenemos un resultado y un registro, podemos usar Writer.apply o podemos usar la sintaxis de Writer de cats.syntax.writer:

import cats.syntax.writer._ // for writer

val a = Writer(Vector("msg1", "msg2", "msg3"), 123)

// a: cats.data.WriterT[cats.package.Id, Vector[String], Int] = WriterT(

// (Vector("msg1", "msg2", "msg3"), 123)

// )

val b = 123.writer(Vector("msg1", "msg2", "msg3"))

// b: Writer[Vector[String], Int] = WriterT(

// (Vector("msg1", "msg2", "msg3"), 123)

// )

Podemos extraer el resultado y el registro de un Writer utilizando los métodos de valor y escrito respectivamente:

val aResult: Int = a.value

// aResult: Int = 123

val aLog: Vector[String] =a.written

// aLog: Vector[String] = Vector("msg1", "msg2", "msg3")

Podemos extraer ambos valores al mismo tiempo usando el método de ejecución:

val (log, result) = b.run

// log: Vector[String] = Vector("msg1", "msg2", "msg3")

// result: Int = 123