Elegir la arquitectura correcta es una parte clave de la construcción de un servicio front-end. La desarrolladora Anna Karpelevich les dijo a los estudiantes
de la Escuela de Desarrollo de Interfaces qué es la arquitectura, qué funciones realiza y qué problemas resuelve. De la conferencia puede aprender sobre los enfoques arquitectónicos más populares en el front-end: Model-View- * y Flux.
- Buenas tardes. Me llamo Anya Karpelevich. Hoy hablaremos sobre la arquitectura del front-end de nivel superior.
Yo trabajo en Yandex.Direct. Hacemos interfaces para anunciantes. Publican anuncios, los personalizan. Este es un sistema muy complejo e interesante, tiene muchos componentes interconectados, crecen entre sí, tienen una funcionalidad común y propia. "Los pantalones se convierten en pantalones cortos elegantes". Todo esto tiene que ser controlado con mucho cuidado. Y la arquitectura en nuestras aplicaciones es muy compleja. Esta es una de las razones por las que hoy doy esta conferencia. Realmente amo este tema.
¿Qué es la arquitectura? El hecho es que probablemente no hay respuesta a esta pregunta. O lo hay, pero cada uno tiene el suyo. Este es un tema muy controvertido. Causa mucha controversia, muchos holivars. Y mucho de lo que hablaré hoy es mi opinión. En parte cuenta con el apoyo de mi grupo de trabajo, en parte no mucho. Y todos, cuando escribe la arquitectura de su aplicación, deciden por sí mismos cómo y qué hacer.
Es por eso que la arquitectura es uno de los lugares más creativos en el trabajo de un programador. Y por lo tanto, nuestra presentación de hoy también comenzará con creatividad.

Miremos la imagen de la izquierda. Estaré muy contento si alguien reconoce el edificio que se muestra en él. Esta es la iglesia de Saint-Sulpice en París. Presta atención a las torretas, por el bien de esta iglesia fue puesta aquí. Espero que sean diferentes. Son bastante diferentes, y hay una razón interesante para esto. Entre ellos 130 años de diferencia. Luego, la torre izquierda fue demolida y reconstruida durante la guerra franco-prusiana.
¿Por qué está ella aquí? Mira esta foto. Las torres tienen la misma arquitectura, y todo el entorno, estas viñetas, accesorios, estructuras arqueadas son diferentes. Por qué Porque el propósito de estas torres es el mismo. Ninguno de ellos, por ejemplo, era un campanario. Estas son solo torres. Algo estaba almacenado en ellos, y todo lo demás era diferente. Por qué Porque la arquitectura de estas torres es la misma. Ambos tienen una bóveda, solo una ventana, y es lanceta. Las ventanas tienen aproximadamente la misma altura. Y la idea es que la arquitectura, tanto los edificios como las aplicaciones, es una estructura de soporte. Esto no es una viñeta, ni un parpadeo, ni una implementación. Esto es lo que está en el núcleo. Y esta base, como regla, depende del medio ambiente, del suelo, cuando se trata del edificio, del objetivo que el arquitecto se establece, pero casi nunca depende de los refinamientos del diseño.
El ejemplo de construcción para el tema de la arquitectura es bastante obvio. Pero la imagen correcta es más interesante. "La arquitectura es música insensible". "Architektur ist gefrorene Musik", dijo Johann Wolfgang Goethe en el siglo XVIII. Goethe probablemente no sabía nada sobre la arquitectura de los edificios, era un poeta. Y tenía la garantía de no saber nada sobre la arquitectura de aplicaciones. Pero expresó una idea muy valiosa e interesante.
La música existe en la dinámica. Esto no es algo estático. Este es un proceso. Y así, una aplicación es un proceso. Tiene un momento de lanzamiento, tiene un momento de desarrollo, cuando hacemos algo con él, trabajamos. Y finalmente tiene un momento de finalización. La arquitectura de la aplicación es su sector en cualquier momento dado. En cualquier momento, nuestra aplicación, como tema musical, debe ser clara, concisa, comprensible, predecible, etc. De lo contrario, todo se vendrá abajo.
Con esta introducción creativa, finalizamos, pasamos a cosas más mundanas, más cercanas a la práctica de crear aplicaciones.
¿Qué es la arquitectura y por qué es necesaria?

