sábado, 12 de enero de 2013

Lo que amo de Scala: su cercanía a Java

Estoy en el proceso de registrar lo indispensable de Scala para el día que mire seriamente a otros lenguajes  "Mirar seriamente" es hacer un poco más que leer un tutorial y programar un "hello world", o sea demanda algo de esfuerzo.  No tengo el tiempo de revisar todos los lenguajes que se inventan así que debo filtrar los potenciales candidatos.  Por el momento, son Kotlin, Ceylon e Xtend porque todos comparten la cercanía con Java.

Esta cercanía con Java es importante por varias razones.

Por la JVM, los servidores de aplicación y en general los middleware basados en la JVM

No todos tenemos la suerte de trabajar para una startup que puede escoger completamente su arquitectura y, por ende, debemos negociar con el cliente la tecnología que se usará.  Casi todos los clientes tienen una plataforma definida y resulta más o menos difícil alterarla según lo que esta definición cubre.

Casi siempre, la definición de plataforma incluye la arquitectura física (servidores, redes, sistemas operativos, estaciones clientes) y la arquitectura de ejecución, o sea los middleware como los servidores de aplicación, servidores de mensajería y las bases de datos.  Es muy frecuente poder usar un middleware basado en la JVM

Otras veces la definición de plataforma incluye la arquitectura de desarrollo o sea, los lenguajes, las API, los frameworks, patrones y hasta el IDE de desarrollo.  En este caso, si el cliente pide Java+Spring-*, hay que tratar de convencerlo.  En la practica, es más fácil negociar cambiar la arquitectura de desarrollo que las arquitecturas físicas y de ejecución.

En resumen, la JVM y sus middleware (Tomcat, Websphere, Weblogic) son importantes por un tema de oportunidad laboral   

He leído que otros destacan la robustez, el performance, la seguridad y en general, la madurez de la JVM.  Estoy de acuerdo con estos argumentos y son las razones por las cuales, hay middleware basados en la JVM en todas partes.

Por las toneladas de API's y framework para Java

La popularidad de Java permite que haya soluciones para todo y a menudo de bajo costo.  No recuerdo cuando fue la ultima vez que me preocupe de encontrar un driver JDBC compatible con la versión de mi base de datos: no quiero pasar por lo mismo si me salgo de la JVM.

Poco a poco, hay API y framework que son optimizados para Scala, pero siempre habrá necesidades de usar esta vieja API Java que saca de apuro.

Por la sintaxis

Java hereda muchas ideas archi probadas en distintos lenguajes y que son familiares para muchos programadores.  Scala sigue usando:
  • la sintaxis básica de C usando bracket y donde una llamada a una función "f" se escribe como en las matemáticas básicas: "y = f (x)"
  • strong typing.  Me gusta que el compilador y el IDE trabajen por mi y no al revés
  • orientación al objeto.  Definitivamente no es la solución para todo, pero es necesario tenerla.
  • programación genérica. Hace el código más legible.
  • estilo imperativo.  No siempre se puede programar al estilo funcional en forma elegante.  El estilo imperativo saca de apuros, lo tengo comprobado.

Por los entornos de programación

Es tiempo ganado si no tengo que cambiar mi IDE (Netbeans, Eclipse), mi build automation (ant, maven), etc.

Lista de lenguajes que descarte

Todos los criterios anteriores me hicieron descartar:
  • los derivados de Lisp como Scheme, Clojure.  No hay ninguna razón para mantener una sintaxis que va contra años de enseñanza de las matemáticas.  Yo creo que usar estos lenguajes para tutoriales de programación funcional crea una barrera completamente absurda.
  • Ruby, Python: son dinámicos, su entorno "natural" no es la JVM.
  • Haskell, Erlang: no corren sobre la JVM y su sintaxis me recuerda demasiado a Lisp.
  • fantom: no tiene programación genérica.





Lo que me agrada de Scala: de NPE a Option

