Skip to content

Resumen del Proyecto

Vanskarner edited this page Nov 2, 2023 · 22 revisions

Aclaración: La relevancia de esta wiki y del proyecto no trata de lo que hace este sistema, sino que su creación tiene como objetivo principal demostrar y conectar los conceptos clave de la arquitectura limpia en un sistema funcional.

Información Básica

  • IDE: Android Studio Giraffe | 2022.3.1
  • Lenguaje: Java
  • Compatibilidad: API 21 (5.0) - API 31 (13.0)
  • Descripción: Este proyecto tiene como objetivo demostrar las diferentes formas de implementar la arquitectura limpia en un sistema funcional. Estas implementaciones están diseñadas para asegurar que las soluciones o características propuestas sean compatibles desde la mínima versión hasta la última versión, manteniendo un enfoque general en su aplicabilidad.

Ramas

Este proyecto tiene 4 ramas y representa la forma en la se ha desacoplado el código, pero todos las ramas hacen lo mismo solo que con algunas pequeñas diferencias:

Paquete por Componente - Principal

Puedes ver los diagramas, pruebas y métricas de esta rama aquí.

Package By Component - Main

Esta rama sigue el enfoque arquitectónico: "Paquete por Componente”, y se distingue de las demás ramas en el sentido de que el repositorio pasa de ser una colección de objetos de negocio a ser una colección de datos críticos del negocio, donde ya no tiene dependencias hacia los objetos de negocio, sino en cambio, hacia simples estructuras de datos. Esta particularidad elimina la necesidad de efectuar mapeos en el componente Movie.

Considero que esta rama sobresale ante el resto de las otras y se adapta mejor al concepto de las reglas de negocio de la empresa como un conjunto pequeño encapsulado de reglas comerciales.

Paquete por Componente - Secundario

Puedes ver los diagramas, pruebas y métricas de esta rama aquí.

Package By Component - Secondary

Esta rama sigue el enfoque arquitectónico: "Paquete por Componente”. Aquí los repositorios tienen dependencias con los objetos o entidades de negocio siendo necesario un mapeador entre los objetos de negocio y las estructuras de datos. La intención de este enfoque es exponer los servicios de las reglas de negocio.

Paquete por Característica

Puedes ver los diagramas, pruebas y métricas de esta rama aquí.

Package By Feature

Esta rama sigue el enfoque arquitectónico: "Paquete por Característica”. Aquí los repositorios tienen dependencias con los objetos o entidades de negocio siendo necesario un mapeador entre los objetos de negocio y las estructuras de datos. La intención de este enfoque no es exponer los servicios como lo hace paquete por componente sino es exponer los servicios de presentación.

El componente AndroidView es un componente concreto que consume los servicios del componente Movie y no condiciona a la arquitectura ya que esta es independiente al detalle.

Paquete por Capa

Puedes ver los diagramas, pruebas y métricas de esta rama aquí.

Package By Layer

Esta rama sigue el enfoque arquitectónico: "Paquete por Capa”. Aquí los repositorios tienen dependencias con los objetos o entidades de negocio siendo necesario un mapeador entre los objetos de negocio y las estructuras de datos. La intención de este enfoque es la separación desde una perspectiva técnica de los componentes.

Componentes Comunes en Cualquier Proyecto

Componente Core

Es común encontrar un componente denominado "core" en cualquier proyecto, aunque también puede recibir otros nombres como "common" o "base". Su propósito principal es alojar artefactos de software compartidos que son utilizados por varios componentes en el sistema.

En este proyecto, el componente core es el mismo para todas las ramas:

Core Component

En relación a la función que este componente aborda en el proyecto, es importante destacar lo siguiente:

  • Emplea programación funcional tanto para las operaciones síncronas (Result) como para las operaciones asíncronas (FutureResult y FutureSimpleResult). Estos mecanismos reciben el nombre Monad y encapsulan un valor o una función en un contexto, proporcionando operaciones para trabajar con él de manera modular y funcional, permiten manejar efectos secundarios, representar computaciones con estado o errores, y componer operaciones de manera elegante y segura.

  • Utiliza abstracciones como FutureResult y FutureSimpleResult para las operaciones asíncronas, esto permite tener la flexibilidad de cambiar el framework según sea necesario. En este caso, estamos usando RxJava del lado del detalle.

  • Aunque la interfaz RxFutureFactory es una abstracción, está relacionada con el detalle, ya que tiene dependencias hacia RxJava y justamente será utilizada solo por el detalle, en concreto por las implementaciones MovieRemoteRxRepository y MovieLocalRxRepository de cada rama.

Pruebas

Estas son las pruebas del componente core y son las mismas en todas las ramas:

Tests in com.vanskarner.core

Componente Main

Cualquier proyecto dispone de un componente Main, que es el encargado de establecer las condiciones y configuraciones del proyecto.

En este proyecto, el componente Main en todas las ramas es representado por el paquete main que se encuentra dentro del módulo gradle "app" y las relaciones de dependencia están representados por la dependencia que tiene este paquete con los otros paquetes main y módulos dagger ubicados en los demás componentes. Mientras que la diferencia del componente en las diferentes ramas radica en cómo se ha dispuesto esta configuración.

