17

Solo para mantener las cosas interesantes y cerrar mi última pregunta abierta, la solución que implementa la siguiente funcionalidad de una manera muy organizada con una arquitectura decente obtiene una buena recompensa. El código completo está en jsfiddle, y no dude en hacer cualquier pregunta :)¿Cómo organizarías una aplicación web compleja grande (mira el ejemplo básico)?

¿Cómo se suelen organizar aplicaciones web complejas que son extremadamente ricas en el lado del cliente? He creado un ejemplo artificial para indicar el tipo de desastre en el que es fácil entrar si las cosas no se gestionan bien para las aplicaciones grandes. Siéntase libre de modificar/ampliar este ejemplo como desee - http://jsfiddle.net/NHyLC/1/

El ejemplo básicamente espejos parte de la publicación de comentarios en SO y sigue las siguientes reglas:

  1. Debe tener 15 caracteres como mínimo, después de múltiples los espacios se recortan en uno.
  2. Si se hace clic en Add Comment, pero el tamaño es inferior a 15 después de eliminar espacios múltiples, a continuación, muestra una ventana emergente con el error.
  3. Indique la cantidad de caracteres restantes y resumen con codificación de color. Gris indica un comentario pequeño de , marrón indica un comentario medio , naranja un gran comentario , y un desbordamiento de comentario rojo.
  4. Un comentario solo puede enviarse cada 15 segundos. Si el comentario es enviado demasiado pronto, muestre una ventana emergente con el mensaje de error apropiado.

Un par de cuestiones que noté con este ejemplo.

  • Esto debería ser idealmente un widget o algún tipo de funcionalidad empaquetada.
  • Cosas como un comentario por 15 segundos, y un mínimo de 15 comentarios de caracteres pertenecen a algunas políticas de aplicación amplia en lugar de estar incrustado dentro de cada widget.
  • Demasiados valores codificados.
  • Sin organización de código. Modelo, Vistas, Controladores están todos juntos. No es que MVC sea el único enfoque para organizar aplicaciones web ricas del lado del cliente, pero no hay ninguna en este ejemplo.

¿Cómo harías para limpiar esto? ¿Aplicando un pequeño MVC/MVP en el camino?

Aquí hay algunas de las funciones relevantes, pero tendrá más sentido si viste el código completo en jsFiddle:

/** 
* Handle comment change. 
* Update character count. 
* Indicate progress 
*/ 
function handleCommentUpdate(comment) { 
    var status = $('.comment-status'); 

    status.text(getStatusText(comment)); 
    status.removeClass('mild spicy hot sizzling'); 
    status.addClass(getStatusClass(comment)); 
} 

/** 
* Is the comment valid for submission 
* But first, check if it's all good. 
*/ 
function commentSubmittable(comment) { 
    var notTooSoon = !isTooSoon(); 
    var notEmpty = !isEmpty(comment); 
    var hasEnoughCharacters = !isTooShort(comment); 

    return notTooSoon && notEmpty && hasEnoughCharacters; 
} 

/** 
* Submit comment. 
* But first, check if it's all good! 
*/ 
$('.add-comment').click(function() { 
    var comment = $('.comment-box').val(); 

    // submit comment, fake ajax call 
    if(commentSubmittable(comment)) { 
     .. 
    } 

    // show a popup if comment is mostly spaces 
    if(isTooShort(comment)) { 
     if(comment.length < 15) { 
      // blink status message 
     } 
     else { 
      popup("Comment must be at least 15 characters in length."); 
     } 
    } 
    // show a popup is comment submitted too soon 
    else if(isTooSoon()) { 
     popup("Only 1 comment allowed per 15 seconds."); 
    } 

}); 

Edición 1:

