Skip to content

Limpieza: código muerto, violaciones SOLID y duplicación #31

Description

@Isma-L154

El proyecto funciona y tiene 279 tests en verde, pero acumuló restos de
refactors anteriores: código de un proveedor que ya no existe, constantes que
nadie lee, y varias piezas donde una clase hace tres trabajos a la vez. Nada de
esto rompe nada hoy; todo encarece cada cambio futuro.

Auditoría completa de los 9 módulos de producción (~1.100 líneas). Cada punto
verificado con grep sobre el árbol, no supuesto.

1. Código muerto

  • utils/checks.py → bot_in_voice() — Ningún cog lo usa. Sus únicas
    referencias son los dos tests que lo prueban, así que el suite cubre una
    función que nadie llama.
  • track["spotify_url"] — El soporte de Spotify se eliminó y _build_track
    nunca escribe esa clave, pero quedan dos lecturas vivas
    (utils/embeds.py:12, cogs/music.py:116) con un or que siempre es falso.
  • cogs/lyrics.py:38 — title.split(" — ")[0] existe porque los títulos de
    Spotify venían como "Canción — Artista". Sin Spotify, ese split ahora
    corta títulos legítimos de YouTube que contengan un guion largo.
  • track["stream"] — _build_track la fija a None en cada track y ningún
    módulo la lee jamás. El streaming real pasa por AudioStream.
  • config.COOKIES_PATH — Se define pero nadie la importa: services/media.py
    lee os.getenv("COOKIES_PATH") por su cuenta. Dos dueños para un mismo ajuste,
    y el módulo de configuración deja de ser la fuente de verdad.

2. Violaciones SOLID

  • SRP — MusicPlayer hace tres trabajos. Es el motor de reproducción, pero
    además construye embeds de Discord (_load_error_embed) y publica mensajes en
    el canal (_safe_send, _idle_disconnect). Un cambio de redacción obliga a
    tocar el núcleo de audio.
  • DIP — dependencia circular MusicPlayer ↔ players. destroy() llama al
    singleton global players.discard(...), de modo que la clase depende del
    registro que la contiene. Instanciar un player en un test arrastra el estado
    global del proceso.
  • Encapsulación rota. PlayerManager.get_or_create lee player._destroyed,
    un atributo privado de otra clase.
  • Abstracción con fugas. get_or_create(bot, ctx) recibe un Context de
    discord.py entero solo para sacar ctx.guild.id y ctx.channel. El gestor de
    players queda atado al framework de comandos sin necesitarlo.
  • OCP — añadir un efecto obliga a editar tres sitios. El filtro va en
    EFFECTS, el texto en _LABELS y además hay que escribir un método de comando
    casi idéntico a los otros ocho. Dos diccionarios con las mismas claves que
    pueden desincronizarse en silencio, y 60 líneas que solo cambian en el nombre.
  • !help duplica el registro de comandos. main.py lista los comandos a
    mano; los cogs son los que realmente los definen. Ya hay deriva: !effect
    existe y no aparece en la ayuda
    .

3. Complejidad y duplicación

  • utils/checks.py:_error es idéntica a utils.embeds.error_embed. Misma
    función, dos implementaciones, dos sitios que cambiar si cambia el color.
  • cogs/lyrics.py:52 define un @lyrics.error que responde
    ctx.send(str(error)). Tiene dos efectos malos: expone texto crudo de
    excepción al usuario, y como utils/errors.handle se rinde cuando ve
    has_error_handler(), desactiva el manejo central de errores para todo el
    cog de letras
    — justo lo que el PR Answer every wrong command invocation #16 construyó.
  • services/lyrics_api.py:47 usa print() en vez de logging. Esquiva la
    configuración de logs y no llega a journalctl con nivel ni timestamp, contra
    la regla de logging del CLAUDE.md.
  • services/lyrics_api.py construye un cliente de Genius nuevo en cada
    consulta.
  • Comentarios redundantes que repiten lo que la línea ya dice
    (source.cleanup() # stop FFmpeg) y banners decorativos.

Fuera de alcance (deliberado)

Criterio de aceptación

  • Los 279 tests siguen en verde, sin relajar ninguna aserción.
  • Ningún cambio de comportamiento observable para el usuario, salvo dos
    correcciones deliberadas: !help pasa a incluir !effect, y los errores de
    !lyrics dejan de mostrar texto crudo de excepción.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions