Architecture frontale de niveau supérieur. Conférence Yandex

Le choix de la bonne architecture est un élément clé de la création d'un service frontal. La développeur Anna Karpelevich a expliqué aux étudiants de la School of Interface Development ce qu'est l'architecture, quelles fonctions elle remplit et quels problèmes elle résout. De la conférence, vous pouvez en apprendre davantage sur les approches architecturales les plus populaires dans le front-end: Model-View- * et Flux.


- Bonsoir. Je m'appelle Anya Karpelevich. Aujourd'hui, nous allons parler de l'architecture du front-end de haut niveau.

Je travaille dans Yandex.Direct. Nous réalisons des interfaces pour les annonceurs. Ils publient des publicités, les personnalisent. C'est un système très complexe et intéressant, il a de nombreux composants interconnectés, ils se développent les uns dans les autres, ils ont des fonctionnalités communes et propres. "Les pantalons se transforment en shorts élégants." Tout cela doit être contrôlé très soigneusement. Et l'architecture de nos applications est très complexe. C'est l'une des raisons pour lesquelles je donne cette conférence aujourd'hui. J'adore vraiment ce sujet.

Qu'est-ce que l'architecture? Le fait est qu'il n'y a probablement pas de réponse à cette question. Ou il y en a, mais chacun a le sien. C'est un sujet très controversé. Cela provoque beaucoup de controverse, beaucoup d'holivars. Et une grande partie de ce dont je vais parler aujourd'hui est mon opinion. Il est en partie soutenu par mon groupe de travail, en partie pas beaucoup. Et chacun, lorsqu'il écrit l'architecture de son application, décide par lui-même comment et quoi faire.

C'est pourquoi l'architecture est l'un des endroits les plus créatifs du travail d'un programmeur. Et donc, notre présentation d'aujourd'hui commencera également par la créativité.



Regardons l'image de gauche. Je serai très heureux si quelqu'un reconnaît le bâtiment qui y est représenté. Il s'agit de l'église Saint-Sulpice à Paris. Faites attention aux tourelles, pour elles cette église a été installée ici. J'espère qu'ils sont différents. Ils sont très différents, et il y a une raison intéressante à cela. Entre eux 130 ans de différence. Puis la tour de gauche a été démolie et reconstruite pendant la guerre franco-prussienne.

Pourquoi est-elle ici? Regardez cette photo. Les tours ont la même architecture, et l'ensemble de l'environnement, ces vignettes, luminaires, structures arquées sont différents. Pourquoi Parce que le but de ces tours est le même. Aucun d'entre eux, par exemple, n'était un clocher. Ce ne sont que des tours. Quelque chose y était stocké et tout le reste était différent. Pourquoi? Parce que l'architecture de ces tours est la même. Les deux ont une voûte, une seule fenêtre et c'est une lancette. Les fenêtres ont à peu près la même hauteur. Et l'idée est que l'architecture, à la fois des bâtiments et des applications, est une structure de support. Ce n'est pas une vignette, pas un scintillement, pas une implémentation. C'est ce qui est au cœur. Et cette fondation, en règle générale, dépend de l'environnement, du sol, en ce qui concerne le bâtiment, du but que l'architecte se fixe, mais ne dépend presque jamais des améliorations de conception.

L'exemple de construction pour le thème de l'architecture est assez évident. Mais la bonne image est plus intéressante. "L'architecture est une musique engourdie." «Architektur ist gefrorene Musik», a déclaré Johann Wolfgang Goethe au XVIIIe siècle. Goethe ne savait probablement rien de l'architecture des bâtiments, il était poète. Et il était assuré de ne rien savoir de l'architecture des applications. Mais il a exprimé une idée très précieuse et intéressante.

La musique existe en dynamique. Ce n'est pas quelque chose de statique. Ceci est un processus. Et juste comme ça, une application est un processus. Il a un moment de lancement, il a un moment de développement, quand on fait quelque chose avec lui, on travaille. Et il a enfin un moment d'achèvement. L'architecture de l'application est sa tranche à tout moment. À tout moment, notre application, en tant que thème musical, doit être claire, concise, compréhensible, prévisible, etc. Sinon, tout s'effondrera.

Avec cette introduction créative, nous terminons, passons à des choses plus banales, plus proches de la pratique de la création d'applications.

Qu'est-ce que l'architecture et pourquoi est-elle nécessaire?



Premièrement, nous avons l'organisation d'une grande quantité de codes, quelque chose que nous rencontrons tout le temps dans Direct, et pas seulement dans Direct. Il y a tellement de code que vous pouvez vous y perdre. Nous ne voulons pas nous perdre dans le code.

Deuxièmement, la duplication des fonctionnalités. C'est également un problème éternel que vous rencontrerez toujours, et aujourd'hui ce sujet de duplication passera par la ligne rouge tout au long de la conférence. La même fonctionnalité dont nous pouvons avoir besoin à plusieurs endroits sur l'interface. S'il est nécessaire à plusieurs endroits, il doit s'agir physiquement du même code utilisé à plusieurs endroits, pas d'une copie. Pourquoi? Nous en reparlerons plus loin. Mais l'architecture devrait nous aider à éviter le copier-coller.

