cuatro cosillas básicas sobre el $scope en AngularJS

La idea de scope, o mejor dicho $scope, cuando trabajo con AngularJS siempre me produce sentimientos enfrentados. Se trata de un concepto clarísimo pero a la vez tiene un toque abstracto que a veces parece escurrirse entre las neuronas así que me ha parecido una buena idea dedicar un rato a escribir(me) esta nota mental para el próximo día que me enfrente al köan que supone esta idea en mi cabeza.

 

¿Que es el scope y para que sirve?

El scope es el pegamento entre la vista y el controlador. Es ese objeto que lleva consigo los métodos y las propiedades que podemos aplicar en la vista y/o en el controlador.

¿Como funciona el scope?

La idea suena genial pero todo empieza a complicarse cuando te remangas y empiezas a hurgar en código así que voy a intentar explicarlo con un ejemplo.

Vamos a empezar con la vista. Un sencillo html de toda la vida pero con un poco de aderezo:

 

Dentro del tag body vemos tenemos dos divs cada uno con su directiva de angular. Con ng-app definimos que modulo es «responsable» de este elemento del DOM y en un elemento anidado (o en el mismo) añadimos la directiva ng-controller. En este caso counterController será el controlador responsable de ese div y así definimos el scope en la vista. Digamos que todo lo que queda dentro del elemento etiquetado con la directiva ng-controller será el scope para ese controlador.

 

Y aquí está nuestro modulo y nuestro controlador. Al controlador siempre debemos pasarle , por lo menos, $scope. Aquí debo preceder de $scope. todas las propiedades y funciones que quiero que estén accesibles desde la vista. Por ejemplo la variable counter que después se muestra en la vista. EN el controlador va precedida de $scope. igual que el método startCounter.

En cambio la variable timer o la función updateCounter solo se utilizan en el interior del controlador y por eso no es necesario añadirles ningún tipo de prefijo fuera de los standars de JavaScript.

 

 

Scope compartido utilizando un module

Esta es una entrada corta pero estoy seguro de que la revisitaré en breve ya que cada dos por tres me encuentro a mi mismo intentando evitar repetirme con los scopes.
Y la solución es tan fácil como mover el scope a un concern:

E incluirlo en los modelos en los que lo necesitemos:

Y ahora ya podemos escribir:

Nota mental: simplemente no olvides respetar las convenciones de nomenclatura y el uso del pasadoen el modulo a la hora de escribir «included».

Día 1 de 100. Mi viaje a través del #100DaysOfCode Challenge

Trata de dejar este mundo un poco mejor de lo que lo encontraste

Robert Baden Powell

Después de comprometerme con el reto no estaba muy seguro de por donde empezar. Como ya dije en mi post anterior tengo muchas razones para empezar y esto se traduce un montón de opciones pero no quería quedarme atascado en mi indecisión así que he decidido hacerlo simple y hoy he empezado trabajando en haciendo un refactor de una prueba que ya tenía publicada en mi perfil de github.

La prueba original formaba parte del proceso de selección de una compañía Británica llamada Reedsy. Resumiendo os diré que mi código no era lo que ellos esperaban pero lo digo sin ningun tipo de resentimiento, todos fueron muy majos y se tomarón la molestia de hacerme llegar un feed back sobre mi código para que pudiese mejorar mis habilidades.

Este feedback fue directo a una tarjeta de trello en mi lista de cosas que hacer hasta hoy, cuando he decidido utilizarla como punto de inicio para desarrollar una app básica en Rails 5 donde pueda aplicar algunos patrones y best practices empezando con un poco de refactor.

Veamos hasta donde nos lleva.

Tagged ,

4 razones para empezar el #100DaysOfCode

Hace ya un tiempo que vengo dando vueltas a la idea de participar en este «challenge». Llevo ya unos 10 años lidiando con código y en ocasiones podría parecer que este tipo de iniciativas van dirigidas exclusivamente a gente que quiere iniciarse en la programación pero la realidad es que se me ocurren unas cuantas razones para estar emocionado con esto:

1- Métete en tu propio código:

