Retrospectiva de 2016

Finaliza un nuevo año y es hora de mirar hacia atrás para visualizar el camino recorrido. Este año sin dudas ha sido el menos «productivo». Prueba de ello es que este es el primer y último post del año.

Repositorios y código

También es testigo de esto Github que sigue listando casi los mismos repositorios del año pasado con poquísimas excepciones:

  • Open.NAT sigue siendo mantenido a duras penas y solo corrijo algunos defectos. El hecho que existan productos exitosos que utilicen esta librería, y el que sea mi proyecto con más «stars», me fuerza a mantenerla viva y dar soporte. Por desgracia cada router implementa el protocolo IGD como se le canta y eso hace que algo tan sencillo como Open.NAT reciba reporte de errores más de lo deseado.
  • Open.HttpProxy es un proyecto que comencé (hace mucho) con la idea implementar soluciones de seguridad y tareas comúnmente implementadas mediante reverse proxies. No la he tocado en meses pero pienso hacerlo cuando encuentre el tiempo. Este proyecto es el que más me ha enseñado técnicamente hablando. He aprendido sobre IP, TCP, HTTP, FTP y WebSocket lo que llevaría años de lectura, lo mismo con los sockets y sus diferentes implementaciones en .NET, el manejo de memoria que requieren, los pros y contras de async/await en lo que performance se refiere y un larguísimo listado de etcéteras.
  • Dragonchain es una plataforma basada en el patrón blockchain diseñada por la gente de Tecnologías Avanzadas de Disney en la cual estuve contribuyendo mientras el repositorio era privado. No obstante, una vez abierto no he continuado ayudando allí por cuanto existen mejores proyectos relacionados en los que prefiero contribuir con mi tiempo.
  • PyChainpoint es una librería Python para validar recibos de datos con timestamps en una blockchain, típicamente la de bitcoin. Me ayudó a aprender algo de python.
  • MerkleTools es una librería .NET para la creación merkle trees y validación de recibos chainpoint. Esto es para probar criptográficamente la existencia de algo.
  • NBitcoin es una librería para programar Bitcoin con .NET. Esta librería no es mia pero es por lejos la más activa y con mayor potencial en el ámbito .NET y además su creador es uno de los tipos más inteligentes que he conocido en toda mi vida así que se siente muy bien contribuir. Además, con solo 68 commits, 4757 linea agregadas y 7101 lineas eliminadas soy el primer contribuyente del proyecto, luego de su creador obviamente.
  • BitcoinLite es mi librería Bitcoin para .NET. Es una ultra-pequeña librería enfocada a ser utilizada «del lado del cliente» (expresión extraña para una tecnología peer-to-peer). Tengo un inmenso push que hacer pronto. La idea es aprender el protocolo Bitcoin y la criptografía asociada al más mínimo detalle.

Artículos

En cuanto a escribir artículos, lo único que he escrito es un artículo en codeproject.com: Bitcoin Traffic Sniffer and Analyzer el cual muestra a nivel de código cómo, en el contexto de ECDSA, pueden obtenerse las claves privadas para debloquear bitcoins a partir de las firmas digitales de transacciones que reutilizan un número r el cual debería ser aleatorio.

Lenguajes

He aprendido algo de Python este año. La verdad es que siempre supe que era un buen lenguaje y podía entender su sintaxis sin más trámite pero nunca había escrito más que un par de scripts de prueba, hoy debo decir que es un lenguaje fabuloso.

He querido aprender Rust y Elixir pero me ha sido realmente difícil, sobre todo Elixir. Claramente se me viene atrofiando el cerebro. Por otro lado, no iba a programar más en .NET pero me tira mucho Visual Studio, R# y casi 14 años de .NET encima. Creo que seguiré aprendiendo Python y volveré a C++, de esa manera con Javascript, C#, Python y C++ voy a donde quiero.

Aprendizaje

Este año he continuado aprendiendo sobre Bitcoin,  bastante matemática, criptografía de curva elípica (ECC), firmas digitales, matemática modular, algoritmos de hashing y funciones de derivación de claves (PBKDF2 y Scrypt), merkle trees, protocoles Tcp, Http y WebSocket, tipos de sockets en .NET, Python y algo de Rust (muy poco).

Para 2017

Voy a continuar estudiando y trabajando en todo lo relacionado a Bitcoin que esté a mi alcance, por mi cuenta o para terceros y seguiré dando guerra desde las trincheras del código.

Por otra parte, en 2017 cumpliré 39 años y creo será un año bisagra en mi vida, o debería serlo. Será el año en que las empresas, tanto tecnológicas como de salud prepaga me comenzarán a mirar como algo poco conveniente, una inversión dudosa. Será necesario evaluar esta situación con la cabeza fría.

Mis tecnologías del 2015

Juan María Hernández hace en su blog un resumen de las tecnologías que ha ido incorporando a su arsenal como así también de aquellas que va abandonando o que le han dado menores resultados en su trabajo como profesional del desarrollo de software, y me ha parecido una muy buena lectura pero sobre todo una buena idea el resumir algo de la experiencia de nuestro día a día, nuestras elecciones con sus aciertos y errores. Así que acá va mi resumen.

