Nouvelle application "Jellyfish". Pourquoi papillonner?

Le directeur technique Boris Goryachev explique comment Medusa y a travaillé pendant un an et pourquoi il a été écrit en Flutter


Le 12 mai, la sortie des nouvelles applications mobiles Medusa ( iOS , Android ) a eu lieu - près de deux ans après que nous avons décidé de les réécrire. Pourquoi si longtemps? Pourquoi pas des applications natives? Pourquoi Flutter? Tout cela est raconté par le directeur technique de Medusa Boris Goryachev.



Contrairement à nos anciennes applications, nous avons décidé de ne pas en faire de nouvelles natives. Tout d'abord, écrire deux fois le même code est fastidieux. Deuxièmement, cela ne fonctionnera jamais de sorte que dans deux projets différents écrits par des personnes différentes, tout soit synchrone et identique. Habituellement, quelqu'un travaille plus lentement, quelqu'un part en vacances, quelqu'un a une dette technique qui doit être clôturée. Toute notre expérience dans la création et la prise en charge d'applications natives nous a incités - soit nous faisons quelque chose de mal, soit ce n'est tout simplement pas notre chemin. Et nous avons commencé à chercher la nôtre. Nous avons essayé React Native et Ionic, pensé à l'approche Basecamp - tout sur le web + une fine couche native, même essayé d'aller vers la Progressive Web App et de rester en ligne.

À peu près à la même époque, j'ai assisté à une conférence Google I / O et rencontré des gens qui y fabriquent Flutter. J'ai immédiatement essayé Dart et travaillé un peu sur Flutter, mais à cette époque, la technologie n'était pas encore prête pour Medusa: il était impossible d'incorporer divers matériaux interactifs et incorporés à l'intérieur de nos matériaux, mais cela est essentiel pour les médias. J'ai donc décidé d'attendre que Flutter grandisse.

Pendant l'attente, nous avons fait beaucoup de choses côté web: réécriture du site, écriture d'une nouvelle version d'AMP. Nous avons écrit et transféré tous les projets de Medusa vers ui-kit - une bibliothèque unique de composants que le site utilise et grâce à laquelle un grand nombre de nos mécanismes de jeu sont possibles. Nous avons divisé les versions de bureau et mobiles du site, de sorte que les pages de distribution (pages principale et section) ont commencé à se former à deux endroits différents selon leurs propres règles.

Parallèlement au travail sur le site, nous pensions à une nouvelle application - nous avons imaginé sa navigation, ses significations, ses écrans, ses fonctionnalités, etc.



Parallèlement, des changements importants ont eu lieu dans la structure du service technique. Nous avons commencé à utiliser activement le calendrier Google et d'autres outils de planification de réunions, et nous sommes passés de Trello à Basecamp. C'est tellement évident qu'il est même étrange d'en parler. Mais il a fallu beaucoup de temps et d'efforts pour rationaliser le chaos. Un ordre du jour clair des réunions, un suivi rapide, des fichiers qui ne sont pas perdus et des portées de carte de colline ont permis de faire face à un énorme flux de tâches et de ne pas mourir.

Pourquoi est-ce encore Flutter. Et un peu sur Dart


Lorsque les gens découvrent Flutter, ils apprennent inévitablement Dart. Il semble que ce soit considéré comme le plus gros inconvénient de Flutter, mais exactement jusqu'à ce que vous essayiez d'écrire dessus. Il est vraiment cool. Suivre JavaScript est tellement spécial.

Dart est un langage de programmation développé par Google. Il a été annoncé en 2011, c'est-à-dire qu'il s'agit encore d'une langue jeune. Il n'est pas devenu un langage de programmation majeur (du moins pour l'instant), mais en même temps, il est très activement utilisé dans l'entreprise elle-même. En plus de Google, il existe d'autres grandes entreprises, par exemple Wrike, qui utilisent Dart et y écrivent la pile complète.

