"Fui muy negativo hacia las corutinas": Artyom Zinnatullin sobre el desarrollo de Android



Entre los desarrolladores de Android, Artyom Zinnatullin es tan respetado que puedes componer un análogo de "hechos sobre Chuck Norris" sobre él, algo como esto:

  • Artyom es tan duro que cuando lo ve, el github se pone verde (¿cuál de nosotros puede presumir de tal calendario de contribuciones?)
  • Artyom es tan duro que para él Git es un mensajero .
  • Artyom es tan duro que en su contexto de aplicaciones es un podcast .

Cuando lo entrevistamos en nuestra conferencia de Mobius, estaba destinado a una transmisión en línea. Pero después de ver cómo se refieren a él en el chat de Android, decidimos que también podría ser de interés para muchos en Habré, e hicimos una versión de texto para usted (también adjuntamos la grabación de video).

¿Cómo vivir con un proyecto en un millón de líneas de código? ¿Cuál es la desventaja de la corotina Kotlin? ¿Qué le pasa a Google? ¿En qué se diferencia el desarrollo en San Francisco del ruso? ¿De qué hablaba Mobius? Debajo del corte, sobre todo esto.


Evgeny Trifonov : En este Mobius, me perdí tu charla "Las compilaciones de Android en Lyft", pero luego vi una multitud de personas que deseaban hacer una pregunta en el área de discusión. Y quería aclarar: pero después de todo, la mayoría de los espectadores no están trabajando en un proyecto gigante como Lyft, ¿fue esta experiencia relevante para ellos de todos modos?

Artyom : Esto es algo interesante. El resumen original del informe en mi cabeza, y la forma en que finalmente lo implementé, son muy diferentes gracias a su elegante comité de programa.

Inicialmente, iba a contarles cómo comenzó todo en Lyft, por qué llegamos a ciertas soluciones técnicas. Habló con Sergey Boishtyan del comité del programa durante dos horas, escuchó y dijo: "Genial, por supuesto, pero hiciste el discurso principal". Y al final, me di cuenta de que ese informe, por supuesto, es interesante de escuchar, pero realmente no es relevante para nadie.

Y luego lo rehice, cambiando el énfasis a los enfoques de ingeniería fundamentales para la elección de sistemas de ensamblaje, otros sistemas. No tenía el objetivo de decir qué herramientas usamos específicamente. No quiero que alguien tome y empiece a usarlos a ciegas, y luego me escriba cartas formidables que no todo funciona como te dije. Quería transmitir exactamente las prácticas de ingeniería sobre cómo hacer una elección y lo que es importante en mi opinión (naturalmente, subjetiva). Por lo tanto, espero que al final la experiencia sea relevante para más personas, y no solo "el tipo de Lyft salió y dijo algo".

Oleg olegchir Chirukhin : ¿Hay elecciones inusuales de Lyft que sean difíciles de tomar para otros?

Artyom : Sí, por supuesto. Tenemos dos sistemas de compilación en el proyecto al mismo tiempo, no recomiendo absolutamente a nadie (risas) .

Es muy doloroso mantenerlo: persigues constantemente a dos pájaros de un tiro, en ambos, algo no funciona hasta el final. Pero este es nuestro estado actual, por lo que históricamente, debido a que un sistema de compilación comenzó a callarse en parte de las tareas, tuvimos que comenzar el segundo. Hablé sobre cómo evitar esto y migrar correctamente a uno de ellos.

Oleg : ¿Y qué tipo de sistemas de compilación?

Artyom : Usamos Gradle y Buck, y hablé sobre cómo llegar a Bazel desde Google.

Oleg : Este es algún tipo de movimiento hacia el mal: desde la bonita Gradle hasta Bazel, en la que ni siquiera hay dependencias normales.

Artyom : Ahora hay más o menos. Bueno, sí, por supuesto, hay compensaciones y, por supuesto, Gradle tiene sus méritos. Todo depende del tipo de proyecto. Algunos Gradle serán más adecuados que Buck y Bazel, porque tienen algunos puntos fundamentales que no se acumularán gradualmente dentro del mismo módulo, pero Gradle lo será, y para muchos esto es muy importante. Y es genial que Gradle pueda hacer eso.