En lo profesional

En primer lugar aclarar que mi trabajo actual consiste más en formar equipos y asistirlos hasta que maduren y no me necesiten más, y aunque muchas de las decisiones tecnológicas recaen sobre mi, el trabajo dentro de una entidad financiera no es de lo más excitante en materia tecnológica. No obstante, creo que he cometido suficientes errores como para que alguien más pueda aprender algo y no repetirlos.

En cuanto a tecnologías .NET tenemos un proyecto con MVC, Clientes WCF y Cache AppFabric como proveedor de sesiones que si bien se configura de manera muy sencilla y funciona a la primera, lograr la sintonía fina o realizar un troubleshooting es un parto y la documentación a mi gusto es muy escasa. Como SCM utilizamos SVN (cada dev usa el cliente que le resulta más amigable) y debo decir que no me simpatiza en lo absoluto. Como servidor de CI utilizamos un Hudson el cual si bien cumple con su cometido, tampoco me convence demasiado. Para los unit test utilizamos NUnit y Moq, FxCop para el análisis estático de código y Sonar por requerimiento del cliente.

En otro proyecto que corre en unas terminales táctiles ubicadas en las sucursales del cliente tenemos una SAP desarrollada con Knockoutjs y jquery, cosa que a diferencia de la experiencia de Juan María, a nosotros sí nos resultó porque se trata de una aplicación no muy compleja en la que solo queríamos bindear un modelo con el DOM y eso es precisamente lo que obtuvimos. En cuanto al código del cliente lo codificamos con Coffeescript ya que brindaba muchas facilidades que consideramos convenientes como OOP, solución al problema del scope de this, menos código y más legible,  y una sintaxis mucho más declarativa. Hoy esto parece ser un error luego de ES6. Así que ni a quedar pegados con estos dialectos javascript ni a frameworks dictatoriales como angularjs porque el mundo js está muy loco. Los tests, también escritos con coffeescript utilizan jasmine y son corridos con chutzpah ya que se integra a VS y muchos devs .NET tienen problemas con todo lo que no esté en VS.  En cuanto al lado del servidor tenemos WebAPI retornando tipos anónimos (lo más simple y flexible) también Autofac, log4net y poco más.

Lo único quizás más interesante han sido los proyectos relacionados con bitcoin en los cuales utilicé NBitcoin, BouncyCastle y la implementación de referencia de Bitcoin core, OpenAssets y tecnologías afines las cuales estoy seguro no les interesan a nadie que lea mi blog. Solo comentar que en este proyecto utilizamos git, bitbucket, github, travis-ci y teamcity (dependiendo si el repo es público o privado),  lo que es simplemente fantástico para mi.

En lo personal

En lo personal no utilizo más .NET ya que casi todo lo que me interesa está primero y con menos fricción en linux, no obstante seguí manteniendo mi proyecto Open.NAT y otros aún menos importantes. Luego de pasar por el mundillo de nodejs, express, mongodb y miles de paquetes npm que en su gran mayoría son simplemente basura, debo decir que una cosa es que te digan que node es rápido y otra cosa es experimentarlo en persona, simplemente vuelva. No obstante, npm para las dependencias del lado del cliente todavía no está (es simplemente mi opinión personal), no se puede especificar otro directorio para las módulos que no sea el node_modules por lo que el moverlas a otras carpetas es un trabajo sucio ha realizar con grunt (o lo puede haber estado haciendo mal). Nodemon para reiniciar el servicio ante una modificación, forever para asegurar la continua ejecución de la aplicación en producción y passport para loguearse con facebook, twitter, goggle y otros… en fin, todo muy estandar.

Si bien me encanta nodejs, creo que es parte de una comunidad algo alocada que no ataca problemas que llevan años sin resolver como debugging y tracing que si bien están en el roadmap, todavía no hay nada. Los módulos son viejos y abandonados, cuando no simplemente triviales. No sé, algo no va bien allí y se siente. Por esto es que pienso pasar algunos proyectos a golang no sin antes hacer un piloto portando Open.NAT a Go.

Microsoft incorpora Bitcoin

Y es que aún cuando se veía venir a lo lejos, la noticia sorprende un poquito. No está demasiado claro nisiquiera para mi el por qué sorprende si con solo buscar Microsoft y Bitcoin en Google uno se encuentra con resultados como los de la imagen al pie de este post. 

imagePero sí, ahora Microsoft incorpora Bitcoin entre sus opciones de pago para los Estados Unidos quizás deba transcurrir algo de tiempo hasta que se extienda a otras regiones pero lo importante es que luego de Dell, PayPal,  la adopción por parte de Microsoft no debería sorprender y se posiciona entre los primeros gigantes del mundo en dar el gran paso.

Chau Google, chauuuuu

Mientras Google y Apple siguen intentando crear sus propios mecanismos de pago mediante sus iniciativas de monedas propietarias, Microsoft se decide y toma la delantera y creo que va a dejar en posición adelantada a toda la industria que ahora va a tener que repensar y rediseñar sus estrategias o quedarán muy retrasadas.

 

Movida temeraria?