@matpol Gracias por la sugerencia para una objeto envoltorio y complemento. Eso realmente será una gran mejora sobre el desastre existente. Sin embargo, el complemento no es independiente y, como mencioné, sería parte de una aplicación compleja más grande. Las políticas de aplicación amplia en el lado del cliente/servidor dictarían cosas como la duración mínima/máxima de un comentario, la frecuencia con la que un usuario puede comentar, etc. Seguramente el complemento puede ser alimentado con esta información como parámetros.

Además, para una aplicación de cliente enriquecida, los datos deberían separarse de su representación html, ya que se pueden guardar muchos viajes de ida y vuelta del servidor ya que la aplicación es compatible con datos y se pueden almacenar localmente, y periódicamente actualizado en el servidor, o en eventos interesantes dentro de la propia aplicación (como cuando la ventana está cerrada). He aquí por qué realmente no me gusta el enfoque de un plugin. Funcionaría como proporcionar una representación empaquetada, pero aún estaría centrada en el DOM, lo que será problemático cuando tenga 20 de estos complementos en la aplicación, lo que no es un número absurdo de ninguna manera.

+0

Puede considerar el cambio de nombre de la pregunta para expresar más detalles o intenciones, solo un pensamiento. –

+0

¡Buena idea Mike! el título no es muy indicativo de la pregunta. Déjame reformularlo. – Anurag

+0

¿Está imponiendo la misma validación en el servidor? Si es así, tiene mucho sentido que los dos compartan una interfaz común. Dependiendo del idioma/framework del servidor/etc., eso puede dictar cómo está organizado el lado del cliente (o viceversa). – tadamson

Respuesta

23

La forma en que haría esto es 3 veces.

  1. Encapsular Javascript en pequeñas clases bien definidas dentro de los espacios de nombres clases
  2. Javascript deben tener HTML que requieren "inyecta" en ellos como la dependencia permitiendo out-of-browser unit testing
  3. movimiento como la funcionalidad del lado del cliente tanto al servidor como sea posible y utilizar un concepto conocido como AHAH

Javascript nombre de espaciamiento

Esto puede lograrse con facilidad y se ha cubierto en otros mensajes como este Is there a "concise" way to do namespacing in JavaScript?

clases encapsulados pequeños

de código Javascript, al igual que el código del lado del servidor debe estar bien encapsulado con pequeñas clases y métodos cohesivos. Cada clase vive en un archivo separado, nombrado junto con el espacio de nombres en el que se encuentra, por ejemplo: MyCompany.SomePackage.MyClass.js. Se pueden guardar solicitudes HTTP excesivas a cada archivo a través de combining and minifying estos archivos de clase en tiempo de compilación.

Dependencia Inversion en Javascript

tan eficazmente en lugar de seleccionar los elementos que se requieren para trabajar con el interior de su clase, como esto:

var MyNamespace.MyClass = function() { 
    var elementINeed = $('#IdOfElementINeed'); 
} 

Se inyectaría como tal:

var foo = new MyNamspace.MyClass($('#IdOfElementINeed')); 

var MyNamespace.MyClass = function(incomingDependency) { 
    var elementINeed = incomingDependency; 
} 

Esta técnica se presta bien para javascript comprobable y la separación de preocupaciones a través de MVC style capas de su código.

AHAH y simplificación del lado del cliente

AHAH es absolutamente una vieja técnica que ha existido desde hace bastante tiempo en desarrollo web, aunque está haciendo un resurgimiento entre los aficionados web por su sencillez pura.Sin embargo, la filosofía debe comprarse en más que el nivel de técnica arquitectónica y debe usarse como reemplazo de todo su lado del cliente javascript, por ejemplo: validación, mostrar/ocultar contenido dinámico, cálculos, etc.

Donde solía adjuntado un evento de clic con la complejidad del lado del cliente:

$('#someElement').click(function(){ 
    // insert complex client-side functionality here, such as validating input 
    // eg var isValid = $(this).val() < minimumCommentLength; 
    // update page based on result of javascript code 
    // eg $('#commentTooLong').show(); 
}) 