Sigo poblando mi lista de lo que me gusta del lenguaje Scala.  La motivación es poder comparar con otros lenguajes parecidos que están llegando para la JVM como Ceylon/Kotlin/Xtend y tener claro lo que tienen que ofrecer estos lenguajes para que valga la pena mirarlos con un poco más de detalle.  En este contexto, cabe mencionar esta encuesta de Infoq donde hay una lista de lenguajes potenciales y donde Scala y Clojure están bien posicionados.

Los títulos anteriores de mis entradas sobre el mismo tema empezaban con "Lo que amo de Scala".  Ahora voy a hablar de algo que solamente me agrada.

Donde Scala se contagia de Java

NullPointerException o NPE existen porque cualquier objeto en la JVM puede tener el valor null.  No hay forma en Java garantizar que un objeto es distinto de null excepto validandolo antes de referenciarlo.  Si se valida en forma paranoica todos los parámetros de entrada  y retornos de los métodos, se agrega mucho código bastante inútil.  La otra solución es no validar nada y capturar la NPE lo más inteligentemente posible. Si se opta por no validar, en algún momento aparecerá el NPE en algún log y ojala antes de entrar en producción.

Scala corre sobre la JVM e necesita interoperar con código Java.  Sigue existiendo el valor null y la posibilidad de NPE incluso en código 100% Scala.


Valores opcionales

Java no permite hacer la distinción entre un objeto que es nulo por error o intencionalmente sin valor.  Un objeto puede estar sin valor:
  • porque es naturalmente opcional, como el calculo de un valor máximo sobre una colección vacía o el retorno de una consulta por una primary key que no existe.
  • porque no conocemos aun su valor:
    • hay que rescatarlo con algún proceso largo, 
    • es un valor externo que debemos rescatar de parámetros de ambiente, archivos de configuración o preguntar al usuario.
En Java se puede manejar estas situaciones con objetos nulos o lanzando excepciones.  En SQL se puede definir un campo como "NULL" o "NOT NULL".  Scala soluciona este caso con el tipo Option y los subtipos None y Some.

Ejemplo de un atributo que es opcional y cuyo valor se conoce al runtime.


Un caso frecuente en mis aplicaciones es durante la inicialización de actores con el framework Akka.  Generalmente, los actores se crean en unos pocos thread y si su inicialización es larga (por ejemplo, porque tienen que rescatar algo de una base de datos) el arranque de la aplicación akka es lenta.  Entonces, el arranque del actor se hace en 2 pasos: la creación del actor mismo y luego su inicialización procesando un mensaje de "arranque".  Entre estos 2 pasos hay atributos del actor que no están conocidos aun.


Algunos comentarios finales

Entonces, porque solamente me agradan los Option y no los adoro:
  • Habría sido espectacular eliminar el valor nulo y la NPE por completo.  Pero prefiero mil veces mantener la interoperabilidad con Java, la cual si adoro.
  • Ceylon y Kotlin tienen una sintaxis especial para manejar los nulos la cual permite código más corto y más legible.  Scala no usa sintaxis especial, sino la capacidad de su type system.  El mismo type system permite implementar tipos equivalentes como los Box/Full/Empty/Failure del framework Liftweb .
En resumen, Scala mejora Java sin erradicar por completo el problema.  

domingo, 11 de noviembre de 2012

Lo que amo de Scala: los tuples

Tengo una relación de amor y odio con los tuples. Los adoro cuando escribo código por primera vez y los odio cuando vuelvo a leer el código más tarde.  Son, por lejos, lo que me hace más difícil entender mi propio código.  Igual los uso a cada rato porque son demasiado prácticos.

En Scala, Java y cualquier lenguaje tipeado es fácil agregar un parámetro de entrada a un método.  Se define el nuevo parámetro y se deja el IDE o el compilador detectar todos los usos del método que fueron quebrados.  Los tuples me permiten exactamente lo mismo pero con el parámetro de salida.