En lo absoluto, el gigante de Redmon no ha tomado una decisión apresurada en lo absoluto, el equipo de Microsoft Research  ha venido investigando las criptomonedas en los últimos años y de hecho habían propuesto Permacoin (pdf), un fork de bitcoin con propósito de servir de almacenamiento de datos permanente.

 

Bill, el creyente

Pero no solo esto es de resaltar sino que Bill Gates hace un par de años que desde su fundación viene ayudando a distintas ONGs de todo el mundo, y en particular de Kenia donde el sistema MPESA tiene un éxito increible, mediante distintos sistemas de transferencia de valor por medios digitales y ha visto en primera persona las potencialidades de estas tecnologias y lo ha manifestado en reiteradas entrevistas que se pueden encontrar en la web. Una de esas entrevistas la pueden ver abajo en un video.

Bill es un creyente de Bitcoin no solo porque, más allá de su estatus de hombre de negocios utra exitoso, sigue siendo un hacker sino porque está en contacto con distintos sistemas emergentes de intercambio y él mismo ha vivenciado el impacto que éstos pueden tener. En este caso me refiero a las poblaciones más desfavorecidas del mundo en el que la inmensa mayoría de los habitantes no tienen acceso al sistema bancario y que aún teniéndolo no pueden costear los costos ni los tiempos que requieren las transacciones bancarias transnacionales.

 

Es solo por la XBox?

 

De la experiencia de Dell y Expedia podemos saber que Microsoft no va a experimentar un salto de ventas de XBoxes por incluir Bitcoin como medio de pago pero sí podemos estar seguros de algunas cosas:

  • Microsoft le da credibilidad a las monedas digitales y,
  • Google y Apple van a tener que reaccionar de alguna manera

Así que tal parece que no es para vender más ni para ahorrarse una comisión bancaria (ni ahorrársela a los clientes) sino que más bien parece una estrategia en varios sentidos. Por un lado Microsoft necesita volver a hacer punta y esta es “La” gran oportunidad, esto también le permite el uno de los primeros no solo en aceptar la moneda sino en darle aplicación real. Además, si viste mi video sobre el por qué Bitcoin es importante, entenderás que es sumamente ventajoso el incursionar en el desarrollo de software que manipulan monedas digitales (a esto le llamo la industria de la Alta Tecnología Financiera).

Así que Microsoft no es la empresa conservadora que todos muchas veces creimos que era…. Esto es gigante! Bien Microsoft, Bien!

Cómo puede Bitcoin cambiar nuestro mundo?

Los que estamos en “esto” de las computadoras venimos viviendo tiempos asombrosos y se está poniendo cada vez mejor! En el video de abajo (6min) explico muy rápidamente algunas ideas sobre por qué bitcoin es importante y cómo puede cambiar en mundo en poco tiempo.

 

Saludos

BlockchainParser–Para descubrir la historia de Bitcoin

Introducción

Son muchos los sitios webs en donde podemos encontrar gráficas sobre distintos aspectos de bitcoin. blochain.info, por ejeimagemplo, nos provee de un rico conjunto de gráficas como las que podemos ver en la imagen de la derecha, entre muchas otras.

También existen blogs en donde se muestran análisis muy interesantes sobre tendencias, investigaciones, evidencias de ataques DDOS, introducción de contenido indeseado en la blockchain, potenciales nuevos usos del protocolo bitcoin y mucho más.

Por último, también podemos acceder a algunos papers sobre investigaciones respecto al anonimato (o falta de) de bitcoin, cómo seguir la traza del dinero, validar hipótesis como la del pago de sicarios mediante bitcoins que habría realizado el fundador de SkillRoad o, la competencia (o falta de) entre los distintos pooles de minning, entre muchas otras cosas.

 

Blockchain

Todo lo anterior es posible gracias a que todo lo que uno desee saber de bitcoin lo puede encontrar en la blockchain, allí está toda la historia desde el primer día. No obstante no existen, al menos hasta el momento en escribo estas lineas, herramientas que permitan realizar estos análisis con la flexibilidad necesaria. Es más, cada uno de estos blogs o papers comienzan explicando la creación de algun componente de software capaz de extraer la información deseada de la blockchain.

 

BlockchainParser

Mientras que cada uno crea la herramienta que necesita para cumplir con un objetivo particular, existe un componente en común que es no es necesario reescribir con cada nuevo proyecto y este es el Parser.

Por esta razón he publicado en Github un nuevo proyecto BlockchainParser en cual es capaz de recorrer la blockchain y retornar los bloques de información (bloques, transacciones, entradas y salidas) para su procesamiento posterior.

 

BlockchainToSql

