Brackets, el nuevo editor de código para la web, es un proyecto bastante ambicioso en muchos niveles, es una herramienta que está escrita utilizando HTML, CSS y JavaScript; los desarrolladores están utilizando al mismo Brackets en la gran mayoría.

Brackets logo

En un momento cuando las discusiones acerca de las mejores prácticas para el desarrollo de aplicaciones web, nunca habían estado tan animadas con Brackets, que es de código abierto, es una gran oportunidad para los desarrolladores para presenciar cómo se puede construir un proyecto complejo de la vida real basado en estándares web. Mientras que el editor de código se encuentra todavía en su infancia (Sprint 11 se acaba de lanzar en el momento de escribir estas líneas), ya hay muchas cosas que puedes aprender al estudiar su código fuente actual.

Organización General

Brackets está alojado en GitHub, dentro de dos repositorios diferentes: uno del código fuente principal, responsable del núcleo de la aplicación web; el otro contiene el recurso nativo de la aplicación shell, lo que hace posible que el editor se ejecute como una aplicación independiente para Windows y Mac OS (antes de preguntar. si, Linux está en la ruta). Por esta aplicación nativa shell, Brackets utiliza el framework de Chromium Embedded, que incorpora una versión de WebKit.

La razón de esta preocupación en cuanto a la separación, podría ser obvia:

Brackets tiene el potencial para ser ejecutado en muchos lugares fuera de las aplicaciones de escritorio nativas. Esta universalidad es la principal fortaleza de los estándares web, y es lo que hace que el proyecto sea tan emocionante, si quieres pregúntame.

En términos de organización de archivos, el repositorio central de Brackets tiene una estructura de carpetas bastante auto-explicativa, además está muy bien documentado, así que creo que no es necesario detallar todos y cada uno de ellos secuencialmente aquí. En cambio, prefiero destacar los distintos aspectos que me llamaron la atención como desarrollador.

Convenciones de código principal

Un vistazo rápido a cualquier archivo JavaScript en el repositorio responderá a una pregunta común acerca de las aplicaciones web modernas: Sí, el código JavaScript de Brackets está escrito usando módulos. Esto no debería sorprenderte. Los módulos son una gran forma para proporcionar un ámbito claro, limitado y una adecuada encapsulación de código JavaScript. Es también una estupenda forma para proporcionar un nivel básico de privacidad, ya que sólo los miembros expuestos a través del objeto devuelto están públicamente disponibles.

Como puedes saber, hay varias propuestas de formato para los módulos, pero sólo dos son realmente usadas hoy en día: CommonJS Modules JS y AMD (Definición de Módulo Asíncrono). El equipo de Brackets ha elegido un enfoque híbrido: utiliza el formato de CommonJS dentro de contenedores compatibles de AMD:

Observa que no se utiliza el parámetro del módulo: es sólo para el cumplimiento de CommonJS. También, los módulos son cargados mediante el popular modulo/script RequireJS. Para más información sobre módulos y cargadores de modulo, recomiendo leer el escrito de Addy Osmani Acerca de JavaScript Modular. Por cierto, algo importante que debes tener en mente es que un módulo y su correspondiente archivo, puede definir cero, una, o muchas clases. Así que si estás buscando una definición de clase, no es necesario buscar el nombre del archivo correspondiente.

Otra cosa un poco interesante que puedes encontrar mientras pases por el repositorio es el uso de un mecanismo diferido/promesa. Brevemente, es un mecanismo de respaldo de llamada en el cual un objeto diferido puede registrarse y enlazar múltiples funciones de respaldo de llamadas, y llamarlas de acuerdo a su estado (Por lo general, pendiente, satisfactorio o fracaso). Este patrón se utiliza para controlar las APIs asíncronas, las cuales son necesarias únicamente sí en una versión hospedad del navegador del editor, todas la operaciones I/O serían asíncronas. Para aprender más acerca de este patrón, te recomiendo leer the Deferred Object in the jQuery docs o CommonJS Promises/A proposal.

En caso de que te estés preguntando, Brackets no utiliza cualquier framework de micro arquitectura de terceros. Encontrarás algunos conceptos comunes como: modelos, vistas y controles, pero no formalizados alrededor de un mecanismo en particular.

Por último, hay una página en el wiki que describe las convenciones de código utilizadas para Brackets. Aunque nada de lo que vi debería sorprender a cualquier desarrollador JavaScript, creo es importante para un proyecto abierto, acordar y comunicar sobre esas prácticas, aunque son bastante comunes.

