Listado

Comentamos en equipo Tao of React de Alex Kondov

Como desarrolladores, una de las cosas a las que dedicamos mas tiempo es a leer, no solo código, sino también documentación, libros y, por supuesto, artículos sobre nuestro campo. Y no siempre es fácil encontrar buenos textos. Por si no lo conoces, te recomendamos uno de los artículos que más nos gustan en Redradix, TAO of React de Alex Kondov.

Autor/a

Fecha de publicación

15/3/2023

Compartir

Twitter

LinkedIn

En este artículo (que bien podría ser un libro), Alex Kondov habla sobre las mejores prácticas para trabajar con React. Para ello, el autor lo divide en varias secciones en las que se comentan temas específicos sobre componetización, stage management, cómo estructurar la aplicación, testing, etc.

La cosa es que aquí, en Redradix, sabemos también bastante de React, así que nos animamos a hacer una mesa redonda para comentar Tao of React de forma conjunta entre los equipos de maqueta y desarrollo. El objetivo era ver cuántas de las buenas prácticas que recoge el texto teníamos integradas en nuestro día a día, descubrir si había alguna más que pudiéramos incorporar o, si directamente, no estábamos de acuerdo con alguno de los puntos comentados. A partir de las conclusiones de este encuentro nació esta entrada del blog.

Los puntos que destacamos aquí son aquellos con los que no estábamos del todo de acuerdo o en los que había división de opiniones. A nuestro entender, el resto de recomendaciones que no se mencionan y que sí aparecen en el artículo forman parte de las buenas prácticas y son realmente aplicables en el día a día.

Components

En esta sección se plantea cómo deberíamos crear los componentes y cómo estructurar el código de los mismos. A este respecto hubo una serie de puntos con los que se generó más debate:

  • Favor functional components → Según lo vemos en Redradix, no tiene que ser un dogma el hacer componentes funcionales, ya que si el equipo que desarrolla se encuentra más cómodo trabajando con el paradigma de Programación Orientada a Objetos (OOP) no tiene por qué dejar de hacerlo. Igual en este otro ejemplo, si estás en un proyecto que ya tiene hecha una base de componentes basados en React, tampoco hay por qué cambiarlo. Al final tiene que ser elección del equipo orientarlo hacia la mejor solución posible.
  • Conditional rendering → En este punto hubo un poco de fricción, puesto que algunos compañeros se sentían cómodos usando tanto el conditional rendering como el short circuit. Lo que sí que vimos es que cuando se decide usar el short circuit hay que estar seguros de que estamos operando siempre con un valor booleano y no con valores falsy o truthy.
// 👍 Usar ternario
function Component() {
  const count = 0

  return <div>{count ? <h1>Messages: {count}</h1> : null}</div>
}

// 👎 Evitar valores falsys / truthys
function Component() {
  const count = 0

  return <div>{count && <h1>Messages: {count}</h1>}</div>
}

// 👍 Evaluar condicion que devuelva un booleano
function Component() {
  const count = 0

  return <div>{count > 0 && <h1>Messages: {count}</h1>}</div>
}

Move Lists in a Separate Component → Aquí tuvimos consenso en que solo tiene sentido emplearlo si la lista es lo suficientemente compleja. Si es una lista que apenas tiene lógica y solo se consume en un sitio localizado igual no hace falta abstraerlo.

Destructure Props → Sobre esto también hubo un debate interesante acerca de si las [.rr-code]props[.rr-code] de los componentes debemos desestructurarlas o usar [.rr-code]props.property[.rr-code] para saber diferenciar qué viene de fuera del componente y qué es local del propio componente.

Para poder reflejar esto ultimo sin tener que renunciar a desestructurar las [.rr-code]props[.rr-code], nuestro compañero Alejandro Mur nos propuso una solución alternativa definiendo el objeto de las [.rr-code]PropTypes[.rr-code] arriba del componente para así, en un primer vistazo, ver la definición de dichas [.rr-code]props[.rr-code].

const refillViewPropTypes = {
  onCancel: PropTypes.func.isRequired,
  onContinue: PropTypes.func.isRequired,
  onSkip: PropTypes.func.isRequired,
}

const RefillView = ({ onCancel, onContinue, onSkip }) => ()

RefillView.propTypes = refillViewPropTypes

Stage Management

