¿Por qué FreeBSD y no (x)BSD?

Minientrada

Por eliminación.

Elegí FreeBSD porque NVIDIA publica drivers para la ABI de FreeBSD. Lo que significa que puedo tener aceleración gráfica y tener mis pantallas con la resolución correcta en vez de usar el driver genérico xorg-vesa. No sirve de nada más porque NVENC no está disponible fuera de Windows y porque no uso FreeBSD para jugar.

Eso es todo. No soy un fanboy de FreeBSD y si mis casos de uso hubiesen sido otros tal vez hubiese ganado otro sistema operativo. Pero ganó este. Los tres sistemas son muy similares entre sí de todos modos.


Otros candidatos:

  • NetBSD: me gusta por su extremada simpleza, hecha para darle una perfecta portabilidad. El lema de NetBSD es “por supuesto que corre NetBSD”, haciendo referencia al hecho de que es posible instalarlo en muchísimas arquitecturas (incluso en Macs de principios de los años 90 o en Play Stations).
  • OpenBSD: lo admiro por su extrema seguridad, pero mis casos de uso con mi ordenador me llevan a admirarlo de lejos. OpenBSD es tan seguro que hace unos años eliminaron el soporte para Bluetooth porque es un protocolo inseguro y su driver no estaba bien mantenido.

Primera dosis

Imagen

Un cartel señala la dirección del punto de vacunación del Zendal
La única foto que he tomado, en parte porque me prometí a mi mismo que no haría la cutrez de tomarme un selfie.

Primera dosis puesta. Ha tocado Pfizer. En tres semanas a regresar, y en cinco semanas esto definitivamente se acaba.

Ha sido un año muy largo.

SQL: Suma acumulativa

Minientrada

Tengo una tabla como la siguiente:

datetime               points
2021-07-05 10:00:00    1
2021-07-05 10:05:00    1
2021-07-05 10:08:00    -1
2021-07-05 10:10:00    1
2021-07-05 10:11:00    -1

Y quiero sacar las sumas acumulativas. Es decir, no quiero sacar simplemente un SUM(points) y que me devuelva 1, sino que quiero ir viendo, para cada fila, la suma parcial de todas las filas que hay hasta llegar a esa desde el principio.

Por lo que veo en Stack Overflow, una forma universal de hacerlo aunque poco eficiente con tablas muy grandes, es utilizar INNER JOINs aplicados sobre la misma tabla que parcialmente vayan agrupando los resultados por fecha. Me hice algo como lo siguiente en mi caso usando un WITH para filtrar sólo aquellos resultados que realmente quiero sumar y así tratar de hacerlo más eficiente.

WITH points AS (
  SELECT datetime, points
    FROM data
   WHERE target_id = 12345
)
SELECT a.datetime, a.points, SUM(b.points)
  FROM points a
       INNER JOIN points b
               ON b.datetime <= a.datetime;

GitLab vs Gitea

Minientrada

No entiendo por qué GitLab se ha convertido en la implementación de referencia para alojar repositorios con funciones extras como tareas, peticiones de integración o cuentas de usuario. Es lento, dificil de utilizar, dificil de instalar… y además, es un software que se sigue llamando «libre» porque tiene una versión comunitaria, pero que vista la capa de marketing que tiene como producto, no se siente tan libre.

Y sin embargo es lo que plataformas como GNOME, Xfce o Free Desktop han instalado en los últimos años como alternativa a los clientes más duros pero simples como cgit. Una alternativa mucho más ligera que dispone de funciones web es Gitea. Una de las cosas buenas de las aplicaciones web hechas en Go es que igualmente se distribuyen como un binario que se puede arrancar de la forma que haga falta. Configurar un GitLab es absurdamente complicado.

Sobre el Copilot y lo de repetir código

Minientrada

No estoy siguiendo mucho el tema de GitHub Copilot más allá sobre los memes que ya se han hecho, así que tampoco puedo contar nada innovador.

