Muchos lingüistas creen que el lenguaje natural que habla una persona afecta su forma de pensar . ¿Se aplica el mismo concepto a los lenguajes de programación? Los programadores que trabajan en diferentes tipos de lenguajes de programación a menudo encuentran soluciones radicalmente diferentes a los problemas. Como un ejemplo más extremo, los científicos informáticos eliminaron la declaración goto para fomentar programas más estructurados (no es lo mismo que los líderes totalitarios en la novela 1984 que eliminan las palabras heréticas del lenguaje natural para eliminar los delitos de pensamiento, pero se entiende la idea).
¿Qué tiene esto que ver con Flutter y Dart ? Un poco en realidad. El primer equipo de Flutter evaluó más de una docena de idiomas y eligió Dart porque coincidía con la forma en que creaban las interfaces de usuario.
Dart es una gran razón por la que a los desarrolladores les encanta Flutter. Como dice un tuit :
El resto de este artículo profundiza en muchas de las características de Dart (incluidas sus bibliotecas estándar) que lo convierten en el mejor lenguaje para implementar Flutter .
[Puede omitir esta sección si ya conoce temas como lenguajes estáticos versus dinámicos, compilación AOT y JIT y máquinas virtuales.]
Históricamente, los lenguajes informáticos se han dividido en dos grupos: lenguajes estáticos (p. ej., Fortran o C, donde las variables se escriben estáticamente en tiempo de compilación) y lenguajes dinámicos (p. ej., Smalltalk o JavaScript, donde el tipo de una variable puede cambiar en el momento de la ejecución). tiempo). Los lenguajes estáticos generalmente se compilaban para producir programas de código de máquina nativo (o código ensamblador ) para la máquina de destino, que en tiempo de ejecución eran ejecutados directamente por el hardware. Los lenguajes dinámicos fueron ejecutados por un intérprete, sin producir código de lenguaje de máquina.
Por supuesto, las cosas eventualmente se volvieron mucho más complicadas. Se hizo popular el concepto de una máquina virtual (VM), que en realidad es solo un intérprete avanzado que imita una máquina de hardware en el software. Una máquina virtual facilita la migración de un idioma a nuevas plataformas de hardware. En este caso, el idioma de entrada de una máquina virtual suele ser un idioma intermedio . Por ejemplo, un lenguaje de programación (como Java ) se compila en un lenguaje intermedio (código de bytes ) y luego se ejecuta en una máquina virtual (la JVM ).
Además, ahora hay compiladores justo a tiempo (JIT) . Un compilador JIT se ejecuta durante la ejecución del programa, compilando sobre la marcha. Los compiladores originales que se ejecutan durante la creación del programa (antes del tiempo de ejecución) ahora se denominan compiladores adelantados (AOT) .
En general, solo los lenguajes estáticos son aptos para la compilación AOT en código de máquina nativo porque los lenguajes de máquina generalmente necesitan conocer el tipo de datos, y en los lenguajes dinámicos el tipo no se fija con anticipación. En consecuencia, los lenguajes dinámicos suelen interpretarse o compilarse JIT.
Cuando la compilación AOT se realiza durante el desarrollo, invariablemente da como resultado ciclos de desarrollo mucho más lentos (el tiempo entre realizar un cambio en un programa y poder ejecutar el programa para ver el resultado del cambio). Pero la compilación AOT da como resultado programas que pueden ejecutarse de manera más predecible y sin pausas para el análisis y la compilación en tiempo de ejecución. Los programas compilados de AOT también comienzan a ejecutarse más rápido (porque ya se han compilado).
Por el contrario, la compilación JIT proporciona ciclos de desarrollo mucho más rápidos, pero puede resultar en una ejecución más lenta o entrecortada. En particular, los compiladores JIT tienen tiempos de inicio más lentos, porque cuando el programa comienza a ejecutarse, el compilador JIT tiene que realizar análisis y compilación antes de que se pueda ejecutar el código. Los estudios han demostrado que muchas personas abandonarán una aplicación si tarda más de unos segundos en comenzar a ejecutarse .
Ese es el final de la información de fondo. ¿No sería increíble combinar las ventajas de la compilación AOT y JIT? sigue leyendo
Antes de trabajar en Dart, los miembros del equipo de Dart realizaron un trabajo innovador en compiladores avanzados y máquinas virtuales, tanto para lenguajes dinámicos (como el motor V8 para JavaScript y Strongtalk para Smalltalk) como para lenguajes estáticos (como el compilador Hotspot para Java). Usaron esta experiencia para hacer que Dart fuera inusualmente flexible en la forma en que se puede compilar y ejecutar.
Dart es uno de los pocos lenguajes (y quizás el único lenguaje "principal") que se adapta bien para ser compilado tanto AOT como JIT. La compatibilidad con ambos tipos de compilación brinda ventajas significativas a Dart y (especialmente) a Flutter.
La compilación JIT se usa durante el desarrollo, utilizando un compilador que es especialmente rápido. Luego, cuando una aplicación está lista para su lanzamiento, se compila AOT. En consecuencia, con la ayuda de herramientas y compiladores avanzados, Dart puede ofrecer lo mejor de ambos mundos: ciclos de desarrollo extremadamente rápidos y tiempos de ejecución y puesta en marcha rápidos.
La flexibilidad de Dart en compilación y ejecución no termina ahí. Por ejemplo, Dart se puede compilar en JavaScript para que los navegadores puedan ejecutarlo. Esto permite la reutilización de código entre aplicaciones móviles y aplicaciones web. Los desarrolladores han reportado hasta un 70% de reutilización de código entre sus aplicaciones móviles y web. Dart también se puede usar en un servidor ya sea compilando en código nativo o compilando en JavaScript y usándolo con node.js.
Finalmente, Dart también proporciona una máquina virtual independiente que usa el propio lenguaje Dart como su lenguaje intermedio (esencialmente actuando como un intérprete).
Dart se puede compilar AOT o JIT de manera eficiente, interpretar o transpilar a otros idiomas. La compilación y ejecución de Dart no solo es inusualmente flexible, sino que es especialmente rápida .
La siguiente sección proporciona un ejemplo de cómo la velocidad de compilación de Dart puede cambiar las reglas del juego...
Una de las características más populares de Flutter es su recarga en caliente extremadamente rápida. Durante el desarrollo, Flutter usa un compilador JIT que puede recargar y continuar ejecutando el código, generalmente en menos de un segundo. El estado de la aplicación se conserva entre recargas siempre que sea posible, por lo que la aplicación puede continuar desde donde la dejó.
Recarga en caliente con estado de subsegundos de Flutter
Es difícil apreciar lo importante que puede ser una recarga en caliente realmente rápida (y confiable) durante el desarrollo, a menos que lo haya experimentado usted mismo. Los desarrolladores informan que cambia la forma en que crean sus aplicaciones, y lo describen como si pintaran su aplicación para que cobrara vida .
Esto es lo que dice un desarrollador de aplicaciones móviles sobre la recarga en caliente de Flutter :
Quería probar la recarga en caliente, así que cambié un color, guardé mi modificación y… ¡me enamoré ❤️!
Esta característica es realmente asombrosa. Pensé que Editar y continuar en Visual Studio era bueno, pero esto es simplemente asombroso . Solo con esto, creo que un desarrollador móvil puede ser dos veces más productivo.
Esto es realmente un cambio de juego para mí. Cuando implemento mi código y toma mucho tiempo, pierdo el enfoque, hago otra cosa y cuando vuelvo al simulador/dispositivo, he perdido la noción de lo que quería probar. ¿Qué es más frustrante que perder 5 minutos para mover un control 2px? Con Flutter esto ya no existe.
La recarga en caliente de Flutter hace que sea mucho más fácil probar nuevas ideas o experimentar con alternativas, proporcionando un gran impulso a la creatividad.
Hasta ahora, hemos discutido cómo Dart mejora las cosas para el desarrollador. La siguiente sección trata sobre cómo Dart también facilita la creación de aplicaciones fluidas que deleiten a los usuarios.
Una aplicación rápida es excelente, pero una aplicación fluida es aún mejor. Incluso una animación súper rápida se verá mal si es entrecortada. Sin embargo, prevenir el bloqueo puede ser difícil porque hay muchas causas diferentes. Dart tiene una serie de características para evitar muchas de las cosas comunes que causan bloqueos.
Por supuesto, (como cualquier idioma) todavía es posible escribir una aplicación janky en Flutter; Dart ayuda al ser más predecible y brindar al desarrollador más control sobre la fluidez de su aplicación, lo que facilita brindar la mejor experiencia de usuario posible, sin excepción.
Con una velocidad de 60 fps, las interfaces de usuario creadas con Flutter funcionan mucho mejor que las creadas con otros marcos de desarrollo multiplataforma.
Y no solo mejor que las aplicaciones multiplataforma, sino tan bueno como las mejores aplicaciones nativas:
La interfaz de usuario es suave como la mantequilla... Nunca había visto una aplicación de Android tan fluida.
Ya hemos discutido una característica que ayuda a mantener las cosas sin problemas, y esa es la capacidad de Dart para compilar AOT en código de máquina nativo. El código AOT precompilado es más predecible que JIT porque no hay pausas durante el tiempo de ejecución para realizar el análisis o la compilación JIT.
Sin embargo, hay una ventaja aún mayor en el código compilado AOT y es evitar el "puente de JavaScript". Cuando los lenguajes dinámicos (como JavaScript) necesitan interoperar con el código nativo en la plataforma, tienen que comunicarse a través de un puente , lo que provoca cambios de contexto que tienen que guardar una gran cantidad de estado (potencialmente en almacenamiento secundario). Estos cambios de contexto son un doble golpe porque no solo ralentizan las cosas, sino que pueden causar problemas graves.
"El puente"
Nota: incluso el código compilado puede necesitar una interfaz para hablar con el código de la plataforma, y esto también se puede llamar puente, pero generalmente es mucho más rápido que el puente requerido por un lenguaje dinámico. Además, dado que Dart permite mover cosas como widgets a la aplicación, se reduce la necesidad de cruzar un puente.
La mayoría de los lenguajes informáticos que admiten varios subprocesos de ejecución simultáneos (incluidos Java, Kotlin, Objective-C y Swift) utilizan la preferencia para cambiar entre subprocesos. A cada subproceso se le asigna una "porción" de tiempo para ejecutarse, y si excede el tiempo asignado, el subproceso se adelanta mediante un cambio de contexto. Sin embargo, si la preferencia se produce cuando se actualiza un recurso que se comparte entre subprocesos (como la memoria), se produce una condición de carrera .
Las condiciones de carrera son un doble golpe porque pueden causar errores graves, incluido el bloqueo de su aplicación y la pérdida de datos, y son particularmente difíciles de encontrar y corregir porque dependen del tiempo relativo de subprocesos independientes . Es muy común que las condiciones de carrera dejen de manifestarse cuando ejecuta la aplicación en un depurador.
La forma típica de corregir una condición de carrera es proteger el recurso compartido mediante un bloqueo que evita que se ejecuten otros subprocesos, pero los bloqueos en sí mismos pueden causar bloqueos o incluso problemas más graves (incluidos interbloqueos y agotamiento ).
Dart tomó un enfoque diferente a este problema. Los subprocesos en Dart, llamados aislados , no comparten memoria, lo que evita la necesidad de la mayoría de los bloqueos. Los aislados se comunican pasando mensajes a través de canales, lo que es similar a los actores en Erlang o los trabajadores web en JavaScript.
Dart, como JavaScript, tiene un solo subproceso , lo que significa que no permite la preferencia en absoluto. En cambio, los subprocesos ceden explícitamente (usando async/await, Futures o Streams ). Esto le da al desarrollador más control sobre la ejecución. El subproceso único ayuda al desarrollador a garantizar que las funciones críticas (incluidas las animaciones y las transiciones) se ejecuten hasta el final, sin preferencia. Esto suele ser una gran ventaja no solo para las interfaces de usuario, sino también para otros códigos cliente-servidor.
Por supuesto, si el desarrollador se olvida de ceder el control, esto puede retrasar la ejecución de otro código. Sin embargo, hemos descubierto que olvidarse de ceder el paso suele ser mucho más fácil de encontrar y solucionar que olvidarse de bloquear (porque las condiciones de carrera son difíciles de encontrar).
Otra causa grave de bloqueo es la recolección de basura. De hecho, este es solo un caso especial de acceso a un recurso compartido (memoria), que en muchos idiomas requiere el uso de bloqueos. Pero los bloqueos pueden impedir que se ejecute toda la aplicación mientras se recopila memoria libre. Sin embargo, Dart puede realizar la recolección de basura casi todo el tiempo sin bloqueos .
Dart utiliza un esquema de asignación y recolección de basura generacional avanzado, que es particularmente rápido para asignar muchos objetos de corta duración (perfecto para interfaces de usuario reactivas como Flutter que reconstruyen el árbol de vista inmutable para cada cuadro). Dart puede asignar un objeto con un solo golpe de puntero (no se requiere bloqueo). Una vez más, esto da como resultado un desplazamiento y una animación suaves, sin bloqueos.
Otro beneficio de Dart es que Flutter no divide el diseño entre su programa y un lenguaje de diseño o plantilla adicional como JSX o XML, ni requiere herramientas de diseño visual separadas. Aquí hay una vista simple de Flutter, escrita en Dart:
nuevo centro (hijo: nueva columna (hijos: [nuevo texto ('¡Hola, mundo!'), nuevo icono (iconos.estrella, color: colores.verde),]))
Una vista en Dart y lo que produce
Tenga en cuenta lo fácil que es visualizar el resultado que produce este código (incluso si no tiene experiencia con Dart).
Tenga en cuenta que ahora que Flutter usa Dart 2, el diseño se ha vuelto aún más simple y claro porque la new
palabra clave es opcional, por lo que los diseños estáticos pueden verse aún más como si estuvieran escritos en un lenguaje de diseño declarativo, como este:
Center(child:Column(children: [Text('Hello, World!'),Icon(Icons.star, color: Colors.green),]))
Sin embargo, sé lo que probablemente esté pensando: ¿cómo puede llamarse una ventaja la falta de lenguajes de diseño especializados? Pero en realidad es un cambio de juego. Esto es lo que escribió un desarrollador en un artículo titulado " Por qué los desarrolladores de aplicaciones nativas deberían considerar seriamente a Flutter ".
En Flutter, los diseños se definen solo con el código Dart. No hay XML / lenguaje de plantillas. Tampoco hay una herramienta de diseño visual/guión gráfico.
Mi corazonada es que, al escuchar esto, algunos de ustedes podrían incluso encogerse un poco. Prima facie, esa también fue mi reacción. ¿No es más fácil hacer diseños usando una herramienta visual? ¿Escribir todo tipo de lógica de restricciones en el código no complicaría demasiado las cosas?
La respuesta para mí resultó ser no . ¡Y chico! qué revelador ha sido.
La primera parte de la respuesta es la recarga en caliente mencionada anteriormente.
No puedo enfatizar lo suficiente cómo esto está años luz por delante de Instant Run de Android o cualquier solución similar. Simplemente funciona, incluso en grandes aplicaciones no triviales. Y es increíblemente rápido. Ese es el poder de Dart para ti.
En la práctica, eso hace que una interfaz de editor visual sea redundante. No me perdí en absoluto el agradable diseño automático de XCode.
Dart crea un diseño conciso y fácil de entender, mientras que la recarga en caliente "locamente rápida" te permite ver los resultados al instante. Y eso incluye las partes no estáticas de su diseño.
Y como resultado, he sido mucho más productivo escribiendo diseños en Flutter (Dart) que en Android/XCode. Una vez que aprendes a hacerlo (para mí eso significó un par de semanas), hay una reducción sustancial de los gastos generales debido a que se está produciendo un cambio de contexto muy pequeño. Uno no tiene que cambiar a un modo de diseño, elegir un mouse y comenzar a hacer clic. Y luego preguntarse si algo tiene que hacerse programáticamente, cómo lograrlo, etc. Todo es programático. Y las API están muy bien diseñadas. Pronto se vuelve intuitivo y es mucho más poderoso que las construcciones que ofrecen los XML de diseño/diseño automático.
Por ejemplo, aquí hay un diseño de lista simple que agrega un divisor (línea horizontal) entre todos los demás elementos, definido mediante programación:
return new ListView.builder(itemBuilder: (context, i) {if (i.isOdd) return new Divider();// rest of function});
En Flutter, todo el diseño existe en un solo lugar, independientemente de si es un diseño estático o programático. Y las nuevas herramientas de Dart , que incluyen Flutter Inspector y la vista de contorno (que aprovechan que todos los diseños están en un solo lugar) hacen que los diseños complejos y hermosos sean aún más fáciles.
No, Dart (como Flutter) es completamente de código abierto con una licencia limpia y también es un estándar ECMA . Dart es popular dentro y fuera de Google. Dentro de Google es uno de los lenguajes de más rápido crecimiento y es utilizado por Adwords, Flutter, Fuchsia y otros; Afuera, el repositorio de Dart tiene más de 100 confirmadores externos.
Un indicador aún mejor de la apertura de Dart es el crecimiento de la comunidad fuera de Google. Por ejemplo, estamos viendo un flujo constante de artículos y videos sobre Dart (incluidos Flutter y AngularDart) de terceros, algunos de los cuales he citado en este artículo.
Además de los confirmadores externos de Dart, hay más de 3000 paquetes en el repositorio público de paquetes de Dart , incluidas bibliotecas para Firebase, Redux, RxDart, internacionalización, encriptación, bases de datos, enrutamiento, colecciones y más.
Si no muchos programadores conocen Dart, ¿será más difícil encontrar programadores calificados? Irónicamente, Dart facilita la búsqueda de programadores porque es un lenguaje increíblemente rápido de aprender. Los programadores que ya conocen lenguajes como Java, JavaScript, Kotlin, C# o Swift pueden comenzar a programar en Dart casi de inmediato. Además de eso, la recarga en caliente alienta a los usuarios a jugar con Dart y probar cosas nuevas, lo que hace que aprender Dart sea aún más rápido y placentero.
Así es como lo expresó un programador en un artículo titulado " Por qué Flutter despegará en 2018 ":
Dart , el lenguaje utilizado para desarrollar aplicaciones de Flutter, es estúpido y simple de aprender . Google tiene experiencia en la creación de lenguajes simples y bien documentados como Go, por ejemplo. Hasta ahora, a mí, Dart me recuerda a Ruby y es un placer aprender. Además, no es solo para dispositivos móviles, sino también para la web .
De otro artículo sobre Flutter y Dart, titulado “ ¿Por qué Flutter? y no marco X? o mejor aún, por qué voy a hacer Flutter con todo”.
Flutter también usa el lenguaje Dart que fue creado por Google, para ser honesto, no soy un fanático de los lenguajes fuertemente tipados como C # o JAVA, pero no sé por qué la forma de escribir el código de Dart parece diferente. Y me siento muy cómodo escribiéndolo. Tal vez porque es muy simple de aprender y muy directo.
Dart fue diseñado específicamente para ser familiar y fácil de aprender, a través de una extensa investigación y prueba de UX. Por ejemplo, en la primera mitad de 2017, el equipo de Flutter realizó un estudio de UX con ocho desarrolladores . Les dimos una breve introducción a Flutter, luego los soltamos durante una hora más o menos para crear una vista simple. Todos los participantes pudieron comenzar a programar de inmediato, aunque nunca antes habían usado Dart. Se centraron en escribir puntos de vista reactivos, no en el lenguaje. Dart acaba de funcionar .
Al final, un participante (que había progresado particularmente en la tarea) no mencionó nada sobre el idioma, por lo que les preguntamos si se daban cuenta de qué idioma estaban usando. Ellos no sabían. El idioma no importaba ; estaban programando en Dart en minutos.
La parte difícil de aprender un nuevo sistema generalmente no es aprender el lenguaje, sino aprender todas las bibliotecas, marcos, herramientas, patrones y mejores prácticas para escribir un buen código. Y las bibliotecas y herramientas de Dart son excepcionalmente buenas y están bien documentadas. Un artículo proclama : "Como beneficio adicional, también cuidan mucho su base de código y tienen la mejor documentación que he visto". El poco esfuerzo que se dedica a aprender Dart se compensa fácilmente con el ahorro de tiempo en el aprendizaje del resto.
Como evidencia directa, un gran proyecto dentro de Google quería portar su aplicación móvil a iOS. Estaban a punto de contratar a algunos programadores de iOS, pero decidieron probar Flutter. Supervisaron cuánto tiempo les tomó a los desarrolladores ponerse al día con Flutter. Sus resultados mostraron que un programador podía aprender Dart y Flutter y volverse productivo en tres semanas. Esto se compara con las cinco semanas que habían observado anteriormente para que los programadores se pusieran al día solo con Android (sin mencionar que habrían tenido que contratar y capacitar a los desarrolladores para iOS).
Finalmente, el artículo " Por qué elegimos Flutter y cómo cambió nuestra empresa para mejor " es de una empresa que trasladó su gran aplicación empresarial a Dart en las tres plataformas (iOS, Android y web). Sus conclusiones:
Mucho más fácil de contratar. Ahora buscamos elegir al mejor candidato sin importar si es de la Web, iOS o Android.
Tenemos 3 veces el ancho de banda ahora que todos nuestros equipos están consolidados en una sola base de código.
El intercambio de conocimientos está en su punto más alto
Pudieron triplicar su productividad usando Dart y Flutter. Esto no debería ser una sorpresa dado lo que estaban haciendo antes. Ellos, como muchas empresas, estaban creando aplicaciones separadas para cada plataforma (web, iOS y Android) utilizando lenguajes, herramientas y programadores separados . Cambiar a Dart significó que ya no tenían que contratar tres tipos diferentes de programadores. Y fue fácil para ellos trasladar a sus programadores existentes a Dart.
Ellos y otros descubrieron que una vez que los programadores comienzan a usar Flutter, a menudo se enamoran de Dart . Les gusta la concisión del lenguaje y la falta de ceremonia. Les encantan las funciones de lenguaje como cascadas, parámetros con nombre, asíncrono/espera y flujos. Y, por encima de todo, les encantan las características de Flutter (como la recarga en caliente) que son posibles gracias a Dart, y las hermosas y eficaces aplicaciones que Dart les ayuda a crear.
A medida que se publica este artículo, se lanza Dart 2 . Dart 2 se centra en mejorar la experiencia de creación de aplicaciones cliente , incluida la velocidad del desarrollador, las herramientas mejoradas para desarrolladores y la seguridad de tipos. Por ejemplo, Dart 2 cuenta con un sistema de tipos de sonido e inferencia de tipos.
Dart 2 también hace que la new
palabra clave sea opcional. Esto significa que es posible describir muchas vistas de Flutter sin usar ninguna palabra clave , lo que las hace menos desordenadas y más fáciles de leer. Por ejemplo:
Widget build(BuildContext context) =>Center(child:Column(children: [Text('Hello, World!'),Icon(Icons.star, color: Colors.green),]))
Dart 2 también usa la inferencia de tipos para hacer que muchos usos de la palabra clave const
sean opcionales al no requerir que const
se especifique de manera redundante dentro de un contexto const
. Por ejemplo, la declaración:
const desayuno = {const Donuts(): const [const Cruller(), const BostonCream()],};
ahora puede ser reemplazado por esto:
const desayuno = {Donuts(): [Cruller(), BostonCream()],};
Debido a que el breakfast
es const
, se infiere que todo lo demás también es const
.
Las mejoras en Dart 2 se centran en optimizar el desarrollo del lado del cliente. Pero Dart seguirá siendo un gran lenguaje para crear sistemas embebidos, de escritorio, del lado del servidor u otros programas.
El enfoque es algo bueno . Prácticamente todos los lenguajes populares perdurables se beneficiaron de estar muy enfocados. Por ejemplo:
Por otro lado, muchos lenguajes han intentado explícitamente (y fallado) ser completamente de propósito general, como PL/1 y Ada, entre otros. El problema más común es que sin foco , estos lenguajes se convirtieron en proverbiales fregaderos de cocina.
Muchas de las características que hacen de Dart un excelente lenguaje del lado del cliente también lo convierten en un mejor lenguaje para usar en el lado del servidor. Por ejemplo, el hecho de que Dart evite la multitarea preventiva le otorga las mismas ventajas que Node en el servidor, pero con una escritura mucho mejor y más segura.
Lo mismo ocurre con la escritura de software para sistemas integrados. La capacidad de Dart para manejar múltiples entradas simultáneas de manera confiable es clave aquí.
Finalmente, el éxito de Dart en el cliente inevitablemente generará más interés en usarlo en el servidor, tal como sucedió con JavaScript y Node. ¿Por qué obligar a las personas a usar dos idiomas diferentes para crear software cliente-servidor?
Este es un momento emocionante para Dart. A las personas que usan Dart les encanta, y las nuevas características de Dart 2 lo convierten en una adición aún más valiosa a su arsenal de herramientas. Si no ha usado Dart, espero que este artículo le haya brindado información valiosa sobre las novedades o diferencias de Dart, y que le dé una oportunidad, y también a Flutter.