En primer lugar, tenemos la organización de una gran cantidad de códigos, algo que nosotros en Direct, y no solo en Direct, encontramos todo el tiempo. Hay tanto código que puede perderse en él. No queremos perdernos en el código.
En segundo lugar, la duplicación de la funcionalidad. Este también es un problema eterno con el que siempre se encontrará, y hoy este tema de la duplicación irá directamente a través de la línea roja durante toda la conferencia. La misma funcionalidad que podemos necesitar en varios lugares de la interfaz. Si se necesita en varios lugares, entonces debe ser físicamente el mismo código que se usa en varios lugares, no una copia. Por qué Hablaremos más sobre esto. Pero la arquitectura debería ayudarnos a evitar copiar y pegar.
El tercero es el apoyo. Es bastante obvio que si tenemos una aplicación, entonces debemos apoyarla de alguna manera, y es aconsejable que no se desperdicien todos los recursos del equipo en esto.
Cambiar la composición del equipo. También es algo que nos encontramos en la vida real con más frecuencia de lo que nos gustaría. Alguien viene, alguien se va, y si una persona pasa seis meses para ingresar el código, esto es malo. Si el conocimiento del código se almacena en una sola cabeza, y transmitirá este conocimiento durante seis meses en caso de abandono, esto es aún peor. En general, aquí la arquitectura también nos ayuda a hacer que todo esto sea más comprensible y a mantener el intercambio de conocimientos.
Añadiendo y ampliando funcionalidad. También algo bastante obvio. El gerente viene corriendo hacia nosotros y dice que esto se necesita con urgencia. Y si para hacer esto con urgencia, tiene que gastar mucho tiempo y esfuerzo, entonces esta es una mala solución arquitectónica. Y necesitamos lo bueno.
Y finalmente, errores. Cuanto más comprensible y predecible sea nuestra arquitectura, más fácil será buscar errores, menos errores.
¿Cómo se puede llamar todo esto? Todo esto se puede llamar: los problemas de un sistema complejo. Una aplicación es un sistema complejo; la arquitectura nos ayuda a resolver un problema.

En resumen, de alguna manera. Aquí hay una imagen de fideos a mi derecha, y esto es lo que sucede si no sigues la arquitectura, si no la construyes, piénsalo y diséñalo. Y la segunda imagen es lo que sucede si la arquitectura al menos se piensa de alguna manera. Este no es Saint-Sulpice, pero al menos un diseñador infantil, se mantiene firme y no se desmorona. Hoy jugaremos mucho constructor también.

Formalmente sobre todo esto. La arquitectura es una forma de resolver los problemas de un sistema complejo mediante la abstracción de la implementación desde la interfaz y la diferenciación de poderes entre bloques de código. Además, analizaremos esta larga frase en detalle.
¿Cuáles son las características de la arquitectura de aplicaciones como campo de conocimiento? Ella tiene un área específica con la que trabajamos. Es decir, no es algo abstracto, es algo muy específico. Aquí está la tarea, seleccionamos la arquitectura para ello, y no de modo que, oooh, un enfoque arquitectónico interesante, debemos intentarlo. Entonces no. Puede probar algo pequeño, pero para un proyecto serio, se selecciona la arquitectura, a veces compuesta para un proyecto específico.
La historia del problema, cuando, en general, surgió esta idea de que la arquitectura debería hacerse. Esto, debo decir, en un momento una idea muy extraordinaria fue expresada en 1968 por Edsger Dijkstra, un programador maravilloso. Probablemente sea mejor conocido como el autor del algoritmo Dijkstra, la búsqueda del camino más corto en un gráfico. Pero él tiene muchas, de hecho, ideas innovadoras para su tiempo. Y uno de ellos es un artículo, luego te daré una referencia a los materiales, puedes leer, solo hay dos páginas, un ensayo corto. Suena como "Operador GOTO considerado dañino", en la traducción "Operador GOTO - operador de transición incondicional - malvado". Fue el primer pensamiento que digamos oficialmente que necesitamos escribir arquitectura, no fideos.
En los años 70, esta idea ya fue desarrollada por Dijkstra en colaboración con Parnassus, y por su cuenta, individualmente. El primer libro detallado sobre arquitectura de aplicaciones en general fue escrito en 1996 por Mary Shaw y David Garlan. Después de eso, de hecho, tales libros detallados sobre arquitectura de software no fueron escritos precisamente por el alcance, que cada campo de conocimiento tiene sus propios enfoques arquitectónicos, en algún lugar, en otro lugar más popular, algo, en general No aplicable en algunos lugares. Y dado que la arquitectura es un proceso creativo, no encontrará libros específicos sobre cómo escribir arquitectura. Quizás después de 1996 no hubo nada particularmente detallado sobre este tema.
¿Cuáles son los requisitos para la arquitectura del proyecto ahora? En primer lugar, y lo más importante, lo que se requiere de él, de hecho, es la extensibilidad, porque si su proyecto no se expande, está muerto.
Reutilizando el código. Esto se trata de copiar y pegar. Si tiene dos bloques que se usan en dos lugares diferentes, necesita la misma funcionalidad, entonces debe reutilizar el mismo código, y la arquitectura debe ser tal que cualquier parte del código pueda tomarse y reutilizarse tan pronto como sea necesario .
Separación de autoridad entre módulos de código. Hablaremos de esto hoy con más detalle, por qué es necesario. La idea es esta: cada módulo, cada bloque, cada pieza de código debe realizar una acción específica, llevar exactamente una función. Y esta función debe colocarse en el título de este método, clase, lo que sea, módulo. Un módulo, una función.
Y finalmente, la calidad de las aplicaciones. Hay muchas cosas que me gustaría hacer, tanto confiabilidad como compatibilidad con versiones anteriores. En realidad, nuevamente, se selecciona para la tarea. En algún lugar se necesita compatibilidad con versiones anteriores para que en ningún caso se mueva nada. Se necesita confiabilidad en algún lugar para que, Dios no lo quiera, las contraseñas, códigos PIN de tarjetas o CVV no se filtren en ningún lado. En algún lugar necesita que no tenga problemas si es un satélite u otra cosa. En general, elija algunos. Cuanto más desee admitir, más complejidad encontrará en la arquitectura.
Además, hablaremos con usted sobre algunas definiciones, tales cosas enciclopédicas. ¿Por qué es esto importante? Porque la terminología en arquitectura es muy importante, y necesitamos hablar el mismo idioma con usted. Las definiciones en su mayor parte están tomadas del paradigma de programación llamado OOP. Pero, de hecho, han brotado en otros paradigmas, con los términos "clase, objeto, interfaz" que operan no solo dentro del marco de la POO. Sin embargo, estas definiciones y comprensión se toman precisamente del mundo de OOP.