La primera y mas importante es que no suelo encontrar tiempo para mi propio código.

developer’s weekend

Todos los programadores nos vemos expuestos a ideas y proyectos que acaban estimulando a ese pequeño emprendedor que tenemos dentro. Ya sea para acabar lanzando nuestra propia startup o simplemente para practicar con nuevas tecnologías. La cuestión es que nunca he conocido a un desarrollador que no tuviese al menos un proyecto en mente al que le gustaría dedicar algo de tiempo. En mi caso el problema es elegir una de las muchas y muy diversas (y descabelladas) ideas y encontrar el tiempo necesario para ponerlo en marcha y he pensado que comprometerme a terminar este reto me puede ayudar a crear el habito de dedicar tiempo a mi propio código.

2- Aprende algo nuevo cada día:

Otra razón realmente importante es seguir aprendiendo. Muchas veces me encuentro a mi mismo guardando para después información muy interesante que podría aplicar en mi código pero como no tengo tiempo para investigar y experimentar acabo salvando la situación con las herramientas que ya tengo y eso es sin duda es un gran error en el que los desarrolladores con cierta experiencia solemos caer.

Tener ciertas herramientas y recursos que te han permitido abrirte paso hasta donde estás ahora está bien pero no debe ser motivo para dormirse en los laureles y dejar de aprender. Existen pocos sectores laborales en los que la necesidad de mantenerse actualizado sea tan apremiante como en el desarrollo de software y si no estas dispuesto a dedicar algo de tiempo cada día a aprender cosas nuevas quizás deberías plantearte pivotar a una profesión algo mas tradicional.

 

3- Unificar y consolidar conocimientos:

Es raro el día en el que no tropiezo con un nuevo método de Ruby que me alegra el día o una nueva forma de complicarme la vida con los comportamientos asíncronos en cualquier framework de JavasScript pero en ocasiones tengo la sensación de que todo ese conocimiento esta disperso por el limbo y no encuentro oportunidad para unificar todos esos pequeños tips, patrones y paradigmas de programación que van apareciendo en los diferentes tabs de mi navegador a medida que investigo en busca de una solución especifica para mi problema del día. El reto que propone #100DaysOfCode me da la oportunidad de explayarme con estos descubrimientos, conectando los puntos, obligándome a ir mas allá de la solución rápida buscando escenarios en los que aplicar estos conocimientos aparcados.

4- Contribuir en OpenSource:

Esta es mi gran asignatura pendiente y podría escribir un post considerablemente largo con todas las razones por las que quiero contribuir en la comunidad opensource así que aquí voy a limitarme a explicar brevemente como el reto de #100DaysOfCode puede ayudarme a conseguirlo.

Mi mayor problema a la hora de participar en un repositorio público es el tiempo. Da igual cual sea tu nivel como desarrollador porque si quieres empezar a contribuir en algún proyecto público vas a tener que invertir un montón de tiempo en entender como funciona la comunidad, como se comunican y toma decisiones, como se asignan los bugs y se deciden las prioridades, como funciona el proceso de pull request o simplemente como puedes instalar el código en local y ponerlo a funcionar en tu entorno de desarrollo. Todo eso requiere un tiempo que has de invertir voluntariamente y ¿que mejor ejercicio que comprometerte a dedicar por lo menos una hora diaria a programar para adquirir este habito?

 

 

 

Tagged ,

Refactor desde cero

Trabajando con legacy code en Ruby On Rails.

Esta semana he dedicado algo de tiempo a una de esas tareas que siempre tengo en mente pero a la que  nunca te piden que dediques tiempo hasta que ya es demasiado tarde.

En producción tenemos un controlador que se ha descuidado y se ha puesto gordo. Nuestra app sigue el model MVC y lo ideal en estos casos es seguir la norma de tener controladores lo mas escasos posibles y dejar todo el peso de la lógica dentro del modelo.

He de confesar que al principio el código del controlador era muy simple y solo pedía las conversaciones para pasarlas a la vista pero poco a poco a se ha ido echando a la espalda nuevas tareas de esas que llamamos «sencillitas» y ha acabado  algo orondo.

 

