14 razones por las que nadie utiliza tu plugin jQuery
Spanish (Español) translation by Esther (you can also view the original English article)
Con tanta gente desarrollando plugins de jQuery, no es raro encontrarse con uno que simplemente, a falta de mejores palabras, apesta. No hay ejemplos ni documentación, el plugin no sigue las mejores prácticas, etc. Pero tú eres uno de los afortunados: este artículo detallará las trampas que debes evitar.
jQuery no es un desconocido para aquellos que frecuentan Nettuts+. Los increíbles 30 días para aprender jQuery de Jeffrey Way (y varios otros tutoriales aquí y en otros lugares) nos han llevado por el camino de la maravilla impulsada por Sizzle. Con todo el bombo y platillo (y muchos saltos en la adopción de JavaScript por parte de los desarrolladores y los proveedores de navegadores), han aparecido en escena muchos plugins. Esta es en parte la razón por la que jQuery se ha convertido en la biblioteca de JavaScript más popular disponible. El único problema es que muchas de ellas no son demasiado buenas.
En este artículo, nos centraremos menos en el JavaScript específicamente, y más en las mejores prácticas para la entrega de plugins.
1- No estás haciendo un plugin de jQuery
Hay algunos patrones que son, más o menos, universalmente aceptados como "La manera correcta" de crear plugins jQuery. Si no sigues estas convenciones, tu plugin puede... ¡apestar! Considera uno de los patrones más comunes:
1 |
(function($, window, undefined){
|
2 |
$.fn.myPlugin = function(opts) {
|
3 |
var defaults = {
|
4 |
// setting your default values for options |
5 |
} |
6 |
|
7 |
// extend the options from defaults with user's options |
8 |
var options = $.extend(defaults, opts || {});
|
9 |
|
10 |
return this.each(function(){ // jQuery chainability
|
11 |
// do plugin stuff |
12 |
}); |
13 |
})(jQuery, window); |
En primer lugar, creamos una función anónima autoinvocada para evitar el uso de variables globales. Pasamos $, window, y undefined. Los argumentos con los que se llama a la función autoinvocable son jQuery y window; no se pasa nada para undefined, de modo que si decidimos usar la palabra clave undefined dentro del plugin, "undefined" será realmente undefined.
¡Esto protege de la posibilidad de que otros scripts asignen un valor malicioso a
undefined, comotrue!
$ se pasa como jQuery; lo hacemos así para asegurarnos de que, fuera de la función anónima, $ puede seguir refiriéndose a algo completamente distinto, como Prototype.
Pasar la variable para el objeto window accesible globalmente permite un código más comprimido a través de los procesos de minificación (lo que deberías estar haciendo, también).
A continuación, vamos a utilizar el patrón de plugin de jQuery, $.fn.PluginName. Esta es una forma de registrar tu plugin para ser usado con el formato $(selector).method(). Simplemente extiende el prototipo de jQuery con su nuevo método. Si en cambio quieres crear un plugin que defina una función sobre el objeto jQuery, añádelo directamente, así:
1 |
$.PluginName = function(options){
|
2 |
// extend options, do plugin stuff |
3 |
} |
Este tipo de plugin no será encadenable, ya que las funciones que se definen como propiedades del objeto jQuery normalmente no devuelven el objeto jQuery. Por ejemplo, considera el siguiente código:
1 |
$.splitInHalf = function(stringToSplit){
|
2 |
var length = stringToSplit.length; |
3 |
var stringArray = stringToSplit.split(stringToSplit[Math.floor(length/2)]); |
4 |
return stringArray; |
5 |
} |
Aquí, estamos devolviendo un array de cadenas. Tiene sentido devolver esto simplemente como un array, ya que esto es lo que probablemente los usuarios querrán usar (y pueden envolverlo fácilmente en el objeto jQuery si lo desean). Por el contrario, consideremos el siguiente ejemplo artificial:
1 |
$.getOddEls = function(jQcollection){ //
|
2 |
return jQcollection.filter(function(index){
|
3 |
var i = index+1; |
4 |
return (index % 2 != 0); |
5 |
}); |
6 |
} |
En este caso, el usuario probablemente espera que el objeto jQuery regrese de $.getOddEls; por lo tanto, devolvemos el método filter, que devuelve la colección jQuery definida por la función que se pasa. Una buena regla general es envolver los elementos devueltos en la función jQuery, especialmente si se pueden encadenar; si está devolviendo arrays, cadenas, números, funciones u otros tipos de datos, déjalos sin envolver.
2 - No estás documentando tu código (correctamente)
Podría decirse que lo más importante que puedes hacer al publicar tu código es añadir la documentación necesaria. La brecha entre lo que explicas a los desarrolladores y lo que el código realmente hace o puede hacer es el tiempo que los usuarios no quieren perder averiguando los entresijos de tu código.
La documentación es una práctica que no tiene reglas fijas; sin embargo, se acepta generalmente que cuanta más documentación (bien organizada) se tenga, mejor.
Este proceso debe ser tanto una práctica interna (dentro/intercalada en tu código) como una práctica externa (explicando cada método público, opción y múltiples casos de uso a fondo en un wiki o readme).
3 - No ofreces suficiente flexibilidad o personalización
Los plugins más populares ofrecen acceso completo a las variables (lo que la mayoría de los plugins denominan objetos "opciones") que un usuario puede querer controlar. También pueden ofrecer muchas configuraciones diferentes del plugin para que sea reutilizable en muchos contextos diferentes. Por ejemplo, consideremos un simple plugin de deslizamiento. Las opciones que el usuario podría desear controlar incluyen la velocidad, el tipo y el retraso de la animación.
Es una buena práctica dar también al usuario acceso a los nombres de clase/ID que se añaden a los elementos DOM insertados o manipulados por el plugin. Pero más allá de esto, es posible que también quieran tener acceso a una función de devolución de llamada cada vez que la diapositiva transita, o tal vez cuando la diapositiva transita de vuelta al principio (un "ciclo" completo).
Es tu trabajo pensar en todos los posibles usos y necesidades del plugin.
Consideremos otro ejemplo: un plugin que hace una llamada a una API debe proporcionar acceso al objeto devuelto por la API. Tomemos el siguiente ejemplo de un simple plugin concep:.
1 |
$.fn.getFlickr = function(opts) {
|
2 |
return this.each(function(){ // jQuery chainability
|
3 |
var defaults = { // setting your default options
|
4 |
cb : function(data){},
|
5 |
flickrUrl : // some default value for an API call |
6 |
} |
7 |
// extend the options from defaults with user's options |
8 |
var options = $.extend(defaults, opts || {});
|
9 |
|
10 |
// call the async function and then call the callback |
11 |
// passing in the api object that was returned |
12 |
$.ajax(flickrUrl, function(dataReturned){
|
13 |
options.cb.call(this, dataReturned); |
14 |
}); |
15 |
}); |
16 |
} |
Esto nos permite hacer algo parecido:
1 |
$(selector).getFlickr(function(fdata){ // flickr data is in the fdata object });
|
Otra forma de dar a conocer esto es ofrecer "ganchos" como opciones. A partir de jQuery 1.7.1, podemos utilizar .on(eventName, function(){}) después de nuestra llamada al plugin para separar los comportamientos en sus propias funciones. Por ejemplo, con el plugin anterior, podríamos cambiar el código para que se vea así:
1 |
$.fn.getFlickr = function(opts) {
|
2 |
return this.each(function(i,el){
|
3 |
var $this = el; |
4 |
var defaults = { // setting your default options
|
5 |
flickrUrl : "http://someurl.com" // some default value for an API call |
6 |
} |
7 |
var options = $.extend(defaults, opts || {});
|
8 |
|
9 |
// call the async function and then call the callback |
10 |
// passing in the api object that was returned |
11 |
$.ajax(flickrUrl, function(dataReturned){
|
12 |
// do some stuff |
13 |
$this.trigger("callback", dataReturned);
|
14 |
}).error(function(){
|
15 |
$this.trigger("error", dataReturned);
|
16 |
}); |
17 |
}); |
18 |
} |
Esto nos permite llamar al plugin getFlickr y encadenar otros manejadores de comportamiento.
1 |
$(selector).getFlickr(opts).on("callback", function(data){ // do stuff }).on("error", function(){ // handle an error });
|
Puedes ver que ofrecer este tipo de flexibilidad es absolutamente importante; cuanto más complejas sean las acciones de tus plugins, más complejo debe ser el control disponible.
4 -Exiges demasiada configuración
Ok, así que el consejo número tres sugirió que cuanto más complejas sean las acciones de tus plugins, más complejo será el control disponible. Un gran error, sin embargo, es hacer que se requieran demasiadas opciones para la funcionalidad del plugin. Por ejemplo, es ideal que los plugins basados en la interfaz de usuario tengan un comportamiento por defecto sin argumentos.
1 |
$(selector).myPlugin(); |
Ciertamente, a veces esto no es realista (ya que los usuarios pueden estar buscando una fuente específica, por ejemplo). En este caso, deberías hacer parte del trabajo pesado por ellos. Ten varias formas de pasar opciones al plugin. Por ejemplo, digamos que tenemos un simple plugin de búsqueda de tweets. Debería haber un comportamiento por defecto de ese recuperador de Tweets con una única opción requerida (el nombre de usuario que quieres recuperar).
1 |
$(selector).fetchTweets("jcutrell");
|
Por ejemplo, el valor por defecto puede tomar un solo tweet, envolverlo en una etiqueta de párrafo y llenar el elemento selector con ese html. Este es el tipo de comportamiento que la mayoría de los desarrolladores esperan y aprecian. Las opciones granulares deberían ser solo eso: opciones.
5 -Estás mezclando reglas CSS externas y reglas CSS en línea
Es inevitable, dependiendo del tipo de plugin, por supuesto, que tengas que incluir un archivo CSS si está muy basado en manipulaciones de la interfaz de usuario. Esta es una solución aceptable al problema, en general; la mayoría de los plugins vienen con imágenes y CSS. Pero no olvides el segundo consejo: la documentación también debe incluir cómo usar/referir la(s) hoja(s) de estilos y las imágenes. Los desarrolladores no querrán perder el tiempo buscando en el código fuente para averiguar estas cosas.
Las cosas deberían... funcionar.
Dicho esto, es definitivamente una mejor práctica utilizar estilos inyectados (que son altamente accesibles a través de las opciones del plugin) o estilos basados en clases/IDs. Estos IDs y clases también deben ser accesibles, a través de opciones como se mencionó anteriormente. Sin embargo, los estilos en línea anulan las reglas CSS externas; se desaconseja mezclar ambos, ya que un desarrollador puede tardar mucho tiempo en averiguar por qué sus reglas CSS no son respetadas por los elementos creados por tu plugin. Utiliza tu mejor criterio en estos casos.
Como regla general, el CSS en línea es malo, a menos que sea tan mínimo que no justifique su propia hoja de estilos externa.
6 - No ofreces ejemplos
La prueba está en el pudín: si no puedes proporcionar un ejemplo práctico de lo que hace tu plugin con el código que lo acompaña, la gente se desanimará rápidamente a usar tu plugin. Así de sencillo. No seas perezoso.
Una buena plantilla de ejemplos:
- Un ejemplo de "hola mundo", normalmente la llamada al plugin con la configuración/opciones mínimas pasadas, y su html/css de acompañamiento
- Unos cuantos ejemplos más complicados, normalmente con ejemplos de funcionalidad completa de múltiples opciones
- Un ejemplo de integración, si alguien puede usar otro plugin con tu plugin, aquí es donde puedes mostrar cómo hacerlo. (Esto te da puntos extra en el mundo del desarrollo de código abierto, también. Kudos).
7 -Tu código no coincide con su versión de jQuery
jQuery, como toda buena biblioteca de código, crece con cada versión. La mayoría de los métodos se mantienen incluso después de que el soporte sea obsoleto. Sin embargo, se añaden nuevos métodos; un ejemplo perfecto de esto es el método .on(), que es la nueva solución de jQuery para la delegación de eventos. Si escribes un plugin que usa .on(), la gente que usa jQuery 1.6 o anterior no tendrá suerte. No estoy sugiriendo que codifiques para el mínimo común denominador, pero, en tu documentación, asegúrate de explicar qué versión de jQuery soporta tu plugin. Si introduces un plugin con soporte para jQuery 1.7, deberías considerar fuertemente mantener el soporte para 1.7 incluso cuando salga la 1.8. También deberías considerar aprovechar las nuevas, mejores y más rápidas características de jQuery a medida que vayan apareciendo.
Anima a los desarrolladores a actualizarse, pero no rompas tu plugin con demasiada frecuencia. Una opción es ofrecer un "legado" de versiones obsoletas y no soportadas de tu plugin.
8 - ¿Dónde está el Changelog?
Es el momento de morder la bala si aún no has aprendido a utilizar el control de versiones.
Además de mantener el soporte/compatibilidad de la versión de jQuery como parte de tu documentación, también deberías trabajar en el control de versiones. El control de versiones (específicamente, a través de GitHub) es en gran medida el hogar de la codificación social. Si estás desarrollando un plugin para jQuery que quieres publicar eventualmente en el repositorio oficial, debe ser almacenado en un repositorio de GitHub de todos modos; es hora de morder la bala si no has aprendido a usar el control de versiones. El control de versiones tiene innumerables ventajas, todas ellas fuera del alcance de este artículo. Pero uno de los principales beneficios es que permite a la gente ver los cambios, las mejoras y las correcciones de compatibilidad que haces, y cuando las haces. Esto también abre el camino para la contribución y la personalización/extensión de los plugins que escribes.
Recursos adicionales
- El libro Git
- Control de versiones fácil con Git
- El flujo de trabajo perfecto con Git, GitHub y SSH
- Cómo ser bueno con Git ($19)
- GitCasts
9 - Nadie necesita tu plugin
El mundo no necesita otro plugin de deslizamiento.
Vale, ya lo hemos ignorado lo suficiente: algunos "plugins" son inútiles o demasiado superficiales para justificar que se les llame plugin. ¡El mundo no necesita otro plugin de deslizamiento! Sin embargo, hay que tener en cuenta que los equipos internos pueden desarrollar sus propios plugins para sus propios usos, lo cual está perfectamente bien. Sin embargo, si esperas impulsar tu plugin en la esfera de la codificación social, encuentra una razón para escribir más código. Como dice el refrán, no hay razón para reinventar la rueda. En lugar de eso, coge la rueda de otro y construye un coche de carreras. Por supuesto, a veces hay nuevas y mejores formas de hacer las mismas cosas que ya se han hecho. Por ejemplo, es muy posible que escriba un nuevo plugin de deslizamiento si utilizas una tecnología más rápida o nueva.
10 - No estás proporcionando una versión reducida
Esto es bastante sencillo: ofrece una versión minificada de tu código. Esto lo hace más pequeño y más rápido. También asegura que tu Javascript está libre de errores cuando se compila. Cuando minifiques tu código, no olvides ofrecer también la versión sin comprimir, para que tus compañeros puedan revisar el código subyacente. Existen herramientas gratuitas y baratas para desarrolladores de front end de todos los niveles de experiencia.
Consulta el consejo número trece para una solución automatizada.
11 - Tu código es demasiado inteligente
Cuando escribes un plugin, está destinado a ser utilizado por otros, ¿verdad? Por esta razón, el código fuente más eficaz es altamente legible. Si estás escribiendo innumerables funciones inteligentes de estilo lambda de una línea, o tus nombres de variables no son semánticos, será difícil depurar los errores cuando inevitablemente ocurran. En lugar de escribir nombres de variables cortos para ahorrar espacio, sigue el consejo del consejo número nueve (¡minifica!). Esta es otra parte de la buena documentación; los desarrolladores decentes deberían ser capaces de revisar tu código y entender lo que hace sin tener que gastar demasiada energía.
Si te encuentras llamando a las variables "
a" o "x", lo estás haciendo mal.
Además, si te encuentras consultando la documentación para recordar lo que hace tu propio código de aspecto extraño, también es probable que tengas que ser menos conciso y más explicativo. Restringe el número de líneas de cada función al menor número posible; si se extienden durante treinta o más líneas, podría haber un olor a código.
11. No necesitas jQuery
Por mucho que nos guste usar jQuery, es importante entender que es una librería, y eso tiene un pequeño coste. En general, no necesitas preocuparte demasiado por cosas como el rendimiento del selector jQuery. No seas odioso, y estarás bien. jQuery está altamente optimizado. Dicho esto, si la única razón por la que necesitas jQuery (o un plugin) es para realizar algunas consultas en el DOM, podrías considerar eliminar la abstracción por completo y, en su lugar, quedarte con el JavaScript de vainilla, o con Zepto.
Nota: si decides seguir con el JavaScript de vanilla, asegúrate de que utilizas métodos que sean compatibles con todos los navegadores. Es posible que necesites un pequeño polyfill para las nuevas APIs.
13 -No estás automatizando el proceso
Usa Grunt. Período.
Grunt es una "herramienta de construcción de línea de comandos basada en tareas para proyectos de JavaScript", que fue cubierta en detalle recientemente aquí en Nettuts+. Te permite hacer cosas como esta:
1 |
grunt init:jquery |
Esta línea (ejecutada en la línea de comandos) te hará una serie de preguntas, como el título, la descripción, la versión, el repositorio git, las licencias, etcétera. Estas piezas de información ayudan a automatizar el proceso de configuración de tu documentación, licencias, etc.
Grunt hace mucho más que crear un código personalizado para ti; también ofrece herramientas integradas, como el linter de código JSHint, y puede automatizar las pruebas de QUnit por ti siempre que tengas instalado PhantomJS (del que Grunt se encarga). De esta manera, puedes agilizar tu flujo de trabajo, ya que las pruebas se ejecutan instantáneamente en el terminal al guardarlas.
14 - No estás probando
Por cierto, ¿pruebas tu código, verdad? Si no es así, ¿cómo puedes asegurar/declarar que tu código funciona como se espera? Las pruebas manuales tienen su lugar, pero, si te encuentras refrescando el navegador innumerables veces cada hora, lo estás haciendo mal. Considera el uso de herramientas como QUnit, Jasmine o incluso Mocha.
Las pruebas son particularmente útiles cuando se fusionan las solicitudes de extracción en GitHub. Puedes requerir que todas las solicitudes proporcionen pruebas para asegurar que el código nuevo/modificado no rompa tu plugin existente.
Si el concepto de probar plugins jQuery es nuevo para ti, considera ver nuestro screencast exclusivo para Premium, Técnicas para probar plugins jQuery. ¡Además, vamos a lanzar un nuevo curso de "Pruebas de JavaScript con Jasmine" a finales de esta semana en el sitio!
Algunos recursos útiles
No te haríamos ningún favor si solo te dijéramos lo que estás haciendo mal. Aquí tienes algunos enlaces que te ayudarán a retomar el camino correcto.
- 30 días para aprender jQuery
- Patrones esenciales de plugins jQuery, Smashing Magazine
- Uso de patrones de herencia para organizar grandes aplicaciones jQuery
- Documentación oficial de jQuery para la creación de plugins
- Plantilla jQuery
- OOP jQuery Plugin Boilerplate
- 10 consejos de codificación para escribir plugins jQuery superiores
Reflexiones finales
Si estás escribiendo un plugin de jQuery, es vital que te alejes de las trampas mencionadas anteriormente. ¿Me he perdido algún signo clave de un plugin mal ejecutado?