Le troisième est le soutien. Il est bien évident que si nous avons une application, nous devons en quelque sorte la soutenir, et il est conseillé que toutes les ressources de l’équipe ne soient pas gaspillées.

Modifiez la composition de l'équipe. C’est aussi une telle chose que nous rencontrons dans la vie réelle plus souvent que nous le souhaiterions. Quelqu'un vient, quelqu'un part et si une personne passe six mois à entrer le code, c'est mauvais. Si la connaissance du code est stockée dans une seule tête, et qu'elle transmettra cette connaissance pendant six mois en cas de départ, c'est encore pire. En général, ici l'architecture nous aide également à rendre tout cela plus compréhensible et à maintenir le partage des connaissances.

Ajout et extension de fonctionnalités. Aussi une chose assez évidente. Le directeur vient en courant vers nous et dit que cela est urgent. Et si pour le faire de toute urgence, vous devez dépenser beaucoup de temps et d'efforts, alors c'est une mauvaise solution architecturale. Et nous avons besoin du bien.

Et enfin, des erreurs. Plus notre architecture est compréhensible et prévisible, plus il est facile de rechercher des erreurs, moins il y a de bogues.

Comment appeler tout cela? Tout cela peut être appelé - les problèmes d'un système complexe. Une application est un système complexe, l'architecture nous aide à résoudre un problème.



Bref, en quelque sorte. Voici une photo de nouilles à ma droite, et c'est ce qui se passe si vous ne suivez pas l'architecture, si vous ne la construisez pas, réfléchissez-y et concevez-la. Et la deuxième image est ce qui se passe si l'architecture est au moins réfléchie d'une manière ou d'une autre. Ce n'est pas Saint-Sulpice, mais au moins un créateur pour enfants, il se tient fermement et ne s'effondre pas. Aujourd'hui, nous jouerons aussi beaucoup de constructeur.



Formellement à propos de tout cela. L'architecture est un moyen de résoudre les problèmes d'un système complexe par abstraction de l'implémentation de l'interface et différenciation des pouvoirs entre les blocs de code. Plus loin, nous analyserons cette longue phrase en détail.

Quelles sont les caractéristiques de l'architecture d'application en tant que domaine de connaissance? Elle a un domaine spécifique avec lequel nous travaillons. Autrement dit, ce n'est pas quelque chose d'abstrait, c'est une chose très spécifique. Voici la tâche, nous sélectionnons l'architecture pour cela, et non pour que, oooh, une approche architecturale intéressante, nous devons essayer. Alors non. Vous pouvez essayer quelque chose de petit, mais pour un projet sérieux, l'architecture est sélectionnée, parfois composée pour un projet spécifique.

L'histoire de la question, quand, en général, cette idée a surgi que l'architecture devrait être fait. C'est, je dois dire, qu'à une époque une idée très extraordinaire a été exprimée en 1968 par Edsger Dijkstra, un merveilleux programmeur. Il est probablement mieux connu comme l'auteur de l'algorithme de Dijkstra, la recherche du chemin le plus court dans un graphique. Mais il a en fait beaucoup d'idées révolutionnaires pour son temps. Et l'un d'eux est un article, alors je vais vous donner une référence au matériel, vous pouvez le lire, il n'y a que deux pages, un court essai. Cela ressemble à "Opérateur GOTO considéré comme nuisible", dans la traduction "Opérateur GOTO - opérateur de transition inconditionnelle - mal". C'était la première pensée qui disons officiellement que nous devons écrire l'architecture, pas les nouilles.

Dans les années 70, cette idée était déjà développée par Dijkstra en collaboration avec Parnassus, et individuellement, individuellement. Le premier livre détaillé sur l'architecture d'application en général a été écrit en 1996 par Mary Shaw et David Garlan. Après cela, en fait, de tels livres détaillés sur l'architecture logicielle n'ont pas été écrits précisément en raison de la portée, que chaque domaine de la connaissance a ses propres approches architecturales, quelque part un, quelque part plus populaire, quelque chose, généralement non applicable à certains endroits. Et comme l'architecture est un processus créatif, vous ne trouverez aucun livre spécifique sur la façon d'écrire l'architecture. Peut-être qu'après 1996, il n'y avait rien de particulièrement détaillé à ce sujet.

Quelles sont les exigences pour l'architecture du projet maintenant. Premièrement et surtout, ce qui est exigé, en fait, c'est l'extensibilité, car si votre projet ne se développe pas, il est mort.

Réutilisation du code. Il s'agit du très copier-coller. Si vous avez deux blocs qui sont utilisés à deux endroits différents, vous avez besoin des mêmes fonctionnalités, puis vous devez réutiliser le même code, et l'architecture doit être telle que tout morceau de code puisse être pris et réutilisé dès qu'il est nécessaire .

Séparation des pouvoirs entre les modules de code. Nous allons en parler aujourd'hui plus en détail, pourquoi cela est nécessaire. L'idée est la suivante: chaque module, chaque bloc, chaque morceau de code doit effectuer une action spécifique, porter exactement une fonction. Et cette fonction doit être placée dans le titre de cette méthode, classe, quelle qu'elle soit, module. Un module - une fonction.

