David Harron, el autor del material que publicamos hoy, hizo la siguiente pregunta: “¿Debería una persona que ha trabajado durante más de 10 años en Sun Microsystems en el equipo Java SE, hasta el último aliento, pensar solo en el código de bytes de Java y crear instancias de interfaces abstractas? ". Hizo esta pregunta en relación a sí mismo, y para él la plataforma Node.js, después de Java, resultó ser como un soplo de aire fresco. David dice que cuando fue despedido de Sun en enero de 2009 (justo antes de la adquisición de esta compañía Oracle), se enteró de Node.js. Esta tecnología lo enganchó. ¿Qué significa "enganchado"? Desde 2010, escribió mucho sobre programación para Node.js. Es decir, escribió varios libros, incluido Node.js Web Development, cuya cuarta edición se lanzó este año. Ha preparado muchos materiales pequeños sobre Node.js publicados en Internet. De hecho, dedicó mucho tiempo y esfuerzo a hablar sobre la plataforma Node.js y las características de JavaScript. ¿Por qué los que anteriormente trabajaban exclusivamente en Java estaban tan atraídos por Node.js y JavaScript?

Sobre el mundo de Java
Mientras trabajaba en Sun, creía en la tecnología Java. Hice presentaciones en JavaONE, participé en el desarrollo de la clase java.awt.Robot, organicé el evento del Concurso de Regresiones Mustang (fue una competencia destinada a encontrar errores en Java 1.6), ayudé a lanzar el proyecto de Licencia de Distribuciones para Java, que sirvió como respuesta a la pregunta sobre las distribuciones JDK de Linux antes del advenimiento de OpenJDK. Más tarde, jugué un papel en el lanzamiento del proyecto OpenJDK. En el camino, durante unos 6 años, publiqué material de blog en java.net (ahora este sitio está cerrado). Estos fueron 1-2 artículos por semana dedicados a eventos importantes en el ecosistema de Java. Jugué un papel importante en mi trabajo al proteger Java de aquellos que predijeron un futuro sombrío para esta tecnología.
Este premio, el Premio Duke, fue otorgado a los empleados más distinguidos de Sun. Lo obtuve después de organizar el concurso de regresiones de Mustang¿Qué le pasó a la persona que hizo tanto con todo lo relacionado con Java? En realidad, aquí quiero hablar sobre cómo pasé de ser un devoto de Java a un ardiente defensor de Node.js y JavaScript.
Debo decir que lo que me pasó no se puede llamar un abandono completo de Java. En los últimos 3 años, he escrito bastante código Java, he usado Spring e Hibernate. Aunque lo que ahora hago en esta área realmente me gusta (trabajo en la industria de la energía solar, hago lo que me gusta hacer, por ejemplo: escribo solicitudes para trabajar con datos del sector de la energía), la programación de Java en mis ojos ahora perdió su antiguo esplendor.
Dos años de desarrollo con Spring me permitieron aclarar claramente una cosa importante: un intento de ocultar mecanismos complejos no conduce a la simplicidad, solo conduce a la aparición de estructuras aún más complejas.
Aquí, en resumen, están las ideas principales que abordaré en este material:
- Los programas Java están llenos de código repetitivo que oculta las intenciones del programador.
- Trabajar con Spring y Spring Boot me ha dado una buena lección, que es que tratar de ocultar mecanismos complejos conduce a construcciones aún más complejas.
- La plataforma Java EE fue un proyecto creado, por así decirlo, por "esfuerzos comunes", que cubre absolutamente todas las necesidades de desarrollo de aplicaciones empresariales. Como resultado, la plataforma Java EE ha demostrado ser prohibitiva.
- Desarrollar con Spring es, hasta cierto punto, una experiencia agradable. Esta ilusión desaparece el día en que una excepción que es completamente imposible de entender surge de las profundidades de un subsistema del que nunca has oído hablar, y lleva al menos tres días descubrir cuál es el problema.
- ¿Qué mecanismos auxiliares que crean una carga excesiva en el sistema necesita un marco que pueda "escribir" código para programadores?
- Aunque los IDE como Eclipse son aplicaciones potentes, son un indicador de la complejidad del ecosistema Java.
- La plataforma Node.js surgió como resultado de los esfuerzos de una persona para mejorar su visión de la arquitectura ligera basada en eventos.
- La comunidad de JavaScript parece estar entusiasmada por deshacerse del código repetitivo, que permite a los programadores expresar sus intenciones de la manera más clara posible.
- Async / await es una solución al problema JS callback hell, que es un ejemplo de rechazo del código de plantilla y contribuye a la claridad de expresión de las intenciones de los programadores.
- La programación para Node.js es un verdadero placer.
- No hay una tipificación fuerte específica de Java en JavaScript. Esta es la bendición y la maldición de la lengua. Esto facilita la escritura de código, pero para verificar su corrección, debe dedicar más tiempo a las pruebas.
- El sistema de gestión de paquetes introducido por npm / yarn es fácil y divertido de usar. Ella no puede ser comparada con Maven.
- Tanto Java como Node.js ofrecen un gran rendimiento. Esto va en contra del mito de que JavaScript es un lenguaje lento, cuyo uso conduce a un bajo rendimiento de la plataforma Node.js.
- Performance Node.js se basa en los esfuerzos de Google para mejorar V8, el motor que afecta la velocidad del navegador Chrome.
- La feroz competencia entre los fabricantes de motores JS basados en navegador contribuye al desarrollo de JavaScript, y esto es muy beneficioso para Node.js.
Acerca de los problemas de desarrollo de Java
Algunas herramientas u objetos son el resultado de muchos años de esfuerzos de los ingenieros para mejorarlos. Los programadores prueban diferentes ideas, eliminan atributos innecesarios y, como resultado, obtienen entidades en las que existe exclusivamente lo que se necesita para resolver un determinado problema. A menudo, tales tecnologías tienen una simplicidad muy atractiva que oculta capacidades poderosas. Esto no se aplica a Java.
Spring es un marco popular para desarrollar aplicaciones web basadas en Java.
El objetivo principal de Spring, y en particular Spring Boot, es proporcionar la capacidad de utilizar la pila Java EE preconfigurada. El programador que usa Spring no debe, para crear un sistema listo para usar, cuidar los servlets, los sistemas de almacenamiento persistente, los servidores de aplicaciones y lo que aún se desconoce. Todas estas preocupaciones se transmiten a Spring, y el programador está escribiendo un código que implementa la lógica de la aplicación. Por ejemplo, los mecanismos JPARepository son responsables de generar consultas en la base de datos para métodos cuyos nombres se parecen a
findUserByFirstName
. El programador no tiene que escribir el código para tales métodos. Es suficiente pasar la descripción del método al sistema, y Spring hará el resto.
Todo suena muy bien, es bueno trabajar con este estilo, pero hasta que ocurra algo inesperado.
Me refiero a una situación en la que, por ejemplo, se lanza una Hibernate
PersistentObjectException
con la
detached entity passed to persist
del mensaje
detached entity passed to persist
. ¿Qué podría significar? Tardó varios días en descubrirlo. Resultó que si describe todo de una manera muy simplificada, esto significa que los datos JSON recibidos en el punto final REST tienen campos de ID con algunos valores. Hibernate, una vez más, si no entra en detalles, busca controlar los valores de ID y, como resultado, arroja la oscura excepción anterior. Hay miles de tales mensajes de error que son confusos y difíciles de leer. Teniendo en cuenta que en Spring hay cascadas enteras de subsistemas entre sí, la pila de Spring parece un enemigo jurado de un programador que lo mira y espera a que el programador cometa el más mínimo error, y cuando esto sucede, lanza excepciones que no son compatibles con él. funcionamiento normal de la aplicación.
Además, aquí puede recordar los rastros de pila más largos. Representan varias pantallas llenas de todo tipo de métodos abstractos. Spring obviamente crea la configuración necesaria para implementar lo que se expresa en el código. Tal nivel de abstracción, sin duda, requiere una cantidad considerable de lógica auxiliar, que tiene como objetivo descubrir todo lo necesario para que el código funcione, por ejemplo, para cumplir con las solicitudes. Y las trazas de pila largas no son necesariamente malas. Es más probable que tales cosas sean un síntoma, lo que lleva a la pregunta de qué tipo de carga en el sistema se crea mediante mecanismos auxiliares.
¿Cómo se
findUserByFirstName
método
findUserByFirstName
, dado que el programador no escribió el código para tal método? El marco debe analizar el nombre del método, comprender la intención del programador, crear algo así como un árbol de sintaxis abstracta, generar algún tipo de código SQL, etc. ¿Cómo carga todo esto el sistema? ¿Y todo esto existe solo para que el programador no necesite escribir código?
Después de que tenga que pasar por algunas decenas de veces a través de algo como buscar el significado del error anterior, pasar semanas tratando de desentrañar secretos que, en general, no debe desentrañar, puede llegar a la misma conclusión a la que llegué . Su significado es que un intento de ocultar mecanismos complejos no conduce a la simplicidad, solo conduce a la aparición de estructuras aún más complejas. La plataforma Node.js es mucho más simple.
El lema "La compatibilidad importa" ocultaba una idea maravillosa, según la cual la compatibilidad con versiones anteriores era la característica más importante de la plataforma Java. Nos tomamos esto en serio, poniendo imágenes en camisetas como la que puedes ver a continuación.
La compatibilidad con versiones anteriores es muy importante.Por supuesto, este nivel de atención a la compatibilidad con versiones anteriores puede ser una fuente de ansiedad constante, y de vez en cuando es útil alejarse de los mecanismos antiguos que ya no se benefician.
Java y Node.js
Spring y Java EE son demasiado complicados. La plataforma Node.js en su contexto se percibe como un soplo de aire fresco. Lo primero que notará cuando se familiarice con Node.js es el enfoque de Ryan Dahl para el desarrollo del núcleo de la plataforma. Su experiencia le dijo que las plataformas que usan transmisiones son necesarias para crear sistemas complejos y pesados. Estaba buscando algo más y pasó un par de años mejorando el conjunto de mecanismos básicos incorporados en Node.js. Como resultado, obtuvo un sistema liviano que se caracteriza por un solo hilo de ejecución, el uso inventivo de funciones anónimas de JavaScript como devoluciones de llamada asíncronas y una biblioteca de tiempo de ejecución que originalmente implementa mecanismos asincrónicos. El mensaje inicial al crear dicho sistema era proporcionar un procesamiento de eventos de alto rendimiento con la entrega de estos eventos en una función de devolución de llamada.
A continuación, una característica importante de Node.js es el uso de JavaScript. Existe la sensación de que quienes escriben en JS tienden a deshacerse del código de plantilla, lo que les permite describir claramente las intenciones del programador.
Como ejemplo de la diferencia entre Java y JavaScript, considere la implementación de funciones de escucha (observadores). En Java, para trabajar con oyentes, debe crear una instancia específica de la interfaz abstracta. Esto implica el uso de construcciones de lenguaje voluminoso que ocultan la esencia de lo que está sucediendo. ¿Cómo discernir la intención de un programador oculta bajo las tapas del código repetitivo?
JavaScript utiliza funciones anónimas simples en su lugar. Al implementar un oyente, no necesita buscar una interfaz abstracta adecuada. Es suficiente, sin la necesidad de usar una variedad de textos auxiliares, escribir el código necesario.
Entonces, aquí hay una idea importante que se puede extraer del análisis de los mecanismos anteriores: la mayoría de los lenguajes de programación ocultan las intenciones del programador, lo que lleva al hecho de que el código es difícil de entender.
La decisión sobre el uso de las funciones de devolución de llamada que ofrece Node.js parece muy atractiva. Pero no está exento de problemas.
Resolución de problemas y resolución de problemas
En JavaScript, ha habido dos problemas asociados con la programación asincrónica. El primero es lo que Node.js llama infierno de devolución de llamada. Este problema radica en el hecho de que, durante el desarrollo, es fácil caer en una trampa construida a partir de funciones de devolución de llamada profundamente anidadas, donde cada nivel de anidación complica el programa, así como el procesamiento de los resultados del código y los errores. Había otro problema relacionado con esto, cuya esencia era que los mecanismos del lenguaje JavaScript no ayudaban al programador a expresar adecuadamente las ideas de ejecución de código asíncrono.
Han surgido varias bibliotecas para simplificar el desarrollo asincrónico en JS. Pero este es otro ejemplo de un intento de ocultar mecanismos complejos que solo conduce a la aparición de estructuras aún más complejas.
Considere un ejemplo:
const async = require('async'); const fs = require('fs'); const cat = function(filez, fini) { async.eachSeries(filez, function(filenm, next) { fs.readFile(filenm, 'utf8', function(err, data) { if (err) return next(err); process.stdout.write(data, 'utf8', function(err) { if (err) next(err); else next(); }); }); }, function(err) { if (err) fini(err); else fini(); }); }; cat(process.argv.slice(2), function(err) { if (err) console.error(err.stack); });
Esta es una imitación indescriptible del
cat
Unix
cat
. La biblioteca
async
por simplificar las secuencias de llamadas asíncronas. Sin embargo, su uso requiere una gran cantidad de código repetitivo que oculta la intención del programador.
En esencia, este código contiene un bucle. No está escrito como un ciclo regular, no utiliza construcciones naturales de la descripción de los ciclos. Además, los resultados de la ejecución del código y los errores generados por ellos no llegan a donde deberían haber sido correctos. Están bloqueados en devoluciones de llamada, lo cual es inconveniente. Pero, antes de la implementación de los estándares ES2015 / 2016 en Node.js, no se podía hacer nada mejor.
Si reescribimos este código teniendo en cuenta las nuevas características, que, en particular, están disponibles en Node.js 10.x, obtenemos lo siguiente:
const fs = require('fs').promises; async function cat(filenmz) { for (var filenm of filenmz) { let data = await fs.readFile(filenm, 'utf8'); await new Promise((resolve, reject) => { process.stdout.write(data, 'utf8', (err) => { if (err) reject(err); else resolve(); }); }); } } cat(process.argv.slice(2)).catch(err => { console.error(err.stack); });
En este ejemplo, utilizamos la construcción
async/await
. Aquí se presentan los mismos mecanismos asincrónicos que en el ejemplo anterior, pero aquí se usan las estructuras habituales utilizadas en la organización de bucles. Trabajar con resultados y errores parece bastante normal. Tal código es más fácil de leer y escribir. Este enfoque facilita la comprensión de la intención del programador.
El único inconveniente es que
process.stdout.write
no tiene una interfaz Promise, como resultado, este mecanismo no puede usarse en funciones asíncronas sin envolverlo en una promesa.
Ahora podemos concluir que el problema del infierno de devolución de llamada en JavaScript se resolvió de una manera diferente de tratar de ocultar mecanismos complejos. En cambio, se realizaron cambios en el idioma, lo que resolvió el problema en sí, y nos salvó de los inconvenientes causados por la necesidad de utilizar grandes cantidades de código de plantilla en una solución temporal. Además, con el uso del mecanismo asíncrono / espera, el código simplemente se volvió más hermoso.
Comenzamos esta sección con una discusión sobre la falla de Node.js, pero una excelente solución al infierno de una devolución de llamada hizo que la conversación sobre fallas se convirtiera en una conversación sobre las fortalezas de Node.js y JavaScript.
Tipeo fuerte, interfaces y claridad de código imaginario.
En esos días cuando estaba protegiendo Java de todo tipo de ataques, enfaticé que la escritura estricta le permite escribir aplicaciones enormes. En aquellos días, el desarrollo de sistemas monolíticos estaba en uso (no había microservicios, no había Docker y similares). Como Java es un lenguaje fuertemente tipado, el compilador de Java ayuda al programador a evitar muchos problemas al evitar que compile el código incorrecto.
JavaScript, a diferencia de Java, no está fuertemente tipado. De esto podemos sacar la conclusión obvia de que el programador no sabe exactamente con qué objetos tiene que trabajar. ¿Cómo puede un programador saber qué hacer, por ejemplo, con un determinado objeto recibido de alguna parte?
La otra cara del tipeo Java fuerte es que necesita realizar constantemente acciones repetitivas. El programador está constantemente emitiendo o verificando que todo esté exactamente como se esperaba. El desarrollador pasa tiempo escribiendo código, lo hace con una precisión excepcional, utiliza volúmenes considerables de diseños de plantillas y espera que todo esto lo ayude a ahorrar tiempo mediante la detección temprana y la corrección de errores.
El problema de programar en un lenguaje fuertemente tipado es tan grande que un programador, casi sin opciones, debe usar un IDE grande y complejo. Un editor de código simple no es suficiente aquí. La única forma de mantener al programador de Java en condiciones adecuadas (con la excepción de la pizza) es mostrarle constantemente listas desplegables que contengan campos de objetos disponibles o descripciones de los parámetros del método. Este y otros mecanismos de apoyo de IDEs como Eclipse, NetBeans o IntelliJ ayudan en la creación de clases, facilitan la refactorización y otras tareas.
Y ... no hablaré de Maven. Esta es solo una herramienta de pesadilla.
En JavaScript, los tipos de variables no se especifican cuando se declaran, la conversión de tipos generalmente no se usa, etc. Como resultado, el código es más fácil de leer, pero este estado de cosas también implica el riesgo de errores de programación que son difíciles de detectar.
Si lo anterior se relaciona con las ventajas de Java o las desventajas depende del punto de vista.
Hace diez años, creía que todas estas dificultades se justificaban al darle al programador una mayor confianza en el código que escribe. Hoy, creo que la escritura fuerte aumenta la carga de trabajo del programador y es mucho más fácil desarrollar proyectos como lo hacen en JavaScript.
Combate errores con módulos pequeños que son fáciles de probar
Node.js empuja al programador a dividir sus proyectos en pequeños fragmentos, en los llamados módulos. Puede encontrar este hecho insignificante, pero resuelve parcialmente el problema que acabamos de mencionar.
Estas son las principales características del módulo:
- Independencia El módulo combina código interconectado en una sola entidad.
- Limites claros. El código dentro del módulo está protegido contra interferencias por cualquier mecanismo externo.
- Exportación explícita. Por defecto, el código y los datos del módulo no se exportan. El desarrollador decide independientemente qué funciones y datos deben estar disponibles públicamente.
- Importación explícita. Al desarrollar un módulo, el programador decide por sí mismo de qué módulos dependerá.
- Potencial independencia. Los módulos pueden hacerse públicos, en el sentido más amplio de la palabra, publicándolos en npm o, si están destinados a las necesidades internas de la empresa, publicando en repositorios cerrados. Esto facilita el uso de los mismos módulos en diferentes aplicaciones.
- Código fácil de entender. El hecho de que los módulos sean pequeños, simplifica la lectura y la comprensión de su código, abre la posibilidad de una discusión gratuita sobre ellos.
- Facilitar las pruebas. Un módulo pequeño, si se implementa correctamente, puede probarse fácilmente en la unidad.
Todo esto convierte a los módulos de Node.js en entidades con límites claramente definidos, cuyo código es fácil de escribir, leer y probar.
Sin embargo, preocuparse por trabajar con JavaScript es el hecho de que la falta de tipeo fuerte puede hacer que el código haga algo mal. En un pequeño módulo destinado a resolver algún problema estrecho con límites claros, "algo está mal" puede afectar solo el código del módulo en sí. Esto lleva al hecho de que los problemas que pueden causar la falta de escritura estricta están bloqueados dentro del módulo.
Otra solución al problema de escritura dinámica en JavaScript es probar a fondo el código.
El desarrollador debe tomarse en serio las pruebas, lo que elimina parte de los beneficios que provienen de la simplicidad del proceso de desarrollo de JS. Los sistemas de prueba creados por un programador JS deben encontrar aquellos errores que, si los desarrolla en algo como Java, el compilador podría encontrarlos automáticamente. ¿Estás escribiendo pruebas para tus aplicaciones JS?
Para aquellos que necesitan un sistema de escritura estático en JavaScript, puede ser útil echar un vistazo a TypeScript. No uso este lenguaje, pero he escuchado muchas cosas buenas al respecto. Es compatible con JavaScript y extiende el lenguaje con un sistema de control de tipo y otras características útiles.
Al final, podemos decir que usar un enfoque modular para el desarrollo es la fortaleza de Node.js y JavaScript.
Gestión de paquetes
Me siento mal por el mero pensamiento de Maven, por lo que ni siquiera puedo escribir normalmente sobre eso. Y, según tengo entendido, Maven, sin compromiso, es amado u odiado.
El problema aquí es que en el entorno Java no existe un sistema holístico para administrar paquetes. Existen paquetes de Maven, puede trabajar con ellos normalmente, Gradle los admite. Pero la forma en que se organiza el trabajo con ellos no se parece mucho a las comodidades que el sistema de gestión de paquetes para Node.js ofrece al desarrollador.
En el mundo de Node.js, hay dos grandes gestores de paquetes que trabajan estrechamente entre sí. Al principio, la única herramienta de ese tipo era el repositorio npm y la herramienta de línea de comando del mismo nombre.
Gracias a npm, tenemos un excelente esquema para describir las dependencias del paquete. Las dependencias pueden ser estrictas (por ejemplo, se indica que solo se necesita la versión 1.2.3 de un determinado paquete), o se pueden dar con varios grados de libertad, hasta
*
, lo que significa utilizar la última versión de un determinado paquete.
La comunidad Node.js ha publicado cientos de miles de paquetes en el repositorio npm. Al mismo tiempo, usar paquetes que no están en npm es tan fácil como usar paquetes de npm.
El sistema npm resultó ser tan exitoso que no solo los desarrolladores de productos de servidor en Node.js lo usan, sino también programadores front-end. Anteriormente, herramientas como Bower se usaban para administrar paquetes. Bower quedó en desuso, y ahora puede encontrar que todas las bibliotecas JS para el desarrollo frontend existen como paquetes npm. Muchas herramientas de soporte para el desarrollo del cliente, como la CLI de Vue.js y Webpack, están escritas como aplicaciones Node.js.
Otro sistema de gestión de paquetes para Node.js, yarn, descarga paquetes del repositorio npm y utiliza los mismos archivos de configuración. La principal ventaja del hilo sobre el administrador de paquetes npm es su mayor velocidad.
El repositorio npm, ya sea que use el administrador de paquetes npm o el administrador de paquetes de hilo, es una base poderosa para lo que hace que el desarrollo de Node.js sea tan fácil y divertido.
Una vez, después de ayudar a desarrollar java.awt.Robot, me inspiré para crear esto. Mientras que la imagen oficial de Duke está formada por curvas, RoboDuke está construido a partir de líneas rectas. Solo las articulaciones del codo de este robot son redondasRendimiento
Tanto Java como JavaScript fueron criticados por su bajo rendimiento. En ambos casos, el compilador convierte el código fuente del programa en bytecode ejecutado en una máquina virtual implementada para una plataforma específica. La máquina virtual, a su vez, convierte el código de bytes en código de máquina usando varias optimizaciones.Tanto Java como JavaScript tienen razones para luchar por un alto rendimiento. Si hablamos de Java y Node.js, entonces están relacionados por el deseo de un código de servidor rápido. En el caso de JavaScript basado en navegador, el incentivo para un alto rendimiento es mejorar la calidad de las aplicaciones cliente. Hablaremos de esto en la sección sobre aplicaciones de Internet enriquecidas.JDK Sun/Oracle HotSpot — , -. , , , , , . HotSpot — , .
JavaScript, , JS-, , , - . , JavaScript . , , . , , Google Docs, . JS .
Node.js , V8 Google Chrome.
, Google, V8, . , V8 Crankshaft Turbofan.
— , , R Python. , , . JavaScript, , ,
JavaScript.
JavaScript , TensorFlow.js. API API TensorFlow Python, . , , , .
IBM, Node.js, , , Docker/Kubernetes. , Node.js Spring Boot. -, . , Node.js , , , V8.
, Node.js . . - , Node.js , . , «Node.js Web Development», , :
JavaScript , Node.js. — Node.js-. Node.js-
node-gyp
, .
, Rust- Node.js.
WebAssembly , , JavaScript, . WebAssembly , JavaScript-.
WebAssembly Node.js.
-
- (Rich Internet Applications, RIA) . , , ( ) JS-, .
, 20 . Sun Netscape Java- Netscape Navigator. JavaScript , , Java-. , Java-, — Java-. , . .
JavaScript , . RIA, , - Java -.
, RIA . Node.js , , , . JavaScript.
Aquí hay algunos ejemplos:
- Google Docs ( ), , .
- , React, Angular Vue.js, , HTML, CSS JavaScript.
- Electron — Node.js Chromium. - . , Visual Studio Code, Atom, GitKraken, Postman.
- Electron/NW.js , -, , React, Angular, Vue, .
Java, , - -, JavaScript. , , - Sun Microsystems. Sun , . . Java- , Java Java Web Start. Java- Webstart-.
Java, , , IDE NetBeans Eclipse . Java , , Java.
JavaFX.
JavaFX, 10 , Sun iPhone. , Java, , , . Flash iOS. . JavaFX , , . - React, Vue.js .
JavaScript Node Java.
Java, - JavaONE. Java . , , , .
Java
Resumen
. «P-» (Perl, PHP, Python) Java, Node.js, Ruby, Haskell, Go, Rust, . .
, , , Java, Node.js, , , Node.js-. Java , Node.js . , , , Java, .
. , , Node.js - , - . . , XBRL-. XBRL Python, , , Python. , , , .
Estimados lectores! , , JavaScript - , - Node.js, .
