Cuando empezamos a desarrollar un proyecto con un nuevo lenguaje o framework una de las primeras dudas que nos surgen es cómo organizo mi proyecto y, en el caso de React, esto no es una excepción.

Si nos basamos en la documentación oficial, React no define una forma correcta de organizar nuestros ficheros y lo deja a criterio del desarrollador. Esto puede parecer extraño si hemos trabajado anteriormente con frameworks como Angular, pero hay que tener en cuenta que React es una librería de frontend que se puede utilizar tanto para crear aplicaciones completas, como para componentes concretos dentro de una base de código ya existente, por lo tanto tiene sentido que esta elección sea libre.

Sin embargo, ofrecen un par de ejemplos acerca de estructuras popularmente utilizadas. Estas son la estructura basada en tipo de fichero y la estructura basada en funcionalidades. Por desgracia, las variantes que muestran se quedan cortas y no cubren ni el proyecto más simple.

En este artículo vamos a ver 4 formas de organizar y estructurar proyectos que utilicen tanto React como React Native y daremos nuestra opinión acerca de estas.

Estructura de carpetas para proyecto React

Estructura por tipo de fichero

Si estamos empezando a utilizar React lo más probable es que empecemos con una organización basada en tipo de fichero donde la mayoría de los ficheros se sitúan dentro de carpetas con el nombre de cada tipo y que están en el nivel principal de nuestra aplicación.

Esta organización nos permite tener estructuras muy sencillas para proyectos que estén empezando o queramos realizar sin demasiados quebraderos de cabeza, y es la que recomendaría para todos aquellos que se inicien con React. El problema principal es que una vez empieza a crecer nuestro proyecto puede convertirse en un auténtico caos, sobre todo a nivel de componentes, ya que en la variante más sencilla los tendríamos todos dentro de una carpeta llamada componentes.

Por eso la versión que más me gusta para este tipo de organización es la que diferencia entre componentes y páginas. De esta forma en la raíz tendríamos una carpeta componentes para los componentes compartidos, y en la carpeta de páginas cada página contendría la vista principal y los componentes que solo se utilizan en esa página. Con esta variación esta estructura escala mucho mejor y la podemos llevar a proyectos mucho más grandes.

src/
|-- components/
|   |-- Avatar/
|   |   |-- Avatar.jsx
|   |   |-- Avatar.test.js
|   |-- Button/
|   |   |-- Button.jsx
|   |   |-- Button.test.js
|   |-- TextField/
|   |   |-- TextField.jsx
|   |   |-- TextField.test.js
|-- contexts/
|   |-- UserContext/
|   |   |-- UserContext.js
|-- hooks/
|   |-- useMediaQuery/
|   |   |-- useMediaQuery.js
|-- pages/
|   |-- UserProfile/
|   |   |-- components/
|   |   |   |-- SomeUserProfileComponent/
|   |   |   |   |-- SomeUserProfileComponent.jsx
|   |   |   |   |-- SomeUserProfileComponent.test.js
|   |   |-- UserProfile.jsx
|   |   |-- UserProfile.test.js
|   |-- index.js
|-- routes/
|   |-- routes.jsx
|   |-- routes.test.js
|-- utils/
|   |-- some-util/
|   |   |-- index.js
|   |   |-- someUtil.js
|   |   |-- index.test.js
|-- services/
|   |-- some-service/
|   |   |-- index.js/
|   |   |-- someService.js/
|   |   |-- index.test.js
|-- App.jsx
|-- index.js

Cómo podemos ver en el ejemplo, esta estructura es muy intuitiva para cualquier persona que vea nuestro código, por eso es la organización que más se suele utilizar cuando se empieza a utilizar React.

Estructura por funcionalidad o modular

La siguiente forma de organización que se menciona en la documentación es la basada en módulos, esta organización es interesante para proyectos con una escala mayor.

