Cuando echamos un vistazo al top 10 de vulnerabilidades de OWASP [1], las Inyecciones SQL siguen en una posición popular. En este breve artículo, discutimos varias opciones sobre cómo las Inyecciones SQL pueden ser evitadas.
Cuando las aplicaciones tienen que lidiar con bases de datos existentes siempre preocupaciones de alta seguridad, si un invasor tiene la posibilidad de secuestrar la capa de base de datos de su aplicación, puede elegir entre varias opciones. Robar los datos de los usuarios almacenados para inundarlos de spam no es el peor escenario que podría darse. Aún más problemático sería que se abusara de la información de pago almacenada. Otra posibilidad de un ciberataque SQL Injection es conseguir acceso ilegal a contenidos y/o servicios de pago restringidos. Como podemos ver, hay muchas razones por las que preocuparse por la seguridad de las Aplicaciones (Web).
Para encontrar medidas preventivas eficaces contra las inyecciones SQL, primero debemos comprender cómo funciona un ataque de inyección SQL y a qué puntos debemos prestar atención. En resumen: cada interacción de usuario que procesa la entrada sin filtrar en una consulta SQL es un posible objetivo para un ataque. La entrada de datos puede ser manipulada de manera que la consulta SQL enviada contenga una lógica diferente a la original. El listado 1 le dará una buena idea de lo que podría ser posible.
La primera sentencia del Listado 1 muestra la consulta original. Si no se filtra la entrada para las variables Username y Password, tenemos una falta de seguridad. La segunda consulta inyecta para la variable Username un String con el nombre de usuario John Doe y se extiende con los caracteres ‘; -. Esta sentencia se salta la rama AND y da, en este caso, acceso al login. La secuencia ‘; cierra la sentencia WHERE y con – todos los caracteres siguientes quedan sin comentar. Teóricamente, es posible ejecutar entre ambas secuencias de caracteres cualquier código SQL válido.
Por supuesto, mi plan no es difundir las ideas de que los comandos SQL podrían suscitar las peores consecuencias para la víctima. Con este simple ejemplo, asumo que el mensaje es claro. Necesitamos proteger cada variable de entrada UI en nuestra aplicación contra la manipulación del usuario. Incluso si no se utilizan directamente para consultas a la base de datos. Para detectar esas variables, siempre es una buena idea validar todos los formularios de entrada existentes. Pero las aplicaciones modernas suelen tener más que unos pocos formularios de entrada. Por esta razón, también menciono mantener un ojo en sus puntos finales REST. A menudo sus parámetros también están conectados con consultas SQL.
Por esta razón, la validación de entradas, en general, debería formar parte del concepto de seguridad. Las anotaciones de la especificación Bean Validation [2] son, para este propósito, muy potentes. Por ejemplo, @NotNull, como Anotación para el campo de datos en el objeto de dominio, asegura que el objeto sólo es capaz de persistir si la variable no está vacía. Para utilizar las Anotaciones de Validación de Bean en tu proyecto Java, sólo necesitas incluir una pequeña librería.
Quizá sea necesario validar estructuras de datos más complejas. Con las expresiones regulares, tiene otra poderosa herramienta en sus manos. Pero tenga cuidado. No es tan fácil escribir una RegEx que funcione correctamente. Veamos un pequeño ejemplo.
publicstaticfinalStringRGB_COLOR="#[0-9a-fA-F]{3,3}([0-9a-fA-F]{3,3})?";publicbooleanvalidate(String content,String regEx){booleantest;if(content.matches(regEx)){ test =true;}else{ test =false;}return test;}validate('#000', RGB_COLOR);
Java
Listing 3: Validación mediante expresiones regulares en Java
El RegEx para detectar el esquema de color RGB correcto es bastante simple. Las entradas válidas son #ffF o #000000. El rango para los caracteres es 0-9, y las letras A a F. Insensible a mayúsculas y minúsculas. Cuando desarrollas tu propio RegEx, siempre necesitas comprobar muy bien los límites existentes. Un buen ejemplo es también el formato de 24 horas. Errores típicos son entradas inválidas como 23:60 o 24:00. El método validate compara la cadena de entrada con el RegEx. Si el patrón coincide con la entrada, el método devolverá true. Si quieres obtener más ideas sobre validadores en Java, también puedes consultar mi repositorio de GitHub [3].
En resumen, nuestra primera idea para asegurar la entrada del usuario contra el abuso es filtrar todas las secuencias de caracteres problemáticas, como – y así sucesivamente. Bueno, esta intención de crear una lista de bloqueo no es tan mala. Pero sigue teniendo algunas limitaciones. Al principio, la complejidad de la aplicación aumentó porque bloquear caracteres individuales como -; y ‘ podría causar a veces efectos secundarios no deseados. Además, una limitación de caracteres por defecto en toda la aplicación puede causar problemas. Imagina que hay un área de texto para un sistema de Blog o algo similar.
Esto significa que necesitamos otro concepto potente para filtrar la entrada de forma que nuestra consulta SQL no pueda manipularla. Para alcanzar este objetivo, el estándar SQL tiene una gran solución que podemos utilizar. Los Parámetros SQL son variables dentro de una consulta SQL que serán interpretadas como contenido y no como una sentencia. Esto permite que los textos grandes bloqueen algunos caracteres peligrosos. Echemos un vistazo a cómo funcionará esto en una base de datos PostgreSQL [4].
DECLARE user String;SELECT*FROMloginWHEREname= user;
SQL
Listing 4: Definición de parámetros en PostgreSQL
En el caso de que esté utilizando el mapeador OR Hibernate, existe una forma más elegante con la Java Persistence API (JPA).
StringmyUserInput;@PersistenceContextpublicEntityManagermainEntityManagerFactory;CriteriaBuilderbuilder=mainEntityManagerFactory.getCriteriaBuilder();CriteriaQuery<DomainObject>query=builder.createQuery(DomainObject.class);// create CriteriaRoot<ConfigurationDO>root=query.from(DomainObject.class);//Criteria SQL ParametersParameterExpression<String>paramKey=builder.parameter(String.class);query.where(builder.equal(root.get("name"), paramKey);// wire queries together with parametersTypedQuery<ConfigurationDO>result=mainEntityManagerFactory.createQuery(query);result.setParameter(paramKey, myUserInput);DomainObjectentry=result.getSingleResult();
Java
Listing 5: Uso de parámetros SQL de Hibernate JPA
El listado 5 se muestra como un ejemplo completo de Hibernate utilizando JPA con la API de criterios. La variable para la entrada del usuario se declara en la primera línea. Los comentarios en el listado explican cómo funciona. Como puedes ver, no es ninguna ciencia espacial. La solución tiene otras ventajas además de mejorar la seguridad de la aplicación web. Al principio, no se utiliza SQL plano. Esto asegura que cada sistema de gestión de bases de datos soportado por Hibernate puede ser asegurado por este código.
Puede que el uso parezca un poco más complejo que una simple consulta, pero el beneficio para tu aplicación es enorme. Por otro lado, por supuesto, hay algunas líneas extra de código. Pero no son tan difíciles de entender.
Desde hace más de una década, está ampliamente aceptado que los sistemas informáticos deben mantenerse actualizados. Quienes instalan actualizaciones con regularidad reducen el riesgo de tener brechas de seguridad en su ordenador de las que se podría hacer un mal uso. Siempre con la esperanza de que los fabricantes de software corrijan siempre en sus actualizaciones también los fallos de seguridad. Microsoft, por ejemplo, ha impuesto una obligación de actualización a sus usuarios desde la introducción de Windows 10. En el fondo, la idea tenía fundamento. Porque los sistemas operativos sin parches facilitan el acceso a los hackers. Así que el pensamiento: “Lo último es lo mejor” prevaleció hace mucho tiempo.
Los usuarios de Windows tenían poco margen de maniobra. Pero incluso en dispositivos móviles como smartphones y tabletas, las actualizaciones automáticas están activadas en los ajustes de fábrica. Si alojas un proyecto de código abierto en GitHub, recibirás regularmente correos electrónicos sobre las nuevas versiones de las bibliotecas utilizadas. Así que, a primera vista, esto es algo bueno. Sin embargo, si profundizas un poco más en el tema, llegarás rápidamente a la conclusión de que lo último no siempre es lo mejor.
El ejemplo más conocido es Windows 10 y los ciclos de actualización impuestos por Microsoft. Es indiscutible que los sistemas deben comprobarse periódicamente para detectar problemas de seguridad e instalar las actualizaciones disponibles. También es comprensible que el mantenimiento de los sistemas informáticos lleve su tiempo. Sin embargo, resulta problemático cuando las actualizaciones instaladas por el fabricante paralizan todo el sistema y se hace necesaria una nueva instalación porque la actualización no ha sido suficientemente probada. Pero también en el contexto de las actualizaciones de seguridad sin pedir cambios de función al usuario para traer en considero irrazonable. Especialmente con Windows, hay un montón de programas adicionales instalados, que pueden convertirse rápidamente en un riesgo para la seguridad debido a la falta de un mayor desarrollo. Eso significa con todas las consecuencias forzadas actualizaciones de Windows no hacen un equipo seguro, ya que aquí el software instalado adicionalmente no se examina en busca de puntos débiles.
Si echamos un vistazo a los sistemas Android, la situación es mucho mejor. Sin embargo, aquí también hay bastantes puntos criticables. Las aplicaciones se actualizan con regularidad, por lo que la seguridad mejora notablemente. Pero también con Android, cada actualización suele implicar cambios funcionales. Un ejemplo sencillo es el muy popular servicio Google StreetMaps. Con cada actualización, el uso del mapa se vuelve más confuso para mí, ya que se muestra mucha información adicional no deseada, lo que reduce considerablemente la ya limitada pantalla.
Como usuario, afortunadamente todavía no me ha ocurrido que las actualizaciones de aplicaciones en Android hayan paralizado todo el teléfono. Lo que también demuestra que es bastante posible probar exhaustivamente las actualizaciones antes de lanzarlas a los usuarios. Sin embargo, esto no significa que todas las actualizaciones estén exentas de problemas. Los problemas que se pueden observar aquí con regularidad son cosas como un aumento excesivo del consumo de batería.
Las actualizaciones puras del sistema Android, por otro lado, hacen que regularmente el hardware se vuelva tan lento después de casi dos años que a menudo se decide comprar un nuevo smartphone. Aunque el teléfono antiguo todavía esté en buenas condiciones y se pueda utilizar mucho más tiempo. He observado que muchos usuarios experimentados desactivan las actualizaciones de Android al cabo de un año aproximadamente, antes de que el fabricante envíe el teléfono a la obsolescencia.
¿Cómo consigue un silenciador de actualizaciones mantener sus sistemas al día y seguros? Mi planteamiento como desarrollador y gestor de configuración es bastante sencillo. Distingo entre actualización de características y parche de seguridad. Si sigues el versionado semántico en el proceso de publicación y utilizas un modelo de rama por publicación para sistemas SCM como Git, esa distinción puede aplicarse fácilmente.
Pero también me he dedicado a la cuestión de una configuración versionable para aplicaciones de software. Para ello, existe una implementación de referencia en el proyecto TP-CORE en GitHub, que se describe en detalle en el artículo en dos partes Treasue Chest. Después de todo, debemos tener claro que si restablecemos toda la configuración realizada por el usuario a los valores de fábrica durante una actualización, como ocurre con bastante frecuencia con Windows 10, pueden surgir vulnerabilidades de seguridad bastante singulares.
Esto también nos lleva al punto de la programación y cómo GitHub motiva a los desarrolladores a través de correos electrónicos para que incluyan nuevas versiones de las librerías utilizadas en sus aplicaciones. Porque si dicha actualización supone un cambio importante en la API, el problema es el elevado esfuerzo de migración para los desarrolladores. Aquí es donde me ha funcionado una estrategia también bastante sencilla. En lugar de dejarme impresionar por las notificaciones sobre actualizaciones de GitHub, compruebo regularmente a través de OWASP si mis bibliotecas contienen riesgos conocidos. Porque si OWASP detecta un problema, no importa lo costosa que pueda ser una actualización. La actualización y la migración asociada deben aplicarse con prontitud. Esto también se aplica a todas las versiones que todavía están en producción.
Para evitar el infierno de las actualizaciones desde el principio, sin embargo, hay una regla de oro: sólo instalar o utilizar lo que realmente se necesita. Cuantos menos programas se instalen en Windows y menos aplicaciones haya en el smartphone, menos riesgos de seguridad habrá. Esto también se aplica a las bibliotecas de programas. Menos es más desde el punto de vista de la seguridad. Aparte de eso, al prescindir de programas innecesarios, también obtenemos una medida de rendimiento gratuita.
Ciertamente, para muchos usuarios privados la cuestión de las actualizaciones del sistema apenas es relevante. Sólo las nuevas funciones no deseadas en los programas existentes, la degradación del rendimiento o, de vez en cuando, el bloqueo de los sistemas operativos causan un disgusto más o menos fuerte. En el entorno comercial, pueden surgir con bastante rapidez costes considerables, que también pueden repercutir negativamente en los proyectos que se ejecutan. Las empresas y las personas que desarrollan software pueden mejorar considerablemente la satisfacción de los usuarios si distinguen en sus versiones entre parches de seguridad y actualizaciones de características. Y una actualización de características debería contener también todas las actualizaciones de seguridad conocidas.
Durante mi trabajo como Gestor de Configuración / DevOps para grandes proyectos web, he observado cómo las empresas hacían caso omiso de la Ley de Conway y fracasaban estrepitosamente. Ese fracaso a menudo se traducía en importantes sobrecostes presupuestarios y plazos incumplidos.
La infraestructura interna en la colaboración del proyecto se modeló exactamente según las estructuras organizativas internas y todas las experiencias y normas establecidas se “doblaron” para adaptarlas a la organización interna. Esto dio lugar a problemas que hicieron que las canalizaciones de CI/CD fueran especialmente engorrosas y provocaron largos tiempos de ejecución. Pero además, los ajustes sólo podían hacerse con mucho esfuerzo. En lugar de simplificar los procesos existentes y adaptarlos a los estándares establecidos, se pusieron excusas para mantener todo como estaba. Veamos qué es la Ley de Conway y por qué hay que respetarla.
El investigador y programador estadounidense Melvin E. Conway se doctoró en la Case Western Reserve University en 1961. Su especialidad son los lenguajes de programación y el diseño de compiladores.
En 1967, presentó su artículo “How Do Committees Invent?” (¿Cómo inventan los comités?) en The Harvard Business Review. (Engl.: ¿Cómo inventan los comités?) y fue rechazado. La razón aducida fue que su tesis no estaba fundamentada. Sin embargo, Datamation, la mayor revista de informática de la época, aceptó su artículo y lo publicó en abril de 1968. Y este artículo es ahora ampliamente citado. La afirmación central es:
Cualquier organización que diseñe un sistema (en el sentido más amplio) creará un diseño cuya estructura sea una copia de la estructura de comunicación de la organización.
Conway, Melvin E. “How do Committees Invent?” 1968, Datamation, vol. 14, num. 4, pp. 28–31
Cuando Fred Brooks citó el ensayo en su legendario libro de 1975 “The Mythical Man-Month”, llamó a esta afirmación central Ley de Conway. Brooks reconoció la conexión entre la Ley de Conway y la teoría de la gestión. En el artículo encontramos el siguiente ejemplo:
Dado que el diseño elegido en primer lugar casi nunca es el mejor posible, el sistema imperante puede necesitar cambiar conceptos del sistema. Por ello, la flexibilidad de la organización es importante para un diseño eficaz.
The Mythical Man-Month: Essays on Software Engineering
Un ejemplo a menudo citado del tamaño “ideal” de un equipo en términos de la Ley de Conway es la regla de las dos pizzas de Amazon, que establece que los equipos de proyectos individuales no deben tener más miembros de los que dos pizzas puedan llenar en una reunión. Sin embargo, el factor más importante que hay que tener en cuenta en la alineación de equipos es la capacidad de trabajar entre equipos y no vivir en silos.
La Ley de Conway no pretendía ser un chiste ni un koan zen, sino una observación sociológica válida. Fijémonos en las estructuras de las administraciones públicas y su implantación digital. Pero también los procesos de las grandes empresas han sido emulados por sistemas informáticos. Estas aplicaciones se consideran muy engorrosas y complicadas, por lo que encuentran poca aceptación entre los usuarios, que prefieren recurrir a alternativas. Por desgracia, a menudo es casi imposible simplificar los procesos en las grandes estructuras organizativas por motivos políticos.
Entre otras cosas, hay un detallado artículo de Martin Fowler, que trata explícitamente de las arquitecturas de software y elabora la importancia del acoplamiento de objetos y módulos. La comunicación entre desarrolladores desempeña un papel esencial para lograr los mejores resultados posibles. Este hecho sobre la importancia de la comunicación también fue recogido por el desarrollo ágil de software e implementado como un punto esencial. Especialmente cuando equipos distribuidos trabajan en un proyecto conjunto, la diferencia horaria es un factor limitante en la comunicación del equipo. Por tanto, ésta debe organizarse de forma especialmente eficaz.
En 2010, Jonny Leroy y Matt Simons acuñaron el término Inverse Conway Maneuver en el artículo “Dealing with creaky legacy platforms”:
La Ley de Conway… puede resumirse así: “Las organizaciones disfuncionales tienden a crear aplicaciones disfuncionales”. Parafraseando a Einstein: No se puede solucionar un problema desde la misma mentalidad que lo creó. Por lo tanto, a menudo merece la pena investigar si la reestructuración de su organización o equipo evitaría que la nueva aplicación tuviera las mismas disfunciones estructurales que la original. En una especie de “maniobra Conway a la inversa”, se puede empezar por romper los silos que limitan la capacidad del equipo para trabajar juntos con eficacia.
Desde la década de 2010, un nuevo estilo arquitectónico ha entrado en la industria del software. Son los llamados microservicios, creados por pequeños equipos ágiles. El criterio más importante de un microservicio en comparación con un monolito modular es que un microservicio puede verse como un módulo o subsistema independientemente viable. Por un lado, esto permite reutilizar el microservicio en otras aplicaciones. Por otro lado, existe un fuerte encapsulamiento del dominio funcional, lo que abre una flexibilidad muy elevada para las adaptaciones.
La ley de Conway también puede aplicarse a muchos otros ámbitos y no se limita exclusivamente a la industria del software. Esto es lo que hace que el trabajo sea tan valioso.
Resourcen
Los enlaces sólo son visibles para los usuarios registrados.
Hablamos de inteligencia artificial, pero ¿qué es en realidad? Es una rama de la informática que trata de imitar la inteligencia humana, para actuar como un ser humano. La inteligencia artificial abarca principalmente áreas como el aprendizaje, la toma de decisiones, la resolución de problemas y el reconocimiento de patrones.
Hay muchas empresas implicadas en el desarrollo de la inteligencia artificial, entre las empresas líderes en este campo, se encuentran actualmente Microsoft, IBM, Samsung, Qualcomm, Google, Philips, Siemens, Sony, Intel y Canon.
Las ventajas de la I.A. son que puede utilizarse en muchos ámbitos, por ejemplo en sanidad, transporte, seguridad, comercio, industria, análisis de grandes cantidades de datos, realización de tareas tediosas y repetitivas, análisis de grandes cantidades de información para detectar patrones y tendencias, sistemas de conducción autónoma para evitar accidentes, modelos predictivos de mercados y consumidores, para tomar decisiones empresariales, detección de fraudes y delitos, personalización de la educación, detección y diagnóstico de enfermedades, creación de imágenes mediante descripciones, procesamiento de textos y artículos.
Pero esta tecnología también tiene sus inconvenientes y riezgos, por esta razón, directores ejecutivos, líderes tecnológicos, académicos, científicos y muchos otros, han escrito una carta conjunta en la que piden un enfoque prudente de la inteligencia artificial y detener desarrollos arriba de GPT-5.
El revuelo en torno a la inteligencia artificial dura ya varios años. Actualmente, empresas como OpenAI están causando un gran revuelo con redes neuronales de libre acceso como ChatGPT. Los usuarios están fascinados por las posibilidades y algunas figuras intelectuales de nuestro tiempo advierten a la humanidad sobre la inteligencia artificial. Entonces, ¿qué tiene el espectro de la IA? En este artículo exploro esta cuestión y le invito a acompañarme en este viaje. Vamos a seguirme hacia el futuro.
En la primavera de 2023, se desbordaron los informes sobre la capacidad de rendimiento de las redes neuronales artificiales. Esta tendencia continúa y, en mi opinión, no remitirá en breve. Sin embargo, en medio de la incipiente fiebre del oro, también circulan algunas malas noticias. Microsoft, por ejemplo, anunció que invertiría fuertemente en inteligencia artificial. Este anuncio se vio subrayado en la primavera de 2023 con el despido de casi 1.000 empleados, suscitando los consabidos temores a la industrialización y la automatización. Las cosas fueron menos espectaculares en Digital Ocean, que despidió a todo su equipo de creación de contenidos y documentación. Rápidamente, algunos se preguntaron, con razón, si la IA convertiría ahora en obsoletas profesiones como las de programador, traductor, periodista, redactor, etc. Por el momento, me gustaría responder a esta pregunta con un no. A medio plazo, sin embargo, se producirán cambios, como ya nos ha enseñado la historia. Lo viejo pasa y lo nuevo nace. Acompáñenme en una pequeña excursión histórica.
Veamos primero las distintas etapas de la industrialización, que se originó en Inglaterra en la segunda mitad del siglo XVIII. Incluso el significado del término latino original Industria, que puede traducirse como diligencia, es sumamente interesante. Lo que nos lleva a Norbert Wiener y su libro de 1960 God and Golem Inc [1]. En él reflexionaba públicamente sobre si las personas que crean máquinas, que a su vez pueden crear máquinas, son dioses. Algo que, desde mi punto de vista, no me gustaría suscribir. Pero volvamos de momento a la industrialización.
La introducción de la máquina de vapor y el uso de fuentes de energía independientes del lugar, como el carbón, permitieron una producción en masa precisa. Al abaratarse la automatización de la producción mediante máquinas, se desplazaron los puestos de trabajo manuales a domicilio. A cambio, ahora se podían adquirir productos más baratos en las tiendas. Pero también se produjeron cambios significativos en el transporte. El ferrocarril permitió viajes más rápidos, cómodos y baratos. Esto catapultó a la humanidad a un mundo globalizado. Porque ahora las mercancías también podían recorrer largas distancias en poco tiempo y sin problemas. Hoy, cuando recordamos los debates de la época en que el ferrocarril inició su marcha triunfal, sólo podemos sonreír. Al fin y al cabo, algunos intelectuales de la época sostenían que velocidades de tren superiores a 30 kilómetros por hora aplastarían literalmente a los ocupantes humanos. Un temor que afortunadamente resultó infundado.
Mientras que en la primera revolución industrial la gente ya no podía obtener ingresos trabajando en casa, encontró una alternativa para ganarse la vida en una fábrica.
La segunda revolución industrial se caracterizó por la electrificación, que aumentó aún más el grado de automatización. Las máquinas se volvieron menos engorrosas y más precisas. Pero también se introdujeron nuevos inventos en la vida cotidiana. El fax, el teléfono y la radio difundieron información a gran velocidad. Esto nos condujo a la era de la información y aceleró no sólo nuestra comunicación, sino también nuestras vidas. Creamos una sociedad que se caracteriza sobre todo por el dicho “el tiempo es oro”.
La tercera revolución industrial bendijo a la humanidad con una máquina universal que determinaba su funcionalidad a través de los programas (software) que se ejecutaban en ella. Hoy en día, los ordenadores nos ayudan en multitud de actividades. Los modernos sistemas de caja registradora hacen mucho más que escupir el importe total de la compra realizada. Registran los flujos de dinero y mercancías y permiten realizar evaluaciones de optimización con los datos recogidos. Se trata de una nueva calidad de automatización que hemos alcanzado en los últimos 200 años. Con la generalización de las redes neuronales artificiales, estamos saliendo de esta fase, por lo que actualmente nos encontramos en la transformación hacia la cuarta revolución industrial. ¿De qué otra forma pretendemos, como humanos, hacer frente a la creciente avalancha de información?
Aunque la Industria 4.0 se centra en la conexión en red de las máquinas, no se trata de una auténtica revolución. Internet es solo una consecuencia del desarrollo anterior para permitir la comunicación entre máquinas. Podemos compararlo con la sustitución de la máquina de vapor por motores eléctricos. La verdadera innovación fueron las máquinas eléctricas que cambiaron la forma de comunicarnos. Esto está ocurriendo ahora en nuestra época a través del amplio campo de la inteligencia artificial.
En un futuro próximo, ya no utilizaremos los ordenadores de la misma manera que hasta ahora. Esto se debe a que los ordenadores actuales deben su existencia a la hasta ahora limitada comunicación entre el hombre y la máquina. En realidad, el teclado y el ratón son dispositivos de entrada torpes. Son lentos y propensos a errores. El control por voz y gestos a través del micrófono y la cámara sustituirá al ratón y al teclado. Hablaremos con nuestros ordenadores como hablamos con otras personas. Pero esto también significa que los programas informáticos actuales quedarán obsoletos. Ya no rellenaremos tediosas máscaras de entrada en interfaces gráficas de usuario para alcanzar nuestro objetivo. Atrás quedarán los días en que tenía que teclear mis artículos. Ahora los teclearé y mi ordenador me los mostrará visualmente para que los corrija. Presumiblemente, la profesión de logopeda experimentará entonces un auge considerable.
Seguramente también habrá bastantes protestas de personas que temen la desintegración de la comunicación humana. Este temor no es en absoluto infundado. No hay más que ver la evolución de la lengua alemana desde el cambio de milenio. Se caracterizó por la aparición de diversos servicios de mensajería de texto y la optimización de los mensajes mediante el uso del mayor número posible de abreviaturas. Esto, a su vez, no hizo sino crear interrogantes en la frente de los padres a la hora de descifrar el contenido de los mensajes de sus hijos. Aunque la tendencia actual es pasar de los mensajes de texto a los mensajes de audio, eso no significa que nuestro lenguaje no siga cambiando. Yo mismo he observado durante años que muchas personas ya no son capaces de expresarse correctamente por escrito o de extraer contenido de textos escritos. A largo plazo, esto podría llevarnos a desaprender habilidades como la lectura y la escritura. En consecuencia, los clásicos artículos impresos, como libros y revistas, también quedarán obsoletos. Por último, los contenidos también pueden producirse en forma de vídeo o podcast. Nuestras capacidades intelectuales degenerarán a largo plazo.
Desde el cambio de milenio, a mucha gente le resulta cada vez más fácil utilizar ordenadores. Primero las buenas noticias. En el futuro será mucho más fácil utilizar ordenadores a medida que la interacción hombre-máquina sea más intuitiva. Mientras tanto, veremos cómo cada vez más grandes portales de Internet cierran sus servicios porque su modelo de negocio ya no es viable. He aquí un pequeño ejemplo.
Como programador, a menudo utilizo el sitio web StackOverflow para encontrar ayuda con los problemas. La información de este sitio web sobre temas de programación es ahora tan amplia que puedes encontrar rápidamente soluciones adecuadas a tus propias inquietudes buscando en Google y similares, sin tener que formular tú mismo las preguntas. Hasta aquí todo bien. Pero si ahora integras una red neuronal como ChatGPT en tu propio entorno de programación para encontrar la respuesta a todas tus preguntas, el número de visitantes de StackOverflow descenderá continuamente. Esto, a su vez, repercute en las campañas publicitarias para poder ofrecer el servicio de forma gratuita en la red. Inicialmente, esto se compensará con el pago de una tarifa plana por el uso de la base de datos por parte de los operadores de los sistemas de IA que acceden a los datos de StackOverflow. Sin embargo, esto no detendrá la disminución del número de visitantes. Como resultado, o bien una barrera de pago impedirá el uso gratuito o el servicio se interrumpirá por completo. Hay muchas ofertas en Internet que se encontrarán con problemas similares, lo que garantizará a largo plazo que Internet, tal y como la conocemos, desaparezca en el futuro.
Imaginemos cómo sería una futura consulta sobre el término de búsqueda “revolución industrial”. Le pregunto a mi asistente digital ¿Qué sabes sobre la revolución industrial? – En lugar de buscar resultados relevantes en una lista aparentemente interminable de miles de entradas, me lee una breve explicación con una dirección personalizada que coincide con mi edad y nivel de educación. Lo que plantea inmediatamente la pregunta de quién y cómo juzga mi nivel de educación.
Es otra degradación de nuestras capacidades. Aunque al principio se perciba como algo muy cómodo. Si ya no tenemos la necesidad de centrar nuestra atención en una cosa concreta durante un largo periodo de tiempo, sin duda nos resultará difícil idear cosas nuevas en el futuro. Nuestra creatividad se reducirá al mínimo absoluto.
También cambiará en el futuro la forma de almacenar los datos. Las estructuras complicadas que se almacenan de forma óptima en bases de datos serán la excepción y no la regla. Más bien, espero trozos independientes de datos que se encadenen como listas. Veámoslo juntos para hacernos una idea de lo que quiero decir.
Tomemos como punto de partida el libro de Aldous Huxley “Un mundo feliz”, de 1932. Además del título, el autor y el año de publicación, podemos añadir el inglés como idioma a la metainformación. A continuación se muestra todo el contenido del libro, incluidos el prefacio y el epílogo, como texto ASCII sin formato. Los elementos genéricos o modificables, como el índice o el copyright, no se incluyen en esta fase. Con este trozo, hemos definido un dato atómico que puede identificarse de forma única mediante un valor hash. Dado que Brave New World de Huxley fue escrito originalmente en inglés, este dato es también una fuente inmutable para todos los datos derivados y generados a partir de él.
Si la obra de Huxley se traduce al alemán o al español, es la primera derivada con la referencia al original. Puede ocurrir que los libros hayan sido traducidos por diferentes traductores en distintas épocas. Esto da lugar a un hash de referencia diferente para la traducción alemana de Herbert E. Herlitschka de 1933 con el título “Un mundo feliz” que para la traducción de Eva Walch publicada en 1978 con el mismo título “Un mundo feliz”.
Si ahora se producen audiolibros a partir de los distintos textos, estos audiolibros son el segundo derivado del texto original, ya que representan una versión abreviada. Un texto también se crea como versión independiente antes de ser grabado. La banda sonora creada a partir del texto original abreviado tiene como autor al director y hace referencia al locutor o locutores. Como en el teatro, un texto puede ser interpretado y puesto en escena por diferentes personas. Las adaptaciones cinematográficas pueden tratarse del mismo modo.
A su vez, los libros, audiolibros y películas tienen gráficos para la cubierta. Estos gráficos representan a su vez obras independientes, a las que se hace referencia con la versión correspondiente del original.
Las citas de libros también pueden enlazarse de este modo. Del mismo modo, críticas, interpretaciones, reseñas y todo tipo de variaciones de contenido que hagan referencia a un original.
Pero estos bloques de datos no se limitan a los libros, sino que también pueden aplicarse a partituras musicales, letras de canciones, etc. La clave está en enlazar todo lo posible con el original. El factor decisivo es que se pueda partir del original en la medida de lo posible. Los archivos resultantes están optimizados exclusivamente para programas informáticos, ya que no tienen ningún formato visible para el ojo humano. Por último, el valor hash correspondiente sobre el contenido del archivo basta como nombre de archivo.
Aquí empieza la visión del futuro. Como autores de nuestro trabajo, ahora podemos utilizar la inteligencia artificial para crear automáticamente traducciones, ilustraciones, audiolibros y animaciones incluso a partir de un libro. En este punto, me gustaría referirme brevemente a la red neuronal DeepL [2], que ya ofrece traducciones impresionantes e incluso mejora el texto original si se maneja con habilidad. ¿Ahora DeepL deja sin trabajo a traductores y editores? Quiero decir que no. Porque las inteligencias artificiales, como nosotros los humanos, no son infalibles. También cometen errores. Por eso creo que el precio de este trabajo bajará mucho en el futuro, porque ahora estas personas pueden hacer mucho más trabajo que antes gracias a sus conocimientos y a las excelentes herramientas de que disponen. Esto hace que el servicio individual sea considerablemente más barato, pero como gracias a la automatización es posible realizar más servicios individuales en el mismo periodo de tiempo, esto compensa la reducción de precio para el proveedor.
Si ahora nos fijamos en las nuevas posibilidades que se abren ante nosotros, no parece que nos resulte tan problemático. Entonces, ¿de qué tratan de advertirnos personas como Elon Musk?
Si ahora suponemos que la cuarta revolución industrial digitalizará todo el conocimiento humano y que todo el nuevo conocimiento sólo se creará en forma digital, los algoritmos informáticos serán libres de utilizar la potencia de cálculo adecuada para cambiar estos trozos de conocimiento de tal forma que los humanos no nos demos cuenta. Un escenario vagamente basado en el Ministerio de la Verdad de Orwell de la novela 1984. Si desaprendemos nuestras habilidades por conveniencia, también tendremos pocas oportunidades de verificación.
Si cree que esto no es un problema, me gustaría remitirle a la conferencia “Don’t trust a scan” de David Kriesel [3]. ¿Qué ocurrió? En resumen, se trataba de una empresa constructora que observó discrepancias en las copias de sus planos de construcción. El resultado eran diferentes copias del mismo original, en las que los valores numéricos estaban cambiados. Este es un problema muy grave en un proyecto de construcción para los oficios que realizan la obra. Cuando el albañil recibe especificaciones de tamaño diferentes a las de los encofradores de hormigón. Finalmente, se descubrió que el error se debía a que Xerox utilizaba una IA como software en sus escáneres para el OCR y la compresión posterior, que no podía reconocer de forma fiable los caracteres escaneados.
Pero la cita de Ted Chiang “Piensa en ChatGPT como un jpeg borroso de todo el texto de la web” también debería darnos que pensar. Ciertamente, para quienes sólo conocen la IA como aplicación, es difícil entender lo que quiere decir “ChatGPT es sólo un jpeg borroso de todo el texto de la web”. Sin embargo, no es tan difícil de entender como parece al principio. Debido a su estructura, las redes neuronales son siempre sólo una instantánea. Porque con cada entrada, el estado interno de una red neuronal cambia. Igual que nos ocurre a los humanos. Al fin y al cabo, sólo somos la suma de nuestras experiencias. Si, en el futuro, cada vez más textos creados por una IA se colocan en la red sin reflexión, la IA formará su conocimiento a partir de sus propias derivaciones. Los originales se desvanecen con el tiempo porque pierden peso debido a que cada vez hay menos referencias. Si alguien inundara Internet con temas como la tierra plana y los lagartos, programas como ChatGPT reaccionarían inevitablemente a ello y lo incluirían en sus textos. Estos textos podrían entonces ser publicados automáticamente por la IA en la red o ser difundidos en consecuencia por personas irreflexivas. Hemos creado así una espiral que sólo puede romperse si las personas no han renunciado a su capacidad de juicio por conveniencia.
Vemos, pues, que las advertencias de tener cuidado al tratar con la IA no son infundadas. Aunque considero improbables escenarios como el de la película de 1983 Juegos de guerra [4], deberíamos pensar muy detenidamente hasta dónde queremos llegar con la tecnología de la IA. No queremos acabar como el aprendiz de brujo y descubrir que ya no podemos controlarla.
Referencias
Los enlaces sólo son visibles para los usuarios registrados.
Cuando diseñamos modelos de datos y sus correspondientes tablas a veces aparece Boolean como tipo de dato. En general estos indicadores no son realmente problemáticos. Pero tal vez podría haber una mejor solución para el diseño de datos. Permítanme darles un breve ejemplo de mi intención.
Supongamos que tenemos que diseñar un dominio simple para almacenar artículos. Como un Sistema de Blog o cualquier otro Gestor de Contenidos. Además del contenido del artículo y el nombre del autor, podríamos necesitar una bandera que indique al sistema si el artículo es visible para el público. Algo así como publicado como un booleano. Pero también hay un requisito de cuando el artículo está programado una fecha para su publicación. En la mayoría de los diseños de bases de datos observé para esas circunstancias un Booleano: published y una Fecha: publishingDate. En mi opinión este diseño es un poco redundante y también propenso a errores. Como conclusión rápida me gustaría aconsejarte que utilices desde el principio sólo Date en lugar de Boolean. El escenario que he descrito anteriormente también puede transformarse en muchas otras soluciones de dominio.
Por ahora, después de tener una idea de por qué debemos sustituir Boolean por Date datatype nos centraremos en los detalles de cómo podemos alcanzar este objetivo.
Tratar con SQL estándar sugiere que reemplazar un Sistema de Gestión de Bases de Datos (SGBD) por otro no debería ser un gran problema. Desgraciadamente, la realidad es un poco diferente. No es recomendable utilizar todos los tipos de datos disponibles para fechas como Timestamp. Por experiencia prefiero usar el simple java.util.Date para evitar futuros problemas y otras sorpresas. El formato almacenado en la tabla de la base de datos se parece a: ‘YYYY-MM-dd HH:mm:ss.0’. Entre la Fecha y la Hora hay un espacio y .0 indica un offset. Este desfase describe la zona horaria. La zona horaria estándar de Europa Central CET tiene un desfase de una hora. Eso significa UTC+01:00 en formato internacional. Para definir el offset por separado obtuve buenos resultados utilizando java.util.TimeZone, que funciona perfectamente junto con Date.
Antes de continuar os voy a mostrar un pequeño fragmento de código en Java para el gestor OR de Hibernate y cómo podríais crear esas columnas de la tabla.
Traducción realizada con la versión gratuita del traductor www.DeepL.com/Translator
Veamos un poco más de cerca el listado anterior. Primero vemos la anotación @CreationTimestamp. Esto significa que cuando el objeto ArticleDO se crea, la variable creada se inicializa con la hora actual. Este valor nunca debe cambiar, porque un artículo puede ser creado una sola vez pero cambiado varias veces. La Zona Horaria se almacena en un String. En el Constructor puedes ver como la Zona Horaria del sistema puede ser tomada – pero ten cuidado este valor no debe confiarse mucho. Si tienes un usuario como yo que viaja mucho, verás que en todos los lugares en los que estoy tengo la misma hora del sistema, porque normalmente nunca la cambio. Como zona horaria por defecto defino la cadena correcta para UTC-0. Lo mismo hago para la variable publicada. Date también puede ser creada por un String lo que usamos para establecer nuestro valor cero por defecto. El Setter para published tiene la opción de definir una fecha futura o usar la hora actual en el caso de que el artículo se publique inmediatamente. Al final del listado demuestro una simple importación SQL para un solo registro.
Pero no hay que precipitarse. También tenemos que prestar un poco de atención a cómo tratar con el desplazamiento UTC. Debido a que he observado en los sistemas enormes varias veces los problemas que se produjeron porque el desarrollador se utilizó sólo los valores predeterminados.
La zona horaria en general forma parte del concepto de internacionalización. Para gestionar correctamente los ajustes de desfase podemos decidir entre diferentes estrategias. Como en tantos otros casos, no hay un claro correcto o incorrecto. Todo depende de las circunstancias y necesidades de su aplicación. Si se trata de un sitio web de ámbito nacional, como el de una pequeña empresa, y no hay eventos críticos en el tiempo, todo resulta muy sencillo. En este caso no será problemático gestionar la configuración de la zona horaria automáticamente por el DBMS. Pero hay que tener en cuenta que en el mundo existen países como México con más de una zona horaria. Un sistema internacional donde los clientes se extienden por todo el mundo podría ser útil para configurar cada DBMS en el clúster a UTC-0 y gestionar el desplazamiento por la aplicación y los clientes conectados.
Otra cuestión que debemos resolver es cómo inicializar el valor de la fecha de un registro por defecto. Porque los valores nulos deben evitarse. Una explicación completa de por qué devolver null no es un buen estilo de programación se encuentra en libros como ‘Effective Java’ y ‘Clean Code’. Tratar con Excepciones de Puntero Nulo es algo que realmente no necesito. Una buena práctica que funciona bien para mí es una fecha por defecto – valor de tiempo por ‘0000-00-00 00:00:00.0’. Así evito publicaciones no deseadas y el significado es muy claro para todos.
As you can see there are good reasons why Boolean data types should replaced by Date. In this little article I demonstrated how easy you can deal with Date and timezone in Java and Hibernate. It should also not be a big thing to convert this example to other programming languages and Frameworks. If you have an own solution feel free to leave a comment and share this article with your colleagues and friends.
Como proveedor de servicios informáticos, a menudo tenemos que ayudar a nuestros clientes a reinstalar sistemas Windows antiguos. El reto más frecuente al que nos enfrentamos en esta actividad es hacer una copia de seguridad de los archivos antiguos y restaurarlos en el nuevo sistema. No sólo los particulares, también las empresas que utilizan el cliente de correo Thunderbird. Así que hemos decidido publicar esta breve guía sobre cómo hacer una copia de seguridad y restaurar su perfil de Thunderbird. Para evitar una pérdida de datos – usted debe hacer copias de seguridad con regularidad en el caso de que su hardware o sistema operativo se estrelló por completo.
copia de seguridad
Conecta un pen drive o un disco duro (soporte USB) a tu ordenador.
Crea un directorio de tu elección en el soporte USB para hacer una copia de seguridad de tu perfil. Elija un nombre con el que pueda reconocer posteriormente el contenido. (e.g. 2022-01-19_Thunderbird-profile)
Mantenga la “ventana del Explorador” abierta y asegúrese de que el directorio está activo.
Abra Thunderbird en el ordenador del que desea hacer una copia de seguridad.
Para encontrar el perfil antiguo, haz clic en las “barra del árbol” de la esquina superior derecha.
En la siguiente ventana que se abre, haz clic en “Abrir carpeta“.
Aparecerá una nueva “ventana del Explorador” que le mostrará todos los archivos de su perfil.
Marque todos los archivos haciendo clic – haga clic en el “1er archivo”, luego mantenga pulsada la tecla de su teclado y al mismo tiempo pulse la tecla “Flecha abajo” hasta que la “barra de desplazamiento” gris de la ventana llegue a la parte inferior. Una vez seleccionados todos los archivos (marcados en azul), haga clic con el “botón derecho del ratón” sobre cualquier archivo y seleccione la opción de menú “Copiar“.
Vuelva a la otra “ventana del Explorador“, pulse el botón derecho del ratón y luego “Pegar“.
Una vez finalizado el proceso de copia, puedes cerrar tu Thunderbird.
restaurar
Conecte su “medio USB” al ordenador (destino) donde desea transferir su perfil Thunderbird.
Abra el “Explorador” y cree los siguientes directorios: “Datos” ➡️ ” Thunderbird” ➡️ “Post-Office xxx” (C:\Data\Thunderbird\Post-Office xxx\ “xxx” debe sustituirlo por el nombre de su perfil de Thunderbird)
Una vez creados los directorios, puede copiar los datos de su perfil desde el soporte USB al directorio recién creado “Post-Office xxx“.
Una vez finalizado el proceso de copia, aún debe configurar su nuevo directorio de perfil en Thunderbird.
Pulse las teclas + de su teclado. Se abrirá el cuadro de diálogo “Ejecutar“. Introduce el siguiente comando: thunderbird -p como puedes ver en la captura de pantalla y pulsa “Aceptar“.
En la ventana emergente recién abierta “Thunderbird – Elegir perfil de usuario“, haga clic en “Crear perfil…” para iniciar el asistente.
En la 1ª ventana del “Asistente para perfiles – Bienvenido” pulse “Siguiente“.
En la segunda ventana del “Asistente para perfiles – Finalizar“, introduzca el “Nombre del perfil” (Oficina de correos xxx) en “1”, como puede ver en la captura de pantalla. En “2” seleccione la ruta del perfil haciendo clic en “Elegir carpeta“. (C:\Data\Thunderbird\Post-Office xxx)”.
Para finalizar el proceso, sólo tienes que pulsar el botón “Finalizar“.
Ahora puedes iniciar Thunderbird normalmente desde la barra de inicio – todos tus correos y configuraciones están restaurados. Si tienes preguntas o sugerencias puedes escribirnos un e-mail o dejar un comentario. Si te gusta esta guía no dudes en compartir este artículo
Después de que la banda de los cuatro (GOF) Erich Gamma, Richard Helm, Ralph Johnson y John Vlissides publicaran el libro Design Patterns: Elements of Reusable Object-Oriented Software, aprender a describir problemas y soluciones se hizo popular en casi todos los campos del desarrollo de software. Del mismo modo, aprender a describir lo que no se debe hacer y los antipatrones se hizo igualmente popular.
En las publicaciones que trataban estos conceptos, encontramos recomendaciones útiles para el diseño de software, la gestión de proyectos, la gestión de la configuración y mucho más. En este artículo, compartiré mi experiencia con los números de versión para artefactos de software.
La mayoría de nosotros ya estamos familiarizados con un método llamado versionado semántico, un conjunto de reglas potentes y fáciles de aprender sobre cómo deben estructurarse los números de versión y cómo deben aumentar los segmentos.
Ejemplo de numeración de versiones:
Mayor: Cambios incompatibles en la API.
Menor: Añade nuevas funcionalidades.
Patch: Corrección de errores y correcciones.
Label: SNAPSHOT que marca el estado “en desarrollo”.
Un cambio de API incompatible se produce cuando se elimina o cambia el nombre de una función o clase accesible desde el exterior. Otra posibilidad es un cambio en la firma de un método. Esto significa que el valor de retorno o los parámetros se han modificado con respecto a su implementación original. En estos escenarios, es necesario aumentar el segmento Mayor del número de versión. Estos cambios suponen un alto riesgo para los consumidores de la API porque tienen que adaptar su propio código.
Cuando se trata de números de versión, también es importante saber que 1.0.0 y 1.0 son iguales. Esto tiene efecto en el requisito de que las versiones de una versión de software tienen que ser únicas. Si no, es imposible distinguir entre artefactos. En mi experiencia profesional, he participado varias veces en proyectos en los que no había procesos bien definidos para crear números de versión. El efecto de estas circunstancias era que el equipo tenía que asegurar la calidad del artefacto y se confundía con qué versión del artefacto estaba tratando en ese momento.
El mayor error que he visto es el almacenamiento de la versión de un artefacto en una base de datos junto con otras entradas de configuración. El procedimiento correcto debería ser: colocar la versión dentro del artefacto de forma que nadie después de una liberación pueda cambiarla desde fuera. La trampa en la que podrías caer es el proceso de cómo actualizar la versión después de un lanzamiento o instalación.
Puede que tenga una lista de comprobación para todas las actividades manuales durante una publicación. Pero, ¿qué sucede después de que una versión se instala en una etapa de prueba y por alguna razón otra versión de la aplicación tiene que ser instalada. ¿Todavía tiene que cambiar manualmente el número de versión? ¿Cómo averiguar qué versión está instalada o cuándo la información de la base de datos es incorrecta?
Detectar la versión correcta en esta situación es un reto muy difícil. Por esa razón, tenemos el requisito de mantener la versión dentro de la aplicación. En el próximo paso, discutiremos una forma segura y simple de resolver este problema de forma automática.
Nuestra precondición es una simple construcción de una librería Java con Maven. Por defecto, el número de versión del artefacto está escrito en el POM. Después del proceso de construcción, nuestro artefacto es creado y nombrado como: artefacto-1.0.jar o similar. Mientras no renombremos el artefacto, tendremos una forma adecuada de distinguir las versiones. Incluso después de un renombrado con un simple truco de empaquetado y comprobación, entonces, en la carpeta META-INF, somos capaces de encontrar el valor correcto.
Si usted tiene la Versión hardcoded en una propiedad o archivo de clase, también funcionaría bien, siempre y cuando no se olvide de actualizar siempre. Tal vez la ramificación y la fusión en los sistemas SCM como Git podría necesitar su atención especial para tener siempre la versión correcta en su código base.
Otra solución es utilizar Maven y el mecanismo de colocación de tokens. Antes de que corras a probarlo en tu IDE, ten en cuenta que Maven utiliza dos carpetas diferentes: sources y resources. La sustitución de tokens en sources no funcionará correctamente. Después de una primera ejecución, tu variable es reemplazada por un número fijo y desaparece. Una segunda ejecución fallará. Para preparar tu código para el reemplazo de tokens, necesitas configurar Maven como primero en el ciclo de vida de construcción:
Después de este paso, necesita conocer la propiedad ${project.version} del POM. Esto le permite crear un archivo con el nombre version.property en el directorio resources. El contenido de este archivo es sólo una línea: version=${project.version}. Después de una compilación, encontrará en su artefacto la version.property con el mismo número de versión que utilizó en su POM. Ahora, usted puede escribir una función para leer el archivo y utilizar esta propiedad. Podrías almacenar el resultado en una constante para usarla en tu programa. ¡Eso es todo lo que tienes que hacer!