Como ejemplo, 2 versiones de un método supuestamente complejo: evaluación de riesgo de un cliente  La primera versión solamente retorna un boolean que indica si el cliente es demasiado riesgoso
En la siguiente versión, el método calcula el riesgo usando varios criterios y se requiere retornar un mensaje que indica el porque.

Si no existiesen los tuples, tendría que definir una clase para contener el retorno.  A pesar que en Scala, crear un "case class" es rápido, tengo que por lo menos escoger un nombre para la clase.  Y, es en este preciso momento que adoro los tuples: cuando estoy pensando en un algoritmo no trivial mi capacidad creativa para nombrar las clases, objetos y variables tiende a cero.  Si tengo que detener mi pensamiento para nombrar correctamente la clase, evaluar si puedo re-utilizarla en otra situación, si debo hacerla más genérica, etc, pierdo completamente el hilo del algoritmo que estoy resolviendo.  Los tuples son una forma rápida de salirme del paso y enfocarme en la parte "matemática" del problema.

Los tuples son perfectos cuando uso el resultado del método localmente. Los problemas de mantenebilidad surgen cuando tengo que guardar los tuples en alguna colección y procesarla en otra parte del código. Cuando eso ocurre, tengo que hacer un refactoring y por eso los odio.


viernes, 2 de noviembre de 2012

Lo que amo de Scala: el poder (casi siempre) fácil de usar

Supongo que crear un lenguaje poderoso y al mismo tiempo fácil de usar, es una tarea compleja.  Cuando los creadores de Scala tienen que eligir, prefieren priorizar el poder.  Yo me alegro por eso.

Estoy consciente que la estrategia de Scala no es una necesariamente ganadora.   Se puede argumentar que parte del éxito de Java es debido a su simplicidad inicial.  Muchos competidores de Scala (como Ceylon y Kotlin), usan el argumento de "Scala es complejo" para tratar de ganarle terreno: básicamente, tratan de describir Scala como un lenguaje académico que contiene montones de ensayos que no se juntan perfectamente. Y Scala se ha ganado una imagen de elitista que primero busca satisfacer a los mejores programadores, como los creadores de framework, en detrimento del programador promedio.

Para mi no hay duda, yo prefiero el "poder" y estoy dispuesto a invertir un poco más de tiempo para manejarlo en forma responsable.  Voy a usar para argumentar, el "operator overloading", la implementación de la programación genérica y las conversiones implícitas.  Estas 3 técnicas son generalmente reconocidas como peligrosas o complejas.  Ademas puedo usar Java como referencia para argumentar.


Operator overloading

Java escogió no soportar "operator overloading".  El argumento inicial era que varias bibliotecas C++ (lenguaje donde existe esta capacidad) habían abusado tanto, que son responsables de fuentes que parecen una sopa de símbolos.  Java decidió proteger a los programadores de si mismo.

Yo siento que Java me trata como un bruto que, a pesar de estar informado de los potenciales riesgos, se va a dedicar generar código incomprehensible por el puro hecho que lo puede hacer.  Me parece que es mucho mejor permitir el "operator overloading" e implementar las bibliotecas básicas del lenguaje como una muestra de las buenas practicas.  Y Scala cumple con eso.

El primer ejemplo es la API colección, donde se usa "::" para agregar un elemento a una lista.  


El mismo ejemplo en Java



Otro ejemplo es la "combinator libary" que permite crear un DSL externo.

Una vez que uno se acostumbra a como funciona esta biblioteca, la interpretación de los símbolos "|", "~", "~>", "<~" y "^^" es inmediata y la sintaxis del DSL salta a la vista.

Entonces, ahora cuando veo un símbolo que no entiendo, yo se que no es el símbolo en si el problema, sino que me falta entender bien el concepto o la abstracción que representa.  Una vez que leí la documentación y luego de un poco de practica, el símbolo llega a ser casi invisible y me deja ver el código.  Al contrario, una palabra siempre atraerá la atención y ofuscara el código.  Entonces, luego de una pequeña curva de aprendizaje, el código queda mucho mas limpio y fácil de entender si se usan símbolos adecuadamente.