Antes de nada es importante definir que esta haciendo el controller:

  • Comprueba que el usuario actual no sea el admin y si lo es le pasa un mensaje de error.
    • Si no es admin:
    • comprueba si existe el params[:users] y si existe lo añade como parametro para la acción que utilizamos para conseguir la lista de conversaciones.
    • Aplica la paginación a esta lista.
    • Si el layout es nuevo y existe el parametro params[:new_layout] añade al json un campo is_new_count con un valor integer que corresponde al numero de conversaciones que son nuevas.
    • Si no es new_lay_out añade al json el resultado de c.patient.formated_answers.

El primer paso es mover todas las acciones que hay dentro del controlador a acciones externas, en este caso métodos privados del controlador, a los que llamaré desde el index.

Mi plan es que estas acciones se encarguen unicamente de llamar a métodos del modelo.

A la hora de testear empezaré con los métodos del modelo y luego comprobando que las acciones del controlador llaman a esos métodos.

Modelos

En el modelo del usuario he definido este metodo:

Hay un parte del código que manipula patients_emails. Esto forma parte de un filtro que ya no se utiliza así que se puede eliminar del código dejando al metodo la única tarea de comprobar el rol del usuario actual y aplica el scope where_last_message_is_not_nil sobre la colección de conversaciones de este usuario.

Este es el código del test para el scope:

Y este el test para el método conversations_as_current_user:

 

El siguiente metodo a testear será new_conversations_count que encadena el metodo anterior con  dos scopes y nos devuleve el numero de elementos que hay en la colección:

Eston son los dos scopes:

Y estos los tests para los dos scopes:

Una vez testeados los scopes el test del método sólo tiene que asegurar que se encadenará la llamada a los 2 scopes sobre la colección que proporciona conversations_as_current_user:

 

Controlador

Muevo toda la lógica de query para conseguir la lista de conversaciones en función del rol del usuario y del layout que utiliza a un metodo privado fuera del controlador principal:

Y hago lo mismo con lógica que comprueba si estamos en la última pagina, consulta el numero de conversaciones nuevas y el proceso que da formato a la info relativa a las conversaciones que queremos enviar en nuestro json:

Dejandonos con un controlador mucho mas fácil de leer y que solo se encarga de llamar a distintos métodos

El testing de los controladores ya solo tiene que preocuparse de que el index llame a cada uno de los metodos pero esto es otra historia y como este post me ha quedado realmente largo dejaré esta cuestión para otro post.

La mejor manera de determinar lo indeterminado (en javascript, no en la vida)

llevo un par de días (o algo mas de una semana) luchando con un pequeño reajuste que estamos realizando en el código en AngularJS en el que estoy trabajando.
Me voy a ahorrar los detalles que seguramente no le interesen a nadie, ni a mi yo del futuro, y voy a ir directo al grano:
Antes teníamos un valor por defecto en una variable nada mas iniciar el cliente. En relación a esta variable se realizaban ciertas comprobaciones pero llego un momento en el que se decidió que era mejor no cargar ningún valor por defecto en esa variable y esperar a la interacción del usuario para asignarle un valor a esa variable.
Eliminar ese valor por defecto, que era el primero de una lista de conversaciones, parecía coser y cantar pero resulta que el cliente podía seguir recibiendo toda una serie de eventos (utilizamos pusher para gestionar los eventos con su triggers y binds) y algunos de ellos esperaban encontrarse ese valor por defecto para compararse con el y al no encontrarlo nos daba un feisimo error de esos de undefined for que tanto duele y jode.
Después de localizar todas las partes del código donde había que controlar la existencia del valor antes de utilizarlo me he encontrado con que saber si es null o undefined no era tampoco una pregunta trivial.
En este enlace de stackoverflow sugieren dos metodos:


if (typeof variable === 'undefined' || !variable)

Y el otro:

if (variable == null)

