sábado, 4 de octubre de 2014

No hemos cambiado nada

Dentro de unos días, en Uruguay vamos a tener elecciones parlamentarias y presidenciales. Como siempre en estos casos hay campaña y hay temas que se destacan por sobre otros.

Uno de los temas a los que más importancia se le ha dado, es el de la seguridad pública. Más allá de los argumentos y posturas que cada uno pueda tener, me interesaba comentar una frase que leí hace poco.

Para ponerle un poco de contexto, es una frase en medio de un diálogo, que transcribo:
- ¿Hablan ustedes del asesinato [...]?
- Sí. ¿Ha oído usted hablar de este crimen?
- ¿Cómo no? Ha ocurrido en las cercanías de la casa donde me hospedo.
- ¿Conoce usted los detalles?
- Los detalles, no, pero este asunto me interesa por la cuestión general que plantea. Dejemos a un lado el aumento incesante de la criminalidad durante los últimos cinco años en las clases bajas. [...]
Y resalto "el aumento incesante de la criminalidad durante los últimos cinco años". Parece sin duda una frase sacada del debate previo a las elecciones. De hecho, podría ser una frase de cualquier debate electoral de cualquier parte del mundo, de los últimos tiempos.

Nosotros, los que vivimos de la tecnología, pensamos que el mundo cambia muy rápido. Sin embargo, hay cosas que no cambian...

De hecho, este diálogo es de la novela Crimen y Castigo, escrita en Rusia en 1866 por Fiódor Dostoyevsky, y todo parece indicar que hace 150 años, tenían más o menos los mismos problemas que tenemos hoy en día.




jueves, 2 de octubre de 2014

GX24

Se terminó otro Encuentro GeneXus, el número 24 en esta oportunidad. Otra vez un muy buen evento con una organización impecable y charlas de muy buen nivel.

Hubo muchas charlas interesantes, no pude ver todas las que quería así que ahora me tengo que poner al día.

Sobre la temática de las charlas, vi que hubo muchas charlas sobre diseño. Es una opinión subjetiva, pero creo que muchas más que en eventos anteriores. No creo que sea casualidad que se hable tanto de diseño: en la medida que maduran las plataformas (Smart Devices en particular, pero también Web) y los usuarios se acostumbran a aplicaciones de mejor nivel de diseño, nos exige a nosotros los desarrolladores de aplicaciones a pensar más en este tema.

Una conclusión a la que todos llegan, es que el diseño tiene que ser parte del desarrollo de la aplicación desde el primer momento, y no ser algo que se agrega luego de terminar la funcionalidad.

También vi que hubo muchas charlas sobre "cloud computing", otro tema que cobra cada vez más importancia.

Con respecto a mi charla, creo que salió bien. El tema era "Sincronización en aplicaciones Offline", y la idea era hacer una charla de unos 15 minutos y luego dejar otros 15 para preguntas. Debo reconocer que me daba un poco de miedo que no hubiera preguntas, o que fueran muy específicas o de errores puntuales que alguien pudiera tener. Pero por suerte no, las preguntas fueron lo suficientemente generales y de buen nivel, así que todo bien :)

Si quieren ver la charla, está disponible en el sitio del evento.

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.