Author Archives: admin

Mito de gestión: Puedo medir el trabajo por el tiempo que la gente pasa en la oficina

Resumen: Incrementar la cantidad de tiempo que alguien pasa en la oficina no resulta directamente en mejorar su trabajo. De hecho, dependiendo de la persona, puede ser que pase lo contrario – pasar menos tiempo en la oficina puede mejorar los resultados. Johanna afronta los mitos de medir el trabajo por el tiempo.

[Fuente: http://www.stickyminds.com/sitewide.asp?Function=edetail&ObjectType=ART&ObjectId=17791&tth=DYN&tt=siteemail&iDyn=2]

Seapine

“¿Te has enterado lo nuevo que está haciendo Andrew?” preguntó Gabe, moviendo su cabeza según iba con Cynthia hacia la cafeteria.

“No, qué es?” dijo Cynthia.

“Tenemos que rellenar fichas de tiempo poniendo nuestro tiempo de trabajo real. Él quiere conocer cuanto tiempo inverimos trabajando realmente en la oficina. Cuanto más tiempo, más trabajo”

Cynthia le paró. “¿Estás hablando en serio? Creia que lo había visto todo , pero esto realmente se lleva la palma”.

“Sí. Se supone que nosotros seguimos un ritmo constante.Pero está tarjeta de tiempo va a provocar que nuestro ritmo sea todo menos constante.No entiendo porque cree que puede medir nuestra productividad por el tiempo que pasamos en la oficina. Yo tengo buenos días y malos días. Algunas veces, creo que paso mucho menos tiempo aquí en los días buenos y se produce el doble. Desde luego , algunas veces . dejo de escribir código en los malos días porque estoy produciendo cuatro veces el número de bugs en el código!.”

Cynthia sonrió. “Bien , yo he tenido ciertamente ese tipo de días. Cómo podemos hacer ver a Andrew de que va mal por ese camino?. Quizás habla con Tina , el otro director , para hablar con él?”

“Quizás. O quizás deberíamos explicar que la velocidad no tiene mucho que ver con el tiempo que pases en la oficina. Quizás, podemos medir nuestra productividad por semana ahora y medir nuestra productividad por semana después que él insista en que hagamos horas extras. Lo qué tenemos que hacer nuestro dolor suyo, porque esto es totalmente una locura”.

Tiempo no son resultados

He visto managers intentar premiar a sus empleados con el número de horas que los coches de los empleados estaban en el parking. La gente puede trucar el tiempo que pasas en la oficina fácilmente- sólo deja el coche aparcado en la oficina una semana. Un compañero de trabajo lo hizo y se lo encontró sepultado por una montaña de nieve después de una tormenta de nieve inesperada. Los gestores estaban sorprendidos y enfadados por el engaño del empleado.

Cuando se utiliza el tiempo como la medida de cuanto de bueno es el trabajo de un trabajador, tu les estas favoreciendo que usen la picaresca y se comporten de forma extraña. Tiempo en la oficina no es equivalente a buen trabajo. Nunca lo ha sido , y nunca lo será. Está claro que no se puede sacar la tarea adelante sin empeñar tiempo en ello sea donde sea , en la oficina o en tu casa , pero eso no significa que que tengas que hacer horas extras.

 

Cuanto tiempo de máximo puede trabajar una persona al día?

Los días de cada uno son distintos, pero hay un límite razonable de cuantas horas se puede trabajar en un día. La gente puede trabajar bien alrededor de ocho horas en un día , sobre todo hablando de un trabajo que requiere cierto esfuerzo intelectual o mental antes de que empiece el cansancio mental. Algunas personas pueden trabajar como máximo algo menos de ocho horas. Esto quiere decir que si quieres trabajadores que realicen la tarea, entonces debes restringir su tiempo de trabajo a no más de ocho horas al día.

Se empieza a hacer un ranking de las tareas pendientes

Cuando tu valores el tiempo que la gente pasa en la oficina , ellos empezarán a hacer decisiones sobre el trabajo a realizar. Empezarán a posponer el trabajo que no es prioritario y a priorizar las otra tareas. Ellos empiezan a crear sus propios planings y a priorizar los trabajos en el proyecto.

Asi es normal que si no lo tienen claro empiecen a preguntarte cuáles son las tareas más críticas.

 

Lo primero que se hace , eliminar todas las reuniones

Una vez que están priorizadas las tareas y se ha hecho el reparto de las mismas , lo siguiente es examinar la cantidad de tiempo que gastamos en reuniones.

Si decides que solo puedes trabajar ocho horas , entonces debes de tomar decisiones sobre las reuniones. Necesitas asistir? ¿Puede ir alguien en tu lugar? Quizás no necesites esa reunión.

Si la reunión es importante , entonces la apuntas en la agenda. No durará demasiado. Tendrá un “Orden del día” y alguíe la dirigirá. Si las reuniones que te invitan no cumplen estos requisitos entonces mejor que no asistas

 

Cómo es la rutina de tu día de trabajo?

Yo me he dado cuenta que hay como tres momentos del día en los que se está trabajando más productivamente: dos horas por la mañana y otros dos paquetes de dos horas por la tarde. Esto hace un total de 6 horas de trabajo. Algunos compañeros de profesión me dicen que ellos a menudo tiene menos de esas seis horas. Cuantas más experiencia tiene el manager , menos trozos de tiempo , porque el manager tiende a hacer más reuniones e interrupciones.

Of course, the more geographically distributed the project team is, the more email is a part of the team’s work. That’s unfortunate, because there is plenty of other email that is not part of a technical person’s work that arrives in an inbox. The more email a person has to process, the less time for technical work. The longer a person can go between processing email, the more technical work a person can do. It is just that simple.

One of the most productive things you can do for email processing is to turn of any signals that tell you that more email has arrived. Assume you have more email. It’s a good assumption. Then, decided how many times a day you can safely process email.

When I explain this trick to my coaching clients, there is always a pregnant pause. “But, I’m supposed to answer email within five minutes of receiving it!” If people want you to answer a question right away, then they should pick up the phone or text you. Email is for low-bandwidth communication (a fact that runs counter to yet another popular office myth).

Mide los resultados , y no el tiempo en la oficina

Los trabajadores experimentados trabajan a distintos ritmos en días diferentes. Algunos días son rápidos. Algunos lentos. No quieras saber cuánto me llevo escribir algunas partes de este artículo , sin embargo el es resultado es el artículo completo, que es lo que cuenta.

Tú pagas a tu gente por las funcionalidades desarrolladas. Si quieres más funcionalidades , asegurate que no trabajen más de 40 horas a la semana. Menos horas puede ser incluso mejor, pero lo que es cierto que trabajar más horas por semana lo única que te garantiza con peores resultados.

 

Desarrollar para iPhone o para Android

[Fuente:http://www.error500.net/desarrollar-para-iphone-o-para-android/]

App Store

Dos plataformas en el móvil sobre las que desarrollar software casi antagónicas.iPhone y Android han dado mucho que hablar – y más que darán – como alternativas al actual escenario en el que domina Symbian, RIM sigue creciendo y Windows Mobile no tiene buena pinta. Por aquí hemos hablado mucho de ellas, pero merece la pena analizar ambos modelos de plataforma móvil para entender la visión del futuro de la informática personal e internet que tienen ambas compañías.

Vocación de plataforma frente a acercamiento inevitable

Android fue pensado desde el primer momento como una plataforma sobre la que cualquiera pudiese construir aplicaciones. Apple, por otro lado, pensó en iPhone como un terminal para aplicaciones web que no exigiesen instalación. El éxito del Installer entre otros factores empujó a la compañía de Jobs a cambiar de rumbo y abrir el dispositivo a terceros. Google llegó a gastarse varios millones de dólares en un concurso, para que Android llegase al mercado con bastantes aplicaciones.

Apertura total o controlada

Cualquiera puede desarrollar para Android, creando aplicaciones con la funcionalidad que se le ocurra. La apertura de Android llega a la plataforma en sí, con licencia Apache, por lo que cualquier fabricante u operador puede utilizarla, adaptándola a sus necesidades sin pagar un céntimo. Por su parte Apple ejerce control sobre iPhone, qué aplicaciones se pueden distribuir y hasta se reserva una puerta trasera para desinstalarlas. Lo último, contratos de confidencialidad que impidan hacer público que una aplicación ha sido rechazada en la AppStore (EsferaiPhone).

El éxito del concepto de tienda de aplicaciones

Ambas plataformas se apoyan en una “tienda de aplicaciones” integrada en el terminal que permite la compra, descarga e instalación de software de terceros de una forma fácil y centralizada. En el caso de iPhone tenemos la App Store y en el caso del primer móvil con Android, es la operadora quien la gestiona.

Teléfono t-mobile g1 con android

Plataformas para internet

Coinciden en su vocación para articular dispositivos que permitan estar siempre conectados. Se comercializan con una tarifa plana de datos (más o menos buena) y vienen preconfigurados con aplicaciones y servicios para la red: correo, cliente de vídeos, calendario integrado con el online, tiendas de contenidos (iTunes y Amazon respectivamente),…

Integración con servicios online

La plataforma como palanca para fidelizar o captar usuarios de los servicios online. En el caso de Android, su integración con el ecosistema Google es muy marcada, aunque cualquiera puede desarrollar aplicaciones que compitan con él. Con iPhone esto no es tan claro, por el control que ejerce Apple para proteger a iTunes o Mobile Me.

Negocio para el dueño de la plataforma

Apple controla todo el ciclo y todo el negocio alrededor de iPhone: precio del terminal, negociación con las operadoras, ventas de música y aplicaciones (de las que se lleva una comisión), servicios extra como MobileMe, comisión por publicidad en las búsquedas en el terminal… Android no llega a estas cotas, pero apuesta por Google como motor de búsqueda predeterminado (empuja el negocio principal), trae la tienda de Amazon (lo que apunta a comisiones) y su apuesta por el posicionamiento del usuario será la base de la publicidad por proximidad.

Finalmente, experiencia de usuario frente a modelo abierto

Tanto Android como iPhone son plataformas con una visión basada en el teléfono como nueva puerta a la red, con el que estar siempre conectados a internet y sobre las montar otros negocios. Donde son radicalmente opuestas es en la estrategia principal para lograr constituirse en una referencia: Android es abierto, se puede llevar a dispositivos de varios fabricantes, cualquiera puede desarrollar sobre él… y Apple apuesta por controlar la experiencia de usuario, ofreciendo una solución en la que crea o supervisa todos los aspectos de la misma.

Hemos discutido mucho sobre esta estrategia, que está cerca de constituirse en un cambio de paradigma en la informática personal y sobre la que hay numerosas voces criticas, como la la dirección de Nokia España, que no ve relación directa entre cerrar el código o la plataforma y dar una mejor experiencia de usuario. En todo caso, parece evidente que Android potencia mucho más el desarrollo de terceros sobre su plataforma, mientras que Apple constituye más barreras de entrada. ¿Será decisivo el grado de apertura en que los programadores se animen a desarrollar más para una que para otra? En este punto creo que las decisiones son pragmáticas, si los usuarios se mueven a entornos más cerrados, los desarrolladores les seguirán por mucho que no les guste el control.

Una competencia fascinante puesto que enfrenta dos modos de entender el futuro de la informática personal y de la web . Cierto que ya existen Symbian, Windows Mobile, OpenMoko y RIM entre otros y que es injusto atribuir a Android el mérito de estrategias ya presentes en los productos que llevan más tiempo en el mercado, pero estoy convencido de que iPhone y Android han venido para quedarse y reconfigurar el mercado de la telefonía móvil.

Ámbitos y Alcance en Javascript

[Fuente: http://pensamientoobjetivo.blogspot.com.es/2009/09/ambitos-y-alcance-en-javascript.html]

Dependiendo de los lenguajes programación en los que hemos programado con anterioridad, en Javascript nos podemos topar con algunas sorpresas, y no todas ellas son agradables, Específicamente, puede ser un problema si venimos de un background de lenguajes con alcance de bloque (c, c++, java, etc.) o sin él (basic, pascal, etc.). Ya que el alcance en Javascript puede ser la fuente de bugs muy difíciles de encontrar, a continuación hacemos un pequeño recuento de cómo funcionan los ámbitos de variable en Javascript.

El ámbito “global”

En la mayor parte de los navegadores web actuales, el objeto window es el espacio global que contiene todas las funciones base del lenguaje y todas las variables y funciones que serán definidas en este.

Si se declara una variable, usted verá que usted puede hayarla en el objeto window:

var miAncho = 100;
miAltura = 200;

alert( window['miAncho'] ); // "100"

alert( window.miAncho );    // también muestra "100"

alert( window['miAltura'] ); // "200"
alert( window.miAltura === miAltura ); // "true"

Obviamente, no todo es accesible desde el objeto window, ya que en Javascript podemos usar el ámbito de nivel de función.

Declaración de variables

Tal vez esto sea obvio para muchos, pero para mi inicialmente fue una duda que durante algún tiempo limitó mi entendimiento de Javascript. En Javascript, es perfectamente válido declarar una variable con la palabra reservada var ¡O sin ella! (a todos los que hemos programado en Basic alguna vez, nos trae hermosos recuerdos de lo grandioso que nos parecía esta “característica”… hasta que nos ocasionó nuestro primer dolor de cabeza).

La idea básica que debemos entender es que var no es solo lo que la abreviación parece indicar: una declaración de una variable, sino por el contrario, es la definición del alcance de la misma. En el ejemplo anterior hemos usado ambas notaciones y podemos ver que en el caso del alcance global, el ámbito de la variable no se modifica.

// Al estar en el ámbito global, ambas lineas
// son equivalentes
var miAltura = 100;
miAltura = 100;

En el espacio de nombres global, la instrucción var no tiene ninguna repercusión, por lo que podemos hacer algo como esto:

var miAltura = 100;
miAncho = 100;

function muestraVariables() {
 alert( miAltura + ' y ' + miAncho);
}

Las variables declaradas en el ámbito global serán accesibles desde dentro de todas las funciones, pues todas están también contenidas en el objeto window. Sin embargo, las cosas cambian cuando usamos var en el contexto de funciones. A continuación vemos un ejemplo en el que var modifica el alcance de una variable:

var miAltura = 100;
miAncho = 100;

function muestraVariables() {
 alert( miAltura + ' y ' + miAncho);
 var miColor='#000000';
 miFondo='#FFFF00';
}

function muestraColores() {
 alert( miColor + ' y ' + miFondo );
}

muestraVariables(); // "100 y 100"
muestraColores();   // "undefined y #FFFF00"

Aquí es conveniente prestar mucha atención a la manera en que muestraVariables define variables. La variable miColor está definida usando var, mientras que miFondo no la usa. De hecho, cuando una variable es definida sin utilizar var dentro de una función, tras bambalinas esto es como Javascript lo interpretaría:

function muestraVariables() {
 alert( miAltura + ' y ' + miAncho);
 var miColor = '#000000';
 window.miFondo = '#FFFF00';
}

Cada variable que no se defina usando la instrucción var en el contexto de una función, será asignada al objeto window y por lo tanto se convierte en una variable global.

Una variable definida dentro de una función con la palabra var se vuelve inaccesible desde el exterior, y es por ello que podemos decir que efectivamente se convierte en una variable privada.

También es posible crear funciones dentro de otras funciones:

function muestraVariables() {
 var miColor ='#000000';

 var miOtraVariable = function () {
     return miColor;
 }

 alert( miOtraVariable() );  // "#000000"
}

// fuera de la función
alert( miOtraVariable() );   // ¡Error!

Las variables definidas dentro de muestraVariables son inaccesibles fuera de ella, aunque miOtraVariable guarde una referencia a una función. Sin embargo, podemos ver que la función anidada si tiene acceso a miColor, ya que la función misma está definida dentro de muestraVariables.

Por lo anterior, podemos concluir que se debe evitar colocar variables e incluso funciones en el ámbito global, ya que por ejemplo, si se usa el mismo nombre de variable o función en dos archivos JS distintos, el último de ellos “sobreescribe” las definiciones del anterior, lo que en un momento dado implica que ¡Es posible que no estemos trabajando con las funciones o variables que pensamos!

En Javascript, el último en llegar gana.

En realidad, esto no es muy relevante si solo usamos una o dos funciones en una página web, pero cuando tenemos que trabajar en un equipo de desarrollo, cuando utilizamos o tenemos que convivir con código de terceros o cuando incorporamos bibliotecas externas en nuestra aplicación y si todos ellos colocan sus variables y funciones en el contexto global es posible que tengamos un mal rato tratando de entender porqué no obtenemos los resultados que esperamos, ¡Pensando incluso que se trata de un bug en nuestro código!

Alcance de nivel de bloque

En Javascript no existe el ámbito de variables a nivel de bloques, por lo que debemos estar atentos al hecho de que cualquier variable definida dentro de un bloque de código (for, while, if, switch, etc) será accesible desde el ámbito inmediato superior (siguiendo las reglas explicadas anteriormente con respecto al uso de var).

if( miAncho == 100) {
   var miAltura=200;
}
alert( miAltura ); // "200"

Esta es una diferencia fundamental con respecto a Java, en el cual el tiempo de vida de una variable termina al cerrarse el bloque que la contiene.

for(var i=0; i<=100; i++) {
   miColor=i;
}

for(; i<50; i++) {
   miAncho=i;
}

alert(miColor); //100
alert(miAncho); //error

Al definir la variable i con la palabra reservada var no se le da alcance de bloque dentro del ciclo for. Por lo tanto, al entrar al siguiente ciclo, el valor de i es 100, por lo que nunca se entra al segundo ciclo.

Esto no significa que no debamos definir variables dentro de bloques. Es importante que las variables se declaren lo más cerca posible del lugar en el que se usarán para aumentar la claridad de nuestro código. En este aspecto, es similar a utilizar Dim en Basic para declarar una variable dentro de un IF o un WHILE. Aunque posición de la declaración no cambia la semántica de la misma, si tiene un efecto en el potencial de comunicación de esta.

Objetos, Funciones y alcance

Hemos visto que la palabra var solo tiene significado dentro del contexto de una función, lo que nos habilita a tener variables privadas y globales si así lo deseamos. Sin embargo, las funciones nos posibilitan un nivel más de alcance: el “nombre” de la función.

Hemos visto que todas las variables definidas dentro de una función sin la instrucción var son asignadas al objeto window. Ok, pero digamos que queremos escribir código limpio y evitar el uso de variables globales, ¿Cómo podemos hacerlo?

De hecho, fuera de una función, en el ámbito global, podemos usar otro método para referirnos al objeto window mediante otra palabra reservada: this.

La palabra this tiene un papel muy importante en Javascript, pero al mismo tiempo es una fuente de confusión cuando se comienza a programar en este lenguaje.

Poniéndolo de forma llana, this siempre “apunta” al contexto actual en el que se está ejecutando nuestro código. Veamos por ejemplo:

miColor = 100;

alert( this.miColor );    // 100
alert( window.miColor );  // 100
alert( window === this ); // true

Como podemos ver, this en el ámbito global hace referencia al objeto window.

Por otro lado, las funciones también nos permiten utilizar this, pero en este caso, this no se referirá al objeto window. ¿Entonces a qué?

Como se mencionó anteriormente, todas las funciones están siempre asociadas a un objeto. Si la función se declara globalmente, entonces están asociadas al objeto window; si son “métodos” de un objeto, entonces están asociadas a ese objeto. Y this siempre apuntará al contexto dentro del cual se ejecuta una función, por lo que dependiendo de la forma en que llamemos a una función, puede afectar el contexto al que apunta this:

function miFunc() {
  alert( this === window );
}
miFunc();     // true
new miFunc(); // false

En este caso, this está apuntando a algo más que no es el objeto window. Para entender qué es ese algo, veamos cómo interpreta Javascript la última linea del ejemplo:

new miFunc();
 temp = new Object();

 temp.miFunc = miFunc;
 temp.miFunc()

Cuando se usa una función para inicializar un objeto (usando la palabra new, se dice que esta función es el constructor de ese objeto y el nombre de esa función se convierte en la clase del objeto.

Podemos comprobar que this se refiere a un objeto con el nombre de la función utilizando el operador instanceof, que nos dice si un objeto es de una “clase” específica o bien la propiedad constructor:

function miFunc() {
  alert(this instanceof miFunc);
  alert(this.constructor == miFunc);
}

miFunc();     // false, false
new miFunc(); // true, true

Todo esto puede sonar un poco confuso. Trataré de explicarme: Al usar la palabra reservada new se crea un objeto temporal en el background por nosotros, el mismo que se asociará al nombre de nuestra función. Pero, ¿para qué nos sirve esto?

Bueno, en primer lugar nos habilita a utilizar un nivel más de alcance, el de objeto, que es similar al concepto de variables de instancia de los lenguajes orientados a objetos tradicionales. Con esto tenemos 3 niveles distintos:

function pruebaAlcance() {
    global = 100;

    var privada = 200;

    this.publica = 300;

    this.metodoPublico = function() {
         alert( 'puedo ser usado desde el objeto pruebaAlcance' );
    }
    var metodoPrivado = function() {
        alert( '¡No puedes llamarme desde el exterior!' );
    }
}
pruebaAlcance();

alert( global ); // 100

alert( privada ); // error

alert( pruebaAlcance.privada ); // undefined

alert( pruebaAlcance.publica ); // 300

alert( publica ); // undefined

alert( pruebaAlcance.metodoPublico() ) // 'puedo ser... etc'

alert( metodoPublico() ) // error

alert( pruebaAlcance.metodoPrivado() ); // error

alert( metodoPrivado() ); // error

Los niveles de alcance de Javascript pueden parecer extraños en un principio y puede costar trabajo acostumbrarse a ellos en un principio, pero también pueden ser una herramienta poderosa al momento de construir bibliotecas o convivir con código de terceros sin pisar los dedos de nadie más.

Las diferentes formas de declarar variables o métodos dentro de una función u objeto es la base mediante la cual se pueden simular espacios de nombres (namespaces) en Javascript y son la base de las técnicas orientadas a objetos del mismo.

Espero haya sido de su interés.

Este post fue publicado originalmente el 30 de Septiembre de 2008 en un blog anterior y posteriormente perdido en un crash de servidor.

Una guia de campo para Mobile App Testing

[Fuente: http://mobile.smashingmagazine.com/2012/10/22/a-guide-to-mobile-app-testing/]

 

Los testers son a menudo vistos como gente que encuentra fallos, pero alguna vez has considerado como los testers de hecho abordan el testing? Te has preguntado qué hacen realmente, y cómo pueden añadir valor a un proyecto de tecnología típico?

En este artículo explicaremos los procedimientos que siguen los testers y discutir los tipos de cosas que ellos consideran cuando prueban una mobile app. La intención aqui es sacar a la luz los procesos de pensamientos y mostrar la cobertura y profundidad a la que a menudo llegan los testers.

 

Los testers Hacen preguntas.

En lo fundamental del testing está la capacidad de hacer preguntas desafiantes y relevantes. Estás en el buen camino de convertirte en un buen tester si combinas habilidades de hacer preguntas con habilidades de investigación teniendo conocimiento de la tecnología y los productos.

Por ejemplo , los testers se pueden hacer preguntas como:

  • What platforms should this product work on?
  • What is the app supposed to do?
  • What happens if I do this?

And so forth.

Testers find questions in all sorts of places. It could be from conversations, designs, documentation, user feedback or the product itself. The options are huge… So, let’s dive in!

Where To Start Testing

In an ideal world, testers would all have up-to-date details on what is being built. In the real world, this is rare. So, like everyone else, testers make do with what they have. Don’t let this be an excuse not to test! Information used for testing can be gathered from many different sources, internally and externally.

At this stage questions, testers might ask these questions:

  • What information exists? Specifications? Project conversations? User documentation? Knowledgeable team members? Could the support forum or an online company forum be of help? Is there a log of existing bugs?
  • What OS, platform and device should this app work on and be tested on?
  • What kind of data is processed by the application (i.e. personal, credit cards, etc.)?
  • Does the application integrate with external applications (APIs, data sources)?
  • Does the app work with certain mobile browsers?
  • What do existing customers say about the product?
  • How much time is available for testing?
  • What priorities and risks are there?
  • Who is experiencing pain, and why?
  • How are releases or updates made?

Based on the information gathered, testers can put together a plan on how to approach the testing. Budgets often determine how testing is approached. You would certainly approach testing differently if you had one day instead of a week or a month. Predicting outcomes gets much easier as you come to understand the team, its processes and the answers to many of these types of questions.

EXAMPLE: SOCIAL COMMENTARY ON THE FACEBOOK APP

I love using the Facebook app as an example when I’m gathering information as a tester. Complaints of it are everywhere. Just check out the comments in the iTunes App Store for some of the frustrations users are facing. Plenty more are dotted across the Web.


Facebook’s iPhone App has a lot of negative reviews.

If I were challenged to test the Facebook app, I would definitely take this feedback into consideration. I would be daft not to!

The Creativity Of Testers

You probably know what the app is meant to do, but what can it do? And how will people actually use it? Testers are great at thinking outside of the box, trying out different things, asking “What if” and “Why” constantly.

For example, mobile testers will often adopt the mindset of different types of people — not literally, of course, but the ability to think, analyze and visualize themselves as different users can be quite enlightening.

Testers might put themselves in these shoes:

  • Novice user,
  • Experienced user,
  • Fan,
  • Hacker,
  • Competitor.

Many more personalities could be adopted; much of this really depends on what you are building. But it’s not just about personalities, but about behavior and workflows, too. People use products in strange ways. For example, they:

  • Go back when they are not supposed to,
  • Are impatient and hit keys multiple times,
  • Enter incorrect data,
  • Can’t figure out how to do something,
  • Might not have the required setup,
  • Might assume they know what they are doing (neglecting to read instructions, for example).

Testers look for these situations, often discovering unexpected results along the way. Sometimes the bugs initially found can appear small and insignificant, whereupon deeper investigation uncovers bigger problems.

Many of these issues can be identified up front with testing. When it comes to testing mobile apps, these might not all be relevant, but perhaps try asking questions such as these:

  • Does it do what it says on the tin?
  • Does the app perform the tasks it was designed to do?
  • Does the app perform tasks that it wasn’t designed to do?
  • How does the app perform when being used consistently or under a load? Is it sluggish? Does it crash? Does it update? Does it give feedback?
  • Do crash reports give clues about the app?
  • How can one navigate creatively, logically or negatively around the app?
  • Does the user trust your brand?
  • How secure is the user’s data?
  • Is it possible to break or hack the app?
  • What happens when you push the app to its limits?
  • Does the app ask to turn on related services? (e.g. GPS, Wifi)? What if the user does? Or doesn’t?
  • Where does the app redirect me? To the website? From website to app? Does it cause problems?
  • Is communication and marketing consistent with the app’s function, design and content?
  • What is the sign-up process like? Can it be done on the app? On a website?
  • Does sign-up integrate with other services such as Facebook and Twitter?

EXAMPLE: RUNKEEPER’S BUGGY UPDATE

RunKeeper, an app to track your fitness activities, recently released an update with new “Goal Setting” features. I was interested in giving it a try, a bit from a testing perspective, but also as a genuinely interested user. I discovered a few problems.

  1. It defaulted to pounds. I wanted weights in kilograms.
  2. Switching between pounds and kilograms just didn’t work properly.
  3. This ended up causing confusion and causing incorrect data and graphs to be shown when setting my goals.
  4. Because of that, I wanted to delete the goals, but found there was no way to do it in the mobile app.
  5. To work around this, I had to change my weight so that the app would register the goal as being completed.
  6. I could then try adding the goal again.
  7. Because of all of this confusion, I played around with it a bit more to see what other issues I could find.

Below are some screenshots of some of the issues found.

RunKeeper Date Bug
A recent update of RunKeeper included a new “Goals” section. Playing around with its dates, I discovered start and end dates could be set from the year 1 A.D. Also, why two years with “1”?

Run Keeper Typo Bug
Another RunKeeper bug. This one is a typo in the “Current Weight” section. This happened when removing the data from the field. Typos are simple bugs to fix but look very unprofessional if ignored.

Run Keeper Goals Bug
Here is the confusion that happened as a result of trying to switch between pounds and kilograms. If I want to lose 46 pounds, the bar actually shows 21 pounds.

There is no quick way to identify issues like these. Every app and team faces different challenges. However, one defining characteristic of testers is that they want to go beyond the limits, do the unusual, change things around, test over a long period of time — days, weeks or months instead of minutes — do what they have been told is not possible. These are the types of scenarios that often bring up bugs.

Where’s All The Data?

Testers like to have fun with data, sometimes to the frustration of developers. The reality is that confusing either the user or the software can be easy in the flow of information. This is ever more important with data- and cloud-based services; there is so much room for errors to occur.

Perhaps you could try checking out what happens in the following scenarios:

  • The mobile device is full of data.
  • The tester removes all of the data.
  • The tester deletes the app. What happens to the data?
  • The tester deletes then reinstalls the app.
  • Too much or too little content causes the design or layout to change.
  • Working with different times and time zones.
  • Data does not sync.
  • Syncing is interrupted.
  • Data updates affect other services (such as websites and cloud services).
  • Data is processed rapidly or in large amounts.
  • Invalid data is used.

EXAMPLE: SOUP.ME IS WRONG

I was trying out Soup.me, a Web service that sorts your Instagram photos by map and color, but I didn’t get very far. When I tried to sign up, it said that I didn’t have enough Instagram photos. This is a lie not true because I have published over 500 photos on my Instagram account. It’s not clear what the problem was here. It could have been a data issue. It could have been a performance issue. Or perhaps it was a mistake in the app’s error messages.

SoupMe

ANOTHER EXAMPLE: QUICKLYTICS

Quickytics is a Web analytics iPad app. In my scenario, a website profile of mine still exists despite my having deleted it from my Google Analytics account. My questions here are:

  • I have deleted this Web profile, so why is this still being displayed?
  • The left panel doesn’t appear to have been designed to account for no data. Could this be improved to avoid confusing the user?

Quicklytics

Testers like to test the limits of data, too. They will often get to know the app as a typical user would, but pushing the limits doesn’t take them long. Data is messy, and testers try to consider the types of users of the software and how to test in many different scenarios.

For example, they might try to do the following:

  • Test the limits of user input,
  • Play around with duplicate data,
  • Test on brand new clean phone,
  • Test on an old phone,
  • Pre-populate the app with different types of data,
  • Consider crowd-sourcing the testing,
  • Automate some tests,
  • Stress the app with some unexpected data to see how it copes,
  • Analyze how information and data affects the user experience,
  • Always question whether what they see is correct,

Creating Errors And Messages

I’m not here to talk about (good) error message design. Rather, I’m approaching this from a user and tester’s point of view. Errors and messages are such common places for testers to find problems.

QUESTIONS TO ASK ABOUT ERROR MESSAGES

Consider the following questions:

  • Is the UI for errors acceptable?
  • Are error messages accessible?
  • Are error messages consistent?
  • Are they helpful?
  • Is the content appropriate?
  • Do errors adhere to good practices and standards?
  • Are the error messages security-conscious?
  • Are logs and crashes accessible to user and developer?
  • Have all errors been produced in testing?
  • What state is the user left in after an error message?
  • Have no errors appeared when they should have?

Error messages quite often creep into the user experience. Bad and unhelpful errors are everywhere. Trying to stop users from encountering error messages would be ideal, but this is probably impossible. Errors can be designed for and implemented and verified against expectations, but testers are great at finding unexpected bugs and at carefully considering whether what they see could be improved.

SOME EXAMPLES OF ERROR MESSAGES

I like the example below of an error message in the Facebook app on the iPhone. Not only is the text somewhat longwinded and sheepishly trying to cover many different scenarios, but there is also the possibility that the message gets lost into the ether.

Perhaps the messages below are candidates for the Hall of Fame of how not to write messages?

A badly written message. A badly written message.

What about this one from The Guardian’s app for the iPad? What if I don’t want to “Retry”?

The Guardian's

Platform-Specific Considerations

Becoming knowledgeable about the business, technology and design constraints of relevant platforms is crucial for any project team member.

So, what types of bugs do testers look for in mobile apps?

  • Does it follow the design guidelines for that particular platform?
  • How does the design compare with designs by competitors and in the industry?
  • Does the product work with peripherals?
  • Does the touchscreen support gestures (tap, double-tap, touch and hold, drag, shake, pinch, flick, swipe)?
  • Is the app accessible?
  • What happens when you change the orientation of the device?
  • Does it make use of mapping and GPS?
  • Is there a user guide?
  • Is the email workflow user-friendly?
  • Does the app work smoothly when sharing through social networks? Does it integrate with other social apps or websites?
  • Does the app behave properly when the user is multitasking and switching between apps?
  • Does the app update with a time stamp when the user pulls to refresh?
  • What are the app’s default settings? Have they been adjusted?
  • Does audio make a difference?

EXAMPLE: CHIMPSTATS

ChimpStats is an iPad app for viewing details of email campaigns. I first started using the app in horizontal mode. I got a bit stuck as soon as I wanted to enter the API key. I couldn’t actually enter any content into the API field unless I rotated it vertically.

ChimpStats

ChimpStats

Connectivity Issues And Interruption

Funny things can happen when connections go up and down or you get interrupted unexpectedly.

Have you tried using the app in the following situations:

  • Moving about?
  • With Wi-Fi connectivity?
  • Without Wi-Fi?
  • On 3G?
  • With intermittent connectivity?
  • Set to airplane mode?
  • When a phone call comes in?
  • While receiving a text message?
  • When receiving an app notification?
  • With low or no battery life?
  • When the app forces an update?
  • When receiving a voicemail?

These types of tests are a breeding ground for errors and bugs. I highly recommend testing your app in these conditions — not just starting it up and checking to see that it works, but going through some user workflows and forcing connectivity and interruptions at particular intervals.

  • Does the app provide adequate feedback?
  • Does data get transmitted knowingly?
  • Does it grind to a halt and then crash?
  • What happens when the app is open?
  • What happens midway through a task?
  • Is it possible to lose your work?
  • Can you ignore a notification? What happens?
  • Can you respond to a notification? What happens?
  • Is any (error) messaging appropriate when something goes wrong?
  • What happens if your log-in expires or times out?

Maintaining The App

Speeding up the process of testing an app is so easy. Test it once and it will be OK forever, right?

Think again.

One problem I’m facing at the moment with some apps on my iPad is that they won’t download after being updated. As a user, this is very frustrating.

Perhaps this is out of the control of the app’s developer. Who knows? All I know is that it doesn’t work for me as a user. I’ve tried removing the app and then reinstalling, but the problem still occurs. I’ve done a bit of searching; no luck with any of my questions, aside from suggestions to update my OS. Perhaps I’ll try that next… when I have time.

The point is, if the app was tested once and only once (or over a short period of time), many problems could have gone undetected. Your app might not have changed, but things all around it could make it break.

When things are changing constantly and quickly, how does it affect your app? Ask yourself:

  • Can I download the app?
  • Can I download and install an update?
  • Does the app still work after updating?
  • Can I update the app when multiple updates are waiting?
  • What happens if the OS is updated?
  • What happens if the OS is not updated?
  • Does the app automatically sync downloading to other devices via iTunes?
  • Is it worth automating some tasks or tests?
  • Does the app communicate with Web services? How would this make a difference?

Testing your mobile app after each release would be wise. Define a set of priority tests to cover at each new release, and make sure the tests are performed in a variety of conditions — perhaps on the most popular platforms. Over time, it might be worth automating some tests — but remember that automated tests are not a magic bullet; some problems are spotted only by a human eye.

EXAMPLE: ANALYTICS APP ON THE IPHONE

I’ve had this app for two years now. It’s worked absolutely fine until recently; now, it has been showing no data for some of my websites (yes, more than one person has visited my website over the course of a month!). A quick look at the comments in the app store showed that I wasn’t the only one with this problem.

Here is another example from the Twitter app for the iPhone. After updating and starting up the app, I saw this message momentarily (Note: I have been an active tweeter for five years). I got a bit worried for a second! Thankfully, the message about having an empty timeline disappeared quickly and of its own accord.

Testing Is Not Clear-Cut

We’ve covered some ground of what mobile testing can cover, the basis of it being: with questions, we can find problems.

All too often, testing is thought of as being entirely logical, planned and predictable, full of processes, test scripts and test plans, passes and fails, green and red lights. This couldn’t be further from the truth.

Sure, we can have these processes if and when necessary, but this shouldn’t be the result of what we do. We’re not here just to create test cases and find bugs. We’re here to find the problems that matter, to provide information of value that enables other project members to confidently decide when to release. And the best way we get there is by asking questions!

(al)

Illustrator Leccion 1: qué es Illustrator?

[Fuente: http://www.vectordiary.com/illustrator/what-is-illustrator/]

 

Sobre  Adobe Illustrator

Illustrator es un programa de dibujo vectorial. Se utiliza a menudo para dibujar ilustraciones , dibujos animados, diagramas , gráficas y logos. A diferencia de las imágenes bitmap que almacenan info en un grid de píxeles, Ilstrator utiliza ecuaciones matemáticas para dibujar las formas. Esto hace que los gráficos vectoriales sean escalables sin perder resolución.

 

Ventajas de gráficos vectoriales

  • Son escalables sin perdida de resolución
  • Las lineas son bien definidas en cualquier tamaño
  • Se pueden hacer impresiones de alta resolución
  • Tamaño pequeño de fichero
  • Es bueno para dibujar ilustraciones

Desventajas de los gráficos vectoriales

  • Los dibujos tienden a ser todos parecidos: todos son planos y como dibujos animados
  • Es dificil producir dibujos realistas, es decir estilo fotográfico

Casos comunes donde utilizamos Illustrator

1) Diseño de Logos

Designing logos
By: Draplin Design

2) Dibujo de mapas

drawing maps

3) Dibujo de ilustraciones

drawing illustrations

By: Chih Hang

4) Infografias

infographics

5) Dibujos fotorealistas

camera
By: Kevin Hulsey

6) Diseño de envases
packaging design

