sábado, febrero 03, 2007

Prototipando con Ruby

Desde hace algo así como unos nueve meses mi equipo de trabajo tiene a Ruby on Rails como herramienta principal de trabajo a la hora de desarrollar aplicativos web. Puedo culpar a Topocho y a EGG por esto ya que se la pasan evangelizando a cuanto pecador se encuentran en el camino. Mi tarea en el equipo de desarrollo muchas veces tiene que ver nada más con el diseño de como debe trabajar el software, las especificaciones funcionales y alguna que otra vez sugerir modificaciones en el código para hacerlo óptimo o ajustarlo a algo específico. Así que rara vez me interno en las profundidades del código aunque se supone que debo dominarlo al menos a nivel básico. Nueve meses no es mucho la verdad, pero es suficiente para haber desarrollado un sistema completo de control financiero para un cliente que requería instalarlo en una intranet. El resultado ha sido excelente, alto grado de mantenibilidad del código, legibilidad y desarrollo extremadamente rápido.

Pero el cuento no es sobre esta aplicación web típica de Ruby on Rails. El cuento es sobre una idea que tuvimos hace poco de usar Ruby para prototipar una interfaz web que se supone debe colocar datos en tiempo real proveniente de unos controladores de proceso, o PLC's como se dice en nuestra jerga de automatización. En este caso, por la presión con que trabajamos, no me ha dado tiempo de escribir una especificación clara de lo que necesitamos. Lo que tenemos son discusiones, algunos dibujos hechos en papeles e ideas discutidas en reuniones informales. Y con esto por supuesto no hay manera que un equipo de desarrollo formal lo entienda. Así que no me ha quedado más remedio que desarrollar yo mismo los prototipos.

Lo primero es definir la arquitectura de hardware. Simple, es solamente un PLC conectado mediante una conexión Ethernet y usando el protocolo de comunicaciones Modbus TCP. Programé el PLC para tener algunos datos tanto de variables analógicas como de variables digitales, o booleanas como les gusta llamarlas a los computistas. Luego en mi laptop en Linux y con Ruby instalado me dediqué a programar las funciones de lectura de datos. La primera de ellas, para comenzar por algún lado, fue la de lectura de datos digitales, o función 02 en jerga Modbus. Esta función requiere que le enviemos al controlador una solicitud compuesta por una ristra de bytes donde le indicamos la función a usar, la dirección inicial que queremos leer y finalmente la cantidad de registros que queremos interrogar. El controlador debe respondernos con un mensaje donde nos dice que está bien la solicitud, la cantidad de bytes de datos que nos va a enviar, y luego los bytes con la información.

Todo luce sencillo. Al menos en seudo código todo luce perfecto. El problema es el paradigma de alguien acostumbrado a ver código en C, en C# o en Java. Cuando me metí a programar los detalles en Ruby simplemente quedé asombrado con una sonrisa de oreja a oreja. El programa en cuestión quedó increíblemente pequeño, claro seguro que podrá ser optimizado aún más. Cuando llegué a la parte de decodificar los bytes me pareció increíble que los números que recibía, de la clase Ruby Fixnum (número entero para los legos), se comportaban como arreglos donde cada uno de los elementos del arreglo era el bit de su representación en binario. Así si tenemos el Fixnum 8 y se lo asignamos a la variable n, entonces tenemos que n[3] = 1, n[2] = 0, n[1] = 0 y n[0] = 0. Con esto nos ahorramos un kilo de código.

En este momento estoy trabajando en el código de las funciones restantes y las excepciones en caso de errores. Luego pondremos a este programita cliente a funcionar indefinidamente y cargar las lecturas en variables que puedan ser mostradas en una página web. El resultado eventualmente lo pondremos en la web de la compañía con algún tipo de licencia de código abierto, pero después de que pase las pruebas. Los detalles técnicos los publicaré en la medida de lo posible en La Cara Oscura.

Ruby tiene en esto grandes ventajas para nosotros los ingenieros no computistas. Es fácil de aprender, es muy legible y muy poderoso. Otra cosa es que es mucho más amigable que Python en mi humilde opinión, pero supongo que esto es cuestión de gustos.

11 comentarios:

hlp dijo...

Tu también te convertiste a Ruby?!? Joder, a mi me encanta (desde hace como un año) Python, y al parecer me pondré a hacer cosas web por primera vez en mi vida para sacarme algunas espinas, asi que quizás me toque comenzar con Ruby.

