Translate

sábado, 4 de abril de 2026

¿Cual es el estado de los lenguajes que corren sobre la plataforma Java?



La plataforma Java no es solo el lenguaje Java. Gracias a la JVM (Java Virtual Machine), es posible ejecutar múltiples lenguajes con distintos paradigmas y objetivos.

A continuación, un resumen breve de los más relevantes:


Java

Objetivo: Lenguaje generalista, orientado a objetos.

Uso típico: Backend, enterprise, Android (históricamente).

Estado: Activo y en constante evolución (LTS recientes, mejoras funcionales).


Kotlin

Objetivo: Alternativa moderna a Java, más concisa y segura.

Uso típico: Android, backend, multiplataforma.

Estado:  Muy activo, impulsado por JetBrains y adoptado oficialmente por Google.


Scala

Objetivo: Mezclar programación funcional y orientada a objetos.

Uso típico: Big Data, sistemas distribuidos.

Estado: Activo, pero con menor adopción reciente frente a Kotlin.


Groovy

Objetivo: Lenguaje dinámico para simplificar Java.

Uso típico: Scripts, testing, herramientas como Gradle.

Estado:  Estable, pero en segundo plano.


Clojure

Objetivo: Programación funcional pura (Lisp en la JVM).

Uso típico: Sistemas concurrentes, data processing.

Estado: Activo en nichos específicos.


Jython

Objetivo: Implementación de Python sobre la JVM.

Uso típico: Integración con ecosistema Java.

Estado: Limitado (sin soporte moderno de Python 3 completo).


JRuby

Objetivo: Ejecutar Ruby en la JVM.

Uso típico: Integración con sistemas Java.

Estado: Activo, pero nicho.


Frege

Objetivo: Lenguaje funcional inspirado en Haskell.

Uso típico: Académico / experimental.

Estado: Poco activo.


Eta

Objetivo: Llevar Haskell a la JVM.

Uso típico: Funcional puro sobre JVM.

Estado: Proyecto prácticamente detenido.


 JavaScript (GraalVM)

Objetivo: Ejecutar JavaScript en la JVM mediante GraalVM.

Uso típico: Polyglot, microservicios, scripting.

Estado:  Activo y en crecimiento.


Python (GraalVM)

Objetivo: Ejecutar Python sobre la JVM con GraalVM.

Uso típico: Integración polyglot.

Estado:  Experimental.


La JVM es en una plataforma polyglot, donde distintos lenguajes conviven según la necesidad.

Cursos Gugler: Inscripciones para el primer cuatrimestre del año 2026

Se encuentran abiertas las inscripciones para el primer cuatrimestre del año 2026, para todas las capacitaciones dictadas por el Laboratorio de Investigación Gugler. Podés asegurar tu lugar en el curso y comisión que desees !!!.

Las clases inician:

  • Lunes 06/04 , Jueves 09/04 o Sábado 11/04, según el curso que elegiste.

Podés inscribirte utilizando el siguiente enlace: INSCRIBIRME

Cursos, horarios y comisiones disponiblesINFO CURSOS






jueves, 2 de abril de 2026

DORA 2025: mejora el rendimiento de tu equipo con la IA

 

Estado actual de Roslyn (.NET Compiler Platform)


Roslyn es la plataforma de compilación de .NET que provee compiladores para C# y VB.NET, junto con APIs para análisis de código, generación y tooling.