Cómo ejemplo de eso de este componente he publicado también una aplicación (muy pequeña y sucia) que extrae toda la info de la blockchain y la introduce en una base de datos SQL para así poder analizar los datos con mayor flexibilidad. Así, mediante consultas SQL, es posible responder preguntas como las que siguen:  

  • ¿Cuales son las direcciones con más bitcoins? ¿Cual es el top 100 de direcciones que más reciben?
  • ¿Cómo es la tendencia en la dificultad de minado?
  • ¿Que poder de cómputo tenía Satoshi Nakamoto? ¿Cuantos bitcoins tiene? ¿Cuando gastó por última vez?
  • ¿Cuantos bitcoins tiene el FBI? ¿Cuando los vendió?
  • ¿Cuando se introdujeron las cadenas de virus en la blockchain? ¿cuanto costó hacerlo?
  • ¿Cómo se distribuyen los bitcoins entre sus tenedores?
  • ¿Cómo le va a Dell con BTC?
  • ¿Que porcentaje de Bitcoins se usan en la especulación y cuantos se mantienen sin gastarse?
  • ¿Qué porcentaje de Bitcoins se han perdido?

image

Otros usos

Existen muchos usos de este parser y entre ellos uno que me resulta muy interesante es la posibilidad de crear watchers para vigilar ciertas condiciones. Por ejemplo:

  • Vigilar las direcciones de Satoshi ya que un movimiento en cualquiera (o todas) estas direcciones puede significar un movimiento grande en el mercado.
  • Vigilar direcciones del grande jugadores como pooles, exchangers, FBI, Satoshi, BitPay.
  • Vigilar que la dificultad no baje de un umbral X. Esto podría significar que se ha perdido poder de cómputo en la red.
  • Vigilar número de micro transacciones. Esto puede significar un ataque a la red (y su consecuente impacto en la prensa, mercado, etc)
  • Vigilar el contenido de las nuevas direcciones y scripts. Esto puede significar un mal uso del protocolo o un uso novedoso.
  • Vigilar nuestras propias direcciones. Si se han gastado y no hemos sido nosotros significa que no somos tan inteligentes como creíamos.

Saludos

 

del.icio.us Tags: ,,

Open.NAT 2.0 Released

Acabo de liberar Open.NAT 2.0.6. Solo un par de ejemplos de uso:

 

Descubrir el router (Upnp o Pmp) y obtener su IP pública:

image

Descubrir router que soporte Upnp (por no más de 10 segundos) y crear un mapping TCP port: 1600 –> port: 1700

image

Este puede utilizarse ya sea del su código fuente como desde su paquete NuGet desde el administrador de paquetes:

Screenshot_1

Espero les sea de utilidad.

[CoffeeScript] Mi primer proyecto

Sobre la elección del lenguaje

En todo proyecto de desarrollo de software los arquitectos deben, tarde o temprano, tomar ciertas decisiones o enfrentarse a elecciones que pueden despertar polémicas; decisiones referentes a aspectos tales como la tecnología de persistencia de datos, los middlewares, los frameworks (léase aquí: librerías), tecnología de la capa de delivery,  granularidad de los servicios, estrategias de despliegue y un larguísimo listado de etcéteras.  Pero de entre todas las elecciones, la que quizás resulte más arriesgada es la elección del lenguaje de programación, y no me refiero a elecciones del tipo Java vs C#, de hecho difícilmente alguien pueda dudar de estos lenguajes. Tampoco resultaría extraña la utilización de PHP, ni de Python o Ruby, ni de Javascript con NodeJs aunque otros, como Scala o Lua, podrían requerir cierta justificación en algunos entornos.

Cuando digo que no generarían demasiado ruido me refiero a que son muy buenos lenguajes, bien conocidos, bien documentados, con una enorme comunidad y miles y miles de sistemas han sido desarrollados con ellos. Pero, ¿qué sucede si decidimos que el mejor lenguaje para el proyecto que le vamos a desarrollar a nuestro cliente es, por ejemplo, GorillaScript, Sugar o Fun? Es muy probable que la resistencia sea lo suficientemente fuerte, tanto desde dentro como  desde fuera del equipo, como para desistir y volver a PHP, Java o C#. Es más, en algunos casos extremos, como el del cliente para el que estamos desarrollando algunas aplicaciones actualmente, el temor a un nuevo lenguaje de programación ha sido históricamente tan grande que desarrollaron todo su sitio web en COBOL! (Pero eso será motivo de otro post)

 

Coffeescript

imageLa elección de CS no es algo que podamos considerar arriesgado ya que no es más que un dialecto de Javascritpt y compila a Javascript. No obstante, en un entorno corporativo, a diferencia de lo que puede suceder en un proyecto Open Source o en nuestro Pet Project, apostar por este lenguaje requiere de coraje. En parte porque si el proyecto fracasa (por las razones que sean) una de las primera preguntas a las que el arquitecto puede ser sometido es la siguiente: “Coffeescript?! Pero en qué diablos estabas pensando!? ”. Por otra parte, todos los que eventualmente se hubiesen opuesto, ya sea por temor al cambio, o simplemente por preferencia personal,  podrían sacar leña del árbol caído; a veces sucede.

Por cierto, una eventual justificación acerca de por qué encarar un nuevo desarrollo con este lenguaje se vuelve algo complicado puesto que, aún hasta el día de hoy, existe toda una controversia a su alrededor. Controversia en la que prominentes personalidades del mundo Javascript no terminan de ponerse de acuerdo. 

 

Coffeescript en el mundo real