Ahora sólo tendría que activar una petición ajax de vuelta al servidor para obtener el nuevo HTML y simplemente reemplazar la totalidad o algunos de los elementos que le interesan, como tal, :

$('#addCommentButton').click(function(){ 
    $.ajax({ 
    url: "/comment/add", 
    context: document.body, success: 
    function(responseHTML){ 
     $('body').html(reponseHTML); 
     }}); 
}) 

Obviamente, este es un ejemplo trivial, pero cuando se utiliza de forma efectiva, CUALQUIER evento de javascript en la página, simplemente activa la solicitud de ajax idéntica y el reemplazo de HTML, reduciendo en gran medida la cantidad de código requerido por el cliente. Moverlo al servidor donde puede ser probado de manera efectiva.

ahaḥ nay-Sayers, argumentan que esto no es una forma performant para ejecutar un sitio web, sin embargo he utilizado y visto esta técnica en los sitios con acceso módem de 56k y también a escala masiva sitios web públicos. El resultado es, por supuesto, más lento, pero aún puede producir viajes de ida por debajo de 100 milisegundos, que es prácticamente instantáneo para los humanos.

+0

Gracias, estos son todos puntos realmente buenos. He visto que AHAH se usa para simplificar enormemente el desarrollo del lado del cliente de un sitio web y, al mismo tiempo, hace que sea extremadamente fácil tener una estrategia API sin demasiada sobrecarga. Simplemente tener múltiples puntos de entrada como '/ comment/add.json' o'/comment/add.xml' que devuelven una respuesta JSON o XML, respectivamente, es simplemente una cuestión de agregar más vistas. – Anurag

+0

@Anurag Cuando se piensa en REST, que haría una sola/commend/poner punto final, que entiende cómo tratar con 'Accept: text/xml' o 'Accept: application/cabeceras json'. – bukzor

3

Podría convertirlo en un complemento jQuery o en un objeto estático.

El objeto estático simplemente actúa como un tipo o envoltorio. También lo dividiría en funciones más pequeñas, por ej.

init() 
checkLength() 
checkTime() 

lo que podría terminar con algo como:

