P
Recherches récentes

CodeIgniter 4: nuestra elección, nuestras razones

15 vues

Elegir un framework es un compromiso

Elegir un framework no es un detalle de arquitectura: es un compromiso de varios años. Convives con sus fuerzas y sus defectos en cada línea de código, cada subida de versión, cada contratación. Más vale elegirlo con los ojos abiertos.

Cuando sentamos los cimientos de Punky Tools, elegimos CodeIgniter 4. No por costumbre, no por moda — por convicción. Y tres años después, sigue siendo la columna vertebral de todo lo que construimos.

Estas son nuestras razones, sin rodeos: la legibilidad, la sobriedad, las cifras, las comparaciones con los pesos pesados de PHP, código concreto — y también, con honestidad, lo que cuesta.

La legibilidad antes que la moda

Muchos frameworks PHP apilan capas de abstracción hasta que ya no sabes qué pasa de verdad. Contenedores de inyección, fachadas, eventos mágicos, resolución dinámica… Es potente, pero cuando surge un bug, a veces cavas diez niveles antes de tocar suelo.

CI4 hace la apuesta inversa: un núcleo ligero y explícito, que entiendes leyendo el código. Una llamada parece una llamada. Una ruta apunta a un controlador, sin intermediario oculto. Cuando surge un problema, subes la pila sin perderte.

No es un detalle de comodidad: es lo que hace una base de código mantenible a lo largo del tiempo, y transmisible. Un desarrollador que llega al proyecto lee el código y entiende — no tiene que descifrar una catedral de abstracciones antes de ser productivo.

Lo explícito envejece mejor que lo mágico. Lo mágico impresiona; lo explícito se arregla a las tres de la madrugada.

Un núcleo ligero: las cifras

CI4 está bajo licencia MIT — libre, sin suscripción, sin trampa de licencia. Su versión 4 inicial data de febrero de 2020; hoy vamos por la rama 4.7 (publicada a principios de 2026), lo que representa seis años de maduración sin rupturas brutales. Tranquilizador para un producto que se mantiene en el tiempo.

En cuanto al runtime: PHP 8.2+ requerido (y hasta PHP 8.5 soportado), lo que permite aprovechar el JIT, el config caching, el file locator caching y el preloading — todo ganancias de CPU en producción.

Sobre todo, allí donde un ecosistema «completo» arrastra decenas de paquetes Composer transitivos en la instalación, el núcleo de CI4 se conforma con un puñado de dependencias. Menos código de terceros es menos superficie de ataque, menos conflictos de versiones y un arranque más rápido. El lema oficial no miente: «the small framework with powerful features».

En concreto, en un servidor OVH/Plesk clásico, esta sobriedad se traduce en una huella de memoria contenida y un tiempo de bootstrap corto — sin necesidad de una infraestructura desmesurada.

El routing: claro y explícito

El routing marca el tono. En CI4, declaras tus rutas a mano, y lees la tabla de rutas como un índice de la aplicación. Sin descubrimiento implícito oscuro: lo que está enrutado está escrito.

Routes.php
$routes->get('articles', 'ArticleController::index');
$routes->get('articles/(:segment)', 'ArticleController::show/$1');
$routes->post('articles', 'ArticleController::create');

// Grupo protegido por un filtro
$routes->group('starshield', ['filter' => 'session'], function ($routes) {
    $routes->resource('posts');
});

Los placeholders tipados ((:segment), (:num)…) mantienen las URLs limpias, los grupos aplican un prefijo y un filtro de una vez, y el orden de las rutas está controlado — las rutas específicas antes que los atrapa-todo. Es nítido, y se depura a simple vista.

Este carácter explícito tiene un coste mínimo al escribir, ampliamente compensado por la claridad al releer. Siempre sabes por qué una URL lleva a algún sitio.

El ORM ligero: Model + Query Builder

CI4 no entrega un ORM monumental al estilo Doctrine, ni la omnipresencia de un Active Record que lo esconde todo. Ofrece un Model simple y un Query Builder que se pega al SQL — sin perder el control de lo que realmente va a la base de datos.

ArticleModel.php
class ArticleModel extends Model
{
    protected $table         = 'articles';
    protected $primaryKey    = 'id';
    protected $allowedFields = ['title', 'slug', 'body', 'status'];
    protected $useTimestamps = true;
}

// Query Builder: legible, cercano al SQL
$articles = $model
    ->where('status', 'published')
    ->orderBy('published_at', 'DESC')
    ->findAll(10);

Conservas la legibilidad de una consulta encadenada, pero siempre puedes bajar al SQL crudo cuando se justifica. Sin sorpresa de rendimiento escondida tras una relación «lazy» que dispara cien consultas sin avisar.