Después de meditar por meses sobre los pros y contras, y sobre cómo podría solucionar algunos problemas que tuvimos en los desarrollos anteriores con javascript, me puse a buscar sobre experiencias en el mundo real y lo único que encontré fueron Trello y Dropbox, y obviamente un millar de librerías y aplicaciones open source, algunas muy buenas por cierto.

Eso me pareció suficiente puesto que, por cada aplicación mundialmente reconocida en internet, existen miles de otras aplicaciones bien hechas y brindando soluciones reales solamente que no son tan conocidas. Así que me decidí: “¡Vamos con Coffeescript!”

 

Pero ¿por qué?

En muchos proyectos web veo que se repite lo mismo una y otra vez: programadores para los que javascript no es su principal lenguaje y que no saben javascript o, en el peor de los casos, programadores que no saben que no saben javascript. Lo que sucede en estos casos es que mientras que el código del servidor es decente, el del cliente suele ser una colección de cientos o miles de snippets de jquery traídos desde StackOverflow.com y una librería javascript por cada problema que se les presenta. 

La solución es evidente: deben aprender javascript. ¿Pero cómo? ¿con una capacitación? ¿con un libro? ¿con guías de desarrollo? ¿con JLint? No. Definitivamente no. Incluso muchos patrones javascript requieren un entendimiento profundo de la naturaleza prototipal del lenguaje, los temas relacionados al scope de las variables en las funciones y closures requiere también atención extra, aprender las diferencias de uso de los operadores y las funciones de alto orden también suelen resultar dificultosas. Es simplemente demasiado.

CS soluciona estas y muchas (pero realmente muchas, muchas) cosa más, permite escribir un código más claro, conciso, con menos defectos, más mantenible, en menor tiempo (al menos una vez que ya nos hemos familiarizado con él), incorporando patrones comunes y bien conocidos de manera gratuita, generando código javascript que funciona en prácticamente todos los browsers, etc. La idea no es enumerar las bondades aquí.

Pero una imagen vale más que mil palabras, asi que, ¿alguien me explica como se pueden mantener 13.000 LoC como las que siguen? Advertencia: es código real.

image

Primer proyecto con Coffeescript

imageYa a punto de terminar con el desarrollo de la aplicación y viendo hacia atrás creo que la elección no sólo ha sido correcta sino que ha superado mis expectativas. Me explico, la aplicación es una SPA desarrollada con Knockoutjs, JQuery y CS; Knockoutjs posibilita (o fuerza) la utilización del patrón MVVM por lo que tenemos Views, ViewModels y Models por separado, obviamente los últimos 2 son 100% CS y al ser una SPA requiere de todos los conceptos que típicamente implementamos con otros lenguajes: OOP (sí, encapsulamiento, herencia y polimorfismo) y AOP, tracing, exception handling,  organización mediante namespaces y módulos, unit tests, además de una lógica de negocios harto compleja (con una interfaz de usuario que la acompaña).

Esto es algo distinto al desarrollo de una aplicación web tradicional con ASP.NET MVC en el que nuestro lenguaje es C# y en donde las vistas utilizan Razor, aquí nuestro lenguaje es javascript, y la lógica de la interfaz de usuario está en el cliente.

En este escenario no valen los snippets jquery ni que todo sea global (obviamente esto no vale en ningún desarrollo, pero es muy común), aquí necesitamos código Javascript de alta calidad, bien limpio, que incorpore las mejores prácticas utilizadas con este lenguaje, que sea orientado a objetos, que permita la inyección de dependencias, que sea sencillo de leer y modificar,  que sea modular.

Hay quienes podrían argumentar que todo esto se puede lograr igualmente con javascript ya que ninguna de las consideraciones anteriores tiene relación directa con CS. Eso es tecnológicamente cierto pero técnica y humanamente falso, me explico:

  • Tecnológicamente hablando, todo lo que se puede hacer con C# 5.0 ya se podía hacer con C# 4.0 y este, no introduce nada que no se pudiera hacer con C# 3.0 y así podemos llegar a la conclusión de que todo lo que se puede hacer con C# 5.0 ya podía hacerse con C# 1.0. Y aunque esto es cierto, no deja de resultar ridículo ya que no es lo mismo programar una operación sobre colecciones genéricas con Linq que programar bucles anidados para operar sobre colecciones de objects.

    O como decían los programadores de assembler: “Todo lo que se puede hacer con C, se puede lograr igualmente con ensamblador y por lo tanto, C no trae nada nuevo”. Este es el argumento que más resuena en la red y, aunque cierto, es absolutamente estúpido.

  • Técnica y humanamente hablando, no es lo mismo escribir y mantener 6.500 LoC que 10.000 LoC y esto se vuelve aún más evidente a medida que este número crece, es decir que no es lo mismo mantener 650.000 LoC que 1.000.000 LoC. Pero es incluso mucho más fácil mantener 65.000 LoC en un claro CS que 1.000.000 LoC de un ruidoso JS.

 

Pero mejor una imagen de código real de nuestro proyecto:

image

