Categoría: Sin categoría

  • Guía práctica para ganar dinero probando apps (experiencia real)

    Guía práctica para ganar dinero probando apps (experiencia real)

    Resumen: este artículo resume una experiencia real probando aplicaciones para obtener ingresos extra y ofrece una guía práctica. Incluye requisitos, pasos operativos, ejemplos de reporte y un checklist para maximizar tus posibilidades de pago.

    La guía está basada en el testimonio de una persona que ganó $81.20 en dos días con tareas de testing. Los valores y plazos citados provienen de ese relato y se presentan como experiencia, no como garantía.

    Introducción

    El flujo descrito corresponde a plataformas de pruebas de producto donde actúas como tester de aplicaciones móviles: recibes tareas por correo, ejecutas pruebas y envías reportes siguiendo pautas específicas.

    En la experiencia citada, el autor completó varias tareas, cobró por proyectos y por reportes de bugs, e hizo pruebas de reproducibilidad que aportaron ingresos adicionales.

    Prerrequisitos

    1. Cuenta de correo activa y accesible para recibir notificaciones de nuevos proyectos.
    2. Cuenta para recibir pagos (el relato menciona PayPal o Upwork como vías de pago).
    3. Dispositivo móvil compatible con los requisitos de cada proyecto; a veces solicitan cámara u otros accesorios.
    4. Perfil completado y haber pasado el test comunitario de la plataforma (en el relato se permiten dos intentos).

    Nota: la disponibilidad de oportunidades puede depender de la ubicación geográfica y del dispositivo que declares.

    Desarrollo

    Procedimiento

    1. Registro: completa el formulario de la plataforma, confirma tu correo y rellena el perfil con datos reales sobre tus dispositivos.
    2. Evaluación: realiza el test comunitario de la plataforma. En el caso relatado solo hay dos intentos; tómalo en serio.
    3. Notificaciones: vigila el correo; las oportunidades llegan por email con detalles (ubicación, tipo de prueba, requisitos de dispositivo).
    4. Unirse a la prueba: al encontrar un proyecto compatible, pulsa la opción para unirte y lee las instrucciones del test con atención.
    5. Ejecutar pruebas: realiza las tareas solicitadas, documenta pasos y evidencia (capturas si se permiten) y busca bugs siguiendo las pautas del FAQ.
    6. Reportar: envía el informe de bug conforme al formato exigido. Si tu informe cumple las reglas, se paga por bug; en el relato el pago por bug llegó a US$16 dependiendo de la gravedad.
    7. Pruebas de reproducibilidad: cuando alguien reporta un bug, puedes confirmar su reproducción en tu dispositivo y recibir un pago adicional (US$1–1.50 según el relato).
    8. Plazos y cobro: las pruebas suelen tener deadlines (ejemplo en el relato: 48 horas) y los pagos se procesan en días posteriores (el relato menciona 12–14 días de procesamiento).

    Consejos operativos: sé honesto sobre tu equipo, enumera todos tus dispositivos si puedes, activa notificaciones y lee la guía/FAQ de cada proyecto antes de enviar reportes.

    Sé honesto sobre tu setup; la plataforma puede pedir requisitos extra (por ejemplo cámara) y rechazará participantes que no cumplan.

    Ejemplos

    A continuación hay plantillas que sirven como punto de partida: un ejemplo de reporte de bug y un procedimiento breve para una prueba de reproducibilidad.

    Resumen: [Título breve del bug]
    Plataforma: Android / iOS
    Versión de la app: [número]
    Dispositivo: [marca y modelo]
    OS: [versión de sistema]
    Pasos para reproducir:
    1. Abrir la app
    2. Ir a [sección]
    3. Realizar [acción]
    Resultado esperado: [qué debería pasar]
    Resultado real: [qué sucedió]
    Evidencia: [capturas, logs, video] (adjuntar si la plataforma lo permite)
    Severidad sugerida: [baja/mediana/alta]
    Observaciones: [datos adicionales, condiciones de red, permisos]
    Lenguaje del código: texto plano (plaintext)
    Procedimiento de reproducibilidad (ejemplo de 5 minutos):
    1. Verificar la versión de la app y el sistema operativo.
    2. Seguir exactamente los pasos indicados en el reporte original.
    3. Anotar si el bug ocurre en el mismo punto y bajo las mismas condiciones.
    4. Probar con diferentes estados (con/sin red, permisos activados/desactivados) si aplica.
    5. Adjuntar evidencia y confirmar si el bug es reproducible o no.
    Lenguaje del código: texto plano (plaintext)

    Checklist

    1. Perfil completo y correo verificado.
    2. Dispositivo registrado y descripción veraz del setup.
    3. Leer FAQ e instrucciones del test antes de empezar.
    4. Comprobar deadlines y planificar tiempo para enviar dentro de 48 horas (si aplica).
    5. Usar la plantilla de reporte y adjuntar evidencia según lo permitido.
    6. Revisar políticas de pago y métodos disponibles (p. ej. PayPal/Upwork según el relato).

    Conclusión

    Según la experiencia descrita, probar apps puede generar ingresos adicionales si sigues las reglas de la plataforma y envías reportes bien documentados. No es garantía de ingresos constantes, ya que la disponibilidad depende de la localización y la demanda.

    Si decides probar esta vía, comienza por completar el perfil, pasar la evaluación comunitaria y activar notificaciones. Utiliza la plantilla y el checklist para aumentar la probabilidad de pago.

    Si ya probaste plataformas de testing como la descrita, comparte tu experiencia en los comentarios para ayudar a otros.

  • Agentes inteligentes con Sequential Thinking MCP y OpenAI Agents

    Agentes inteligentes con Sequential Thinking MCP y OpenAI Agents

    Resumen: Este artículo muestra cómo combinar Sequential Thinking MCP con el OpenAI Agents SDK para dotar a agentes de una memoria estructurada y razonamiento paso a paso.

    Incluye los prerrequisitos, la arquitectura básica, ejemplos de código y una checklist para empezar rápidamente.

    Introducción

    Los agentes conversacionales tienden a perder el hilo cuando la tarea requiere múltiples pasos o reflexión profunda. Sequential Thinking MCP actúa como una memoria externa donde el agente puede registrar pensamientos, organizar etapas y recuperar resúmenes.

    El enfoque permite transformar respuestas reactivas en procesos de razonamiento sistemático que pueden auditarse y reutilizarse.

    Prerrequisitos

    Antes de integrar Sequential Thinking MCP con un agente necesitas instalar las dependencias y disponer del entorno donde ejecutar el servidor MCP.

    Instala los paquetes necesarios con pip:

    pip install openai-agents
    pip install mcp-sequential-thinking
    Lenguaje del código: Bash (bash)

    Desarrollo

    La integración sigue un patrón sencillo: arrancar el servidor MCP, registrar el servidor como herramienta del agente y usar las funciones de registro y resumen durante la sesión de razonamiento.

    Funciones básicas que ofrece el servidor Sequential Thinking MCP (según el diseño comentado):

    • process_thought — registra un pensamiento con metadatos (etapa, secuencia, importancia).
    • generate_summary — produce un resumen del proceso de pensamiento acumulado.
    • clear_history — borra la memoria de pensamientos para empezar una sesión nueva.

    Procedimiento

    Ejemplo básico de flujo para crear y registrar un servidor MCP en un agente. El snippet ilustra el lanzamiento del servidor y la creación del agente que lo utiliza.

    async def create_thinking_agent():
        # Launch the Sequential Thinking MCP server
        seq_server = MCPServerStdio(
            name="SequentialThinkingServer",
            params={
                "command": "mcp-sequential-thinking",
                "args": []
            }
        )
        
        # Connect and register with agent
        async with seq_server as mcp:
            agent = Agent(
                name="ThinkingAgent",
                instructions=(
                    "You are a methodical problem-solver. Use Sequential "
                    "Thinking tools to organize your analysis step-by-step."
                ),
                mcp_servers=[mcp]
            )
            
            return agent, mcp
    Lenguaje del código: texto plano (plaintext)

    Con el agente registrado, puedes ejecutar tareas complejas pasando la pregunta inicial al Runner del SDK:

    # Definir un agente que use el servidor MCP
    agent = Agent(
        name="TimeTravelPlanner",
        instructions=(
            "You are a planning assistant. Think step-by-step, and use the Sequential "
            "Thinking tools (thought recording, summary) to organize your plan."
        ),
        mcp_servers=[mcp]
    )
    
    # Ejecutar la tarea con Runner
    user_query = "Devise a safe and efficient plan to travel to the year 2050 and back."
    result = await Runner.run(starting_agent=agent, input=user_query)
    print(result.final_output)
    Lenguaje del código: texto plano (plaintext)

    Maneja fallos de conexión al servidor MCP con un fallback sencillo para mantener disponibilidad:

    try:
        async with seq_server as mcp:
            # Lógica del agente que usa MCP
            pass
    except ConnectionError:
        # Fallback a agente sin MCP
        agent = Agent(name="FallbackAgent", instructions="...")
    Lenguaje del código: texto plano (plaintext)

    Ejemplos

    En un caso complejo (p. ej. plan de viaje temporal), el agente con memoria estructurada produce un resumen con etapas claras en lugar de respuestas dispersas.

    Ejemplo simplificado de salida estructurada (ilustrativa):

    Time Travel Plan Analysis:
    Problem Definition: Safe bidirectional time travel to 2050
    Research: Evaluated 3 theoretical methods
    Analysis: Relativistic travel most feasible
    Synthesis: Detailed 30-year mission plan
    Conclusion: Actionable recommendations with safety protocols
    Lenguaje del código: texto plano (plaintext)

    Checklist

    1. Instalar dependencias: openai-agents y mcp-sequential-thinking.
    2. Arrancar el servidor MCP y verificar conexión estable.
    3. Registrar el MCP como herramienta en el agente.
    4. Diseñar etapas de pensamiento (Problem → Research → Analysis → Synthesis → Conclusion).
    5. Implementar manejo de fallos y fallback sin MCP.
    6. Probar con un caso complejo y comparar resultados con el agente tradicional.
    7. Medir y auditar la memoria de pensamientos según necesidades del proyecto.

    Conclusión

    Sequential Thinking MCP aporta una memoria estructurada que permite a los agentes razonar de forma secuencial y coherente. La integración con OpenAI Agents SDK simplifica el patrón: registrar pensamientos, generar resúmenes y continuar la reflexión.

    Empieza por implementar el flujo básico, maneja las conexiones con cuidado y aplica el enfoque solo en problemas que requieran análisis en varias etapas.

  • Identificar y gestionar limitaciones personales en equipos de software

    Identificar y gestionar limitaciones personales en equipos de software

    Resumen: En este artículo técnico explico cómo identificar qué función cumplen las limitaciones personales, cómo analizarlas y opciones prácticas para gestionarlas en contextos personales y de equipo.

    Introducción

    En entornos técnicos, las limitaciones personales suelen manifestarse como creencias internas que condicionan decisiones, prioridades y desarrollo profesional.

    Este artículo adapta conceptos de prácticas como hipnoterapia, counselling y programación neurolingüística para ofrecer un enfoque práctico y aplicable en equipos de software.

    Prerrequisitos

    No se requieren certificaciones específicas para comenzar el autoanálisis; sí es útil disponer de tiempo para reflexión y, cuando procede, el apoyo de un profesional o colega de confianza.

    Desarrollo

    Procedimiento

    El enfoque central es descubrir qué función cumple la limitación: qué evita y qué beneficio oculto proporciona. Una vez identificado, se diseñan alternativas concretas que satisfagan esa función sin la carga negativa.

    1. Identificar la creencia limitante y cuándo aparece.
    2. Analizar qué evita esa creencia (riesgo, esfuerzo, comparación social).
    3. Explorar qué beneficio oculto ofrece (comodidad, protección, coherencia social).
    4. Diseñar alternativas que cubran ese beneficio sin impedir objetivos.

    En equipos, aplicar este procedimiento implica conversaciones estructuradas y retroalimentación orientada a la función de la limitación, no a su moralización.

    #!/usr/bin/env bash
    # script de reflexión rápida
    echo "Describe la limitación (en una frase):"
    read LIMITATION
    echo "¿Qué evita esta limitación? (riesgo/tiempo/vergüenza):"
    read AVOIDED
    echo "¿Qué beneficio oculto ofrece?:"
    read BENEFIT
    echo "Alternativas posibles (3):"
    read ALT1
    read ALT2
    read ALT3
    cat <<EOF
    Limitación: $LIMITATION
    Evita: $AVOIDED
    Beneficio: $BENEFIT
    Alternativas:
     - $ALT1
     - $ALT2
     - $ALT3
    EOF
    Lenguaje del código: Bash (bash)

    Ejemplos

    Ejemplo práctico: la creencia “no soy buen programador en X” puede ocultar la preferencia por dedicar tiempo a otras áreas o el miedo a la exposición.

    Al identificar la función (ahorrar tiempo, evitar crítica), se pueden proponer alternativas: aprendizaje estructurado, tareas pair-programming o revisiones anónimas de código.

    {
      "limitation": "No soy natural en X",
      "when": "Durante revisiones de código",
      "avoids": "Exposición y crítica",
      "hidden_benefit": "Mantener tiempo para otras prioridades",
      "alternatives": [
        "Sesiones de aprendizaje estructuradas",
        "Pair programming con colega de confianza",
        "Objetivos pequeños y medibles"
      ]
    }
    Lenguaje del código: JSON / JSON con comentarios (json)

    Checklist

    1. Registrar la limitación con contexto concreto.
    2. Especificar qué evita y qué aporta.
    3. Evaluar si renombrarla o sustituirla por una alternativa.
    4. Probar la alternativa en pequeño (experimentación controlada).
    5. Revisar resultados y ajustar en equipo.

    Conclusión

    Las limitaciones son, a menudo, estrategias adaptativas con una función concreta.

    Al enfocarnos en la función y diseñar alternativas concretas, podemos cambiar comportamientos sin negar la necesidad subyacente.

  • Module Federation en Next.js: microfrontends prácticos

    Module Federation en Next.js: microfrontends prácticos

    Resumen: Este artículo explica cómo configurar Module Federation en Next.js para compartir componentes entre aplicaciones en tiempo de ejecución y crear micro‑frontends desplegables de forma independiente.

    Incluye pasos prácticos, ejemplos de configuración y código listo para copiar y adaptar en tus proyectos.

    Introducción

    Module Federation (a través del plugin de Webpack) permite compartir módulos entre aplicaciones en tiempo de ejecución en lugar de durante el build.

    En Next.js esto se usa para convertir un frontend monolítico en varios micro‑frontends que se desarrollan y despliegan de forma independiente, manteniendo una experiencia de usuario unificada.

    Prerrequisitos

    • Node.js y entorno para ejecutar aplicaciones Next.js.
    • Dos aplicaciones Next.js (por ejemplo: remote-app y host-app).
    • El paquete de integración para Next.js: @module-federation/nextjs-mf.

    Desarrollo

    Procedimiento

    Lista de pasos resumidos para crear el flujo host/remote:

    1. Crear la aplicación remote y añadir el plugin de Module Federation.
    2. Configurar next.config.js en la remote para exponer componentes.
    3. Crear los componentes que se van a exponer.
    4. Crear la aplicación host, añadir el plugin y configurar los remotes.
    5. Declarar tipos (si usas TypeScript) y consumir los componentes remotos con import dinámico y ssr: false.

    En las siguientes subsecciones se incluyen ejemplos mínimos de configuración y uso.

    Ejemplos

    Comandos iniciales para crear las aplicaciones (ejemplo):

    npx create-next-app@latest remote-app --typescript --tailwind --app
    cd remote-app
    npm install @module-federation/nextjs-mf
    npm run dev -- -p 3001
    Lenguaje del código: Bash (bash)

    Ejemplo: next.config.js de la aplicación remote (expone componentes):

    const { NextFederationPlugin } = require('@module-federation/nextjs-mf');
    
    module.exports = {
      webpack(config, options) {
        config.plugins.push(
          new NextFederationPlugin({
            name: 'remote_app',
            filename: 'static/chunks/remoteEntry.js',
            exposes: {
              './Button': './components/Button',
              './UserCard': './components/UserCard',
            },
            shared: {
              react: { singleton: true },
              'react-dom': { singleton: true },
            },
          })
        );
        return config;
      },
    };
    Lenguaje del código: JavaScript (javascript)

    Componente Button en TypeScript (remote/components/Button.tsx):

    interface ButtonProps {
      onClick?: () => void;
      children: React.ReactNode;
      variant?: 'primary' | 'secondary';
    }
    
    export default function Button({ onClick, children, variant = 'primary' }: ButtonProps) {
      const baseClasses = 'px-4 py-2 rounded-md font-medium transition-colors';
      const variantClasses = {
        primary: 'bg-blue-500 text-white hover:bg-blue-600',
        secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
      };
    
      return (
        <button
          onClick={onClick}
          className={`${baseClasses} ${variantClasses[variant]}`}
        >
          {children}
        </button>
      );
    }
    Lenguaje del código: TypeScript (typescript)

    Arrancar la remote en el puerto 3001:

    npm run dev -- -p 3001
    Lenguaje del código: Bash (bash)

    Comandos y configuración para la aplicación host:

    npx create-next-app@latest host-app --typescript --tailwind --app
    cd host-app
    npm install @module-federation/nextjs-mf
    Lenguaje del código: Bash (bash)

    next.config.js de la aplicación host (consume la remote):

    const { NextFederationPlugin } = require('@module-federation/nextjs-mf');
    
    module.exports = {
      webpack(config, options) {
        config.plugins.push(
          new NextFederationPlugin({
            name: 'host_app',
            remotes: {
              remote_app: 'remote_app@http://localhost:3001/_next/static/chunks/remoteEntry.js',
            },
            shared: {
              react: { singleton: true },
              'react-dom': { singleton: true },
            },
          })
        );
        return config;
      },
    };
    Lenguaje del código: JavaScript (javascript)

    Definiciones de tipos para TypeScript (types/remote-components.d.ts):

    declare module 'remote_app/Button' {
      interface ButtonProps {
        onClick?: () => void;
        children: React.ReactNode;
        variant?: 'primary' | 'secondary';
      }
      
      const Button: React.ComponentType<ButtonProps>;
      export default Button;
    }
    
    declare module 'remote_app/UserCard' {
      interface User {
        id: string;
        name: string;
        email: string;
        avatar?: string;
      }
      
      interface UserCardProps {
        user: User;
        onEdit?: () => void;
      }
    
      const UserCard: React.ComponentType<UserCardProps>;
      export default UserCard;
    }
    Lenguaje del código: TypeScript (typescript)

    Consumo dinámico de componentes remotos en app/page.tsx (host):

    'use client';
    
    import { Suspense, useState } from 'react';
    import dynamic from 'next/dynamic';
    
    const RemoteButton = dynamic(() => import('remote_app/Button'), {
      ssr: false,
    });
    const RemoteUserCard = dynamic(() => import('remote_app/UserCard'), {
      ssr: false,
    });
    
    export default function Home() {
      const [message, setMessage] = useState('');
    
      const sampleUser = {
        id: '1',
        name: 'John Doe',
        email: '[email protected]',
      };
    
      return (
        <div className="container mx-auto px-4 py-8">
          <h1 className="text-3xl font-bold text-center mb-8">
            Module Federation Demo
          </h1>
          
          <div className="max-w-2xl mx-auto space-y-8">
            <div className="text-center">
              <h2 className="text-xl font-semibold mb-4">Remote Button Component</h2>
              <Suspense fallback=<>Loading button...</>>
                <RemoteButton 
                  onClick={() => setMessage('Hello from remote button!')}
                  variant="primary"
                >
                  Click Me (Remote)
                </RemoteButton>
              </Suspense>
              {message && (
                <p className="mt-4 text-green-600 font-medium">{message}</p>
              )}
            </div>
    
            <div className="text-center">
              <h2 className="text-xl font-semibold mb-4">Remote UserCard Component</h2>
              <Suspense fallback=<>Loading user card...</>>
                <div className="flex justify-center">
                  <RemoteUserCard 
                    user={sampleUser}
                    onEdit={() => alert('Edit clicked!')}
                  />
                </div>
              </Suspense>
            </div>
          </div>
        </div>
      );
    }
    Lenguaje del código: TypeScript (typescript)

    Arrancar la host en otro puerto (ejemplo 3000):

    npm run dev -- -p 3000
    Lenguaje del código: Bash (bash)

    Nota práctica: siempre usar import dinámico con ssr: false y envolver en Suspense para evitar problemas con SSR.

    Ejemplo de manejo de URL remota entre entornos (ejemplo tomado como referencia):

    const remoteUrl = process.env.NODE_ENV === 'production' 
      ? 'https://your-host-app.vercel.app/_next/static/chunks/remoteEntry.js'
      : 'http://localhost:3000/_next/static/chunks/remoteEntry.js';
    Lenguaje del código: JavaScript (javascript)

    Checklist

    1. Usar import dinámico con ssr: false y envolver en Suspense.
    2. Compartir React y react-dom como singleton en la configuración de Module Federation.
    3. Declarar tipos .d.ts para los módulos federados si usas TypeScript.
    4. Probar en desarrollo con URLs locales y configurar la URL remota para producción mediante variables de entorno.
    5. Verificar que no se carguen múltiples instancias de React (comportamientos extraños en hooks).

    Estos pasos cubren las causas más comunes de errores y facilitan el diagnóstico durante la integración.

    Conclusión

    Module Federation en Next.js permite compartir componentes entre aplicaciones sin recompilar todo el ecosistema, lo que facilita equipos independientes y despliegues más rápidos.

    No obstante, añade complejidad: obliga a diseñar componentes para renderizado en cliente y a gestionar dependencias compartidas con cuidado.

    Si tu equipo gestiona varias aplicaciones relacionadas o necesitas un sistema de diseño compartido en tiempo real, Module Federation es una herramienta que vale la pena probar y dominar.

  • Escala Symfony con Memcached, múltiples PHP‑FPM y Nginx

    Escala Symfony con Memcached, múltiples PHP‑FPM y Nginx

    Resumen: configuración práctica para escalar una aplicación Symfony en Docker con Nginx como proxy, tres (o más) contenedores PHP‑FPM y Memcached para sesiones compartidas.

    El artículo describe la arquitectura, los archivos clave, comandos para levantar el entorno y pruebas para verificar persistencia de sesión entre contenedores.

    Introducción

    Cuando una aplicación Symfony supera la capacidad de un solo contenedor PHP‑FPM, la solución es ejecutar múltiples instancias de PHP‑FPM y balancearlas con Nginx. Para que las sesiones funcionen entre instancias se requiere un almacén centralizado: Memcached.

    Prerrequisitos

    Antes de empezar, confirma lo siguiente en tu entorno:

    1. Docker y Docker Compose instalados en la máquina host.
    2. Una aplicación Symfony ubicada en ./src dentro del proyecto.
    3. Conocimientos básicos de Nginx, PHP‑FPM y configuración de servicios en contenedores.

    Desarrollo

    La arquitectura recomendada mínima incluye: un contenedor Nginx (proxy/load‑balancer), tres contenedores PHP‑FPM idénticos, un contenedor Memcached y un contenedor PostgreSQL. Nginx distribuye peticiones entre los PHP‑FPM y Memcached almacena sesiones.

    project/
    ├── docker/
    │   ├── nginx/
    │   │   ├── Dockerfile
    │   │   └── default.conf
    │   ├── php-fpm/
    │   │   ├── Dockerfile
    │   │   └── php.ini
    │   └── memcached/
    │       └── memcached.conf
    ├── src/  (tu aplicación Symfony)
    ├── docker-compose.yml
    └── .env
    Lenguaje del código: texto plano (plaintext)

    Procedimiento

    Los pasos esenciales: definir docker-compose, configurar Nginx upstream, preparar la imagen PHP‑FPM con memcached y opcache, ajustar php.ini y la pool de PHP‑FPM, configurar Symfony para usar Memcached como handler de sesión y levantar el conjunto.

    version: '3.8'
    
    services:
      nginx:
        build:
          context: ./docker/nginx
          dockerfile: Dockerfile
        ports:
          - "80:80"
        volumes:
          - ./src:/var/www/symfony
          - php-fpm-sockets1:/var/run/sock/fpm1
          - php-fpm-sockets2:/var/run/sock/fpm2
          - php-fpm-sockets3:/var/run/sock/fpm3
        depends_on:
          - php-fpm-1
          - php-fpm-2
          - php-fpm-3
        networks:
          - symfony-network
    
      php-fpm-1:
        build:
          context: ./docker/php-fpm
          dockerfile: Dockerfile
        volumes:
          - ./src:/var/www/symfony
          - php-fpm-sockets1:/var/run/sock:rw
        environment:
          - APP_ENV=prod
          - DATABASE_URL=postgresql://symfony:secret@postgres:5432/symfony_db
          - MEMCACHED_HOST=memcached
          - MEMCACHED_PORT=11211
        depends_on:
          - memcached
          - postgres
        networks:
          - symfony-network
    
      php-fpm-2:
        build:
          context: ./docker/php-fpm
          dockerfile: Dockerfile
        volumes:
          - ./src:/var/www/symfony
          - php-fpm-sockets2:/var/run/sock:rw
        environment:
          - APP_ENV=prod
          - DATABASE_URL=postgresql://symfony:secret@postgres:5432/symfony_db
          - MEMCACHED_HOST=memcached
          - MEMCACHED_PORT=11211
        depends_on:
          - memcached
          - postgres
        networks:
          - symfony-network
    
      php-fpm-3:
        build:
          context: ./docker/php-fpm
          dockerfile: Dockerfile
        volumes:
          - ./src:/var/www/symfony
          - php-fpm-sockets3:/var/run/sock:rw
        environment:
          - APP_ENV=prod
          - DATABASE_URL=postgresql://symfony:secret@postgres:5432/symfony_db
          - MEMCACHED_HOST=memcached
          - MEMCACHED_PORT=11211
        depends_on:
          - memcached
          - postgres
        networks:
          - symfony-network
    
      memcached:
        image: memcached:1.6-alpine
        ports:
          - "11211:11211"
        command: memcached -m 256
        networks:
          - symfony-network
    
      postgres:
        image: postgres:15-alpine
        environment:
          - POSTGRES_DB=symfony_db
          - POSTGRES_USER=symfony
          - POSTGRES_PASSWORD=secret
        volumes:
          - postgres-data:/var/lib/postgresql/data
        networks:
          - symfony-network
    
    networks:
      symfony-network:
        driver: bridge
    
    volumes:
      postgres-data:
      php-fpm-sockets1:
      php-fpm-sockets2:
      php-fpm-sockets3:
    Lenguaje del código: YAML (yaml)
    FROM nginx:1.25-alpine
    
    COPY default.conf /etc/nginx/conf.d/default.conf
    RUN mkdir -p /var/www/symfony
    WORKDIR /var/www/symfony
    EXPOSE 80
    Lenguaje del código: Dockerfile (dockerfile)
    upstream php_fpm_backend {
        least_conn;
        server unix:/var/run/sock/fpm1/php-fpm.sock weight=1 max_fails=3 fail_timeout=30s;
        server unix:/var/run/sock/fpm2/php-fpm.sock weight=1 max_fails=3 fail_timeout=30s;
        server unix:/var/run/sock/fpm3/php-fpm.sock weight=1 max_fails=3 fail_timeout=30s;
    }
    
    server {
        listen 80;
        server_name localhost;
        root /var/www/symfony/public;
        index index.php;
        client_max_body_size 20M;
        client_body_buffer_size 128k;
    
        location / {
            try_files $uri /index.php$is_args$args;
        }
    
        location ~ ^/index\.php(/|$) {
            fastcgi_pass php_fpm_backend;
            fastcgi_split_path_info ^(.+\.php)(/.*)$;
            include fastcgi_params;
    
            fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
            fastcgi_param DOCUMENT_ROOT $realpath_root;
    
            fastcgi_buffer_size 128k;
            fastcgi_buffers 4 256k;
            fastcgi_busy_buffers_size 256k;
            fastcgi_temp_file_write_size 256k;
    
            fastcgi_read_timeout 300;
            fastcgi_send_timeout 300;
    
            fastcgi_intercept_errors off;
            internal;
        }
    
        location ~ \.php$ {
            return 404;
        }
    
        error_log /var/log/nginx/symfony_error.log;
        access_log /var/log/nginx/symfony_access.log;
    }
    Lenguaje del código: Nginx (nginx)
    FROM php:8.2-fpm-alpine
    
    RUN apk add --no-cache \
        postgresql-dev \
        libzip-dev \
        libmemcached-dev \
        zlib-dev \
        cyrus-sasl-dev \
        git \
        unzip
    RUN docker-php-ext-install \
        pdo \
        pdo_pgsql \
        opcache \
        zip
    RUN apk add --no-cache --virtual .build-deps $PHPIZE_DEPS \
        && pecl install memcached-3.2.0 \
        && docker-php-ext-enable memcached \
        && apk del .build-deps
    COPY php.ini /usr/local/etc/php/conf.d/custom.ini
    RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
    WORKDIR /var/www/symfony
    RUN addgroup -g 1000 symfony && adduser -D -u 1000 -G symfony symfony
    RUN chown -R symfony:symfony /var/www/symfony
    USER symfony
    EXPOSE 9000
    CMD ["php-fpm"]
    Lenguaje del código: Dockerfile (dockerfile)
    [PHP]
    memory_limit = 512M
    upload_max_filesize = 20M
    post_max_size = 20M
    max_execution_time = 300
    max_input_time = 300
    
    [opcache]
    opcache.enable = 1
    opcache.memory_consumption = 256
    opcache.interned_strings_buffer = 16
    opcache.max_accelerated_files = 20000
    opcache.validate_timestamps = 0
    opcache.revalidate_freq = 0
    opcache.save_comments = 1
    opcache.fast_shutdown = 1
    
    [Session]
    session.save_handler = memcached
    session.save_path = "memcached:11211"
    session.gc_maxlifetime = 3600
    
    [Date]
    date.timezone = Europe/Paris
    Lenguaje del código: TOML, también INI (ini)
    [www]
    user = symfony
    group = symfony
    listen = 9000
    listen.owner = symfony
    listen.group = symfony
    
    pm = dynamic
    pm.max_children = 50
    pm.start_servers = 10
    pm.min_spare_servers = 10
    pm.max_spare_servers = 20
    pm.max_requests = 500
    pm.status_path = /fpm-status
    ping.path = /fpm-ping
    request_terminate_timeout = 300
    request_slowlog_timeout = 10
    slowlog = /var/log/php-fpm/slow.log
    catch_workers_output = yes
    decorate_workers_output = no
    php_admin_value[error_log] = /var/log/php-fpm/error.log
    php_admin_flag[log_errors] = on
    Lenguaje del código: TOML, también INI (ini)
    framework:
        secret: '%env(APP_SECRET)%'
        session:
            handler_id: session.handler.memcached
            cookie_secure: auto
            cookie_samesite: lax
            save_path: '%env(MEMCACHED_HOST)%:%env(MEMCACHED_PORT)%'
            gc_maxlifetime: 3600
    
    services:
        session.handler.memcached:
            class: Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcachedSessionHandler
            arguments:
                - '@memcached.connection'
        
        memcached.connection:
            class: Memcached
            calls:
                - method: addServer
                  arguments:
                      - '%env(MEMCACHED_HOST)%'
                      - '%env(int:MEMCACHED_PORT)%'
                - method: setOption
                  arguments:
                      - !php/const Memcached::OPT_PREFIX_KEY
                      - 'symfony_'
                - method: setOption
                  arguments:
                      - !php/const Memcached::OPT_BINARY_PROTOCOL
                      - true
    Lenguaje del código: YAML (yaml)
    docker-compose build
    docker-compose up -d
    docker-compose ps
    
    docker-compose exec php-fpm-1 composer install
    docker-compose exec php-fpm-1 php bin/console doctrine:migrations:migrate --no-interaction
    Lenguaje del código: Bash (bash)

    Ejemplos

    Controlador de ejemplo para verificar persistencia de sesión y cuál contenedor atiende la petición.

    <?php
    
    namespace App\Controller;
    use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpFoundation\Response;
    use Symfony\Component\Routing\Annotation\Route;
    class TestController extends AbstractController
    {
        #[Route('/test/session', name: 'test_session')]
        public function testSession(Request $request): Response
        {
            $session = $request->getSession();
            
            $counter = $session->get('counter', 0);
            $counter++;
            $session->set('counter', $counter);
            
            $hostname = gethostname();
            
            return $this->json([
                'container' => $hostname,
                'session_id' => $session->getId(),
                'counter' => $counter,
                'timestamp' => time()
            ]);
        }
    }
    Lenguaje del código: PHP (php)

    Prueba desde la terminal usando cookies para mantener la sesión entre llamadas:

    curl -c cookies.txt -b cookies.txt http://localhost/test/session
    curl -c cookies.txt -b cookies.txt http://localhost/test/session
    curl -c cookies.txt -b cookies.txt http://localhost/test/session
    Lenguaje del código: Bash (bash)

    Checklist

    • Verificar que todos los PHP‑FPM apunten al mismo Memcached (host/puerto).
    • Asegurar permisos de lectura/escritura sobre sockets compartidos si se usan sockets Unix.
    • Configurar health checks (fpm-ping, nginx stub_status) y revisar logs.
    • Ajustar pm.max_children según RAM disponible y uso por worker.
    • Usar .env o secretos para credenciales y no versionarlas.

    Conclusión

    Con Nginx como balanceador, múltiples contenedores PHP‑FPM y Memcached para sesiones puedes escalar horizontalmente una aplicación Symfony sin cambios en el código de sesión.

    Comienza con tres contenedores PHP‑FPM, monitoriza CPU/memoria y ajusta pm.* o añade contenedores según la demanda. Implementa health checks y protege credenciales en producción.

  • 7 apps para Mac que mejoran productividad y flujo de trabajo

    7 apps para Mac que mejoran productividad y flujo de trabajo

    Resumen: este artículo presenta una selección de siete aplicaciones para macOS que optimizan la gestión de ventanas, atajos, descansos y captura de pantalla. Aquí encontrarás descripción, usos prácticos y un checklist para probarlas.

    Introducción

    Este texto resume características prácticas de siete aplicaciones para Mac que el autor descubrió y adoptó para mejorar su productividad diaria.

    El objetivo es ofrecer descripciones accionables para evaluar cada app y decidir si encaja en tu flujo de trabajo.

    Prerrequisitos

    Se asume que el lector usa macOS y dispone de permisos básicos para instalar y ejecutar aplicaciones. No se detallan versiones específicas del sistema operativo porque no están en la fuente original.

    Desarrollo (apps clave)

    DockDoor

    Problema que resuelve: macOS no muestra vistas previas de ventanas al pasar el cursor por el Dock o al cambiar entre ventanas de una misma app.

    Qué ofrece: añade vistas previas tipo Windows y un conmutador Alt/Tab mejorado (Opt + Tab por defecto). Permite configurar uso de Cmd + Tab si se prefiere.

    Personalización: se pueden ajustar ancho/alto de las vistas previas y su apariencia; la aplicación incluye soporte para efectos visuales como “Liquid Glass” según la descripción original.

    Rcmd

    Concepto: sustituye o complementa a Cmd + Tab usando la tecla Cmd derecha combinada con una letra para saltar directamente a una app.

    Ejemplo práctico: con Rcmd puedes presionar Right Cmd + S para ir directamente a Safari. Si hay varias apps que comparten la misma letra, se vuelve a pulsar la combinación para alternar entre ellas.

    LookAway

    Propósito: reducir la fatiga visual y mejorar la postura mediante recordatorios configurables de pausas y postura.

    Configuración descrita: alertas cada 30 min o 1 h; el autor usa 45 min. Duración de las pausas entre 20 y 60 segundos. También ofrece recordatorios de postura (el autor recomienda ~10 minutos).

    NotchNook

    Funcionalidad: aporta una “isla dinámica” al Mac (incluso si no tienes notch físico) para mostrar controles multimedia y accesos directos, además de una función de “mirror” que abre la webcam en una ventana emergente.

    Tray y acciones: incluye una “Tray” para arrastrar archivos y acceder rápidamente a ellos desde cualquier aplicación; permite activar AirDrop desde ese flujo según la descripción.

    Shareshot

    Para quién sirve: autores de contenido que toman muchas capturas y quieren presentarlas dentro de marcos (iPhone, Mac, Watch) sin ajustarlas manualmente.

    Comportamiento útil: la app elige automáticamente el marco según la relación de aspecto; la versión pro permite ajustar efectos de iluminación de fondo y eliminar la marca de agua.

    Launchy

    Qué hace: ofrece un lanzador radial que se invoca con un atajo (opt + cmd en el relato) y muestra las apps en una rueda para seleccionarlas visualmente.

    Personalización: tamaño del radial, mostrar/ocultar nombres, distancia entre iconos y múltiples conjuntos de apps se pueden configurar para ajustar el flujo de trabajo.

    Amphetamine

    Utilidad concreta: evita que el Mac entre en reposo en situaciones puntuales (por ejemplo, cuando se desconecta el cargador y el autor carga simultáneamente un iPhone con el mismo cable).

    Nota práctica: en el caso del autor fue útil desactivar la opción ‘Closed-Display Mode’ para mantener el equipo despierto en modo clamshell.

    Ejemplos (atajos y ajustes)

    Dos ejemplos prácticos extraídos de las descripciones para aplicar en pruebas rápidas.

    Right Command + S => Safari
    Presiona la misma combinación nuevamente para alternar entre apps que comparten la misma letra
    Lenguaje del código: texto plano (plaintext)

    Ejemplo de ajustes recomendados para recordatorios y pausas (LookAway):

    Intervalo de descanso recomendado: 45m
    Duración de descanso: 30s
    Recordatorio de postura: cada 10m
    Lenguaje del código: texto plano (plaintext)

    Checklist

    1. Instalar DockDoor y probar vistas previas al pasar el cursor por el Dock o usar Opt + Tab.
    2. Configurar Rcmd: asignar Right Cmd + <letra> para las apps más usadas y verificar alternancia si hay duplicados.
    3. Configurar LookAway con un intervalo que no interrumpa tu flujo (probar 45m y 30s por defecto).
    4. Probar NotchNook: comprobar controles multimedia, mirror y la Tray para compartir archivos rápidamente.
    5. Tomar capturas con Shareshot y verificar la selección automática de marcos; evaluar la versión pro si necesitas efectos y sin marca de agua.
    6. Probar Launchy: configurar conjuntos de apps y ajustar la rueda para lanzarlas con opt + cmd.
    7. Usar Amphetamine para mantener el equipo activo en escenarios de clamshell; revisar la opción ‘Closed-Display Mode’.

    Opcional: si usas muchos apps de pago, considera servicios tipo suscripción que agreguen catálogos (la fuente original menciona Setapp como opción de acceso a múltiples apps).

    Conclusión

    Estas siete aplicaciones ofrecen mejoras puntuales: gestión de ventanas, atajos rápidos, recordatorios de descanso, lanzadores visuales, y herramientas para capturas estéticamente presentadas.

    El autor concluye que descubrir herramientas pequeñas y bien pensadas puede ahorrar tiempo real y mejorar ergonomía. También menciona la opción de probar un servicio que da acceso a muchas apps por una cuota mensual y un código de afiliado (‘usefultech’).

    Próximo paso recomendado: seguir la checklist y evaluar cada app durante al menos una semana para medir el impacto real en tu flujo de trabajo.

  • Reducir el uso de Jira en equipos Agile: por qué y cómo

    Reducir el uso de Jira en equipos Agile: por qué y cómo

    Resumen: El uso intensivo de herramientas como Jira suele consumir gran parte del tiempo del equipo sin garantizar prácticas Agile reales. Este artículo explica por qué reducir ese uso y propone alternativas centradas en colaboración directa y automatización de pruebas.

    Introducción

    Durante años muchos equipos han puesto la herramienta de gestión (por ejemplo, Jira) en el centro del proceso. Eso convierte a la herramienta en el flujo de trabajo, no al equipo ni al software entregado.

    Using Jira does NOT mean doing Agile.

    El resultado observado: horas diarias perdidas en actualizar tickets, comentar requerimientos en la herramienta y usarla como registro de vida del proyecto, en vez de invertir ese tiempo en ejecutar, probar y entregar software.

    Prerrequisitos

    Antes de reducir la dependencia de una herramienta de gestión, verifique que el equipo cumpla algunas condiciones mínimas:

    1. Comunicación directa entre Product Owner, desarrolladores y testers.
    2. Cobertura razonable de pruebas end-to-end automatizadas que detecten y reproduzcan defectos.
    3. Canales simples para capturar decisiones y cambios (p. ej., notas mínimas o tarjetas físicas).

    Si alguna de esas condiciones falta, la reducción del uso de la herramienta debe ser gradual y acompañada de mejoras en comunicación y automatización.

    Desarrollo

    Procedimiento

    1. Identificar qué actividades realmente aportan valor cuando se hacen en la herramienta y cuáles son tareas administrativas repetitivas.
    2. Sustituir seguimientos y discusiones largas en la herramienta por reuniones cortas o comunicación directa y registro mínimo.
    3. Aumentar la inversión en pruebas end-to-end automatizadas que reproduzcan defectos y actúen como registro ejecutable.
    4. Preferir artefactos livianos (tarjetas físicas, notas de reunión) para planificación cuando facilite la conversación.
    5. Reducir a lo estrictamente necesario el tiempo en la herramienta: estados automáticos desde CI, notificaciones puntuales y un único punto de verdad para auditoría si es imprescindible.

    La idea no es eliminar el registro, sino desplazar el esfuerzo desde actualizar la herramienta hacia crear software y automatizar su verificación.

    Ejemplos

    Ejemplo práctico: cuando aparece un defecto, lo ideal es convertirlo en un caso de prueba reproducible y añadirlo a la suite de regresión automatizada en lugar de gestionarlo como un ticket administrativo prolongado.

    # Instalar dependencias
    npm ci
    # Ejecutar suite E2E (local o en CI)
    npm run test:e2e -- --grep "nombre_del_caso"
    # Si el caso reproduce el defecto, convertirlo en test y versionarlo
    git add tests/e2e/replicated-test.spec.js
    git commit -m "Añadir test reproducible para defecto XYZ"
    git push
    Lenguaje del código: Bash (bash)

    Ese flujo garantiza que el defecto quede registrado como prueba automatizada que previene regresiones futuras, y evita ciclos de vida largos en la herramienta de gestión.

    Checklist

    1. ¿El equipo escribe pruebas que reproduzcan defectos antes de crear tickets extensos?
    2. ¿Se usan reuniones cortas para aclarar requisitos en vez de hilos largos en la herramienta?
    3. ¿La CI ejecuta la suite de regresión y actualiza estados automáticamente cuando procede?
    4. ¿Hay un proceso mínimo para auditoría cuando el registro formal es necesario?

    Si la respuesta a la mayoría de estos items es sí, el equipo está listo para minimizar su dependencia de una herramienta de gestión.

    Conclusión

    Poner la herramienta en el centro del proceso no equivale a hacer Agile. Reducir el tiempo que el equipo pasa en herramientas como Jira libera recursos para construir, probar y entregar software con más frecuencia. La vía práctica es reforzar comunicación directa, usar artefactos ligeros y priorizar la automatización que capture y prevenga defectos.

  • Variables, tipos y arrays en PHP: conceptos esenciales

    Variables, tipos y arrays en PHP: conceptos esenciales

    Breve guía práctica sobre variables, tipos de datos y arrays en PHP. Incluye ejemplos de sintaxis, comprobación de tipos y patrones comunes para manipular arrays.

    Apunta a desarrolladores que ya conocen lo básico de PHP y quieren reforzar conceptos clave para construir aplicaciones dinámicas.

    Introducción

    Variables, tipos de datos y arrays son la base de cualquier programa en PHP: almacenan y organizan la información que tu aplicación procesa. Aquí verás reglas sintácticas, herramientas de depuración y patrones prácticos para trabajar con datos.

    Prerrequisitos

    Se asume que dispones de un entorno con PHP instalado y acceso para ejecutar scripts (CLI o servidor). Si no, configura un entorno local antes de probar los ejemplos.

    Desarrollo

    Variables y sintaxis

    En PHP las variables comienzan con $ y distinguen mayúsculas de minúsculas. Deben iniciar con una letra o guion bajo. Ejemplo básico:

    <?php
    $name = "Nikul";
    $age = 25;
    
    echo "Hello, my name is $name and I am $age years old.";
    ?>
    Lenguaje del código: PHP (php)

    Tipos de datos y comprobación

    PHP es de tipado dinámico: el tipo se determina en tiempo de ejecución. Para depurar y comprobar tipos se usan funciones como var_dump() y gettype().

    <?php
    $name = "Nikul";
    $age = 25;
    
    var_dump($name); // muestra tipo y valor
    echo gettype($age); // muestra "integer"
    ?>
    Lenguaje del código: PHP (php)

    Operadores y conversión

    Usa operadores aritméticos, lógicos y de comparación según necesites. Para forzar tipos existen casts explícitos (por ejemplo (int), (string)).

    Ejemplos

    Arrays indexados

    Los arrays indexados almacenan valores accesibles por índice numérico. Ejemplo y acceso al primer elemento:

    <?php
    $colors = ["red", "green", "blue"];
    echo $colors[0]; // red
    ?>
    Lenguaje del código: PHP (php)

    Arrays asociativos

    Los arrays asociativos usan claves legibles para modelar objetos simples (por ejemplo, un usuario). Accede por la clave:

    <?php
    $user = [
      "name" => "Nikul",
      "age" => 25,
      "email" => "nikul@example.com"
    ];
    
    echo $user["email"]; // nikul@example.com
    ?>
    Lenguaje del código: PHP (php)

    Arrays multidimensionales

    Para estructuras tabulares o listas de objetos, usa arrays multidimensionales y accede por índices anidados:

    <?php
    $students = [
      ["name" => "Amit", "score" => 90],
      ["name" => "Sara", "score" => 85]
    ];
    
    echo $students[1]["name"]; // Sara
    ?>
    Lenguaje del código: PHP (php)

    Recorrer arrays (foreach)

    El bucle foreach es el patrón más común para iterar arrays indexados y asociativos:

    <?php
    $colors = ["red", "green", "blue"];
    foreach ($colors as $color) {
      echo $color . "\n";
    }
    
    $user = ["name" => "Nikul", "age" => 25];
    foreach ($user as $key => $value) {
      echo "$key: $value\n";
    }
    ?>
    Lenguaje del código: PHP (php)

    Checklist

    1. Usar nombres de variable claros y consistentes
    2. Verificar tipos con var_dump() o gettype() durante la depuración
    3. Preferir arrays asociativos para datos con claves significativas
    4. Evitar mezclar tipos dentro de un mismo array cuando sea crítico
    5. Usar foreach para iteraciones legibles y eficientes

    Conclusión

    Dominar variables, tipos y arrays en PHP te permitirá modelar datos correctamente y construir lógica más robusta. Practica los ejemplos y aplica la checklist en tus proyectos para evitar errores comunes.

    Próximo paso sugerido: revisar control de flujo (if, switch, loops) para combinar estructuras de datos con lógica de aplicación.

  • Agentes AI en PHP con MCP y Neuron

    Agentes AI en PHP con MCP y Neuron

    Resumen: Este artículo explica cómo integrar agentes AI escritos en PHP con servidores MCP usando el framework Neuron. Incluye requisitos, flujo de trabajo y ejemplos de código.

    Se cubre la arquitectura mínima (Host, MCP server, MCP client), cómo cargar herramientas desde un servidor MCP y ejemplos prácticos en PHP.

    Introducción

    MCP (Model Context Protocol) normaliza la exposición de APIs y herramientas para que los LLM puedan descubrir y ejecutar funciones. En lugar de implementar cada integración desde cero, un servidor MCP actúa como capa intermedia que traduce y presenta herramientas listas para LLM.

    Los modelos de lenguaje por sí solos gestionan texto; necesitan herramientas para ejecutar acciones en el mundo real.

    Prerrequisitos

    Antes de empezar necesita PHP (versión compatible con su proyecto), Composer y acceso al repositorio de Neuron. También, durante desarrollo, deberá instalar el MCP server localmente.

    composer require inspector-apm/neuron-aiLenguaje del código: Bash (bash)

    Desarrollo

    En términos prácticos MCP requiere tres componentes: un Host donde corre el agente, un MCP server que expone herramientas y un MCP client que permite al agente comunicarse con el servidor (normalmente vía stdio en implementaciones locales).

    Procedimiento

    • Instalar el MCP server en la misma máquina del agente (desarrollo y producción cuando aplique).
    • Configurar el servidor MCP y exponer las herramientas necesarias.
    • Usar Neuron y su McpConnector para descubrir y cargar herramientas en el agente.

    Neuron integra la conexión con MCP para que, cuando el agente decida ejecutar una herramienta, la petición se envíe al MCP server y el resultado vuelva al LLM como si fuera una herramienta nativa.

    Ejemplos

    Ejemplo mínimo: un agente PHP que define un proveedor de IA y sus instrucciones. Este ejemplo usa la estructura de Neuron para declarar el proveedor.

    <?php
    use NeuronAI\Agent;
    use NeuronAI\Providers\AIProviderInterface;
    use NeuronAI\Providers\Anthropic\Anthropic;
    
    class MyAgent extends Agent
    {
        public function provider(): AIProviderInterface
        {
            return new Anthropic(
                key: 'ANTHROPIC_API_KEY',
                model: 'ANTHROPIC_MODEL',
            );
        }
    
        public function instructions(): string
        {
            return "LLM system instructions.";
        }
    }
    Lenguaje del código: PHP (php)

    Agregar herramientas y conectar un MCP server con McpConnector para cargar las herramientas expuestas automáticamente. En este ejemplo se combinan las herramientas recuperadas desde un servidor MCP con herramientas personalizadas.

    <?php
    use NeuronAI\Agent;
    use NeuronAI\Providers\AIProviderInterface;
    use NeuronAI\Providers\Anthropic\Anthropic;
    use NeuronAI\Tools\Tool;
    use NeuronAI\Tools\ToolProperty;
    
    class MyAgent extends Agent
    {
        public function provider(): AIProviderInterface
        {
            return new Anthropic(
                key: 'ANTHROPIC_API_KEY',
                model: 'ANTHROPIC_MODEL',
            );
        }
    
        public function instructions(): string
        {
            return "LLM system instructions.";
        }
    
        public function tools(): array
        {
            return [
               // Cargar herramientas desde un MCP server
               ...McpConnector::make([
                    'command' => 'npx',
                    'args' => ['-y', '@modelcontextprotocol/server-everything'],
                ])->tools(),
      
                // Herramienta personalizada
                Tool::make(
                    "get_article_content", 
                    "Use the ID of the article to get its content."
                )->addProperty(
                    new ToolProperty(
                        name: 'article_id',
                        type: 'integer',
                        description: 'The ID  of the article you want to analyze.',
                        required: true
                    )
                )->setCallable(function (string $article_id) {
                    // Use su capa de datos aquí
                    global $pdo;
                    $stmt = $pdo->prepare("SELECT * FROM articles WHERE id=? LIMIT 1");
                    $stmt->execute([$article_id]);
                    return json_encode(
                        $stmt->fetch(PDO::FETCH_ASSOC)
                    );
                })
            ];
        }
    }
    Lenguaje del código: PHP (php)

    Puede encontrar más ejemplos y una sección de instalación en la documentación oficial: https://docs.neuron-ai.dev/installation

    Checklist

    1. Instalar Neuron via Composer en el proyecto.
    2. Instalar y configurar el MCP server localmente (desarrollo).
    3. Usar McpConnector para descubrir y cargar herramientas automáticamente.
    4. Definir herramientas personalizadas que usen las APIs internas (DB, servicios externos).
    5. Probar el flujo: agente decide, ejecuta herramienta en MCP, recibe resultado y continúa la resolución.

    Conclusión

    MCP facilita exponer herramientas listas para LLM y reduce la complejidad de integrar múltiples servicios. Con Neuron en PHP puede aprovechar MCP para crear agentes capaces de ejecutar acciones complejas sin replicar integraciones desde cero.

    Empiece instalando Neuron, ponga en marcha un MCP server local y use McpConnector para acelerar la integración de herramientas en sus agentes.

  • Laravel HelperBox: 600+ helpers listos para producción

    Laravel HelperBox: 600+ helpers listos para producción

    Laravel HelperBox reúne 600+ helpers listos para producción que reducen boilerplate, detectan N+1, agregan caching con jitter y simplifican clientes HTTP.

    Introducción

    Muchas aplicaciones Laravel invierten tiempo en funciones utilitarias repetitivas. HelperBox consolida 600+ helpers probados en producción para acelerar el desarrollo y reducir errores comunes.

    Prerrequisitos

    Compatibilidad mencionada: Laravel 9–12 y PHP 8.0+. La instalación es rápida vía Composer y la librería se auto-descubre.

    composer require subhashladumor/laravel-helperbox
    php artisan tinker  # Test: array_flatten_recursive()Lenguaje del código: Bash (bash)

    Desarrollo

    En esta sección se describen los pasos recomendados para integrar y validar los helpers en un proyecto existente.

    Procedimiento

    1. Instalar el paquete con Composer.
    2. Probar funciones críticas en Tinker o tests unitarios.
    3. Validar detección de N+1, configuraciones de cache y clientes HTTP en entornos de staging.
    4. Desplegar con monitoreo y rollback rápido si aparece un problema.

    Ejemplos

    Fragmentos de uso reales para los helpers más relevantes. Copia y adapta según tu contexto.

    <?php
    // Detectar N+1 en una consulta Eloquent
    $issues = db_detect_n_plus_one(
        Order::query(),
        ['customer', 'items', 'payments']
    );
    
    // Ejemplo de salida simplificada
    [
        'n_plus_one_detected' => true,
        'relation' => 'items',
        'estimated_queries' => 1500,
        'fix_suggestion' => "Use with('items')"
    ]Lenguaje del código: PHP (php)
    <?php
    // Caching con jitter para evitar stampedes
    $leaderboard = cache_with_jitter(
        'global:leaderboard',
        900,   // TTL: 15min
        60,    // Jitter: ±60s
        fn() => User::leaderboard()
    );Lenguaje del código: PHP (php)
    <?php
    // Clientes HTTP de producción (JSON)
    $repos = http_get_json('https://api.github.com/users/laravel/repos');
    
    // Subir archivos sin boilerplate
    http_post_formdata($uploadUrl, [
        'file' => $request->file('avatar'),
        'user_id' => $user->id,
    ]);Lenguaje del código: PHP (php)
    <?php
    // Ejemplos rápidos en Tinker
    array_flatten_recursive([[1,[2,[3,4]]],5]);
    // >> [1, 2, 3, 4, 5]
    
    str_slugify('  Café with Résumé?  ');
    // >> "cafe-with-resume"Lenguaje del código: PHP (php)

    Checklist

    • Confirmar instalación y auto-discovery del ServiceProvider.
    • Ejecutar tests unitarios que cubran los helpers usados.
    • Validar detección de N+1 y aplicar with() cuando sea necesario.
    • Configurar TTL y jitter en caches críticos.
    • Revisar licencia MIT y compatibilidad del proyecto.

    Conclusión

    Laravel HelperBox ofrece una colección práctica de helpers que pueden reducir horas de trabajo repetitivo y mitigar problemas comunes como N+1 o stampedes de cache. Integrarlo con pruebas y validación en staging maximiza su beneficio.