¿Qué es una arquitectura front-end escalable?

Cuando se trata de desarrollo de software, los dos significados más comunes de la palabra escalabilidad se relacionan con el rendimiento y la capacidad de mantenimiento a largo plazo de una base de código. Puede tener ambos, pero centrarse en una buena capacidad de mantenimiento hará que sea más fácil ajustar el rendimiento sin afectar otras partes de la aplicación. Esto es aún más cierto en primer plano, donde tenemos una distinción importante con respecto al backend: el estado local.

En esta serie de artículos, hablaremos sobre cómo desarrollar y mantener una aplicación front-end escalable utilizando métodos probados en la vida real. La mayoría de nuestros ejemplos usarán React y Redux, pero a menudo los compararemos con otras pilas tecnológicas para mostrar cómo puede lograr el mismo efecto. Comencemos hablando de la arquitectura de esta serie, la parte más importante de su software.

¿Qué es la arquitectura de software?
¿Qué es exactamente la arquitectura? Puede parecer pretencioso decir que la arquitectura es la parte más importante de su software, pero escúcheme.

La arquitectura es cómo hace que las diversas unidades de su software interactúen para resaltar las decisiones más importantes que debe tomar y diferir las decisiones menores y los detalles de implementación. Diseñar la arquitectura de un software significa separar la aplicación real de sus tecnologías de soporte. Su aplicación real no tiene conocimiento de bases de datos, solicitudes AJAX o GUI; en cambio, está compuesta de casos de uso y unidades de dominio que representan los conceptos cubiertos por su software, independientemente de los roles en los que se ejecutan los casos de uso o dónde se almacenan los datos. se persiste.

Hay algo más importante de lo que hablar sobre la arquitectura: no implica la organización de archivos, ni cómo se nombran los archivos y las carpetas.


Capas en el desarrollo front-end
Una forma de separar las cosas importantes de las menos importantes es usar capas, cada una con responsabilidades diferentes y específicas. En una arquitectura basada en capas, un enfoque común es dividirla en cuatro capas: aplicación, dominio, infraestructura y entrada. Estas cuatro capas se explican mejor en otro artículo "NodeJS y Buenas Prácticas". Le recomendamos que lea la primera parte de la publicación sobre ellos antes de continuar. No necesita leer la segunda parte, ya que es específica de NodeJS.

Las capas de dominio y aplicación no son tan diferentes entre front-end y back-end porque son independientes de la tecnología, pero no podemos decir lo mismo de las capas de entrada e infraestructura. En los navegadores web, la capa de entrada generalmente tiene una sola función, la vista, por lo que incluso podríamos llamarla capa de vista. Además, la interfaz no tiene acceso a una base de datos ni a un motor de colas, por lo que no los encontraremos en nuestra capa de infraestructura de interfaz. Lo que encontraremos son abstracciones que encapsulan solicitudes AJAX, cookies de navegador, almacenamiento local e incluso unidades para interactuar con servidores WebSocket. La principal diferencia es simplemente algo que se abstrae, por lo que incluso puede tener repositorios frontend y backend con exactamente la misma interfaz pero con diferentes tecnologías subyacentes. ¿Puedes ver lo asombrosa que puede ser una buena abstracción?

No importa si usa React, Vue, Angular o algo más para crear sus vistas. Es importante seguir las reglas de la capa de entrada sin ninguna lógica, delegando así los parámetros de entrada a la siguiente capa. Hay una regla más importante sobre las arquitecturas basadas en capas de front-end: para que la capa de entrada/vista esté siempre sincronizada con el estado local, debe seguir un flujo de datos unidireccional. ¿Te suena familiar este término? Podemos hacer esto agregando una quinta capa especializada: estado, también conocida como almacenamiento.


Capa de estado
Mientras seguimos un flujo de datos unidireccional, nunca mutamos o mutamos los datos recibidos por una vista directamente en la vista. En su lugar, despachamos lo que llamamos "acciones" desde la vista. Funciona así: una acción envía un mensaje a la fuente de datos, la fuente de datos se actualiza y se vuelve a enviar a la vista con los nuevos datos. Tenga en cuenta que nunca hay una ruta directa de la vista a la tienda, por lo que si dos subvistas usan los mismos datos, puede enviar acciones desde cualquiera de las subvistas, lo que hará que ambas subvistas se vuelvan a representar con los nuevos datos. Parece que estoy hablando específicamente de React y Redux, pero ese no es el caso; puede lograr el mismo resultado con casi cualquier marco o biblioteca de front-end moderno, como React + context API, Vue + Vuex, Angular + NGXS , o incluso Ember, utilice el método de reducción de datos (también conocido como DDAU). ¡Incluso puedes hacerlo con jQuery, usando su sistema de eventos para enviar acciones!