¿De cuál lado prefieres trabajar? ¿Cúal te gustaría mantener? Personalmente prefiero trabajar sobre las 19 líneas de código CS de la izquierda (muy claras y sencillas de modificar) que con las 74 líneas de JS de la derecha. Y si bien es cierto que yo no escribiría el código de la derecha del mismo modo que lo hace el compilador de CS, también es cierto que luego de algún esfuerzo y un buen refactoring, el código JS escrito a mano seguiría siendo todavía más ‘verboso’, ruidoso y duro de mantener que su equivalente CS del lado izquierdo. ¿Puede apreciarse ese ruido?

 

El equipo

Nuestro equipo se conforma de un desarrollador .NET, un Líder Técnico puede dedicar aproximadamente un 50% de su asignación a la programación de la aplicación y soporte (o incluso menos) y yo, que puedo dedicar entre un 10% y un 30% como mucho a soporte y programación. Testing y diseño web se requieren en momentos puntuales del ciclo de vida y, aunque no es así como trabajamos habitualmente, por restricciones de contrato y presupuesto no nos quedó otra alternativa.

Este equipo debía desarrollar la aplicación en 2 meses, y si no fuera porque el alcance fue ampliándose, esta semana estaríamos terminándolo. El punto aquí es que solo yo contaba con alguna experiencia previa con CS así que debíamos aprenderlo sobre la marcha y muy, pero muy rápido.     

 

Aprendiendo Coffeescript y algunos problemas

CS se aprendió sobre la marcha y aún estamos aprendiendo nuevas cosas todos los días porque el lenguaje tiene muchas más features y caminos que los que se describen brevemente en el sitio CoffeeScript.org. Pero cada vez que aprendemos algo nuevo inmediatamente cambiamos el código en aquellos lugares en donde hicimos algo “casero” y que CS resuelve de manera más conveniente.

Pero esto no fue feliz al comienzo. Al principio del proyecto hubo cierta resistencia por parte del TL y del desarrollador en cuanto al lenguaje,  y es lógico que eso sucediera puesto que es frustrante pasar 8hs tratando de realizar una tarea trivial y no lograrlo por no conocer el lenguaje. Y no sólo el lenguaje, KOJS era también nuevo para los dos, era realmente esperable. Encima, los desarrolladores se sienten presionados por mostrar resultado rápidamente y el no poder desempeñarse como quisieran por culpa de un cóctel de tecnologías nuevas genera un desagradable estrés.

Fue necesario acompañar el proceso de aprendizaje, asistirlos y aclararles lo evidente: nadie espera que aprendan todo esto en unas semanas. Y aunque eso no reduce la frustración, al menos queda claro donde están las responsabilidades y cuáles son las expectativas que se tiene ellos. Otro punto importante es que el desarrollador hacía lo correcto y luego lo hacía correctamente, eso también ayuda.

Por último, y no de menor importancia, es el hecho de que revisando y depurando el código generado, el equipo todo ha aprendido mucho más sobre javascript y algunos patrones comúnmente utilizados de lo que tal vez lo hubiera hecho programando directamente con javascript.

 

Lecciones aprendidas

Solo algunas:

  • Mantener los archivos .coffee pequeños hace más sencilla la tarea de depuración y correlacionar nuestro código con el javascript generado.
  • No hacer demasiadas cosas en una sola línea. Aún cuando CS posibilita (y avaces parece que alentara) la escritura de sentencias larguísimas, éstas se vuelven difíciles de leer y mantener, ni que hablar de comparar y mergear. Simplemente hay que pensar que el código debe ser legible no sólo para nosotros y listo.
  • Usar una herramienta que permita ver el JS generado mientras se escribe CS o al menos revisar el código generado con frecuencia. De esta manera se evitan varios dolores de cabeza puesto que a veces el código generado no es lo que esperábamos simplemente por un typo en nuestro código CS o un espacio/tab mal puesto. De paso se familiariza uno con el código ‘real’ que se ejecutará.
  • Configurar el editor (en nuestro caso Visual Studio) para que muestre los espacios en blanco y tabulaciones. Esto es importante porque muchas veces, sin quererlo, se mezclan espacios y tabs y uno debe saber donde es que están. Lo mismo sucede cuando el editor está configurado para hacer “word wrapping”, uno no sabe si es una línea nueva o si simplemente es la continuación de la línea anterior.
  • Los UTs no son opcionales. A medida que se escriben más y más líneas de código, el refactoring se vuelve mucho más riesgoso y uno termina rompiendo funcionalidades inesperadas que luego solo pueden detectarse en tiempo de ejecución.
  • Integrar los UTs con el entorno de desarrollo y correlos a cada rato, luego de una modificación en cualquier parte correrlos a todos. Luego de actualizar la copia local del repositorio correlos a todos, antes de subir algo correlos a todos. Escribir UTs en CS (o JS) es infinitamente más sencillo y rápido de hacer que en C# o Java así que, a menos que hagas TDD (no es nuestro caso), escribí tantos casos como puedas. No te vas a arrepentir.
  • Dedicar parte del día a leer algo sobre CS. Siempre vas a encontrar una manera mejor de hacer algo que hiciste.

Herramientas

Desarrollamos con Visual Studio así que utilizamos las siguientes extensiones para trabajar con CoffeeScript:

Mindscape Web Workbech