Otra cosa es que cuando agrega módulos (más, más módulos, ochocientos mil), Gradle está tan rediseñado que ralentizará linealmente el ensamblaje en algunos lugares. Pero me parece que Gradle puede arreglar todo esto si la comunidad los presiona, lo que tal vez estoy haciendo. A ver (nota: unos días después de esta entrevista, Artyom escribió una larga publicación sobre los problemas de Gradle)

Oleg: Es decir, ¿Bazel solo porque quiero admitir una gran cantidad de módulos?

Artyom : Digamos que en nuestro caso no "tenemos ganas", pero dividir el proyecto en módulos permite que nuestro negocio avance más rápido. Básicamente, según tengo entendido, esto es aislamiento, por lo que no funciona el espagueti, que es difícil de mantener. Los módulos dan más control sobre qué partes del código interactúan con cuáles. Tenemos casi un millón de líneas de código. Si estuviera en un módulo, tendría que hacer spaghetti. Porque además del lenguaje, Java, Kotlin, será necesario terminar algo para prohibir las llamadas entre paquetes, entre los cuales nadie los esperaba. Además, surgirá la pregunta de que Gradle no eliminará tanto código en un módulo. No lo recogerá en paralelo, arme de manera incremental dentro del módulo.

Cada solución tiene compensaciones. En nuestro caso, me parece que esta es la solución correcta, pero hay un problema, ya que actualmente admitimos dos sistemas de compilación.

Oleg : ¿Y qué es mejor para cientos de módulos: monorepo o muchos repositorios?

Artyom : Este es un punto muy doloroso. Probablemente un repositorio es mejor desde el punto de vista de que no tiene que pensar en el control de versiones y no hay un infierno de dependencia cuando clona una docena de repositorios para hacer un cambio, y luego abre una solicitud de extracción y una docena después. La "fricción" se elimina del sistema y las personas no tienen miedo de cambiar el código. Para ellos, surge una atomicidad de cambios: todo se combina en un proyecto y los cambios de un módulo se transfieren automáticamente a otros sin su consentimiento explícito. Al mismo tiempo, todas las comprobaciones que escribió automáticamente en CI se ejecutarán y verificarán que el código se compila, se prueba y todo esto.

Oleg : ¿Y si no llegas al hecho de que, como en algunos Chrome, las ramas cambiarán durante dos minutos, mientras tomas té?

Artyom : Sí, por supuesto, existe la posibilidad. Pero aquí, probablemente, la pregunta ya está en el tamaño del producto: ¿Chrome necesita contener tanto código? ¿Quizás valga la pena resaltar algunas partes en instrumentos separados, que se ajustarán periódicamente cuando ocurran cambios importantes en ellos? Esta es probablemente una pregunta para la organización del proyecto. Buen ejemplo, por cierto. Tengo uno similar: correspondencia con tipos de Yandex.Browser, donde también tienen enchufes grandes.

Chrome se puede dividir en varios componentes, y si tomas algunos V8, no soy un gran especialista, pero por lo que entiendo, podría ser un proyecto separado en general, ¿verdad? ¿Y por qué, entonces, la GUI debe saber sobre el motor, volver a ensamblarlo cada vez y pensar en el código fuente que se encuentra cerca? Bazel, por cierto, también es compatible con esto.

En general, ahora todos los grandes sistemas de compilación, ese Gradle, ese Buck, ese Bazel, admiten cosas como compilaciones compuestas cuando se refiere, por ejemplo, a otro ensamblaje de Bazel. Esta es una situación difícil, pero, sin embargo, funciona, le permite eliminar parte del archivo del repositorio y reducir el tamaño. El IDE, por ejemplo, se volverá loco al indexar todos estos archivos, por lo que quiero separarlos de alguna manera del componente general del proyecto.

Pero estamos lejos de eso. Me parece que podemos imaginarnos con calma otros cinco años. Es poco probable que encontremos un pago de dos minutos todavía. No tenemos mucha gente.

Eugene : ¿Lyft todavía tiene sus propios detalles, además de dos sistemas de compilación?

