«J'étais très négatif envers les coroutines»: Artyom Zinnatullin sur le développement Android



Parmi les développeurs Android, Artyom Zinnatullin est tellement respecté que vous pouvez composer un analogue des «faits sur Chuck Norris» à son sujet - quelque chose comme ceci:

  • Artyom est si sévère que quand il le voit, le github lui-même devient vert (lequel d'entre nous peut se vanter d' un tel calendrier de contributions?)
  • Artyom est si dur que pour lui, Git est un messager .
  • Artyom est si sévère que dans son contexte d'applications est un podcast .

Lorsque nous l'avons interviewé lors de notre conférence Mobius, il était destiné à une diffusion en ligne. Mais après avoir vu comment ils s'y réfèrent dans le chat Android, nous avons décidé que cela pourrait également intéresser beaucoup de gens sur Habré, et avons fait une version texte pour vous (nous joignons également l'enregistrement vidéo).

Comment vivre avec un projet sur un million de lignes de code? Quel est l'inconvénient de la corotine Kotlin? Quel est le problème avec Google? En quoi le développement à San Francisco est-il différent du russe? De quoi parlait Mobius? Sous la coupe - à propos de tout cela.


Evgeny Trifonov : À ce Mobius, j'ai raté votre discours «Android builds at Lyft», mais après cela, j'ai vu une foule de personnes souhaitant poser une question dans la zone de discussion. Et je voulais clarifier: mais après tout, la plupart des téléspectateurs ne travaillent pas dans un projet géant comme Lyft, cette expérience était-elle pertinente pour eux de toute façon?

Artyom : C'est une chose intéressante. Les grandes lignes du rapport dans ma tête et la façon dont je l'ai finalement mis en œuvre sont très différentes grâce à votre comité de programme chic.

Au départ, j'allais vous dire comment tout a commencé chez Lyft, pourquoi nous sommes arrivés à certaines solutions techniques. Il a parlé à Sergey Boishtyan du comité de programme pendant deux heures, il a écouté et a dit: "Cool, bien sûr, mais vous avez fait un discours." Et à la fin, j'ai réalisé qu'un tel rapport, bien sûr, est intéressant à écouter, mais il n'est vraiment pertinent pour personne.

Et puis je l'ai refait, en mettant l'accent sur les approches d'ingénierie fondamentales pour le choix des systèmes d'assemblage, d'autres systèmes. Je n'avais pas pour objectif de dire quels outils nous utilisons spécifiquement. Je ne veux pas que quelqu'un les prenne et commence à les utiliser aveuglément, puis écris-moi de formidables lettres qui ne fonctionnent pas comme je te l'ai dit. Je voulais transmettre exactement les pratiques d'ingénierie sur la façon de faire un choix et ce qui est important à mon avis (naturellement, subjectif). Par conséquent, j'espère qu'à la fin l'expérience sera pertinente pour plus de gens, et pas seulement "le mec de Lyft est sorti et a dit quelque chose".

Oleg olegchir Chirukhin : Existe-t-il des choix Lyft inhabituels difficiles à faire pour les autres?

Artyom : Oui, bien sûr. Nous avons deux systèmes de construction dans le projet en même temps, je ne recommande absolument personne (rires) .

C'est très douloureux à entretenir: on poursuit constamment deux oiseaux avec une pierre, dans les deux, quelque chose ne marche pas jusqu'au bout. Mais c'est notre état actuel, donc historiquement, parce qu'un système de construction a commencé à se taire sur une partie des tâches, nous avons dû en démarrer un deuxième. J'ai expliqué comment éviter cela et migrer correctement vers l'un d'eux.

Oleg : Et quel genre de systèmes de construction?

Artyom : Nous utilisons Gradle et Buck, et j'ai parlé de comment venir à Bazel depuis Google.

Oleg : C'est une sorte de mouvement vers le mal: de la jolie Gradle à Bazel, dans laquelle il n'y a même pas de dépendances normales.

Artyom : Maintenant, il y en a plus ou moins. Eh bien, oui, bien sûr, il y a des compromis, et, bien sûr, Gradle a ses mérites. Tout dépend du type de projet. Certains Gradle conviendront mieux que Buck et Bazel, car ils ont des points fondamentaux qu'ils ne collecteront pas progressivement dans le même module, mais Gradle le sera, et pour beaucoup, c'est très important. Et c'est cool que Gradle puisse faire ça.

Une autre chose est que lorsque vous ajoutez des modules - plus, plus de modules, huit cent, mille - Gradle est tellement repensé qu'il ralentit linéairement l'assemblage à certains endroits. Mais il me semble que Gradle peut arranger tout cela si la communauté fait pression sur eux - ce que je fais peut-être. Voyons voir. (note: quelques jours après cette interview, Artyom a écrit un long post sur les problèmes de Gradle)

Oleg: Autrement dit, Bazel uniquement parce que je veux prendre en charge un grand nombre de modules?

Artyom : Disons simplement que dans notre cas, nous ne le «voulons» pas, mais la division du projet en modules permet à notre entreprise de progresser plus rapidement. Fondamentalement, si je comprends bien, il s'agit d'isolement afin qu'il ne fonctionne pas sur les spaghettis, qui est alors difficile à entretenir. Les modules donnent plus de contrôle sur les parties du code qui interagissent avec lesquelles. Nous avons près d'un million de lignes de code. Si c'était dans un module, je devrais spaghetti. Parce qu'en plus du langage - Java, Kotlin - il faudra liquider quelque chose pour interdire les appels entre packages, entre lesquels personne ne les attendait. De plus, la question se posera que Gradle ne supprimera pas autant de code dans un module. Il ne le collectera pas en parallèle, l'assemblera progressivement à l'intérieur du module.

Chaque solution a des compromis. Dans notre cas, il me semble que c'est la bonne solution, mais il y a un problème: nous prenons actuellement en charge deux systèmes de build.

Oleg : Et quoi de mieux pour des centaines de modules: monorepo ou plusieurs référentiels?

Artyom : C'est un point très sensible. Un référentiel est probablement meilleur du point de vue du fait que vous n'avez pas à penser au versioning et il n'y a pas cet enfer de dépendance lorsque vous allez cloner une douzaine de référentiels pour effectuer un changement, puis ouvrir une demande de tirage et dix autres après. La «friction» est supprimée du système et les gens n'ont pas peur de changer le code. Pour eux, une atomicité de changements se produit: tout est regroupé en un seul projet, et les modifications d'un module sont automatiquement transférées à d'autres sans leur consentement explicite. Dans le même temps, toutes les vérifications que vous avez écrites automatiquement dans CI seront exécutées et vérifieront que le code est compilé, testé et tout cela.

Oleg : Et si vous n'arrivez pas au fait que vous, comme dans certains Chrome, les branches vont changer pendant deux minutes, pendant que vous buvez du thé?

Artyom : Oui, bien sûr, il y a une possibilité. Mais ici, probablement, la question est déjà dans la taille du produit: Chrome doit-il contenir autant de code? Peut-être vaut-il la peine de mettre en évidence certaines parties dans des instruments distincts, qu'elles resserrent périodiquement lorsque des changements majeurs se produisent dans ces instruments? C'est probablement une question pour l'organisation du projet. Un bel exemple, au fait. J'en ai un similaire: correspondance avec des mecs de Yandex.Browser, où ils ont aussi de gros plugs.

Chrome peut être divisé en plusieurs composants, et si vous prenez du V8 - je ne suis pas un grand spécialiste, mais pour autant que je sache, ce pourrait être un projet distinct en général, non? Et pourquoi, alors, l'interface graphique devrait-elle connaître le moteur, le remonter à chaque fois et penser au code source se trouvant quelque part à proximité? Soit dit en passant, Bazel le soutient également.

En général, maintenant tous les grands systèmes de construction - ce Gradle, ce Buck, ce Bazel - prennent en charge une chose telle que les constructions composites lorsque vous vous référez, par exemple, à un autre assemblage Bazel. C'est une situation délicate, mais, néanmoins, cela fonctionne, cela vous permet de supprimer une partie des fichiers du référentiel, de réduire la taille. L'IDE, par exemple, va devenir fou pour indexer tous ces fichiers, donc je veux les séparer en quelque sorte du composant général du projet.

Mais nous en sommes loin. Il me semble que nous pouvons tranquillement calculer encore cinq ans. Il est peu probable que nous nous heurtions encore à un paiement de deux minutes. Nous n'avons pas beaucoup de monde.

Eugene : Lyft a-t-il toujours ses propres spécificités, en plus de deux systèmes de construction?

Artyom : Oui, il y a quelques histoires atypiques là-bas. Il se trouve que les personnes qui sont venues dans l'entreprise (de Google, Facebook, partout dans le monde) détestent les mono-référentiels. En conséquence, chez Lyft, nous avons trois mono-référentiels: Android, iOS et L5 (ce sont nos voitures autonomes ).

Et tout le reste représente plus de 1 500 dépôts git: pour tous les microservices, pour toutes les bibliothèques séparément. C'est historiquement le cas. Cela a son propre prix énorme que nous payons: pousser les changements à travers eux est vraiment difficile. D'un autre côté, lorsque vous travaillez avec chacun d'eux, vous avez un clone git instantané, un push git instantané, tout est très rapide, les index IDE par seconde. Je peux dire que c'est vraiment une partie intéressante. Des mecs de San Francisco, je m'attendrais à un seul référentiel.

Oleg : Et lorsque l'un de ces référentiels séparés est mis à jour - l'API change, par exemple - comment ce changement s'applique-t-il au reste de l'entreprise?

Artyom: Ça fait mal. (rires) Eh bien, je ne suis pas un développeur de backend dans la mesure où je n'écris pas de backends de fonctionnalités, j'écris des backends d'infrastructure - ils sont généralement assez autonomes à cet égard.

En règle générale, ce n'est qu'un tas de rassemblements, d'interactions croisées, puis de planification.

Oleg: Les rassemblements font donc partie du système d'assemblage? (rire)

Artyom : Oui, nous devons d'abord assembler un rallye, puis assembler un référentiel. De plus, malheureusement, historiquement, nous avons beaucoup de ces microservices - c'est Python, qui a aussi ses propres blagues.

Oleg : Certains n'aiment pas Python.

Artyom : Plutôt détester pour la frappe dynamique. Python, pas Python - cela ne fait aucune différence, mais la saisie dynamique est une chose douloureuse.



Eugene : Et ça a glissé «pour une entreprise de San Francisco», et il est curieux de se poser la question: mais en termes de développement, les entreprises de San Francisco diffèrent des entreprises de Russie, y a-t-il une différence notable?

Artyom : Une très grande différence. Je ne suis pas un grand fan de le classer comme ça, mais il me semble que voici une école d'ingénieurs plus correcte.

Oleg : Ici - où est-il?

Artyom : En Russie, dans les pays de l'ex-URSS. Les gens accordent plus d'attention aux aspects techniques du fonctionnement des composants de leur système. Et aux États-Unis, il arrive souvent que certaines bibliothèques résolvent un problème, et les gens ne voient même pas comment il est mis en œuvre. En règle générale, ils ne se soucient absolument pas que cela ralentisse ou qu'ils l'utilisent incorrectement.

J'y interviewerai beaucoup de gens, car cela fait partie du travail, et le niveau général de connaissances, peut-être, est encore plus bas. Il y a quelque chose à changer. Chaque fois qu'une personne vient d'Europe de l'Est, cela devient plus intéressant lors des entretiens, car les gens n'ont pas peur de résister, de discuter quelque part. Bien que très souvent, les candidats américains ne répondent pas du tout aux questions ou répondent «Je ne me souviens pas de la dernière fois où je l'ai utilisé». Pour des questions comme "Comment fonctionne une requête HTTP?" ou "Quel format de données choisirez-vous?" ils ne peuvent pas donner de réponses d'ingénierie normales, mais disent: "Eh bien, je l'ai utilisé pendant les cinq dernières années." Cool, bien sûr, mais le seigneur ne tire pas.

D'un autre côté, il y a des projets qui ont mis des années à se comparer à ce que nous faisons ici. Les gens fabriquent plus de produits de masse et il y a simplement plus d'échelle. Par exemple, Chrome ou Uber - ils ont déjà plus d'un millier de modules là-bas. Ce n'est que l'ampleur des problèmes. Disons dans Uber moins de trois cents développeurs Android. La question se pose: pourquoi? (rires) Mais, néanmoins, ils ont réussi à faire fonctionner ce colosse, à le relâcher constamment. Je dirais que de tels problèmes sont moins fréquemment résolus ici.

Ici, Yandex est un bon exemple. J'ai un ami sur Yandex.Maps: dix personnes font une application Android. Dans Google, une centaine sont probablement assis. Et en même temps, Yandex.Mart a plus de fonctionnalités. C'est la différence, à mon avis.

Eugene : De plus, la vallée est également associée aux start-ups, et elles ont une approche «bouger vite et casser les choses», et il semble que cela devrait également affecter le développement: vivre à la pointe du progrès, utiliser les dernières. Est-ce vrai?

Artyom : Je ne travaillais pas dans des startups, Lyft est difficile d'appeler cela: il y a déjà trois mille trois personnes, quelque part plus d'un millier d'entre elles sont des ingénieurs. Autrement dit, c'est une entreprise déjà formée.

C'est une technologie de pointe qui est rarement utilisée. Si la technologie est en vogue, alors oui. Si la technologie est de niche, mais cool, très souvent non. Jusqu'à ce que toutes les conférences en parlent, très peu de gens l'utiliseront.

Mais en même temps, ce que j'aime vraiment (à San Francisco et en partie dans la vallée) - beaucoup de problèmes sont résolus du fait que les entreprises sont physiquement proches. Très souvent, vous écrivez à quelqu'un dans une salle de discussion: «Allons déjeuner ensemble chez nous ou dans votre bureau et décidons, nous avancerons une question», puis une fois - un projet open source ou une demande de pull apparaît dans un autre projet, quelque chose fixe.

Ce qui est intéressant: les gens discutent souvent de choses qui ne devraient en fait pas être discutées sur la NDA. Mais c'est ainsi que toute la vallée se déplace, à la fin tout le monde comprend où va le reste et toute l'industrie va de pair. Disons que les mobilisateurs de Lyft et Uber parlent constamment de choses techniques, car nous utilisons l'open source d'Uber. Et, bien sûr, il y a directement des experts hardcore dans certaines technologies. C'est aussi cool: vous pouvez simplement croiser avec eux.

J'adore ça, et cela ne m'a pas suffi dans certaines villes où j'habitais. Ici, à Saint-Pétersbourg, il y avait un groupe d'utilisateurs Java très cool (je ne sais pas comment c'est maintenant): vous venez après le travail, et Shipilev sort votre cerveau, et quelque chose est bien!

Et là, il apparaît à nouveau: par exemple, il a également son propre groupe d'utilisateurs Java, et il y a souvent des mecs, par exemple, d'Oracle, qui ont filmé un nouveau Reactive JDBC. Et vous vous asseyez, argumentez-vous, parce qu'un chef de projet Reactor ou un chef réactif au printemps est assis au même endroit, une discussion chaude est en cours, et c'est cool.

Oleg : Je vais poser une question sur autre chose: j'ai regardé le référentiel Mainframer, et Rust y est utilisé. Pourquoi tout cela n'est-il pas écrit sur la bienheureuse Javka, mais sur une sorte de rouille?

Artyom : Récemment, je suis allé du côté du fait que le programme devrait avoir une quantité minimale de ressources. Autrement dit, je veux être très proche de la façon dont le fer digère les octets. Et en Java, beaucoup de choses se passent autour (je ne parle même pas de la collecte des ordures), c'est-à-dire JIT et tout ça. J'aime vraiment que Java se dirige maintenant vers le fait qu'il y aura également une compilation à l'avance. Il me semble que ce sera très cool, par exemple, de commencer le lancement d'un microservice en téléchargeant depuis le cache sa compilation anticipée, qui s'est produite à l'origine sur d'autres machines, et en la démarrant très rapidement, sans s'échauffer. C'est cool, mais Java a un prix. Je ne peux pas simplement demander aux personnes qui construisent un projet iOS d’avoir Java sur leur système.

Mainframer a été à l'origine écrit dans le dialecte Bash. Mais je voulais le réécrire dans un langage système pour obtenir un multithreading normal, la possibilité d'écrire des tests unitaires normaux, et pas seulement des tests d'intégration en plus de l'utilitaire ...

Oleg : Et on pourrait prendre, par exemple, Python.

Artyom : Oui. Mais alors la question se poserait avec le fait que, d'une part, il s'agit de typage dynamique, et d'autre part ...

Oleg : Donc dans Bash aussi, la frappe dynamique.

Artyom : Je voulais donc le réécrire. Et en plus de cela, il y a un problème avec le fait que Python est maintenant deux: sur macOS, par défaut le deuxième, et presque tout sur Linux est maintenant le troisième. Il y a toutes sortes de blagues. Si j'ai besoin d'une sorte de dépendance pour me lier, je demanderai aux gens d'exécuter pip? Ou vais-je devoir la frapper?

Je voulais prendre un langage système qui ne nécessite aucune dépendance, afin que je puisse mettre un binaire qui pèsera, conditionnellement, moins d'un mégaoctet, et fonctionnera avec un minimum de surcharge.

Oleg : Vous pourriez prendre Golang, au moins il y a un ramasse-miettes.

Artyom : C'est exactement pourquoi je voulais essayer Rust. Et ça a marché. De plus, Golang est un peu triste avec les génériques.

Eugene : Depuis qu'ils ont commencé à discuter des langages ... Dans le contexte du développement Android, la question "Kotlin ou Java" est déjà fatiguée, mais je vais quand même la poser afin de passer à la question suivante.

Artyom : Eh bien, Kotlin, bien sûr.

Eugene : Maintenant, la question qui intéresse vraiment. Récemment, à Kotlin, les coroutines sont devenues stables et les voix «Hourra, éloignons-nous de RxJava» se font entendre. Par conséquent, quand je vois une personne en face de moi qui est très proche de RxJava, je veux immédiatement lui demander son avis sur les coroutines.

Artyom : J'étais très négatif envers les coroutines. En principe, il est toujours majoritairement négatif, mais cela a en partie changé la très longue conversation avec Roma Elizarov , qui y travaille.

En tant qu'utilisateur de programmes, je veux qu'ils soient aussi non bloquants que possible, pour utiliser les ressources aussi correctement que possible. J'entends par là à la fois le parallélisme et le fait qu'ils utilisent les bonnes API du système d'exploitation pour l'accès non bloquant au réseau ou aux fichiers - il y a beaucoup de problèmes avec cela dans les systèmes d'exploitation, mais, néanmoins, il existe de telles API. Qu'est-ce que cela résout exactement? En tant qu'utilisateur, cela n'a pas d'importance pour moi - si seulement les développeurs pouvaient résoudre ce problème d'une manière qui les rendait confortables. Je n'ai pas de gros problèmes avec ça. Et c'est la vision de Roma Elizarov. Après cette conversation, je l'ai en quelque sorte laissé tomber.

Avant cela, comme mon ami Arthur Dremov , cela me semblait un pas en arrière après plusieurs années d'utilisation de Java en production: le code redevient impératif, impur, il perd la compréhension du pipeline, il redevient un gâchis, que le compilateur transforme pour vous en un gâchis asynchrone.

Je n'utilise pas de coroutines, mais tous les exemples que j'observe maintenant sont passés à une approche structurée, quand vous ne voyez même pas quel morceau de code de cette coroutine. Pour être honnête, j’ai très peur de le regarder. Parce que j'ouvre la demande de pull sur GitHub, certaines méthodes sont appelées pour télécharger l'image et le profil, l'une d'entre elles va au réseau, et l'autre va au SQLite local, et ici le SQLite local peut facilement être bloquant. Je ne vois pas cela dans le code, car les coroutines sont conçues pour que vous ne les voyiez pas. C'est peut-être bien, mais pour moi, c'est toujours un inconvénient de la conception, car dans les approches Rx, c'est très évident: comprenez-vous si cela fait partie du pipeline synchrone ou non.

C'est peut-être ma seule plainte aux coroutines: je veux voir quand mon asynchronie se produit, et quand ce n'est pas le cas. Idéalement, je veux que les gens écrivent du code plus fonctionnel quand il y a de petites pièces réutilisables, ou du moins testables qui se combinent avec d'autres. Et nous revenons au fait que tout cela est intégré dans la logique, puis le compilateur le retourne simplement.

Oleg : Permettez-moi de vous opposer un peu. Le code hérité est bien plus que nouveau. Et si nous prenons des choses comme travailler avec le réseau, travailler avec des fichiers, etc., personne ne réécrira rapidement tout cela, par exemple, en utilisant RxJava. Et si nous avons des routines automatiques, nous pouvons, par exemple, suivre tous les appels système, les envelopper automatiquement et les envoyer à la serrure pour le stationnement.

Artyom : Vrai, dans tous les cas, vous devrez appeler des fonctions à partir du contexte de la corutine. Mais c'est une pensée intéressante, oui.

Oleg : Peut-être qu'ils devraient être combinés d'une manière ou d'une autre? L'API de niveau supérieur sera sur RxJava et l'API de bas niveau sur les coroutines.

Artyom : Oui, il y a maintenant de tels changements. Mais alors la question se pose, car pour le moment, RxJava peut faire tout ce que font les coroutines, et les coroutines ne peuvent pas faire tout ce que fait RxJava. , — . , , , - Rx Kotlin. . forEach - map, . , , Java- , . .

, Kotlin — . , Go , , API, , : . , , , , legacy, , . , Java Kotlin — legacy, , . , . - , .

, , . , , , — . .



: , . , , : Android-? , .

: … . , Android- . , . , : , . RxJava , : - . , , .

, iOS. , Lyft iOS- dependency injection RxSwift. 2019-. iOS-, , , clean, . , Android — .

, , — Google. « opinionated, , : , , ». — , , .

, «RxJava — , ...» : «, LiveData». , — RxJava, , . , , Google , .

: «, Google MVVM». , MVVM , , , MVVM . , Google.

, , scope . .

: , Room . - Architecture Components — , . Google , ? .

: , . , . !

: .

Le prochain Mobius se tiendra à Saint-Pétersbourg les 22 et 23 mai . Maintenant, son programme n'a pas encore été annoncé, mais c'est le moment le plus rentable pour acheter un billet: le 1er février, le prix des billets va augmenter. Et puis, comme le programme n'est pas encore terminé, le moment est également propice pour y entrer nous-mêmes: nous sommes en plein essor acceptant les candidatures aux rapports. Toutes les informations sur la conférence et les billets sont sur le site .

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


All Articles