Esta extensión brinda el coloreado de la sintaxis CS y genera compila (genera el equivalente JS) cada vez que se guarda un archivo. Solo es cuestión de escribir algunas líneas y hacer Ctrl+S para ver cómo queda nuestro código.  Esta extensión es una buena alternativa y no hemos tenido problema alguno con ella.

image

Chutzpah Test Adapter for Test Explorer

Esta extensión permite que Visual Studio detecte la existencia de tests escritos en CS y permite correrlos desde Visual Studio de la manera habitual, haciendo fácil es escribir algo de código y correr los test, todo en el ambiente integrado de VS. Para esto, compila y corre nuestros tests con PhantomJS utilizando la librería que queramos (Jasmine, Mocha o QUnit). Chutzpah hace lo que promete, y lo hace muy bien, pero por desgracia cuando falla un test uno no puede simplemente poner un breakpoint para ver qué pasa, ni crea un code map para saber al menos en qué línea CS está fallando.  

Por esta razón yo hubiese preferido correrlos desde el browser pero bueno, aún así la herramienta vale la pena y nos está dando buenos resultados.

image

Aquí puede verse un test sencillo:

image

Y aquí puede verse la suite corrida:

image

 

Conclusión

  • CS es un lenguaje que llegó para quedarse porque los beneficios que trae consigo son reales y evidentes para todos los que se quitan las anteojeras ideológicas de javascript y lo evalúan desde una posición de neutralidad.
  • La incorporación de CS puede generar alguna frustración y penalidad de productividad en las primeras semanas si no se lo conoce de antemano.
  • CS puede ser aprendido, en un nivel suficiente para realizar un desarrollo, en un período de tiempo muy corto. Si se conoce bien javascript, el pasaje es sencillo; de lo contrario se van aprendiendo algunos conceptos y patrones javascript observando y depurando el código generado (pero primero JS y luego CS, lo opuesto no es válido).
  • Las extensiones para Visual Studio funcionan bien y permiten el desarrollo completo de una aplicación sin tener que cambiar de editor de texto para codificar ni cambiar de entorno para correr las pruebas unitarias.
  • CS es simplemente JS.
  • No pieso volver a escribir javascript nunca más en mi vida.

Documentacion XML a Markdown

Necesitaba documentar Open.NAT y colgarlo en la wiki del proyecto en GitHub pero no encontré nada, así que escribí un transformador XML—> Markdown que me sirviera. La verdad es que el código, si bien son solo 100 LoC, está bastante sucio pero si a alguien le sirve aquí se los dejo.

Y este es el resultado:

image

 

Con esto lo invoco:

  1. class Program
  2. {
  3.     static void Main(string[] args)
  4.     {
  5.         var xml = File.ReadAllText(args[0]);
  6.         var doc = XDocument.Parse(xml);
  7.         var md = doc.Root.ToMarkDown();
  8.         Console.WriteLine(md);
  9.     }
  10. }