En este caso, el poder y la simplicidad de uso van de la mano: no hay ninguna razón para no incluir el operator overloading.

Nota: cabe señalar que Scala no tiene "operator overloading" en si, sino que es muy liberal en como nombrar las funciones y métodos.


Programación genérica y herencia

Java decidió no implementar la programación genérica hasta la versión 1.5.  No obstante tomo una decisión clave en su versión 1.0 con respecto a la herencia y los arreglos: si un String es un Object entonces, un arreglo de String es también un arreglo de Object.  Intuitivo pero incorrecto.


La implementaciòn de la programación genérica en Java desde la versión 1.5, no sigue el mismo patrón que los arreglos.  Una decisión que parecía intuitiva y simple, se transformo en una complicación: un arreglo es lógicamente una colección, pero en Java no lo es.

Scala en comparación decidió implementar los conceptos de covariance y contravariance.  Algunas veces, el compilador parece reclamar demasiado y prohibir código "correcto".   Hay que leer y entender la justificación de porque se comporta así, lo que hace el aprendizaje un poco más largo.

En mi caso, cuando me toco implementar un algoritmo de la teoría de los grafos donde los vértices y nodos eran genéricos, recupere el tiempo invertido.


Implicit conversion

Scala usa inplicit en varias partes.  Me voy a referir a las conversiones implícitas porque se parecen al autoboxing de Java el cual convierte un tipo primitivo a un objeto que lo encapsula, como por ejemplo un int a un Integer.


El poder de las conversiones implícitas de Scala no esta en duda.

No voy a olvidar cuando vi algo como el ejemplo anterior: primero pensé que Scala estaba imitando la sintaxis de Visual Basic.  No me gusto mucho la idea.  Luego descubrí que "to" en "0 to 10" es un método común y corriente pero no esta en la clase Scala.Int sino que en  la clase RichInt.  Este método retorna un rango sobre el cual itera la sintaxis "for".  Para que funcione, tiene que haber una conversión automática desde el Scala.Int 0 a RichInt.  Para eso, existen las conversiones implícitas 

Como en el autoboxing de Java, el peligro es que algo que se ve de un cierto tipo se comporta como otro al momento de ejecutar.

Ademas, Scala permite al programador definir sus propias conversiones implícitas.y obliga importar la definición del implicit para usarla.  Eso rompe muchas veces el "Google-copy-paste" porque es frecuente encontrar micro-ejemplos sin los import necesarios y copiar un código que no compila por una razón misteriosa.  Este ultimo problema se ha mitigado gracias a mejores mensajes del compilador (aunque a veces muy largos) y el mejor soporte en IDE.

Finalmente, para demostrar el super poder de las conversiones implícitas  es bueno mirar su uso en internal DSL como camel Scala DSL y compararlo con el camel Java DSL


Conclusión

En los tres casos mencionados anteriormente, el poder de Scala implica una curva de aprendizaje.  En caso de "operator overloading" se recupera inmediatamente y rápidamente con las conversiones implícitas, (basta usar una API diseñada como internal DSL),  En caso de la programación genérica me demando implementar un algoritmo no trivial para darme cuenta que Scala estaba en lo correcto.  Y fuera de estos 3 ejemplos, no he encontrado todavía alguna característica del lenguaje cuya curva de aprendizaje sea mayor al poder que otorga.

lunes, 15 de octubre de 2012

Lo que amo de Scala: las colecciones

Primera entrada en la serie de lo que me gusta de Scala.  Ojo que no pretendo escribir un tutorial, solamente explicar porque me gusta y que me permite hacer.  Ojo 2: no se cuales otros lenguajes permiten implementar lo mismo, solamente puedo comparar con Pascal, Fortran, C, C++, PL-SQL, Shell script, Javascript y Java.