Et enfin, la qualité des applications. Il y a beaucoup de choses que j'aimerais faire - à la fois la fiabilité et la compatibilité descendante. En réalité, encore une fois, il est sélectionné pour la tâche. Quelque part, la rétrocompatibilité est nécessaire pour qu'en aucun cas rien ne bouge. Quelque part, la fiabilité est nécessaire pour que, Dieu ne plaise, les mots de passe, les codes PIN des cartes ou les CVV ne fuiront nulle part. Quelque part, vous en avez besoin pour être sans problème s'il s'agit d'un satellite ou autre chose. En général, choisissez-en quelques-uns. Plus vous voulez prendre en charge, plus vous êtes susceptible de rencontrer de la complexité en architecture.

De plus, nous parlerons avec vous de quelques définitions, de telles choses encyclopédiques. Pourquoi est-ce important? Parce que la terminologie en architecture est très importante, et nous devons parler le même langage avec vous. Les définitions sont pour la plupart tirées du paradigme de programmation appelé POO. Mais en fait, ils ont germé dans d'autres paradigmes, avec les termes «classe, objet, interface», ils opèrent non seulement dans le cadre de la POO. Cependant, ces définitions et cette compréhension sont tirées précisément du monde de la POO.



La chose la plus simple est la classe. Qu'est-ce qu'une classe? Ceci est un modèle, ceci est un exemple. Par exemple, la classe Snake est la classe Snake. Nous avons défini avec elle trois champs privés, c'est-à-dire un champ qui n'est accessible à personne sauf aux méthodes de la classe elle-même - le nombre de buts, le nombre de queues et la longueur des perroquets. Nous avons déterminé le constructeur dans lequel nous avons mis ces mêmes têtes, queues et longueur en perroquets. J'ai la classe Snake. Tout est simple.



Nous allons plus loin. Objet. Et un objet est une instance d'une structure spécifique. De plus, encore une fois dans la POO classique, il est sous-entendu qu'un objet est un objet d'une classe. Dans le monde moderne, en JavaScript, qui n'était pas toujours un langage OOP, et même maintenant ce n'est pas toujours et pas partout OOP, on sait qu'il peut y avoir des objets abstraits. Autrement dit, nous pouvons créer un objet, un littéral, qui ne sera pas un objet de la classe. Mais voici un exemple de la façon dont nous créons un objet de la classe Snake. Ici, nous avons un serpent à deux queues d'une longueur de 38 perroquets, - un boa constrictor.



Module Un module est une unité sémantique. Ce n'est pas toujours une classe. Il peut s'agir d'un ensemble de classes, d'un ensemble d'objets, d'un ensemble de méthodes qui ne sont pas combinées en classes. En règle générale, vous pouvez supposer qu'un module correspond à ce que vous avez écrit dans un seul fichier. Mais, en principe, le module est le dossier dans lequel ils se trouvent, par exemple, le fichier et les tests de ce module sont également un module. Ce qui est important ici, c'est qu'un module est ce que vous appelez un module, ce que vous considérez comme une unité de sémantique. Dans ce cas, le module concerne la façon dont nous mangeons les serpents. Le résultat de ce module est la dernière méthode, eatSnake, car nous avons mangé des serpents. Je ne sais pas pourquoi nous mangeons des serpents, mais nous pouvons le faire, car nous avons écrit ce module comme ça.



C'était trivial, alors une chose un peu plus intéressante va commencer. Interface de classe. L'interface d'une classe est, plus simplement, ses méthodes publiques, ce à quoi elle ressort, ce que nous pouvons obtenir d'un objet de cette classe d'un objet de l'extérieur. Cette classe implémente l'interface getSnakeLength. Il peut nous rendre la longueur du serpent. Veuillez noter qu'il n'y a pas d'accès externe aux champs privés. L'accès depuis l'extérieur est uniquement à la méthode publique getSnakeLength.



Et puis une chose très intéressante. Nous avons longtemps discuté de la façon d'appeler cette chose, car j'ai inventé le terme «interface abstraite» lorsque j'ai créé cette conférence. Et honnêtement, je n'ai jamais vu une définition normale de cette approche et méthode. Cependant, de nombreux langages de programmation vous permettent de créer des interfaces abstraites, et de les appeler, dès que ce ne sont pas des classes abstraites, et des interfaces abstraites aussi, juste des interfaces. Il s'avère un homonyme avec l'interface de classe. L'idée est qu'une interface abstraite est un ensemble de méthodes qui font quelque chose. Lorsque nous créons une classe, nous partons de la question "qu'est-ce que c'est?" C'est un serpent et elle sait faire quelque chose ou pas. Elle peut juste donner sa longueur.

Et lorsque nous créons l'interface, nous partons de ce qu'il fait, de ce qu'il devrait être capable de faire. Et cela s'avère être un moyen très puissant d'étendre les classes. Nous pouvons attribuer des classes à certaines classes, en les développant à l'aide d'interfaces. Par exemple, le cadre I-BEM peut faire une telle chose, une telle histoire avec des interfaces abstraites est intégrée dans le cadre. Malheureusement, de nombreux frameworks ne savent pas comment faire, et la chose est puissante.

