miércoles, 14 de mayo de 2014

I Maratón de Montevideo

El pasado domingo 11 de mayo de 2014 se llevó a cabo la primer edición de la Maratón de Montevideo.

Con un tiempo de 4 horas y 43 minutos logré completar el recorrido de 42.195 metros, por lo que ahora puedo decir que soy maratonista :)

Por qué correr una maratón es una pregunta que me han hecho bastante. Seguramente haya tantas respuestas como corredores, en mi caso lo que quería era demostrarme a mi mismo que era capaz de hacerlo. Habiendo corrido 21 kilómetros en 2013, parecía un desafío interesante.

No me había puesto meta de tiempo, sabía que bajar de 4 horas y media iba a ser difícil por los tiempos que estaba haciendo en los entrenamientos, y esperaba poder hacerlo en menos de 5 horas. El límite máximo, puesto por la organización, era de 6 horas.

Hablando del entrenamiento, fueron 16 semanas de actividad cada vez más exigente, con 4 actividades semanales y llegando a correr más de 60 kilómetros por semana, con un máximo de 32km en una oportunidad. Es un entrenamiento bastante duro, pero totalmente necesario para lograr completar la carrera.

La organización de la carrera fue impecable. La carrera largó en hora, el circuito estuvo bien señalizado con carteles para los kilómetros, los puntos de hidratación estuvieron siempre bien abastecidos con agua, Gatorade, frutas y gel de carbohidratos como estaba planificado. La única queja tal vez es que demoraron mucho en publicar la información oficial, pero del día de la carrera no tengo ninguna queja.

Foto por Mauricio Ramirez, via Facebook
De la carrera en sí, estuvo bueno el recorrido, bien la gente que acompaño y alentaba todo a lo largo del trayecto, y la verdad que el clima también acompañó, salvo por un poco de viento en contra a la ida por la Rambla.

Me llamó la atención que había mucha gente acompañando a algún corredor en bicicleta, pero si veían que alguien paraba o podía precisar algo, en seguida le preguntaban si estaba bien y si necesitaba agua o fruta.

Con respecto a mi desempeño iba bien hasta pasado el kilómetro 30, venía con un tiempo de unos 6 minutos por kilómetro, pero en ese punto me di contra el famoso “muro” y tuve que caminar un poco para recuperarme. Desde ahí hice corriendo las partes llanas, pero con las subidas no pude, las tuve que hacer caminando. De todas formas el tiempo estuvo dentro de lo que esperaba, así que quedé muy conforme.

Terminé obviamente muy cansado y los días siguientes a la carrera estuve (estoy) con bastante dolor en las piernas (no saben lo que se sufre subiendo un piso por escalera al otro día...), pero como decía un cartel en la carrera “el dolor se va, la gloria es para siempre” :)

Realmente una experiencia recomendable, para hacerlo al menos una vez en la vida… Por lo menos para aquellos que corren y quieren exigirse más.


viernes, 11 de abril de 2014

Disparo de eventos desde un User Control GeneXus en iOS

Los User Controls en GeneXus permiten extender la funcionalidad provista por los generadores, para resolver escenarios de User Interface que no están resueltos en los controles estandar. Hay varios controles interesantes en el Marketplace, principalmente para Web pero también para Smart Devices.

Si bien estos User Controls se utilizan mayormente para cambiar el aspecto visual de las aplicaciones, puede haber casos donde sea necesario ejecutar código del usuario.

En iOS esto es muy fácil de hacer, si la implementación del control hereda de la clase GXControlBase o alguna de sus clases derivadas.

Hay dos forma de hacerlo: disparando una acción del panel o disparando un evento del control.

Disparar una acción del panel

Para disparar una acción definida en el panel donde se encuentra el User Control, alcanza con incluir el siguiente código:
[self fireActionWithName:actionName userInterfaceContext:nil withEntityData:nil];
donde self es la implementación del user control y actionName es el nombre del evento como se definió en GeneXus.

Para poder disparar esta acción, obviamente necesitamos conocer el nombre de la misma. Puede ser fijo (y estar documentado...) o se puede configurar en una propiedad.

Disparar un evento del control

Otra forma de hacerlo es definiendo un evento en el User Control.