Lo más simple es la clase. ¿Qué es una clase? Esta es una plantilla, esta es una muestra. Por ejemplo, la clase Snake es la clase Snake. Definimos tres campos privados con ella, es decir, un campo que no es accesible para nadie, excepto los métodos de la clase en sí: el número de goles, el número de colas y la longitud de los loros. Determinamos el constructor en el que colocamos estas mismas cabezas, colas y longitud en loros. Tengo la clase Serpiente. Todo es simple

Vamos más lejos Objeto. Y un objeto es una instancia de una estructura específica. Además, nuevamente en la OOP clásica se implica que un objeto es un objeto de una clase. En el mundo moderno, en JavaScript, que no siempre fue un lenguaje OOP, e incluso ahora no es siempre y en todas partes OOP, sabemos que puede haber objetos abstractos. Es decir, podemos crear un objeto, un literal, que no será un objeto de la clase. Pero aquí hay un ejemplo de cómo creamos un objeto de la clase Snake. Aquí tenemos una serpiente de dos colas con una longitud de 38 loros, una boa constrictora.

Modulo Un módulo es una unidad semántica. Esto no siempre es una clase. Puede ser un conjunto de clases, un conjunto de objetos, un conjunto de métodos que no se combinan en clases. Por lo general, puede suponer que un módulo es lo que escribió en un solo archivo. Pero, en principio, el módulo es la carpeta en la que se encuentran, por ejemplo, el archivo y las pruebas para este módulo también son un módulo. Lo importante aquí es que un módulo es lo que usted llama un módulo, lo que considera una unidad de semántica. En este caso, el módulo trata sobre cómo comemos serpientes. El resultado de este módulo es el último método, eatSnake, ya que comimos serpientes. No sé por qué comemos serpientes, pero podemos hacerlo, porque escribimos este módulo así.

Fue trivial, entonces comenzará algo un poco más interesante. Interfaz de clase. La interfaz de una clase es, más simplemente, sus métodos públicos, a qué se destaca, lo que podemos obtener de un objeto de esta clase de un objeto del exterior. Esta clase implementa la interfaz getSnakeLength. Puede devolvernos la longitud de la serpiente. Tenga en cuenta que no hay acceso externo a campos privados. El acceso desde el exterior es solo al método público getSnakeLength.

Y luego una cosa muy interesante. Discutimos durante mucho tiempo cómo llamar a esto, porque acuñé el término "interfaz abstracta" cuando creé esta conferencia. Y honestamente, nunca he visto una definición normal de este enfoque y método. Sin embargo, muchos lenguajes de programación le permiten crear interfaces abstractas y llamarlas, tan pronto como no sean clases abstractas, y también interfaces abstractas, solo interfaces. Resulta un homónimo con la interfaz de clase. La idea es que una interfaz abstracta es un conjunto de métodos que hacen algo. Cuando creamos una clase, pasamos de la pregunta "¿qué es esto?" Esta es una serpiente y ella sabe cómo hacer algo, o no. Ella solo puede dar su longitud.
Y cuando creamos la interfaz, pasamos de lo que él hace, lo que debería poder hacer. Y esto demuestra ser una forma muy poderosa de extender las clases. Podemos atribuir clases a algunas clases, expandiéndolas con la ayuda de interfaces. Por ejemplo, el marco I-BEM puede hacer tal cosa, tal historia con interfaces abstractas está integrada en el marco. Desafortunadamente, muchos marcos no saben cómo, y la cosa es poderosa.
Aquí, como ejemplo, creamos la interfaz audible, algo que puede sonar. Y su definición es el método getNoise vacío abstracto. Expandimos nuestra serpiente con la clase audible, implementamos su método getNoise y nuestra serpiente silbó. La inspiración para este conjunto de ejemplos me fue dada por el maravilloso libro de Eric Freeman y Design Patterns.
Ahora intentaremos ver estos ejemplos un poco más específicamente.