Ici, à titre d'exemple, nous avons créé l'interface audible, quelque chose qui peut sonner. Et sa définition est la méthode abstraite getNoise vide. Nous avons élargi notre serpent avec la classe audible, implémenté sa méthode getNoise et notre serpent a sifflé. L'inspiration pour cet ensemble d'exemples m'a été donnée par le merveilleux livre d'Eric Freeman et Design Patterns.

Nous allons maintenant essayer d'examiner ces exemples un peu plus précisément.



Mais d'abord, parlons de la raison pour laquelle ces exemples étaient nécessaires. Et ils étaient nécessaires ici pour cette grande diapositive. Ce qui est écrit ici est si important que je l'ai même mis dans le cartouche jaune. On peut dire un mantra. Il s'agit d'un principe très important auquel vous devez toujours penser lorsque vous concevez l'architecture. Haute cohésion, faible couplage - forte adhérence, faible connectivité. Il y a un certain problème avec le fait que le mot cohésion et le mot couplage sont traduits en russe, et ainsi de suite, et ainsi de suite, «connectivité» est traduit, le mot couplage a été spécialement inventé pour ce principe.

Telle est l'idée. Vos blocs doivent être très compacts, très étroitement couplés. Ils doivent implémenter exactement une fonction. Et entre eux, ils doivent être connectés très facilement pour pouvoir être facilement combinés, assemblés, comme un designer. Et puis votre architecture sera suffisamment flexible et fiable. Et aussi facile à tester.

Voyons comment on peut obtenir une traction forte et un couplage faible sur les points de ce qu'on appelle.



Spécialisation. Chaque bloc ne résout qu'un seul problème. Ici, nous avons une bonne illustration - un designer pour enfants. Nous avons chaque bloc ou un ensemble de blocs. Ils sont tous de leur forme, de leur taille. Et si nous devons construire une maison, nous prendrons de longues barres. Si nous devons construire une balle, nous prendrons des barres courtes. Chaque barre a sa propre fonction. Et ceux qui ont joué aux constructeurs le savent: plus la forme des pièces est simple, plus vous pouvez en construire. Rien ne sera construit à partir d'une telle zagoguline, ou seulement ce qui est décrit dans l'instruction est construit. Et qui en a besoin?

La même chose, l'abstraction. Il s'agit de l'abstraction de l'interface de l'implémentation. L'idée est que l'interface est externe, comment notre classe est, notre bloc ressort, comment il interagit avec d'autres blocs ne devrait pas affecter son implémentation interne. Au contraire - cela arrive. L'autre façon - jamais. Dans une bonne architecture. Ici, à titre d'exemple, la formation de ces boutons n'affecte pas la forme du bloc lui-même. Nous sélectionnons séparément la forme du bloc et collons déjà dessus.



Encapsulation. Suite du sujet précédent. Dans les méthodes privées, c'est-à-dire à l'intérieur de nos blocs, nous réalisons le sens même de notre bloc, l'implémentation. Et l'interface, la façon dont ils sont connectés, est publique. Autrement dit, dans ce cas, toutes ces croix, tirets et le formulaire lui-même sont implémentés. Et les boutons sont l'interface. Et une bonne architecture ressemble à un tel constructeur.



Oh quel monstre effrayant. Il s'agit de réutiliser du code. Au départ, ce monstre devait en fait montrer un exemple d'architecture médiocre, mais regardez-le attentivement. Il est beau. De plus, il est visiblement satisfait de sa vie, court assez vigoureusement sur ses étranges jambes. Peut-être qu'il sait même voler, ou, au moins, il a de belles ailes de papillon.

Quelle est l'idée? Si vous avez une implémentation pour un chameau et une implémentation pour un crocodile, et qu'un gestionnaire vient à vous et vous dit qu'un chameau-crocodile est urgent. Vous n'écrivez pas séparément un crocodile de chameau. Vous prenez le corps d'un chameau, le séparez de la réalisation entière du chameau. Prenez la tête du crocodile, séparez-la du crocodile et réutilisez les blocs. Pourquoi est-ce nécessaire?

Ensuite, lorsque le manager revient vous voir et dit que nous nous étendons de toute urgence en Amérique du Sud, et qu'il y a des alligators, nous devons maintenir une forme de mâchoire irrégulière, ou que là, la quatrième dent du crocodile n'est pas comme ça, vous ne fouillerez pas tout le projet , où avez-vous copié les têtes de crocodiles. Parce que vous pourriez avoir d'autres crocodiles de zèbres-bisons à proximité. Vous prenez simplement votre classe la tête d'un crocodile, faites une extension à partir de la série de la tête de l'alligator, donnez-lui les paramètres, il déterminera lui-même quelles dents dessiner pour lui. Et c'est tout. En un seul endroit et pas dans tous les endroits où il est utilisé.

Ici, la fiabilité augmente parfois, car vous êtes assuré d'oublier une tête copiée dans un projet très rare. En général, il n'y a rien de mal à de tels cadavres. Bon cadavre, utile.



Nous allons maintenant examiner directement des exemples de mauvais code. , . TypeScript, . , . , , , TypeScript 2.7 , ( — . .).

, User. . . 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 )