Para esto, debemos indicar en la definición del control que define un evento. Esto se hace en el archivo .control, y la forma de hacerlo es muy simple:
<Events>
    <Event>NombreDelEvento</Event>
</Events>
Luego, en el código GeneXus, podemos escribir:
Event Control.NombreDelEvento
    ...
EndEvent
Para dispararlo desde el código Objective-C, también en este caso es una línea
[self fireControlEvent:@"NombreDelEvento" userInterfaceContext:nil withEntityData:nil];
Un ejemplo de esto último lo pueden ver en el control SD Paged Grid, que define un evento PageChanged.

Si bien las dos opciones son equivalentes en cuanto a funcionalidad, creo que es mejor la segunda porque queda más fácil de entender el código GeneXus y facilita al usuario la posibilidad de encontrar esta funcionalidad de nuestro control.


martes, 25 de marzo de 2014

Cómo hacer una aplicación para iOS en 45 minutos

Es verdad, lo reconozco, el título de la nota es un poco tendencioso(1)... Pero también es verdad lo que dice, que pude hacer una aplicación e instalarla en mi teléfono en 45 minutos, desde la idea hasta tenerla en ejecución.

La aplicación es muy simple, obviamente. Necesitaba tener algunas notas para una presentación que iba a ser sin PPTs, para no olvidarme de decir nada.

En realidad me hubiera servido cualquier aplicación de notas, pero se me ocurrió que podría ser divertido hacer la aplicación, y con GeneXus es realmente fácil, así que me animé.

La aplicación tiene dos entidades con sus respectivos "work with": Presentaciones y Notas. Las Presentaciónes tienen un Título, las Notas tienen un Titulo y una Descripción. Solo eso.

La otra pantalla que tiene la aplicación es el "modo presentación", donde se elige la presentación que voy a hacer y se muestran las notas en un Paged Grid, el título más grande y la descripción al pie. Para pasar de una nota a la siguiente, se hace un gesto de "swipe".


Lo otro que es interesante, es que la aplicación es 100% offline. De hecho, si la hubiese querido hacer online hubiera sido más difícil, porque tendría que haber usado seguridad o como mínimo agregar el Device Id a todas las tablas para saber a quién corresponde cada presentación.

No intenté pasarla a Android, pero en cuanto a UI es todo por defecto, así que debería funcionar bien sin mucho esfuerzo.

Si a alguien le interesa la puedo publicar en algún GeneXus Server...


(1)En realidad no se puede considerar una aplicación terminada, porque le faltan los iconos e imágenes, y todo el proceso de publicación en el Store, pero la aplicación está funcionando y cumple con su objetivo.

jueves, 20 de febrero de 2014

Operador condicional ternario en Objective-C

En la muchos lenguajes de programación (en los que provienen de C al menos...) existe un operador condicional ternario de la forma
condición ? expresión1 : expresión2
que evalúa la condición, y el resultado de la expresión completa será expresión1 o expresión2 según el la condición evalúe a true o false respectivamente.

En Objecive-C, la condición debe ser evaluable como una expresión booleana, por lo que se puede usar un objeto, y en ese caso el significado es el mismo que preguntar si el objeto es distinto de nil.

Por otro lado, Objective-C adopta una convención del compilador GCC (según esta respuesta en StackOverflow), donde la expresión1 es opciona, pudiendo escribir
condición ? : expresión2
y en ese caso, si la condición es verdadera, será además el resultado de la expresión completa.

¿Para qué sirve todo esto? Sirve por ejemplo para escribir una asignación cuando el valor asignado puede ser nil y en ese caso queremos asignar un valor por defecto. Algo así:
id obj = someValue ? : @"";
Creo que el código queda bastante más simple y entendible (una vez que conocemos como funciona el operador) que hacerlo con if:
id obj = someValue;
if (!obj) {
    obj = @"";
}
También tiene la ventaja que la expresión se evalúa una sola vez, lo cual es útil cuando la expresión puede ser compleja, y necesario cuando la expresión puede tener efectos secundarios.
id obj = [[some complicated] expresion] ? : @"";
Por último, al escribir solamente una vez la expresión que queremos evaluar, eliminamos código duplicado lo que, como todos sabemos, es fuente de errores.

jueves, 9 de enero de 2014

Finanzas.app