Widget = { 

init:function(){//setup events etc}, 
checkLength:function(){}, 
checkTime:function(){}, 
doMessage:function(){} 


} 
+0

¿cómo harías para crear un plugin jquery? – Smickie

+0

Creo que la creación de un widget o plugin definitivamente será una gran mejora sobre las funciones de rociado en todas partes, pero recuerde que un plugin/wrapper se trata principalmente de empaquetar esto en una sola unidad, y generalmente no tiene un sentido de modelo ya que es básicamente una envoltura alrededor del DOM. – Anurag

+0

@Anurag - Creo que, como con la mayoría de los elementos de programación, es necesario descomponer la aplicación en sus componentes más pequeños. Tener una serie de widgets haciendo ciertas cosas es probablemente mejor que tener un widget haciendo todo. – matpol

4

Matpol dio una solución literal a la información específica proporcionada. Su edición implica que está buscando una respuesta a una pregunta más hipotética. En otras palabras, estás buscando el "enfoque".

Respondiendo a la pregunta de esta manera; el único ejemplo que dio es un poco de arenque rojo. No es más que un elemento único en toda la aplicación, y nos impide "ver el bosque desde los árboles". Entonces, ¿qué es el bosque? La pregunta, hecha como tal, no la define. Pero creo que todos los programadores estarán de acuerdo cuando digo que es una pesadilla trabajar en un proyecto que no tiene definición. Entonces, volveré a formular su pregunta y respuesta, "¿Cuál es el proceso para definir un proyecto?"

mina es, de hecho, hacer una serie de preguntas:

  • ¿Cuál es el propósito central de esta aplicación?
  • ¿Cuándo lo quieres lanzar? Si tuviéramos que lanzarlo en 1/4 de esa vez, ¿qué características mantendría?
  • ¿Qué características tiene absolutamente la certeza de que va a necesitar después?

Una gran parte del tiempo, para llegar a la parte inferior de estas preguntas, necesito hacer otras preguntas de negocio:

  • Quién es su público?
  • ¿Por qué les importa este sitio? ¿Qué los hará volver?
  • ¿Cómo va a generar ingresos?
  • ¿Cuál es su llamado a la acción? Si pudieras canalizar a todos tus usuarios por una sola ruta, ¿cuál sería?

Afortunadamente, estas preguntas darán como resultado un conjunto de códigos fundamentales que puede considerar su núcleo. Su núcleo, como sospechaba, probablemente no se ajusta al enfoque modular. Y como ha identificado, querrá dividir ese núcleo en un diseño de Modelo/Vista/Controlador.

Pero es inevitable que necesite añadir pelusas de diseño. Y esto nos lleva de vuelta a su ejemplo de código: su pelusa. Fluff pertenece a un complemento, separado del núcleo. Esto no quiere decir que todos sus complementos se deben entregar al usuario en archivos js separados ...pero para su desarrollo, deben verse como modulares e independientes de la base del código central.

+0

Gracias por la respuesta. Usted cubre algunos puntos realmente buenos, pero hice la pregunta muy específica porque es muy difícil obtener buenas respuestas para preguntas muy amplias y abiertas. Dicho esto, escribí el código anterior específicamente para esta pregunta ignorando cualquier diseño o arquitectura. Las funciones y la lógica se escribieron con un tipo de enfoque de arreglo a medida que se vaya. Una solución horrible puede mejorarse de muchas maneras, pero lo mismo puede no aplicarse a una solución decente. Así que supongo que estoy buscando formas innovadoras de manejar solo el caso anterior y nada más. Espero que tenga sentido :) – Anurag

+0

Para el código específico proporcionado, creo que la respuesta de Matpol fue buena. Para un widget de contador de texto, creo que un plugin de jquery (si está usando jquery) es la solución perfecta. Pero me hicieron creer que había más cuando dijiste "... que va a ser problemático cuando tienes 20 de esos complementos en la aplicación, lo cual no es un número absurdo de ninguna manera." era la pregunta más sobre ¿cómo configurarlo con configuraciones? Si es así, ¿qué aspectos le gustaría tener configurable? Si es para un solo sitio que usted puede controlar, que puede ser una preocupación menor? – Matrym

+0

Un encapsulado componentes de interfaz de usuario, lo llaman un widget o un plugin de jQuery es de hecho el camino a seguir. en cuanto al segundo punto, la idea es hacer que estos widgets/plugins configurable a través de una configuración global. los widgets de mantener el control sobre los aspectos triviales de la plugin y los aspectos importantes están controlados por la aplicación o las configuraciones de todo el módulo. He reescrito el ejemplo original parcialmente usando MooTools (el marco es irrelevante), donde la configuración global se suministra al cuadro de comentarios. Con los eventos de aplicaciones personalizadas, las cosas pueden parecer mucho mejor del ejemplo original. – Anurag

1

El código actual es un buen comienzo y se puede "escalar" en grandes aplicaciones que evitan la codificación rígida y tienen una separación clara de MVC con solo unos pocos cambios.

  • Esto debería ser, idealmente, un widget o algún tipo de funcionalidad empaquetada

Un widget hará que la reutilización de funcionalidad comentario más fácil y proveer para su reutilización en diferentes páginas/aplicaciones. Extienda la encapsulación y separación de preocupaciones no solo a la presentación, sino también al modelo del widget. Cuando piensa en un campo de comentarios, es intuitivo pensar en el estado del componente como el texto de comentario, pero todos los parámetros que afectan su comportamiento pueden ser parte de su modelo, incluidos los parámetros de validación. Así, además del texto del comentario, me gustaría tener el modelo incluyen:

  • un mapeo de Recuento de caracteres de un tamaño-categoría (demasiado pequeño, pequeño, mediano, grande, desbordamiento).
  • el comentario máx presentar frecuencia (15 segundos)

