<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ernesto λrroyo</title>
    <description>The latest articles on DEV Community by Ernesto λrroyo (@earroyoron).</description>
    <link>https://dev.to/earroyoron</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F221825%2F71412bf2-16c4-47a3-a24a-98a3b50ac09e.png</url>
      <title>DEV Community: Ernesto λrroyo</title>
      <link>https://dev.to/earroyoron</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/earroyoron"/>
    <language>en</language>
    <item>
      <title>Be immutable my friend!</title>
      <dc:creator>Ernesto λrroyo</dc:creator>
      <pubDate>Sat, 01 Feb 2020 18:52:08 +0000</pubDate>
      <link>https://dev.to/earroyoron/be-immutable-my-friend-2a28</link>
      <guid>https://dev.to/earroyoron/be-immutable-my-friend-2a28</guid>
      <description>&lt;p&gt;En este artículo explico brevemente el concepto de inmutabilidad y porque deberías usarlo por defecto.&lt;/p&gt;

&lt;p&gt;El concepto de inmutabilidad en la programación no es novedoso. El resurgir(*) de la programación funcional le ha dado una nueva vida, pero en otros paradigmas ha existido desde antaño. &lt;/p&gt;

&lt;p&gt;No hay más que leer, por ejemplo, uno de los libros referente de la programación como es "Effective Java" (Joshua Bloch) que en su recomendación número 15 menciona el principio de &lt;em&gt;minimizar la mutabilidad de los objetos&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;An immutable class is simply a class whose instances cannot be modified. All of the information contained in each instance is fixed for the lifetime of the object, so no changes can ever be observed. The Java platform libraries contain many immutable classes, including String, the boxed primitive classes, and BigInteger and BigDecimal. There are many good reasons for this: Immutable classes are easier to design, implement, and use than mutable classes. They are less prone to error and are more secure.&lt;/em&gt; &lt;em&gt;Bloch, Joshua. Effective Java.&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;(*) &lt;em&gt;la programación bajo el paradigma funcional tiene su origen teórico en los años 30 y el que podría ser el primer lenguaje funcional, LISP, es de 1950.&lt;/em&gt; &lt;/p&gt;

&lt;h1&gt;
  
  
  Beneficios
&lt;/h1&gt;

&lt;p&gt;Un clase inmutable es aquella cuyas instancias no podrán ser modificadas. Con este modelo evitamos errores y nuestras aplicaciones serán más seguras. &lt;/p&gt;

&lt;p&gt;En entornos de alta concurrencia evitan errores de acceso compartido y no hace falta disponer de herramientas de protección para modificar objetos (mutex, locks, semáforos,...) porque, bueno, no se puede modificar nada.&lt;/p&gt;

&lt;p&gt;Un objeto (mejor dicho, una de sus instancias) sólo puede estar en un estado, el estado en el que fue construido. Si hace falta modificarlo el proceso es crear una copia modificada.&lt;/p&gt;

&lt;p&gt;Esto que puede parecer poco natural en realidad es un arma tremendamente poderosa y permite usar un estilo funcional de programación que es mucho más seguro y menos peligroso que la programación que suele utilizarse.&lt;/p&gt;

&lt;p&gt;Podemos encontrar más razones para usar siempre objetos inmutables incluso en la misma Oracle:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An object is considered immutable if its state cannot change after it is constructed. Maximum reliance on immutable objects is widely accepted as a sound strategy for creating simple, reliable code. &lt;/p&gt;

&lt;p&gt;Immutable objects are particularly useful in concurrent applications. Since they cannot change state, they cannot be corrupted by thread interference or observed in an inconsistent state.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html"&gt;https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Un objeto mutable presenta muchos problemas para entornos de concurrencia.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Estas rodeado de inmutabilidad
&lt;/h1&gt;

&lt;p&gt;Lo cierto es que incluso en lenguajes de OOP se usa profusamente la idea de inmutabilidad. En Java las clases como &lt;code&gt;String&lt;/code&gt;, &lt;code&gt;BigInteger&lt;/code&gt;, &lt;code&gt;Long&lt;/code&gt;, &lt;code&gt;UUID&lt;/code&gt;,...&lt;/p&gt;

&lt;p&gt;En otros lenguajes más modernos, y vamos a dar el ejemplo con Kotlin, es más fácil trabajar con objetos inmutables e, incluso, las colecciones son inmutables por omisión. &lt;/p&gt;

&lt;p&gt;Es decir Kotlin, al contrario que Java, prefiere la inmutabilidad y una lista no es modificable una vez creada; si necesitas que lo sea deberás usar otro tipo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   val immutableList = listOf("one")
   val changingList = mutableListOf&amp;lt;String&amp;gt;("one")
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Aún así en Java es trivial (aunque verboso) definir clases inmutables.&lt;/p&gt;