Como comentaba Rodrigo en su blog Neurona Financiera, el registro de nuestros gastos es fundamental si queremos tener controladas nuestras finanzas. Yo también pasé como él por varias etapas: una planilla Excel, un programa Visual Fox Pro hecho con GeneXus 9.0 que después migró a .Net, una aplicación web en Google App Engine.

Finanzas.app es la siguiente iteración en este ciclo, está desarrollada en GeneXus Tilo B3, y es una aplicación que funciona completamente desconectada.

El hecho de que sea Offline es el punto fuerte de la aplicación. Seguramente no se compara en funcionalidad con las alternativas (por ejemplo ZetaCuentas por nombrar otra hecha con GeneXus), pero me permite tener los datos locales sin que intervenga un tercero. No me considero extremadamente paranoico, pero cuando hablamos de dinero, prefiero no darle la información a otros...

Cómo obtener la aplicación

La aplicación la estoy desarrollando para uso personal, por lo que no me interesa distribuirla en formato binario. Esto implica que no está en mis planes publicarla en los Stores, ya que eso requiere de un trabajo que no me aporta valor en esta etapa.

Sin embargo, sí creo que puede resultar útil a otras personas, por lo que estoy dejando disponible la base de conocimiento en un GeneXus Server. La licencia que decidí usar es la de MIT como comentaba hace unos días en el blog, porque creo que es la menos restrictiva en cuanto a lo que se puede hacer con los fuentes.

La URL para obtenerla es: http://open.genexusserver.com/tilo/home.aspx?FinanzasOffline,0

La aplicación está funcionando en mi iPhone con iOS 7, no la probé en otras plataformas ni en otros dispositivos...

Modelo de datos

En cuanto al modelo de datos, es muy sencilla, consiste solamente de cuatro tablas: Movimientos, Monedas, Rubros y Tipos de Rubro.

La tabla principal es donde se registran los Movimientos, que están compuestos por una Fecha, un Origen y un Destino. Tanto el origen como el destino consisten de una Moneda, un Rubro y un Importe.

Así por ejemplo, un movimiento puede ser: Fecha: 9/1/2014, Origen: $100 efectivo, Destino: $100 almuerzo. El origen es de donde sale la plata, el destino es a donde va.

Sobre las Monedas no hay mucho para decir, tienen un nombre, un símbolo y una descrpción corta para usar en el ingreso rápido (ver más adelante la explicación).

Los Rubros tienen una descripción y un Tipo de Rubro, que es una forma de agruparlos. A su vez cada Tipo de Rubro puede ser un Ingreso, un Gasto o un Activo (es decir dinero; contadores abstenerse, seguramente el nombre no es el adecuado).

 

Ingreso rápido

En cuanto a funcionalidad tampoco hay mucho para decir. La característica principal es el "Ingreso rápido", que agiliza mucho el registro de movimientos. Esto es fundamental para que no nos resulte pesado el registro, para que no dejemos de usar la aplicación.

De hecho, el ingreso rápido es la primer pantalla que nos encontramos al abrir la aplicación. Allí vamos a ver simplemente dos campos: una fecha y una descripción.


La descripción debe tener el siguiente formato:
<moneda origen> <importe origen> <rubro origen>, <moneda destino> <importe destino> <rubro destino>
con las siguientes reglas:
  • la <moneda origen> se puede omitir, y en dicho caso se usa la moneda por defecto (que se configura en los parámetros de la aplicación)
  • el <rubro origen> se puede omitir, en cuyo caso se usa el rubro por defecto
  • la <moneda destino> se puede omitir, en cuyo caso se usa la <moneda origen>
  • el <importe destino> se puede omitir, en cuyo caso se usa el <importe origen>
  • el <rubro destino> se puede omitir, en cuyo caso se usa el rubro por defecto
  • para las monedas se usa la descripción corta que es un Character(3)
  • para los rubros se busca por LIKE, y se queda con el primero que encuentra
Esto permite que el ingreso sea muy sencillo. En el ejemplo que ponía antes, lo único que tengo que escribir es: "100, alm", suponiendo que el rubro por defecto es Efectivo y la moneda es Pesos.

Si quiero registrar un retiro de $1000 del banco, tengo que escribir simplemente "1000 banco"; y si quisiera que fuera en dólares (suponiendo que la descripción corta es "usd") debería escribir "usd 1000 banco".