Y como en la mayoría de cosas en la programación una vez que tienes dos maneras de hacer algo ya se ha abierto el debate.
Lo bueno y malo de la segunda propuesta es que en algunos casos devuelve un ReferenceError. Por ejemplo si la variable ni se ha llegado a declarar.
Los que defienden este método se apoyan en la idea de que este mensaje de error puede ayudar a debuggar y que ademas conlleva una forma de escribir y estructurar codigo mucho mas ordenada.
En mi caso he de confesar que me he decantado por la primera opción ya que es mas genérica y me permite revisar si la variable existe ya o todavía no. En e caso en elq ue estoy trabajando me encuentro con que esa variable se declará tarde o temprano y no necesito (o eso creo yo) el ReferenceError que interrumpa el flujo del código.

Tagged

MongoDB quiere comerse mi disco

Después de un par de días ignorando las alertas que ubuntu me estaba mostrando para avisarme de que me estoy quedando sin espacio en el directorio raíz he decidido empezar la semana con buen pie y dedicarle un rato a ver de que podía deshacerme.
En ocasiones me encuentro con que sufro una especie de síndrome de Diogenes cuando se trata de ponerme a borrar cosas del disco. Nunca tengo muy claro si debo guardarlo para un futuro en el que pueda hacerme falta….

Superada esta primera fase de apego emocional a mis datos he visto en el resultado del análisis de uso de disco que estaba ocupando mas de 3 gigas en la carpeta de mongodb/journal
Resulta que para agilizar el acceso a la info mongodb genera una serie de archivos con nombre prealloc que ocupan bastante espacio. Es una solución cojonuda para un servidor de producción (o integración en el que dispones de espacio de sobras) ya que segurisisisimo que mejorar la performance una barbaridad, pero para el caso que me ocupa, que es mi pobre ordenador y mi entorno de desarrollo minimalista, lo mejor será que me deshaga de ellos.
De todos modos la próxima vez que ponga en marcha mongodb volverá a generarlos a no ser que modifique la configuracion en /etc/mongodb.conf añadiendo:

nojournal = true
noprealloc = true

4 o 5 cosas básicas que hay que saber de Redis

Enfrentarme a Redis era una de esas cosas que me daban pereza, miedo y emoción a partes iguales.
Algo dentro de mi intuía que incorporar esta herramienta no iba a ser cosa de 5 minutos.

Si eres algo curioso tienes que haber oído hablar de este motor de bases de datos en memoria. Quizás nunca lo has utilizado pero si no lo has visto en ninguna oferta de trabajo o en la descripción de algún proyecto es que algo estas haciendo mal.

Como primer acercamiento este tutorial sirve para hacerse una idea del nivel al que trabaja esta herramienta.
Como bien explican en el tutorial Redis es un sistema de almacenamiento basado en una relación de clave y valor (key/value de toda la vida, vamos)

SET counter 5
GET counter => 5

Nos proporciona un SET y GET totalmente intuitivos que nos permite inicializar y acceder al valor que queramos guardar con la clave server:name en este caso.


SETNX connections 10
INCR connections => 11
INCR connections => 12
DEL connections

SETNX nos permite inicializar unicamente si la clave no existe ya.
DEL sorprendentemente nos permite deshacernos del par clave/valor.
INCR es un incrementador unitario que también nos permite crear el par key/value en el caso de que este no exista de forma atómica (es decir que crea el par y lo inicializa con valor 1 en una sola acción).


EXPIRE connections 120
TTL connections => 119

EXPIRE es un comando muy practico que nos permite ponerle fecha de caducidad a nuestra pareja. En el ejemplo le damos 120 segundos de vida. Al ejecutar TTL connections el resultado será el tiempo que le queda antes de expirar, si ya ha expirado el resultado será -2 y si no tiene fecha de caducidad será -1.

Con Redis podemos gestionar lista en el mismo formato key/value. LPUSH, RPUSH añaden valores al principio y al final de la lista respectivamente:

RPUSH fruits "banana"
RPUSH fruits "apple"
LPUSH fruits "coconut"
LRANGE fruits 0 -1 => 1) "coconut", 2) "banana", 3) "apple"
LRANGE fruits 0 1 => 1) "coconut", 2) "banana"

