En ingeniería de software, imperativa y declarativa no son “estilos” superficiales: son familias de paradigmas con diferencias profundas en cómo describen el cómputo, cómo razonas sobre el programa, cómo se optimiza y cómo se controlan los efectos.
1) Definiciones formales (modelo mental)
Programación imperativa
Describe cómo se realiza una tarea mediante una secuencia de instrucciones que modifican el estado del programa.
- Unidad conceptual: instrucción (statement)
- Abstracción central: estado (memoria) + control de flujo
- Semántica típica: “ejecuta esto, luego esto, actualiza estas variables”
Ejemplos de sub-paradigmas dentro de imperativa:
- Procedimental/estructurada (C, Pascal, PHP procedural)
- Orientada a objetos (Java, C#, PHP OOP)
- Orientada a eventos (JavaScript en UI, sistemas reactivos clásicos; suele ser imperativa aunque no siempre)
Programación declarativa
Describe qué propiedad o resultado se desea, y delega el “cómo” a un motor de evaluación (runtime, compilador, optimizador, solver).
- Unidad conceptual: expresión, regla, consulta, relación
- Abstracción central: transformación o restricción (no pasos)
- Semántica típica: “esto debe cumplirse” / “quiero este conjunto de resultados”
Ejemplos de sub-paradigmas declarativos:
- Funcional (Haskell, Elm; también en JS/Python/PHP como estilo)
- Lógico (Prolog)
- Consultas (SQL, LINQ en su forma declarativa)
- Configuración/infra (Terraform, Kubernetes YAML) es declarativo en intención, aunque su motor interno es complejo
2) Diferencia clave: estado y control de flujo
Imperativa: estado mutable + control explícito
- Variables mutan:
x = x + 1 - Control:
if/for/while, early returns, breaks, etc. - El orden de ejecución es parte del significado del programa.
Declarativa: orden implícito + minimización de mutación
- Tiende a favorecer:
- expresiones en vez de statements
- inmutabilidad (o mutación encapsulada)
- composición (funciones/pipelines)
- El “plan” de ejecución puede ser derivado por el motor.
3) Semántica: cómo se “define” el significado de un programa
Imperativa: semántica operacional (operational semantics)
El significado se entiende como:
- “qué pasos ejecuta la máquina abstracta”
- “cómo cambia el estado tras cada instrucción”
Esto hace natural razonar sobre:
- costos temporales por paso
- manipulación de memoria
- algoritmos clásicos con bucles
Declarativa: semántica denotacional / relacional
El significado se entiende como:
- “qué valor denota esta expresión”
- “qué conjunto de soluciones satisface estas reglas”
Esto habilita:
- optimización más agresiva (reordenamiento, fusionado, paralelización)
- razonamiento ecuacional (en funcional puro)
- ejecución por “planes” (query planners en SQL)
4) Ejemplos equivalentes (mismo problema, dos familias)
Problema: sumar montos “expense” de una lista
Imperativo (procedural)
$total = 0.0;
foreach ($txs as $tx) {
if ($tx['type'] === 'expense') {
$total += (float) $tx['amount'];
}
}
return $total;
Características:
- estado mutable (
$total) - control explícito (
foreach,if) - fácil de depurar paso a paso
Declarativo (estilo funcional)
$total = array_sum(
array_map(
fn($tx) => (float) $tx['amount'],
array_filter($txs, fn($tx) => $tx['type'] === 'expense')
)
);
return $total;
Características:
- describes transformaciones: filtrar → mapear → sumar
- menos estado explícito
- puede ser más fácil de componer y testear como pipeline
Problema: obtener en SQL el total de gastos por cuenta (declarativo por naturaleza)
SELECT account_id, SUM(amount) AS total_expense
FROM transaction_debit_cards
WHERE transaction_type = 'expense' AND deleted_at IS NULL
GROUP BY account_id;
Tú declaras qué datos quieres. El motor decide:
- qué índice usar
- en qué orden leer/filtrar/agrupar
- si hace hash aggregate o sort aggregate, etc.
5) Optimización: quién “controla” el plan de ejecución
Imperativa: el programador fija el plan
Si escribes un doble bucle, el runtime lo ejecuta como tal.
Optimización típica:
- compilador (si aplica)
- micro-optimizaciones del runtime
- pero el macro plan lo decidiste tú
Resultado: gran control, pero más responsabilidad.
Declarativa: el motor reescribe / planifica
Casos típicos:
- SQL: query optimizer construye un plan físico
- Funcional: fusion, deforestación, evaluación perezosa (según lenguaje)
- Reglas lógicas: búsqueda/backtracking/heurísticas
Resultado: más libertad para optimizar… y a veces sorpresas si no entiendes el plan.
6) Concurrencia y paralelismo
Imperativa: más fricción con estado compartido
- Hilos + estado mutable ⇒ race conditions, locks, deadlocks
- Tienes que diseñar:
- exclusión mutua
- secciones críticas
- invariantes
Declarativa (especialmente funcional puro): más facilidad
- Menos mutación compartida ⇒ más fácil paralelizar transformaciones
- Pipelines tipo map/reduce se prestan bien
Ojo: declarativo no significa “automáticamente concurrente”. Significa “más apto” para que el motor o el diseño lo habilite.
7) Testeo, mantenibilidad y refactor
Imperativa
Pros:
- directa para algoritmos de bajo nivel
- depuración paso a paso muy natural
Contras: - si hay muchos efectos, el comportamiento puede depender del orden
- riesgo de “spaghetti flow” si hay returns/breaks/continues por todas partes
Declarativa
Pros:
- piezas más pequeñas y composables
- tiende a favorecer funciones puras → tests simples (input → output)
Contras: - puede ser menos intuitiva al inicio
- si el motor optimiza, debes aprender a inspeccionar el plan (SQL
EXPLAIN, por ejemplo)
8) Rendimiento: mitos comunes
- “Declarativo siempre es más lento”: falso. SQL bien indexado puede superar a loops en app por órdenes de magnitud porque reduce I/O y aprovecha el motor.
- “Imperativo siempre es más rápido”: tampoco. Depende de si estás evitando overhead, de si estás moviendo datos innecesariamente, y de si el motor declarativo puede optimizar mejor.
Regla práctica:
- Lo declarativo suele ganar cuando el motor tiene contexto suficiente para optimizar (BD, compilers, runtimes).
- Lo imperativo gana cuando necesitas control fino (memoria, tiempo real, hot loops) o el motor no puede inferir un plan eficiente.
9) “Multiparadigma”: lo que realmente pasa en proyectos modernos
Lenguajes como PHP, JavaScript, Python, Java se usan así:
- Imperativo/POO para arquitectura: módulos, servicios, entidades, capas.
- Declarativo/funcional para procesamiento de datos: colecciones, pipelines.
- Declarativo SQL para consultas y agregaciones.
- Eventos para flujos asíncronos.
Un backend típico (Symfony/Laravel) mezcla:
- Controlador imperativo (manejo request/response)
- Dominio POO (servicios/entidades)
- Consultas declarativas (ORM/SQL)
- Transformaciones funcionales (arrays/collections)
10) Criterios técnicos para elegir (en serio)
Usa imperativo cuando:
- necesitas control explícito del orden (protocolos, IO secuencial, parsers)
- el estado es central (simulaciones, juegos, caches, máquinas de estado)
- estás optimizando un hot path y el overhead importa
Usa declarativo cuando:
- el problema es naturalmente una consulta o una transformación (datos)
- quieres composición, legibilidad por intención, y testeo fácil
- hay un motor que optimiza (DB, reglas, compilador funcional)
11) Checklist de señales en tu código
Estás en imperativo si ves mucho:
- variables acumuladoras
- bucles con
break/continue - mutación frecuente de estructuras
- orden de instrucciones “define” el resultado
Estás en declarativo si ves mucho:
- composición de funciones/operadores
- expresiones que describen resultados
- consultas y filtros expresados por intención
- menor dependencia del orden (o está encapsulada)
Cierre: la diferencia en una línea
- Imperativa: “controlas el proceso”.
- Declarativa: describes la propiedad/resultado y delegas el proceso.