Étant donné que Dart et Flutter sont pris en charge par la même entreprise, cela permet de changer la langue en fonction des besoins de Flutter. Pour autant que je sache, les deux équipes interagissent activement l'une avec l'autre, de sorte que les puces apparaissent constamment dans la langue, ce qui vous permet d'écrire du code plus agréable sur Flutter.

Je n'essaierai pas d'expliquer en quoi consiste Flutter - Wikipedia fera mieux face à cette tâche, mais je dirai seulement que parmi les auteurs, il y a des gens qui ont rendu dans Chromium.

En décembre 2018, l'équipe Flutter a publié la bibliothèque d'intégration Webview dans Flutter. Il était brut et, soit dit en passant, n'a toujours pas quitté le statut de prévisualisation des développeurs, mais ce fait n'a pas cessé de commencer à estimer la structure de la future application. Pendant plusieurs mois, j'ai expérimenté mon temps libre, puis une décision finale a été prise.

Au début, je me suis assis pour écrire une nouvelle version de l'API spécifiquement pour l'application. L'idéologie de cette API peut être formulée comme suit: si quelque chose peut être fait sur le backend, alors vous devez le faire sur le backend. Et pas parce qu'il est difficile de faire quelque chose sur le client. Le fait est que les sorties sur l'App Store et Google Play sont un processus laborieux et long. Vous devez vous adapter à leurs horaires de travail et n'oubliez pas que tous les utilisateurs ne mettront pas immédiatement à jour l'application. Cela peut être évité lorsque la logique principale se produit sur votre serveur. Besoin de déplacer le titre de 10 pixels vers le bas? Je vous en prie. Supprimer ou ajouter rapidement un composant? Pas de problème!



Pour la même raison, l'API pour une application mobile contient les composants les plus simples possibles, à partir desquels presque tous les matériaux sont collectés de manière récursive. Je dis «presque» parce que nous montrons des jeux via WebView. L'application n'a pas d'importance quoi montrer - une carte, un podcast, des nouvelles ou "Big Top". Tout est traité par un seul code, et la tâche de l'application est de prendre le composant et de le rendre (ou d'aller dans la liste de ses enfants et de l'appeler récursivement).

Autre argument important en faveur de Flutter: le développeur "contrôle tous les pixels". Lorsque vous devez vous assurer qu'il y a des ombres correctes partout, comme dans la mise en page dans Sketch, ou que vous souhaitez que la transparence change le long des courbes, ou que vous souhaitez que les tailles de police et toute la typographie soient personnalisables, tout est simple et réaliste dans Flutter.

Une autre caractéristique qui tue Flutter est le confort de développement. Le rechargement à chaud, auquel je suis si habitué dans le développement Web, et la vitesse rapide de rechargement de l'application sans perdre son état rendent le travail aussi simple que possible. Vous n'avez pas besoin de vous asseoir et d'attendre que l'application soit reconstruite, puis d'attendre que le nouveau code fonctionne et de répéter l'état dans lequel vous travaillez. Tout se passe vraiment vite et cool.

Écosystème


Bien que Flutter et Dart ne soient pas encore des technologies très populaires, nous n'avons eu aucun problème pour trouver des bibliothèques. La plupart de ce qui est nécessaire dans l'application se trouve dans le framework lui-même ou sur pub.dev. La communauté est très agréable et prête à aider. Cette communication est une véritable bouffée d'air frais, très solidaire.

