e
Componentes de clase, misceláneos
Componentes de clase
Durante el curso solo hemos utilizado componentes de React que se han definido como funciones de Javascript. Esto no fue posible sin la funcionalidad de hooks que venía con la versión 16.8 de React. Antes, al definir un componente que usa estado, uno tenía que definirlo usando la sintaxis de Javascript de Clase.
Es beneficioso al menos estar familiarizado con los componentes de clase hasta cierto punto, ya que el mundo contiene una gran cantidad de código React antiguo, que probablemente nunca se reescribirá por completo con la sintaxis actualizada.
Conozcamos las características principales de los componentes de clase produciendo otra aplicación, que ya nos es muy familiar, la de anécdotas. Almacenamos las anécdotas en el archivodb.json usando json-server. El contenido del archivo se extrae de aquí.
La versión inicial del componente de clase se ve así
import React from 'react'
class App extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
<div>
<h1>anecdote of the day</h1>
</div>
)
}
}
export default App
El componente ahora tiene un constructor, en el que no sucede nada en este momento, y contiene el método render. Como se puede suponer, render define cómo y qué se renderiza en la pantalla.
Definamos un estado para la lista de anécdotas y la anécdota actualmente visible. A diferencia de cuando se usa el hook useState, los componentes de clase solo contienen un estado. Por tanto, si el estado se compone de varias "partes", deben almacenarse como propiedades del estado. El estado se inicializa en el constructor:
class App extends React.Component {
constructor(props) {
super(props)
this.state = { anecdotes: [], current: 0 } }
render() {
if (this.state.anecdotes.length === 0) { return <div>no anecdotes...</div> }
return (
<div>
<h1>anecdote of the day</h1>
<div> {this.state.anecdotes[this.state.current].content} </div> <button>next</button> </div>
)
}
}
El estado del componente está en la variable de instancia this.state. El estado es un objeto que tiene dos propiedades. this.state.anecdotes es la lista de anécdotas y this.state.current es el índice de la anécdota que se muestra actualmente.
En componentes funcionales, el lugar adecuado para obtener datos de un servidor es dentro de un effect hook, que se ejecuta cuando un componente se renderiza o con menos frecuencia si es necesario, por ejemplo, solo en combinación con el primer renderizado.
Los métodos de ciclo de vida de componentes de clase ofrecen la funcionalidad correspondiente. El lugar correcto para desencadenar la obtención de datos de un servidor es dentro del método de ciclo de vida componentDidMount, que se ejecuta una vez justo después de la primera vez que se renderiza un componente:
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
anecdotes: [],
current: 0
}
}
componentDidMount = () => { axios.get('http://localhost:3001/anecdotes').then(response => { this.setState({ anecdotes: response.data }) }) }
// ...
}
La función callback de la solicitud HTTP actualiza el estado del componente mediante el método setState. El método solo toca las keys que se han definido en el objeto pasado al método como argumento. El valor de la key current permanece sin cambios.
Llamar al método setState siempre desencadena la re-renderización del componente de clase, es decir que realiza nuevamente un llamado al método render.
Terminaremos el componente con la posibilidad de cambiar la anécdota mostrada. El siguiente es el código para todo el componente con la adición resaltada:
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
anecdotes: [],
current: 0
}
}
componentDidMount = () => {
axios.get('http://localhost:3001/anecdotes').then(response => {
this.setState({ anecdotes: response.data })
})
}
handleClick = () => { const current = Math.floor( Math.random() * this.state.anecdotes.length ) this.setState({ current }) }
render() {
if (this.state.anecdotes.length === 0 ) {
return <div>no anecdotes...</div>
}
return (
<div>
<h1>anecdote of the day</h1>
<div>{this.state.anecdotes[this.state.current].content}</div>
<button onClick={this.handleClick}>next</button> </div>
)
}
}
A modo de comparación, aquí está la misma aplicación como un componente funcional:
const App = () => {
const [anecdotes, setAnecdotes] = useState([])
const [current, setCurrent] = useState(0)
useEffect(() =>{
axios.get('http://localhost:3001/anecdotes').then(response => {
setAnecdotes(response.data)
})
},[])
const handleClick = () => {
setCurrent(Math.round(Math.random() * (anecdotes.length - 1)))
}
if (anecdotes.length === 0) {
return <div>no anecdotes...</div>
}
return (
<div>
<h1>anecdote of the day</h1>
<div>{anecdotes[current].content}</div>
<button onClick={handleClick}>next</button>
</div>
)
}
En el caso de nuestro ejemplo, las diferencias fueron menores. La mayor diferencia entre los componentes funcionales y los componentes de clase es principalmente que el estado de un componente de clase es un solo objeto y que el estado se actualiza utilizando el método setState, mientras que en los componentes funcionales el estado puede constar de múltiples variables diferentes, con todas ellos tienen su propia función de actualización.
En algunos casos de uso más avanzados, el hook effect ofrece un mecanismo considerablemente mejor para controlar los efectos secundarios en comparación con los métodos de ciclo de vida de los componentes de clase.
Un beneficio notable de usar componentes funcionales es no tener que lidiar con la auto-referencia this de la clase Javascript.
En mi opinión, y la opinión de muchos otros, los componentes de clase básicamente no ofrecen beneficios sobre los componentes funcionales mejorados con hooks, con la excepción del llamado mecanismo de error boundary, que actualmente (15 de febrero de 2021) aún no está en uso por componentes funcionales.
Al escribir código nuevo, no hay ninguna razón racional para usar Componentes de Clase si el proyecto usa React con un número de versión 16.8 o superior. Por otro lado, actualmente no hay necesidad de reescribir todo el código React antiguo como componentes funcionales.
Organización del código en la aplicación de React
En la mayoría de las aplicaciones seguimos el principio según el cual los componentes se colocaban en el directorio components, los reducers se colocan en el directorio reducers y el código responsable de comunicarse con el servidor se colocaba en el directorio services. Esta forma de organización se adapta perfectamente a una aplicación pequeña, pero a medida que aumenta la cantidad de componentes, se necesitan mejores soluciones. No existe una forma correcta de organizar un proyecto. El artículo La forma 100% correcta de estructurar una aplicación React (o por qué no existe tal cosa) proporciona una perspectiva sobre el problema.
Frontend y backend en el mismo repositorio
Durante el curso, hemos creado el frontend y el backend en repositorios separados. Este es un enfoque muy típico. Sin embargo, hicimos el despliegue copiando el código de frontend incluido en el repositorio de backend. Un enfoque posiblemente mejor habría sido desplegar el código del frontend por separado.
A veces, puede haber una situación en la que la aplicación completa se coloque en un solo repositorio. En este caso, un enfoque común es colocar package.json y webpack.config.js en el directorio raíz, así como colocar el código de frontend y backend en sus propios directorios, por ejemplo, client y server.
Cambios en el servidor
Si hay cambios en el estado del servidor, por ejemplo, cuando otros usuarios agregan nuevos blogs al servicio de Blog List el frontend de React que implementamos durante este curso no notará estos cambios hasta que la página se vuelva a cargar. Una situación similar surge cuando el frontend desencadena un cálculo lento en el backend. ¿Cómo reflejamos los resultados del cálculo en el frontend?
Una forma es ejecutar polling en el frontend, es decir, solicitudes repetidas a la API de backend, por ejemplo, utilizando el comando setInterval.
Una forma más sofisticada es utilizar WebSockets, mediante los cuales es posible establecer un canal de comunicación bidireccional entre el navegador y el servidor. En este caso, el navegador no necesita sondear el backend y, en su lugar, solo tienes que definir funciones callbacks para situaciones en las que el servidor envía datos sobre la actualización del estado mediante un WebSocket.
Los WebSockets son una API proporcionada por el navegador, que aún no es totalmente compatible con todos los navegadores:
En lugar de utilizar directamente la API de WebSocket, es aconsejable utilizar la librería Socket.io, que proporciona varias opciones de fallback en caso de que el navegador no tenga el soporte completo para WebSockets.
En la parte 8, nuestro tema es GraphQL, que proporciona un buen mecanismo para notificar a los clientes cuando hay cambios en los datos del backend.
Virtual DOM
El concepto de virtual DOM a menudo surge cuando se habla de React. ¿Que es todo esto? Como se mencionó en la parte 0, los navegadores proporcionan una API DOM, mediante la cual el JavaScript que se ejecuta en el navegador puede modificar los elementos que definen la apariencia de la página.
Cuando un desarrollador de software usa React, rara vez o nunca manipula directamente el DOM. La función que define el componente React devuelve un conjunto de elementos React. Aunque algunos de los elementos parecen elementos HTML normales
const element = <h1>Hello, world</h1>
internamente también son elementos de React basados en JavaScript.
Los elementos React que definen la apariencia de los componentes de la aplicación conforman el Virtual DOM, que se almacena en la memoria del sistema durante el tiempo de ejecución.
Con la ayuda de la librería ReactDOM, el DOM virtual definido por los componentes se renderiza en un DOM real que el navegador puede mostrar utilizando la API DOM:
ReactDOM.createRoot(document.getElementById('root')).render(<App />)
Cuando el estado de la aplicación cambia, los componentes definen un nuevo virtual DOM. React tiene la versión anterior del virtual DOM en la memoria y en lugar de renderizar directamente el nuevo virtual DOM usando la API DOM, React calcula la forma óptima de actualizar el DOM (eliminar, agregar o modificar elementos en el DOM) de modo que el DOM refleje el nuevo virtual DOM.
El papel de React en las aplicaciones
Es posible que en el material no hayamos puesto suficiente énfasis en el hecho de que React es principalmente una librería para administrar la creación de vistas para una aplicación. Si nos fijamos en el patrón de Modelo Vista Controlador tradicional, entonces el dominio de React sería la Vista. React tiene un área de aplicación más estrecha que, por ejemplo, Angular, que es un framework de Frontend MVC que lo abarca todo. Por lo tanto, React no es un framework, sino que es una librería.
En aplicaciones pequeñas, los datos manejados por la aplicación se almacenan en el estado de los componentes de React, por lo que en este escenario el estado de los componentes se puede considerar como modelos de una arquitectura MVC.
Sin embargo, la arquitectura MVC no se suele mencionar cuando se habla de aplicaciones React. Además, si usamos Redux, las aplicaciones siguen la arquitectura Flux y el papel de React se centra aún más en la creación de vistas. La lógica de negocio de la aplicación se maneja utilizando los creadores de acciones y estados de Redux. Si usamos Redux Thunk, que vimos en la parte 6, entonces la lógica de negocio puede separarse casi por completo del código de React.
Debido a que tanto React como Flux fueron creados en Facebook, se podría decir que usar React solo como una librería de UI es el caso de uso previsto. Seguir la arquitectura Flux agrega un poco de complejidad a la aplicación, y si estamos hablando de una pequeña aplicación o prototipo, podría ser una buena idea usar React "incorrectamente", ya que la sobre-ingeniería rara vez produce un resultado óptimo.
El ultimo capítulo de la parte 6 cubre las nuevas tendencias de gestión de estado en React. Las funciones de hooks de React useReducer y useContext proporcionan una versión liviana de Redux. React Query, por otro lado, es una librería que resuelve muchos de los problemas asociados con el manejo del estado en el servidor, eliminando la necesidad de que una aplicación React almacene los datos obtenidos del servidor directamente en el estado del frontend.
Seguridad en aplicaciones React/node
Hasta ahora, durante el curso, no hemos abordado en absoluto la seguridad de la información. Tampoco tenemos mucho tiempo ahora, pero afortunadamente la Universidad de Helsinki cuenta con un curso MOOC Securing Software que cubre este tema tan importante.
Sin embargo, echaremos un vistazo a algunas cosas específicas de este curso.
El Open Web Application Security Project (proyecto abierto de seguridad de aplicaciones web), también conocido como OWASP, publica una lista anual de los riesgos de seguridad más comunes en las aplicaciones web. La lista más reciente se puede encontrar aquí. Los mismos riesgos se pueden encontrar de un año a otro.
En la parte superior de la lista encontramos la inyección, lo que significa que, por ejemplo, el texto enviado mediante un formulario en una aplicación se interpreta de forma completamente diferente de lo que pretendía el desarrollador del software. El tipo de inyección más famoso es probablemente la inyección SQL.
Por ejemplo, si la siguiente consulta SQL se ejecuta en una aplicación vulnerable:
let query = "SELECT * FROM Users WHERE name = '" + userName + "';"
Ahora supongamos que un usuario malintencionado Arto Hellas definiría su nombre como
Arto Hell-as'; DROP TABLE Users; --
para que el nombre contenga una comilla simple '
, que es el carácter inicial y final de un string SQL. Como resultado de esto, se ejecutarían dos operaciones SQL, la segunda de las cuales destruiría la tabla Users de la base de datos.
SELECT * FROM Users WHERE name = 'Arto Hell-as'; DROP TABLE Users; --'
Las inyecciones de SQL se previenen utilizando queries parametrizadas. Con ellas, el input del usuario no se mezcla con la SQL query, en cambio, la base de datos inserta los valores del input en los placeholders de la query (normalmente ?
):
execute("SELECT * FROM Users WHERE name = ?", [userName])
Los ataques de inyección también son posibles en bases de datos NoSQL. Sin embargo, mongoose los previene desinfectando las consultas. Puedes encontrar más información sobre el tema, por ejemplo, aquí.
Cross-site scripting (XSS) es un ataque en el que es posible inyectar código JavaScript malicioso en una aplicación web legítima. Luego, el código malicioso se ejecutaría en el navegador de la víctima. Si intentamos inyectar lo siguiente en, por ejemplo, la aplicación de notas:
<script>
alert('Evil XSS attack')
</script>
el código no se ejecuta, sino que solo se renderiza como 'texto' en la página:
ya que React se encarga de desinfectar los datos en variables. Algunas versiones de React han sido vulnerables a los ataques XSS. Los agujeros de seguridad, por supuesto, han sido reparados, pero no hay garantía de que no vuelvan a suceder.
Es necesario permanecer alerta cuando se utilizan librerías; si hay actualizaciones de seguridad para esas librerías, se recomienda actualizarlas en nuestras aplicaciones. Las actualizaciones de seguridad para Express se encuentran en la documentación de la librería y las de Node se encuentran en este blog.
Puedes verificar qué tan actualizadas están tus dependencias usando el comando
npm outdated --depth 0
El proyecto del año pasado que es utilizado en la parte 9 ya tiene bastantes dependencias desactualizadas:
Las dependencias se pueden actualizar al actualizar el archivo package.json. La mejor manera de hacerlo es utilizando una herramienta llamada npm-check-updates. Puede instalarse globalmente ejecutando el comando:
npm install -g npm-check-updates
Usando esta herramienta, la actualización de las dependencias se verifica de la siguiente manera:
$ npm-check-updates
Checking ...\ultimate-hooks\package.json
[====================] 9/9 100%
@testing-library/react ^13.0.0 → ^13.1.1
@testing-library/user-event ^14.0.4 → ^14.1.1
react-scripts 5.0.0 → 5.0.1
Run ncu -u to upgrade package.json
El archivo package.json se actualiza ejecutando el comando ncu -u.
$ ncu -u
Upgrading ...\ultimate-hooks\package.json
[====================] 9/9 100%
@testing-library/react ^13.0.0 → ^13.1.1
@testing-library/user-event ^14.0.4 → ^14.1.1
react-scripts 5.0.0 → 5.0.1
Run npm install to install new versions.
Ahora es el momento de actualizar las dependencias ejecutando el comando npm install. Sin embargo, las versiones antiguas de las dependencias no necesariamente son un riesgo de seguridad.
El comando npm audit se puede utilizar para verificar la seguridad de las dependencias. Compara los números de versión de las dependencias de tu aplicación con una lista de los números de versión de las dependencias que contienen amenazas de seguridad conocidas en una base de datos de errores centralizada.
Ejecutando npm audit en el mismo proyecto, imprime una larga lista de quejas y sugerencias de arreglos. A continuación se muestra una parte del informe:
$ patientor npm audit
... many lines removed ...
url-parse <1.5.2
Severity: moderate
Open redirect in url-parse - https://github.com/advisories/GHSA-hh27-ffr2-f2jc
fix available via `npm audit fix`
node_modules/url-parse
ws 6.0.0 - 6.2.1 || 7.0.0 - 7.4.5
Severity: moderate
ReDoS in Sec-Websocket-Protocol header - https://github.com/advisories/GHSA-6fc8-4gx4-v693
ReDoS in Sec-Websocket-Protocol header - https://github.com/advisories/GHSA-6fc8-4gx4-v693
fix available via `npm audit fix`
node_modules/webpack-dev-server/node_modules/ws
node_modules/ws
120 vulnerabilities (102 moderate, 16 high, 2 critical)
To address issues that do not require attention, run:
npm audit fix
To address all issues (including breaking changes), run:
npm audit fix --force
Después de solo un año, el código está lleno de pequeñas amenazas de seguridad. Afortunadamente, solo hay 2 amenazas críticas. Ejecutemos npm audit fix como sugiere el informe:
$ npm audit fix
+ mongoose@5.9.1
added 19 packages from 8 contributors, removed 8 packages and updated 15 packages in 7.325s
fixed 354 of 416 vulnerabilities in 20047 scanned packages
1 package update for 62 vulns involved breaking changes
(use `npm audit fix --force` to install breaking changes; or refer to `npm audit` for steps to fix these manually)
62 amenazas permanecen porque, por defecto, audit fix no actualiza las dependencias si su número de versión major ha aumentado. Actualizar estas dependencias podría conducir al colapso de toda la aplicación.
El origen del error crítico es la librería immer
immer <9.0.6
Severity: critical
Prototype Pollution in immer - https://github.com/advisories/GHSA-33f9-j839-rf8h
fix available via `npm audit fix --force`
Will install react-scripts@5.0.0, which is a breaking change
Ejecutando npm audit fix --force actualizaría la versión de la librería, pero también actualizaría la librería react-scripts y eso podría potencialmente colapsar el entorno de desarrollo. Así que dejaremos las actualizaciones de librerías para más tarde...
Una de las amenazas mencionadas en la lista de OWASP es Broken Authentication y Broken Access Control. La autenticación basada en tokens que hemos estado usando es bastante sólida si la aplicación se usa con el protocolo HTTPS de cifrado de tráfico. Al implementar el control de acceso, por ejemplo, se debe recordar no solo verificar la identidad de un usuario en el navegador, sino también en el servidor. Mala seguridad sería evitar que se tomen algunas acciones solo ocultando las opciones de ejecución en el código del navegador.
En MDN de Mozilla hay una muy buena guía de seguridad de sitios web, que trae a colación este tema tan importante:
La documentación de Express incluye una sección sobre seguridad: Mejores prácticas de producción: seguridad, que vale la pena leer. También se recomienda agregar una librería llamada Helmet al backend. Incluye un conjunto de middlewares que eliminan algunas vulnerabilidades de seguridad en aplicaciones Express.
También vale la pena usar el plugin de seguridad de ESlint.
Tendencias actuales
Finalmente, echemos un vistazo a la tecnología del mañana (o en realidad ya de hoy), y las direcciones en las que se dirige el desarrollo web.
Versiones tipadas de JavaScript
A veces, el tipado dinámico de variables de JavaScript crea errores molestos. En la parte 5 hablamos brevemente sobre PropTypes: un mecanismo que permite hacer cumplir la verificación de tipos para los props pasados a los componentes de React.
Últimamente ha habido un aumento notable en el interés por la verificación de tipos estáticos. Por el momento, la versión tipada más popular de Javascript es Typescript, que ha sido desarrollado por Microsoft. Typescript se cubre en la parte 9.
Renderización del lado del servidor, aplicaciones isomórficas y código universal
El navegador no es el único dominio donde se pueden renderizar los componentes definidos usando React. La renderización también se puede realizar en el servidor. Este tipo de enfoque se utiliza cada vez más, de modo que cuando se accede a la aplicación por primera vez, el servidor muestra una página renderizada previamente creada con React. A partir de aquí, el funcionamiento de la aplicación continúa como de costumbre, es decir, el navegador ejecuta React, que manipula el DOM que muestra el navegador. La renderización que se realiza en el servidor se conoce con el nombre de server-side rendering.
Una motivación para la renderización del lado del servidor es la optimización de motores de búsqueda (SEO). Los motores de búsqueda tradicionalmente han sido muy malos para reconocer el contenido renderizado en JavaScript, sin embargo, la marea podría estar cambiando, por ejemplo, échale un vistazo a esto y esto.
Por supuesto, la renderización del lado del servidor no es algo específico de React o incluso de JavaScript. Usar el mismo lenguaje de programación en todo el stack en teoría simplifica la ejecución del concepto, porque el mismo código se puede ejecutar tanto en el frontend como en el backend.
Junto con la renderización del lado del servidor se ha hablado de las llamadas aplicaciones isomórficas y de código universal, aunque ha habido cierto debate sobre sus definiciones. Según algunas definiciones, una aplicación web isomórfica es aquella que realiza la renderización tanto en el frontend como en el backend. Por otro lado, el código universal es código que se puede ejecutar en la mayoría de los entornos, es decir, tanto el frontend como el backend.
React y Node proporcionan una opción deseable para implementar tanto una aplicación isomorfa como código universal.
Escribir código universal directamente usando React todavía es bastante engorroso. Últimamente, una librería llamada Next.js, que se implementa sobre React, ha atraído mucha atención y es una buena opción para hacer aplicaciones universales.
Aplicaciones web progresivas
Recientemente, la gente ha comenzado a usar el término aplicación web progresiva (PWA) lanzado por Google.
En resumen, estamos hablando de aplicaciones web funcionando lo mejor posible en todas las plataformas, aprovechando las mejores partes de esas plataformas. La pantalla más pequeña de los dispositivos móviles no debe obstaculizar la usabilidad de la aplicación. Las PWA también deberían funcionar sin problemas sin Internet o con una conexión a Internet lenta. En dispositivos móviles, deben ser instalables como cualquier otra aplicación. Todo el tráfico de red en una PWA debe estar cifrado.
Arquitectura de microservicios
Durante este curso solo hemos arañado la superficie del lado del servidor. En nuestras aplicaciones teníamos un backend monolítico, es decir, una aplicación que formaba un todo y se ejecutaba en un solo servidor, sirviendo solo unos pocos endpoints de API.
A medida que la aplicación crece, el enfoque de backend monolítico comienza a tornarse problemático tanto en términos de rendimiento como de mantenibilidad.
Una arquitectura de microservicios es una forma de componer el backend de una aplicación a partir de muchos servicios independientes que se comunican entre sí a través de la red. El propósito de un microservicio individual es encargarse de un todo funcional lógico particular. En una arquitectura de microservicios pura, los servicios no utilizan una base de datos compartida.
Por ejemplo, la aplicación de lista de blogs podría constar de dos servicios: uno que maneja al usuario y otro que se ocupa de los blogs. La responsabilidad del servicio de usuario sería el registro y la autenticación del usuario, mientras que el servicio de blogs se haría cargo de las operaciones relacionadas con los blogs.
La siguiente imagen muestra la diferencia entre la estructura de una aplicación basada en una arquitectura de microservicios y una basada en una estructura monolítica más tradicional:
El papel del frontend (encerrado por un cuadrado en la imagen) no difiere mucho entre los dos modelos. A menudo existe una API gateway (puerta de enlace API) entre los microservicios y el frontend, que proporciona la ilusión de una API más tradicional de "todo en el mismo servidor". Netflix, entre otros, utiliza este tipo de enfoque.
Las arquitecturas de microservicios surgieron y evolucionaron para las necesidades de las grandes aplicaciones a gran escala de Internet. Amazon marcó la tendencia mucho antes de la aparición del término microservicio. El punto de partida crítico fue un correo electrónico enviado a todos los empleados en 2002 por el CEO de Amazon, Jeff Bezos:
De ahora en adelante, todos los equipos expondrán sus datos y funcionalidad a través de interfaces de servicio.
Los equipos deben comunicarse entre sí a través de estas interfaces.
No se permitirá ninguna otra forma de comunicación entre procesos: ningún enlace directo, ninguna lectura directa del almacén de datos de otro equipo, ningún modelo de memoria compartida, ninguna puerta trasera. La única comunicación permitida es a través de llamadas de interfaz de servicio a través de la red.
No importa qué tecnología uses.
Todas las interfaces de servicio, sin excepción, deben diseñarse desde cero para ser externalizables. Es decir, el equipo debe planificar y diseñar para poder exponer la interfaz a los desarrolladores del mundo exterior.
Sin excepciones.
Cualquiera que no haga esto será despedido. Gracias; ¡que tengas un buen día!
Hoy en día, uno de los mayores precursores en el uso de microservicios es Netflix.
El uso de microservicios ha ido ganando popularidad hasta convertirse en una especie de bala de plata de hoy en día, que se ofrece como una solución a casi todo tipo de problemas. Sin embargo, hay una serie de desafíos cuando se trata de aplicar una arquitectura de microservicios, y podría tener sentido ir primero al monolito al hacer inicialmente un backend tradicional que lo abarque todo. O quizás no. Hay un montón de opiniones diferentes sobre el tema. Ambos enlaces conducen al sitio de Martin Fowler; como podemos ver, incluso los sabios no están completamente seguros de cuál de las formas correctas es la más correcta.
Desafortunadamente, no podemos profundizar en este importante tema durante este curso. Incluso una mirada superficial al tema requeriría al menos 5 semanas más.
Serverless (Sin servidor)
Después del lanzamiento del servicio Lambda de Amazon a fines de 2014, comenzó a surgir una nueva tendencia en el desarrollo de aplicaciones web: sin servidor.
Lo principal acerca de Lambda, y hoy en día también de Google Cloud functions, así como de una funcionalidad similar en Azure, es que permite la ejecución de funciones individuales en la nube. Antes, la unidad ejecutable más pequeña en la nube era un proceso único, por ejemplo, un entorno de ejecución que ejecuta un backend de Node.
Utilizando la API gateway de Amazon es posible crear aplicaciones sin servidor donde las solicitudes a la API HTTP definida obtienen respuestas directamente de las funciones de la nube. Por lo general, las funciones ya operan utilizando datos almacenados en las bases de datos del servicio en la nube.
Serverless no se trata de que no haya un servidor en las aplicaciones, sino de cómo se define el servidor. El desarrollador de software puede cambiar sus esfuerzos de programación a un mayor nivel de abstracción, pues ya no es necesario definir mediante programación el enrutamiento de solicitudes HTTP, relaciones de bases de datos, etc., debido a que la infraestructura de la nube proporciona todo esto. Las funciones en la nube también se prestan para crear un buen sistema de escalado, por ejemplo, Lambda de Amazon puede ejecutar una gran cantidad de funciones en la nube por segundo. Todo esto ocurre automáticamente a través de la infraestructura y no es necesario iniciar nuevos servidores, etc.
Librerías útiles y enlaces interesantes
La comunidad de desarrolladores de JavaScript ha producido una gran variedad de librerías útiles. Si estás desarrollando algo más sustancial, vale la pena comprobar si las soluciones existentes ya están disponibles. A continuación se enumeran algunas librerías recomendadas por partes confiables.
Si tu aplicación tiene que manejar datos complicados, lodash, que recomendamos en la parte 4, es una buena librería para usar. Si prefieres un estilo de programación funcional, podrías considerar usar ramda.
Si maneja horas y fechas, date-fns ofrece buenas herramientas para eso.
Si tienes formularios complejos en tus aplicaciones, puede que React Hook Form sea una buena opción.
Si tu aplicación muestra gráficos, hay varias opciones para elegir. Se recomiendan tanto recharts como highcharts .
La librería Immer provee implementaciones inmutables de algunas estructuras de datos. La librería podría ser útil cuando se usa Redux, ya que como recordamos de la parte 6, los reducers deben ser funciones puras, lo que significa que no deben modificar el estado del store, sino que deben reemplazarlo por uno nuevo cuando se produce un cambio.
Redux-saga proporciona una forma alternativa de hacer las acciones asíncronas para redux thunk que vimos en la parte 6. Algunos abrazan el hype y les gusta. Yo no.
Para las aplicaciones de una sola página, la recopilación de datos analíticos sobre la interacción entre los usuarios y la página es más desafiante que para las aplicaciones web tradicionales donde se carga toda la página. La librería React Google Analytics 4 ofrece una solución.
Puedes aprovechar tu conocimiento de React al desarrollar aplicaciones móviles utilizando la extremadamente popular librería React Native de Facebook, la cual es el tema de la parte 10 del curso.
En lo que respecta a las herramientas utilizadas para la gestión y bundling de proyectos de JavaScript, la comunidad ha sido muy voluble. Las mejores prácticas han cambiado rápidamente (los años son aproximaciones, nadie recuerda bien tan atrás en el tiempo):
Los hipsters parecían haber perdido su interés en el desarrollo de herramientas después de que webpack comenzara a dominar los mercados. Hace unos años, Parcel comenzó a hacer marketing, vendiéndose a sí mismo como más simple (cosa que Webpack no es) y más rápido que Webpack. Sin embargo, después de un comienzo prometedor, Parcel no ha cobrado fuerza. Pero recientemente, esbuild ha ganado mucha popularidad y ya está reemplazando a Webpack.
El sitio https://reactpatterns.com/ ofrece una lista concisa de las mejores prácticas para React, algunas de las cuales ya son familiares en este curso. Otra lista similar es react bits.
Reactiflux es una gran comunidad de chat de desarrolladores de React en Discord. Podría ser un buen lugar para obtener ayuda después de que el curso haya concluido. Numerosas librerías tienen sus propios canales.
Si conoces algunos enlaces o librerías recomendables, ¡haz un pull request!