Administración de documentos y edición de código

Mucho de lo que hace a Brackets una gran herramienta para editar el código proviene de la utilización de un gran proyecto de terceros: CodeMirror. Todo sobre el diseño de un documento de texto, que representa al código y el modificarlo en forma adecuada, proviene de CodeMirror, incluyendo la gestión de sintaxis y enfoque.

La administración de proyectos y los documentos, sin embargo, se manejan por separado. Esta es la lógica responsable de cosas como la definición de un proyecto o un conjunto de trabajo, seleccionar un archivo y realizar el seguimiento de los archivos abiertos dentro de ese proyecto. Si bien esto puede parecer trivial cuando se ponen así, esto es realmente parte fundamental de cualquier software diseñado para editar documentos.

Varias clases están involucradas en este proceso, como son Document, Editor y sus respectivos administradores, y así entender que su relación es esencial para comprender la arquitectura de Brackets.

Mientras que un documento representa un archivo y expone métodos para editarlo mediante programación, un Editor encapsula la interfaz de usuario para editar el documento. Documentos y editores tienen una relación uno a muchos (un documento puede ser editado por varios Editores). Puedes ver el Documento como un modelo y el Editor como un intermediario entre una vista y, el Documento representado como un objeto.

El DocumentManager y el EditorManager pueden crear, eliminar clases, y así proporcionar un acceso central para todos los documentos y editores, respectivamente. Por ejemplo, para acceder documento actual, puedes pedir el DocumentManager:

Pero ya que el editor sigue revisando el documento que se está editando, y el EditorManager administra todos los editores; también podría ir de esta manera:

Observa que el Editor actual y su correspondiente documento no necesariamente corresponden a la pestaña abierta actualmente en la interfaz de usuario, ya que Brackets tienen una noción de editores en línea que pueden venir en la parte superior del editor principal en tamaño completo, que representa el documento abierto actualmente.

Los editores resumen la aplicación de CodeMirror, proporcionando métodos para obtener y establecer la selección, posición del cursor, posición de desplazamiento y otras propiedades. La API de CodeMirror puede aún ser accedida directamente a través de CodeMirror, pero debes utilizar los métodos de Documentos o Editor.

El API Document expone las operaciones de edición de texto como setText() y replaceRange(), que automáticamente se refleja en todos los Editores asociados con ese Documento. Por lo tanto, para modificar el texto, simplemente usa la API Document, independientemente de los Editores:

La administración de selección, sin embargo, está relacionada con una vista correspondiente, por lo que solo está disponible a través del objeto Editor, utilizando métodos como getSelectedText() y setSelection(start, end). Aquí cómo podrías definir la selección del documento que actualmente tiene el foco:

Finalmente, una advertencia: como solución para evitar la falta de referencias en JavaScript, sí, cuando es necesario hacer una referencia de un objeto Document, tienes que llamar a Document.addRef() y, por el contrario Document.releaseRef() cuando hayas terminado. Esto incluye todos los detectores de eventos anexados al documento.

Para más información sobre Documents en Brackets, recomiendo leer la sección dedicada en su github wiki.

Desarrollo directo y editores en línea

Una de las cosas que hace que Brackets sea único hoy en día es su característica de desarrollo directo: Brackets está “conectado” a el navegador de tal manera que mientras se va escribiendo se van mostrando los cambios en el navegador. No hace falta decir, que esto es una característica potencialmente asesina en términos de productividad.

El corazón de la implementación del desarrollo directo es el archivo Inspector.js, la cual está a cargo de la comunicación con el API remota de depuración de Chrome utilizando JSON sobre WebSockets. Otros elementos envueltos en este proceso incluyen Agentes – los cuales mantienen un seguimiento de los cambios y los propagan- y Documents los cuales, de nuevo, representan archivos CSS, JS y HTML en el sistema (no los confundas con la clase genérica descrita arriba)

La característica de editor en línea, que hace posible sobreponer contenido sobre código, es implementada a través de la clase InlineWidget (la base de los editores en línea, que es solo un panel que flota sobre el código). La clase InlineTextEditor es ligeramente más sofisticada: hereda de InlineWidget y agrega un editor de texto sencillo.

La clase que se utilizará para crear un editor en línea, como el editor en línea de CSS de Brackets, es MultiRangeInlineEditor, la cual misma hereda de InlineTextEditor.

Para utilizar un editor en línea, se tiene que registrar una función proveedora con el EditorManager, de esta forma:

EditorManager.registerInlineEditProvider(providerFunction);

Esta función toma dos parámetros: el editor que hospeda y un objeto de posición. Los objetos de posición son utilizados por CodeMirror y contiene dos propiedades: el número de línea y la posición del carácter. Dentro de esta función, simplemente se instancia a MultiRangeInlineEditor y se le pasa la instancia de Editor correspondiente, retornando un objeto Promise (ver arriba) que es resuelto una vez que está completo:

Vistas y administración de la entrada del usuario

No profundizaré mucho en estilos, widgets, layouts, u otros detalles de UI, pero me gustaría señalar que, además de jQuery, Brackets hace uso del popular framework Twitter Bootstrap para su UI elegante que significa que también utiliza LESS CSS preprocessor.

Brackets no utiliza ningún sistema de plantillas. Muchas de las UI están hardcodeadas en el archivo HTML principal. A mi parecer esto podría cambiar en el futuro.

Lo más importante de comprender es la forma en que Brackets maneja la entrada del usuario. Para hacerlo, hace uso del patrón Command. Este patrón encapsula acciones que serán realizadas por el software (por ejemplo “abrir archivo”) como objetos (el comando). Esto es muy conveniente para trazar los gestos del usuario y la entrada de estos objetos, por muchas razones:

1. Permite el desacoplamiento de las interacciones del usuario de su consecuencia en el editor, lo cual ofrece un código más fácil de mantener.

2. Ya que las acciones son tratadas como objetos, pueden mantener un estado, y se pueden realizar todas las operaciones en estas. Por ejemplo, si se deshabilita un comando, o cambia su etiqueta, sus elementos de UI correspondientes serán automáticamente actualizados. Este también es un patrón popular para implementar cosas básicas como una administración de historial y herramientas de scripting, así que también puedes esperar estas características en el futuro.

3. Hace el código más fácil de probar.

En términos de implementación, registrar un comando es tan fácil como esto:

Entonces se puede adjuntarlo a un elemento de menú para que sea ejecutado cuando este elemento sea seleccionado por el usuario:

Aunque también se puede ejecutar manualmente:

Calidad

El código de calidad es absolutamente esencial para cualquier proyecto serio, y por supuesto Brackets no es la excepción. Utiliza JSLint para evaluar la calidad del código. JSLint es una de las herramientas más populares de análisis para JavaScript estático. Fue hecho por Douglas Crockford como una forma de escanear código fácilmente y reportar cualquier problema, como describe en su mecanismo de configuración basado en comentarios.

Encontrarás las directivas de configuración de JSLint al inicio de cada módulo:

Nota que JSLint también es utilizado en Brackets para proporcionar a los desarrolladores retroalimentación inmediata acerca de la calidad de su código.

Brackets también utiliza un framework de pruebas, Jasmine, para garantizar la calidad del código. Jasmine es un framework popular de desarrollo de comportamiento dirigido, utilizado para el desarrollo de JavaScript.

Se ha incluido un realizador de pruebas (en Debug > Run Tests), así que puede ser fácilmente probado, desde sí mismo.

Modelo de extensibilidad temprana

Se incluyó un mecanismo de extensibilidad temprana, permitiendo a los usuarios a extender la funcionalidad de Brackets fácilmente sin tener que poner parches en el núcleo del código. El flujo de trabajo típico para hacerlo sería el ejecutar una segunda instancia de brackets para probar el código actual, utilizando Debug > New Window.

La extensión misma esta descrita como un módulo, pero en alguna forma separa el alcance del resto del código fuente. Para cargar dependencias desde Brackets, se tiene que utilizar brackets.getModule().

Aquí hay una extensión completa de Hello World escrito originalmente por Mike Chambers:

Lo genial es que tu extensión puede tomar ventaja de muchas de las características de Brackets, como el mecanismo del editor en línea.

A dónde ir desde aquí

Espero que esta visión a alto nivel te haga querer saber más acerca de este proyecto, e incluso contribuyas en Brackets.

Para un comprendimiento más profundo acerca de cómo funciona Brackets, te recomiendo dar un vistazo a la wiki de Brackets. Hay varios videos en YouTube desde el primer hackathon de Brackets, pero algunas cosas que se mencionan ahí están desactualizadas, así que no las tomes tan enserio.

Este artículo está publicado bajo licencia Creative Commons así como su versión original en Adobe Devnet, fue traducida y adaptada en nuestro blog por Margarita García.