De plus, Google lui-même prend bien en charge Flutter. Nous utilisons Firebase pour effectuer des poussées, des analyses, des profils et stocker des données utilisateur (lecture de l'historique, positions des épisodes, signets), et tout y fonctionne. Bien sûr, en tant que personne qui n'a jamais écrit d'applications natives auparavant, il est parfois délirant de grimper dans des fichiers gradle ou de mettre des propriétés dans info.plist. Mais généralement, tout est googlé, et il n'y a rien d'incroyablement compliqué.

Différences de plate-forme


Vous pouvez parler sans cesse de la différence entre iOS et Android. En règle générale, ils se souviennent immédiatement que les modèles doivent être familiers à l'utilisateur et que les directives de conception doivent être suivies. Nous sommes d'accord avec cela, mais pas tout à fait. Il est important de se souvenir de votre identité d'entreprise, du bon sens et de la logique de comportement des utilisateurs que vous connaissez déjà.

Si vous regardez l'historique des plates-formes elles-mêmes, nous voyons que certains modèles changent avec les appareils, tandis que d'autres circulent du système vers le système. Ce ne sont pas des tablettes, rien ne s'arrête. Il existe des dizaines d'exemples intéressants où les entreprises s'écartent des recommandations de Google et d'Apple et font ce qu'elles pensent être juste.



L'exemple le plus simple et le plus vivant est de glisser dans iOS. La zone de l'écran qui accepte le balayage est super petite par défaut, environ 20 pixels. C'est ainsi que l'application Mail fonctionne sur les iPhones, et c'est très gênant. Sur Twitter, cette zone est légèrement élargie, tandis que sur Telegram, elle est tout simplement énorme! Telegram sur Android a son propre type spécial de navigation de la liste de discussion au chat, c'est un croisement entre iOS et Android. Oui, les directives sont cool, mais sur l'iPhone XR, atteindre votre doigt vers le bord supérieur gauche de l'appareil est très gênant. Nous avons donc décidé (bien sûr, en nous appuyant sur les données) que dans l'application "Medusa", le bouton "Retour" sur iOS serait ci-dessous. Mais sur Android, ce ne sera pas du tout. Pour ce faire, il existe des svaypas (les nôtres et les nouveaux svaypas Android) et un bouton système "Retour".

Dit mon collègue, directeur artistique de Medusa Nastya Yarovaya:

J'ai de petites mains et un gros téléphone. Cela semble ridicule, mais cela a affecté deux décisions importantes dans le processus de développement. Tout d'abord, j'ai proposé d'augmenter considérablement la zone de balayage (augmentée à 50%) - la première déviation par rapport aux lignes directrices. Ensuite, lorsque nous avons travaillé sur les boutons de navigation et de fonction à l'intérieur du matériau, j'ai suggéré de mettre le bouton de retour dans le menu général ci-dessous - c'est une autre déviation du modèle habituel dans l'interface. Maintenant, vous pouvez l'atteindre avec votre pouce, car ils sont principalement défilés par lui.


Nous savons que nous allons certainement voler pour le fait que nous avons violé un certain nombre de recommandations d'Apple et de Google. Mais, si quoi que ce soit, nous utilisons également des téléphones et comprenons que de nombreux modèles sont obsolètes, car ils ont été inventés pour les appareils de moitié.

Un peu de pratique: comment ça marche à Flutter


Après React et d'autres frameworks réactifs, vous pouvez créer un prototype sur Flutter en quelques jours. Idée générale de Flutter - tout est un widget. Flutter donne deux (en fait trois) paradigmes: vous pouvez utiliser des widgets de matériaux qui suivent le concept de conception de matériaux. Vous pouvez utiliser des widgets Cupertino - des widgets qui ressemblent et se comportent comme sur iOS. Et vous pouvez tout écrire vous-même.

En gros, il existe deux types de widgets avec lesquels un développeur interagit: sans état et avec état.

Les widgets sans état sont des widgets plus ou moins qui ne contiennent pas de logique à l'intérieur qui devrait changer l'état du widget.

Les widgets avec état ont une fonction setState (bonjour, réagissez!). Vous changez d'état et le widget est redessiné.

Mais bien sûr, une grande application sur simple setState n'ira pas loin, donc une solution de gestion d'état est nécessaire.

Il existe plusieurs solutions pour Flutter. Par exemple, il existe un modèle BloC dans lequel des flux et des événements provenant de sources de données sont utilisés, ils contiennent une logique métier qui provoque la naissance de nouveaux événements. Ces événements sont entendus par les widgets et les widgets répondent aux changements.

Ceux qui viennent après React voudront peut-être essayer Redux. En théorie, il ne devrait pas y avoir de problème si vous avez écrit dans React en utilisant cette approche.

J'ai essayé les deux approches et j'ai fini par en choisir une troisième. L'application Jellyfish utilise Provider. Il s'agit d'une bibliothèque qui n'a pas été écrite par Google, mais il est intéressant de noter que Google, après avoir essayé Provider à la maison, a commencé à abandonner son BloC et a même décidé de répéter Provider en tant que bibliothèque distincte. Mais à la fin, il a abandonné l'idée de répéter le code de quelqu'un d'autre et a commencé à utiliser et à maintenir ce qui était né comme open source.

L'appareil Provider est assez simple. Il s'agit d'un widget dans lequel se trouve un état. Cet état est modifié par les fonctions qui appellent en interne notifyListeners (). Les widgets qui doivent répondre aux modifications se trouvent dans l'arborescence des widgets - ils sont soit les enfants directs du fournisseur de widgets, soit les enfants de ses enfants. Lorsque notifyListeners () est appelé, les enfants obtiennent de nouvelles valeurs via le contexte et la reconstruction se produit.

En règle générale, les fournisseurs sont annoncés tout en haut de l'application, et vous pouvez utiliser plusieurs fournisseurs à la fois - chacun est responsable de sa propre logique métier.

Nous utilisons maintenant huit fournisseurs qui «écoutent» à différents endroits de l'application. Par exemple, voici comment fonctionne le fournisseur de signets, grâce auquel les lecteurs peuvent enregistrer leurs documents préférés, les lire hors ligne et au même endroit sur différents appareils.

La réaction est ajoutée à l'instance aux modifications apportées au document à partir de Firebase, qui contient les clés des documents mis en signet par les lecteurs. Pour chaque onChange de ce document, la variable associée dans le fournisseur est mise à jour et notifyListeners est appelée. Par conséquent, tous les widgets qui écoutent ce fournisseur affichent l'icône correcte.

Grâce aux fournisseurs, le thème de l'application a également été changé. L'application a ThemeProvider, qui contient en soi deux instances de thèmes - et, en fait, c'est juste une carte avec notre dénomination des couleurs et les couleurs elles-mêmes.

En conséquence, la couleur correcte vient au widget comme ceci:

TextSpan(
	text: block['data']['first'],
	style: TextStyle(
		color: Provider.of<ThemeProvider>(context)
        .current
        .bodyFontColor,                            
  fontFamily: 'Proxima Nova',
));

Le code du fournisseur, s'il était simplifié, serait:

class ThemeProvider extends ChangeNotifier {
  CustomThemeData current;
  
  CustomThemeData blackTheme = CustomThemeData(
    name: 'black',
    bodyFontColor: Color.fromRGBO(184, 184, 184, 1),
    ...
  );
  
  CustomThemeData lightTheme = CustomThemeData(
    name: 'black',
    bodyFontColor: Color.fromRGBO(184, 184, 184, 1),
    ...
  );
  
  ThemeProvider(withTheme, withFontMultiplier, withAutoTheme) {
    theme = withTheme;
    autoTheme = withAutoTheme;
    current = withTheme == 'light' ? lightTheme : blackTheme;
  }
}

Par conséquent, lorsque vous modifiez la variable actuelle, tous les widgets qui prennent des couleurs du thème s'affichent correctement sans exception.

Et après


Ces dernières semaines, nous avons testé activement la nouvelle application sur un groupe de plusieurs centaines de lecteurs de Medusa. Nous vous expliquerons comment les tests se sont déroulés dans un article séparé, mais je noterai seulement que Flutter a répondu à toutes mes attentes. Oui, il a un moyen de développer, oui, pas toutes les bibliothèques riches en fonctionnalités, mais, observant la vitesse à laquelle tout cela se déplace, je conclus, du moins pour moi, que Flutter avec Medusa durera longtemps.

All Articles