A los programadores nos encanta soltar siglas para todo. Una de ellas es DRY: do not repeat yourself. Resolver continuamente los mismos problemas y reescribir el mismo código es absurdo porque provoca código complicado de mantener. El código debería ser reusable.

Excepto que no todo el código acaba siendo fácil de reutilizar. O, al menos, puede ser bastante excéntrico tratar de reutilizar cierto código. Crear librerías de funciones útiles que hagan las cosas sencillas pero que la librería estandar de nuestro lenguaje de programación no nos proporcione, o marcarse un Node.js y tener un ecosistema lleno de paquetes monofuncionales (en el sentido más literal de la palabra) para hacer cosas como comprobar si un array está vacío, si un número es par, o para introducir espacios en una palabra.

«¿Un paquete para crear un array de N posiciones en JavaScript? Eso es absurdo». Posiblemente. El zero-dependency es un estilo de vida, y en el caso de lenguajes como JavaScript, reducir el número de dependencias en el package.json no le viene nada mal a la mayoría de paquetes. Pero probablemente para la mayoría de estas funciones, no puedas escribirlas de tirón sin tener que entrar en Google a buscar en Stack Overflow, y a veces no tenemos tiempo ni de buscar en Stack Overflow.

Es aquí donde creo que las IAs de este estilo podrían tener potencial. No me hagas cambiar de ventana para buscar en internet cómo hacer X en Y, perder tiempo consultando la segunda respuesta porque la primera no aplica, luego la segunda pregunta porque la primera no contiene las respuesta que me interesa… En su lugar, deja que le diga al ordenador en palabras propias qué pretendo hacer y que me genere código sin levantar los dedos del teclado. O deja que automatice el código más aburrido y repetitivo de escribir para ahorrarme tiempo.

Existen razones por las cuales ni quiero pedir acceso a la beta de GitHub Copilot, pero de usarlo, se me ocurrirían casos de uso interesantes que de otro modo tendría que resolver perdiendo tiempo para escribir la función o buscando en internet, como por ejemplo:

  • Dado este array asociativo de objetos ({item1: { k1: v1, k2: v2 }, item2: { k1: v3, k2: v4 }}), fabrica un índice inverso a partir del campo k2 de cada item del array asociativo.
  • Fabrica un array con integers monotónicamente crecientes ([0, 1, 2, 3, 4...]). La IA generaría algo como Array(40).fill(0).map((_, i) => i).
  • Haz una función que valide un e-mail (¿te sabes la regex de memoria sin buscar en internet? ¿te sabes los mil millones de casos edge que tiene el RFC de las direcciones de e-mail?).

Parafraseándome a mí mismo en Twitter hace unos días,

Si programas en Java llevas pudiendo hacer clic para que el ordenador te genere los getters y los setters de tus clases desde hace décadas. Esto podría revalorizar el análisis y el diseño y dejar al ordenador que rellene specs. Imagina escribir un TDD y que el IDE lo rellene.

Trabajar en los procedimientos más complejos y reales y en la lógica de negocio que requiere intervención humana con el tiempo que gano cuando al pulsar un botón me rellena los métodos chorra tipo «buscar X en este array»? Lo compro. Y eso que no espero usar este producto.

@makigas

App Nap en Mojave vs Big Sur

Minientrada

El otro día enchufé mi ordenador portátil después de tenerlo dos días desconectado de la corriente pero encendido y en modo suspensión. La batería estaba al 95% de carga. Es curioso porque antes del downgrade, durante los meses en los que usé Big Sur, la batería se me descargaba más rápido en este tipo de casos. Hablamos de una pérdida del 30% o del 40% de la batería en ese mismo intervalo de tiempo.

Me pregunto si habría algún tipo de cambio en App Nap o en algún componente del sistema operativo responsable de esto, que haga que consuma más batería en Big Sur. O si fue algún tipo de bug temporal que ha quedado resuelto en sucesivos parches del sistema operativo. (Sigo sin plantearme actualizar, de todos modos.)

El cacao de los requisitos de Windows 11

Minientrada