La idea principal es que cada módulo que definimos tenga todo el código relacionado con este y solo se importe código del modulo en sí. Cuando tenemos varios módulos que necesitan de la misma pieza de código esta la podemos escribir dentro de una carpeta compartida e importarla a los diferentes módulos. La regla fundamental que se pretenden seguir es no importar código entre módulos.

src/
|-- components/
|   |-- Avatar/
|   |   |-- Avatar.jsx
|   |   |-- Avatar.test.js
|   |-- Button/
|   |   |-- Button.jsx
|   |   |-- Button.test.js
|   |-- TextField/
|   |   |-- TextField.jsx
|   |   |-- TextField.test.js
|-- contexts/
|   |-- UserContext/
|   |   |-- UserContext.js
|-- hooks/
|   |-- useMediaQuery/
|   |   |-- useMediaQuery.js
|-- features/
|   |-- Home/
|   |   |-- components/
|   |   |   |-- SomeUserProfileComponent/
|   |   |   |   |-- SomeUserProfileComponent.jsx
|   |   |   |   |-- SomeUserProfileComponent.test.js
|   |   |-- utils/
|   |   |-- services/
|   |   |-- hooks/
|   |   |-- contexts/
|   |   |-- views/
|   |   |   |-- HomeView.jsx
|   |   |-- pages/
|   |   |   |-- HomePage.jsx
|   |-- index.js
|-- utils/
|   |-- some-common-util/
|   |   |-- index.js/
|   |   |-- index.test.js
|-- services/
|   |-- some-common-service/
|   |   |-- index.js/
|   |   |-- some-common-service.js/
|   |   |-- index.test.js
|-- App.jsx
|-- index.js

Las ideas principales de esta forma de organización parten de los conceptos explicados en Domain Driven Design aplicados desde hace tiempo en el backend. El gran inconveniente de esta estructura es que puede ser complejo definir qué es un modulo ya que, en función de cómo se haga, radicará el mayor o menor éxito de nuestra organización.

Estructura basada en Atomic design

Una vez cubiertas la estructura basada en módulos y en tipo de ficheros, otro de los conceptos que suelen aparecer a menudo es el de Atomic Design. Esta es una metodología para crear sistemas de diseño desarrollada por Brad Frost y Dave Olsen y no es exclusiva de React, pero encaja muy bien con la librería debido a la forma de crear interfaces en base a componentes.

Más que una forma completa de estructurar nuestro proyecto, se trata de una forma de organizar los componentes. Por lo tanto sería más bien un patrón que podemos aplicar dentro de nuestra organización ya existente.

La idea principal es dividir nuestros componentes en cinco tipos de elementos:

  • Átomos
  • Moléculas
  • Organismos
  • Templates
  • Páginas

Si aplicamos esto en las dos estructuras que hemos visto quedarían de la siguiente manera:

Basada en tipo de fichero

src/
|-- components/
|	 |- atoms/
|  |  |-- Button/
|	 |  |   |-- Button.jsx
|	 |  |   |-- Button.test.js
|  |- molecules
|  |- organisms
|  |- templates
|-- contexts/
|   |-- UserContext/
|   |   |-- UserContext.js
|-- hooks/
|   |-- useMediaQuery/
|   |   |-- useMediaQuery.js
|-- pages/
|   |-- UserProfile/
|   |   |-- components/
|   |   |   |-- SomeUserProfileComponent/
|   |   |   |   |-- SomeUserProfileComponent.jsx
|   |   |   |   |-- SomeUserProfileComponent.test.js
|   |   |-- UserProfile.jsx
|   |   |-- UserProfile.test.js
|   |-- index.js
|-- routes/
|   |-- routes.jsx
|   |-- routes.test.js
|-- utils/
|   |-- some-util/
|   |   |-- index.js
|   |   |-- someUtil.js
|   |   |-- index.test.js
|-- services/
|   |-- some-service/
|   |   |-- index.js/
|   |   |-- someService.js/
|   |   |-- index.test.js
|-- App.jsx
|-- index.js