&lt;p&gt;Nota: en Java 14 esto parece que puede cambiar gracias a la incorporación de los &lt;code&gt;record&lt;/code&gt;. No me parece mal que Java haya decidido al final adoptar lo que sus primos de la JDK (Groovy, Scala, Kotlin,...) ya tienen desde su nacimiento. &lt;code&gt;&amp;lt;/ironic&amp;gt;&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;¡ah! pero siendo fácil podemos repasar antes una barbaridad.&lt;/p&gt;

&lt;h1&gt;
  
  
  Un mal ejemplo
&lt;/h1&gt;

&lt;p&gt;El problema: necesitas un objeto que no pueda modificarse.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Solución adecuada: pasar copias del objeto, o crear el objeto como inmutable. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Solución "creativa" 🙀, crear un interfaz que tenga sólo métodos para lectura y pasar el interfaz a los consumidores.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Básicamente, en lugar de usar el lenguaje usas tu imaginación. 🤦🏻&lt;/p&gt;

&lt;p&gt;Esta solución creativa implica que usaremos un interfaz -que define comportamiento o un contrato de un servicio- para lo que viene a ser un objeto de dominio o un DTO si lo usamos entre capas. &lt;/p&gt;

&lt;p&gt;Es más que rara porque además pasando el interfaz "de setters" perdemos poder serializar el elemento&lt;/p&gt;