No solo mintieron con lo de que Windows 10 iba a ser la última versión de Windows, sino que Windows 11 tiene por el momento una importante subida de requisitos mínimos que ha enfadado a bastante gente. Quizá tenga su explicación lógica: los requisitos mínimos de Windows 10 en 2015 fueron tan bajos que a cualquier máquina compatible con Windows 7 se le ofreció actualizar a la versión 10, y en algún momento habrá que empezar a dejar de lado máquinas de 11 o 12 años de vida. Sin embargo, tal vez el timing no sea el más adecuado para pedirle a gente que se deshaga de hardware perfectamente funcional solo porque no es de la generación de procesadores que a Microsoft le parece bien.

Antes de que Microsoft decidiese tumbar la PC and Health Check bajo la promesa de mejorarla, la descargué y la instalé en mi gaming rig para ver la compatibilidad. Llevaba días escuchando que muchos ordenadores no tan viejos estaban reportando ser incompatibles, pero la herramienta hacía una pésima labor en decir por qué. El primer intento de ejecutarla sobre mi ordenador, comprado hace 7 meses, no me sorprendió del todo.

Interesante.

Hasta que Microsoft arregle su PC and Health Check y haga que muestre un mensaje de error un poco más claro, una forma de ver por qué no es compatible un ordenador con Windows 11 es utilizar WhyNotWin11. Este programa analiza las specs y muestra en detalle todas las specs mínimas para Windows 11 y las comprueba y reporta por separado de forma gráfica.

Foto del GitHub, no es mi ordenador.

Después de una pequeña confusión entre «Windows 11 requerirá activar Secure Boot» y «Windows 11 requerirá ser compatible con Secure Boot» (FreeBSD no utiliza todavía Secure Boot y no me gustaría complicarme el acceso a esa partición, bien gracias), el único problema está en TPM 2.0. Mi Ryzen tiene TPM, pero al ser un ordenador montado, se conoce que no viene activo por defecto en la configuración del UEFI.

Para poder activar TPM tuve que consultar varios vídeos en YouTube que me explicasen cómo utilizar el menú UEFI de mi ordenador, entender por cuál de las docenas de submenús me tengo que meter, y ser capaz de localizar la entrada correcta del menú, que tiene el sensual nombre de AMD CPU fTPM (a veces parece que los nombres de las cosas se eligen dejando caminar un gato sobre el teclado…)

Todo lo que podía pensar mientras hacía esto es cómo un usuario con menos conocimientos (y eso que yo no entiendo de hardware, por eso alguien montó mi ordenador por mí y por eso paralelamente mis otros dispositivos son Apple) iba a ser capaz de sobrevivir a este paso en el supuesto de que sea esto todo lo que tiene que hacer para hacer una máquina compatible con Windows 11.

Después de hacer este paso, la PC and Health reportó que mi máquina ya podría recibir la actualización a Windows 11 (¡gracias!).

Gracias, hombre.

Listar paquetes instalados no automáticamente con pkg

Minientrada

pkg es el gestor de paquetes de FreeBSD. Es una alternativa a ports que permite instalar paquetes adicionales en el sistema que no vienen con el sistema base.

Es posible listar los paquetes instalados utilizando pkg-info(8). Sin embargo, mi principal problema con casi todos los gestores de paquetes es lo mal que diferencian entre paquetes instalados por mi y paquetes instalados como dependencia.

Me interesa sacar una lista de los paquetes verdaderamente instalados por mi. Esos paquetes que puse explícitamente en mi terminal al escribir algún comando pkg install. Por supuesto es importante saber la lista de dependencias que hay instaladas en mi sistema, pero si estoy fabricando una copia de seguridad con el listado de paquetes que he instalado en mi máquina, me parece importante ocultar las dependencias que no haya pedido, porque puede ocurrir que en el futuro esa dependencia también cambie con respecto a mis programas y deje de ser necesaria (o aparezcan otras nuevas).

