Actividad 1 - Componentes, mediación y configuraciones.
El objetivo de esta actividad es profundizar en el concepto de arquitectura de software basada en servicios y componentes, específicamente en el proceso de selección de componentes y mediación a partir de una arquitectura de referencia.
1. Caso de estudio
Section titled “1. Caso de estudio”1.1. Descripción del problema
Section titled “1.1. Descripción del problema”Los sistemas de traducción básicos que traducen palabra por palabra suelen generar textos con errores ortográficos, falta de contexto y una gramática incorrecta. El sistema propuesto procesa el texto de manera integral para ofrecer traducciones precisas y naturales. Para lograrlo, el sistema no solo debe sustituir palabras, sino que también necesita corregir errores previos en el texto original, buscar los términos más adecuados según el contexto y aplicar las reglas sintácticas correctas del idioma de destino, todo ello con soporte dinámico para múltiples idiomas.
1.2. Arquitectura
Section titled “1.2. Arquitectura”El sistema principal, encapsulado bajo el componente compuesto Sistema Avanzado de Traducción, se divide en los siguientes elementos funcionales:
-
Traductor Central (Orquestador): Actúa como el núcleo de control. Expone la interfaz principal Traducción hacia el exterior (por ejemplo, a una API o interfaz de usuario). Su función es coordinar el flujo de datos, delegando las tareas de procesamiento a los componentes especializados y ensamblando el resultado final.
-
Corrector Ortográfico: Provee la interfaz Revisión Ortográfica. Actúa en la fase de preprocesamiento, limpiando y corrigiendo el texto de origen para garantizar que los errores tipográficos no comprometan la calidad de la traducción.
-
Diccionario Léxico: Provee la interfaz Sugerencias. Recibe las palabras o frases limpias y consulta sus equivalencias, devolviendo las opciones más adecuadas según el contexto semántico.
-
Analizador Gramatical: Provee la interfaz Reglas de Sintaxis. Se encarga del postprocesamiento. Toma las sugerencias del diccionario y las ordena conjugando verbos y ajustando concordancias (género, número, estructura) para que la oración resultante suene natural en el idioma de destino.
-
Base de Datos de Idiomas: Constituye la capa de persistencia estática. Expone la interfaz Paquetes de Idioma. A diferencia de los demás, este componente no es consumido por el orquestador, sino que alimenta de datos directamente al Diccionario Léxico (vocabulario) y al Analizador Gramatical (reglas estructurales).
Se ha diseñado el siguiente diagrama de componentes en UML utilizando la herramienta PlantUML, donde se aprecian las interfaces proporcionadas y requeridas que conectan los módulos del traductor.
La arquitectura del Traductor Inteligente se estructura a partir de sus componentes, definiéndolos según las funcionalidades que aportan y las dependencias que necesitan para operar.
, donde:
- : Servicios proporcionados
- : Servicios requeridos
Arquitectura del Sistema ()
| Componente | Servicios Proporcionados () | Servicios Requeridos () |
|---|---|---|
| Traductor Central | , , | |
| Corrector Ortográfico | - | |
| Diccionario Léxico | ||
| Analizador Gramatical | ||
| Base de Datos Idiomas | - |
1.3. Componentes candidatos
Section titled “1.3. Componentes candidatos”Para satisfacer la arquitectura propuesta, se define un conjunto de componentes candidatos que representan el catálogo de software disponible para la composición. Estos candidatos presentan diversas agrupaciones de servicios, algunos cubriendo múltiples necesidades arquitectónicas y otros siendo específicos para una sola tarea. Se incluye una dependencia externa a una API en la nube () para evaluar la detección de dependencias no contempladas.
: Componentes candidatos
2. Desarrollo del programa
Section titled “2. Desarrollo del programa”En esta sección se describe el programa desarrollado para la actividad, con el fin de obtener todas las configuraciones que satisfacen los requisitos planteados.
2.1. Implementación de la API de TraderConfigs
Section titled “2.1. Implementación de la API de TraderConfigs”Se ha implementado una API REST que actúa como interfaz entre el cliente y el binario TraderConfigs.
Esta transforma solicitudes JSON al formato esperado por el ejecutable y devuelve
las configuraciones generadas mediante Python y FastAPI.
Estructura del Proyecto
Section titled “Estructura del Proyecto”Directoryapi/
Directorybin/
- TraderConfigs (binario ejecutable)
- main.py
- requirements.txt
- Dockerfile
- .dockerignore
Código y Explicación
Section titled “Código y Explicación”from collections import defaultdictfrom fastapi import FastAPI, HTTPExceptionfrom fastapi.middleware.cors import CORSMiddlewarefrom pydantic import BaseModelfrom typing import List, Dictimport subprocess, tempfile, os
app = FastAPI(title="TraderConfigs API")app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])
class ComponentInput(BaseModel): index: int offered: List[str] required: List[str] = []
class ConfigRequest(BaseModel): components: List[ComponentInput] architecture: List[str]
class ConfigResponse(BaseModel): single_configurations: List[Dict[str, List[str]]] long_configurations: List[Dict[str, List[str]]]
def to_text(components: List[ComponentInput], architecture: List[str]) -> tuple[str, str]: comps = "\n".join(f"O: {' '.join(c.offered)}{' I: ' + ' '.join(c.required) if c.required else ''}" for c in components) arch = f"O: {' '.join(architecture)}" return comps, arch
def from_text(lines: List[str]) -> List[Dict[str, List[str]]]: result = [] for line in lines: config = defaultdict(list) for part in line.split(): if '.' in part: comp, svc = part.split('.', 1) config[comp].append(svc) result.append(dict(config)) return result
@app.get("/")def root(): return {"message": "TraderConfigs API"}
@app.post("/generate-configurations", response_model=ConfigResponse)def generate_configurations(request: ConfigRequest): comps_text, arch_text = to_text(request.components, request.architecture)
with tempfile.TemporaryDirectory() as tmpdir: for name, content in [("components.txt", comps_text), ("architecture.txt", arch_text)]: with open(os.path.join(tmpdir, name), "w") as f: f.write(content)
result = subprocess.run( [os.path.join(os.path.dirname(__file__), "bin", "TraderConfigs"), os.path.join(tmpdir, "components.txt"), os.path.join(tmpdir, "architecture.txt")], cwd=tmpdir, capture_output=True, text=True ) if result.returncode != 0: raise HTTPException(500, result.stderr)
single = from_text(open(os.path.join(tmpdir, "single_configurations.out")).readlines()) if os.path.exists(os.path.join(tmpdir, "single_configurations.out")) else [] long = from_text(open(os.path.join(tmpdir, "long_configurations.out")).readlines()) if os.path.exists(os.path.join(tmpdir, "long_configurations.out")) else []
return ConfigResponse(single_configurations=single, long_configurations=long)El programa define una API REST con dos endpoints: uno de verificación de estado (GET /) y otro principal (POST /generate-configurations).
Utiliza modelos Pydantic para validar la estructura de los datos de entrada y salida.
Las funciones auxiliares to_text y from_text transforman los datos entre JSON y
el formato de texto plano que el binario TraderConfigs puede procesar. El flujo de ejecución
crea archivos temporales, ejecuta el binario y, posteriormente, procesa los resultados obtenidos.
Entradas
Section titled “Entradas”| Campo | Tipo | Descripción |
|---|---|---|
components | Array | Lista de componentes del sistema |
architecture | Array | Servicios disponibles |
Cada componente:
| Campo | Tipo | Descripción |
|---|---|---|
index | Integer | Identificador único |
offered | Array | Servicios que ofrece |
required | Array | Servicios que requiere |
Salidas
Section titled “Salidas”| Campo | Tipo | Descripción |
|---|---|---|
single_configurations | Array | Configuraciones válidas |
long_configurations | Array | Todas las combinaciones |
Ejemplo
Section titled “Ejemplo”En el siguiente ejemplo se utilizan identificadores simplificados de servicios con fines ilustrativos.
Request:
{ "components": [ {"index": 1, "offered": ["CIO"], "required": []}, {"index": 2, "offered": ["CAL"], "required": []} ], "architecture": ["CAL", "CIO"]}Response:
{ "single_configurations": [{"C1": ["CIO"], "C2": ["CAL"]}], "long_configurations": [{"C1": ["CIO"]}, {"C1": ["CIO"], "C2": ["CAL"]}]}2.2. Vista web y ejemplo de uso
Section titled “2.2. Vista web y ejemplo de uso”Para la interfaz web se han desarrollado cuatro vistas, de las cuales dos corresponden a formularios.
Formulario de entrada de datos, en el que se introduce la arquitectura:
Otro formulario de datos, en el que se introducen los componentes con sus servicios ofrecidos y requeridos:
Después, se presenta un resumen de la arquitectura y de los componentes introducidos:
Finalmente, se muestra una vista con los resultados obtenidos, en la que se presentan las configuraciones válidas y todas las combinaciones posibles:
3. Configuración y resultados
Section titled “3. Configuración y resultados”Tras la ejecución de la aplicación con el algoritmo de TraderConfigs,
se obtienen las siguientes configuraciones válidas:
| # | C1 | C2 | C3 | C4 | C5 | C6 | C7 | R | C |
|---|---|---|---|---|---|---|---|---|---|
| 1 | Traductor_Central | Corrector_Ortografico | BBDD_Idiomas | Analizador_Gramatical | Diccionario_Lexico | - | - | Sí | No |
| 2 | Traductor_Central | Corrector_Ortografico | BBDD_Idiomas | - | Diccionario_Lexico | Analizador_Gramatical | - | Sí | Sí |
| 3 | Traductor_Central | - | BBDD_Idiomas | Analizador_Gramatical | Diccionario_Lexico | - | Corrector_Ortografico | Sí | No |
| 4 | Traductor_Central | - | BBDD_Idiomas | - | Diccionario_Lexico | Analizador_Gramatical | Corrector_Ortografico | Sí | Sí |
Para evaluar qué configuraciones son válidas, se revisan dos criterios clave:
-
Configuraciones cerradas (columna C): Una configuración es cerrada cuando ninguno de sus componentes depende de servicios externos a la arquitectura definida. En este caso, las configuraciones que incluyen
C4no son cerradas, porque ese candidato necesita un servicio externo (API) que no forma parte de la arquitectura del sistema de traducción. Por eso, en la tabla aparecen como cerradas las configuraciones #2 y #4, mientras que #1 y #3 no lo son. -
Respeto de la arquitectura (columna R): Una configuración respeta la arquitectura si los servicios proporcionados por los candidatos pueden asignarse a los servicios exigidos por el diseño original (
Traductor_Central,Analizador_Gramatical,Corrector_Ortografico,Diccionario_LexicoyBBDD_Idiomas). En las cuatro configuraciones obtenidas se cumple esta condición, por lo que todas presentanR = Sí.
Atendiendo a estos dos criterios, las configuraciones más adecuadas son #2 y #4, ya que son las únicas que cumplen simultáneamente que respetan la arquitectura y, además, son cerradas.
La actividad se ha desarrollado en el siguiente repositorio de GitHub, donde puede encontrarse el código completo junto con instrucciones adicionales de ejecución: