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.