By: sanna annukka

Estos son unos pocos ejemplos de lo que Ilsutrator puede hacer, Si tienes experiencia con Photoshop , entonces

This are just a few examples of what Illustrator can do. If you have experience with Photoshop, you can bring your illustrations into Photoshop and enchance it. That’s how professional does it. During the next few days, I will be covering the basics of Illustrator so that you can produce your first vector art!

 

Opencart: pasos para empezar a programar

[Fuente: http://www.opencart.com/index.php?route=documentation/documentation&path=77_67]

Actualizado para versión 1.5

Aquí hay un plan paso a paso para instalar manualmente Opencart par usuarios avanzados o programadores.

A. Paso Uno – Leer documentación

Antes de que inviertas tu valioso tiempo y energía en instalar Opencart, hay alguna información que necesitas leer. Opencart es un gran sistema de shopping cart; es fácil de utilizar y es potente.

  1. Cinco tipos diferentes de e-commerce (link externo)
  2. Comparación de Wikipedia de software de shopping cart (link externo)
  3. Lista de características de Opencart
  4. Requerimientos técnicos para instalar Opencart
  5. Opencart FAQ’s

B. Paso Dos – Preparación

Basado en el información que acabas de leer, incluyendo los requerimientos técnicos de Opencart. deberías tener una lista de las cosas que necesitas, y de las cosas que necesitas hacer. Si no la tienes, hazla ahora — asegurate de incluir la siguiente información:

  1. ¿Dónde está alojado tu site? Sugerimos que leas el tema del foro Web hosts. Who’s good and who to avoid
  2. Debes contactar con la empresa de tu hosting  si no estás seguro de si tienes estas settings:
  3. (Estos requerimientos son automáticamente chequeados en la instlaaciónThis requirement will be  automatically checked on installation.)

PHP Setting

PHP Version 5+Register Globals: Off

Magic Quotes GPC: Off File Uploads: On

Session Auto Start: Off

Extensions

MySQL: On

GD: On

cURL: On

ZIP: On

2. ¿Qué otras herramientas utilizar? Ver: Tools
3. ¿Has revisado Opencart Extensions? Asegurate de que la extensión que vas a realizar no existe ya.

C. Paso Tres – Instalación

  1. Antes de empezar , asegurate de comprobar que la versión de OC en OC Version y descarga la última versión en download .
  2. Sube tus ficheros al host
  3. Echale un ojo a los fallos documentadosKnown BUGS topic for All OC Versions.
  4. Resolución de problemas después de una instalación o una actualización: Troubleshooting
  5. Después de Install – Pasos sugeridos para asegurar la aplicación:
    • Set index.php to 444 to avoid any outside script attacks
    • Set config.php and admin/config.php to 444
    • Password protect the admin directory with htpasswd/.htaccess
    • Install SSL Certificate – ask your web host

D. Paso 4 – Checklist para programadores

  1. Eres nuevo con Opencart y quieres desarrollar por ti mismo; empieza aqui:  Official DocumentationFramework Explanation] & Framework structure.
  2. Esto es lo más cercano a un  Opencart API: OpenCart Global Library Methods.
  3. Necesitas un tutorial para hacer alguna customization: Collection of Tutorial.
  4. Necesitas extensiones adicionales: Free or Commercial.
  5. Necesitas ayuda comercial: Opencart Development Partner.