Roslyn no es solo un compilador, sino una plataforma como servicio:

  • Compilación de código (C#, VB.NET)
  • Análisis estático (analyzers)
  • Refactorizaciones
  • Generación de código (source generators)
  • Base de herramientas como Visual Studio y OmniSharp


Antes de Roslyn, los compiladores eran “cajas negras”, pero con Roslyn:

  • El código se representa como árboles de sintaxis (Syntax Trees)
  • Podés inspeccionar y modificar código en tiempo de compilación
  • Todo está expuesto como API


Esto habilita cosas como:

  • linters avanzados
  • refactorizaciones automáticas
  • generación de código en compile-time


Estado actual (2026)

  • Totalmente activo y mantenido por Microsoft
  • Evoluciona junto con C# (últimas versiones como C# 12/13)
  • Fuerte adopción en tooling moderno (.NET CLI, IDEs, analyzers)
  • Ecosistema maduro de analyzers y source generators


Tendencias actuales

Source Generators cada vez más usados

  → reemplazando reflexión en muchos casos


Incremental Generators

  → mejor performance y menos recompilaciones


Mayor uso en:

  • validaciones en compile-time
  • frameworks
  • librerías de alto rendimiento


Roslyn hoy es:

  • el corazón del ecosistema .NET moderno
  • una plataforma estable y madura
  • clave para tooling avanzado y metaprogramación



GraalVM vs GraalOS vs Containers vs Unikernels


En los últimos años aparecieron múltiples formas de ejecutar aplicaciones:

  • GraalVM
  • GraalOS
  • Containers como Docker
  • Y el concepto de Unikernel


Todas apuntan a lo mismo: Ejecutar software de forma más eficiente, portable y segura

Pero no compiten exactamente en el mismo nivel


Antes de comparar, entendamos esto:


| Tecnología | Nivel                          |

| ---------- | ------------------------------ |

| GraalVM    | Runtime / compilación          |

| GraalOS    | Sistema operativo experimental |

| Containers | Empaquetado y ejecución        |

| Unikernels | Arquitectura de sistema        |


Un error común es compararlas como si fueran alternativas directas. En realidad, muchas se pueden combinar.


GraalVM es un runtime avanzado que permite:

  • Ejecutar múltiples lenguajes
  • Compilar a binarios nativos (Native Image)


Ventajas

  • Arranque ultrarrápido
  • Menor consumo de memoria
  • Ideal para microservicios


Limitaciones

  • Problemas con reflection Complejidad operativa



GraalOS intenta combinar:

GraalVM + filosofía unikernel


Es decir:

  • Apps compiladas como native image
  • Ejecutándose sobre un OS mínimo


Estado actual:

  • Experimental
  • Sin adopción masiva
  • Poco foco en los últimos años


Hoy el mundo real es claro:

  • Docker domina el deploy
  • GraalVM optimiza ejecución
  • Unikernel es prometedor pero nicho
  • GraalOS es más idea que realidad :(


miércoles, 1 de abril de 2026

Rendimiento de Consola: Linux vs Windows (¿realmente uno es más rápido?)


Hace poco me encontré con un comportamiento curioso ejecutando el siguiente código en Java:


var lista = new LinkedList<Long>();

for (var i = 0L; i < Long.MAX_VALUE; i++) {

    System.out.println(i);

    lista.add(i);

}


En Linux corría muchísimo más rápido que en Windows.


La primera reacción fue: ¿La JVM es más rápida en Linux?

Pero la respuesta es: no necesariamente.


El problema no está en Java ni en la lógica del programa. Está en: System.out.println(i);


Cada println implica:

  • Sincronización interna (thread-safe)
  • Conversión a string
  • Llamada al sistema operativo (I/O)
  • Escritura en la consola


Windows (cmd / PowerShell)

  • Consola históricamente más lenta
  • Mayor overhead en escritura
  • Menor eficiencia en buffering
  • Renderizado de texto menos optimizado


🐧 Linux (terminal)

  • Mejor manejo de buffers
  • I/O más eficiente
  • Consolas más livianas (bash, zsh, tty)
  • Mejor throughput de escritura


Si sacamos el println anda muy rápido :


var lista = new LinkedList<Long>();

for (var i = 0L; i < 10_000_000; i++) {

    lista.add(i);

}


El cuello de botella era la consola, no el sistema operativo.


Como lecciones importantes tengo :

  1. Nunca midas performance con println
  2. El I/O domina el rendimiento
  3. No culpes al lenguaje o al OS sin aislar variables
  4. Linux suele tener mejor rendimiento de consola



sábado, 28 de marzo de 2026

GraalOS ¿qué es y en qué estado está?


Si venís siguiendo GraalVM, probablemente escuchaste hablar de GraalOS.


La idea suena ambiciosa. Un sistema operativo optimizado para correr aplicaciones compiladas con GraalVM.

Pero… ¿es algo real hoy? ¿o sigue siendo experimental?


GraalOS es un concepto/proyecto que busca ejecutar aplicaciones native image directamente sobre un sistema mínimo.


Sin necesidad de:

  • JVM tradicional
  • Sistema operativo generalista


En esencia:

  • Llevar la idea de GraalVM al extremo:
  • una app = un runtime + un OS mínimo

GraalOS está muy relacionado con el concepto de Unikernel


Un unikernel:

  • Incluye solo lo necesario para una app
  • Corre directamente sobre el hypervisor
  • Reduce overhead y superficie de ataque


Pero, pero, GraalOS no es un producto maduro ni ampliamente disponible


En los últimos años:

  • No tuvo adopción masiva
  • No hay releases estables mainstream
  • No forma parte del flujo típico de GraalVM


En la práctica es más un concepto exploratorio / investigación que una herramienta de uso diario.

Mientras GraalVM avanzó mucho, GraalOS perdió protagonismo :(


En lugar de GraalOS, crecieron:

  • Containers (Docker)
  • Orquestación (Kubernetes)
  • Serverless

La industria resolvió el problema con otra abstracción


Hoy usarías antes:

  • Un container liviano
  • Un binary con GraalVM Native Image
  • Kubernetes o serverless


Antes que meterte en algo como GraalOS. GraalOS es más una idea interesante que una herramienta práctica.

¿En que anda GraalVM?


GraalVM es uno de los proyectos más interesantes del ecosistema Java. Permite ejecutar múltiples lenguajes (Java, JavaScript, Python, etc.) y, sobre todo, compilar aplicaciones a binarios nativos mediante Native Image.

En los últimos años, el proyecto evolucionó bastante — no tanto en hype, sino en madurez real. Además, hubo cambios importantes en cómo se distribuye y licencia.


Uno de los cambios más importantes: Gran parte de GraalVM se integró más profundamente con OpenJDK

  • El compilador Graal JIT ya no es algo “externo raro”
  • Se volvió más estándar dentro del ecosistema Java
  • Mejor compatibilidad con versiones recientes del JDK (17, 21, 23)


En otras palabras:

  • Antes GraalVM era “algo aparte”.
  • Hoy está mucho más alineado con el stack oficial de Java.


La feature estrella sigue siendo:

  • Ahead-of-Time compilation (AOT)
  • Genera binarios nativos sin JVM
  • Arranque ultra rápido
  • Bajo consumo de memoria


En estos años mejoró muchísimo:

  • Mejor soporte para frameworks (Spring, Micronaut, Quarkus)
  • Menos configuración manual
  • Mejor manejo de reflection
  • Debugging menos doloroso


Especialmente con:

  • Spring Boot + AOT
  • Quarkus (que sigue siendo el más “native-first”)


Cambio clave: licencias y distribución. Acá está el punto más importante del post 

Antes existían dos ediciones:

  •   Community Edition (open source)
  •   Enterprise Edition (mejoras pagas)


Ahora (últimos años) oracle reorganizó todo:

GraalVM Community

  • Basado en OpenJDK
  • Licencia: GPL (con classpath exception)
  • Sigue siendo gratis y open source


GraalVM Oracle (antes Enterprise)

  • Parte del ecosistema comercial de Oracle
  • Incluye optimizaciones avanzadas
  • Integrado con Oracle JDK


Y esto está más alineado con el modelo de licencias de Oracle Java.


Bueno pero, ¿GraalVM ahora es pago?”

La respuesta corta:

  • No, la versión Community sigue siendo gratis
  • Pero algunas features avanzadas están en el ecosistema comercial


Y algo que no me gusta es que Polyglot tiene menos hype y es más de nicho. 

GraalVM nació con la idea de: “Un runtime para múltiples lenguajes”


Soporta:

  • Java
  • JavaScript
  • Python
  • Ruby
  • WebAssembly


Pero, no se usa mucho, creo que es una tendencia general en la industria. 


En estos años se vio algo interesante que hubo menos marketing, más uso concreto


Casos típicos:

  • Microservicios con arranque rápido
  • Serverless
  • Apps en contenedores (menos RAM)


La pregunta del millon ¿Vale la pena hoy? Sí, si:

  • Querés arranque rápido
  • Buscás bajo consumo de memoria
  • Usás frameworks compatibles
  • Estás en cloud / Kubernetes


No tanto si:

  • Usás mucha reflexión dinámica
  • Dependés de librerías complejas
  • Querés “zero config”

Mi opinión es que GraalVM es un producto real, que todos tendríamos que conocer y usar. Si tenés una aplicación en Java y en el cloud, no cuesta nada probar migrar a GraalVM y medir su performance, ya sea usando Graal Jit o binarios nativos. 

martes, 24 de marzo de 2026

Consumir una API en Google Sheets


Con Google Sheets y Google Apps Script podés crear funciones personalizadas que consuman APIs externas.

En este ejemplo vamos a obtener el valor del dólar oficial desde: https://dolarapi.com/v1/dolares/oficial

Crear la función:

1. Ir a Extensiones → Apps Script

2. Crear la siguiente función:


function DOLAR_OFICIAL() {

  var url = "https://dolarapi.com/v1/dolares/oficial";

  

  var response = UrlFetchApp.fetch(url);

  var data = JSON.parse(response.getContentText());

  

  return data.venta;

}


Cómo usarla en la hoja:


En cualquier celda:

=DOLAR_OFICIAL()


¿Qué está pasando?

UrlFetchApp.fetch(url) → hace la llamada HTTP

JSON.parse(...) → convierte la respuesta a objeto

data.venta → accede al valor de venta del dólar


Podemos devolver más datos (compra y venta):


function DOLAR_OFICIAL_COMPLETO() {

  var url = "https://dolarapi.com/v1/dolares/oficial";

  

  var response = UrlFetchApp.fetch(url);

  var data = JSON.parse(response.getContentText());

  

  return [

    ["Compra", "Venta"],

    [data.compra, data.venta]

  ];

}


Uso:

=DOLAR_OFICIAL_COMPLETO()


Esto va a llenar dos columnas automáticamente.


Funciones personalizadas en Google Sheets con Apps Script



Google Sheets permite crear funciones personalizadas usando Google Apps Script, que luego podés usar como si fueran fórmulas nativas (tipo `SUM` o `VLOOKUP`).


Una función personalizada es una función en JavaScript que:

  • Recibe parámetros desde una celda
  • Procesa datos
  • Devuelve un resultado que se muestra en la hoja


Cómo crear una función:

1. Abrí tu hoja en Google Sheets

2. Ir a Extensiones → Apps Script

3. Escribí tu función

4. Guardá el proyecto


Veamos un ejemplo: 

Creamos una función que reciba un nombre y devuelva `"Hola " + nombre`:


function SALUDAR(nombre) {

  return "Hola " + nombre;

}


Cómo usarla?


En cualquier celda escribís:


=SALUDAR("Emanuel")


Resultado:

Hola Emanuel


También podés usar una celda como parámetro:

=SALUDAR(A1)


Nota que: 

  • El nombre de la función suele escribirse en mayúsculas (convención)
  • Debe devolver un valor (string, número, array, etc.)
  • No puede modificar otras celdas directamente (solo retornar valores)
  • Se recalcula cuando cambian los datos


Veamos otro ejemplo: 

Una función que saluda a múltiples nombres:


function SALUDAR_VARIOS(nombres) {

  return nombres.map(n => "Hola " + n);

}



Uso:

=SALUDAR_VARIOS(A1:A3)



Resultado:

Hola Juan

Hola Ana

Hola Pedro


Ideas para usar funciones personalizadas

  • Validaciones complejas
  • Transformación de datos
  • Integración con APIs (clima, cotizaciones, etc.)
  • Automatización de reportes

lunes, 23 de marzo de 2026

Elementos personalizados en Elm




Los navegadores parecen estar admitiendo cada vez más elementos personalizados, lo cual resulta muy útil para integrar JavaScript en programas Elm.

Veamos un ejemplo mínimo de cómo usar elementos personalizados para la localización e internacionalización.

Supongamos que queremos localizar fechas, pero esta funcionalidad aún no está disponible en los paquetes principales de Elm. Quizás quieran escribir una función que localice las fechas:


//

//   localizeDate('sr-RS', 12, 5) === "петак, 1. јун 2012."

//   localizeDate('en-GB', 12, 5) === "Friday, 1 June 2012"

//   localizeDate('en-US', 12, 5) === "Friday, June 1, 2012"

//

function localizeDate(lang, year, month)

{

    const dateTimeFormat = new Intl.DateTimeFormat(lang, {

        weekday: 'long',

        year: 'numeric',

        month: 'long',

        day: 'numeric'

    });


    return dateTimeFormat.format(new Date(year, month));

}


Pero, ¿cómo usamos eso en Elm? Los navegadores más recientes permiten crear nuevos tipos de nodos DOM como este:


//

//   <intl-date lang="sr-RS" year="2012" month="5">

//   <intl-date lang="en-GB" year="2012" month="5">

//   <intl-date lang="en-US" year="2012" month="5">

//

customElements.define('intl-date',

    class extends HTMLElement {

        // things required by Custom Elements

        constructor() { super(); }

        connectedCallback() { this.setTextContent(); }

        attributeChangedCallback() { this.setTextContent(); }

        static get observedAttributes() { return ['lang','year','month']; }


        // Our function to set the textContent based on attributes.

        setTextContent()

        {

            const lang = this.getAttribute('lang');

            const year = this.getAttribute('year');

            const month = this.getAttribute('month');

            this.textContent = localizeDate(lang, year, month);

        }

    }

);


Las partes más importantes aquí son attributeChangedCallback y observedAttributes. Necesitas una lógica similar para detectar los cambios en los atributos que te interesan.

Cárgala antes de inicializar tu código Elm y podrás escribir código como este:


import Html exposing (Html, node)

import Html.Attributes (attribute)


viewDate : String -> Int -> Int -> Html msg

viewDate lang year month =

  node "intl-date"

    [ attribute "lang" lang

    , attribute "year" (String.fromInt year)

    , attribute "month" (String.fromInt month)

    ]

    []


Ahora puedes llamar a viewDate cuando necesites acceder a ese tipo de información localizada en tu vista.


domingo, 22 de marzo de 2026

Apps Script en Google Docs


Este post es nada que ver con este blog, pero Apps Script me ha salvado tanto que sería malísimo no compartirlo. 

Google Docs no solo sirve para escribir documentos: también permite automatizar tareas mediante scripts usando Google Apps Script.

Esto te permite agregar lógica personalizada, generar contenido dinámico o incluso integrar servicios externos.

Apps Script es una plataforma basada en JavaScript que corre en la nube y permite extender herramientas como:

  • Google Docs
  • Google Sheets
  • Google Drive
  • Gmail


En el caso de Google Docs, podemos crear funciones que modifiquen el documento o generen contenido automáticamente.


1. Abrí un documento en Google Docs

2. Ir a Extensiones → Apps Script

3. Se abrirá el editor de scripts

4. Escribí tu función y guardá


Vamos a crear una función que reciba un nombre y retorne "Hola " + nombre.


function saludar(nombre) {

  return "Hola " + nombre;

}


A diferencia de Google Sheets, en Docs no podés invocar funciones directamente en el texto como fórmulas. Pero podés:

  • Ejecutarla desde el editor
  • O usarla para insertar contenido en el documento


Por ejemplo, una versión que escribe directamente en el documento:


function insertarSaludo() {

  var doc = DocumentApp.getActiveDocument();

  var body = doc.getBody();

  

  var nombre = "Emanuel";

  var saludo = "Hola " + nombre;

  

  body.appendParagraph(saludo);

}


Podés combinar esto con menús personalizados para ejecutar funciones desde la UI del documento.


function onOpen() {

  DocumentApp.getUi()

    .createMenu('Mis Scripts')

    .addItem('Insertar saludo', 'insertarSaludo')

    .addToUi();

}


Es ideal para: 

  • Generar reportes automáticamente
  • Insertar firmas o textos repetitivos
  • Crear plantillas dinámicas
  • Integrar con APIs externas



miércoles, 18 de marzo de 2026

Puertos en Elm

 


Los puertos permiten la comunicación entre Elm y JavaScript.

Los puertos se utilizan con mayor frecuencia para WebSockets y localStorage. Centrémonos en el ejemplo de WebSockets.

Aquí tenemos prácticamente el mismo HTML que hemos usado en las páginas anteriores, pero con un poco de código JavaScript adicional. Creamos una conexión a wss://echo.websocket.org que simplemente repite lo que le enviamos.

<!DOCTYPE HTML>

<html>


<head>

  <meta charset="UTF-8">

  <title>Elm + Websockets</title>

  <script type="text/javascript" src="elm.js"></script>

</head>


<body>

    <div id="myapp"></div>

</body>


<script type="text/javascript">


// Start the Elm application.

var app = Elm.Main.init({

    node: document.getElementById('myapp')

});


// Create your WebSocket.

var socket = new WebSocket('wss://echo.websocket.org');


// When a command goes to the `sendMessage` port, we pass the message

// along to the WebSocket.

app.ports.sendMessage.subscribe(function(message) {

    socket.send(message);

});


// When a message comes into our WebSocket, we pass the message along

// to the `messageReceiver` port.

socket.addEventListener("message", function(event) {

    app.ports.messageReceiver.send(event.data);

});


// If you want to use a JavaScript library to manage your WebSocket

// connection, replace the code in JS with the alternate implementation.

</script>


</html>


Llamamos a Elm.Main.init() como en todos nuestros ejemplos de interoperabilidad, pero esta vez estamos usando el objeto app resultante. Nos suscribimos al puerto sendMessage y enviamos mensajes al puerto messageReceiver.


Observa las líneas que utilizan la palabra clave port en el archivo Elm correspondiente. Así es como definimos los puertos que acabamos de ver en JavaScript.

port module Main exposing (..)


import Browser

import Html exposing (..)

import Html.Attributes exposing (..)

import Html.Events exposing (..)

import Json.Decode as D




-- MAIN



main : Program () Model Msg

main =

  Browser.element

    { init = init

    , view = view

    , update = update

    , subscriptions = subscriptions

    }





-- PORTS



port sendMessage : String -> Cmd msg

port messageReceiver : (String -> msg) -> Sub msg




-- MODEL



type alias Model =

  { draft : String

  , messages : List String

  }



init : () -> ( Model, Cmd Msg )

init flags =

  ( { draft = "", messages = [] }

  , Cmd.none

  )




-- UPDATE



type Msg

  = DraftChanged String

  | Send

  | Recv String



-- Use the `sendMessage` port when someone presses ENTER or clicks

-- the "Send" button. Check out index.html to see the corresponding

-- JS where this is piped into a WebSocket.

--

update : Msg -> Model -> ( Model, Cmd Msg )

update msg model =

  case msg of

    DraftChanged draft ->

      ( { model | draft = draft }

      , Cmd.none

      )


    Send ->

      ( { model | draft = "" }

      , sendMessage model.draft

      )


    Recv message ->

      ( { model | messages = model.messages ++ [message] }

      , Cmd.none

      )




-- SUBSCRIPTIONS



-- Subscribe to the `messageReceiver` port to hear about messages coming in

-- from JS. Check out the index.html file to see how this is hooked up to a

-- WebSocket.

--

subscriptions : Model -> Sub Msg

subscriptions _ =

  messageReceiver Recv




-- VIEW



view : Model -> Html Msg

view model =

  div []

    [ h1 [] [ text "Echo Chat" ]

    , ul []

        (List.map (\msg -> li [] [ text msg ]) model.messages)

    , input

        [ type_ "text"

        , placeholder "Draft"

        , onInput DraftChanged

        , on "keydown" (ifIsEnter Send)

        , value model.draft

        ]

        []

    , button [ onClick Send ] [ text "Send" ]

    ]




-- DETECT ENTER



ifIsEnter : msg -> D.Decoder msg

ifIsEnter msg =

  D.field "key" D.string

    |> D.andThen (\key -> if key == "Enter" then D.succeed msg else D.fail "some other key"


Fíjate que la primera línea dice "port module" en lugar de simplemente "module". Esto permite definir puertos dentro de un módulo. El compilador ofrece una pista si es necesario, ¡así que esperemos que nadie se quede atascado en esto!


Bien, ¿pero qué ocurre con las declaraciones de puerto para sendMessage y messageReceiver?

La declaración sendMessage nos permite enviar mensajes desde Elm.

port sendMessage: String -> Cmd msg

Aquí declaramos que queremos enviar valores de tipo String, pero podríamos enviar cualquier tipo que funcione con indicadores. 

A partir de ahí, podemos usar sendMessage como cualquier otra función. Si tu función de actualización genera un comando sendMessage "hello", lo recibirás en JavaScript:


app.ports.sendMessage.subscribe(function(message) {

socket.send(message);

});


Este código JavaScript se suscribe a todos los mensajes salientes. Puedes suscribir varias funciones y cancelar suscripciones por referencia, pero generalmente recomendamos mantener la configuración estática.

También recomendamos enviar mensajes más completos, en lugar de crear múltiples puertos individuales. Esto podría implicar tener un tipo personalizado en Elm que represente todo lo que necesites comunicar a JavaScript, y luego usar Json.Encode para enviarlo a una única suscripción de JavaScript. Muchos consideran que esto crea una separación de responsabilidades más clara. El código de Elm gestiona claramente parte del estado, y JavaScript gestiona otra parte.


La declaración messageReceiver nos permite escuchar los mensajes que llegan a Elm.


messageReceiver: (String -> msg) -> Sub msg


Estamos indicando que vamos a recibir valores de tipo String, pero también podemos escuchar cualquier tipo que pueda llegar a través de indicadores o puertos de salida. Simplemente reemplazamos el tipo String por uno de los tipos que pueden cruzar el límite.


Podemos usar messageReceiver como cualquier otra función. En nuestro caso, llamamos a messageReceiverRecv al definir nuestras suscripciones porque queremos recibir mensajes entrantes de JavaScript. Esto nos permitirá recibir mensajes como Recv "¿cómo estás?"` en nuestra función de actualización.


En JavaScript, podemos enviar datos a este puerto cuando queramos:


socket.addEventListener("message", function(event) {

    app.ports.messageReceiver.send(event.data);

});


En este caso, enviamos mensajes cada vez que el websocket recibe uno, pero también se pueden enviar en otros momentos. Quizás también estemos recibiendo mensajes de otra fuente de datos. Está bien, ¡y Elm no necesita saber nada al respecto! Simplemente envía las cadenas a través del puerto correspondiente.


Los puertos sirven para establecer límites claros. Definitivamente, no intentes crear un puerto para cada función de JavaScript que necesites. Puede que te guste mucho Elm y quieras hacerlo todo con él, cueste lo que cueste, pero los puertos no están diseñados para eso. En su lugar, concéntrate en preguntas como "¿quién controla el estado?" y usa uno o dos puertos para enviar y recibir mensajes. Si te encuentras en un escenario complejo, incluso puedes simular valores de Msg enviando JavaScript como `{ tag: "active-users-changed", list: ... }`, donde tienes una etiqueta para cada variante de información que podrías enviar.


Aquí tienes algunas pautas sencillas y errores comunes:


Se recomienda enviar `Json.Encode.Value` a través de puertos. Al igual que con las banderas, ciertos tipos básicos también pueden pasar a través de puertos. Esto es de la época anterior a los decodificadores JSON, y puedes leer más al respecto aquí.


Todas las declaraciones de puertos deben aparecer en un módulo de puerto. Probablemente sea mejor organizar todos los puertos en un solo módulo para que la interfaz sea más fácil de visualizar en un solo lugar.


Los puertos son para aplicaciones. Un módulo de puerto está disponible en las aplicaciones, pero no en los paquetes. Esto garantiza que los desarrolladores de aplicaciones tengan la flexibilidad que necesitan, pero el ecosistema de paquetes está completamente escrito en Elm. Creemos que esto creará un ecosistema y una comunidad más sólidos a largo plazo, y analizaremos las ventajas y desventajas en profundidad en la siguiente sección sobre los límites de la interoperabilidad entre Elm y JavaScript.


Los puertos pueden eliminarse como código muerto. Elm tiene un sistema de eliminación de código muerto bastante agresivo y eliminará los puertos que no se utilicen dentro del código Elm. El compilador desconoce lo que sucede en JavaScript, así que intente conectar las cosas en Elm antes que en JavaScript.


jueves, 12 de marzo de 2026

Fragmentación de índices en oracle


En Oracle Database la fragmentación de índices ocurre por la forma en que Oracle administra internamente las estructuras B-tree. Entender esto requiere mirar cómo se organizan los índices y cómo cambian con el tiempo.

1. Cómo está estructurado un índice en Oracle

La mayoría de los índices en Oracle son B-tree.

Un índice B-tree está compuesto por:

Root block: punto de entrada del índice.

Branch blocks: nodos intermedios.

Leaf blocks: contienen los valores indexados y los ROWID de la tabla.


Visualmente:

        Root

       /    \

   Branch  Branch

    /  \      \

 Leaf Leaf   Leaf


Los leaf blocks están ordenados por la clave del índice.



2. Qué es la fragmentación de un índice


La fragmentación ocurre cuando los leaf blocks quedan con espacio libre o desordenados respecto al uso real del índice.


Esto suele pasar cuando:

  • se insertan registros
  • se borran registros
  • se actualizan columnas indexadas


El resultado es:

  • bloques medio vacíos
  • más bloques de los necesarios
  • más I/O al recorrer el índice


3. Cómo se fragmenta un índice

 Caso 1 — Inserts aleatorios

Supongamos un índice sobre:

cliente_id


Insertamos:

10

20

30

40

50


Los leaf blocks quedan llenos y ordenados.


Pero si luego insertamos:

25



Oracle debe dividir el bloque.


Esto se llama: block split


Ejemplo:


Antes:

[10 20 30 40 50]


Después:

[10 20 25]

[30 40 50]


Cada split genera:

  • más bloques
  • más profundidad en el árbol


Caso 2 — Deletes


Supongamos que borramos muchos registros:

DELETE FROM ventas

WHERE fecha < SYSDATE - 365;


Los bloques del índice quedan así:

[10 _ _ _]

[20 _ _ _]

[30 _ _ _]


Oracle no compacta automáticamente los bloques.


Resultado:

  • muchos bloques
  • con poco contenido


Esto es fragmentación lógica.


Caso 3 — Updates en columnas indexadas


Si actualizas una columna indexada:

UPDATE clientes

SET cliente_id = 900

WHERE cliente_id = 20;


Oracle hace internamente:


DELETE + INSERT en el índice


Esto produce nuevamente:

  • splits
  • huecos


4. Tipos de fragmentación


Fragmentación interna

Bloques con mucho espacio libre.


Ejemplo:

[10 _ _ _]


Problema:

  • se necesitan más bloques para recorrer el índice.


Fragmentación externa


Los bloques están fuera de orden físico en disco.


Esto afecta:

index range scans


Porque Oracle debe saltar más bloques.


5. Cuándo ocurre más fragmentación

Situaciones típicas: índices sobre columnas con valores aleatorios


Ejemplo:

UUID

hash

random_id


Cada insert puede generar splits y muchas eliminaciones


updates frecuentes: especialmente sobre claves indexadas.


6. Cómo saber si un índice está fragmentado


Oracle permite analizar índices:


ANALYZE INDEX idx_clientes VALIDATE STRUCTURE;


Luego consultar:


SELECT

  height,

  lf_rows,

  del_lf_rows,

  lf_blks

FROM index_stats;


Indicadores importantes:


DEL_LF_ROWS → filas eliminadas

LF_BLKS → bloques leaf


Si hay muchos DEL_LF_ROWS, puede haber fragmentación.


Otra forma:


SELECT

  index_name,

  blevel,

  leaf_blocks,

  num_rows

FROM user_indexes;


Si leaf_blocks crece mucho respecto a num_rows, puede haber fragmentación.


7. Cómo desfragmentar índices

Hay dos formas principales.


COALESCE (la más segura)


ALTER INDEX idx_clientes COALESCE;


Qué hace:

  • fusiona leaf blocks vacíos
  • no bloquea la tabla
  • no requiere espacio extra


Ventajas:

  • online
  • rápido


Limitación:

  • no reorganiza completamente el índice.


REBUILD


ALTER INDEX idx_clientes REBUILD;


Qué hace:

  • recrea completamente el índice
  • elimina fragmentación
  • reorganiza bloques


Resultado:

  • índice más compacto
  • mejor locality en disco


También existe:


ALTER INDEX idx_clientes REBUILD ONLINE;


8. ¿Hay que desfragmentar índices regularmente?


En Oracle generalmente NO. Oracle maneja bastante bien los índices.

Solo conviene hacerlo cuando:

  • muchos deletes


 ✔ índices muy grandes


ejemplo:


```

millones de registros

```


---


### ✔ degradación visible de performance


queries que antes usaban:


```

INDEX RANGE SCAN

```


y ahora son más lentas.


---

9. Caso donde casi nunca hay fragmentación


Si el índice es sobre:

ID autoincremental


los inserts siempre van al final del índice.


Ejemplo:

1

2

3

4

5


Esto produce casi cero splits.


Es el caso ideal.


10. Regla práctica en Oracle

No hagas mantenimiento automático de índices sin evidencia.


Recomendación típica de DBAs:

  • monitorear
  • usar COALESCE
  • usar REBUILD solo si es necesario


En Microsoft SQL Server la fragmentación de índices es mucho más problemática y suele requerir mantenimiento periódico.


En Oracle Database, en cambio, es mucho menos común tener que intervenir.