Para nuestras necesidades — multilingüe, relaciones, traducciones — construimos nuestros propios traits encima (joins, HasTranslations…). El Model ligero de CI4 se deja extender sin pelear contra él.

Las migraciones y el esquema

La base de datos se versiona como el código. Las migraciones de CI4, impulsadas por la clase Forge, describen el esquema en PHP: creas, modificas, reviertes, y todo el mundo trabaja sobre la misma estructura.

Migration_Articles.php
public function up()
{
    $this->forge->addField([
        'id'           => ['type' => 'INT', 'unsigned' => true, 'auto_increment' => true],
        'title'        => ['type' => 'VARCHAR', 'constraint' => 255],
        'slug'         => ['type' => 'VARCHAR', 'constraint' => 255],
        'published_at' => ['type' => 'DATETIME', 'null' => true],
    ]);
    $this->forge->addKey('id', true);
    $this->forge->createTable('articles');
}

Combinadas con los seeders para los datos iniciales, las migraciones hacen un nuevo entorno reproducible en un solo comando Spark. Se acabó el «funciona en mi máquina»: la estructura está en el repositorio, punto.

Es un ejemplo de la filosofía CI4: una herramienta simple, que hace una cosa bien, sin imponer un workflow rígido alrededor.

Shield: la autenticación, sin reinventarla

La autenticación es justo el tipo de pieza que no quieres escribir tú mismo — demasiado sensible, demasiadas trampas. CI4 tiene su respuesta oficial: Shield, mantenido por el equipo del framework.

auth.php
// Una zona reservada a los conectados
$routes->group('starshield', ['filter' => 'session'], function ($routes) {
    // back-office Punky
});

// Comprobar un permiso en un controlador
if (! auth()->user()->can('posts.edit')) {
    return redirect()->back()->with('error', 'Acceso denegado');
}

Sesiones, tokens de API, gestión de grupos y permisos, salvaguardas de seguridad: Shield cubre lo esencial con limpieza. En nuestro caso, todo el back-office vive tras el prefijo starshield, protegido por el filtro de sesión.

Es exactamente el equilibrio que buscamos: una pieza oficial y sólida para lo que debe serlo — y la libertad de programar nosotros mismos el resto.

Tasks & Queue: lo asíncrono bien hecho

No todo debe hacerse mientras el visitante espera. Envío de e-mails, generación de miniaturas, sincronización de catálogo, generación de sitemap… eso se va a una tarea en segundo plano.

queue.php
// Apilar un job asíncrono
service('queue')->push('emails', SendNewsletter::class, [
    'campaignId' => $id,
]);

// El worker corre vía Spark:
// php spark queue:work emails

CI4 dispone de Tasks (planificación tipo cron) y de una Queue para los jobs asíncronos. Apilas, un worker desapila: la petición del visitante sigue siendo rápida, y el trabajo pesado se hace en otro sitio.

Solo aprendimos una sutileza: lanzar un comando Spark desde un contexto HTTP/FPM requiere algo de cuidado (PHP no define ahí los flujos CLI). Una vez el patrón en su sitio, todo en orden.

Rendimiento y sobriedad

Un framework ligero significa un arranque rápido y una huella de memoria contenida. En servidores OVH/Plesk clásicos — no clústers interminables — eso marca toda la diferencia entre una página ágil y una que se arrastra.

cache.php
$menu = cache('menu:main');

if ($menu === null) {
    $menu = $this->navModel->tree();
    cache()->save('menu:main', $menu, 3600); // 1 h
}

return $menu;

Combinado con Redis y una verdadera disciplina de caché, CI4 aguanta la carga sin infraestructura desmesurada. Memorizas lo que es costoso pero estable, invalidas con precisión, y la base respira.

A ello se añaden las optimizaciones nativas de PHP 8.2+ (JIT, preloading) y las cachés internas del framework (config, file locator). La sobriedad no es solo una postura: se mide en milisegundos y en facturas de servidor.

CI4 frente a Laravel y Symfony

Seamos claros: Laravel es excelente. Su ecosistema es inmenso, su productividad inmediata, su comunidad enorme. Symfony es una referencia de ingeniería para las aplicaciones de empresa complejas. El «mejor» framework no existe en absoluto — solo el mejor adaptado a un contexto.

CriterioCodeIgniter 4LaravelSymfony
Enfoqueminimalista, explícitofull-stack, convencionesmodular (bundles)
ORMQuery Builder + Model ligeroEloquent (Active Record)Doctrine (Data Mapper)
Contenedor / inyecciónservicios explícitos (service())contenedor IoC + fachadascontenedor DI + autowiring
Dependencias Composerun puñadodecenas (transitivas)decenas de componentes
Motor de plantillasvistas PHP / BladeOneBladeTwig
Perímetro integradorouting, migraciones, validaciónqueue, mail, broadcasting, caché…núcleo + bundles a demanda
Curva de aprendizajerápidamediaempinada
Huella / bootstrapfaiblemás pesadavariable según config
Ideal para…control, mantenimiento largoproductividad, gran ecosistemaapps de empresa complejas