Pero primero, hablemos de por qué se necesitaban estos ejemplos. Y fueron necesarios aquí para esta gran diapositiva. Lo que está escrito aquí es tan importante que incluso lo puse en el bloque de título amarillo. Se puede decir un mantra. Este es un principio muy importante que debe tener siempre en cuenta al diseñar la arquitectura. Alta cohesión, bajo acoplamiento: adhesión fuerte, conectividad débil. Hay un cierto problema con el hecho de que la palabra cohesión y la palabra acoplamiento se traducen al ruso, y así sucesivamente, se traduce “conectividad”, la palabra acoplamiento se inventó especialmente para este principio.
Esta es la idea Sus bloques deben ser muy compactos, muy bien acoplados. Deben implementar exactamente una función. Y entre ellos, deben conectarse muy fácilmente para que puedan combinarse, ensamblarse fácilmente, como un diseñador. Y luego su arquitectura será lo suficientemente flexible y confiable. Y también fácil de probar.
Veamos cómo podemos lograr una tracción fuerte y un acoplamiento débil en los puntos de lo que se llama.

Especialización Cada bloque resuelve solo un problema. Aquí tenemos una buena ilustración: un diseñador infantil. Tenemos cada bloque, o un conjunto de bloques. Todos tienen su forma, su tamaño. Y si necesitamos construir una casa, tomaremos barras largas. Si necesitamos construir una pelota, tomaremos barras cortas. Cada barra tiene su propia función. Y aquellos que interpretaron a los constructores saben: cuanto más simple es la forma de las piezas, más se puede construir a partir de ellas. Nada se construirá con tal zagogulina, o solo se construye lo que se describe en las instrucciones. ¿Y quién lo necesita?
Lo mismo, abstracción. Se trata de la abstracción de la interfaz de la implementación. La idea es que la interfaz es externa, cómo es nuestra clase, nuestro bloque sobresale, cómo interactúa con otros bloques no debería afectar su implementación interna. Por el contrario, sucede. A la inversa, nunca. En una buena arquitectura. Aquí, como ejemplo, la formación de estos granos no afecta la forma del bloque en sí. Seleccionamos por separado la forma del bloque y ya pegamos pegamentos.

Encapsulación Continuación del tema anterior. En métodos privados, es decir, desde dentro de nuestros bloques, nos damos cuenta del significado mismo de nuestro bloque, la implementación. Y la interfaz, la forma en que están conectados, es pública. Es decir, en este caso, todas estas cruces, guiones y la forma en sí son implementación. Y las espinillas son la interfaz. Y la buena arquitectura se parece a tal constructor.

Oh, qué monstruo aterrador. Esto se trata de reutilizar el código. Inicialmente, este monstruo, de hecho, debía mostrar un ejemplo de arquitectura pobre, pero míralo con cuidado. El es hermoso. Además, está claramente satisfecho con su vida, corre bastante vigorosamente sobre sus extrañas piernas. Tal vez incluso sabe volar, o, al menos, tiene hermosas alas de mariposa.
Cual es la idea Si tiene una implementación para un camello y una implementación para un cocodrilo, y un gerente se le acerca y le dice que se necesita con urgencia un cocodrilo. No escribes por separado un cocodrilo camello. Tomas el cuerpo de un camello, lo separas de toda la realización del camello. Toma la cabeza del cocodrilo, sepárala del cocodrilo y reutiliza los bloques. ¿Por qué es esto necesario?
Luego, cuando el gerente viene a usted nuevamente y le dice que nos estamos expandiendo urgentemente a Sudamérica, y que hay caimanes, necesitamos mantener una forma irregular de la mandíbula, o que allí, el cuarto diente del cocodrilo no es así, no se perderá todo el proyecto. , ¿dónde has copiado las cabezas de los cocodrilos? Porque podrías tener algún otro cocodrilo cebra-bisonte cerca. Simplemente tomas a tu clase la cabeza de un cocodrilo, haces una extensión de la serie de la cabeza del cocodrilo, le das los parámetros, determinará por sí mismo qué dientes dibujar para él. Y eso es todo. En un lugar, y no en todos los lugares donde se usa.
Aquí, la fiabilidad aumenta a veces, porque se garantiza que olvidará algunos cabezales copiados en algún proyecto muy raro. En general, no hay nada de malo en tales cadáveres. Buen cadavre, útil.

- . , . TypeScript, . , . , , , TypeScript 2.7 , ( — . .).
, User. . Todo esta bien. User , . User , , .
printLabel. User. , User User, . User User , , . - , .
, ? , . , . , − , UserWithSurname, , printLabel. ? , , , , . - ? , . , − , . . PrintLabel . ? ? , .
, . , . , , . , if, , . , , .

printLabel, , iPrintLabel , iPhone, . - getText. User, iPrintLabel. , , , - , getText iPrintLabel, , . UserWithSurname, User, Surname getText. printLabel . iPrintLabel getText.
, , , . . , , . , , , , , iPrintLabel, , , , − . printLabel . , .
. , , , front-end, , . , front-end , , .