Artyom : Sí, hay un par de historias atípicas allí. Dio la casualidad de que las personas que vinieron a la empresa (de Google, Facebook, en todas partes) odian los mono-repositorios. Como resultado, en Lyft tenemos tres mono-repositorios: Android, iOS y L5 (estos son nuestros autos autónomos ).

Y todo lo demás son más de 1.500 repositorios git: para todos los microservicios, para todas las bibliotecas por separado. Este es históricamente el caso. Esto tiene su propio precio enorme que pagamos: impulsar los cambios a través de ellos es realmente difícil. Por otro lado, cuando trabajas con cada uno de ellos, tienes clon git instantáneo, push git instantáneo, todo es muy rápido, el IDE indexa por segundo. Puedo decir que esta es realmente una parte interesante. De los tipos de San Francisco, esperaría un solo repositorio.

Oleg : Y cuando se actualiza uno de estos repositorios separados, la API cambia, por ejemplo, ¿cómo se aplica este cambio al resto de la empresa?

Artyom: duele. (Risas) Bueno, no soy un desarrollador de back-end en el sentido de que no escribo backends de características, escribo backends de infraestructura, generalmente son bastante autónomos en este sentido.

Como regla general, esto es solo un grupo de manifestaciones, interacción cruzada y luego planificación.

Oleg: ¿Entonces las manifestaciones son parte del sistema de ensamblaje? (risa)

Artyom : Sí, primero tenemos que armar un rally, luego armar un repositorio. Además, desafortunadamente, históricamente, tenemos muchos de estos microservicios: este es Python, que también tiene sus propios chistes.

Oleg : Se disipó algo de Python.

Artyom : Más bien no me gusta la escritura dinámica. Python, no Python: no hay diferencia, pero la escritura dinámica es algo doloroso.



Eugene : Y se deslizó "para una compañía de San Francisco", y es curioso preguntar esto: pero en términos de desarrollo, las compañías de San Francisco difieren de las compañías de Rusia, ¿hay una diferencia notable?

Artyom : Una gran diferencia. No soy un gran admirador de clasificarlo así, pero me parece que aquí hay una escuela de ingeniería más correcta.

Oleg : Aquí, ¿dónde está?

Artyom : En Rusia, en los países de la antigua URSS. Las personas prestan más atención a los aspectos técnicos de cómo funcionan los componentes de su sistema. Y en los Estados Unidos a menudo sucede que algunas bibliotecas resuelven un problema, y ​​las personas ni siquiera miran cómo se implementa. A ellos, por regla general, no les importa que se desacelere o que lo usen incorrectamente.

Entrevistaré a muchas personas allí, porque esto es parte del trabajo, y el nivel general de conocimiento, tal vez, es aún más bajo. Hay algo que cambiar. Cada vez que una persona viene de Europa del Este, se vuelve más interesante durante las entrevistas, porque las personas no tienen miedo de resistirse, de discutir en alguna parte. Si bien los candidatos estadounidenses a menudo no responden preguntas o responden "No recuerdo cuándo la usé por última vez". Para preguntas como "¿Cómo funciona una solicitud HTTP?" o "¿Qué formato de datos elegirás?" no pueden dar respuestas de ingeniería normales, pero dicen: "Bueno, he usado esto durante los últimos cinco años". Genial, por supuesto, pero el señor no tira.

Por otro lado, hay proyectos que tomaron años para comparar con lo que estamos haciendo aquí. La gente fabrica más productos en masa, y simplemente hay más escala. Por ejemplo, Chrome o Uber: ya tienen más de mil módulos allí. Esto es solo la escala de los problemas. Digamos en Uber menos de trescientos desarrolladores de Android. Surge la pregunta: ¿por qué? (Risas) Pero, sin embargo, lograron hacer que este coloso funcionara, se liberara constantemente. Diría que estos problemas se resuelven con menos frecuencia aquí.

Aquí Yandex es un buen ejemplo. Tengo un amigo en Yandex. Mapas: diez personas crean una aplicación de Android. En Google, probablemente cien estén sentados. Y al mismo tiempo, Yandex.Mart tiene más funcionalidad. Esa es la diferencia, en mi opinión.

Eugene : Además, el Valle también está asociado con nuevas empresas, y tienen un enfoque de "moverse rápido y romper cosas", y parece que esto también debería afectar el desarrollo: vivir en la vanguardia, usar lo último. ¿Es eso cierto?