Configuración inicial

Evidentemente la organización de nuestras finanzas es algo bastante personal, por lo que los rubros que cada uno defina serán los que le sirvan.

Podemos hacer la carga inicial de forma manual usando los "work with", pero esto puede ser bastante tediosos. Para facilitar la tarea, hay un data provider en la KB (llamado DatosInicialesRubros) que hace la carga inicial de Rubros y Tipos de Rubro, que cada uno deberá modificar de acuerdo a sus necesidades.

Consultas

La aplicación por el momento tiene solamente dos consultas: Resumen mensual y Saldos

El Resumen mensual muestra por Tipo de Rubro y Moneda, todos los movimientos que sean Ingreso o Gasto del mes. Se puede consultar para el mes actual y para el mes anterior.

La consulta de Saldos muestra por Rubro y Moneda para aquellos rubros que son de Activos, el saldo a la fecha especificada. La fecha puede ser hoy, el mes anterior o el año anterior.

Estado actual y futuro

Esta aplicación es la que estoy usando para el registro de gastos, desde el 1º de enero dejé de usar la aplicación que tenía antes. Por lo tanto, puedo decir que la aplicación está en producción y con el sello de calidad:


A futuro quedan sin dudas cosas a mejorar. Le falta mucho de estética, de lo que no me he preocupado por ahora, y también le falta en cuanto a funcionalidad.

Si alguien la prueba y quiere colaborar, puede pasarme los cambios que (si los apruebo) yo los publico en el GXServer. Si encuentran problemas y no los quieren arreglar... me avisan que los iré corrigiendo en la medida que tenga tiempo de hacerlo.

lunes, 23 de diciembre de 2013

Respaldo de la base de datos Offline en iTunes

El escenario principal para las aplicaciones Offline que generamos con GeneXus, se tiene un componente en el servidor donde se centralizan los datos ingresados en cada uno de los dispositivos.

En este escenario no es imprescindible hacer un respaldo de la base de datos Offline, ya que la misma siempre se puede volver a construir a partir de los datos del servidor.

Sin embargo, el generador Offline permite otro escenario donde sí puede ser importante tener respaldo de los datos: cuando la aplicación es completamente Offline y no tiene componente en el servidor.

Si bien acceder al sistema de archivos del iPhone se puede, no hay una forma "nativa" de hacerlo. Hay aplicaciones que exponen dicho sistema de archivos a la Mac o al PC, pero en general tienen algún costo.

En particular para la base de datos Offline, como se almacena en la carpeta Documents que es una carpeta especial dentro de la aplicación, es posible copiar el archivo desde iTunes como se explica en este documento de Apple.

Para lograr esto, simplemente debemos agregar una nueva clave al archivo .plist del proyecto generado (o se puede cambiar el template si lo vamos a querer siempre...). La clave que se debe agregar es UIFileSharingEnabled con valor YES. La forma de hacerlo está explicada en este documento.

Cabe aclarar que si se hace un respaldo completo del dispositivo mediante iTunes, este archivo también se respalda. Lo que se explica en esta nota es cómo respaldar solo este archivo si quisieramos hacerlo...

martes, 10 de diciembre de 2013

Licencias de software libre, ¿cuál usar?

Quisiera conocer la opinión de gente que sepa más que yo del tema de licencias de software libre, para saber cuál conviene usar.

Lo que quiero es distribuir algo(1) de la forma menos restrictiva posible, es decir, que quien lo quiera usar lo use para lo que más le convenga, y si lo quiere distribuir, vender, usar de ejemplo, o lo que sea, lo pueda hacer.

En la página de Wikipedia sobre el tema tiene varias de estas licencias, muchas de ellas no las conozco.

De las que aparecen ahí, las que más me convencen por las cosas que permiten y por ser conocidas son la de Apache, la de BSD y la de MIT.

También entiendo que existe el concepto de "copyleft" que no se muy bien como juega en todo esto.

Por el momento me inclino por la de MIT, pero acepto sugerencias :)


(1) Para que no quede demasiado misterioso, se trata de una KB GeneXus correspondiente a una aplicación para Smart Devices. Nada demasiado complicado, es de uso personal, pero que pienso puede servirle a alguien más... Ya habrá más novedades.