Ce sont les approches architecturales. Nous en avons mentionné certains aujourd'hui. Architecture client-serveur; l'architecture des composants, une de ses variantes vous est familière de React, si tout va bien. Événement, qui, curieusement, est également familier à tout le monde, il est basé sur presque tous les systèmes d'exploitation pour ordinateurs personnels. REST, ce que nous aimons dans le serveur, et les deux derniers, que nous apprendrons en détail aujourd'hui, sont les plus frontaux, avec lesquels nous travaillons est un modèle de présentation * et des flux de données unidirectionnels.

Commençons par MV *. Pourquoi un astérisque? L'histoire, comme on dit, pleine de douleur et de colère. Il était une fois, dans les années 80, la merveilleuse approche architecturale de MVC a été inventée. M - Modèle, V - Vue, C - Contrôleur. L'approche était très pratique. Inventé généralement pour les applications de console. Mais quand les technologies web ont commencé à se développer, quand elles ont toutes commencé à l'utiliser, il s'est avéré que parfois c'était nécessaire, ici le modèle MV est bon, mais le Controller n'est pas implémenté correctement. En conséquence, il y avait tellement de variantes différentes de l'implémentation de Model-View - quelque chose qui au début a été confondu du fait qu'il s'appelait tout MVC. Parce que, s'il y a un modèle MV, alors le troisième est Controller, peu importe ce que nous y avons réellement fourré.

Ensuite, il s'est avéré que les gens sont confus et signifient des choses complètement différentes par MVC. Il y a environ un an, ils ont commencé à partager activement cette terminologie et à se faire un nom pour chaque implémentation de cette approche. D'une manière ou d'une autre, ce MV * est apparu. J'ai également vu le terme MVW sur Internet, où W est n'importe quoi. Eh bien, nous passons, en fait, aux technologies MVC.



Comment sont-ils arrangés? L'idée est que nous avons un modèle qui stocke les données. Il y en a généralement beaucoup. Il existe une sorte de vue qui montre ces données à l'utilisateur. En règle générale, ils sont également nombreux. Et un troisième composant, qui est un intermédiaire entre eux, relie les données et l'affichage. Ici, l'utilisateur dans le coin supérieur droit travaille avec tout cela.



MVC, la façon dont tout a commencé remonte à 1980, Smalltalk. Mais c'est sous cette forme qu'elle existe jusqu'à présent dans certains cadres. Pas dans certains, assez dans beaucoup. Quelle est l'idée? L'utilisateur travaille directement avec la vue et le contrôleur. Il entre des données dans certains champs de la vue, appuie sur le bouton Soumettre et les données vont au contrôleur. Ceci est une soumission de formulaire. Un tel formulaire de soumission honnête par bouton d'envoi, familier à tout le monde depuis longtemps, j'espère.

Nous regardons. La flèche jaune de l'utilisateur au contrôleur - il s'agit des données transférées par l'utilisateur au contrôleur à l'aide du bouton de soumission. Une flèche verte, - le contrôle y est passé. Le contrôleur examine ces données. Peut-être qu'il les traite en quelque sorte, les subtilités de mise en œuvre sont déjà là, et les envoie au modèle souhaité. Le contrôleur lui-même choisit le modèle à envoyer. Envoie une flèche verte, envoie des données avec une flèche jaune.

Le modèle traite également les données. Elle les valide peut-être. Peut-être qu'elle les met dans la base. Bref, le modèle sait quoi en faire. En règle générale, le résultat est de nouvelles données. Par exemple, nous pouvons dire à l'utilisateur s'il s'est connecté ou non, et le modèle a vérifié le mot de passe avec la connexion. Après cela, le modèle transfère à nouveau le contrôle au contrôleur, afin que le contrôleur sélectionne la vue à afficher. Et les données vont directement à la vue. Comment cela peut-il être fait, en général, comment un modèle peut-il envoyer des données à une vue?



Très simple. Si le contrôleur et le modèle se trouvent dans le serveur principal et que la vue de modèles est côté serveur. C'est ainsi que les cadres Ruby on Rails, ASP.NET, Django sont organisés, en général, partout où vous écrivez des modèles côté serveur, et le code HTML collecté arrive au client, et les données remontent également, avec une forte probabilité, c'est cette approche. Quels sont les problèmes ici. Dans une application d'une seule page, une telle chose ne peut pas être construite. Nous avons constamment des données sur le serveur, disparu sur le serveur, la page se recharge. Deuxièmement, on ne sait pas trop où pousser la validation du client, et, en général, le JavaScript du client, AJAX et tout cela ici? Parce que si nous voulons quelque chose de rapide, nulle part. Cela ne fonctionne tout simplement pas dans cette approche, ou fonctionne de sorte qu'il ne fonctionne pas mieux.

La dernière ligne ici, c'est une histoire tellement intéressante, enracinée, semble-t-il, en 2008. La question était: où stocker la logique métier - sur le modèle ou dans le contrôleur? Certains ont déclaré: «Nous stockons la logique métier dans le contrôleur, car il s'agit de données pratiques et immédiatement nettoyées envoyées au modèle. Le contrôleur se validera, revérifiera, le cas échéant, et enverra une erreur. " Il y avait ceux qui disaient que "Le résultat est de gros contrôleurs laids stupides, des contrôleurs épais, stupides et laids." Ils se sont vraiment révélés énormes. Et ils ont dit que la logique métier devrait être dans le modèle, et que le contrôleur devrait être mince, léger, transféré les données, le modèle lui-même traité. Et puis dans la première version, le modèle, en général, se révèle être juste une API pour la base de données.