Artyom : No trabajé en startups, Lyft es difícil de llamar así: ya hay tres mil tres personas, en algún lugar más de mil son ingenieros. Es decir, es una empresa ya formada.

Es una tecnología de punta que rara vez se usa. Si la tecnología es publicitada, entonces sí. Si la tecnología es nicho, pero genial, muy a menudo no. Hasta que todas las conferencias hablen de ello, muy pocas personas lo usarán.

Pero, al mismo tiempo, lo que realmente amo (en San Francisco y en parte en el Valle): muchos problemas se resuelven debido al hecho de que las empresas están físicamente cercanas. Muy a menudo le escribes a alguien en una sala de chat: “Almorcemos juntos en nuestro lugar o en tu oficina y decidimos, avanzaremos alguna pregunta”, y luego una vez: un proyecto de código abierto o solicitud de extracción aparece en otro proyecto, algo arreglado

Lo que es interesante: las personas a menudo discuten cosas que en realidad no deberían discutirse en el NDA. Pero así es como se mueve todo el Valle, al final todos entienden hacia dónde se mueve el resto, y toda la industria se une. Digamos que los activistas de Lyft y Uber hablan constantemente de cuestiones técnicas, porque utilizamos código abierto de Uber. Y, por supuesto, hay expertos directos en algunas tecnologías. Esto también es genial: puedes cruzarte con ellos.

Me encanta esto, y esto no fue suficiente para mí en algunas ciudades donde vivía. Aquí en San Petersburgo había un grupo de usuarios de Java muy bueno (no sé cómo es ahora): vienes después del trabajo, y Shipilev te saca el cerebro, ¡y algo es bueno!

Y allí aparece de nuevo: por ejemplo, también tiene su propio Grupo de usuarios de Java, y a menudo vienen tipos, por ejemplo, de Oracle, que filmó algunos nuevos JDBC reactivos. Y te sientas, discutes, porque algún líder del Proyecto Reactor o líder Reactivo en Spring está sentado en el mismo lugar, hay una discusión candente y esto es genial.

Oleg : Preguntaré sobre otra cosa: miré el repositorio de Mainframer, y Rust se usa allí. ¿Por qué todo esto no está escrito en el bendito Javka, sino en algún tipo de óxido?

Artyom : Recientemente, he pasado al lado de que el programa debería tener una cantidad mínima de recursos. Es decir, quiero estar muy cerca de cómo el hierro digiere los bytes. Y en Java, están sucediendo muchas cosas (ni siquiera estoy hablando de recolección de basura), es decir, JIT y todo esto. Realmente me gusta que Java ahora se esté moviendo hacia el hecho de que también habrá una compilación anticipada. Me parece que sería genial, por ejemplo, comenzar el lanzamiento de un microservicio descargando de la caché su compilación anticipada, que originalmente ocurrió en algunas otras máquinas, y comenzando muy rápidamente, sin calentar. Esto es genial, pero Java tiene un precio. No puedo pedirles a las personas que están creando un proyecto de iOS que tengan Java en su sistema.

Mainframer fue escrito originalmente en el dialecto Bash. Pero quería reescribirlo en un lenguaje de sistema para obtener subprocesos múltiples normales, la capacidad de escribir pruebas unitarias normales y no solo pruebas de integración además de la utilidad ...

Oleg : Y uno podría tomar, por ejemplo, Python.

Artyom : si. Pero entonces la pregunta surgiría con el hecho de que, en primer lugar, se trata de una tipificación dinámica, y en segundo lugar ...

Oleg : Entonces, en Bash, también, escritura dinámica.

Artyom : Entonces quería reescribirlo. Y además de esto, hay un problema con el hecho de que Python ahora es dos: en macOS, por defecto el segundo, y casi todo en Linux es ahora el tercero. Hay todo tipo de chistes. Si necesito algún tipo de adicción para unirme, ¿le pediré a la gente que haga pip? ¿O tendré que golpearla?

Quería tomar un lenguaje de sistema que requiera cero dependencias, para poder poner un binario que pesará, condicionalmente, menos de un megabyte, y trabajará con una sobrecarga mínima.