-? . - back-end. - API, , REST API REST. — , − -. , , - PowerPoint, . .
front-end. Front-end - . - , . , - . . . , -, . , , . .
front-end, , , , , , , .
> - ( Client-server )
> ( Component-based )
> ( Event-driven )
> REST ( Representational state transfer )
> --*( MVC , MVP , MVVM )
> ( Flux )
Estos son los enfoques arquitectónicos. Algunos de ellos los mencionamos hoy. Arquitectura del servidor del cliente; arquitectura de componentes, una de sus variaciones es familiar para usted de React, con suerte familiar. Evento que, curiosamente, también es familiar para todos, se basa en casi todos los sistemas operativos para computadoras personales. REST, lo que amamos en el servidor, y los dos últimos, que conoceremos en detalle hoy, son los más avanzados, con lo que trabajamos es un modelo de presentación * y flujos de datos unidireccionales.
Comencemos con MV *. ¿Por qué un asterisco? Historia, como dicen, llena de dolor y rabia. Érase una vez, en los años 80, se inventó el maravilloso enfoque arquitectónico de MVC. M - Modelo, V - Vista, C - Controlador. El enfoque fue muy conveniente. Inventado generalmente para aplicaciones de consola. Pero cuando las tecnologías web comenzaron a desarrollarse, cuando todos comenzaron a usarlo, resultó que a veces era necesario, aquí el modelo MV es bueno, pero el Controlador no está implementado de manera correcta. Como resultado, hubo muchas variaciones diferentes de la implementación de Model-View, algo que al principio se confundió debido al hecho de que todo se llamaba MVC. Porque, si hay un modelo MV, entonces el tercero es Controlador, no importa lo que hayamos rellenado allí.
Luego resultó que las personas se confunden y quieren decir cosas completamente diferentes por MVC. Aproximadamente ahora, no hace más de un año, comenzaron a compartir activamente esta terminología y a crear sus propios nombres para cada implementación de este enfoque. De una forma u otra, apareció este MV *. También vi el término MVW en Internet, donde W es lo que sea. Bueno, nos estamos moviendo, de hecho, a las tecnologías MVC.

¿Cómo se arreglan? La idea es que tenemos un modelo que almacena datos. Usualmente hay muchos de ellos. Hay algún tipo de Vista que muestra estos datos al usuario. Ellos, como regla, también son muchos. Y un tercer componente, que es un intermediario entre ellos, conecta los datos y la pantalla. Aquí el usuario en la esquina superior derecha trabaja con todo esto.

MVC, la forma en que todo comenzó fue en 1980, Smalltalk. Pero es de esta forma que existe en algunos marcos hasta ahora. No en algunos, sino en muchos. Cual es la idea El usuario trabaja directamente con la vista y el controlador. Ingresa datos en algunos campos de la vista, presiona el botón Enviar y los datos van al controlador. Este es un formulario de envío. Espero que se envíe un formulario tan honesto mediante el botón Enviar, familiar para todos durante mucho tiempo.
Nosotros miramos. La flecha amarilla del usuario al controlador: este es el usuario que transfirió datos al controlador mediante el botón Enviar. Una flecha verde, - el control pasó allí. El controlador mira estos datos. Tal vez los procese de alguna manera, las sutilezas de implementación ya están aquí y las envíe al modelo deseado. El controlador mismo elige qué modelo enviar. Envía una flecha verde, envía datos con una flecha amarilla.
El modelo también procesa datos. Quizás ella los valida. Quizás los ponga en la base. En resumen, el modelo sabe qué hacer con ellos. Como regla, el resultado son datos nuevos. Por ejemplo, podemos decirle al usuario si inició sesión o no, y el modelo verificó la contraseña con el inicio de sesión. Después de eso, el modelo transfiere el control al controlador nuevamente, para que el controlador seleccione qué vista mostrar. Y los datos van directamente a la Vista. ¿Cómo se puede hacer esto, en general, cómo puede un modelo enviar datos a una vista?