&lt;h4&gt;
  
  
  Una solución de bombero jubilado.
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;¡mis ojos! ¡mis ojos!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Creamos un objeto &lt;code&gt;Something&lt;/code&gt; que será donde estén los datos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Something implements SomethingContext {

    @Getter @Setter String somethingId;

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;y cuando queremos usarlo pasamos &lt;code&gt;SomethingContext&lt;/code&gt; y sí, lo has adivinado, la barbaridad es que lo pasarás haciendo un downcasting del objeto al interfaz.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public interface SomethingContext {
    String getSomethingId(); // HORROR!
    ... muchos más getters
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;👉 este modo de ataque y crítica &lt;em&gt;nunca debe ser usado en situaciones reales&lt;/em&gt;, es una falta de respeto y no ayuda ni a mejorar a quien lo hizo mal, ni a quien lo utiliza. Es usado aquí como  recurso literario, y me permito la licencia porque fui yo quien hizo esta &lt;em&gt;escabechina&lt;/em&gt; en un proyecto hace algunos años. 🥳 &lt;/p&gt;

&lt;h1&gt;
  
  
  Varias formas simples y correctas de tener inmutabilidad
&lt;/h1&gt;

&lt;h2&gt;
  
  
  En Java
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Lombok
&lt;/h3&gt;

&lt;p&gt;Puedes hacerlo a mano, está muy bien explicado en la documentación de la misma Oracle™, pero es que es mucho más sencillo con Lombok.&lt;/p&gt;

&lt;p&gt;En lombok la anotación &lt;code&gt;@Value&lt;/code&gt; implica que el objeto sólo puede ser leido tras su construcción. Es el hermano mayor de &lt;code&gt;@Data&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Value
class Something {  
    String somethingId;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;No podrás más que leer objetos, no puedes alterar su valor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Immutable
&lt;/h3&gt;

&lt;p&gt;También tenemos la librería &lt;a href="https://immutables.github.io"&gt;Immutable&lt;/a&gt;   que ayuda en Java a crear objetos inmutables. &lt;/p&gt;

&lt;p&gt;El problema de Lombok y de Immutable es que incorporamos librerías para un concepto que creo debería resolver el lenguaje y bueno, en modo estricto por ejemplo en arquitecturas hexagonales he encontrado gente que dice que en el modelo (dominio) debe ser tan puro que no deberíamos introducir ni siquiera estas utilidades.&lt;/p&gt;

&lt;p&gt;Así que vamos a un lenguaje que tiene la inmutabilidad en su ADN.&lt;/p&gt;

&lt;p&gt;Por ejemplo, por ejemplo,...&lt;/p&gt;

&lt;h1&gt;
  
  
  Kotlin
&lt;/h1&gt;

&lt;p&gt;Llegamos a la solución más elegante y flexible con Kotlin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data class Person (val name: String, 
                   val surname: String, 
                   val gender: String)

val earroyoron = Person(name="Ernesto",surname="Arroyo",gender="Male")
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;En Kotlin este objeto es inmutable. Si necesitamos modificarlo, no podemos. Y esto nos evita muchos problemas. &lt;/p&gt;

&lt;p&gt;Además de paso te he mostrado otras &lt;em&gt;cositas chulas&lt;/em&gt; del lenguaje como son los parámetros con nombre en el constructor.&lt;/p&gt;

&lt;p&gt;Pero algo que no puede cambiar &lt;em&gt;nunca&lt;/em&gt; tampoco es muy util así que, ¿que hacemos cuando va cambiando el estado?&lt;/p&gt;

&lt;p&gt;En un estilo de programación funcional lo que se hace es una copia modificada, que no altera el original. Esto es muy fácil y nos lo ofrece el mismo lenguaje (y no, ¡ni se te ocurra pensar en el &lt;code&gt;clone&lt;/code&gt; de Java!)&lt;/p&gt;

&lt;p&gt;En Kotlin para tener una copia basada en el anterior objeto hacemos esto, por ejemplo pongamos que pudiera recuperar como primer apellido el hermoso segundo apellido de mi padre:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data class Person (val name: String, val surname: String, val gender: String)

fun main() {
    val earroyoron = Person(name="Ernesto",surname="Arroyo",gender="Male")
    val egarciadelasheras = earroyoron.copy(surname="Garcia de las Heras")
    println (earroyoron)
    println (egarciadelasheras)
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Veremos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Person(name=Ernesto, surname=Arroyo, gender=Male)
Person(name=Ernesto, surname=Garcia de las Heras, gender=Male)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Voy a concluir aquí este pequeño repaso inicial a la inmutabilidad. &lt;/p&gt;

&lt;p&gt;Si hay una segunda parte deberíamos entrar a ver como trabajar con Kotlin de forma mucho más potente usando sus &lt;code&gt;sealed class&lt;/code&gt; y empezaremos a pensar en modo funcional con los tipos de datos algebraicos o las ópticas,....&lt;/p&gt;

</description>
      <category>functional</category>
      <category>kotlin</category>
    </item>
    <item>
      <title>Be a boring and lazy developer </title>
      <dc:creator>Ernesto λrroyo</dc:creator>
      <pubDate>Wed, 11 Sep 2019 17:27:06 +0000</pubDate>
      <link>https://dev.to/earroyoron/be-a-boring-and-lazy-developer-3o3m</link>
      <guid>https://dev.to/earroyoron/be-a-boring-and-lazy-developer-3o3m</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclaimer:&lt;/em&gt; sorry for abusing the term as boring is mentioned too many times in this boring article!&lt;/p&gt;

&lt;h1&gt;
  
  
  Boring code and architectures
&lt;/h1&gt;

&lt;p&gt;We have acronyms as SOLID, INVEST, KISS, DRY,... I made one on myself: &lt;em&gt;BORING&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;And what does BORING acronym means? Well, really not an acronym, is just boring. Aburrido. Ennuyeux.&lt;/p&gt;

&lt;p&gt;Because I am thinking, no, not thinking,... &lt;em&gt;I solemnly state that boring code and architectures are the most important development principle.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That good code should be mostly boring. Maybe I'll write a manifesto...&lt;/p&gt;

&lt;h1&gt;
  
  
  How to boring
&lt;/h1&gt;

&lt;p&gt;The key for boring code is using the right abstractions, tools and idioms.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There's no problem in Computer Science that can't be solved by adding another layer of abstraction to it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Cool or creative code is seldom needed. We should be honest: 99% of our problems are not a new deep learning library or controlling a spaceship; most of us develop a REST API, database access, we filter lists, validate inputs,... in this areas the business problems are the hard and complex  thing, but the technologies to apply are not R&amp;amp;D.&lt;/p&gt;

&lt;h1&gt;
  
  
  Also be lazy
&lt;/h1&gt;

&lt;p&gt;Lazy developers find a way to do things easier and, yes, boring.&lt;/p&gt;

&lt;h1&gt;
  
  
  Standing on the shoulders of giants
&lt;/h1&gt;

&lt;p&gt;The key point is that creating really boring code and architectures is not easy.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Law of Leaky Abstractions
&lt;/h2&gt;

&lt;p&gt;The important thing is to master the abstractions, language idioms, tools and architecture principles. &lt;/p&gt;

&lt;p&gt;Ah! don't underestimate the abstractions. Because abstractions have leaks as Spolsky explain &lt;a href="https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And people don't mastering abstractions are dangerous: they fail, do "cool" things, clever but not clean code and such things.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overengineer
&lt;/h2&gt;

&lt;p&gt;All engineer will have a dangerous trend to over-engineer &lt;br&gt;
and apply "all the tools I know"...&lt;/p&gt;

&lt;p&gt;Well, at the end doing BORING code is not easy!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://medium.com/@rdsubhas/10-modern-software-engineering-mistakes-bc67fbef4fc8#577d"&gt;Overzealous Adopter Syndrome&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Bacause of this I have seen tremendous generic abuse, optional misusage,&lt;br&gt;
weird functional interfaces, model entities in libraries or&lt;br&gt;
maven module-abuse, or reimplementing RFCs intead of search &lt;br&gt;
for the proper library...&lt;/p&gt;

&lt;h1&gt;
  
  
  Finally
&lt;/h1&gt;

&lt;p&gt;Actually, the key is be boring and a bit lazy and at the same&lt;br&gt;
time use just the minimal needed toolset without beeing &lt;br&gt;
a cowboy.&lt;/p&gt;

&lt;p&gt;So you have to learn a lot, read a lot of blogs, books, and go to a huge number of conferences and beeing all the they preparing just for...&lt;/p&gt;

&lt;p&gt;DOING YOUR CODE AND ARCHITECTURE A BORING THING.&lt;/p&gt;

&lt;p&gt;Yes, that is the hard part of an architect/engineer.&lt;/p&gt;

&lt;h2&gt;
  
  
  A list of boring things
&lt;/h2&gt;

&lt;p&gt;This&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Boring architectures as hexagonal.&lt;/li&gt;
&lt;li&gt;Boring frameworks: as Spring Boot.&lt;/li&gt;
&lt;li&gt;Your language collections and idioms.&lt;/li&gt;
&lt;li&gt;Boring tools as lombok, apache, mapstruts,...&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>productivity</category>
      <category>career</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Kotlin for better helper methods</title>
      <dc:creator>Ernesto λrroyo</dc:creator>
      <pubDate>Thu, 05 Sep 2019 12:25:41 +0000</pubDate>
      <link>https://dev.to/earroyoron/kotlin-for-better-helper-methods-256c</link>
      <guid>https://dev.to/earroyoron/kotlin-for-better-helper-methods-256c</guid>
      <description>&lt;p&gt;When implementing helper classes in Kotlin you can, compared to Java, take advantage of a less verbose and more powerful idiomatic style.&lt;/p&gt;

&lt;p&gt;Let’s check this easy &lt;em&gt;but verbose&lt;/em&gt; Java example; the method body is not important...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.earroyoron.helpers;

public class EarroyoronHelper {

/* A private constructor to avoid class instantiation */
 private EarroyoronHelper() {}

/* Just some helper method */
 public static String doSomething
 (final String a, final String b) {
 //.... whatever
   return a + " and then " + b;
 }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Too many things just for such a simple thing, isn’t it?&lt;/p&gt;

&lt;p&gt;The Kotlin version just shows &lt;em&gt;what a modern language is&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.earroyoron.helpers

/* Just some helper method */
 fun andThen (a: String, b: String): String {
 return"$a and then $b"
 }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We don’t need things that, actually, does not add value or improve the intention or readiness.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Of course the ; that is useless&lt;/li&gt;
&lt;li&gt;The class, as we will not instantiate it. Kotlin adds the function (method) to the package namespace. You can import as:
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;import io.earroyoron.helpers.andThen&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;the method could indeed return directly the response as in:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;fun andThen (a: String, b: String) = "$a and then $b"&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Even better with extensions
&lt;/h2&gt;

&lt;p&gt;A better version uses class extensions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package io.earroyoron.helpers

fun String.doSomeTransformation (b: String) = "$this and then $b"
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So you can call this helper as:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;"original string".andThen ("more letters")&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  infix
&lt;/h2&gt;

&lt;p&gt;or if you add infix to the function ( infix fun ) to improve as a DSL style:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;infix fun String.doSomeTransformation (b: String) = "$this and then $b"

val sillyString = "original string" andThen "more letters"

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is the most kotlin idiomatic way; you may use object to instantiate a singleton, or companion class to have an static block in a not-singleton class but both are not the perfect way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Functional style
&lt;/h2&gt;

&lt;p&gt;As you are not creating the object and the method is just an static one, with only depending on the input parameters to produce the results you are using a functional style. Is a plus.&lt;/p&gt;

</description>
      <category>kotlin</category>
    </item>
    <item>
      <title>Utilizar la propiedad revision con maven para mantener coherencia de versiones</title>
      <dc:creator>Ernesto λrroyo</dc:creator>
      <pubDate>Mon, 02 Sep 2019 13:19:25 +0000</pubDate>
      <link>https://dev.to/earroyoron/utilizar-revision-con-maven-para-mantener-coherencia-de-versiones-4ih8</link>
      <guid>https://dev.to/earroyoron/utilizar-revision-con-maven-para-mantener-coherencia-de-versiones-4ih8</guid>
      <description>&lt;p&gt;Como pequeña ampliación a mi anterior artículo &lt;a href="https://dev.to/earroyoron/la-forma-correcta-de-versionar-y-establecer-dependencias-4499"&gt;la forma correcta de versionar y establecer dependencias&lt;/a&gt; voy a indicar una ayuda que tenemos en maven, a partir de la versión 3.5.0&lt;/p&gt;

&lt;p&gt;En esta herramienta de construcción podemos indicar una propiedad &lt;code&gt;revision&lt;/code&gt; y usarla en el &lt;em&gt;parent&lt;/em&gt; y heredarla en todos los módulos &lt;em&gt;hijo&lt;/em&gt; de forma que podemos aplicar facilmente el principio de &lt;em&gt;coherencia en el versionado del despliegue&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Esto es en el parent pondríamos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  &amp;lt;groupId&amp;gt;io.earroyoron&amp;lt;/groupId&amp;gt;
  &amp;lt;artifactId&amp;gt;project-parent&amp;lt;/artifactId&amp;gt;
  &amp;lt;packaging&amp;gt;pom&amp;lt;/packaging&amp;gt;
  &amp;lt;version&amp;gt;${revision}&amp;lt;/version&amp;gt;
  &amp;lt;properties&amp;gt;
    &amp;lt;revision&amp;gt;1.3.0&amp;lt;/revision&amp;gt;
  &amp;lt;/properties&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;y en los módulos por debajo indicaremos  esa propiedad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  &amp;lt;parent&amp;gt;
    &amp;lt;groupId&amp;gt;io.earroyoron&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;project-parent&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;${revision}&amp;lt;/version&amp;gt;
  &amp;lt;/parent&amp;gt;

  &amp;lt;groupId&amp;gt;io.earroyoron&amp;lt;/groupId&amp;gt;
  &amp;lt;artifactId&amp;gt;child-module-a&amp;lt;/artifactId&amp;gt;
  &amp;lt;version&amp;gt;${revision}&amp;lt;/version&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;La ventaja principal es, como indico, mantener la &lt;strong&gt;coherencia de versiones&lt;/strong&gt; que sería 1.3.0 en todos los componentes por debajo de ese parent (como debe ser).&lt;/p&gt;

&lt;p&gt;Para quien tenga dudas de si esta es la forma correcta, que se mire el código fuente de, por ejemplo, Spring Boot, que utiliza este esquema.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Y los BOM?
&lt;/h2&gt;

&lt;p&gt;Mi antiguo compañer y amigo &lt;a href="https://twitter.com/cedillomarcos"&gt;Marcos Martínez @cedillomarcos&lt;/a&gt; me recordó que el uso de un BOM también es imprescindible en la gestión de versiones con &lt;em&gt;Maven&lt;/em&gt; pero voy a dejar este tema abierto para un próximo artículo.&lt;/p&gt;

</description>
      <category>maven</category>
    </item>
    <item>
      <title>La forma correcta de versionar y establecer dependencias </title>
      <dc:creator>Ernesto λrroyo</dc:creator>
      <pubDate>Sun, 01 Sep 2019 10:35:47 +0000</pubDate>
      <link>https://dev.to/earroyoron/la-forma-correcta-de-versionar-y-establecer-dependencias-4499</link>
      <guid>https://dev.to/earroyoron/la-forma-correcta-de-versionar-y-establecer-dependencias-4499</guid>
      <description>&lt;p&gt;A la hora de definir la estructura de un proyecto la forma de establecer dependencias y relaciones es un paso crítico. Debes conocer y respetar algunas reglas importantes y, cuando no las cumplas, debes ser consciente de porque has tomado esa decisión y los posibles problemas que enfrentaras.&lt;/p&gt;

&lt;p&gt;Montar un proyecto "de cualquier forma" puede llevar a problemas de dependencias cruzadas, extraños flujos de construcción, código repetido por no poder reutilizar o incluso, a que un servicio dependa de cosas de las que no debería provocando errores posteriores muy complicados de resolver.&lt;/p&gt;

&lt;p&gt;En este artículo uso las definiciones del libro "Clean Architecture" de &lt;br&gt;
Robert C. Martin".&lt;/p&gt;
&lt;h1&gt;
  
  
  Tres principios
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Mantener coherencia en el versionado del despliegue&lt;/li&gt;
&lt;li&gt;Mantener un conjunto común (common-closure)&lt;/li&gt;
&lt;li&gt;El principio de la reutilización&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Mantener la equivalencia por uso en el despliegue
&lt;/h2&gt;

&lt;p&gt;(Reuse/Release Equivalence Principle)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The granule of reuse is the the granule of release&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Como primer &lt;em&gt;principio general&lt;/em&gt; debemos decir que "las clases y módulos que van en el mismo despligue deben tener la misma versión y también deben tenerse juntos en la misma versión de la documentación porque eso mantiene la coherencia para el autor y los usuarios".&lt;/p&gt;

&lt;p&gt;Debes observar que estoy hablando de un "principio" de forma que no es una ley cerrada, y puede tener sus excepciones pero ten en cuenta que las excepciones al Principio de uso y despliegue se ven rapidamente y "cantan" mucho, así que debes estar preparado para saber explicar tus razones para hacerlo de esa forma.&lt;/p&gt;

&lt;p&gt;Si construyes un proyecto maven donde el parent es:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;io.earroyoron:parent:1.0.0
|
 \__ io.earroyoron:moduleA:1.3.3
| 
 \__ io.earroyoron:moduleB:1.5.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;pero que incluye dos módulos y que al contruirlo se generan dos artefactos: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;io.earroyoron:moduleA:1.3.3&lt;/code&gt;&lt;br&gt;
y&lt;br&gt;
&lt;code&gt;io.earroyoron:moduleB:1.5.0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;estás incumpliendo este bello principio y montando un hermoso cacao de versionado. &lt;/p&gt;

&lt;p&gt;Porque si tienes un cambio en el móduloB tendrás que desplegar una versión nueva del módulo B (quizás 2.0.0 porque era un cambio que rompia compatibilidad) y ¿qué versión tendrás en el módulo parent? ¿mantienes como 1.0.0? no tiene sentido porque moduloB está en un &lt;em&gt;major&lt;/em&gt; distinto ¿y 1.x.x? no, el módulo A no está en ese &lt;em&gt;major version&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;En general, y salvo casos muy, muy, pero muy claros, el parent y sus hijos deben tener la misma version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;io.earroyoron:parent:1.0.0
|
 \__ io.earroyoron:moduleA:&amp;lt;parent-version&amp;gt;
| 
 \__ io.earroyoron:moduleB:&amp;lt;parent-version&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Mantener un conjunto común
&lt;/h2&gt;

&lt;p&gt;(Common Closure Principle)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Gather into components those classes that change for the same reason and the same times. Separate into different components those classes that change at different times for different reasons&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Puesto que para la mayoría de las aplicaciones es más importante el mantenimiento y la facilidad de despliegue que la reutilización es mejor tener en un sitio común el código que queremos cambiar.&lt;/p&gt;

&lt;p&gt;No es buena idea que un cambio en un módulo X nos obligue a contruir tres librerias que hemos construido de forma aislada cuando ese cambio sólo afecta al módulo X y es provocado por un requisito del módulo X. Lo correcto es que el contenido de ese otro módulo esté junto en el mismo sitio.&lt;/p&gt;

&lt;p&gt;Volviendo a nuestro anterior ejemplo, moduleA y moduleB están juntos en el mismo sitio y bajo el mismo parent porque cambian a la vez de versión por la misma razón. Es decir, dado que un cambio en moduleA de la versión 1.3.4 a, digamos, la versión 1.4.0 obliga a que el móduloB también pase a la versión 1.4.0 este segundo principio nos dice que es correcto porque el cambio afecta a ambos módulos y su versión.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separar para priorizar la reutilización
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Don't force users of a component to depend on things they don't need&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;El tercer principio es contrario a los dos anteriores. Basicamente indica que separes en módulos diferentes las cosas que son diferentes para que los clientes que declaran una determinada dependencia sólo se traigan lo que realmente requieren.&lt;/p&gt;

&lt;p&gt;O dicho de otro modo, no tener que importar un enorme librería de 7 terabytes si sólo necesito una función muy concreta de esa librería.&lt;/p&gt;

&lt;p&gt;Es un principio contrario a los anteriores porque nos está empujando a romper y separar en muchas piezas nuestros componentes para tener un grano muy fino a la hora de declarar las dependencias.&lt;/p&gt;

&lt;p&gt;En el ejemplo, si otro módulo necesita importar moduleA pero sólo necesita una mínima parte de él quizas la estructura debería separar en otro módulo esa pequeña parte para facilitar la reutilización:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;io.earroyoron:parent:1.0.0
|
 \__ io.earroyoron:module-min-A1:&amp;lt;parent-version&amp;gt;
|
 \__ io.earroyoron:module-A2:&amp;lt;parent-version&amp;gt;
| 
 \__ io.earroyoron:moduleB:&amp;lt;parent-version&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;El problema es que llevado al extremo este principio genera más problemas en los despliegues que los beneficios que trae por reutilización. &lt;/p&gt;

&lt;h2&gt;
  
  
  Tensiones
&lt;/h2&gt;

&lt;p&gt;Los 3 principios o reglas establecen un modelo de lucha y tensión. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7KipMyoY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/vskvtfncaas64bzv74dt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7KipMyoY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/vskvtfncaas64bzv74dt.png" alt="Tensiones"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Si nos enfocamos a separar en muchos componentes pequeños (el 3er principio) agrupados en un versionado común de despliegue (1) vamos estar sacando versiones innecesarias de librerias que no lo necesitan ante el más mínimo y superfluo cambio en alguno de sus elementos:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Demasiado enfoque en reutilizar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;io.earroyoron:parent:1.0.0
|
 \__ io.earroyoron:module-A:&amp;lt;parent-version&amp;gt;
|
 \__ io.earroyoron:module-B1:&amp;lt;parent-version&amp;gt;
|
 \__ io.earroyoron:module-B2:&amp;lt;parent-version&amp;gt;
|
 \__ io.earroyoron:module-C1:&amp;lt;parent-version&amp;gt;
|
 \__ io.earroyoron:module-C2:&amp;lt;parent-version&amp;gt;
|
 \__ io.earroyoron:module-D:&amp;lt;parent-version&amp;gt;
|
 \__ io.earroyoron:module-E1:&amp;lt;parent-version&amp;gt;
| 
 \__ io.earroyoron:module-E2:&amp;lt;parent-version&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Si obviamos el principio de mantener el versionado coherente en el despliegue y sólo nos enfocamos en los otros dos principios (2,3)d nuestras releases tendrán versiones "de su padre y de su madre" y haremos muy complicado el modelo de dependencias.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;io.earroyoron:parent:1.0.0
|
 \__ io.earroyoron:module-A:1.2.3
|
 \__ io.earroyoron:module-B1:2.5.3
|
 \__ io.earroyoron:module-B2:2.5.3
|
 \__ io.earroyoron:module-C1:2.0.0
|
 \__ io.earroyoron:module-C2:2.0.0
|
 \__ io.earroyoron:module-D:1.1.1
|
 \__ io.earroyoron:module-E1:1.1.1
| 
 \__ io.earroyoron:module-E2:1.1.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Finalmente, si sólo nos centramos en mantener un versionado coherente (1) y agrupar las cosas (2) vamos a tener más complicado o imposible la reutilización por terceros de nuestros componentes.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;io.earroyoron:parent:1.0.0
|
 \__ io.earroyoron:module-A:&amp;lt;parent-version&amp;gt;
|
 \__ io.earroyoron:module-B:&amp;lt;parent-version&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;La mayoría de los casos deben primar los principios de versionado común y agrupar por responsabilidades comunes (1 y 2) y dejar la reutización para más adelante ya que suele ser un anti-patrón de optimización prematura que lleva a muchos problemas.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
    </item>
    <item>
      <title>El Teorema CAP: porqué los bancos usan mainframes.</title>
      <dc:creator>Ernesto λrroyo</dc:creator>
      <pubDate>Mon, 21 Jan 2019 19:36:10 +0000</pubDate>
      <link>https://dev.to/earroyoron/el-teorema-cap-porque-los-bancos-usan-mainframes-hap</link>
      <guid>https://dev.to/earroyoron/el-teorema-cap-porque-los-bancos-usan-mainframes-hap</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Una unidad central (en inglés &lt;strong&gt;mainframe&lt;/strong&gt; ) es una computadora grande, potente y costosa, usada principalmente por una gran compañía para el procesamiento de una gran cantidad de datos, como por ejemplo, para el procesamiento de transacciones bancarias. Wikipedia&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F512%2F1%2AbREmhWLPjORa91BP1b5SZw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F512%2F1%2AbREmhWLPjORa91BP1b5SZw.jpeg"&gt;&lt;/a&gt;&lt;a href="https://www.google.es/url?sa=i&amp;amp;rct=j&amp;amp;q=&amp;amp;esrc=s&amp;amp;source=images&amp;amp;cd=&amp;amp;cad=rja&amp;amp;uact=8&amp;amp;ved=2ahUKEwjmkZ-Zz__fAhXFyYUKHQ4FDAkQjhx6BAgBEAM&amp;amp;url=https%3A%2F%2Fwww.datacenterknowledge.com%2Fhardware%2Fwhy-mainframes-arent-going-away-any-time-soon&amp;amp;psig=AOvVaw3Td7XWjLJt-7Pl91WmGnve&amp;amp;ust=1548185654744026" rel="noopener noreferrer"&gt;Why Mainframes Are Still Part of IBM’s Backbone | Data Center Knowledge&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Antes de empezar hay que deshacer un mito: los mainframes ya no son dinasaurios con tecnologías obsoletas, cintas dando vueltas y tarjetas perforadas. Eso es falso. Los sistemas mainframes modernos también ejecutan bajo Linux, y soportan sistemas relacionales como Oracle y lenguajes modernos. &lt;/p&gt;

&lt;p&gt;Lo que diferencia un mainframe es el hardware: son enormes bestias de procesamiento y unos monstruos en su capacidad de entrada/salida. Y no son baratos ni flexibles.&lt;/p&gt;

&lt;p&gt;Puede que algunos se pregunten por qué los bancos no cambian estos sistemas por componentes mucho más baratos, lo que viene a ser un sistema de computación distribuida donde está claro que podemos escalar de forma mucho más económica e incluso podemos ser elásticos y reducir potencia si no necesitamos tanto hierro en determinado momento.&lt;/p&gt;

&lt;p&gt;A mi, tras empezar a conocer un poco mejor el tema de arquitecturas distribuidas me ha venido una razón muy clara, pero no he encontrado este mismo razonamiento en otro sitio; cuando te venden las ventajas de estos sistemas te hablan del TCO, del ahorro,… no te hablan de esto.&lt;/p&gt;

&lt;h4&gt;
  
  
  La Conjetura de Brewer
&lt;/h4&gt;

&lt;p&gt;En 2000 Eric Brewer enunció una Conjetura que sostenía que cuando lo que tienes es un &lt;strong&gt;sistema distribuido&lt;/strong&gt; es imposible garantizar de forma simultanea la &lt;strong&gt;consistencia&lt;/strong&gt; de la información, la &lt;strong&gt;disponibilidad&lt;/strong&gt; del sistema completo y el particionado (esto es, la &lt;strong&gt;tolerancia&lt;/strong&gt; a seguir operando en caso de fallo de algún nodo).&lt;/p&gt;

&lt;p&gt;En un sistema distribuido, por definición, tenemos partición ya que es el concepto mismo de sistema distribuido.&lt;/p&gt;

&lt;p&gt;Por tanto debe elegirse si quieres tener &lt;strong&gt;consistencia de información&lt;/strong&gt; (todos los nodos ven la misma información en el mismo orden en cualquier momento) o quieres asegurar &lt;strong&gt;disponibilidad del sistema&lt;/strong&gt; (algún nodo puede tener información distinta y ya los pondremos de acuerdo, esto es consistencia eventual, pero el sistema siempre responde).&lt;/p&gt;

&lt;h4&gt;
  
  
  El Teorema CAP
&lt;/h4&gt;

&lt;p&gt;La Conjetura de Brewer pasó a ser un teorema demostrado matemáticamente en 2002 (Nancy Lynch and Seth Gilbert, &lt;a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.20.1495&amp;amp;rep=rep1&amp;amp;type=pdf" rel="noopener noreferrer"&gt;“Brewer’s conjecture and the feasibility of consistent, available, partition-tolerant web services”&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Sí, &lt;em&gt;hay una demostración matemática&lt;/em&gt;. Osea que siempre que estés usando un sistema de computación distribuida, o elijes consistencia, o elijes disponibilidad.&lt;/p&gt;

&lt;p&gt;En un sitio web como Amazon probablemente prefieran disponibilidad: si un producto no tiene stock porque el nodo tenía información no actualizada en ese momento, ya lo solucionarán, pero nada de una pantalla de indisponibilidad. Aquí queremos vender mucho.&lt;/p&gt;

&lt;p&gt;Quizás un sistema de información de otro tipo prefiere consistencia. Si no estamos seguros de tener información correcta esperamos a que los nodos se puedan encontrar en el mismo estado, y puedo permitirme esa espera en que la información esté consistente.&lt;/p&gt;

&lt;h4&gt;
  
  
  Entonces ¿qué pasa con los bancos?
&lt;/h4&gt;

&lt;p&gt;Pues ocurre que &lt;em&gt;los bancos no pueden renunciar a la consistencia ni a la disponibilidad.&lt;/em&gt; No podemos anotar operaciones más que en un orden y en un sólo sitio debe tenerse la información. La operación debe garantizar la consistencia fuerte (&lt;em&gt;strong consistency: All accesses are seen by all parallel processes in the same order — sequentially&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;Tampoco podemos dejar de dar servicio 24x7 porque un nodo se haya caído o tenga un tiempo de espera por el que, el resto, deba dejar de atender hasta encontrar un estado consistente (en sistemas distribuidos se puede garantizar la consistencia fuerte si esperamos a que los nodos se trasladen un ACK de haberse puesto en la misma versión de la información, pero nosotros no podemos esperar)&lt;/p&gt;

&lt;p&gt;Osea que esto, según el teorema CAP es imposible,… en sistemas distribuidos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F602%2F1%2Atnc2D208JbgzQnCWd0b7lQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F602%2F1%2Atnc2D208JbgzQnCWd0b7lQ.png"&gt;&lt;/a&gt;Los sistemas distribuidos son complicados.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;La única solución es no tener sistemas distribuidos&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;En una empresa normal diríamos que tenemos una base de datos centralizando la información, lo de toda la vida, pero es que en un banco no hablamos de un sistema normal, es que estamos hablando de un sistema de gestión de información de enorme capacidad de procesamiento y entrada/salida. Esto es lo que ofrece un sistema &lt;em&gt;mainframe&lt;/em&gt;, los &lt;em&gt;big-iron:&lt;/em&gt; una locura de procesamiento y una disponibilidad casi completa en un nodo centralizado que asegura consistencia fuerte (strong consistency).&lt;/p&gt;

&lt;p&gt;El nodo debe ser capaz de soportar un enorme número de transacciones, enorme (sí, esas compras navideñas o del Black Friday, todas anotándose en el mainframe) y debe tener una disponibilidad absoluta (ni caerse, ni perder datos).&lt;/p&gt;

&lt;p&gt;Por eso las arquitecturas de los mainframes escalan de forma vertical, con sistemas de procesamiento de E/S que nada tienen que ver con los ordenadores normales (las tarjetas de E/S tienen CPUs dedicadas).&lt;/p&gt;




</description>
      <category>architecture</category>
      <category>distributedsystems</category>
      <category>spanish</category>
    </item>
  </channel>
</rss>