Comment, à mon avis, vraiment? En fait, vous devez surveiller leurs tâches. Si vous avez une connexion entre une vue et un modèle qui est toujours un à un, une vue est un modèle, alors il est pratique pour vous de faire de la logique métier dans les contrôleurs et de créer un modèle simple et propre, qui, en fait, sera une API pour la base de données. Si vos vues et modèles peuvent se chevaucher, et qu'une vue dépend de plusieurs modèles, le modèle fonctionne avec de nombreuses vues, il est pratique pour vous d'avoir de nombreux contrôleurs fins et de les multiplier dans n'importe quelle progression, peu vous importe combien ils sont, ils sont toujours petits.

Je dois dire que le monde semble avoir gagné le deuxième point de vue, avec la logique métier dans les modèles. Autrement dit, ces gros contrôleurs laids stupides ne semblent pas être utilisés si activement. Signaux, vous pouvez voir ce que dans la documentation d'ASP.NET, le cadre proposé en 2013 proposait la logique métier dans les contrôleurs. Et dans les dernières versions en 2014 - dans les modèles. Il y a eu un moment très intéressant où cela a changé.

Quels MVC ont des problèmes. Nous les avons déjà prononcés, mais nous le ferons. Tester car il n'est pas clair comment implémenter la validation client est possible, mais difficile, AJAX est vissé sur le côté, vous devez faire quelque chose. Ils ont trouvé une solution. La solution s'appelait MVP, et, oui, vous pouvez rencontrer MVP dans le framework avec le texte qu'ils sont MVC. Par exemple, le framework Backbone MVP. A propos de lui depuis longtemps dans la documentation dans le même 2011-2012-2013, il a été écrit qu'il s'agit d'un framework MVC.



Model-View-Presenter. Son schéma est déjà beaucoup plus simple. Il existe des modèles. Ils interagissent les uns avec les autres. Ils donnent des données à Presenter, Presenter les transfère à la vue, les montre à l'utilisateur. Et de retour. L'utilisateur introduit quelque chose dans la vue, appuie sur le bouton, le présentateur regarde, AJAX envoie au modèle ou le place dans le modèle, et le modèle AJAX envoie au serveur. Autrement dit, tout est déjà beaucoup plus simple et linéaire, mais sans normalisation côté serveur, il y aura déjà des difficultés. Si vous voulez un serveur, un tel système sera compliqué.



Comparons. Regardons la première image, où nous allons essayer d'implémenter une chose très simple - envoyer des données d'entrée au modèle. Nous avons entré quelque chose, cliqué sur un bouton, il devrait apparaître dans le modèle, le modèle fera quelque chose avec cela et nous dira que quelque chose s'est produit. Nous sommes entrés: "je m'appelle Vasya", j'ai cliqué sur OK. Si nous voulons une validation côté client, cela se produit ici, presque par interception, dans les cas particulièrement graves, en effet, en interceptant un clic via event.preventDefault (). Et quelque part, un point zéro sur le côté a validé la validation du client.

Ensuite, nous envoyons honnêtement les données via le formulaire de soumission au responsable du traitement. Les données entrent dans le modèle, le modèle le met en lui-même, traite, regarde. Nous dit que, bien, les données sont acceptées, vous êtes vraiment Vasya. La troisième flèche - le contrôle va au contrôleur, le modèle indique au contrôleur que, veuillez afficher l'étiquette «Mon nom est Vasya». Le contrôleur sélectionne la vue appropriée, affiche l'étiquette. Et les données «mon nom est Vasya», la quatrième flèche, jaune, le modèle y met. La question est de savoir comment tester cela? Seulement un instantané. Pas d'autre moyen. Il n'y a rien sur quoi écrire, même des tests fonctionnels.

La deuxième option, déjà avec MVP. Nous avons conduit "mon nom est Vasya", cliqué sur ok. Flèche sous le numéro un, verte, - la direction est allée au présentateur. Le présentateur a dit: le bouton est enfoncé. Le présentateur regarde, flèche numéro deux, bleu, notez qu'il s'agit d'une demande de données. Dans MVP classique, il ne s'agit pas d'envoyer des données de la vue à Presenter, mais une demande de données de Presenter. C'est beaucoup plus propre, car Presenter peut déjà savoir à l'avance, par exemple, qu'il n'a pas besoin de données, tout de même, tout va mal.

Ensuite, le troisième paragraphe sur Presenter est une validation JS honnête. Nous pouvons déjà l'écrire en toute sécurité, c'est un endroit spécial pour cela. La quatrième flèche - les données vont au modèle, par exemple, les mettent dans la base de données, dit: "Tout est en ordre, je le mets." La cinquième flèche, vous voyez, elle est rayée, j'espère qu'il est clair qu'elle est rayée jaune-vert, et la gestion et les données sont revenues à Presenter. Le modèle a dit "je l'ai mis", le présentateur a réalisé que puisque les données ont été placées dans la base de données, cela signifie qu'il est nécessaire de montrer que tout est en ordre, les données sont mises. Et la sixième flèche - ils l'ont envoyée à la vue, peut-être à une autre, mais je n'ai pas dessiné la deuxième vue.