Este componente también está compuesto por todas las fábricas, estrategias, instalaciones globales y marcos de inyección de dependencia. Revise la sección Componente Main.

Análisis

Se ha utilizado la herramienta de análisis estático para código Java llamado JArchitect en su versión 2023.1.0. Esta herramienta ofrece un conjunto de reglas predefinidas, métricas y gráficos útiles para el análisis, proporcionando una visión integral del estado de un proyecto.

Cada rama tiene los resultados de su propio análisis ubicados en la raíz del proyecto, dentro de la carpeta architecture_resources en la cual hay un archivo comprimido con un nombre similar a: MetricsBy....rar. Este archivo comprimido contiene:

  • MetricsBy....jdproj: Este es el archivo que proporciona JArchitect al guardar el análisis de un proyecto. Use la herramienta JArchitect en su computadora para abrir este tipo de archivo.

  • QueryResultBy....htm: Este archivo contiene las reglas en sintaxis CQLinq usadas en el análisis del proyecto. Las reglas de este archivo no se verifican aquí, sino en el reporte HTML generado al analizar el proyecto,ya que este archivo solo contiene el conjunto de reglas utilizadas.

  • JArchitectOutBy...: Esta carpeta contiene el resultado del análisis que hace la herramienta JArchitect, aquí también se encuentra el reporte en html llamado: JArchitectReport.html, que contiene todas las métricas, cuadros y gráficos sobre el proyecto.

Otros Conceptos

Me ha parecido útil incluir información sobre estos conceptos adicionales, los cuales encontrarán al ver el reporte o al usar JArchitect y que no se encuentran en el libro Clean Architecture: A Craftsman’s Guide to Software Structure and Design.

Cohesión Relacional

Uno de los primeros libros en donde se aborda la cohesión en el campo de ingeniería de software es Structured Design: Fundamentals of a Discipline of Computer Program and Systems Design (1979) de Edward Yourdon y Larry L. Constantine.

Esta cohesión se refiere al grado en que todos los elementos de un componente están relacionados entre sí. En otras palabras, un componente tiene una alta cohesión relacional si todos sus elementos que lo componen están fuertemente relacionados.

La siguiente fórmula ha sido extraída de la Definición de Métricas de Jarchitect

Fórmula Descripción
$H=\displaystyle\frac{(R+1)}{N}$ H: Cohesión Relacional
R: Número de relaciones de tipo que son internas al componente
N: Número de tipos del componente.

La sugerencia del rango ideal para esta métrica es: 1.5 < H < 4.0

Bajo mi perspectiva esta métrica puede ayudar a entender si los artefactos contenidos en un componente comparten una razón significativa para estar juntos. Sin embargo, hay que tener en cuenta que una métrica es solo una referencia, y en algunos casos, puede ser necesario ajustar la escala o fórmula según las necesidades específicas del proyecto.

Deuda Técnica

Para obtener un mayor entendimiento sobre este concepto, se recomienda la lectura del artículo de Martin Fowler disponible en: TechnicalDebt.

De forma simplificada la deuda técnica representa el costo futuro asociado con la elección de soluciones rápidas o atajos en el desarrollo de software en lugar de seguir buenas prácticas de desarrollo que requerirían más tiempo o recursos en el corto plazo. Esta deuda técnica puede acumularse a medida que los desarrolladores toman decisiones que, por ejemplo, pueden implicar código mal estructurado, falta de documentación, omisión de pruebas de calidad, entre otros. Con el tiempo, esta deuda puede hacer que el código sea más difícil de mantener y extender, lo que resulta en un aumento de los costos a largo plazo.

JArchitect mide esta deuda especificando lo siguiente:

Tanto la deuda técnica como el interés anual de una emisión se miden en tiempo-hombre.

  • La deuda técnica es el tiempo humano estimado que se necesitaría para solucionar el problema.
  • El interés anual es el tiempo humano estimado consumido por año si el problema no se soluciona. Esto proporciona una estimación del impacto empresarial del problema.
- JArchitect, Compute and Manage the Technical Debt with JArchitect

La fórmula a cargo de la deuda técnica es propia de la herramienta, esta herramienta clasifica qué tipos de fallas se consideran como Deuda Técnica a partir de sus reglas para calcular su estimación. Adicionalmente se puede ajustar la configuración de esta deuda desde JArchitect > Project Properties > Issues and Debt.

Variaciones

No están limitados a seguir las soluciones propuestas en todas las ramas disponibles en el proyecto, ya que existen múltiples formas válidas para la implementación del código. Por ejemplo, tienen la libertad de cambiar el manejo o propagación de errores, el uso del patrón Value Objects, la utilización de un único repositorio (cuya implementación use las ya existentes) o incluso variar la disposición de los elementos de configuración del componente Main. Lo esencial es que cualquier modificación o variación que realicen debe mantenerse alineada con los conceptos principales de la arquitectura limpia.

Clone this wiki locally