Muy simple Si el controlador y el modelo están en el back-end, y la Vista de plantillas es del lado del servidor. Así es como se organizan los marcos para Ruby on Rails, ASP.NET, Django, en general, donde sea que escriba plantillas del lado del servidor, y el HTML recopilado llega al cliente, y los datos también regresan, con una alta probabilidad, este es este enfoque. ¿Cuáles son los problemas aquí? En una aplicación de una sola página, tal cosa no se puede construir. Constantemente tenemos datos en el servidor, en el servidor, la página se recarga. En segundo lugar, no está completamente claro dónde empujar la validación del cliente y, en general, JavaScript del cliente, AJAX y todo esto aquí. Porque si queremos algo rápido, en ninguna parte. Simplemente no funciona en este enfoque, o funciona para que no funcione mejor.
La última línea aquí, esta es una historia tan interesante, enraizada, al parecer, en 2008. La pregunta era: ¿dónde almacenar la lógica empresarial: en el modelo o en el controlador? Hubo quienes dijeron: "Almacenamos la lógica de negocios en el controlador, porque es conveniente, de inmediato se envían datos limpios al modelo. El controlador se validará a sí mismo, volverá a verificar, si corresponde, y enviará un error ". Hubo quienes dijeron que "el resultado son controladores feos, estúpidos y gordos, controladores feos, tontos y gruesos". Realmente resultaron enormes. Y dijeron que la lógica de negocios debería estar en el modelo, y el controlador debería ser delgado, ligero, transferir los datos, el modelo en sí mismo procesado. Y luego, en la primera versión, el modelo, en general, resulta ser solo una API para la base de datos.
¿Cómo, en mi opinión, realmente? De hecho, debes vigilar sus tareas. Si tiene una conexión entre una vista y un modelo que siempre es uno a uno, una Vista es un modelo, entonces le conviene hacer lógica de negocios en los controladores y crear un modelo simple y limpio, que, de hecho, será una API para la base de datos. Si sus vistas y modelos pueden superponerse, y una vista depende de muchos modelos, el modelo funciona con muchas vistas, es conveniente que tenga muchos controladores delgados y los multiplique en cualquier progresión, no le importa cuántos sean, todavía son pequeños.
Debo decir que el mundo parece haber ganado el segundo punto de vista, con lógica de negocios en los modelos. Es decir, estos controladores feos, estúpidos y gordos parecen no usarse tan activamente. Señales, puede ver lo que en la documentación de ASP.NET, el marco de trabajo en 2013, propuso la lógica empresarial en los controladores. Y en las últimas versiones en 2014, en los modelos. Hubo un momento muy interesante cuando esto cambió.
Que MVC tiene problemas. Ya los hemos hablado, pero lo haremos. Es posible probar, ya que no está claro cómo implementar la validación del cliente, pero es difícil, AJAX está atornillado a un lado, debe hacer algo. Se les ocurrió una solución. La solución se llamó MVP y, sí, puede cumplir con MVP en el marco con el texto de que son MVC. Por ejemplo, Backbone MVP framework. Sobre él durante mucho tiempo en la documentación en el mismo 2011-2012-2013 se escribió que este es un marco MVC.

Modelo-Vista-Presentador. Su esquema ya es mucho más simple. Hay modelos. Ellos interactúan entre ellos. Le dan datos al presentador, el presentador lo transfiere a la vista y se lo muestra al usuario. Y de regreso. El usuario introduce algo en la vista, hace clic en el botón, el Presentador mira, AJAX envía al modelo o lo coloca en el modelo, y el modelo AJAX envía al servidor. Es decir, todo ya es mucho más simple y lineal, pero sin la estandarización del lado del servidor ya habrá dificultades. Si desea un servidor, dicho sistema será complicado.

Vamos a comparar Veamos la primera imagen, donde intentaremos implementar algo muy simple: enviar datos desde la entrada al modelo. Ingresamos algo, hicimos clic en un botón, debería aparecer en el modelo, el modelo hará algo con esto y nos dirá que algo sucedió. Entramos: "mi nombre es Vasya", hicimos clic en Aceptar. Si queremos la validación del lado del cliente, entonces sucede aquí, casi por intercepción, en casos especialmente severos, de hecho, al interceptar un clic a través de event.preventDefault (). Y en algún lugar, un punto cero en el lado atornillado validación del cliente.
Luego, honestamente enviamos datos a través del formulario de envío al controlador. Los datos van al modelo, el modelo lo pone en sí mismo, procesa, mira. Nos dice que, bueno, los datos son aceptados, realmente eres Vasya. La tercera flecha: el control va al controlador, el modelo le dice al controlador que, por favor, muestre la etiqueta "Mi nombre es Vasya". El controlador selecciona la vista apropiada, muestra la etiqueta. Y los datos "mi nombre es Vasya", la cuarta flecha, amarilla, el modelo pone allí. La pregunta es cómo probar esto? Solo una instantánea. No hay otra manera No hay nada sobre lo que escribir ni siquiera pruebas funcionales.
La segunda opción, ya con MVP. Manejamos "mi nombre es Vasya", hicimos clic en Aceptar. Flecha debajo del número uno, verde, - la gerencia fue a Presentador. El presentador dijo: se presiona el botón. El presentador mira, flecha número dos, azul, tenga en cuenta que esta es una solicitud de datos. En el MVP clásico, no se envían datos desde la vista a Presenter, sino una solicitud de datos de Presenter. Esto es mucho más claro, porque Presenter ya puede saber de antemano, por ejemplo, que no necesita datos, de todos modos, todo está mal.
A continuación, el tercer párrafo sobre Presentador es la validación honesta de JS. Ya podemos escribirlo con seguridad, este es un lugar especial para ello. La cuarta flecha: los datos van al modelo, por ejemplo, ponerlo en la base de datos, dijo: "Todo está en orden, lo puse". La quinta flecha, como ve, está rayada, espero que quede claro que está rayada de color amarillo verdoso, y la administración y los datos volvieron a Presentador. El modelo decía "lo puse", Presenter se dio cuenta de que, dado que los datos se pusieron en la base de datos, significa que es necesario mostrar que todo está en orden, los datos se ponen. Y la sexta flecha: la enviaron a la vista, tal vez a otra, pero luego no dibujé la segunda vista.
¿Cuál es la ventaja aquí? La validación de JS cayó en el lugar que le correspondía y todo salió bien, AJAX también cayó en su lugar, puede ser la cuarta flecha, por ejemplo, si el modelo está en el servidor, o el modelo AJAX mismo va al servidor. Y finalmente, podemos probar Presenter de forma segura, escribir pruebas funcionales en él.