Quel est le plus ici. La validation JS est tombée à sa juste place et tout s'est bien passé, AJAX est également tombé en place, cela peut être la quatrième flèche, par exemple, si le modèle est sur le serveur, ou le modèle AJAX lui-même va au serveur. Et enfin, nous pouvons tester Presenter en toute sécurité, y écrire des tests fonctionnels.



Deuxièmement, qu'avons-nous d'autre de positif, en plus des tests simplifiés? Nous avons obtenu une séparation de l'affichage visuel et de son travail. Autrement dit, nous pouvons toujours écrire un instantané sur View, et nous pouvons écrire des tests sur Presenter séparément. Nous pouvons réparer le présentateur et ne pas toucher la vue, et vice versa. Notre spécialisation s'est améliorée. C'est ainsi que les frameworks tels que Angular1, Backbone, Ember, Knockout des versions antérieures sont organisés. Une fois qu'il y en avait beaucoup, juste une concurrence féroce.

Quelles sont les fonctionnalités. Le présentateur est déjà placé sur le client, le modèle peut être là et des applications d'une seule page sont tranquillement créées. Cela se passe mieux, mais il y a beaucoup d'applications d'une seule page sur cette histoire, ou du moins cela a été fait auparavant. L'interaction avec le serveur AJAX est bonne. Validation client en place. Il semblerait que tout va bien, pourquoi réfléchir plus loin?

Cependant, au moins MVVM a été inventé. C'est aussi une chose intéressante.



Il s'agit essentiellement d'une implémentation de Presenter utilisant le cadre. Il s'est avéré souvent lorsque vous avez écrit le premier présentateur, le deuxième présentateur, le cinquième présentateur, qu'ils sont tous les mêmes. Et ils ont juste tricoté une vue et un modèle. Comme vous pouvez le voir, il est construit comme MVP.



Et tant de cadres viennent de résoudre ces tâches contraignantes. Quels en sont les avantages? Nous n'avons pas besoin d'écrire de code supplémentaire. Et cela accélère vraiment la vitesse de développement. Quels sont les inconvénients. La connectivité entre Model et ViewModel est améliorée.

Autrement dit, des problèmes surviennent là-bas précisément en raison de la forte connectivité, il arrive donc parfois que MVVM ne soit pas utilisé. Par exemple, je connais personnellement MVVM dans le cadre i-BEM, que nous utilisons parfois, et que nous n'utilisons pas parfois, car il s'agit d'une liaison gênante et trop stricte. Cependant, il existe, Microsoft Silverlight est organisé par cette technologie, et ils disent: bon. Je ne sais pas, je ne l'ai pas essayé.

Pourquoi est-il arrivé qu'en plus de MVP et MVVM, quelque chose d'autre soit apparu, vous tous familiarisés avec le mot redux, pourquoi il y avait des flux de données unidirectionnels.



Nous regardons la bonne image. Nous avec MVP avons régulièrement un tel problème. Supposons que nous ayons un système complexe, pas un à un - de nombreuses vues, de nombreux modèles. Ils sont tous interconnectés. La vue de dessus, jaune, a changé le modèle. Le modèle a changé un autre modèle. La vue jaune du bas a changé. La vue inférieure a également changé le modèle. Tous ensemble, ils ont changé la vision rouge centrale, et quelque chose d'incompréhensible s'y passe.

Facebook a été confronté à ce problème lorsqu'ils ont constamment reçu un bogue en raison de messages contextuels non lus. Autrement dit, l'utilisateur voit "Vous avez un message non lu", s'ouvre, mais ce n'est pas le cas. Parce que les deux points de vue ont corrigé ensemble l'état de celui-ci ... En général, l'état de la vue a été corrigé à partir de deux sources différentes, et qui a raison n'est pas clair. Ils l'ont gouverné, un bug est ressuscité, ils ont régné à nouveau, un bug est ressuscité. Au final, ils étaient fatigués, et ils ont décidé de résoudre le problème radicalement, désolé pour la tautologie, et ont juste rendu l'état de vue déterministe.

Le problème du MVP se situe précisément dans le non-déterminisme de l'état du système. Nous ne pouvons pas toujours prédire dans quel état elle est maintenant, et qui est venu en premier, qui a corrigé quoi. Flux a résolu ce problème, comme on dit, génétiquement. Il ne peut pas avoir ça. Ils m'ont dit ici depuis longtemps que l'idée d'un flux de données unidirectionnel était dans l'air, c'est vrai. Et ce concept a été inventé, bien sûr, bien avant Facebook, bien avant 2013, quand ils l'ont publié. Mais comme ils disent, ils ont breveté, ils ont d'abord publié un spreadshit, que nous avons trouvé une telle chose, utilisez-le.



Regardons Flux plus en détail. Voici l'idée. Nous avons un magasin, et ce magasin est un entrepôt de données, c'est la seule source de vérité pour notre application. Tout le reste est faux. Comment fonctionne-t-il? Au début, si nous regardons spécifiquement le cycle de travail, il commence généralement par l'utilisateur qui fait quelque chose, c'est-à-dire que la vue fonctionne. La vue crée une action. Veuillez noter que l'action n'est pas remplie dans l'image. Pourquoi Parce que c'est une structure. Ce n'est pas une classe, pas un objet, ce n'est pas quelque chose d'intelligent. Telle est la structure. Sur le web, en JavaScript on peut l'écrire, c'est juste cet objet très abstrait.

