Codeando es que se aprende, y esta vez me propuse el reto de combinar los conceptos de arquitectura hexagonal (también conocida como Ports and Adapters) con los principios de Clean Code. Este proyecto no solo es mi portafolio web, sino una oportunidad para aplicar y consolidar buenas prácticas de desarrollo en un entorno real.
Este proyecto surgió como una manera de restructurar mi portafolio web, implementando:
- Principios de Domain Driven Design (DDD).
- Configuración avanzada de ESLint y Prettier, complementada con Husky y lint-staged para mantener un código organizado.
- Arquitectura hexagonal que desacopla responsabilidades y mejora la mantenibilidad del código.
Aunque el proyecto en sí es relativamente sencillo, debo admitir que ha costado algunos conceptos e implementaciones. Sin embargo, como dice el dicho: el que la sigue, la consigue. Este esfuerzo me permitió poner a prueba mis capacidades y dar un gran paso hacia mi meta profesional de convertirme en un arquitecto frontend.
Gracias a las clases compartidas por @AlanBuscaglia y a referencias externas como este repositorio de arquitectura hexagonal que influyó en mi desarrollo.
Este proyecto ha sido diseñado para ofrecer una arquitectura limpia y escalable que sigue los principios de Clean Code y Domain-Driven Design (DDD). Al trabajar con este repositorio, podrás:
- Aprender y aplicar arquitectura hexagonal: Conoce y experimenta con el enfoque de ports and adapters.
- Mejorar tus habilidades en organización de código: Configuraciones como
eslint,prettier,huskyylint-stagedayudan a mantener un código organizado y limpio. - Fomentar buenas prácticas: Refuerza conceptos como separación de capas y manejo de dependencias en proyectos complejos.
- Escalabilidad: La estructura facilita agregar nuevas funcionalidades sin comprometer la integridad del sistema.
- Facilidad de mantenimiento: La arquitectura permite mantener el código limpio y organizado, lo que facilita la actualización y mantenimiento del proyecto.
/root
├── core
│ ├── technicalTests
│ │ ├── __mock__
│ │ ├── domain
│ │ | ├── models
│ │ │ ├── repository
│ │ │ └── ...
│ │ ├── application
│ │ | ├── __test__
│ │ | ├── services
│ │ │ └── ...
│ │ └── infrastructure
│ │ ├── __test__
│ │ ├── data
│ │ │ ├── markdown
│ │ │ ├── constants
│ │ │ └── ...
│ │ ├── utils
│ │ ├── localDataRepository
│ │ ├── LocalMarkdownRepository
│ │ ├── axiosRepository
│ │ └── ...
│ └── ...
├── infrastructure
│ ├── views
│ │ ├── next
│ │ │ └── ...
│ │ ├── astro
│ │ │ └── ...
│ │ └── ...
├── ...settings
└── README.md
- Arquitectura Hexagonal
- Define adaptadores específicos para interactuar con el entorno externo.
- Domain Driven Design (DDD)
- Lógica de negocio y entidades modeladas con claridad.
- Configuración Avanzada
- Integración de ESLint y Prettier.
- Uso de Husky y lint-staged para formateo automático en pre-commits y pre-push.
A continuación, se muestra cómo implementar la funcionalidad para listar las pruebas técnicas (technicalTests) almacenadas en un archivo local.
/root
├── core
│ ├── technicalTests
│ │ ├── __mock__
│ │ ├── domain
│ │ | ├── technicalTest.ts
│ │ │ └── technicalTestRepository.ts
│ │ ├── application
│ │ | ├── __test__
│ │ | └── technicalTestService.ts
│ │ └── infrastructure
│ │ ├── __test__
│ │ ├── data
│ │ │ └── index.ts
│ │ └── localTechnicalTest.repository.ts
| └── ...
└── ...
// technicalTestRepository.ts
import { type Language } from '@core/locale/domain'
import { type Params } from '@core/shared/domain'
import { type TechnicalTest } from './technicalTest'
export type TechnicalTestRepository = {
getAll: (params: Params & { lang: Language }) => Promise<TechnicalTest[]>
}// technicalTestService.ts
import { sortArray } from '@core/shared/utils/sortArray'
import { sortSkills } from '@core/skills/domain/sortSkills'
import { type TechnicalTest } from '../domain/technicalTest'
import { type TechnicalTestRepository } from '../domain/technicalTestRepository'
export const technicalTestService = (repository: TechnicalTestRepository): TechnicalTestRepository => ({
getAll: async (params) => {
const tests = await repository.getAll(params)
const sortedTests = sortArray<TechnicalTest>(tests, 'order', params.order)
const sortedSkills = sortedTests.map((test) => ({ ...test, skills: sortSkills(test.skills) }))
return sortedSkills
},
})// localTechnicalTest.repository.ts
import { DEFAULT_LANG } from '@core/locale/domain'
import { type TechnicalTestRepository } from '../domain/technicalTestRepository'
import { TechnicalTests } from './data'
export const localTechnicalTest = (): TechnicalTestRepository => ({
getAll: async (params) => {
const lang = params?.lang ?? DEFAULT_LANG
return Promise.resolve(TechnicalTests[lang])
},
})import { technicalTestService } from '@core/technicalTests/application/technicalTestService'
import { localTechnicalTest } from '@core/technicalTests/infrastructure/localTechnicalTest.repository'
async function fetchTechnicalTests() {
try {
const technicalTests = await technicalTestService(localTechnicalTest()).getAll({ lang: 'es' })
console.log('Pruebas Técnicas:', technicalTests)
return technicalTests
} catch (error) {
console.error('Error al obtener las pruebas técnicas:', error)
}
}
fetchTechnicalTests()- Node.js >= 18.x
- npm ó yarn ó pnpm (Recomendado)
- Clona el repositorio:
git clone https://github.com/cavargasl/portfolio
cd portfolio- Instala las dependencias en el directorio raíz:
pnpm install- Configura las dependencias del frontend:
cd infrastructure/views/next
'or' cd infrastructure/views/astro
pnpm install cd infrastructure/views/next
'or' cd infrastructure/views/astro
pnpm devLas contribuciones son bienvenidas. Siéntete libre de abrir un issue o enviar un pull request.
Asegúrate de seguir las mejores prácticas de desarrollo y respetar las configuraciones establecidas en el proyecto.
- Fork este repositorio.
- Crea una rama para tu feature o corrección de bug (
git checkout -b feature/nueva-funcionalidad). - Realiza tus cambios y asegura que el código pase las verificaciones automáticas.
- Envía tu pull request para revisión.
¡Gracias por contribuir y ayudar a mejorar este proyecto! 🚀
Este proyecto está bajo la licencia MIT.