El código fuente de las colecciones de Scala tiene la reputación de ser complejo.  Se supone que usan teorías algébricas esotéricas como Category Theory que no son para el común de los mortales.  Algún día me daré el tiempo de investigar más sobre el tema, pero mientras tanto, se que se puede hacer maravillas con ellas en forma simple.

Básicamente, son como tener el poder de SQL sin tener que ir y volver a la base de datos.  Los siguientes extractos comparan código Scala con SQL.


Ahora no dudo en llevar datos en memoria y procesarlos fuera de la BD.  Obtengo mejoras en rendimiento y mejoras en mantenibilidad usando un solo lenguaje y eliminando el código de ida a vuelta a la BD

Scala vs otros "next java"

Kotlin, Ceylon e Xtend son 3 lenguajes que están en la misma liga que Scala
  • basados en la JVM,
  • adoptan algo de programación funcional sin renunciar a la OOP,
  • tratan de evitar algunos errores de Java,
  • mantienen la programación genérica y el static typing.
El hecho que estos lenguajes existen demuestran que hay una necesidad.  Java se estanco y, si se destraba el avance de algunas JSR como el project lambda para Java 8, es probable que la sintaxis de Java termine muy compleja.

Una guerra de lenguajes siempre es entretenida, así que empece a mirarlos.  Me fue difícil intuir como serán cada lenguaje sin ver ejemplos avanzados y todos los micro ejemplos se ven bien.  Así que empece a evaluar primero los aspectos no técnicos, poniéndoles notas y publicando mis resultados en G+ y en ingles.  El resumen es:
El resumen del resumen es que estos lenguajes llegan muy tarde y tendrán que superar bastante a Scala para encontrarse un nicho.  Pueden superar a Scala de varias formas, siendo más simples y abordables por un programador Java promedio, con mejor soporte en IDE, creando una comunidad muy entusiasta, etc.

Al final, decidí no dedicar tiempo tratando de implementar una aplicación real con cada uno de ellos. Lo que si tengo pendiente, es listar lo que me gusta de Scala y lo que necesito que otros lenguajes igualen o superen.   Este tema me da para varias entradas en mi blog resucitado.

sábado, 13 de octubre de 2012

De la TI empresa a la TI para el consumidor

Ahora que re-anime este blog, aprovecho leer mis antiguos post y no puedo dejar de notar como ha cambiado mi visión del mercado de las TI.

Hace 2-3 años atrás, le daba mucha importancia al rol de los proveedores de la TI empresarial como Oracle, Sun, IBM, Adobe, Microsoft, jBoss y SpringSource.  Trataba de analizar el futuro de sus productos como ESB, bases de datos y servidores de aplicación.  Me gustaba predecir como evolucionaran sus tecnologías como JavaFx, Silverlight, Flash, XML, BPEL, SQL.

Ahora, estoy completamente convencido que si se quiere mirar el futuro de la TI, no hay que mirar a estos proveedores y sus tecnologías.  Básicamente porque cambio el negocio y se quedaron en el pasado.

Hace 30 años, la TI era para empresas y los usuarios de los sistemas eran los empleados de estas empresas.  Con la web, despego la TI para el consumidor final y nacieron empresas como Google, Amazon, eBay, Twitter y Facebook.  Con la llegada del móvil, la TI para consumidor final ahora supera la "vieja" TI para empresas.

Un ejemplo claro es Apple que casi muere en los 90 y ahora es la más valiosa en la bolsa.  La razón de ser de Apple nunca fue la TI empresarial y no pudo competir con IBM y Microsoft en los 90. Ahora, Apple esta en su zenit con sus iPhone e iPad.

Entonces, ahora miro que hace Twitter, Facebook, Google, Amazon y Apple.  A pesar que algunos no son proveedores de TI, son los que marcan el pulso de este mercado.