El modelo Reproductor actualiza el tamaño-categoría que se cambia el texto. La vista escucha los cambios en la categoría de tamaño y el valor de categoría de tamaño utilizado para actualizar la clase de texto para producir estilo CSS para diferentes longitudes de comentario. La categoría de tamaño también se marca cuando se hace clic en "Agregar comentario". Si es "demasiado pequeño" o "desbordado", se puede mostrar una ventana emergente. Tenga en cuenta que el controlador Agregar comentario no verifica el recuento de caracteres, que está aislado en el modelo, sino que verifica la categoría de tamaño. Si es necesario, el controlador "Agregar comentario" podría usar la misma asignación de recuento de caracteres a la categoría de tamaño que utiliza el modelo para generar mensajes útiles para el usuario. P.ej. "Los comentarios deben tener al menos 15 caracteres", donde 15 se obtiene del mapa de categoría de tamaño.

El modelo también proporciona una propiedad de "número de caracteres restantes" cuyos eventos de cambio se utilizan para actualizar la interfaz de usuario del widget. El recuento máximo de caracteres se obtiene del personaje al mapa de categoría de tamaño.

  • Cosas como un comentario por cada 15 segundos, y un mínimo de 15 comentario carácter pertenecen a algunas políticas de amplia aplicación en lugar de ser incrustado dentro de cada widget.
  • Demasiados valores codificados.
  • Sin organización de código. Modelo, Vistas, Controladores están todos juntos. No es que MVC sea el único enfoque para organizar aplicaciones web ricas del lado del cliente, pero no hay ninguna en este ejemplo.

Puede haber muchos tipos de comentarios (por ejemplo, diferentes elementos que se comentaron) y diferentes tipos de comentario en widgets. Si todos deben tener el mismo rango mínimo/máximo, todos deben parametrizarse con los mismos valores de modelo que controlan la validación de comentarios. Esto se hace mejor desde el lado del servidor cuando se crean los datos para el modelo de comentarios. El texto de comentario se obtiene para ese comentario específico y los valores de validación de comentarios, como la asignación de categoría de tamaño, se obtienen de los valores predeterminados de configuración de la página o la aplicación. Al tener una lógica central para producir el modelo de validación de componentes, agregar nuevas reglas se vuelve mucho más simple, por ej. como "los moderadores pueden publicar comentarios hasta 1K", se convierte en un cambio en una parte del código.Otro punto para tener el lado del servidor computarizado del modelo de componentes es que el modelo también debe validarse en el lado del servidor: la validación del cliente es más una conveniencia para el usuario (inconveniente que algunos podrían pensar) y no una aplicación estricta. JavaScript puede ser deshabilitado y las solicitudes HTTP construidas independientemente del cliente de validación.

En resumen, gran parte de esto se puede ver como la organización de la producción del lado del servidor del modelo de widget. Al hacer este lado del servidor, el servidor puede aplicar reglas de validación y proteger el widget de la complejidad de las reglas y la configuración de toda la aplicación.

No he mencionado jQuery ni ninguna tecnología de UI, ya que este patrón es válido para aplicaciones independientemente de la tecnología UI. La forma de aplicar el patrón será, en cierta medida, específica de la UI, por ejemplo, cómo se proporciona el modelo de validación al widget o cómo conectar oyentes al modelo, pero el nivel organizativo del patrón es ortogonal a la UI. El enfoque principal está en el modelo, extendiéndolo para incluir aspectos de validación y computarlo desde el lado del servidor. Una vez que eso está en su lugar, el problema de la organización está prácticamente resuelto.

+0

Gracias por esta agradable respuesta. Va a ser una elección difícil :) – Anurag

Cuestiones relacionadas