Basada en funcionalidad

src/
|-- components/
|	 |- atoms/
|  |  |-- Button/
|	 |  |   |-- Button.jsx
|	 |  |   |-- Button.test.js
|  |- molecules
|  |- organisms
|  |- templates
|-- contexts/
|   |-- UserContext/
|   |   |-- UserContext.js
|-- hooks/
|   |-- useMediaQuery/
|   |   |-- useMediaQuery.js
|-- features/
|   |-- Home/
|   |   |-- atoms/
|   |   |-- molecules/
|   |   |-- organisms/
|   |   |-- utils/
|   |   |-- services/
|   |   |-- hooks/
|   |   |-- contexts/
|   |   |-- pages/
|   |   |   |-- HomePage.jsx
|   |-- index.js
|-- utils/
|   |-- some-common-util/
|   |   |-- index.js/
|   |   |-- index.test.js
|-- services/
|   |-- some-common-service/
|   |   |-- index.js/
|   |   |-- some-common-service.js/
|   |   |-- index.test.js
|-- App.jsx
|-- index.js

La verdad es que las veces que he utilizado Atomic Design en algún proyecto de React no me ha terminado de convencer. Para mi el inconveniente principal es que tienes que aprender a categorizar cada tipo de elemento y esto está bien si todo el equipo conoce la metodología pero si no puede llegar a crear más problemas de los que soluciona.

Aún así, si tu equipo está acostumbrados a trabajar con esta metodología o buscáis nuevas forma de organizar los proyectos y las ideas descritas por Brad os gustan, es una muy buena forma no solo de estructurar el código en nuestra aplicación, sino incluso de estructurar nuestro sistema de diseño en aplicaciones como Figma.

Estructura basada en la arquitectura hexagonal

Finalmente, me gustaría mencionar la organización en base a la arquitectura hexagonal. Esta es la única que por el momento no he llegado a utilizar pero me parece muy interesante, sobre todo si el equipo es Full-Stack y está acostumbrado a trabajar con esta arquitectura en el backend.

Esta es la organización más compleja de entender de todas las que hemos visto y basa sus ideas en la arquitectura desarrollada por Alistair Cockburn. En este artículo solo vamos a mostrar un ejemplo de cómo sería su aplicación a React, pero si os interesa y queréis empezar a profundizar hay un artículo al respecto en Software Crafters que lo explica muy bien.

src/
|-- domain/
|   |-- models/
|   |   |-- User.js/
|   |-- services/
|   |   |-- User.service.js/
|-- infrastructure/
|		|-- components/
|		|   |-- Avatar/
|		|   |   |-- Avatar.jsx
|		|   |   |-- Avatar.test.js
|		|	  |-- UserProfile/
|		|   |   |-- UserProfile.jsx
|		|   |   |-- UserProfile.test.js
|		|-- http/
|		|   |-- dto/
|		|   |   |-- userDto.js/
|		|   |-- http.js
|		|-- repositories/
|		|   |-- user.repository.js/
|-- App.jsx
|-- index.js

Como vemos a primera vista, si nunca hemos tratado la arquitectura hexagonal puede ser bastante complejo entender dónde está cada parte de nuestro código, esta organización solo la utilizaría en el caso que estemos acostumbrados a trabajar con ella en nuestro backend y queramos mantener la misma arquitectura en el frontend. De no ser así, creo que las que hemos visto en los puntos anteriores son más recomendables para la mayoría de proyectos.

Conclusiones

Como vemos hay muchas formas de organizar nuestro código desde la más simple a las más compleja. Una forma de organización simple no tiene porqué ser peor que una compleja, todo dependerá del tamaño de nuestra base de código y del tamaño del equipo que la gestione.

De hecho, una organización muy compleja en proyectos simples lo único que nos aportará la mayoría de las veces son dolores de cabeza. Aún así es interesante saber qué opciones hay para organizar nuestros proyectos e intentar aplicar la que más nos encaje en cada caso.