LRANGE nos da acceso a un rango determinado de los elementos de la lista utilizando el primer parámetro como inicio del rango y el segundo como final. Si como segundo parámetro pasamos -1 nos dará todos los valores que queden en la lista.

LLEN nos devuelve el numero de elementos en la lista y LPOP y RPOP eliminan un elemento del principio y final respectivamente:


LLEN fruits => 3
LPOP fruits
LLEN fruits => 2
LRANGE fruits 0 -1 => 1) "banana", 2) "apple"
RPOP fruits
LLEN fruits => 1
LRANGE fruits 0 -1 => 1) "banana"

Otra estructura de datos propia de Redis son los SET. A mi personalmente me viene bien imaginar los SETS como listas sin un orden especifico.


SADD racers "Mario"
SADD racers "Donkey Kong"
SADD racers "Wario"
SADD racers "Cactus Jack"
SREM racers "Cactus Jack"
SISMEMBER racers "Mario" => 1
SISMEMBER racers "Cactus Jack" => 0
SMEMBERS racers => 1) "Mario", 2) "Donkey Kong", 3) "Wario"
SADD plumbers "Mario"
SADD plumbers "Luigi"
SUNION racers plumbers => 1) "Luigi", 2) "Mario", 3) "Donkey Kong", 4) "Wario"


SADD permite añadir elementos y SREM elminarlos. SISMEMBERS devuelve 1 si el elemento esta en el SET y 0 si no esta. SMEBERS nos muestra todo el SET y SUNION permite unir dos SETS distintos.

La siguiente estructura de datos que encontramos en el tutorial son los SORTED SETS. Estos SETS permiten asignarle a cada registro una puntuación o score que sirve para acceder a cada elemento y ordenarlos.


ZADD hackers 1940 "Alan Kay"
ZADD hackers 1906 "Grace Hopper"
ZADD hackers 1953 "Richard Stallman"
ZADD hackers 1965 "Yukihiro Matsumoto"
ZADD hackers 1916 "Claude Shannon"
ZADD hackers 1969 "Linus Torvalds"
ZADD hackers 1957 "Sophie Wilson"
ZADD hackers 1912 "Alan Turing"
ZRANGE hackers 2 4 => 1) "Claude Shannon", 2) "Alan Kay", 3) "Richard Stallman"

La estructura de datos mas practica en el caso de trabajar con objetos es el HASH. El HASH nos permite guardar en un mismo registro diferentes pares del tipo clave/valor.


HSET user:1000 name "John Smith"
HSET user:1000 email "john.smith@example.com"
HSET user:1000 password "s3cret"
HGETALL user:1000
1) "name"
2) "John Smith"
3) "email"
4) "john.smith@example.com"
5) "password"
6) "s3cret"
HMSET user:1001 name "Mary Jones" password "hidden" email "mjones@example.com"
HGET user:1001 name
"Mary Jones"

HSET permite inicializar de uno en uno distintos pares key/value en el HASH y HMSET permite hacerlo con varios al mismo tiempo. HGETALL devolverá todo el contenido del HASH mientras que HGET devolverá el par especificado mediante la clave.

El tutorial termina con las versiones para HASH de INCR y DEL en el caso de que el valor sea numérico.


HSET user:1000 visits 10
HINCRBY user:1000 visits 1 => 11
HINCRBY user:1000 visits 10 => 21
HDEL user:1000 visits
HINCRBY user:1000 visits 1 => 1

Esta colección de comandos tan básicos serán el abc a la hora de trabajar con Redis tanto si se hace directamente vía consola o a través de cualquier otra herramienta o framework.

Nadie dijo que login out fuese fácil (Rails API + devise the hard way part 2)

Después de unos cuantos días dándome contra un muro en los que parecía que ni el mismísimo Google iba a ser capaz de sacarme de este embrollo he encontrado una solución. Por supuesto podría ser muchísimo mejor, de hecho seguramente es vergonzosa pero por lo menos es una solución que permite seguir adelante.