pkg-query(8) es el front-end para la base de datos en la que pkg guarda su configuración y estado de los distintos paquetes. Lo bonito es que cuando se instala un paquete, sí recuerda si se ha hecho a consecuencia de ser una dependencia, o porque se haya pedido explícitamente. Así que se le puede pedir un filtro que deje fuera los paquetes que se han instalado automáticamente para listar sólo los que sí se han instalado intencionalmente con el siguiente comando: pkg query -e '%a = 0' '%n'.

danirod@beastie:~ % pkg query -e '%a = 0' '%n' | head
ImageMagick7
alacritty
base64
claws-mail
compton
doas
dsbmixer
en-freebsd-doc
feh
firefox

jq: filtrar índice inverso por valor de un subcampo

Minientrada

Amo jq, pero a la vez daría lo que fuera por poder aprender del todo su lenguaje de consulta porque a veces se me atraganta.

Sería muy fácil con jq hacer una búsqueda en un array de objetos en función de lo que vale uno de los campos de cada objeto, ¿verdad? Hablo de un array como este:

[
  {
    "nombre": "Carmen",
    "departamento": "Ventas",
    "superior": "Ana"
  }
]

Pero ¿qué pasa si en vez de un array tengo un objeto a modo de índice inverso? Me refiero a la clásica de fabricar con este array un objeto donde como valores tengo cada uno de los valores del array, pero como clave tengo algún identificador concreto de cada objeto. Al fin y al cabo, buscar items en una lista tiene complejidad O(n), pero hacerlo en un mapa tiene complejidad O(1). Es más rápido hacer lista["Ana"] que hacer lista.find(i => i.name == "Ana").

{
  "Carmen": {
    "nombre": "Carmen",
    "departamento": "Ventas",
    "superior": "Ana"
  }
}

El secreto está en usar to_entries y from_entries para convertir entre objeto y array de entries. jq 'to_entries | from_entries' < input.json se anula entre sí. Entre ambas sentencias podemos plantar un select para hacer un filtro de aquellos elementos del nuevo array generado por to_entries que filtre por una condición concreta para .[].value.whatever.

jq 'to_entries | select(.[].value.superior == "Ana") | from_entries' < empleados.json

La salida de to_entries es un array, por lo que cuando se hace el select para filtrar elementos que cumplan un criterio, hay que empezar la query con un .[], para poder hacer introspección sobre cada elemento del array. Realmente no es muy complejo, pero me lo apunto porque me ha costado un poco de ensayo y error dar con el orden correcto en el que tengo que poner los puntos y los corchetes.

Más notas sobre importar posts

Minientrada

Retomo el tema importar entradas en WordPress de forma masiva.

Recientemente volví a tirar de ese script para traerme un JSON con tweets viejos a danirod.es. Ni siquiera los he hecho públicos. Por el momento sólo los he hecho privados porque lo que me interesa es tenerlos consolidados. Tampoco son tweets recientes; estamos hablando de tweets que tienen más de una década. Todos los enlaces externos dan HTTP 404, están fatal escritos y, en general, es contenido poco interesante para internet. Pero me apetecía tenerlos a mano.

Uso el plugin Syndication Links para conectar entradas que sean importadas de otras redes sociales con su URL de referencia; las sindicaciones de Hacker News son un ejemplo. En el caso de tweets de una cuenta que ya ni siquiera existe, es bastante irrelevante plantar un u-syndication. Aun así, me apetecía ponerlo.

En el caso del plugin Syndication Links, la metadata sobre sindicación se guarda como un campo personalizado de WordPress llamado mf2_syndication. Con la API XML-RPC de WordPress es posible crear campos personalizados rellenando el array custom_fields. Hay que tener en cuenta que no es un clave-valor simple, sino que es un array de objetos, con su campo key para el título del campo, y su campo value para el valor del campo. En el módulo de npm, los campos se dan usando la key customFields en la llamada a newPost:

client.newPost({
  title: '...',
  content: '...',
  customFields: [
    { key: 'field-1', value: 'value value' },
    { key: 'field-2', value: 'more value more value' }
  ]
}, (e, id) => console.log(e, id));