Esta sección, como su nombre indica, está dedicada a cómo afrontar el problema de la gestión del estado en nuestras aplicaciones. En general este tema siempre es complejo, así que fue uno de los que más debate generaron en nuestra charla.

  • Use Reducers & State management libraries → Antes de decidir si usar reducers, redux o cualquier otro recurso para gestionar el estado, tenemos que analizar cuán complejo es nuestro estado y si realmente emplear algo de esto no es complicarnos la vida. Tampoco es una decisión que debamos tomar prematuramente, ya que según vaya creciendo el proyecto puede ser que necesitemos o bien escalar a una cosa o mantenernos como estamos. Así que no creemos que sea una regla escrita en piedra.
  • Use Hooks and not HOCS → Las últimas versiones de React implementaron lo que se conoce como hooks. Esto nos ha dado a los equipos de desarrollo una manera de hacer las cosas menos verbosa que las clases, así como una mayor facilidad de lectura y simplicidad. Pero no creemos que sea lo idóneo aplicar esta regla de usar siempre de manera dogmática hooks y nunca HOCS o render props. Como siempre, aplicar lo que consideremos que es mejor para cada caso.
  • Use data fetching libraries → Parece que este tipo de decisiones siempre son muy obvias pero, de nuevo y como nos repetimos en Redradix, no hay que caer en decisiones prematuras. El artículo invita a usar react query pero, ¿es realmente necesario para un proyecto en el que hagas 3 llamadas de tipo GET a un API incorporar una librería como React Query? Ya existen alternativas nativas para hacer eso como [.rr-code]fetch[.rr-code] sin que tengas que incorporar nada a tu proyecto, así que hay que intentar ser conscientes y analizar si realmente es necesario o no.

También es bueno encapsular debidamente en tu código los lugares donde se hace el uso del data fetching, por si en algún momento se decide meter una librería, que haya que tocar el mínimo de sitios posible y esté muy acotada la modificación.

Component mental models

En esta sección se tratan temas más abstractos, como la jerarquización de responsabilidades que le damos a nuestros componentes.

Una práctica bastante conocida es la que se conoce como el patrón presentador & contenedor (o smart & stub), que es la que normalmente la gente utiliza.

En el artículo de TAO of React, el autor nos viene a decir que ese modelo mental puede ser peligroso en aplicaciones con mucha lógica. El motivo: que el modelo mental hace que pensemos en muchos componentes que contienen poca funcionalidad (solo responsabilidades de renderizado) y en otros que centralizan toda la funcionalidad, lo que provoca que queden componentes con demasiada responsabilidad, monolíticos y grandes.

Pero el artículo al final acaba argumentando una jerarquización estricta entre componentes statefull & statless, algo que tampoco creemos que sea lo mejor porque al final supone crear otro patrón mental estricto.

Por eso nosotros apostamos más por ser conscientes de a qué ritmo pueden “cambiar” las implementaciones para así ser capaces de saber cuándo separarlas:

  • Por ejemplo, es posible que el diseño presentacional cambie a un ritmo mucho mayor que la lógica. Por lo que tiene sentido separar en esos dos ámbitos, presentación y lógica.
  • Y mientras, sin embargo, un componente de presentación no tiene porque estar ausente de lógica.

Application Structure

En esta sección ya nos alejamos un poco del código como tal y nos vamos a la estructuración de los ficheros de código fuente y su jerarquización en carpetas.

  • Group Route / module → En Redradix nos sentimos cómodos trabajando con lo que se conoce como arquitecturas incrementales. Nosotros pensamos que asumir una estructura nada más arrancar el proyecto podría ser una abstracción prematura. Aunque al final llegues a una estructura como la que comenta al artículo es mejor llegar de manera orgánica y natural que crearla prematuramente, ya que el código debe colocarse de manera armoniosa y orgánica según va creciendo, usando conceptos como el de colocalización.
  • Create a common module → Esta abstracción nos suscitó bastante ruido porque en diferentes proyectos hemos acabado teniendo el típico [.rr-code]shared[.rr-code] y al final acaba saliendo un cajón de sastre donde se mete de todo y sin sentido. De nuevo, nosotros abogamos más por aplicar el principio de colocalización para ir escalando el (los) módulo(s) al nivel que se necesite.
  • Use Absolute Paths → En este punto tampoco estamos de acuerdo con Kondov, ya que pensamos que usar alias te aleja de ser consciente de la estructura de carpetas del proyecto. Esto genera que acabes pudiendo descuidar dónde colocas las cosas y perdiendo consciencia de dónde esta todo. Ademas de que algunos IDES tienen problemas con los alias y no referencian bien el fichero.
  • Wrap external components → Estamos bastante de acuerdo en que wrappear es una buena práctica, lo que pasa es que creemos que hay librerías más susceptibles de ser wrapeables que otras. No es lo mismo wrappear una librería de componentes que usamos por todo el proyecto y que es más difícil que cambie, que una pequeña librería que empleamos para algún caso de uso.