Laravel aporta un perímetro funcional enorme de inmediato — al precio de una abstracción más marcada (fachadas, contenedor IoC) y decenas de dependencias transitivas. Symfony ofrece una modularidad y un rigor de ingeniería incomparables (contenedor DI, autowiring, bundles) — al precio de una curva de aprendizaje empinada. CI4 apunta a otro punto de equilibrio: un Query Builder legible en vez de un ORM pesado, servicios explícitos en vez de un contenedor omnipresente, suficiente estructura para no reinventar la rueda, suficiente ligereza para seguir siendo dueño del código.

Para un producto del que controlamos cada línea y que mantenemos vivo durante años, este punto de equilibrio es exactamente el que queríamos.

¿Y frente a los micro-frameworks?

En el otro extremo están los micro-frameworks (tipo Slim) o el «PHP desnudo». Aún más ligeros, aún más libres — pero entonces hay que construirlo todo: routing estructurado, validación, migraciones, seguridad, convenciones.

CI4 se coloca justo en el punto adecuado: da una columna vertebral (estructura, convenciones, herramientas esenciales) sin el peso de un ecosistema completo. No empiezas de cero en cada proyecto, y tampoco arrastras una fábrica de gas.

Es ese «término medio» el que inclinó la decisión: la libertad de un framework pequeño, con las salvaguardas de uno grande.

Cómo lo extendemos: nuestros módulos Punky

La ligereza de CI4 se nota sobre todo al extenderlo. Todo Punky Tools está dividido en módulos autónomos, sobre el namespace Punky\{Module}, que se conectan al núcleo sin modificarlo.

Module.php
namespace Punky\Blog;

class Module extends PunkyBaseModule
{
    // Un módulo declara sus rutas, su menú admin
    // y sus providers (sitemap, búsqueda…)
    public function getSitemapProviders(): array
    {
        return [new PostSitemapProvider()];
    }
}

Cada módulo declara sus rutas, su menú admin, sus providers (sitemap, búsqueda…) mediante auto-descubrimiento. Añadir una funcionalidad es añadir un módulo — no parchear el núcleo. El modelo sigue fielmente la lógica de módulos de CI4.

Resultado: reutilizamos la misma arquitectura de un sitio de cliente a otro, y capitalizamos. Una nueva necesidad se traduce en una nueva pieza, que volverá a servir en otro sitio.

La otra cara de la moneda

Porque la hay, y preferimos decirlo. CI4 exige construir más uno mismo: menos paquetes «todo en uno» listos para usar que en el ecosistema Laravel, una comunidad más pequeña, menos tutoriales para cada caso retorcido.

Para nosotros, es una ventaja: dominamos lo que escribimos, no heredamos comportamientos que no elegimos, y sabemos exactamente qué corre en producción. El control tiene un coste, y lo pagamos con gusto.

Pero seamos justos: para un equipo que quiere algo llave en mano inmediato, entregar rápido con el máximo de piezas ya hechas, este «construir uno mismo» será un coste, no un placer. La herramienta adecuada depende de lo que valoras: la velocidad de salida, o el control a largo plazo.

También hay un factor de equipo: la cantera de desarrolladores Laravel es más amplia. Lo asumimos — preferimos gente a la que le gusta entender el código antes que gente que busca una receta ya hecha.

Una base que no nos ha fallado

En tres años, hemos atravesado varias subidas de versión (hasta la 4.7) sin reescritura dolorosa. Los cambios de comportamiento están documentados, las deprecaciones anunciadas, y la retrocompatibilidad tomada en serio — lo que, para un producto que se mantiene, vale oro.

Incluso encontramos regresiones puntuales (un filtro CSRF que codificaba cuerpos JSON, por ejemplo) — pero como el núcleo es legible, diagnosticamos y esquivamos rápido. Esa es toda la ventaja de un código que se puede leer: hasta sus bugs son comprensibles.

La seguridad y el mantenimiento siguen el ritmo de PHP: el framework abandona las versiones de PHP en fin de vida y empuja a mantenerse al día. Una restricción sana, que obliga a una buena higiene.

Tres años después

Hicimos nuestra elección con conocimiento de causa: un framework legible, sobrio, sin magia negra, que extendemos por módulos y dominamos de principio a fin. Conocemos sus fuerzas, y asumimos la otra cara.

Y tres años después, con Punky Tools en producción en sitios de clientes y la propia agencia, lo volveríamos a hacer sin dudar. La columna vertebral aguanta.

Ligero, legible, sin magia negra. El mejor framework es aquel cuya cada línea entiendes.

Partager