Ya estaba yo celebrando que había pasado lo peor cuando conseguí generar y guardar un token via Curl en mi nueva API en Rails. Mi gozo en un pozo cuando me encontré con que al ejecutar el comando curl que debería destruir la sesión a la vez que convertir en nil el token del usuario lo único que recibía era un soso mensaje diciendo algo así como:

«Filter chain halted as :verify_signed_out_user rendered or redirected
Completed 204 No Content in 1ms (ActiveRecord: 0.0ms)»

Por suerte no estaba solo en mi desgracia, después de indagar algo y utilizar las palabras adecuadas en mi búsqueda fui a dar con esta pregunta en SO. la respuesta sugerida parecía totalmente coherente: skip_before_action :verify_signed_out_user

Easy as 1,2,3: Si lo que estaba frenando mi controlador era un filtro de nombre «verify_signed_out_user» skipearlo iba a ser suficiente. Pero resulta que al skipearlo el resultado no era mucho mas placentero:

«Completed 401 Unauthorized in 1ms»

Horas de googleo después me encontré con este pobre hombre que ya había pasado por mi misma situación.

La respuesta me resultó algo críptica. Era como un kōan

,cuanto mas leía la respuesta mas en blanco se quedaba mi mente. Entendía cada una de las partes pero cuando intentaba unirlo todo mi código seguía sin funcionar.

 

Necesito saltarme el filtro «verify_signed_out_user» porque este filtro te redirije y no deja continuar la acción una vez que el usuario ya no está logeado al igual que la primera linea «warden.authenticate!…»

Una vez solucionado esto el siguiente paso es sustituir current_user(hay que recordar que al destruir la sesión ya no tenemos el current_user en ningun sitio) por el usuario que queremos actualizar nilificando el valor del token.

 

De profesión API o la historía de como descubrí que token authenticatable estaba obsoleto(RailsAPI + devise the hard way part 1)

«Haz una API con Rails y devise» dijerón. «Será fácil» decian.
Y yo me lo creí.
El primer tutorial con pies y cabeza que encontré solucionaba la parte de backend en 3 sencillos pasos y yo me las prometía felices.

¿Mi primer fallo? No darme cuenta de que el tutorial tenía fecha del 2012 y la versión utilizada de Rails es la 3.2 algo desactualizada si tenemos en cuenta que a día de hoy ya vamos por la 5.x.

¿El primer obstáculo? En el primer paso del tutorial el autor indica que hay que configurar el modelo para habilitar el uso del modulo token_authenticatable de devise y si lo haces recibirás un verbosico error diciéndote que algo falla porque la propiedad token_authenticatable no existe.

Después de un par de cabezazos contra el monitor y de aporrear la tecla enter varias veces a ver si así se solucionaba entre en razón he hice lo que cualquier desarrollador con años de experiencia haría: buscar en google.

Como de costumbre en stackoveflow me encuentro con que no soy el primero en enfrentarme al reto que se me presenta y en esta publicación encuentro algunas respuestas y comentarios muy interesante. Muchos de ellos abre nuevos debates sobre como gestionar los tokens, cuando y como decidir su caducidad y como compartirlos pero a mi en este momento lo que me interesa es saber cual es el problema con el modulo autheticatable que se suponía que iba a hacerme la vida tan fácil.

En un enlace a otra pregunta encuentro una respuesta muy elaborada que me descubre que el modulo que estoy intentando utilizar esta obsoleto debido a que es vulnerable a timing attacks. También me ofrecen una solución en forma de gemma (benditas gemmas!!).

Pero fue en los comentarios de uno de los issues de esta gemma donde encontré la solución por la que voy a apostar ahora mismo. He de reconocer que, cuando se trata de añadir bundles o gemmas a un proyecto, las que tienen la palabra simple o easy en el nombre son mi debilidad. Después de indagar un poco en los docs de ambas tengo la sensación de que la primera cubre una serie de features mucho mas amplia que la segunda y que ahora mismo no creo necesitar.

A pesar de todo la parte abstracta detrás del ejemplo que estaba siguiendo no tiene porque haberse quedado obsoleta y los pasos lógicos que indica siguen siendo validos (o eso creo yo) así que voy a seguir ese camino.