Por eso aquí hay que aplicar un poco de sentido común y analizar las librerías que consumimos y ver si hay mucha probabilidad de cambie de cara al futuro.

Performance

Esta sección comenta buenas practicas de cara a mantener un buen rendimiento de la aplicación, así como su correcto bundle size.

  • Don´t optimize prematurely → Compartimos lo que dice el artículo y, además, recomendamos una filosofía que aparece en el libro de Implementation patterns que es Make it work, make it right, make it fast que viene a decir que hay cosas más importantes que la optimización, como por ejemplo que el código sea lo más simple, legible y mantenible posible.
  • Watch the bundle size → Estamos de acuerdo con Kondov y añadimos un tip: a la hora de elegir una librería de terceros es importante valorar no solo su popularidad, sino también ver cuán grande es y asegurarnos que tenga tree shaking para integrar solo lo que realmente se usa y no toda la librería.

Testing

Esta es una de las partes mas comentadas y más controvertidas en el desarrollo de software, el testing.

En esta sección estuvimos de acuerdo en gran parte de los puntos comentados, aunque creemos que aquí el artículo toca un tema que se excede un poco del objetivo del mismo, puesto que se aleja de React per se para hablar del testing en general. Las principales conclusiones que sacamos sobre esto fueron:

  • Siempre hay que intentar hacer test, así que hay que pelearlo en la medida que esto sea posible ya que el código mantenible y escalable también es fácilmente testable.
  • Cuando testeas renderizado de UI, hay que verificar tanto lo que se muestra como lo que tiene que estar oculto cuando tiene que estarlo.
  • Hay que testar, en la medida de lo posible, los Edge Cases de los test.
  • Cuando no hay mucho margen para hacer test, pensamos que es mejor priorizar test de integración, ya que creemos que los e2e son complejos (tal y como dice la pirámide de testing), y los tests unitarios al final nos permiten saber sobre cada componente pero no cómo funcionan en conjunto.

Styling

Este apartado se centra en las mejores prácticas para usar con React.

  • Use css in js → Aquí el autor recomienda usar css in js pero, y al igual que expone en una nota al final de la sección, realmente pensamos que no hay solución mejor que aquella con la que el equipo se sienta más cómodo y haga mejor su trabajo.
  • Keep styled components together → Nos ocurre como con la agrupación de ficheros, estamos de acuerdo con el artículo, pero aplicando siempre el principio de colocalización.

Finalmente, a modo de resumen, y como conclusiones generales, queremos destacar algunos puntos que surgieron de forma recurrente durante la conversación:

  • Es importante ser consciente de las decisiones que tomamos y por qué las tomamos.
  • Hay que hacerse las preguntas relevantes en el momento oportuno. Plantearse cuestiones como: ¿Tiene sentido meter redux? ¿Necesito realmente una librería para hacer peticiones, o podemos tirar sin ella usando solo fetch? ¿Necesito una librería de terceros para este pequeño caso de uso?
  • No hay que caer en decisiones ni abstracciones prematuras.

Y como conclusión general: hay que evitar caer en dogmas y verdades universales. Como hemos visto en este artículo siempre conviene tener un pensamiento critico y elaborar una opinión propia y siempre, siempre, consensuarla con el equipo 😊.

Relacionados

Extendiendo el principio de colocalización

Hace un tiempo publicamos un artículo sobre el principio de colocalización, una traducción libre del artículo “Colocation” de Kent C. Dodds. Hoy nos gustaría profundizar en este principio, explicando a dónde nos ha llevado en RedRadix.

26/3/2024

Construir sobre cimientos sólidos: la clave de las auditorías de código

La calidad del código es fundamental para el éxito a largo plazo de un proyecto. Sin embargo, a medida que este crece es común que el código acumule complejidad no deseada y que esta impacte en su mantenimiento y eficiencia. Por eso aquí hablamos de por qué y cómo hacer una buena auditoría del código front-end de un proyecto.

5/3/2024

Button Text