Oleg : Puedes tomar Golang, al menos hay un recolector de basura.

Artyom : Eso es exactamente por qué quería probar Rust. Y funcionó. Además, Golang está un poco triste con los genéricos.

Eugene : Desde que comenzaron a discutir idiomas ... En el contexto del desarrollo de Android, la pregunta "Kotlin o Java" ya está cansada, pero aún así la haré para continuar con la siguiente pregunta.

Artyom : Bueno, Kotlin, por supuesto.

Eugene : Ahora la pregunta que realmente interesa. Recientemente, en Kotlin, las corutinas se estabilizaron y se escuchan las voces "¡Hurra, alejémonos de RxJava"! Por lo tanto, cuando veo a una persona frente a mí que está muy cerca de RxJava, inmediatamente quiero pedirle su opinión sobre las corutinas.

Artyom : Fui muy negativo hacia las corutinas. En principio, sigue siendo mayormente negativo, pero esto ha cambiado en parte la larga conversación con Roma Elizarov , quien está trabajando en ellos.

Como usuario de programas, quiero que sean tan libres de bloqueos como sea posible, para que utilicen los recursos lo más correctamente posible. Con esto quiero decir tanto paralelismo como el hecho de que usan las API correctas del sistema operativo para el acceso sin bloqueo a la red o los archivos; existen muchos problemas con esto en los sistemas operativos, pero, sin embargo, existen tales API. ¿Qué resuelve esto exactamente? Como usuario, no me importa, si solo los desarrolladores resolvieran este problema para que se sintieran cómodos. No tengo grandes problemas con esto. Y esta es la visión de Roma Elizarov. Después de esta conversación, de alguna manera la dejé pasar.

Antes de esto, como mi amigo Arthur Dremov , me pareció un paso atrás después de varios años de usar Java en producción: el código nuevamente se vuelve imperativo, sucio, pierde la comprensión de la tubería, nuevamente se convierte en un desastre, que el compilador convierte en un desastre asincrónico para usted.

No uso corutinas, pero todos los ejemplos que estoy observando ahora han cambiado a un enfoque estructurado, cuando ni siquiera ves qué código de esto es corutina. Para ser sincero, tengo mucho miedo de verlo. Como abro la solicitud de extracción en GitHub, se llaman algunos métodos para cargar la imagen y el perfil, uno de ellos va a la red y el otro va al SQLite local, y aquí el SQLite local puede bloquearse fácilmente. No veo esto en el código, porque las corutinas están hechas para que no lo veas. Tal vez sea bueno, pero para mí esto sigue siendo una desventaja del diseño, porque en los enfoques Rx es muy obvio: ¿entiendes si esto es parte de la tubería síncrona o no?

Quizás esta sea mi única queja para las corutinas: quiero ver cuándo ocurre mi asincronía y cuándo no. Idealmente, quiero que las personas escriban más código funcional cuando hay pequeñas piezas reutilizables, o al menos comprobables, que se combinan con otras. Y volvemos al hecho de que todo está en línea con la lógica, y luego el compilador simplemente lo voltea.

Oleg : Déjame darte una pequeña oposición. El código heredado es mucho más que nuevo. Y si tomamos algunas cosas como trabajar con una red, trabajar con archivos, etc., nadie reescribirá rápidamente todo esto, por ejemplo, usando RxJava. Y si tenemos autocorutinas, entonces podemos, por ejemplo, rastrear todas las llamadas al sistema, envolverlas automáticamente y enviarlas a la cerradura para estacionar.

Artyom : Es cierto, en cualquier caso, tendrá que llamar a funciones desde el contexto de la corutina. Pero este es un pensamiento interesante, sí.

Oleg : ¿Tal vez deberían combinarse de alguna manera? La API de nivel superior estará en RxJava, y la API de bajo nivel en corutinas.

Artyom : Sí, ahora hay tales cambios. Pero entonces surge la pregunta, porque en este momento, RxJava puede hacer todo lo que hacen las corutinas, y las corutinas no pueden hacer todo lo que RxJava hace. , — . , , , - 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 , ? .

: , . , . !

: .

Mobius 22-23 . , : 1 . , , , : . — .

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


All Articles