En segundo lugar, ¿qué más tenemos en positivo, además de las pruebas simplificadas? Conseguimos una separación de la visualización y su trabajo. Es decir, aún podemos escribir instantáneas en View, y podemos escribir pruebas en Presenter por separado. Podemos arreglar el presentador y no tocar la vista, y viceversa. Nuestra especialización ha mejorado. Así es como se organizan marcos como Angular1, Backbone, Ember, Knockout de versiones anteriores. Una vez que había muchos de ellos, solo una feroz competencia.
¿Cuáles son las características? El presentador ya está colocado en el cliente, el modelo puede estar allí y las aplicaciones de una sola página se realizan en silencio. Sucede mejor, pero hay muchas aplicaciones de una sola página en esta historia, o al menos se ha hecho antes. La interacción del servidor AJAX es buena. Validación del cliente en su lugar. Parece que todo está bien, ¿por qué pensar más?
Sin embargo, al menos MVVM fue inventado. También una cosa interesante.

En esencia, esta es una implementación de Presenter usando el marco. A menudo resultó que cuando escribiste el primer presentador, el segundo presentador, el quinto presentador, todos son iguales. Y solo tejen una vista y modelo. Como puede ver, está construido como MVP.

Y muchos marcos simplemente resolvieron estas tareas vinculantes. Cuales son las ventajas? No necesitamos escribir código extra. Y realmente acelera la velocidad de desarrollo. ¿Cuáles son las desventajas? La conectividad entre Model y ViewModel se ha mejorado.
Es decir, los problemas surgen allí precisamente debido a la fuerte conexión, por lo que a veces sucede que no se usa MVVM. Por ejemplo, estoy personalmente familiarizado con MVVM en el marco de trabajo de i-BEM, que a veces usamos, y otras no, porque es un enlace incómodo y demasiado estricto. Sin embargo, sí, Microsoft Silverlight está organizado por esta tecnología, y dicen: bueno. No lo sé, no lo he probado.
¿Por qué sucedió que además de MVP y MVVM, surgió algo más, todos ustedes familiarizados con la palabra redux, por qué había flujos de datos unidireccionales?

Nos fijamos en la imagen correcta. Nosotros con MVP regularmente tenemos ese problema. Supongamos que tenemos un sistema complejo, no uno a uno: muchas vistas, muchos modelos. Todos están interconectados. La vista desde arriba, amarilla, cambió el modelo. El modelo ha cambiado otro modelo. La vista amarilla inferior ha cambiado. La vista inferior también cambió el modelo. Todos juntos cambiaron la vista roja central, y algo incomprensible está sucediendo en ella.
Facebook se enfrentó a esto cuando constantemente recibía un error debido a mensajes emergentes no leídos. Es decir, el usuario ve "Tiene un mensaje no leído", se abre, pero no es así. Debido a que las dos vistas juntas corrigieron el estado de esta ... En general, el estado de la vista se corrigió desde dos fuentes diferentes, y quién tiene la razón no está claro. Lo gobernaron, surgió un error nuevamente, gobernaron nuevamente, surgió un error nuevamente. Al final, estaban cansados y decidieron resolver el problema radicalmente, disculpen la tautología y simplemente hicieron que la vista fuera determinista.
El problema de MVP está precisamente en el no determinismo del estado del sistema. No siempre podemos predecir en qué estado se encuentra ahora, y quién vino primero, quién corrigió qué. Flux resolvió este problema, como dicen, genéticamente. No puede tener eso. Me dijeron aquí durante mucho tiempo que la idea con un flujo de datos unidireccional estaba en el aire, es cierto. Y este concepto fue inventado, por supuesto, mucho antes de Facebook, mucho antes de 2013, cuando lo publicaron. Pero ellos, como dicen, han patentado, primero lanzaron una mierda, que se nos ocurrió tal cosa, úsela.

Veamos Flux con más detalle. Aquí está la idea. Tenemos una tienda, y esta tienda es un almacén de datos, esta es la única fuente de verdad para nuestra aplicación. Todo lo demás es falso. Como trabaja el Al principio, si observamos específicamente el ciclo de trabajo, generalmente comienza con el usuario haciendo algo, es decir, la vista está funcionando. La vista crea una acción. Tenga en cuenta que la acción no se completa en la imagen. Por qué Porque es una estructura. Esto no es una clase, no es un objeto, no es algo inteligente. Esta es la estructura. En la web, en JavaScript podemos escribirlo, es solo ese objeto muy abstracto.
La vista crea una estructura, pasa al administrador de bloques. El administrador de bloques activa una devolución de llamada. Es decir, dice: “Llama a la función que me dijeron que llamara cuando ocurre la Acción. Dijo que llamara a la tienda ". Es decir, se llama al método Store desde el despachador. El método se llama. El método se llama, se obtiene en la Tienda. La tienda mira lo que ha llegado, de alguna manera cambia. Él está cambiando su condición. Y él es el único que puede cambiar su condición. Nadie más hace esto. Es decir, él es la única fuente de verdad. Después de eso, transmite a todas las vistas vinculadas a él, todos los componentes vinculados a él: "He cambiado, ve a buscar los datos".
Las vistas van por datos, y luego comienza un momento interesante. En Flux clásico, como en Facebook, la vista se vuelve a dibujar por completo.