Esta capa es responsable de administrar el estado local y en constante cambio de su interfaz, como los datos obtenidos desde el backend, los datos efímeros creados en la interfaz pero que aún no se conservan o información transitoria como el estado de una solicitud. En caso de que te lo preguntes, esta es la capa donde residen las acciones y los controladores responsables de actualizar el estado.

Aunque a menudo vemos reglas comerciales y definiciones de casos de uso en la base de código ubicadas directamente en la acción, si lee la descripción de las otras capas detenidamente, encontrará que ya tenemos un lugar para colocar nuestros casos de uso y reglas comerciales, no la capa de estado. ¿Significa esto que nuestras acciones ahora son casos de uso? ¡No! Sí. Entonces, ¿cómo debemos tratarlos?

Pensemos en ello... dijimos que la acción no es un caso de uso, y ya tenemos una capa para poner nuestros casos de uso. La vista debe enviar la acción, la acción recibe la información de la vista, la entrega al caso de uso, envía una nueva acción de acuerdo con la respuesta y finalmente actualiza el estado: actualiza la vista y cierra el flujo de datos unidireccional. ¿Estas acciones suenan como controladores ahora? ¿No son el lugar para tomar parámetros de la vista, delegar al caso de uso y responder en función del resultado del caso de uso? Así es exactamente como debes tratarlos. No debe haber lógica compleja o llamadas AJAX directas aquí, ya que estas son responsabilidad de otra capa. La capa de estado solo debe saber cómo administrar el almacenamiento local, nada más.

Hay otro factor importante en juego. Dado que la capa de estado administra el almacenamiento local consumido por la capa de vista, notará que las dos están algo acopladas. Habrá algunos datos de solo lectura en la capa de estado, como una bandera booleana que indica si una solicitud aún está pendiente, de modo que la vista pueda mostrar un control giratorio, lo cual está perfectamente bien.

código:

import api from './infra/api'; // has no dependencies
import { validateUser } from './domain/user'; // has no dependencies
import makeUserRepository from './infra/user/userRepository';
import makeArticleRepository from './infra/article/articleRepository';
import makeCreateUser from './app/user/createUser';
import makeGetArticle from './app/article/getArticle';

const userRepository = makeUserRepository({
  api
});

const articleRepository = makeArticleRepository({
  api
});

const createUser = makeCreateUser({
  userRepository,
  validateUser
});

const getArticle = makeGetArticle({
  userRepository,
  articleRepository
});

export {
  createUser,
  getArticle
};
export default ({ validateUser, userRepository }) => async (userData) => {
  if(!validateUser(userData)) {
    throw new Error('Invalid user');
  }

  try {
    const user = await userRepository.add(userData);
    return user;
  } catch(error) {
    throw error;
  }
};
export default ({ api }) => ({
  async add(userData) {
    const user = await api.post('/users', userData);

    return user;
  }
});

Notará que las partes importantes, los casos de uso createUser, etc., se instancian al final del archivo y son los únicos objetos que se exportan, ya que se inyectarán en la Acción. El resto de su código no necesita saber cómo se creó el repositorio y cómo funciona. Realmente no importa, es solo un detalle técnico.
No importa para el caso de uso si el repositorio envía una solicitud AJAX o persiste algo en LocalStorage; no es responsabilidad del caso de uso saber eso. Si desea usar LocalStorage mientras su API aún está en desarrollo y luego cambiar a llamadas en línea a la API, siempre que el código que interactúa con la API siga la misma interfaz que el código que interactúa con LocalStorage, no No es necesario cambiar su caso de uso.

Incluso si tiene docenas de casos de uso, repositorios, servicios, etc., puede realizar la inyección manualmente como se describe anteriormente. Si construir todas las dependencias es demasiado complicado, puede usar un paquete de inyección de dependencia, siempre que no aumente el acoplamiento.

Una regla general para probar si su paquete DI es lo suficientemente bueno es verificar que pasar de un enfoque manual a usar la biblioteca no requiere tocar nada más que el código del contenedor. Si es así, entonces el paquete es demasiado problemático y debe elegir un paquete diferente. Si realmente quieres usar un paquete, te recomendamos Awilix. Es bastante simple de usar, y es improvisado, simplemente tocando el archivo contenedor. Hay una muy buena serie sobre cómo usarlo y por qué, escrita por el autor del paquete. 

Supongo que te gusta

Origin blog.csdn.net/weixin_44786530/article/details/130194702
Recomendado
Clasificación