Author Archives: admin

Android, iOS, tiempos de respuestas y por qué nada es gratis en sistemas informáticos

[Fuente: http://gallir.wordpress.com/2011/12/07/android-ios-tiempos-de-respuestas-y-por-que-nada-es-gratis-en-sistemas-informaticos/]

Hace unas pocas horas escribí esta respuesta sobre Por qué iOS es más fluido que Android (con buen criterio, eliminaron la entrada). Obviamente, por cuestiones de longitud y la “respuesta rápida” que requiere un comentario, no me quedó todo lo completo que requiere el tema. Lo que me gustaría explicar daría para muchas horas de charlas. De hecho, enseño estos temas en mi asignatura de Sistemas Operativos (II), dedico al menos unas 12 hs de clase, y aún así no entramos en muchos detalles importantes. Pero intentaré resumirlo en este apunte, fundamentalmente para que se entiendan los problemas de arquitectura, y de cómo toda decisión que se tome en una arquitectura, lenguaje o programa tiene implicaciones positivas y negativas, siempre.

Lo básico

Apple tomó muchas decisiones técnicas con el objetivo de mejorar la “experiencia de usuario”, pero por sí mismas serían inútiles -o más perjudiciales- si no van acompañadas de medidas de control estrictas. Es fundamental el papel de los controles de las aplicaciones en el App Store (¡ojo! no los justifico). Independientemente de otras consideraciones políticas, dado su simplicidad y soluciones ad hoc, el iOS sería muy fácil de “abusar” por los desarrolladores y aplicaciones.

Por el contrario, Android es una plataforma abierta que puede usar cualquier fabricante, que permite la instalación de cualquier aplicación. El control de aplicaciones del Market por parte de Google es prácticamente inexistente. Esto hace que no valgan soluciones ad hoc, obliga a implementar en el sistema operativo medidas de seguridad y control “canónicas”, en el sentido que mantenga las condiciones fundamentales de todo sistema operativo de propósito general: eficiencia, equidad (fairness) y seguridad.

Cualquiera que haya estudiado la teoría y arquitectura de sistemas operativos (o que haya leído sobre el tema) entiende perfectamente que la eficiencia, equidad y seguridad son objetivos contradictorios. Mayor equidad o seguridad afectan negativamente a la eficiencia, y viceversa.

Hay otro problema importante. Se desea que los sistemas operativos de teléfonos actúen como sistemas de tiempo real también para las aplicaciones (ya tienen que serlos en otros aspectos, como la “radio” a interacción con protocolos de red de telefonía).  Es decir, con límites precisos de “tiempo de respuesta”: el tiempo que transcurre desde que ocurre un evento (como tocar la pantalla) hasta que se empieza a ejecutar al “gestor” de ese evento (la aplicación).

Los sistemas Unix (como Linux o Darwin) no son de tiempo real, su planificador de procesos (scheduler) es no-determinístico. No lo es por una sencilla razón: si se pretende una buena “multiprogramación” (llamada comunmente “multitarea”) se deben cumplir los objetivos de equidad y otros más complejos, como evitar los tiempos de espera muy largos (starvation). Esos dos objetivos impiden asegurar (formalmente) que el sistema sea de tiempo real. Además, los sistemas de tiempo real exigen que el tiempo de ejecución de cada ráfaga de ejecución de las aplicaciones (CPU bursts) críticas sea lo suficientemente breve para poder asegurar “tiempo real” a las demás aplicaciones (recordad que el scheduler debe ser determinístico, por ende no puede asegurar equidad).

En pocas palabras, si deseas comportamientos próximos al tiempo real necesitas relajar los requerimientos de un sistema de propósito general, y aumentar el control de las aplicaciones que se ejecutan en ese sistema.

¿Se entiende el balance y decisiones contradictorias que hay que tomar? En un sistema de multiprogramación, con el hardware equivalente (los dispositivos iOS y Android lo son), si  se desea disminuir las latencias se deben relajar otras condiciones del planificación de procesador (por lo que se obtiene una “peor multitarea”) y aumentar el control de aplicaciones (lo que genera otros problemas políticos, éticos, sociales y de negocio). Si pretende más apertura y libertad, se debe ser muy estricto con equidad y seguridad, lo que genera efectos negativos sobre el tiempo de respuesta.

Al final el tema de fondo no es [sólo] técnico, sino de otros aspectos más filosóficos: control vs apertura.

Creo que ya expliqué la base del problema técnico-filosófico, ya puedes dejar de leer si te agobian los detalles técnicos. Pero si te interesan, intentaré resumirlos en las cuatro partes que tienen más responsabilidad en los “tiempos de respuesta” de un sistema: las aplicaciones, el lenguaje y plataforma, la gestión de memoria, y el scheduler.

Las aplicaciones

El tipo de programación para móviles es esencialmente “dirigida por eventos” . Cuando el usuario toca la pantalla se llama la función que debe responder a ese evento (en Android se llaman “actividades”). La recomendación es que la aplicación no necesite mucha CPU ni tiempo para generar la respuesta, especialmente en los menús principales. Por supuesto, a este nivel, todo depende de los programadores de la aplicación, y supongo que estos son los mayores culpables de la “reacción lenta” de los menús cuando se interactúa con una aplicación.

Las aplicaciones también pueden tener otros malos comportamientos, por ejemplo consumir mucha CPU (aún cuando están en background o como servicio), no sólo molesta a todos los demás procesos, también aumenta el consumo de batería y la temperatura.

¿Cómo solucionar este problema? O se hace un control estricto de cada aplicación, o se implanta un scheduler más sofisticado y genérico que puede tener algunas aristas.

Ya sabéis qué decisión se tomó en Apple, y cuál en Google.

El lenguaje y plataforma

iOS y Android difieren mucho en este aspecto.iOS usa el mismo lenguaje estándar del Mac OS X, el Objective-C. Los programas se compilan directamente en código ejecutable para el procesador. En cambio Android optó por usar Java, que se convierte a un lenguaje intermedio ejecutado por una máquina virtual optimizada (similar la máquina virtual de Java, pero es diferente), Dalvik.

Obviamente el rendimiento entre ambas es muy diferente, el código ejecutable siempre será más eficiente que otro se que no se ejecuta directamente en el procesador. Pero esto no significa que los diseñadores de Android sean unos imbéciles, de nuevo, fueron decisiones estratégicas que están muy por encima de temas técnicos, aunque terminan afectando dramáticamente a este último.

Si el sistema operativo se va a ejecutar siempre sobre una única arquitectura, como hizo históricamente Apple (aunque tuvo dos migraciones importantes, exitosas pero dolorosas y muy molestas para los desarrolladores), la opción natural es generar directamente el ejecutable. Además, Apple licenció el diseño de ARM [*] y compró una empresa de diseño de chips (Intrinsity) para que se encargue del diseño de sus procesadores y no depender ni de fabricantes externos (antes lo hacía Samsung).

Por otro lado, la intención de Android era entrar a competir en el mercado con un sistema libre/abierto y multiplataforma (después de varios intentos fallidos, como OpenMoko), por  lo que era preferible un sistema que no obligase a compilar una aplicación para cada tipo de procesador. Si no, estaría condenada al fracaso. Para solucionar el problema de la eficiencia diseñaron desde cero el Dalvik, que al usar el lenguaje Java ya tenía a su disposición muchas herramientas (como Eclipse), librerías de desarrollo (como las clases estándar de Java), y una comunidad enorme de programadores (me abstengo de opinar sobre Java, pero afortunadamente Android lo ha mejorado muchísimo con su API y framework de programación).

Aunque Java ya está preparado para multithreading, por cuestiones de seguridad los diseñadores de Android prefirieron, muy acertadamente, ejecutar cada aplicación como un proceso diferente y completamente aislado. Dejaron esta parte de la gestión de procesos al núcleo Linux, que es muy eficiente y está más que probado.  Con esta arquitectura de máquinas virtuales replicadas en procesos independientes, se generan otras infeficiencias: cada proceso debe cargar su máquina virtual, y éste debe cargar después todas las clases estándar de Java que hacen falta para la aplicación. Esto haría que el tiempo de arranque de cada programa fuese inaceptable, y han recurrido a un truco muy guapo para solucionarlo (por eso digo que la arquitectura de Android es una obra impresionante de ingeniería informática): el zygote.

El kernel Linux implementa un mecanismo llamado copy-on-write ( COW) que permite que los procesos hijos (creados con el fork()) compartan memoria con el padre (por eso la creación de procesos es muy rápida de Linux). Cuando un proceso crea un hijo, éste reusa la misma memoria y tablas de páginas del padre, pero todas las páginas se marcan como “sólo lectura”. El hijo puede comenzar a ejecutarse muy rápidamente. Cuando uno de los procesos intenta escribir sobre una página compartida, se genera una interrupción de error (trap), el sistema operativo coge el control, verifica que se trata de memoria COW, asigna una nueva página, copia el contenido de la página afectada, modifica la tabla de páginas de uno de los procesos para apuntar a esta nueva, y permite la continuación de ambos procesos. Además de la rapidez con que puede crear y ejecutar procesos, se ahorra mucha memoria RAM, por ejemplo, el código ejecutale y las librerías comunes siempre se comparten (nunca se modifican).

¿Cómo aprovecha Android este mecanismo? Crea un proceso inicial, el zygote, que carga la máquina virtual y las librerías estándares de Java y del API de Android. Cada nueva aplicación que se arranca es hija de este zygote, et voilà, ya ganaron eficiencia y se ahorra muchísima memoria (Chrome y Chromium usan la misma técnica para abrir pestañas y ventanas rápidamente).

¿Es o no es una obra maestra de ingeniería? Claro que sí, se han tomado todo ese trabajo para compensar el problema de eficiencia y seguridad de una máquina virtual. Por eso, cuando pienso que por debajo hay una máquina vrtual ejecutando el código, me maravillo con la velocidad de ejecución de las aplicaciones en Android.

Por supuesto, esta arquitectura con memoria virtual tiene otros efectos negativos a la hora de medir los tiempos de respuesta: en la gestión de memoria y cache, que trato más adelante.

[*] En la biografía de Steve Jobs cuentan como después de evaluar usar Intel para los iPad, Jobs le dijo muy cabreado a los ejecutivos de Intel algo así como: “son muy buenos para procesadores de alto rendimiento, pero sois unos inútiles para procesadores de bajo consumo”.

La gestión de memoria del núcleo

Los procesadores que usan iOS y Android son similares en cuanto a su gestión de memoria (también similares a los ordenadores que usáis). Ambos gestionan memoria virtual con paginación. Los procesos no generan direcciones físicas de RAM, sino direcciones lógicas que son convertidas a direcciones físicas en cada ejecución por el módulo conocido como Memory Manager Unit (MMU). Cada proceso tiene sus propias tablas de página que mantienen la relación de número de página del proceso (es el índice a la tabla) a ubicación en la memoria RAM. Los procesadores ARM permiten páginas de 4KB a 64KB (lo usual son 4KB), así que cada aplicación tiene miles de páginas, y por lo tanto tablas de miles de entradas (en ARM hay tablas de dos niveles, en la arquitectura Intel o AMD, cuatro niveles).

Cada entrada de la tabla almacena propiedades de la página: lectura (r), escritura (w), ejecución (x), accedida (a, o acces bit), modificada (d, o dirty bit), cargada en memoria (p, present bit), etc. Por esta razón las tablas se mantienen en la memoria RAM, lo que genera otro problema ¿cómo hace el MMU para no tener que acceder dos veces a la memoria -primero a la tablas de página y luego a la dirección que se pretende acceder-? Sin un mecanismo que lo solucione, el tiempo efectivo de acceso a la memoria sería al menos el doble de lo que permite la memoria RAM (o sea, una patata de lento).

Para solucionar este problema se usan sistemas de cache que almacenan en registros del procesador un conjunto de entradas de las tablas: el translation-lookaside-buffer (TLB). El TLB de los ARM suelen tener 128 entradas, cada una de ellas es una copia idéntica de la entrada de la tabla de páginas. Se intenta tener en el TLB las entradas más usadas, así, cada vez que el MMU encuentra la entrada en el TLB puede acceder directamente a la memoria (hit), si no, tiene que descartar una entrada y cargar la que hace falta (fault). El hit ratio es una indicación de la velocidad de acceso efectivo a memoria, viene dado por el procesador y el algoritmo de sustitución que se use, a mayor número de entradas en el TLB, el hit ratio sube.

Cada vez que el scheduler selecciona otra aplicación para ejecutar se produce un cambio de contexto, entre otras cosas significa que las entradas del TLB deben ser invalidadas (ya no sirven para el nuevo proceso, por seguridad tampoco debe poder usar esos datos), además las entradas que han sido modificadas por el procesasor (por ejemplo, que una una página fue accedida o modificada) deben ser copiadas a la tabla original en memoria (flush). Por eso se dice que los cambios de contexto son “caros”, y es muy imporante las decisiones que toma el scheduler para minimizar los cambios de contexto “inútiles” (¡pobre el scheduler!, las cosas que tiene que tener en cuenta para que lo usuarios no se quejen porque el audio pega saltos).

Un proceso con máquina virtual como Android mete mucha más presión al TLB (y por ende baja el hit ratio) que un proceso que ejecuta código nativo. Para ejecutar una función equivalente en máquina virtual se necesita más memoria, la del código del intérprete, la memoria usado por éste, más el código en lenguaje intermedio y la memoria que necesita el programa. No sólo eso, prácticamente cada ejecución del código intermedio implica cambios en las variables del propio programa, también en las de la máquina virtual, forzando a que en cada cambio de contexto sean más las entradas del TLB que deben ser copiadas a la RAM. O sea, los cambios de contexto son también más caros.

Lo mismo que pasa con el TLB (recordemos que es un tipo específico de cache), pasa con la memoria de cache de RAM en el procesador, la máquina virtual mete más presión, por lo que también bajan sus hit ratios.

De nuevo, una decisión de negocio (y política y filosófica), genera muchas complicaciones técnicas que hay que resolver. Si uno las tiene en cuenta, empieza a dejar de pensar en términos de fanboy y se cuestiona muchas cosas. Entre otras, lo eficiente que tiene que ser Linux para gestionar esta complejidad adicional sin que se note demasiado la diferencia.

El scheduler

Se llama scheduler al módulo del sistema operativo que selecciona cuál será el siguiente proceso a ejecutar. A cada proceso se le le asigna un tiempo máximo de ejecución: el cuanto (o quantum). Si al proceso se le acaba el cuanto, el sistema operativo se apropia de la CPU (por eso se llaman apropiativos o preemptive), y llama al scheduler para seleccionar el siguiente de la lista de procesos que esperan para ejecutar (este mecanismo se denomina round robin). El scheduler de Linux (como la gran mayoría) no son determinísticos, significa que a priori no se puede conocer la secuencia de ejecución de procesos, por lo que no se puede asegurar analítica o formalmente que los procesos se ejecuten en un tiempo máximo predeterminado (si éste es suficientemente pequeño).

No todos los procesos tienen los mismos requerimientos, aquellos interactivos, o de reproducción multimedia necesitan menores tiempo de respuesta que un servicio en background, o que consume mucha CPU. Para eso se usan las prioridades, cada proceso tiene una prioridad inicial (por ejemplo “multimedia”, “normal”, “de fondo”, etc.), luego el scheduler la ajusta dinámicamente (prioridad dinámica) dependiendo del comportamiento del proceso y las necesidades de los otros. Por eso, el comportamiento de un sistema que use prioridades depende del comportamiento global de todos los procesos, estos no se pueden predecir, y de allí que sea no determinístico, y que se generen tiempos de respuesta variables.

El scheduler  además tiene que tomar en cuenta muchos factores adicionales (p.e., minimizar los cambios de contexto), y evitar que se produzcan esperas muy largas (starvation) que se pueden producir porque procesos con mayor prioridad están cogiendo siempre la CPU y no dejan ejecutar a otros de menor prioridad. Imaginaros que tenéis el reproducto de música de fondo, y que estáis por sacar una foto. La aplicación de foto podría estar consumiendo el 100% de CPU para actualizar la imagen, por lo que produciría cortes en la música, insoportablemente molesto ¿no? Pues es el pobre scheduler el que tiene que evitar estos problemas, tomando decisiones muy rápidas, cientos de veces por segundo.

Para evitar estas esperas tan largas en los casos extremos (corner cases) como el que acabo de decir, el scheduler mantiene dos colas, la activa y la inactiva. Siempre asigna procesos desde la cola activa. A cada proceso se le asigna un tiempo máximo (además del cuanto) que puede estar en la cola activa (el timeslice, por ejemplo 500 mseg), cuando consume todo su tiempo se le mueve a la cola inactiva. Cuando ya no queda nadie en la cola activa, el scheduler cambia, la activa pasa a ser la inactiva, y viceversa. Esto aumenta aún más el efecto “no determinístico” del scheduler, y puede producir saltos o latencias elevadas si el procesador está temporalmente sobrecargado.

Para evitar estas latencias que molestan a la interactividad del usuario se pueden tomar varias medidas ad hoc, por ejemplo subir la prioridad al máximo a la aplicación que está activa (así hacía Windows), pero esto genera otros problemas: ¿si la aplicacion activa abusa y no deja de usar la CPU? (un truco obvio de programador para que su aplicación parezca que es más rápida y eficiente ¿no?) ¿y si hay procesos en background que necesitan la CPU  -por ejemplo un SMS, o respondera la red antes que pase el timeout- y esperan demasiado tiempo?

Pues es muy complicado, y cualquier “truco” que se ponga al scheduler deja la puerta abierta para que los programadores abusen… salvo que hagas un control exhaustivo de cada aplicación que se vaya instalar en el teléfono. ¿Se entiende por qué Apple puede recurrir a trucos ad hoc y evitar al mismo tiempo el abuso de las aplicaciones?

Si por el contrario renuncias a hacer ese control, no queda más remedio que el scheduler haga su trabajo, como en cualquier sistema operativo de uso genérico. Y que la solución adoptada sea lo suficientemente buena, simple, genérica y probadamente segura. ¿Se entiende por qué la solución en el Linux de Android es más difícil de encontrar? ¿o por qué le llamé una “solución canónica?

¿Como puede Android mejorar los tiempos de respuesta?

Evidentemente hay dos caminos obvios.

Por un lado, mejorar paulatinamente el scheduler (si es que allí reside el problema). No es una cuestión de un día, ni un año, en Linux se tardó años en encontrar un planificador que funcione tan bien como la actual para sistemas interactivos (el scheduler CFQ).

La otra parte, la gestión de memoria, depende en gran medida del apoyo del hardware. Un procesador con más capacidad de cache y TLB mejoraría mucho, pero también tiene su coste: más transistores, más consumo, más temperatura, mayor tamaño. A medida que se mejore el proceso de fabricación (más transistores en el mismo chip), seguramente incluiran TLB y cache con más capacidad. Lo mismo ocurre con el aumento de la potencia bruta y el aumento de cores (aunque  creo que afectan en mejnor medida a los tiempos de respuesta de la interfaz).

Tampoco me extrañaría que el código de los drivers de la pantalla sea de baja calidad (como suelen ser todos los drives, comparados con el núcleo del sistema operativo, se hacen bajo presión, y la prioridad es el hardware, no el SO) y encuentren big locks que no tocan.

De todas formas, los tiempos irán mejorando paulatinamente hasta que no podamos detectar diferencias en las latencias de la interactividad. Al mismo tiempo, iOS tendrá que ir incluyendo mejores capacidad de “multitarea” (como ya pasó desde que salió la primera versión de iOS, y seguramente irá reduciendo los controles de calidad que hace a cada aplicación).

Supongo que os dáis cuenta de la complejidad técnica de estos “cacharritos”, y que las decisiones de negocio imponen muchas restricciones y problemas al desarrollo del software, lo que obliga a los ingenieros a aplicarse a fondo. No es que los ingenieros de iOS son unos genios, y los de Android unos inútiles, los requerimientos y grados de libertad son diferentes.

Ley informática: optar por la apertura tiene costes técnicos iniciales, optar por el software libre tiene costes técnicos iniciales, pero producir una plataforma totalmente bajo control también tiene costes (sociales), y a más largo plazo.

Desarrollo Front End : directrices

[Fuente: http://taitems.github.com/Front-End-Development-Guidelines/#]

Accesibilidad

What’s Up, DOCTYPE?

The absence of a DOCTYPE is a crime punishable by death. You may have relied on the following DOCTYPE in the past, but it’s important to know that this is now being superseded by a leaner and meaner snippet.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
	"http://w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Ideally, the HTML5 DOCTYPE should be used. It’s supported in all modern browsers, and throws IE6 and IE7 into standards modeSource.

<!DOCTYPE html>

Write Valid Semantic Markup

Writing websites with clean, semantic HTML is something we wish we could always do. Sometimes we find ourselves limited by the way pages were setup by our predecessors, or sometimes we’re coding an HTML email. The validity of the HTML should never be compromised, even if to solve a browser specific bug.

Headings should be heirarchically created from <h2> onwards, paragraphs should always be in <p> tags and so on and so forth. If you write semantic HTML, the resultant page will be cleaner, lighter and easily parsed by search engine spiders. This is one of the simplest SEO fixes you can undertake.

WHICH DO YOU THINK LOOKS CLEANER, THIS?:

<span class="sectionHeading">A Heading</span>
<br /> <br />
Lorem ipsum dolor sit amet. ...
<br /> <br />

OR THIS?

<h2>A Heading</h2>
<p>
	Lorem ipsum dolor sit amet. ...
</p>

Fallbacks for Middle Mouse Clicks

One of the most frustrating accessibility and usability flaws of the modern web stems from the remapping of hyperlink click functions. Elements that appear to be hyperlinks may have their single click functionality remapped via JavaScript, breaking middle mouse click (open in new tab) functionality. If they can be opened in a new tab, their href of a single hash sends you back to the same page.

A modern example of a popular website that is contributing to this problem is the Twitter web app. Middle mouse clicking of names or user avatars yields completely different results throughout the web app.

<!-- The old way, breaking the web -->
<a href="#"></a>

<!-- If you can't deliver a page on mouse click, it's not a hyperlink -->
<span class="link" role="link"></span>

Another alternative is the use of “hashbangs“, that remap normal URLs to hash links and fetch pages via AJAX. Libraries that provide hashbang functionality should be able to display the page normally when middle mouse clicked, or load the content from that page into a designated area when clicked normally. But tread carefully, there are plenty of people who believe hashbangs are breaking the web.

Use Microformats

Microformats are a way of making contact information machine readable. hCard classes (not vCard) are used to define the type of content contained within elements. These are then extracted or highlighted by the browser.

<span class="tel">
	<span class="type">home</span>:
	<span class="value">+1.415.555.1212</span>
</span>

If you were to navigate to a page that uses this, you would notice that a program like Skype will easily detect what numbers on the page are phone numbers. Mobile Safari does something similar on iOS devices.

For more information: http://microformats.org/wiki/hcard

Images Need ‘Alt’ Text

The <img> tag requires alt text to both validate and meet accessibility guidelines. The text in the alt attribute should be descriptive of what the image shows, or is trying to achieve, unless of course the image is not critical.

If the image is of a list bullet or other trivial icons, it is recommended to simply leave the alt attribute empty, but still present. A screenreader will then ignore it, as opposed to having to read out “bullet” 20 times.

<img src="dog.gif" alt="Fido and I at the park!" />
<!-- good, descriptive -->

<img src="bullet.gif" alt="bullet" />
<!-- bad, as silly as it seems -->

<img src="bullet.gif" alt="" />
<!-- good -->

Use Tables for Tabular Data Only

Tables should only ever be used for the presentation of tabular data. The only exception is when composing HTML email, in which a table is almost the only thing supported by soul crushing email clients.

For accessibility, table headers should always be presented using <th> elements. Remember to also set cellpadding,cellspacing and border values to 0 as these are more consistently controlled by CSS.

<table cellpadding="0" cellspacing="0" border="0">
	<thead>
		<tr>
			<th>
				Cell Header
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				Cell Item
			</td>
		</tr>
	</tbody>
</table>

Use jQuery & jQuery UI Widgets

jQuery and jQuery UI are constructed to look and behave as close to identical as possible on different browsers. jQuery UI is designed to be WAI WCAG 2.0 and WAI ARIA compliant, so using the framework removes any uncertainty about plugins or scripts running on your site.

JavaScript

Whitespacing & Formatting

Any discussion about formatting, whitespacing and the placement of braces is going to be hotly debated. I guess the simplest rule is that, unless you’re willing to completely format a whole document, respect and maintain the formatting of an existing document. That means: see same-line braces throughout a JS file, continue to write code with same-line braces. Your code should fail the code review process if it doesn’t maintain consistency with the rest of the document.

Consistent formatting makes code more readable, and also means the code can be easily modified with find and replace commands. The coding habits we have picked up are thankfully very similar to what jQuery officially encourages. There are a few minor discrepencies, but again, these are personal issues or things that we think cannot be maintained. Further Reading

CHARACTER SPACING

// Bad
if(blah==="foo"){
	foo("bar");
}

// Good :)
if (blah === "foo") {
	foo("bar");
}

SAME LINE BRACES

// Bad
if (foo)
{
	bar();
}

// Good :)
if (foo) {
	bar();
}

ALWAYS USING BRACES

// Bad
if (foo)
	bar();

// Good :)
if (foo) {
	bar();
}

STRING HANDLING

Strings should always use double quotes. Some people are very fond of their C style strings (single quotes), but this leads to conflicting styles within a script. C style string handling dictates that empty and single character strings should be wrapped in single quotations, while phrases and words should be wrapped in double quotations.

Commenting

The requirement to comment code obsessively was pioneered by managers, team leaders and other people that interact with code infrequently. It is sought merely as a check box for an employee’s KPIs, and provides little return for the time spent doing so.

If a best-practice oriented developer follows the guidelines established in this document, their code should become so readable and obvious that the need to comment what it is doing is embarassingly redundant. Consider the following example. In this: booleans are posed as questions, and functions are named intuitively.

if (user.hasPermission) {
	editPage();
}

Commenting, in this scenario at least, is completely unnecessary.

SITUATIONS WHERE COMMENTING IS IMPORTANT

Some parts of a project will never be easy to scan and understand. Consider a complicated regular expression, or a math function calculating angles or switching between degrees and radians. Without the comment above, beginner and intermediate readers will be fairly clueless to the scripts’ meaning.

// RegEx for validating US phone numbers, can be (XXX) XXX-XXXX (with or without dashes, spaces or brackets)
var phoneRegEx = /^(?(d{3}))?[- ]?(d{3})[- ]?(d{4})$/;

Always Use === Comparison

The use of the == equality operator allows for frustrating bugs to slip through almost undetected. It allows for weak typing that is best explained by JavaScript Garden. The use of the strict equality operator === does not run type coercion and therefore strictly evaluates the difference between two objects. Again, consult JavaScript Garden for more information

var zeroAsAString = "0";

if (zeroAsAString == 0) {
	// gets in here lolwut
}

if (zeroAsAString === 0) {
	// never gets in here
}

THE EXCEPTION

Double equals comparison is allowed when comparing to null, because it will detect both null or undefined properties. If you don’t fully understand this, I still suggest you use triple equals.

var foo = null;

// foo is null, but bar is undefined as it has not been declared
if (foo == null && bar == null) {
	// still got in here
}

Always Specify the Second ‘radix’ Parameter When Using .parseInt()

When parsing a string to an integer, it is considered good practice to specify the second ‘radix’ parameter – which determines to what base the string should be converted to. The default setting will trigger a radix of 16 whenever the string is lead by a 0. Most beginner and intermediate users are only ever going to be using a radix of 10. Thanks to João Moreno for logging thecorrection.

alert( parseInt("08") ); // alerts: 2

alert( parseInt("08", 10) ); // alerts: 8

Avoid Comparing to true and false

Direct comparison to the values of true and false is unnecessary. Sometimes it might be good for clarity, but it’s just extra code.

if (foo === true) {
	// good that they're using triple equals, bad as it's redundant
}

if (foo) {
	// yay!
}

if (!bar) {
	// the opposite
}

Avoid Polluting the Global Namespace

An over-reliance on global variables is something all of us, myself especially, are guilty of. Arguments as to why globals are bad are fairly straight forward: the chance of script and variable conflicts is increased, and both the source file and the namespace itself become littered with countless ambiguously named variables.

Douglas Crockford believes that the quality of a JavaScript application can be assessed by the number of global variables it uses; the less the better. Given that not everything can be a local (but let’s be honest, that one you’re thinking about right now, it can, don’t be lazy) you need to find a way of structuring your variables to prevent clashes and minimise the bloat. The easiest way is to employ a single variable or a minimal amount of modules on which the variables are set. Crockford mentions that YUI uses a single global, YAHOO. He discusses this in more detail in his blog post “Global Domination”.

Considering that, in the case of small web apps, globals are generally used to store application-wide settings: it’s generally better to namespace your project or settings as objects.

// polluted global name space
var settingA = true;
var settingB = false;
var settingC = "test";

// a settings namespace
var settings = {
	settingA: true,
	settingB: false,
	settingC: "test"
}

But if we’re avoiding globals to reduce the chance of conflicts, isn’t standardising the namespaces to be the same going to increase chance of one app’s settings overwriting anothers? Well, it would make sense. It is instead suggested that you namespace your globals to your own specific app name, or reassign your namespace much in the same way that jQuery uses$.noConflict() mode.

var myAppName = {
	settings: {
		settingA: true
	}
}

//accessed as
myAppName.settings.settingA; // true

Camel Case Variables

The camel casing (or camelCasing) of JavaScript variables is accepted as the standard in most coding environments. The only exception that was raised in the comment section is the use of uppercase and underscores to denote contants.

var X_Position = obj.scrollLeft;

var xPosition = obj.scrollLeft; // tidier

SCENE_GRAVITY = 1; // constant

Loop Performance – Cache Array Length

Looping is arguably the most important part of JavaScript performance to get right. Shave a millisecond or two off inside of a loop, potentially gain seconds overall. One such way is to cache the length of an array so it doesnt have to be calculated every time the loop is iterated through.

var toLoop = new Array(1000);

for (var i = 0; i < toLoop.length; i++) {
	// BAD - the length has to be evaluated 1000 times
}

for (var i = 0, len = toLoop.length; i < len; i++) {
	// GOOD - the length is only looked up once and then cached
}

THE EXCEPTION

If you’re looping through an array to find an remove a particular item, this will alter the array length. Any time you change the array length by either adding or removing items from inside the loop, you will get yourself into trouble. Consider either re-setting the length or avoid caching it for this particular situation

Loop Performance – Use ‘break;’ & ‘continue;’

The ability to step over and out of loops is really useful in avoiding costly loop cycles.

If you’re looking for something inside of a loop, what do you do once you find it? Say the condition you’re looking for is matched halfway through a 1000 item loop. Do you execute whatever you intend to do, and allow the loop to continue to iterate over the remaining 500 items, knowing that there’s no chance it will hit an if statement? Nope! You break out of your loop, literally!

var bigArray = new Array(1000);

for (var i = 0, len = bigArray.length; i < len; i++) {
	if (i === 500) {
		break;
	}
	console.log(i); // will only log out 0 - 499
}

Another problem is skipping over a particular iteration and then continuing on with the loop. While things like odds and evens are better managed by replacing i++ with i + 2, some conditions need to be specifically listened for, to then trigger the skip. Anything that prevent’s running through an entire iteration is pretty handy.

var bigArray = new Array(1000);

for (var i = 0, len = bigArray.length; i < len; i++) {
	if (condition) {
		continue;
	}
	doCostlyStuff();
}

Don’t Send Too Many Function Parameters

This is a pretty bad idea, more for readability than anything:

function greet(name, language, age, gender, hairColour, eyeColour) {
	alert(name);
}

It’s a much better idea to construct an object before-hand or to pass the object inline

function greet(user) {
	alert(user.name);
}

greet({
	name: "Bob",
	gender: "male"
});

Remap ‘this’ to ‘self’

When writing object-oriented (OO) JavaScript, the scope of this must be understood. Regardless of what design pattern you choose to structure your pseudo-classes, a reference to this is generally the easiest way to refer back to an instance. The moment you begin integrating jQuery helper methods with your pseudo-classes is the moment you notice the changing scope of this.

Bob.findFriend("Barry");

Person.prototype.findFriend = function(toFind) {
	// this = Bob
	$(this.friends).each(function() {
		// this = Bob.friends[i]
		if (this.name === toFind) {
			// this = Barry
			return this;
		}
	});
}

In the above example, this has changed from a reference to Bob, to his friend Barry. It’s important to understand what happened to the value of this over time. Inside of the prototyped function, this refers to the instance of the pseudo-class (in this case Bob). Once we step inside the $.each() loop, this is then re-mapped to be item i in the parsed array.

The solution is to remap the value of this to either self or _self. While self (sans underscore) is not exactly a reserved keyword, it is a property of the window object. Although my use of self was picked up from the jQuery source code, they have realised their mistake and are attempting to rectify the situation and instead use _self. Personally, I prefer the use of self for the sheer cleanliness – but it can throw some pretty confusing bugs for people. Tread carefully.

In the following example I will better utilise the parameters made available with the $.each() helper, as well as re-mapping the value of this.

Bob.findFriend("Barry");

Person.prototype.findFriend = function(toFind) {

	// the only time "this" is used
	var _self = this; 

	$(_self.friends).each(function(i,item) {
		if (item.name === toFind) {
			return item;
		}
	});

}

CanIHaz Boolean?

Booleans should be easily identifiable by the way they are named. Use prefixes like iscan or has to propose a question.

isEditing = true;

obj.canEdit = true;

user.hasPermission = true;

Minimising Repaints & Reflows

Repaints and reflows relate to the process of re-rendering the DOM when particular properties or elements are altered. Repaints are triggered when an element’s look is changed without altering its layout. Nicole Sullivan describes these changes in a thorough blog post as style changes such as visibility or background-color. Reflows are the more costly alternative, caused by changes that alter the layout of the page. Examples include the addition or removal of elements, changes to an element’s width or height, and even resizing the browser window. Worst yet is the domino effect of reflows that cause ancestor, sibling and child elements to reflow.

There is no doubt that both reflows and repaints should be avoided if possible, but how?

A REFLOW EXAMPLE

It’s not that the following snippet is “bad code” exactly. But let’s assume that the array arr has 10 items.

var myList = document.getElementById("myList");

for (var i = 0, len = arr.length; i < len; i++) {

	myList.innerHTML += "<li>" + arr[i].title + "</li>"; //reflow - appending to element

}

In the above for loop, a reflow will be triggered for every iteration of the loop. 10 iterations cause 10 reflows.

Now consider the following:

var constructedHTML = "";

for (var i = 0, len = arr.length; i < len; i++) {
	constructedHTML += "<li>" + arr[i].title + "</li>"; //no reflow - appending to string
}

document.getElementById("myList").innerHTML = constructedHTML; //reflow

In this scenario, the elements are being constructed within a string. Not a single reflow is created by the loop, as the DOM is not being altered. Only once the array has been completely looped through is the string then applied as the innerHTML of an object, causing the only reflow of the function.

There are endless types of reflows and repaints that can be avoided, and lucky you gets to go on an read about them. Reading material on the subject matter is plentiful, but most of it is linked to from the excellent starting point that is Nicole Sullivan’s blog post. There are important lessons to be taken away from this when it comes to a multitude of technologies synonymous with “web 3.0” and HTML5. The lesson above can be directly applied to writing jQuery. It’s also important to consider when fiddling with canvas, and trying to keep a frame rate in the 30-60 range.

Don’t Use Milliseconds to Generate Unique IDs

There is a method for generating unique IDs that has hung around since the early days of web dev. It involved appending the elapsed milliseconds since January 1, 1970 to your static ID by way of:

var myID = "static" + new Date().getTime();

This was a fairly foolproof method originally, because even if two ofthe above lines were performed one after the other, a few millisecondsnormally separated their execution. New browsers brought with them newJavaScript engines, coupled with ever increasing clock speed. Thesedays it’s more likely that your milliseconds match than are slightlyincremented.

This leads to bugs that are near impossible to debug by conventionalmeans. Because your DOM is created on the fly, traditional validationof the page source won’t identify multiple IDs as an error. JavaScriptand iQuery error handling dictates that the first match for the IDwill be utilised and other matches ignored. So it doesn’t even throw aJS error!

No, the only real method to debug it is line by line breakpoint ingand logging – but “pause” at the wrong line and your milliseconds willno longer clash!

The good thing is that there are plenty of alternatives. To be pedantic, it’s worth noting that a computer’s random function is not truly random as it is seeded by system time- but the probability of clashes is rather minuscule.

var myID = "static" + Math.round(Math.random() * 10000);

Personally, I’m partial to a bit of faux GUID generation. Technicallya GUID is generated according to your hardware, but this JavaScriptfunction does the next best thing. The following is a handy function I’ve pinched from a stack overflow post.

function S4() {
   return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
}
function guid() {
   return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
}
var myID = "static" + guid();

Feature Sniff, Don’t Browser Sniff

Does the client’s browser support geolocation? Does the client’s browser support web workers? HTML5 video? HTML5 audio? The answer used to be:

if ($.browser.msie) {
	// no it doesn't
}

But things are rapidly changing. The latest version of IE is almost a modern browser, but as usual it’s making front end development a pain. Earlier versions of IE were generally as equally sucky as their predecessors, so it enabled lazy JavaScript developers to simply detect if (ie) and execute some proprietary Microsoft slops syntax. Now IE9 has done away with these functions, but that old if (ie) chestnut is throwing a spanner in the works.

So what if you could detect support for individual features without sniffing the (unreliable and cloakable) user-agent?

If you answered “that would be ghetto”, then you are correct.

In steps Modernizr, a JavaScript library developed in part by industry dream-boat Paul Irish. With wide adoption, tiny file-size and plenty of documentation: implementing it is a no-brainer. It creates a Modernizr object that contains the results of its detection tests, so checking feature support is as simple as the following:

// old way of detecting canvas support
if (!!document.createElement('canvas').getContext) { ... }

// with Modernizr
if (Modernizr.canvas) { ... }

Readable Milliseconds

A handy way of writing milliseconds in a readable format. Great for beginners, but mostly a gimmick.

// is this 3, 30 or 300 seconds?
var timeout = 30000; 

// an extra calculation, but easier to read and modify
var timeout = 30 * 1000;

jQuery Specific

Chain Like a Mad Dog

One of the best parts of jQuery is its function chaining. You’ve probably used it a bit, maybe a few simple calls one after another… but have you ever traversed the DOM like a mad dog? Take some time to familiarise yourself with the .end() function. It is critical for when you begin stepping up and down the DOM tree from your original selector.

$(".quote")
	.hide()
	.find("a").text("Click here").bind("click",doStuff).end()
	.parent().removeClass().addClass("testimonial").draggable().end()
	.fadeIn("slow");

In the example above, the .end() function is used once we have finished doing things with a particular DOM object and want to traverse back up the DOM to the original object we called. We then load back up and dive back into the DOM.

Using data-* Attributes

Those of you who have been writing JavaScript (and not jQuery) for a good length of time are most likely familiar with attributes. Setting them. Getting them. Abusing rel and title instead…

So when isn’t HTML5 or jQuery coming the rescue? New specs allow the use of data- prefixes on HTML elements to indicate attributes which can hold data, and jQuery does an awesome job of converting the designated string into the correct JavaScript type. It’s a beautiful partnership. Let’s create a DIV with some data attributes.

<div id="test" data-is-bool="true" data-some-number="123"></div>

Now even though our values are wrapped in quotation marks, they won’t be handled as strings:

typeof $("#test").data("isBool"); // boolean

typeof $("#test").data("someNumber"); // number

SPECIAL CASING

It’s also important to notice the lower casing required to get these snippets to work. But if you’re a great front end developer, you will still want to camel case your data variables. Like many places in JavaScript, a preceding hyphen signifies camel casing of the next letter. The following camel casing of the HTML attribute does not work and the same JavaScript used above will return undefined.

Does not work 🙁

<div id="test" data-isBool="true" data-someNumber="123"></div>

Does work 🙂

<div id="test" data-is-bool="true" data-some-number="123"></div>

‘.stop()’ Collaborate & Listen

Binding jQuery animations to mouse events is a key part of modern web-based user interaction. It’s also something that you see done poorly on even the most famous of web sites. This article provides a straight forward example of built up animations and demonstrates how visually jarring they can be. Thankfully it’s easily fixed with a single function prefix or a parameter added to $.animate calls.

When using $.animatequeue: false can be added to the parameters to prevent chaining. Animation shortcuts such as$.fadeIn or $.slideDown do not take queue settings. Instead you have to pre-empt these animations with the $.stop method of pausing currently executing animations. Certain scenarios require the animation to stop dead in its tracks, or to jump to the end of the transition. It is recommended you familiarise yourself with the documentation of the parameters clearQueue andjumpToEnd, because god knows I can’t help you there.

$("selector").stop(true,true).fadeOut();

$("selector").animate({
	property: value
}, {
	duration: 1000,
	queue: false
}

Optimise Your Selectors

jQuery is pretty chill. It can do pretty much everything but make you coffee, and I hear that’s in the roadmap for 2.0. One thing you have to be careful about is abusing the power that is the sizzleJS selector engine. There are two strategies to overcome this: caching the selector results and using efficient selectors.

CACHING SELECTOR RESULTS

Do a costly DOM query every time you want to change something, or store a reference to the element? Pretty clear choice.

// before
$(".quote a").bind("click", doStuff); // DOM query eww

// now
$(".quote a").addClass("quoteLink"); // DOM query eww

// later
$(".quote a").fadeIn("slow"); // DOM query eww

Ignoring chaining, this is better:

// before
var $quoteLinks = $(".quote a");  // the only DOM query
$quoteLinks.bind("click", doStuff);

// now
$quoteLinks.addClass("quoteLink");

// later
$quoteLinks.fadeIn("slow");

USING EFFICIENT SELECTORS

So jQuery/sizzleJS can use CSS3 selectors like a boss, but what’s the real cost? Behind the scenes the browser is hopefully using document.querySelector(), but there’s also a fair chance it will be breaking down your selector string and querying the DOM manually.

// an ID search is the quickest possible query, then it just takes a list of the childNodes and matches the class
$("#quoteList").children(".quotes"); 

// looks for the "foo" class only in the pre-defined bar element
$(".foo",bar);

A ‘for’ Loop is Always Quicker Than a ‘each()’ Loop

No matter what happens in the next few years of browser development, a native for loop will always be quicker than a jQuery$.each() loop. When you think of what jQuery really is (a library wrapped around native JS functions) you begin to realise that the native underlying JavaScript is always going to be quicker. It’s a tradeoff of run speed versus authoring speed.

It is vital that a native for loop is always used for performance critical functions that could fire potentially hundreds of times per second. Examples include:

  • Mouse movement
  • Timer intervals
  • Loops within loops

CSS

Understanding the Box Model is Key

The “box model” is a key determining factor in how a browser renders your page. A healthy understanding of it’s intricacies will make your job so indescribably easier. The box model denotes the way in which the physical dimensions of a HTML element are calculated. If a block element has a fixed width of say, 100px, then how should the padding, border and margin be placed?

Plenty of websites offer in depth descriptions, but put simply: the standards compliant implementation places the border and padding outside of the specified width. It’s best explained with a graphic. Consider this code:

/* the old way (178 + 20 + 2 = 200) */
.foo {
	width: 150px;
	height: 150px;
	padding: 25px;
	border: 25px solid;
	margin: 20px;
}

WHAT YOU WOULD EXPECT (QUIRKS MODE)

The padding and border are calucated inward, preserving the height and width specifically set to be 150px.

Box Model - Quirks Mode

WHAT YOU GET (STANDARDS COMPLIANT MODE)

Instead, you get 250px. 150px + (2 * 25) + (2 * 25).

Box Model - Standards Mode

If you think it seems odd, you’re not alone. There is a fix at hand, and it involves a CSS property called box-sizing, and it works in IE8 and above. It allows you to choose the exact way in which an elements dimensions are calculated, and its a lifesaver. Parameter support varies and vendor prefixes apply, so consult caniuse for specifics.

/* the old way (178 + 20 + 2 = 200) */
.foo {
	width: 178px;
	padding: 10px;
	border: 1px;
}

/* a better way */
.foo {
	width: 200px;
	padding: 10px;
	border: 1px;
		-webkit-box-sizing: border-box;
		-moz-box-sizing: border-box;
		box-sizing: border-box;
}

While it was always possible to mentally calculate widths by removing pixel units from each other (as per the first method), it was never entirely clear how to do so with variable width units like percentages and EMs. There was no other solution at this point besides wrapping elements in parent elements to ensure widths and padding/margin/borders could all be separate.

Know when to Float, and when to Position

Gone are the days of table based layouts. The moment we admit that we can concentrate our efforts into better understanding the way floats and positions work. There’s a particular mental model that needs to be grasped, and I believe this is something best done with practise.

Floats are great for sucking elements out of the DOM and forcing them hard up against a left or a right edge. They became the bread and butter of the post table layout stage in front end dev, possibly because of the poor browser support of display: inline and inline-block, as well as z-index bugs stemming from position support. These days there really is no excuse. Inline-block is fairly well supported, and a quick hack will get it working in IE7.

The arguments that previously held back absolutely positioning elements with CSS have thankfully died down. In theory, positioning allows you to place elements on a page (or within any container for that matter) with Xs and Ys in a straightforward manner that should be familiar to people like Flash developers.

UNDERSTANDING POSITIONS

It’s important to understand one fact when positioning elements with CSS: the position is always relative to the nearest positioned parent element. When people first start dabbling with CSS, there’s a common misconception that position: absolute; positions right up to the page root. I think this stems from the fact that, yes, without any parent elements with position styles – this is true. It traverses up the DOM tree, not finding any positioned elements, and settles on the root of the page.

So if position: absolute; pulls elements out of their normal flow, how do you position an element relative to it’s parent? That’s straight forward. The parent element needs to by styled position: relative;, and then all child elements will draw from the top, right, bottom and left of this parent container. Using this knowledge, how would you go about achieving the following straightforward layout?

How would go about coding up this image?

Using float, you would need to wrap the items in a clearfix, float .one left, and fiddle with floats and margins on both .twoand .three. You would end up with something similar to the following:

.parent {
	/* ghetto clearfix */
	width: 310px;
	overflow: auto;
}
.one {
	width: 200px;
	height: 210px;
	float: left;
}
.two {
	width: 100px;
	height: 100px;
	float: right;
	margin-bottom: 10px;
}
.three {
	width: 100px;
	height: 100px;
	float: right;
}

Using position allows us to, as described earlier, paint the elements on the screen with x and y co-ordinates in a very explicit way. While the above method with floats will break long lines down the page, the below method will keep everything in place, regardless of content.

.parent {
	position: relative;
	width: 310px;
	height: 210px;
}
.one, .two, .three {
	position: absolute;
}
.one {
	top: 0;
	left: 0;
	width: 200px;
	height: 210px;
}
.two {
	top: 0;
	right: 0;
	width: 100px;
	height: 100px;
}
.three {
	bottom: 0;
	right: 0;
	width: 100px;
	height: 100px;
}

As mentioned earlier, there are z-index issues to be considered. While the above example might seem a bit excessive, once you start thinking with positions, it will opens a world of possibilities.

Whitespacing

Whitespacing of CSS can be difficult as we chop and change between single and multi line CSS arguments. I’m not going to get into that.

PROPER SPACING

/* BAD */
.selector {display:none;background:#ff0000;color:#000000;} 

/* GOOD - SINGLE LINE */
.selector { display: none; background: #ff0000; color: #000000; } 

/* GOOD - MULTI-LINE */
.selector {
	display: none;
	background: #ff0000;
	color: #000000;
}

SAME LINE BRACES

.selector {
	display: none;
	background: #ff0000;
	color: #000000;
}

INDENTING CHILD ELEMENTS

Purely optional, and personally only employed when in a document with single line declarations.

.selector { display: none; background: #ff0000; color: #000000; }
	.selector a { text-decoration: none; }
	.selector span { font-weight: bold; }

GROUPING & INDENTING VENDOR PREFIXES

.selector {
	background: #FFF; border: 1px solid #000; color: #EAEAEA;
		-webkit-border-radius: 3px;
		-moz-border-radius: 3px;
		border-radius: 3px;
}

CSS Shorthand

GROUPING PROPERTIES

Grouping properties together is one of the single most effective methods to greatly reduce the size of a CSS file. It’s important to understand how properties are ordered (clockwise – top, right, bottom, left) and how they can be further shortened (top and bottom, left and right).

/* LONG CODE IS LONG */
padding-top: 1px;
padding-right: 2px;
padding-bottom: 1px;
padding-left: 2px;

/* BETTER */
padding: 1px 2px 1px 2px;

/* BEST */
padding: 1px 2px;

FROM 0PX TO HERO

Assigning a unit type to a property value of zero is redundant. It is not important to know whether an element should be 0pxfrom the left or 0 elephants from the left, just that it’s bang on the left.

/* BAD */
padding: 0px 10px;
/* GOOD */
padding: 0 10px;

Commenting Blocks

Commenting large blocks of CSS is a great way of keeping track of multiple style areas within the one stylesheet. Obviously it works better with single line CSS styles, but the effect is not entirely lost on multi-line either. The use of dashes versus equals versus underscores are all up the individual, but this is how I like to manage my stylesheets.

/* === HORIZONTAL NAV === */
#horizNav { width: 100%; display: block; }
#horizNav li { display: block; float: left; position: relative; }
#horizNav li a { display: block; height: 30px; text-decoration: none; }
#horizNav li ul { display: none; position: absolute; top: 30; left: 0; }

/* === HOME PAGE - CAROUSEL === */
#carousel { width: 960px; height: 150px; position: relative; }
#carousel img { display: none; }
#carousel .buttons { position: absolute; right: 10px; bottom: 10px; }

Clearing Floats

Clearing a <div> used to mean extra DOM, because it involved adding an extra clearer element. The better way is to set a specific width on the parent element (“auto” doesn’t work in all browsers and scenarios) and an overflow value of either “auto” or “hidden”. “Hidden” obviously degrades better, but there are some IE compatibility versions where “auto” works better.

THE HTML:

<div class="parentElement">
	<div class="childElement">
		I'm floated left!
	</div>
	I'm normal text that wraps around the float
</div>

THE CSS:

.parentElement {
	width: 100%;
	overflow: hidden;
}
.childElement {
	float: left;
}

Contributors have also brought the latest clearfix to my attention. The micro clear-fix is considered stable and cross browser compliant enough to make it to the latest HTML5 boiler plate release. I highly recommend you check it out. Although I am not a massive fan of browser-specific CSS and pseudo elements such as :after, the micro clearfix is definitely more robust. It also prevents top margins from collapsing which is an absolute life saver.

Vertical & Horizontal Centering

Centering elements horizontally is not exactly rocket science, and I’m sure most of you are familiar with the following snippet:

.class {
	width: 960px;
	margin: 0 auto;
}

Front end devs have been using this snippet for a long time, without fully understanding why it didn’t work vertically. From my understanding, it’s important to remember that the parent element will generally have a height: auto; on it, and that there is no 100% height in which to vertically center the element. Applying the position: absolute; effectively moves the element out into position mode and responds to the pushing and pulling of auto margins and no specific location.

.exactMiddle {
	width: 100px;
	height: 100px;
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	margin: auto;
}

The downsides of this method include its lack of support in IE6 and IE7, and the absence of a scroll bar if the browser is resized to be smaller than the centered object. There are more methods on this page (this is Method 4), but this is by far the best.

The vertical centering of text in an element is also straightforward. If the text is on a single line, like a horizontal navigation item, you can set the line-height to be that of the element’s physical height.

#horizNav li {
	height: 32px;
	line-height: 32px;
}

Feature Sniff, Don’t Browser Sniff

In the earlier discusison of JavaScript feature detection, applying properties if a browser is any version of IE is increasingly problematic. Man-of-steel Paul Irish pioneered the use of IE version sniffing to address this problem, but Modernizr has since come to the rescue. Modernizr places classes on the root <html> element specifying whether features are supported. Bleeding edge styles can then easily cascade from (or be removed from) these classes.

.my_elem {
   -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.25);
   -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.25);
   box-shadow: 0 1px 2px rgba(0,0,0,0.25);
}

/* when box shadow isn't supported, use borders instead */
.no-boxshadow .my_elem {
   border: 1px solid #666;
   border-bottom-width: 2px;
}

You’re Not !important

A reliance upon the !important tag is a dangerous thing. The cases that warrant its use are rare and specific. They revolve around the necessity to override another stylesheet which you do not have access or permission to edit. Another scenario is hard coding an element’s styles to prevent inline JavaScript styles from taking precedence. Instead !important is used as a lazy shortcut to set the priority of your style over another, causing headaches further down the line.

The use of the !important tag can be mostly avoided via the better understanding of CSS selector precedence, and how to better target elements. The more specific the selector, the more likely it will be accepted as the applicable style. The following example from vanseodesign demonstrates the specificity at work.

p { font-size: 12px; }
p.bio { font-size: 14px; }

Their article on style precedence does a better job explaining inheritence than I ever could, so please give it a go.

Aggressive Degradation

It’s worth noting that this is a personal opinion, and best suited to very specific situations. The stance of aggressive degradation will not be well received in large commercial projects or enterprise solutions relying upon older browsers.

Aggressive degradation dictates that if a particular (older) browser cannot render a certain effect, it should simply be omitted. A CSS3 button is a good example. Effects such as border-radiusbox-shadowtext-shadow and gradients will be displayed in cutting edge browsers. A graceful fallback of a .PNG would be provided for slightly older browsers, and the most graceful of all solutions would include a PNG-Fix for IE6 or the use of filter arguments to replicate gradients and shadows. However, aggressive degradation in this situation instructs you to neglect the older browsers and present them with a flat, satisfactory object.

Put simply, aggressive degradation boils down to: if your browser can’t render a gradient or a box shadow, tough luck.

While not ideal for every situation, it ensures the timely delivery of projects and that the root product is still usable and not reliant on (validation breaking) hacks.

CSS3 & HTML5

Feature Sniff with Modernizr

I think I’ve gone on enough about this already. Use Modernizr to detect the availability of specific HTML5 and CSS3 features.

@font-face Use and Abuse

Before you consider embedding a custom font, is important that you inspect the EULA and check if web embedding is allowed. Foundries are understandably reluctant to allow designers and developers the ability to place font files directly on a server which can then be copied by a savvy end user. Particular foundries also prohibit the embedding of particular file types, such as.TTF and .OTF.

If, after careful consideration, you believe the desired font is web embeddable: head on over to the Font Squirrel @font-face Generator. It utilises Fontspring’s bulletproof @font-face structure and automatically generates all the required file formats.

Degradation

Thankfully browser handling of unsupported HTML5 and CSS3 is already that of a graceful nature. New additions to the list of<input /> types such as “email”, “search” etc. will generally degrade to normal <input type="text" /> when not natively supported. Similarly, CSS3 properties that aren’t supported will simply not appear. Responsive layouts controlled by height and width media queries are simply not applied.

Subtle CSS3 effects should be employed as a reward for users who run a modern browser.

The resources section below includes a few libraries to help normalise HTML5 and CSS3 functionality across a range of older browsers.

Resources

Useful Resources

The following resources are vital for the standardisation of code and interaction in a modern web page. They ensure that CSS3 and HTML5 features are made accessible across a range of browsers that previously lacked support.

Support and Suggestions

This document was prepared by Tait Brown (@taitems).

Questions, corrections and suggestions can be lodged on the GitHub repository for this page. You can also fork your own branch and add your own company/product specific guidelines.

Anunciando jQuery Mobile 1.3.0 Beta

  • Enfocada en mejorar el RWD (responsive web design)
  • Nuevos widgets como panels y tablas responsive

1.3: Un enfoque responsivo

Desde el comienzo del proyecto de Jquery Mobile , se ha perseguido el objetivo de diseñarlo para todos los dispositivos y plataformas en un aproximación “One web”. Con ese proposito, se ha desarrollado todo el código en la filosofia de progressive enhancement y todos los widgets han sido diseñados con el width a 100% para que se ajustaran dentro del grids flexibles y responsivos.

jQuery Mobile-first

Además jQuery Mobile ha sido diseñado y testado completamente para funcionar no sólo en teléfonos móviles, sino para que funcione también en tablets e incluso en equipos de sobremesa. Por tanto , más que pensar en “mobile only” , pensemos en “mobile first”. De hecho, en nuestra próxima release vamos a empezar el proceso de integrarlo más con jquery UI con el objetivo de tener incluso más convenciones y código compartido. Las UI tabs serán las primeras en ser portadas a jQM y al sistema de theming.

Ante la pregunta “Qué debería usar RWD o jQM?” que se nos hacia en los foros , nuestra respuesta era siempre “ambos”. Piensa en jQM como un conjunto de elementos para interfaces gráficos que soportan eventos táctiles y que han sido diseñados para ajustarse a un diseño responsivo. Incluso con la versión 1.0 , nuestras demos y documentación ya daban ejemplo utilizando media queries para tener una experiencia responsiva, pero hemos decidido que podiamos hacer un mejor trabajo ayudando a utilizar las técnicas de diseño responsivo en sus propios proyectos.

Nuestro objetivo con la versión 1.3 ha sido educar a la comunidad en el RWD redactando documentación al respecto: responsive documentation y con demos que explican los conceptos claves , además de insertando nuevos widgets como tablas responsivas , paneles y grids que hacen más fácil desarrollar aplicaciones y webs responsivas.

Atando breakpoints

Las media queries no es fácil que la incluyan los frameworks javascript dentro de su código debido a que responsividad siempre es en base al contenido específico de cada website. Por esta razón, es imposible idear una sola característica que funcione a todo el mundo.

Por ejemplo , en el widget de tabla responsiva necesitamos seleccionar un screen width para poder cambiar la presentación tabular y apilada por el modo reflow. Ese width dependerá completamente tanto del diseño (tipografía y otros elementos de layout) y el contenido (número de columnas , content length) . Para tratar con esto, en los docs de cada widget responsivo , invertimos mucho tiempo explicando cómo escribir código que se ajuste a tus necesidades particulares.

Clases breakpoint al rescate

La otra cara de la moneda es que la gente utiliza un framework porque quieren hacer las cosas de forma más fácil y es duro explicar que un diseño responsivo no funcionará hasta que escribas una buena cantidad de CSS. Asi que el compromiso que hemos tomado con los widgets responsivos es incluir un simple breakpoint llamado “preset” en el CSS structural que esperemos que sea útil en la mayoría de las situaciones. Este breakpoint se aplica añadiendole al html del widget la clase ui-responsive para así activar el breakpoint

Pensamos que esto era una buena solución entre conveniencia y educar a los colegas en cómo utilizar meia queries.

Nuevo Widget: Panels

Uno de los patrones UI más comunes en estos días son los paneles estilo Facebook que se abren para mostrar el menu, formulario u otro contenido. Invertimos mucho tiempo prototipando distintas ideas y estamos contentos con nuestro nuevo widget de panel: new panel widget. Los panels pueden ser posicionados a la izquierda o a la derecha de la pantalla y pueden ser colocados con flexibilidad en el código fuente.

There are three different ways a panel can animate open. The default reveal display slides the page away to show the panel beneath, the push display animates both the panel and page, and the overlay display places the panel on top of the page. Panels can be closed by swiping, tapping onto the page, or hitting the Esc key on the keyboard.

Para hacer este widget responsivo , es fácil utilizar media queries que hagan que el panel permanezca abierto en anchos grandes y se auto-cierre cuando haces click en el contenido central. Esto

To take this widget responsive, it’s easy to add media queries to make the panel stay open at wider widths instead of auto-closing when you click on the page content. This makes this panel more like a collapsible column, like the folder list in a mail program. We’ve included a breakpoint preset to add this behavior by adding a class to the page container. Here’s an example of a typical panel setup with a left nav panel and right panel with a form.

For such a simple looking widget, panel were really challenging to get right across all our platforms. We ended up going through four different re-factors leading up to beta in order to get the animations as smooth as possible and are really happy with the result.

Panel API docs >

New: Responsive tables

There are a lot of possible ways to handle tabular data in responsive designs. We’ve decided to tackle two different responsive table modes in 1.3, each with its own strengths and uses.

The reflow table mode swaps to a stacked label/data style presentation at narrow screen widths and best for situations where the content length is fairly long and comparing data across rows in a table is less critical. For example, a product or movie list might be a good choice for reflow mode.

Reflow table API docs >

The column toggle table mode hides columns at narrower page widths according to a priority you set on each column as a sensible default to ensure that the table fits on-screen. A dynamically generated column chooser popup allows the user to select which columns they want to see for full control. This mode is best for situations where comparing data across rows and columns is critical. For example, a complex table of financial data might be a good choice for column toggle mode.

Column toggle API docs >

We’ve built some cool demos showing how you can customize these basic table tools to make a comparison chart or present complex financial data with grouped headers and more.

New: Range slider

Adding support for dual handle sliders for collecting range values has been a popular request and we’re happy to add this new widget in 1.3. The new dual handle range slider starts with a pair of HTML5range inputs and essentially two sliders with a shared track. All the normal slider options work with ranges: mini sizing, theming, etc.

We’ve also refined the size and styling of the inputs that accompany sliders to make them integrate better visually and leave more room for the slider. The inputs are now mini sized with bold text and no border or spinner arrows (seen in desktop browsers).

All sliders now respect step values smaller than whole numbers which is great for scientific and financial applications that need inputs that capture values to the 0.1 or 0.01 level of accuracy. Slider behavior has been refined so dragging will snap to the closest step position to provide better feedback.

Range slider API docs >

New: Responsive grids

The cornerstone of any responsive design are responsive grids. We believe that the best grid systems are content-specific and not something that can be easily generalized into a framework but for people using our simple grid blocks, there are now detailed instructions on how to create your own media queries to adjust grids at various breakpoints.

We’re also shipping with a present breakpoint that can be applied by adding a class to your grid wrapper. This will apply a CSS breakpoint at narrower screen widths that stack all the grid blocks instead of floating them. This is a simple way to make your grids a bit responsive and fit better on phones.

Grid API docs >
Responsive grids >

 

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.