Aquí está nuestro formulario con una etiqueta y un botón. Como trabaja ella? Nos fijamos en el punto cero. El punto cero también está aquí. Él es la flecha azul en la parte inferior, registro de devolución de llamada. Esto es lo que pasa primero.
El gerente de la tienda llama: "Por favor, registre mi devolución de llamada, ¿qué haré cuando llegue la Acción?" Sucedió Entonces podemos trabajar con la aplicación. Hicimos clic en un botón, creamos una estructura. Tenga en cuenta que, además de los datos ingresados por el usuario, por ejemplo, Vasya, Action también tiene metadatos, tipo. Un punto muy importante es que la Acción misma transmite qué tipo de Acción es, pero de todos modos al despachador. Lanza toda la transmisión de acción. Primera flecha, se llama al método.
El despachador llama al método, de hecho, un desencadenador de acción y pasa esta acción allí. En el activador de acción, se llama una devolución de llamada, que registramos en el punto cero. Aquí está la flecha roja, esta es una llamada de devolución de llamada de una devolución de llamada. Store toma estos datos, parece que, sí, escriba change name, luego me cambio en el campo de nombre a Vasya, y lo envío al back-end, y de alguna manera valida, probablemente, en general, Store sabe qué hacer . A continuación, la flecha morada marca el evento de cambio. Hemos cambiado Todos saben que hemos cambiado la tienda.
A continuación, una pequeña característica del clásico Flux, que puede no ser familiar para aquellos que trabajaron con Redux, más precisamente, incluso con React, y no con Redux. Las vistas van para los datos. Van a la Tienda y dicen: "Tengo este campo, este campo y este campo". Estamos acostumbrados al hecho de que, por el contrario, todo viene a la vista si trabajaste con React, Redux o algo así. Y el sexto punto, un redibujo completo.
Miremos este diagrama y encontremos un cuello de botella, ¿por qué? Redibujando Un redibujo completo, razón por la cual Flux comenzó a usarse activamente después de 2013, ¿cuándo surgió? ¿Qué hizo esto posible? Casa virtual. Una casa virtual que le permite volver a dibujar solo cuando realmente es necesario.

Hagámonos a un lado y hablemos de React, que así, combinado con mucho éxito con Flux, hizo que el mundo que conocemos ahora cuando esta tecnología sea más popular.
El mismo 2013, el mismo 2013, el mismo Facebook. Inicialmente, React se inventó en general, como un aviso de vistas en MVC, MVP, variaciones. Y, de hecho, puede usarse allí. ¿Cuál es su poder? En primer lugar, la casa virtual, como decían correctamente, permite no volver a dibujar la casa real, porque es una operación muy difícil, sino volver a dibujar la virtual. Y solo si, de hecho, hubo un cambio, redibujamos el componente, como resultado de lo cual todo funciona mucho más rápido de lo que podría ser.
Y - componentes puros inmutables. Este es el mecanismo de propiedades. La implementación también es reactiva, lo que le permite crear componentes que no tienen su propio estado. Y si escribe en esta arquitectura, es muy correcto crear componentes limpios, sin estado, sin estado. Solo tienen datos que provienen de la Tienda, y él los dibuja. Son convenientes para probar, rara vez se rompen. Lo que es estático es bastante difícil de romper, y las pruebas son fáciles.
Las aplicaciones combinadas con la arquitectura Flux son potentes. Probablemente, muchas personas saben que esto es realmente algo poderoso. ¿Qué importancia hay que mencionar? Además de React Redux, hay muchos otros paquetes. Y probablemente sabes que hay un segundo Angular. También es una combinación de marco reactivo y arquitectura Flux. Vue, Flux Redux — Fluxxor, MobX . . React Redux. Vue, , , React Redux. .

? , React Redux . Vue, . — . — MVC-. . . - React Redux .
MVP/MVVM- . , — , , . single page application, multiple page application. - - . , -, - . , MVP, .
— single page application , , . . Flux React Redux, View, Angular, MobX, Fluxxor . .
. .
> MVC: Smalltalk-80 , General MVC , ASP.NET , MVC on Web
> MVP: MVP vs MVC , GUI Architecture , Backbone , Angular1
> MVVM: MS Silverlight , i-BEM
> Flux: Hexlet , Flux for stupid people , Flux official , ReactJS , VueJS
> : , «Javascript. » , ., « » , D.Garlain, M.Shaw, ”An introduction to Software Architecture” (1994), E.Dijkstra ”GOTO statement considered harmful” (1968)
MVC, MVP, MVVM . , . Flux . , , . , — . . JavaScript. . ES5, «JavaScript. » , ES6- — , , , .
, « ». . Java, . , , Flux, . MVP, — -. , . .
, , « ». , , , , , . «GOTO operator considered harmful». . , .
. . . , - , . , , Flux, , input Flux. — , , - . . , . ,
. Muchas gracias