La vue crée une structure, passe au gestionnaire de blocs. Le gestionnaire de blocs déclenche un rappel. Autrement dit, il dit: «Appelez la fonction que l'on m'a dit d'appeler lorsque l'action se produit. Il a dit d'appeler le magasin. " Autrement dit, la méthode Store est appelée à partir du répartiteur. La méthode est appelée. La méthode est appelée, elle est obtenue sur le Store. Le magasin regarde ce qui en est arrivé, se change en quelque sorte. Il change son état. Et il est le seul à pouvoir changer son état. Personne d'autre ne fait ça. Autrement dit, il est la seule source de vérité. Après cela, il diffuse toutes les vues qui lui sont liées, tous les composants qui lui sont liés: "J'ai changé, allez chercher les données."

Les vues vont pour les données, puis un moment intéressant commence. Dans Flux classique, comme sur Facebook, la vue est entièrement redessinée.



Voici notre formulaire avec une étiquette et un bouton. Comment fonctionne-t-elle? Nous regardons le point zéro. Le point zéro est également là. Il est la flèche bleue tout en bas, l'enregistrement du rappel. C'est ce qui arrive en premier.

Le responsable du magasin appelle: «Veuillez enregistrer mon rappel, que vais-je faire lorsque l'action viendra à vous.» C'est arrivé. Ensuite, nous pouvons travailler avec l'application. Nous avons cliqué sur un bouton, créé une structure. Veuillez noter qu'en plus des données saisies par l'utilisateur, par exemple Vasya, Action a également des métadonnées, type. Un point très important est que l'action elle-même transmet le type d'action qu'elle est, mais au répartiteur de toute façon. Il jette toute l'émission Action. Première flèche, la méthode est appelée.

Le répartiteur appelle la méthode, en fait, un déclencheur d'action et y passe cette action. Sur le déclencheur Action, un rappel est appelé, que nous avons enregistré au point zéro. Voici la flèche rouge, c'est un rappel depuis un rappel. Le magasin prend ces données, semble que, le type est changer de nom, donc je me change dans le champ du nom en Vasya, et je l'envoie au back-end, et valide d'une manière ou d'une autre, probablement, en général, le magasin sait quoi faire . Ensuite, la flèche violette diffuse l'événement de modification. Nous avons changé. Tout le monde sait que nous avons changé de magasin.

Ensuite, une petite caractéristique du Flux classique, qui peut ne pas être familière à ceux qui ont travaillé avec Redux, plus précisément, même avec React, et non avec Redux. Les vues vont pour les données. Ils vont au magasin et disent: "J'ai ce champ, ce champ et ce champ." Nous sommes habitués au fait que, au contraire, tout dépend des vues si vous avez travaillé avec React, Redux ou quelque chose du genre. Et le sixième point, une refonte complète.

Regardons ce diagramme et trouvons un goulot d'étranglement, à cause de quoi? Redessiner. Une refonte complète, c'est pourquoi Flux a commencé à être activement utilisé après 2013, quand est-ce arrivé? Qu'est-ce qui a rendu cela possible? Maison virtuelle. Une maison virtuelle qui vous permet de redessiner uniquement lorsque c'est vraiment nécessaire.



Mettons-nous de côté et parlons de React qui, comme cela, combiné avec succès avec Flux, a fait le monde que nous connaissons maintenant lorsque cette technologie est la plus populaire.

Le même 2013, le même 2013, le même Facebook. Initialement, React a été inventé en général, comme un avis de vues dans MVC, MVP, variations. Et vous pouvez vraiment l'utiliser là-bas. Quelle est sa puissance. Premièrement, la maison virtuelle, comme ils l'ont dit à juste titre, permet de ne pas redessiner la vraie maison, car c'est une opération très difficile, mais de redessiner la virtuelle. Et seulement si, en effet, il y avait un changement, nous redessinions le composant, à la suite de quoi tout fonctionne beaucoup plus rapidement qu'il ne pourrait l'être.

Et - de purs composants immuables. Ceci est le mécanisme des propriétés. L'implémentation est également réactive, vous permettant de créer des composants qui n'ont pas leur propre état. Et si vous écrivez dans cette architecture, il est très correct de créer des composants propres, sans état, sans état. Ils n'ont que des données provenant du magasin, et il les tire. Ils sont pratiques à tester, ils se cassent rarement. Ce qui est statique est assez difficile à casser et les tests sont faciles.

Les applications combinées avec l'architecture Flux sont puissantes. Beaucoup de gens savent probablement que c'est vraiment une chose puissante. Quelle importance faut-il mentionner? En plus de React Redux, il existe de nombreux autres bundles. Et vous savez probablement qu'il y a un deuxième angulaire. C'est également une combinaison de framework réactif et d'architecture 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 . .

Conclusion .

> 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. — , , - . . , . , . Merci beaucoup.

Source: https://habr.com/ru/post/fr425611/


All Articles