gradient

Estrategias para organizar el código en proyectos con Elixir

Romikya Labs

La organización del código desempeña un papel crucial en el éxito y la longevidad de un proyecto.

Diversas mentes brillantes en la comunidad han propuesto estrategias sofisticadas que no solo mejoran la legibilidad del código, sino que también facilitan el mantenimiento y la evolución continua. En este artículo, exploramos algunos enfoques.

Capas según Bruce Tate y James Gray

Bruce Tate y James Gray, proponen una organización en capas que aborda diversos aspectos del desarrollo. La estrategia abarca desde la manipulación de datos hasta la gestión y la supervisión de procesos. Con capas claramente definidas, como estructuras de datos (data), un núcleo funcional (functional core), pruebas (test), límites o secciones (boundaries), ciclos de vida (lifecycle) y trabajadores (workers), el código adquiere una estructura profunda que simplifica la comprensión y el mantenimiento. No todos los proyectos tendrán todas las capas mencionadas, pero algunas si.

Este enfoque, respaldado por años de experiencia y estudio, encuentra su mejor aplicación en proyectos ambiciosos. Al separar las responsabilidades en capas, los desarrolladores pueden enfocarse en áreas específicas sin perder de vista la imagen general del sistema.

Tal como lo mencionan en el libro "Designing Elixir Systems with Otp", el diseño y capas presentadas no están escritos en piedra. Son un andamiaje, un marco para pensar en soluciones a problemas de diseño comunes.

Es responsabilidad del autor del código base decidir cuales serán las capas que valen la pena mantener y cuales eliminar.

Organización de un sistema en Elixir con OTP

Cómo siempre, es recomendable leer el libro para facilitar la adopción de este diseño. Se puede apreciar en la imagen que el diseño es más conceptual que físico y gracias a la flexibilidad de Elixir, no es necesario crear los directorios y archivos en un orden o jerarquía en particular, aún así, hay que tener presente que cada equipo de desarrollo deberá definir la estructura de los archivos para que tenga mayor sentido la organización del código.

Phoenix Framework

En Phoenix es posible entender mejor como se organiza el código porque tenemos ejemplos claros de manera inicial. Siguiendo la línea de los generadores de código de Phoenix se puede ver una estructura de archivos como la siguiente:

├── assets/ ├── config/ ├── deps/ ├── lib/ │   ├── hello/ │   ├── hello.ex │   ├── hello_web/ │   └── hello_web.ex ├── priv/ └── test/

Esta organización es más genérico y sencilla, la estructura es fácil de entender, el enfoque está orientado a crear una estructura de archivos más flexible y a su vez proveer un código ordenado sin afectar o influir en la lógica de negocio de cada proyecto.

El código se localiza principalmente en /lib, /lib/hello y /lib/hello_web:

lib/ ├── hello │   ├── application.ex │   ├── mailer.ex │   └── repo.ex ├── hello.ex ├── hello_web │   ├── components │   │   ├── core_components.ex │   │   ├── layouts │   │   │   ├── app.html.heex │   │   │   └── root.html.heex │   │   └── layouts.ex │   ├── controllers │   │   ├── error_html.ex │   │   ├── error_json.ex │   │   ├── page_controller.ex │   │   ├── page_html │   │   │   └── home.html.heex │   │   └── page_html.ex │   ├── endpoint.ex │   ├── gettext.ex │   ├── router.ex │   └── telemetry.ex └── hello_web.ex

Mantener la organización del código como se define con Phoenix es útil y facilita el desarrollo inicial, aún así, se debe re-organizar constantemente porque es muy probable que con el paso del tiempo se vuelva algo complicado de mantener en proyectos grandes. Hay que recordar que organizar el código de forma que sea más productivo y fácil de entender para el equipo de desarrollo es prioritario y alguien debe hacerse caso de esto.

Un ejemplo de una estructura re-organizada usando Phoenix pero pensando en la necesidad del proyecto puede ser:

├── assets/ │   ├── css/ │   │   ├── app.css │   │   └── components.css │   ├── js/ │   │   └── app.js │   ├── vendor/ │   │   └── topbar.js ├── config/ │   ├── config.exs │   ├── dev.exs │   ├── prod.exs │   ├── qa.exs │   ├── runtime.exs │   └── test.exs ├── deps/ ├── lib/ │   ├── app/ │   │   ├── accounts/ │   │   │   ├── accounts.ex │   │   │   └── user.ex │   │   ├── analysis/ │   │   │   ├── analysis.ex │   │   │   └── export.ex │   │   ├── analytics/ │   │   │   ├── analytics.ex │   │   │   ├── event.ex │   │   │   └── reports.ex │   │   ├── email/ │   │   │   ├── email.ex │   │   │   ├── job_failed.html.eex │   │   │   ├── process_ready.html.eex │   │   │   └── report_ready.html.eex │   │   ├── mailer.ex │   │   ├── release.ex │   │   ├── repo.ex │   │   ├── s3.ex .. ... │   ├── app.ex │   ├── app_web/ │   │   ├── auth.ex │   │   ├── controllers │   │   │   ├── auth/ │   │   │   │   ├── fallback_controller.ex │   │   │   │   ├── session_controller.ex │   │   │   │   ├── user_controller.ex │   │   │   ├── error_html/ │   │   │   │   ├── 403.html.heex │   │   │   │   ├── 404.html.heex │   │   │   │   └── 500.html.heex │   │   │   │   └── error_html.ex .. ... │   │   │   └── plugs │   │   │      └── authorize_roles.ex │   │   ├── endpoint.ex │   │   ├── gettext.ex │   │   ├── health_check.ex │   │   ├── live/ │   │   | ├── admin.ex │   │   | ├── analytics_live/ │   │   | │   ├── index.ex │   │   | │   └── index.html.heex │   │   | ├── components/ │   │   | │   ├── charts.ex │   │   | │   ├── modal_component.ex │   │   | |   └── modal_component.html.heex │   │   | ├── core_components.ex │   │   | └── live_helpers.ex │   │   ├── router.ex │   │   ├── telemetry.ex │   │   ├── templates/ │   │   | ├── auth │   │   | │   ├── session │   │   | │   │   └── error.html.eex │   │   | │   └── user │   │   | │   ├── form.html.eex │   │   | │   ├── new.html.eex │   │   | │   └── show.html.eex │   │   | └── layout │   │   |    ├── app.html.eex │   │   |    ├── live.html.heex │   │   |    └── root.html.heex │   │   ├── views/ │   │   | ├── auth │   │   | │   ├── session_view.ex │   │   | │   └── user_view.ex │   │   | ├── error_helpers.ex │   │   | ├── error_view.ex │   │   | └── layout_view.ex ... │   │   │ │   │   └── app_web.ex ├── priv/ └── test/

Algunos puntos relevantes a destacar en esta organización de archivos es la separación de lógica de negocio (lib/app) de la funcionalidad web (lib/app_web), por otra parte, algunos proyectos podrían organizar el código en esquemas (schemas) o contextos (context) y clasificar los módulos de acuerdo a su funcionalidad (behaviors/,jobs/, etc). En la organización de ejemplo que se presenta, el objetivo es dejar los archivos lo más simple posible para su localización y fácil entendimiento sin perder de vista en que parte del proyecto tiene sentido ubicar cada archivo.

Para conocer más sobre la organización de archivos en Phoenix, se puede consultar la documentación en línea.

Handlers, services, finders and values

Marcelo Lebre, presidente y co-fundador de Remote, propone una estrategia basada en cuatro patrones clave: manejadores (handlers), servicios (services), buscadores (finders) y valores (values). Este enfoque se diferencia al fragmentar principalmente la lógica de negocio, proporcionando una estructura pensada en la escalabilidad (o extensibility en Inglés) y mantenimiento a largo plazo.

Esquema sugerido por Marcelo Lebre

Al organizar el código en estas categorías, se logra una separación de responsabilidades, Marcelo Lebre menciona en su ponencia que su propuesta la basa en su experiencia y siguiendo los principios SOLID.

Principios SOLID

Aunque no presenta un proyecto de ejemplo o bien no hay un ejemplo publico disponible referenciado por él o la comunidad, explica que el patrón lo ha aplicado en otras tecnologías y que ha ayudado de acuerdo a su experiencia en la productividad del equipo.

Importancia del desacoplamiento

Independientemente del enfoque elegido, todos los expertos enfatizan la importancia del desacoplamiento. La capacidad de realizar cambios, refactorizaciones o actualizaciones sin complejidad no prevista depende en gran medida de cómo esté estructurado el código. En el dinámico entorno de desarrollo, una estructura desacoplada es la clave para afrontar los desafíos con agilidad y confianza.

Conclusión

Cuando se exploran las estrategias la organización del código, queda claro que la comunidad está comprometida en mejorar constantemente sin importar la tecnología empleada. Cada estrategia aborda desafíos específicos, pero comparten un objetivo común: construir sistemas que sean comprensibles, que faciliten el mantenimiento y adaptables a medida que evolucionan.

Estos enfoques no son dogmas, sino guías valiosas que pueden ajustarse según las necesidades específicas de cada proyecto. A medida que se avanza en el desarrollo de software, la organización del código continuará siendo un área de innovación y experimentación, donde cada nueva idea contribuirá al crecimiento y la excelencia de nuestros proyectos.

Referencias

  1. Thomas, D.. (2018) Programming Elixir. Pragmatic Bookshelf.
  2. Martin, R. C.. (2008) Clean Code: A Handbook of Agile Software Craftsmanship.
  3. McCord, C., Tate, B., & Valim, J. (2019). Programming Phoenix.
  4. Marcelo Lebre - President and co-founder at Remote at Remote
  5. Evans, E. (2003). Domain-Driven Design: Tackling Complexity in the Heart of Software.
Compartir:
gradient

Contáctanos

Nos interesa escucharte

Información

No dudes en escribirnos si tienes alguna pregunta adicional o si necesitas más información. Nuestro equipo estará encantado de ayudarte en todo lo que necesites.