E. Step Five – Basic Set Up
Configuration Checklist
Remove Demo Data

  1. Read this first: Remove All Demo Data.
  2. Remove user group Demonstration ( System -> Users -> User Group )
  3. Remove demo coupons ( Sales -> Coupons )
  4. Remove Products, Categories & Manufacture ( Catalog -> Product | Categories | Manufacture )
  5. Delete products image n cache ( image/data/*  &  image/data/chache/* )
  6. Remove Reviews ( Catalog -> Reviews )

Minimum Settings

  1. Store information & setting ( System -> Setting )
  2. Language & Curencies ( System -> Localisation -> Languages | Curencies )
  3. Choose payment method ( Extensions -> Payments )
  4. Choose shipping method ( Extensions -> Shipping )
  5. Modules ( Extensions -> Modules )

Pre-Launch Checklist

  • Check Product (also Categories & Manufacture) :
  • – Tag keyword, Description and Poduct tags.
  • – Status, Price, Quantity and SEO keyword.
  • Checkout process & Payment work well.
  • Basic function is work well: add to cart, search, bookmark, curency and language switch.
  • Information page (ex. about us, privacy policy).

Marketing Checklist

  • SEO Setting:
  • – Use SEO setting ( System -> Setting -> Server Tab)
  • – Rename htaccess.txt to .htaccess
  • – SEO keyword not blank on Product, Categories and Information
  • Social media & Product Feed ( Extensions -> Products Feed )
  • Newsletter subscriptions

Slow

  • Recupere el silencio cuando sea posible, es una sana costumbre. ¿Has probado alguna vez a estar unas horas sin radio ni televisión, escuchando la música de su propio cuerpo o cantando su propia canción?

 

  • ¿Que tal si nos quedamos en casa y disfrutamos del barrio y del entorno cuando llega un puente?

 

  • Recuerde que ir lejos , deprisa , no es obligatorio ni necesariamente satisfactorio

 

  • ¿Le tiene secuestrado el correo electrónico? Si usted no trabaja en el 112, tal vez podría limitarse a consultarlo sólo en la mañana y en la noche.

 

  • Comer es comer , ver la televisión es otra cosa. Cuando se come sin tener la televisión puesta se puede recuperar el placer de la conversación (y , si se come solo , de la charla amigable con uno mismo)

 

  • En los accidentes domésticos, un gran porcentaje se produce por ir corriendo a contestar e teléfono. ¿No cree usted que correr dentro de la casa es un vicio y no una virtud?

 

  • Nos hacen creer que vivir es estar siempre haciendo cosas. ¿Has probado a dejarse estar algún tiempo sin la necesidad de hacer algo?

 

  • Su calidad de vida depende de sus elecciones. Si recupera tiempo, podrá elegir lo que hace en gran parte del día.

Qué son los REST Services

[Fuente: http://www.dosideas.com/noticias/java/314-introduccion-a-los-servicios-web-restful.html]

La Transferencia de Estado Representacional (REST – Representational State Transfer) fue ganando amplia adopción en toda la web como una alternativa más simple a SOAP y a los servicios web basados en el Lenguage de Descripción de Servicios Web (Web Services Descripcion Language – WSDL). Ya varios grandes proveedores de Web 2.0 están migrando a esta técnología, incluyendo a Yahoo, Google y Facebook, quienes marcaron como obsoletos a sus servicios SOAP y WSDL y pasaron a usar un modelo más facil de usar, orientado a los recursos.

Veamos los principios de REST para entender más esta tecnología.

Presentando REST

REST define un set de principios arquitectónicos por los cuales se diseñan servicios web haciendo foco en los recursos del sistema, incluyendo cómo se accede al estado de dichos recursos y cómo se transfieren por HTTP hacia clientes escritos en diversos lenguajes. REST emergió en los últimos años como el modelo predominante para el diseño de servicios. De hecho, REST logró un impacto tan grande en la web que prácticamente logró desplazar a SOAP y las interfaces basadas en WSDL por tener un estilo bastante más simple de usar.

REST no tuvo mucha atención cuando Roy Fielding lo presentó por primera vez en el año 2000 en la Universidad de California, durante la charla academica “Estilos de Arquitectura y el Diseño de Arquitecturas de Software basadas en Redes”, la cual analizaba un conjunto de principios arquitectónicos de software para usar a la Web como una plataforma de Procesamiento Distribuido. Ahora, años después de su presentación, comienzan a aparecer varios frameworks REST y se convertirá en una parte integral de Java 6 a través de JSR-311.

Los 4 principios de REST

Una implementación concreta de un servicio web REST sigue cuatro principios de diseño fundamentales:

  • utiliza los métodos HTTP de manera explícita
  • no mantiene estado
  • expone URIs con forma de directorios
  • transfiere XML, JavaScript Object Notation (JSON), o ambos

A continuación vamos a ver en detalle estos cuatro principios, y explicaremos porqué son importantes a la hora de diseñar un servicio web REST.

REST utiliza los métodos HTTP de manera explícita

Una de las caraterísticas claves de los servicios web REST es el uso explícito de los métodos HTTP, siguiendo el protocolo definido por RFC 2616. Por ejemplo, HTTP GET se define como un método productor de datos, cuyo uso está pensado para que las aplicaciones cliente obtengan recursos, busquen datos de un servidor web, o ejecuten una consulta esperando que el servidor web la realice y devuelva un conjunto de recursos.

REST hace que los desarrolladores usen los métodos HTTP explícitamente de manera que resulte consistente con la definición del protocolo. Este principio de diseño básico establece una asociación uno-a-uno entre las operaciones de crear, leer, actualizar y borrar y los métodos HTTP. De acuerdo a esta asociación:

  • se usa POST para crear un recurso en el servidor
  • se usa GET para obtener un recurso
  • se usa PUT para cambiar el estado de un recurso o actualizarlo
  • se usa DELETE para eliminar un recurso

Una falla de diseño poco afortunada que tienen muchas APIs web es el uso de métodos HTTP para otros propósitos. Por ejemplo, la petición del URI en un pedido HTTP GET, en general identifica a un recurso específico. O el string de consulta en el URI incluye un conjunto de parámetros que definen el criterio de búsqueda que usará el servidor para encontrar un conjunto de recursos. Al menos, así como el RFC HTTP/1.1 describe al GET.

Pero hay muchos casos de APIs web poco elegantes que usan el método HTTP GET para ejecutar algo transaccional en el servidor; por ejemplo, agregar registros a una base de datos. En estos casos, no se utiliza adecuadamente el URI de la petición HTTP, o al menos no se usa “a la manera REST”. Si el API web utiliza GET para invocar un procedimiento remoto, seguramente se verá algo como esto:

GET /agregarusuario?nombre=Zim HTTP/1.1

Este no es un diseño muy atractivo porque el método aquí arriba expone una operación que cambia estado sobre un método HTTP GET. Dicho de otra manera, la petición HTTP GET de aquí arriba tiene efectos secundarios. Si se procesa con éxito, el resultado de la petcición es agregar un usuario nuevo (en el ejemplo, Zim) a la base de datos. El problema es básicamente semántico. Los servidores web están diseñados para responder a las peticiones HTTP GET con la búsqueda de recursos que concuerden con la ruta (o el criterio de búsqueda) en el URI de la petición, y devolver estos resultados o una representación de los mismos en la respuesta, y no añadir un registro a la base de datos. Desde el punto de vista del protocolo, y desde el punto de vista de servidor web compatible con HTTP/1.1, este uso del GET es inconsistente.

Más allá de la semántica, el otro problema con el GET es que al ejecutar eliminaciones, modificaciones o creación de registros en la base de datos, o al cambiar el estado de los recursos de cualquier manera, provova que las herramientas de caché web y los motores de búsqueda (crawlers) puedan realizar cambios no intencionales en el servidor. Una forma simple de evitar este problema es mover los nombres y valores de los parámetros en la petición del URI a tags XML. Los tags resultantes, una representación en XML de la entidad a crear, pueden ser enviados en el cuerpo de un HTTP POST cuyo URI de petición es el padre de la entidad.

Antes:

GET /agregarusuario?nombre=Zim HTTP/1.1

Después:

POST /usuarios HTTP/1.1
Host: miservidor
Content-type: application/xml

<usuario>
    <nombre>Zim</nombre>
</usuario>

El método acá arriba es un ejemplo de una petición REST: hay un uso correcto de HTTP POST y la inclusión de los datos en el cuerpo de la petición. Al recibir esta petición, la misma puede ser procesada de manera de agregar el recurso contenido en el cuerpo como un subordinado del recurso identificado en el URI de la petición; en este caso el nuevo recurso debería agregarse como hijo de /usuarios. Esta relación de contención entre la nueva entidad y su padre, como se indica en la petición del POST, es análoga a la forma en la que está subordinado un archivo a su directorio. El cliente indica esta relación entre la entidad y su padre y define el nuevo URI de la entidad en la petición del POST.

Luego, una aplicación cliente puede obtener una representación del recurso usando la nueva URI, sabiendo que al menos lógicamente el recurso se ubica bajo /usuarios

GET /usuarios/Zim HTTP/1.1
Host: miservidor
Accept: application/xml

Es explícito el uso del GET de esta manera, ya que el GET se usa sólamente para recuperar datos. GET es una operación que no debe tener efectos secundarios, una propiedad también conocida como idempotencia.

Se debe hacer un refactor similar de un método web que realice actualizaciones a través del método HTTP GET. El siguiente método GET intenta cambiar la propipedad “nombre” de un recurso. Si bien se puede usar el string de consulta para esta operación, evidentemente no es el uso apropiado y tiende a ser problemático en operaciones más complejas. Ya que nuestro objetivo es hacer uso explícito de los métodos HTTP, un enfoque REST sería enviar un HTTP PUT para actualizar el recurso, en vez de usar HTTP GET.

Antes:

GET /actualizarusuario?nombre=Zim&nuevoNombre=Dib HTTP/1.1

Después:

PUT /usuarios/Zim HTTP/1.1
Host: miservidor
Content'Type: application/xml

<usuario>
    <nombre>Dib</nombre>
</usuario>

Al usar el método PUT para reemplazar al recurso original se logra una interfaz más limpia que es consistente con los principios de REST y con la definición de los métodos HTTP. La petición PUT que se muestra arriba es explícita en el sentido que apunta al recurso a ser actualiza identificándolo en el URI de la petición, y también transfiere una nueva representación del recurso del cliente hacia el servidor en el cuerpo de la petición PUT, en vez de transferir los atributos del recurso como un conjunto suelo de parámetros (nombre = valor) en el mismo URI de la petición.

El PUT arriba mostrado también tiene el efecto de renombrar al recurso Zim a Dib, y al hacerlo cambia el URI a /usuarios/Dib. En un servicio web REST, las peticiones siguientes al recurso que apunten a la URI anterior van a generar un error estándard “404 Not Found”.

Como un principio de diseño general, ayuda seguir las reglas de REST que aconsejan usar sustantivos en vez de verbos en las URIs. En los servicios web REST, los verbos están claramente definidos por el mismo protocolo: POST, GET, PUT y DELETE. Idealmente, para mantener una interfaz general y para que los clientes puedan ser explícitos en las operaciones que invocan, los servicios web no deberían definir más verbos o procedimientos remotos, como ser /agregarusuario y/actualizarusuario. Este principio de diseño también aplica para el cuerpo de la petición HTTP, el cual debe usarse para transferir el estado de un recurso, y no para llevar el nombre de un método remoto a ser invocado.

REST no mantiene estado

Los servicios web REST necesitan escalar para poder satisfacer una demanda en constante crecimiento. Se usan clusters de servidores con balanceadores de carga y alta disponibilidad, proxies, y gateways de manera de conformar una topología serviciable, que permita transferir peticiones de un equipo a otro para disminuir el tiempo total de respuesta de una invocación al servicio web. El uso de servidores intermedios para mejorar la escalabilidad hace necesario que los clientes de servicios web REST envien peticiones completas e independientes; es decir, se deben enviar peticiones que incluyan todos los datos necesarios para cumplir el pedido, de manera que los componentes en los servidores intermedios puedan redireccionar y gestionar la carga sin mantener el estado localmente entre las peticiones.

Una petición completa e independiente hace que el servidor no tenga que recuperar ninguna información de contexto o estado al procesar la petición. Una aplicación o cliente de servicio web REST debe incluir dentro del encabezado y del cuerpo HTTP de la petición todos los parámetros, contexto y datos que necesita el servidor para generar la respuesta. De esta manera, el no mantener estado mejora el rendimiento de los servicios web y simplifica el diseño e implementación de los componentes del servidor, ya que la ausencia de estado en el servidor elimina la necesidad de sincronizar los datos de la sesión con una aplicación externa.

Servicios con estado vs. sin estado

La siguiente ilustración nos muestra un servicio con estado, del cual una aplicación realiza peticiones para la página siguiente en un conjunto de resultados múlti-página, asumiendo que el servicio mantiene información sobre la última página que pidió el cliente. En un diseño con estado, el servicio incrementa y almacena en algún lugar una variable paginaAnteriorpara poder responder a las peticiones siguientes.

servicio web stateful

Los servicios con estado tienden a volverse complicados. En la plataforma Java Enterprise Edition (Java EE), un entorno de servicios con estado necesita bastante análisis y diseño desde el inicio para poder almacenar los datos eficientemente y poder sincronizar la sesión del cliente dentro de un cluster de servidores. En este tipo de ambientes, ocurre un problema que le resulta familiar a los desarrolladores de servlets/JSP y EJB, quienes a menudo tienen que revolver buscando la causa de una java.io.NotSerializableException cuando ocurre la replicación de una sesión. Puede ocurrir tanto sea en el contenedor de Servlets al intentar replicar la HttpSession o por el contenedor de EJB al replicar un EJB con estado; en todos los casos, es un problema que puede costar mucho esfuerzo resolver, buscando el objeto que no implementa Serializable dentro de un grafo complejo de objetos que constituyen el estado del servidor. Además, la sincronización de sesiones es costosa en procesamiento, lo que impacta negativamente en el rendimiento general del servidor.

Por otro lado, los servicios sin estado son mucho más simples de diseñar, escribir y distribuir a través de múltiples servidores. Un servicio sin estado no sólo funciona mejor, sino que además mueve la responsabilidad de mantener el estado al cliente de la aplicación. En un servicio web REST, el servidor es responsable de generar las respuestas y proveer una interfaz que le permita al cliente mantener el estado de la aplicación por su cuenta. Por ejemplo, en el mismo ejemplo de una petición de datos en múltiples páginas, el cliente debería incluir el número de página a recuperar en vez de pedir “la siguiente”, tal como se muestra en la siguiente figura:

servicio web stateless

Un servicio web sin estado genera una respuesta que se enlaza a la siguiente página del conjunto y le permite al cliente hacer todo lo que necesita para almacenar la página actual. Este aspecto del diseño de un servicio web REST puede descomponerse en dos conjuntos de responsabilidades, como una separación de alto nivel que clarifica cómo puede mantenerse un servicio sin estado.

Responsabilidad del servidor

  • Genera respuestas que incluyen enlaces a otros recursos para permitirle a la aplicación navegar entre los recursos relacionados. Este tipo de respuestas tiene enlaces embebidos. De la misma manera, si la petición es hacia un padre o un recurso contenedor, entonces una respuestsa REST típica debería también incluir enlaces hacia los hijos del padre o los recursos subordinados, de manera que se mantengan conectados.
  • Genera respuestas que indican si son susceptibles de caché o no, para mejorar el rendimiento al reducir la cantidad de peticiones para recursos duplicados, y para lograr eliminar algunas peticiones completamente. El servidor utiliza los atributos Cache-Control y Last-Modified de la cabecera en la respuesta HTTP para indicarlo.

Responsabilidades del cliente de la aplicación

  • Utiliza el atributo Cache-Control del encabezado de la respuesta para determinar si debe cachear el recurso (es decir, hacer una copia local del mismo) o no. El cliente también lee el atributo Last-Modified y envia la fecha en el atributo If-Modified-Since del encabezado para preguntarle al servidor si el recurso cambió desde entonces. Esto se conoce comoGET Condicional, y ambos encabezados van de la mano con la respuesta del servidor 304 (No Modificado) y se omite al recurso que se había solicitado si no hubo cambios desde esa fecha. Una respuesta HTTP 304 significa que el cliente puede seguir usando la copia local de manera segura, evitando así realizar las peticiones GET hasta tanto el recurso no cambie.
  • Envia peticiones completas que pueden ser serviciadas en forma independiente a otras peticiones. Esto implica que el cliente hace uso completo de los encabezados HTTP tal como está especificado por la interfaz del servicio web, y envia las representaciones del recurso en el cuerpo de la petición. El cliente envia peticiones que hacen muy pocas presunciones sobre las peticiones anteriores, la existencia de una sesión en el servidor, la capacidad del servidor para agregarle contexto a una petición, o sobre el estado de la aplicación que se mantiene entre las peticiones.

Esta colaboración entre el cliente y el servicio es esencial para crear un servicio web REST sin estado. Mejora el rendimiento, ya que ahorro ancho de banda y minimiza el estado de la aplicación en el servidor.

REST expone URIs con forma de directorios

Desde el punto de vista del cliente de la aplicación que accede a un recurso, la URI determina qué tan intuitivo va a ser el web service REST, y si el servicio va a ser utilizado tal como fue pensado al momento de diseñarlo. La tercera característica de los servicios web REST es justamente sobre las URIs.

Las URI de los servicios web REST deben ser intuitivas, hasta el punto de que sea facil adivinarlas. Pensemos en las URI como una interfaz auto-documentada que necesita de muy poca o ninguna explicación o referencia para que un desarrollador pueda comprender a lo que apunta, y a los recursos derivados relacionados.

Una forma de lograr este nivel de usabilidad es definir URIs con una estructura al estilo de los directorios. Este tipo de URIs es jerárquica, con una única ruta raiz, y va abriendo ramas a través de las subrutas para exponer las áreas principales del servicio. De acuerdo a esta definición, una URI no es sólamente una cadena de caracteres delimitada por barras, sino más bien un árbol con subordinados y padres organizados como nodos. Por ejemplo, en un servicio de hilos de discusiones que tiene temas varios, se podría definir una estructura de URIs como esta:

http://www.miservicio.org/discusion/temas/{tema}

La raiz, /discusion, tiene un nodo /temas como hijo. Bajo este nodo hay un conjunto de nombres de temas (como ser tecnologia, actualidad, y más), cada uno de los cuales apunta a un hilo de discusión. Dentro de esta estructura, resulta facil recuperar hilos de discusión al tipear algo después de /temas/.

En algunos casos, la ruta a un recurso encacja muy bien dentro de la idea de “esctructura de directorios”. Por ejemplo, tomemos algunos recursos organizados por fecha, que son muy prácticos de organizar usando una sintáxis jerárquica.

El siguiente ejemplo es intuitivo porque está basado en reglas:

http://www.miservicio.org/discusion/2008/12/23/{tema}

El primer fragmento de la ruta es un año de cuatro dígitos, el segundo fragmento es el mes de dos dígitos, y el tercer fragmento es el día de dos dígitos. Puede resultar un poco tonto explicarlo de esta manera, pero es justamente el nivel de simpleza que buscamos. Tanto humanos como máquinas pueden generar estas estructuras de URI porque están basadas en reglas. Como vemos, es facil llenar las partes de esta URI, ya que existe un patrón para crearlas:

http://www.miservicio.org/discusion/{año}/{mes}/{dia}/{tema}

Podemos también enumerar algunas guías generales más al momento de crear URIs para un servicio web REST:

  • ocultar la tecnología usada en el servidor que aparecería como extensión de archivos (.jsp, .php, .asp), de manera de poder portar la solución a otra tecnología sin cambiar las URI.
  • mantener todo en minúsculas.
  • sustituir los espacios con guiones o guiones bajos (uno u otro).
  • evitar el uso de strings de consulta.
  • en vez de usar un 404 Not Found si la petición es una URI parcial, devolver una página o un recurso predeterminado como respuesta.

Las URI deberían ser estáticas de manera que cuando cambie el recurso o cambie la implementación del servicio, el enlace se mantenga igual. Esto permite que el cliente pueda generar “favoritos” o bookmarks. También es importante que la relación entre los recursos que está explícita en las URI se mantenga independiente de las relaciones que existen en el medio de almacenamiento del recurso.

REST transfiere XML, JSON, o ambos

La representación de un recurso en general refleja el estado actual del mismo y sus atributos al momento en que el cliente de la aplicación realiza la petición. La representación del recurso son simples “fotos” en el tiempo. Esto podría ser una representación de un registro de la base de datos que consiste en la asociación entre columnas y tags XML, donde los valores de los elementos en el XML contienen los valores de las filas. O, si el sistema tiene un modelo de datos, la representación de un recurso es una fotografía de los atributos de una de las cosas en el modelo de datos del sistema. Estas son las cosas que serviciamos con servicios web REST.

La última restricción al momento de diseñar un servicio web REST tiene que ver con el formato de los datos que la aplicación y el servicio intercambian en las peticiones/respuestas. Acá es donde realmente vale la pena mantener las cosas simples, legibles por humanos, y conectadas.

Los objetos del modelo de datos generalmente se relacionan de alguna manera, y las relaciones entre los objetos del modelo de datos (los recursos) deben reflejarse en la forma en la que se representan al momento de transferir los datos al cliente. En el servicio de hilos de discusión anterior, un ejemplo de una representación de un recurso conectado podría ser un tema de discusión raiz con todos sus atributos, y links embebidos a las respuetas al tema.

<discusion fecha="{fecha}" tema="{tema}">
    <comentario>{comentario}</comentario>
    <respuestas>
          <respuesta de="
 gaz@mail.com" href="/discusion/temas/{tema}/gaz"/>
          <respuesta de="
 gir@mail.com" href="/discusion/temas/{tema}/gir"/>
    </respuestas>
</discusion>

Por último, es bueno construir los servicios de manera que usen el atributo HTTP Accept del encabezado, en donde el valor de este campo es un tipo MIME. De esta manera, los clientes pueden pedir por un contenido en particular que mejor pueden analizar. Algunos de los tipos MIME más usados para los servicios web REST son:

MIME-Type Content-Type
JSON application/json
XML application/xml
XHTML application/xhtml+xml

Esto permite que el servicio sea utilizado por distintos clientes escritos en diferentes lenguajes, corriendo en diversas plataformas y dispositivos. El uso de los tipos MIME y del encabezado HTTP Accepto es un mecanismo conocido como negociación de contenido, el cual le permite a los clientes elegir qué formato de datos puedan leer, y minimiza el acoplamiento de datos entre el servicio y las aplicaciones que lo consumen.

Conclusión

No simpre REST es la mejor opción. Está surgiendo como una alternativa para diseñar servicios web con menos dependencia en middleware propietario (por ejemplo, un servidor de aplicaciones), que su contraparte SOAP y los servicios basados en WSDL. De algún modo, REST es la vuelta a la Web antes de la aparición de los grandes servidores de aplicaciones, ya que hace énfasis en los primeros estándares de Internet, URI y HTTP. Como examinamos en este artículo, XML sobre HTTP es una interfaz muy poderosa que permite que aplicaciones internas, como interfaces basadas en JavaScript Asincrónico + XML (AJAX) puedan conectarse, ubicar y consumir recursos. De hecho, es justamente esta gran combinación con AJAX que generó esta gran atención que tiene REST hoy en día.

Resulta muy flexible el poder exponer los recursos del sistema con un API REST, de manera de brindar datos a distintas aplicaciones, formateados en distintas maneras. REST ayuda a cumplir con los requerimientos de integración que son críticos para construir sistemas en donde los datos tienen que poder combinarse facilmente (mashups) y extenderse. Desde este punto de vista, los servicios REST se convierten en algo mucho más grande.

Este artículo es tan sólo una breve introducción a los servicios web REST, y espera ser el puntapié inicial para que puedan continuar explorando esta forma de exponer servicios.

Javascript : arrays asociativos

[Fuente: http://www.hunlock.com/blogs/Mastering_Javascript_Arrays#quickIDX9]

Javascript no implementa Arrays asociativos

Un array asociativo es un array que utiliza una string en vez de un número como índice para acceder a un elemento concreto del array.

var normalArray    = [];
    normalArray[1] = 'This is an enumerated array';

    alert(normalArray[1]);   // outputs: This is an enumerated array

var associativeArray           = [];
    associativeArray['person'] = 'John Smith';

    alert(associativeArray['person']); // outputs: John Smith

Javascript no tiene, y no soporta Arrays Asociativos. Sin embargo… Todos los arrays en Javascript son objetos y la sintáxis básica de objetos en Javascript simula un array asociativo. Es por ello que el ejemplo anterior funciona. Pero ten en cuenta que aunque lo parezca no es un array propiamente dicho. Es decir el campo ‘person’ pasa a ser una propiedad del objeto ‘associativeArray’ pero los métodos .length(), .sort() y demás métodos de array que implementa javascript no funcionarán.

Podemos hacer un bucle de todas las propiedades del objeto asi:

var associativeArray = [];
associativeArray["one"] = "First";
associativeArray["two"] = "Second";
associativeArray["three"] = "Third";
for (i in associativeArray) {
   document.writeln(i+':'+associativeArray[i]+', ');
   // outputs: one:First, two:Second, three:Third
};

En el ejemplo de arriba,  associativeArray.length es cero porque de hecho no pones nada dentro del array, realmente lo añadimos como atributos del objeto associativeArray. Por tanto “associativeArray[0]” sale undefined.

Como un ejemplo final, el código anterior funcionará independientemente de si defines associativeArray como un Array ([]) , un objeto ({}) , una expresion regular (//), una String (“”) , o cualquier otro objeto Javascript.

En resumen — intenta no utilizar arrays asociativos, sino que prográmalos como lo que son — propiedades de los objetos , no Arrays.

Crear un plugin de jQuery

[Fuente: http://docs.jquery.com/Plugins/Authoring]

Extender jQuery con plugins y métodos es muy potente y puede ahorrarte mucho tiempo de desarrollo por medio de abstraer las funciones complejas dentro de plugins. Explicaremos aqui lo básico, las mejores prácticas y los fallos más comunes

Primeros pasos

Para escribir un plugin de jQuery , empieza añadiendo una nueva propiedad de función al objeto jQuery.fn donde el nombre de la propiedad es el nombre de tu plugin:

jQuery.fn.myPlugin = function() {

  // Do your awesome plugin stuff here

};

Cuidao!  Dónde está el símbolo del dolar que tanto queremos? Está aún ahí , pero para asegurarnos que tu plugin no colisiona con otras librerias que utilicen el símbolo del dolar, la mejor práctica es pasar jQuery a un IIFE (Immediately Invoked Function Expression) que lo mapea al símbolo del dolar de forma que no puede ser sobreescrito por otra librería en ese ámbito.

(function( $ ) {
  $.fn.myPlugin = function() {

    // Do your awesome plugin stuff here

  };
})( jQuery );

Así mejor. De esta forma , dentro de esa función IIFE podemos utilizar el dolar con total tranquilidad.

Contexto

Ahora que tenemos nuestra interfaz lista podemos empezar a escribir el código del plugin. Pero antes de eso, comentamos algo importante sobre el contexto. En el ámbito inmediato de la función del plugin, la palabra clave this se refiere al objeto jQuery sobre el que se invocó el método del plugin. Es un error muy común confundirlo con los casos donde jQuery accepta una función de callback, y aqui el this se refiere al elemento DOM nativo. Esto hace que muchas veces los programadores de forma innecesaria hagan un wrapping de la palabra clave this en la función jQuery.

(function( $ ){

  $.fn.myPlugin = function() {

    // there's no need to do $(this) because
    // "this" is already a jquery object

    // $(this) would be the same as $($('#element'));

    this.fadeIn('normal', function(){

      // the this keyword is a DOM element

    });

  };
})( jQuery );

$('#element').myPlugin();

Lo básico

Ahora que entendemos el contexto de los plugins de jQuery , escribamos un plugin que haga algo:

(function( $ ){

  $.fn.maxHeight = function() {

    var max = 0;

    this.each(function() {
      max = Math.max( max, $(this).height() );
    });

    return max;
  };
})( jQuery );

var tallest = $('div').maxHeight(); // Returns the height of the tallest div

Este plugin simplemente el div que tenga la altura máxima dentro de la página.

 

Manteniendo la capacidad de encadenamiento

The previous example returns an integer value of the tallest div on the page, but often times the intent of a plugin is simply modify the collection of elements in some way, and pass them along to the next method in the chain. This is the beauty of jQuery’s design and is one of the reasons jQuery is so popular. So to maintain chainability in a plugin, you must make sure your plugin returns thethis keyword.

(function( $ ){

  $.fn.lockDimensions = function( type ) {  

    return this.each(function() {

      var $this = $(this);

      if ( !type || type == 'width' ) {
        $this.width( $this.width() );
      }

      if ( !type || type == 'height' ) {
        $this.height( $this.height() );
      }

    });

  };
})( jQuery );

$('div').lockDimensions('width').css('color', 'red');

Because the plugin returns the this keyword in its immediate scope, it maintains chainability and the jQuery collection can continue to be manipulated by jQuery methods, such as .css. So if your plugin doesn’t return an intrinsic value, you should always return the this keyword in the immediate scope of the plugin function. Also, as you might assume, arguments you pass in your plugin invocation get passed to the immediate scope of the plugin function. So in the previous example, the string ‘width’ becomes the type argument for the plugin function.

Defaults and Options

For more complex and customizable plugins that provide many options, it’s a best practice to have default settings that can get extended (using $.extend) when the plugin is invoked. So instead of calling a plugin with a large number of arguments, you can call it with one argument which is an object literal of the settings you would like to override. Here’s how you do it.

(function( $ ){

  $.fn.tooltip = function( options ) {  

    // Create some defaults, extending them with any options that were provided
    var settings = $.extend( {
      'location'         : 'top',
      'background-color' : 'blue'
    }, options);

    return this.each(function() {        

      // Tooltip plugin code here

    });

  };
})( jQuery );

$('div').tooltip({
  'location' : 'left'
});

In this example, after calling the tooltip plugin with the given options, the default location setting gets overridden to become 'left', while the background-color setting remains the default'blue'. So the final settings object ends up looking like this:

{
  'location'         : 'left',
  'background-color' : 'blue'
}

This is a great way to offer a highly configurable plugin without requiring the developer to define all available options.

Namespacing

Properly namespacing your plugin is a very important part of plugin development. Namespacing correctly assures that your plugin will have a very low chance of being overwritten by other plugins or code living on the same page. Namespacing also makes your life easier as a plugin developer because it helps you keep better track of your methods, events and data.

Plugin Methods

Under no circumstance should a single plugin ever claim more than one namespace in thejQuery.fn object.

(function( $ ){

  $.fn.tooltip = function( options ) {
    // THIS
  };
  $.fn.tooltipShow = function( ) {
    // IS
  };
  $.fn.tooltipHide = function( ) {
    // BAD
  };
  $.fn.tooltipUpdate = function( content ) {
    // !!!
  };

})( jQuery );

This is a discouraged because it clutters up the $.fn namespace. To remedy this, you should collect all of your plugin’s methods in an object literal and call them by passing the string name of the method to the plugin.

(function( $ ){

  var methods = {
    init : function( options ) {
      // THIS
    },
    show : function( ) {
      // IS
    },
    hide : function( ) {
      // GOOD
    },
    update : function( content ) {
      // !!!
    }
  };

  $.fn.tooltip = function( method ) {

    // Method calling logic
    if ( methods[method] ) {
      return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.tooltip' );
    }    

  };

})( jQuery );

// calls the init method
$('div').tooltip(); 

// calls the init method
$('div').tooltip({
  foo : 'bar'
});

// calls the hide method
$('div').tooltip('hide'); 

// calls the update method
$('div').tooltip('update', 'This is the new tooltip content!');

This type of plugin architecture allows you to encapsulate all of your methods in the plugin’s parent closure, and call them by first passing the string name of the method, and then passing any additional parameters you might need for that method. This type of method encapsulation and architecture is a standard in the jQuery plugin community and it used by countless plugins, including the plugins and widgets in jQueryUI .

Events

A lesser known feature of the bind method is that is allows for namespacing of bound events. If your plugin binds an event, its a good practice to namespace it. This way, if you need to unbind it later, you can do so without interfering with other events that might have been bound to the same type of event. You can namespace your events by appending “.<namespace>” to the type of event you’re binding.

(function( $ ){

  var methods = {
     init : function( options ) {

       return this.each(function(){
         $(window).bind('resize.tooltip', methods.reposition);
       });

     },
     destroy : function( ) {

       return this.each(function(){
         $(window).unbind('.tooltip');
       })

     },
     reposition : function( ) {
       // ...
     },
     show : function( ) {
       // ...
     },
     hide : function( ) {
       // ...
     },
     update : function( content ) {
       // ...
     }
  };

  $.fn.tooltip = function( method ) {

    if ( methods[method] ) {
      return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.tooltip' );
    }    

  };

})( jQuery );

$('#fun').tooltip();
// Some time later...
$('#fun').tooltip('destroy');

In this example, when the tooltip is initialized with the init method, it binds the reposition method to the resize event of the window under the namespace ‘tooltip’. Later, if the developer needs to destroy the tooltip, we can unbind the events bound by the plugin by passing its namespace, in this case ‘tooltip’, to the unbind method. This allows us to safely unbind plugin events without accidentally unbinding events that may have been bound outside of the plugin.

Data

Often times in plugin development, you may need to maintain state or check if your plugin has already been initialized on a given element. Using jQuery’s data method is a great way to keep track of variables on a per element basis. However, rather than keeping track of a bunch of separate data calls with different names, it’s best to use a single object literal to house all of your variables, and access that object by a single data namespace.

(function( $ ){

  var methods = {
     init : function( options ) {

       return this.each(function(){

         var $this = $(this),
             data = $this.data('tooltip'),
             tooltip = $('<div />', {
               text : $this.attr('title')
             });

         // If the plugin hasn't been initialized yet
         if ( ! data ) {

           /*
             Do more setup stuff here
           */

           $(this).data('tooltip', {
               target : $this,
               tooltip : tooltip
           });

         }
       });
     },
     destroy : function( ) {

       return this.each(function(){

         var $this = $(this),
             data = $this.data('tooltip');

         // Namespacing FTW
         $(window).unbind('.tooltip');
         data.tooltip.remove();
         $this.removeData('tooltip');

       })

     },
     reposition : function( ) { // ... },
     show : function( ) { // ... },
     hide : function( ) { // ... },
     update : function( content ) { // ...}
  };

  $.fn.tooltip = function( method ) {

    if ( methods[method] ) {
      return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.tooltip' );
    }    

  };

})( jQuery );

Using data helps you keep track of variables and state across method calls from your plugin. Namespacing your data into one object literal makes it easy to access all of your plugin’s properties from one central location, as well as reducing the data namespace which allows for easy removal if need be.

Summary and Best Practices

Writing jQuery plugins allows you to make the most out of the library and abstract your most clever and useful functions out into reusable code that can save you time and make your development even more efficient. Here’s a brief summary of the post and what to keep in mind when developing your next jQuery plugin:

  • Always wrap your plugin in a closure: (function( $ ){ /* plugin goes here */ })( jQuery );
  • Don’t redundantly wrap the this keyword in the immediate scope of your plugin’s function
  • Unless you’re returning an intrinsic value from your plugin, always have your plugin’s function return the this keyword to maintain chainability.
  • Rather than requiring a lengthy amount of arguments, pass your plugin settings in an object literal that can be extended over the plugin’s defaults.
  • Don’t clutter the jQuery.fn object with more than one namespace per plugin.
  • Always namespace your methods, events and data.