RomRod dijo...

conozco Python desde sus inicios cuando lo usaba también para hacer prototipos. Eso era por allá a principios de los noventa. Pero siempre me molestó su rigidez, pero creo que es cuestión de gustos ya que reconozco que la rigidez en la sintaxis hace que el código resulte muy legible y fácil de mantener. Pero creo que Ruby tiene todo lo de Pyhton pero con algunos agregados interesantes como lo de codificar como me de la gana, de manera flexible y libre. Yo lo encuentro mucho más divertido y hasta más intuitivo que Python, pero repito, es una mera impresión mía.

Por ahora la orden en mi equipo de desarrollo es prototipar el software de control y en tiempo real en ruby sin darle mucha importancia si existen las bibliotecas necesarias para los problemas más complejos. Yo le veo mucho futuro.

Y en cuanto a Ruby on Rails ni te cuento, es toda una delicia desarrollar un proyecto completo en la mitad del tiempo que nos llevaría hacerlo en Java o ASP.NET. Y mucho más ordenado y mantenible que algo en PHP al estilo LAMP.

sd dijo...

Amen...

Palabras como "divertido" o "delicia" no suelen ser parte del vocabulario de un programador.

Es una de esas cosas que los que programamos en Ruby entendemos sin tener que explicarlo, mientras que los que nunca lo han hecho no pueden explicarse cual es el atractivo.

Carlos dijo...

Pues me has tocado una fibra muy profunda.

Después de muchos años trabajando con sistemas como el que describes, descubrí que existen "enlatados" muy poderosos que hacen toda esa función de reporte. Se meten en la memoria de las redes de PLC y Servos, compatibles con cualquier protocolo, como modbus, device net, DH+, Control net, etc. y realmente el desarrollo de sistemas que hacen eso ya no tiene mucho sentido.

Capturan la data y la ponen en SQL y ya tienen todas las herramientas para determinación de MTBF, MTTR, listados de fallas típicas. Algunos son "sistemas expertos" que permiten la entrada de los operadores para describir la acción tomada. Luego de un tiempo, sugieren la acción a tomar según la falla presentada

Son software con licencia costosa pero ya pensados en todos los problemas de productividad de las empresas mas grandes del mundo. Muchos conocidos que desarrollaban ese tipo de software, encontraron mas rentable el convertirse en representantes o integradores de esos enlatados.

Ahora bien, esos programas son una maravilla, pero lo que ha resultado mas complejo (y de lo que he comido mucho tiempo) ha sido uniformar la estructura de los programas de los múltiples PLC para que se adapten al sistema de reporte, muchas veces me ha tocado reescribir todos los programas, pues es imposible modificarlos. Generalmente los programadores de PLC no son personas con formación de programación estructurada, simplemente escriben las escaleras para logar que el equipo funcione sin pensar en una estructura que permita a otros leer los programas o estandarlizar los mapas de memoria, sin lo cual es muy dificil lograr que cualquier sistema de reporte funcione bien.

Un gran saludo desde Bruselas.

Carlos dijo...

Se me olvidó darte un link del systema que mas he visto instaldo últimanente en todo el mundo:

http://www.gefanuc.com/en/ProductServices/AutomationSoftware/index.html

RomRod dijo...

gracias Carlos, conozco bien esos sistemas ya que pasé bastante tiempo trabajando en automatización principalmente con Bailey Controls y ultimamente con ABB. Ya hace unos años que me fuí de ABB pero aún sigo siendo contratista de ellos en algunos proyectos. Este proyecto de que hablo es un poco de divertimento endógeno. Por supuesto que hay productos muy elaborados en el mercado que hacen esto de manera bastante efectiva y a muy bajo costo, pero la idea acá es crear herramientas abiertas que le permitan a los usuarios mayor control sobre el proceso de adquisición de datos sobre todo a nivel de instalaciones pequeñas. Los PLC que usamos para el proyecto son marca Sixnet y están basados en Linux y son bastante poderosos y sencillos de usar ya que usan ISaGRAF. Estos controladores combinados con herramientas desarrolladas localmente pueden resolver un mar de problemas acá en nuestro país a muy pero muy bajo costo.

