Despues de la refactorizacion inicial del MainWindow, surgio otro desafio: la duplicacion de codigo entre las secciones de los dos servidores (inferencia y autocompletado). Este post documenta como se resolvio este problema mediante la extraccion del componente ServerWidget.
El Problema: Duplicacion de UI
Llama CPP Launcher soporta dos servidores simultaneos:
- Servidor de inferencia — Para generacion de texto y conversaciones
- Servidor de autocompletado — Para sugerencias de codigo en tiempo real
Ambos servidores necesitan la misma interfaz de usuario:
- Controles de inicio/parada — Botones para gestionar el proceso
- Selector de modelo — Dropdown para elegir el modelo GGUF
- Parametros configurables — Campos para ajustar la configuracion
- Logs del servidor — Area para mostrar la salida del proceso
- Estado del servidor — Indicador visual del estado actual
Antes de la extraccion, el MainWindow tenia dos copias casi identicas de esta interfaz, una para cada servidor. Esto causaba:
- Duplicacion de codigo — Cualquier cambio debia hacerse en dos lugares
- Inconsistencias — Facil que las copias se desincronizaran
- Mantenimiento dificil — El MainWindow seguia siendo complejo
- Extension limitada — Agregar un tercer servidor requeria copiar mas codigo
La Solucion: ServerWidget
Se decidio extraer la interfaz comun en un componente reutilizable llamado ServerWidget. Este componente encapsula toda la UI y logica necesaria para gestionar un servidor llama.cpp.
Responsabilidades de ServerWidget
- Gestion de interfaz — Todos los controles visuales para un servidor
- Conexion con ServerController — Comunicacion con el gestor de procesos
- Mostrar estado — Actualizar la interfaz segun el estado del servidor
- Gestionar logs — Mostrar y filtrar la salida del servidor
Diseno del Componente
ServerWidget fue disenado como un QWidget puro que recibe un puntero al ServerController correspondiente:
- Constructor — Recibe
ServerController*como dependencia - Signals y slots — Se conecta a las signals del controller para actualizar la UI
- Configuracion — Permite personalizar el titulo y comportamiento
- Estado interno — Gestiona su propio estado de UI (expandido/colapsado, filtros, etc.)
Implementacion
Creacion del Componente
El primer paso fue crear la estructura basica de ServerWidget:
- ServerWidget.hpp — Declaracion de la clase con interfaz publica
- ServerWidget.cpp — Implementacion de la UI y logica
- Integracion en CMake — Agregar al sistema de construccion
Migracion de UI
Se extrajo el codigo de UI relevante de MainWindow a ServerWidget:
- Widgets de control — Botones, dropdowns, campos de texto
- Layouts — Organizacion visual de los controles
- Estilos — QStylesheets para apariencia consistente
- Conexiones — Signals y slots para interactividad
Refactorizacion de MainWindow
El MainWindow se simplifico significativamente:
- Crear dos ServerWidget — Uno para inferencia, otro para autocompletado
- Pasar controllers — Inyectar los ServerController correspondientes
- Eliminar codigo duplicado — Toda la UI especifica de servidor se movio a ServerWidget
- Orquestar — MainWindow solo coordina los componentes
Beneficios de la Extraccion
Eliminacion de Duplicacion
- Un solo componente — ServerWidget se usa dos veces en lugar de tener dos copias
- Cambios centralizados — Modificar la interfaz de servidor se hace en un solo lugar
- Consistencia garantizada — Ambos servidores tienen exactamente la misma interfaz
Mejora en Mantenibilidad
- Responsabilidad clara — ServerWidget solo se preocupa por la UI de un servidor
- Codigo mas pequeno — MainWindow se redujo aun mas en lineas
- Depuracion mas facil — Los problemas de UI de servidor se aislaron al widget
Facilidad de Extension
- Agregar servidores — Crear un tercer servidor es trivial: solo agregar otro ServerWidget
- Personalizacion — Se pueden crear variantes de ServerWidget para diferentes tipos de servidor
- Reutilizacion — El componente podria usarse en otras aplicaciones
Resultados Numericos
Antes de la Extraccion
- MainWindow — ~300 lineas (despues de la refactorizacion inicial)
- Codigo duplicado — ~100 lineas de UI de servidor duplicadas
- Complejidad — MainWindow gestionaba directamente la UI de ambos servidores
Despues de la Extraccion
- MainWindow — ~150 lineas como orquestador puro
- ServerWidget — ~200 lineas encapsulando la UI de servidor
- Codigo duplicado — 0 lineas
- Complejidad — Cada componente tiene una responsabilidad clara
Lecciones Aprendidas
Cuando Extraer Componentes
- Codigo duplicado — Si copias y pegas codigo, es candidato a extraccion
- Patrones repetidos — Si ves la misma estructura en multiples lugares
- Responsabilidades similares — Si diferentes clases hacen cosas parecidas
Como Extraer Componentes
- Identificar la interfaz comun — Que widgets y funcionalidades comparten
- Definir el contrato — Que necesita el componente del exterior
- Crear el componente — Implementar la UI y logica encapsulada
- Migrar gradualmente — Reemplazar una instancia a la vez
- Verificar — Asegurar que la funcionalidad se mantiene
Conclus
La extraccion de ServerWidget demuestra como identificar y eliminar duplicacion de codigo mediante la creacion de componentes reutilizables. El resultado es un codigo mas limpio, consistente y facil de mantener, que ademas facilita la extension futura del proyecto.
Este patron de extraccion de componentes es aplicable en muchos contextos donde se repite la misma estructura de UI o logica, y es una herramienta fundamental en el toolkit de cualquier desarrollador.