Aquí está el código:

  1. static class XmlToMarkdown
  2. {
  3.     static IEnumerable<string> DocToMarkDown(XNode e)
  4.     {
  5.         var el = (XElement) e;
  6.         var members = el.Element(«members»).Elements(«member»);
  7.         return new[]
  8.             {
  9.                 el.Element(«assembly»).Element(«name»).Value,
  10.                 string.Join(«», members.Where(x => x.Attribute(«name»).Value.StartsWith(«F:»)).ToMarkDown()),
  11.                 string.Join(«», members.Where(x => x.Attribute(«name»).Value.StartsWith(«M:»)).ToMarkDown()),
  12.                 string.Join(«», members.Where(x => x.Attribute(«name»).Value.StartsWith(«E:»)).ToMarkDown())
  13.             };
  14.     }
  15.  
  16.     internal static string ToMarkDown(this XNode e)
  17.     {
  18.         var templates = new Dictionary<string, string>
  19.             {
  20.                 {«doc», «## {0} ##nn## Fieldsnn{1}nn## Methodsnn{2}nn## Eventsnn{3}nn»},
  21.                 {«field», «### {0}nn{1}nn»},
  22.                 {«method», «### {0}nn{1}nn»},
  23.                 {«event», «### {0}nn{1}nn»},
  24.                 {«summary», «{0}nn»},
  25.                 {«remarks», «**remarks**nn{0}nn»},
  26.                 {«example», «**example**nn{0}nn»},
  27.                 {«see», «[{1}]({0})»},
  28.                 {«param», «_{0}_: {1}» },
  29.                 {«exception», «_{0}_: {1}nn» },
  30.                 {«returns», «Returns: {0}nn»},
  31.                 {«none», «»}
  32.             };
  33.         var d = new Func<string, XElement, string[]>((att, node) => new[]
  34.             {
  35.                 node.Attribute(att).Value,
  36.                 node.Nodes().ToMarkDown()
  37.             });
  38.         var methods = new Dictionary<string, Func<XElement, IEnumerable<string>>>
  39.             {
  40.                 {«doc», DocToMarkDown},
  41.                 {«field», x=> d(«name», x)},
  42.                 {«method»,x=>d(«name», x)},
  43.                 {«event», x=>d(«name», x)},
  44.                 {«summary», x=> new[]{ x.Nodes().ToMarkDown() }},
  45.                 {«remarks», x => new[]{x.Nodes().ToMarkDown()}},
  46.                 {«example», x => new[]{x.Value.ToCodeBlock()}},
  47.                 {«see», x=>d(«cref»,x)},
  48.                 {«param», x => d(«name», x) },
  49.                 {«exception», x => d(«cref», x) },
  50.                 {«returns», x => new[]{x.Nodes().ToMarkDown()}},
  51.                 {«none», x => new string[0]}
  52.             };
  53.  
  54.         string name;
  55.         if(e.NodeType== XmlNodeType.Element)
  56.         {
  57.             var el = (XElement) e;
  58.             name = el.Name.LocalName;
  59.             if (name == «member»)
  60.             {
  61.                 switch (el.Attribute(«name»).Value[0])
  62.                 {
  63.                     case ‘F’: name = «field»break;
  64.                     case ‘E’: name = «event»break;
  65.                     case ‘M’: name = «method»; break;
  66.                     default:  name = «none»;   break;
  67.                 }
  68.             }
  69.             var vals = methods[name](el).ToArray();
  70.             string str=«»;
  71.             switch (vals.Length)
  72.             {
  73.                 case 1: str= string.Format(templates[name], vals[0]);break;
  74.                 case 2: str= string.Format(templates[name], vals[0],vals[1]);break;
  75.                 case 3: str= string.Format(templates[name], vals[0],vals[1],vals[2]);break;
  76.                 case 4: str= string.Format(templates[name], vals[0], vals[1], vals[2], vals[3]);break;
  77.             }
  78.  
  79.             return str;
  80.         }
  81.  
  82.         if(e.NodeType==XmlNodeType.Text)
  83.             return Regex.Replace( ((XText)e).Value.Replace(‘n’, ‘ ‘), @»s+», » «);
  84.  
  85.         return «»;
  86.     }
  87.  
  88.     internal static string ToMarkDown(this IEnumerable<XNode> es)
  89.     {
  90.         return es.Aggregate(«», (current, x) => current + x.ToMarkDown());
  91.     }
  92.  
  93.     static string ToCodeBlock(this string s)
  94.     {
  95.         var lines = s.Split(new char[] {‘n’}, StringSplitOptions.RemoveEmptyEntries);
  96.         var blank = lines[0].TakeWhile(x => x == ‘ ‘).Count() – 4;
  97.         return string.Join(«n»,lines.Select(x => new string(x.SkipWhile((y, i) => i < blank).ToArray())));
  98.     }
  99. }

Open.NAT–Bandwidth

64

Open.NAT heredó la implementación del mecanismo de discovery de Mono.Nat el cual buscaba por todos los servicios UPnp. El protocolo SSDP se basa en UDP el cual no es confiable, por lo que especifica que deben enviarse 3 packets UDP a la IP de broadcasting. Todas las computadoras en la LAN responden con 3 packets por cada una de las peticiones originales y por cada uno de los servicios disponibles por lo que en una LAN de pequeña, 5 computadoras por ejemplo, la que corren 5 servicios cada una, tenemos que Mono.Nat procesa 3*3*5*5 = 225 respuestas (datagramas).

Open.NAT por su parte solo consulta por aquellos servicios que pueden utilizarse para mapear puertos y solo envia 2 packets por lo que solo recibe respuestas de los routers y/o modems ADSL, y solo dos packets. Esto reduce notablemente el tráfico, que si bien en una LAN de 5 computadoras no es nada, en una de 100 no solo que sí es importante sino que el procesar todas esas respuestas consume muchos ciclos de CPU en el cliente.

Open.NAT solo necesita 1.3 segundos para completar el proceso de discovery en la LAN WIFI de mi casa, nada mal!

Esta es la salida por consola que podemos obtener al correr

Your IP: 181.110.171.21
Added mapping: 181.110.171.21:1700 -> 127.0.0.1:1600
+------+-------------------------------+--------------------------------+----------------------------------+
| PROT | PUBLIC (Reacheable)           | PRIVATE (Your computer)        | Descriptopn                      |
+------+----------------------+--------+-----------------------+--------+----------------------------------+
|      | IP Address           | Port   | IP Address            | Port   |                                  |
+------+----------------------+--------+-----------------------+--------+----------------------------------+
|  TCP | 181.110.171.21       |  21807 | 10.0.0.5              |  32400 | Plex Media Server                |
|  UDP | 181.110.171.21       |  25911 | 10.0.0.6              |  25911 | Skype UDP at 10.0.0.6:25911 (2693)|
|  TCP | 181.110.171.21       |  25911 | 10.0.0.6              |  25911 | Skype TCP at 10.0.0.6:25911 (2693)|
|  TCP | 181.110.171.21       |   1700 | 10.0.0.6              |   1600 | Open.Nat Testing                 |
+------+----------------------+--------+-----------------------+--------+----------------------------------+
[Removing TCP mapping] 181.110.171.21:1700 -> 127.0.0.1:1600
[Done]
[SUCCESS]: Test mapping effectively removed ;)
Press any kay to exit...