Para proyectos más ambiciosos utlizamos Sixnet si podemos, pero también la línea ABB o la de Rockwell Automation. En adquisición de datos e interfaces humanas trabajamos principalmente con FactoryLink y en software históricos somos integradores de soluciones con el PI de OSISoft que no se si conoces.

Afortunadamente ya tanto ABB, como el ISaGRAF que usa Sixnet, o los A/B de Rockwell Automation todos se programan usando el estándar IEC61131-3. Esto por supuesto no es garantía de que los que programan los PLC lo hagan de una manera legible y mantenible, pero al menos garantiza que uno pueda cambiar de marca de PLC sin tanto impacto en el entrenamiento de los ingenieros. Lo que ayuda, y eso lo pusimos en práctica cuando estaba en Bailey Controls, es desarrollar estándares internos de programación tanto de los PLC como de los despliegues gráficos. Esos estándares son manuales que describen en detalle macros para cada tipo de control que uno pueda encontrar en una planta industrial. Con esos estándares y una pequeña charla introductoria a los genios que van a programar los sistemas uno puede conseguir uniformidad en la documentación. Jeje pero como siempre los genios son genios y siempre hay que estar detrás de ellos revisando los estándares.

Saludos!

hlp dijo...

Debe ser cuestion de gustos. A mi Python me parece estricto en algunas cosas sintaxis y eso me ayuda.
Prefiero el principio de hay Una manera de hacer las cosas.

Lo de la sintaxis me lo resuelve emacs, la verdad ni me he dado cuenta.

Suelo ser muy muy muy desordenado, y tanta libertad hacer que luego no me acuerde que hice que donde. De hecho, yo solia programar en una cosa que tenia tipos aun mas fuertes que la familia C: caml. Ni siquiera podias sumar 1 + 1.0 porque te daba un error de tipo. Eso si, cuando las cosas compilaban, ya casi funcionaban conceptualmente, y ademas no daba nunca errores a tiempo de ejecución. Era/Es interpretado y compilado al mismo tiempo, lo que permite un ciclo rapido de testeo, etc.

Aunque para cosas sin mucha complicacion conceptual podria estar bien.

Cuando pruebe el bendito Ruby veré.

topocho dijo...

"Aunque para cosas sin mucha complicacion conceptual podria estar bien." La verdad esta no la entendi :-)

RomRod dijo...

jeje, yo tampoco entendí lo de las cosas sin muchas complicaciones conceptuales. En esencia ruby y python son lenguajes equivalentes. Aunque para mi gusto ruby incorpora algunas mejoras que me agradan y hacen que me incline por este lenguaje aún dominando python desde hace años. Una de las razones evidentemente es RoR como framework de desarrollo rápido para aplicaciones web. Pero otra de las razones es justamente lo contrario a lo que dices de "una sola manera de hacer las cosas". Me gusta que exista más de una solución para un mismo problema, eso me garantiza que un desarrollador encuentre la solución mucho más rápido. Y en cuanto a la complejidad de lo que hacemos. Bueno pues son cosas bastante complejas. El sistema que hicimos hace poco para un cliente es para control financiero en un ambiente web. Algo en lo que pudiéramos haber usado J2EE y miles de páginas de código. Con RoR lo hicimos de manera rápida, efectiva y elegante. Con la funcionalidad que esperaba el cliente y bastante mantenible y expandible en caso de que se quiera agregar más cosas. Para el proyecto en tiempo real todavía lo usamos para prototipar ideas, para pruebas de concepto. Pero dado que los requerimientos de tiempo en este proyecto no son tan exigentes es posible que el producto definitivo lo dejemos en ruby aun cuando algunas partes críticas pudieran ser programadas en C si es que se requiere.

egg dijo...

Excelente post, ... sacado de la vida misma.

No esperes a tener los detalles "técnicos" para hacer el post en http://lacaraoscura.com , agarra y escribe esto de una vez, hay que seguir evangelizando ;-)

Anónimo dijo...

Hola estoy viendo por primera vez ruby, estoy en francia porque gane una beca, me encuentro batallando en la escuela a causa
de los algoritmos, antier viernes 16Feb07 el maestro Phillip me ridiculizo en la clase y se rieron :-( y nadie me dice ni ayuda, pero yo persevero y estudio muy duro. Ah y por cierto hay que seguir evangelizando egg y topocho pues es nuestra gran comision jeje DTB