{"id":671828,"date":"2025-12-31T18:01:47","date_gmt":"2025-12-31T17:01:47","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=kotlin&#038;p=671828"},"modified":"2025-12-31T18:01:52","modified_gmt":"2025-12-31T17:01:52","slug":"aumentar-la-adopcion-de-kotlin-en-su-empresa","status":"publish","type":"kotlin","link":"https:\/\/blog.jetbrains.com\/es\/kotlin\/2025\/12\/aumentar-la-adopcion-de-kotlin-en-su-empresa\/","title":{"rendered":"Aumentar la adopci\u00f3n de Kotlin en su empresa"},"content":{"rendered":"<p><em>Art\u00edculo de <a href=\"https:\/\/www.linkedin.com\/in\/urs-peter-70a2882\/\" target=\"_blank\" rel=\"noreferrer noopener\" data-type=\"link\" data-id=\"https:\/\/bit.ly\/urs-peter-linked-in\">Urs Peter<\/a>, ingeniero de software s\u00e9nior y formador de Kotlin certificado por JetBrains. Para los lectores que busquen una forma m\u00e1s estructurada de desarrollar sus habilidades en Kotlin, Urs tambi\u00e9n dirige el <\/em><a href=\"https:\/\/academy.xebia.com\/upskilling\/kotlin-academy\/\" target=\"_blank\" rel=\"noreferrer noopener\"><em>Kotlin Upskill Program<\/em><\/a><em> en Xebia Academy.<\/em><\/p>\n<p><em>Este es el tercer art\u00edculo de <\/em><strong><em>La gu\u00eda definitiva para adoptar Kotlin en un entorno dominado por Java<\/em><\/strong><em>, una serie que sigue c\u00f3mo crece la adopci\u00f3n de Kotlin entre equipos reales, desde la curiosidad de un \u00fanico desarrollador hasta la transformaci\u00f3n de toda la empresa.<\/em><\/p>\n<p><strong>Todos los art\u00edculos de la serie:<\/strong><\/p>\n<ol>\n<li><a href=\"https:\/\/blog.jetbrains.com\/kotlin\/2025\/10\/getting-started-with-kotlin-for-java-developers\/\" target=\"_blank\" rel=\"noreferrer noopener\">Introducci\u00f3n a Kotlin para desarrolladores Java<\/a><\/li>\n<li><a href=\"https:\/\/blog.jetbrains.com\/kotlin\/2025\/10\/evaluating-kotlin-in-real-projects\/\" target=\"_blank\" rel=\"noreferrer noopener\" data-type=\"link\" data-id=\"https:\/\/blog.jetbrains.com\/kotlin\/2025\/10\/evaluating-kotlin-in-real-projects\/\">Evaluaci\u00f3n de Kotlin en proyectos reales<\/a><\/li>\n<li><a href=\"https:\/\/blog.jetbrains.com\/kotlin\/2025\/11\/growing-kotlin-adoption-in-your-company\/\" target=\"_blank\" rel=\"noreferrer noopener\">Aumentar la adopci\u00f3n de Kotlin en su empresa<\/a><\/li>\n<\/ol>\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n<h2 class=\"wp-block-heading\"><strong>Corra la voz: convenza a sus colegas desarrolladores con argumentos y g\u00e1nese su coraz\u00f3n<\/strong><\/h2>\n<p>A estas alturas, ya tiene un equipo base convencido de las ventajas de Kotlin. Ahora llega la fase cr\u00edtica: \u00bfc\u00f3mo expandir la adopci\u00f3n?\u00a0<\/p>\n<p>La clave en esta fase es conquistar la mente y el coraz\u00f3n de los desarrolladores de Java esc\u00e9pticos. Los factores tangibles e intangibles pueden marcar aqu\u00ed la diferencia:<\/p>\n<p>Factores tangibles: el c\u00f3digo<\/p>\n<ul>\n<li>Deje hablar al c\u00f3digo<\/li>\n<\/ul>\n<p>Factores intangibles: apoye y conecte a los desarrolladores<\/p>\n<ul>\n<li>Facilite la incorporaci\u00f3n<\/li>\n<li>Ofrezca material de autoaprendizaje<\/li>\n<li>Establezca una comunidad interna de Kotlin<\/li>\n<li>Sea paciente\u2026<\/li>\n<\/ul>\n<h3 class=\"wp-block-heading\"><strong>Deje hablar al c\u00f3digo<\/strong><\/h3>\n<p>Aproveche la experiencia adquirida al (re)escribir una aplicaci\u00f3n en Kotlin y muestre las ventajas de forma clara y accesible:<\/p>\n<ul>\n<li><strong>No lo diga, h\u00e1galo<\/strong>: demuestre c\u00f3mo Kotlin es m\u00e1s conciso comparando fragmentos de Java con fragmentos de Kotlin.\u00a0<\/li>\n<li><strong>Tome perspectiva para centrarse en los paradigmas generales<\/strong>: Kotlin no solo es <em>diferente<\/em> de Java: Kotlin se fundamenta en la seguridad, la concisi\u00f3n para una legibilidad y mantenibilidad m\u00e1ximas, las funciones como ciudadano de primera y la posibilidad de extensi\u00f3n, que en conjunto resuelven deficiencias b\u00e1sicas de Java, sin dejar de ser totalmente interoperable con el ecosistema Java.<\/li>\n<\/ul>\n<p>Estos son algunos ejemplos tangibles:<\/p>\n<p><strong>1. Verificaci\u00f3n de valores nulos: no m\u00e1s errores multimillonarios\u00a0<\/strong><\/p>\n<p><strong>Java<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/This is why we have the billion-dollar mistake (not only in Java\u2026)\nBooking booking = null; \/\/\ud83e\udd28 This is allowed but causes:\nbooking.destination; \/\/Runtime error \ud83d\ude31\n\nOptional booking = null; \/\/Optionals aren\u2019t safe from null either: \ud83e\udd28\nbooking.map(Destination::destination); \/\/Runtime error \ud83d\ude31<\/pre>\n<p>Con el tiempo, Java ha a\u00f1adido algunas funcionalidades de verificaci\u00f3n de valores nulos, como Optional y Annotations (<code>@NotNull<\/code>, etc.), pero no ha conseguido resolver este problema fundamental. Adem\u00e1s, el proyecto <a href=\"https:\/\/openjdk.org\/projects\/valhalla\/\" target=\"_blank\" rel=\"noreferrer noopener\">Valhalla<\/a> (tipos Null-Restricted y Nullable) no introducir\u00e1 la verificaci\u00f3n de valores nulos en Java, sino que proporcionar\u00e1 m\u00e1s opciones entre las que elegir.\u00a0<\/p>\n<p><strong>Kotlin<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/Important to realize that null is very restricted in Kotlin:\nval booking:Booking? = null \/\/\u2026null can only be assigned to Nullable types \u2705\u00a0\nval booking:Booking = null \/\/null assigned to a Non-nullable types yields a Compilation error \ud83d\ude03\u00a0\n\nbooking.destination \/\/unsafely accessing a nullable type directly causes a Compilation error \ud83d\ude03\nbooking?.destination \/\/only safe access is possible\u00a0 \u2705<\/pre>\n<p>Lo bueno de la verificaci\u00f3n de valores nulos de Kotlin es que no solo es segura, sino que tambi\u00e9n ofrece una gran usabilidad. Un ejemplo cl\u00e1sico de que \u00abno se puede nadar y guardar la ropa\u00bb:<\/p>\n<p>Imaginemos que tenemos este dominio:<\/p>\n<p><strong>Kotlin<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">data class Booking(val destination:Destination? = null)\ndata class Destination(val hotel:Hotel? = null)\ndata class Hotel(val name:String, val stars:Int? = null)<\/pre>\n<p><strong>Java<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public record Booking(Optional destination) {\n\n\u00a0\u00a0\u00a0public Booking() { this(Optional.empty()); }\n\n\u00a0\u00a0\u00a0public Booking(Destination destination) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this(Optional.ofNullable(destination));\n\u00a0\u00a0\u00a0}\n}\n\npublic record Destination(Optional hotel) {\n\n\u00a0\u00a0\u00a0public Destination() { this(Optional.empty()); }\n\n\u00a0\u00a0\u00a0public Destination(Hotel hotel) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this(Optional.ofNullable(hotel));\n\u00a0\u00a0\u00a0}\n}\n\npublic record Hotel(String name, Optional stars) {\n\n\u00a0\u00a0\u00a0public Hotel(String name) {\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this(name, Optional.empty());\n\n\u00a0\u00a0\u00a0}\n\n\u00a0\u00a0\u00a0public Hotel(String name, Integer stars) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0this(name, Optional.ofNullable(stars));\n\u00a0\u00a0\u00a0}\n}<\/pre>\n<p><strong>Construcci\u00f3n de objetos<\/strong><\/p>\n<p><strong>Java<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/Because Optional is a wrapper, the number of nested objects grows, which doesn\u2019t help readability\nfinal Optional booking = Optional.of(new Booking(\n      Optional.of(new Destination(Optional.of(\n            new Hotel(\"Sunset Paradise\", 5))))));<\/pre>\n<p><strong>Kotlin<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/Since nullability is part of the type system, no wrapper is needed: The required type or null can be used.\u00a0\nval booking:Booking? = Booking(Destination(Hotel(\"Sunset Paradise\", 5)))<\/pre>\n<p><strong>Recorrido por objetos anidados<\/strong><\/p>\n<p><strong>Java<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/traversing a graph of Optionals requires extensive unwrapping\nfinal var stars = \"*\".repeat(booking\n\u00a0\u00a0                        .flatMap(Booking::getDestination)\n                          .flatMap(Destination::getHotel)\n                          .map(Hotel::getStars).orElse(0)); \/\/-&gt; \"*****\"<\/pre>\n<p><strong>Kotlin<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/Easily traverse a graph of nullable types with: \u2018?\u2019, use\u00a0 ?: for the \u2018else\u2019 case.\nval stars = \"*\".repeat(booking?.destination?.hotel?.stars ?: 0) \/\/-&gt; \"*****\"<\/pre>\n<p><strong>Desenvoltura de objeto anidado<\/strong><\/p>\n<p><strong>Java<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/extensive unwrapping is also needed for printing a leaf\u00a0\nbooking.getDestination()\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.flatMap(Destination::getHotel)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.map(Hotel::getName)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.map(String::toUpperCase)\n\u00a0\u00a0\u00a0      .ifPresent(System.out::println);<\/pre>\n<p><strong>Kotlin<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/In Kotlin we have two elegant options:\n\/\/1. we can again traverse the graph with \u2018?\u2019\nbooking?.destination?.hotel.?name?.uppercase()?.also(::println)\n\n\/\/2. We can make use of Kotlin\u2019s smart-cast feature\nif(booking?.destination?.hotel != null) {\n\u00a0\u00a0\u00a0\/\/The compiler has checked that all the elements in the object graph are not null, so we can access the elements as if they were non-nullable types\n\u00a0\u00a0\u00a0println(booking.destination.hotel.uppercase())\n}<\/pre>\n<p>La falta de compatibilidad con la verificaci\u00f3n de valores nulos en Java es un punto candente clave para los desarrolladores, lo que lleva a una programaci\u00f3n defensiva, a diferentes construcciones de nulabilidad (o a ninguna en absoluto), incluso a un aumento de la verbosidad. Adem\u00e1s, las NullPointerExceptions son responsables de aproximadamente un tercio de los fallos de las aplicaciones (<a href=\"https:\/\/blog.jetbrains.com\/kotlin\/2020\/11\/productive-server-side-development-with-kotlin-stories\/\" target=\"_blank\" rel=\"noreferrer noopener\">The JetBrains Blog<\/a>). La comprobaci\u00f3n de nulos en tiempo de compilaci\u00f3n de Kotlin evita por completo estos fallos en tiempo de ejecuci\u00f3n. Por eso, todav\u00eda hoy, la <strong>verificaci\u00f3n de valores nulos es el principal motor de la migraci\u00f3n a Kotlin<\/strong>.<\/p>\n<p><strong>2. Las colecciones son sus aliadas, no sus enemigas<\/strong><\/p>\n<p>El creador de Spring, Rod Johnson, declar\u00f3 en una entrevista reciente que no fueron los tipos anulables lo que le hizo probar Kotlin, sino la excesivamente complicada API Java Streams: <a href=\"https:\/\/youtu.be\/Rx3XZoqbi78?t=1018\" target=\"_blank\" rel=\"noreferrer noopener\">Creador de Spring: sin ganas de escribir Java<\/a>.\u00a0<\/p>\n<p>El siguiente ejemplo muestra las diversas razones por las que la API Java Streams es tan terriblemente complicada y c\u00f3mo Kotlin resuelve todos los problemas:<\/p>\n<p><strong>Java<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public record Product(String name, int... ratings){}\nList products = List.of(\n\u00a0\u00a0new Product(\"gadget\", 9, 8, 7),\u00a0\n\u00a0\u00a0new Product(\"goody\", 10, 9)\n);\n\nMap maxRatingsPerProduct =\n\n\u00a0\u00a0\u00a0\/\/\ud83e\udd28 1. Stream introduces indirection\n\u00a0\u00a0\u00a0products.stream()\n\u00a0\u00a0\u00a0\u00a0\u00a0\/\/\ud83e\udd28 1. Always to and from Stream conversion\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.collect(\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/\ud83e\udd28 2. Lacks extension methods, so wrappers are required\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Collectors.groupingBy(\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Product::name,\n\u00a0 \u00a0         \/\/\ud83e\udd28 2. Again\u2026\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Collectors.mapping( groupedProducts -&gt;\n\u00a0               \/\/\ud83e\udd28 3. (too) low-level types, arrays, and primitives cause extra complexity\n\u00a0               \/\/\ud83e\udd28 4. No API on Array, always wrap in stream\u00a0\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Arrays.stream(groupedProducts.ratings())\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .max()\n                      \/\/\ud83e\udd28 5. Extra verbosity due to Optional\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0         .orElse(0.0),\n\u00a0              \/\/\ud83e\udd28 6. No named arguments: what does this do?\n\u00a0               Collectors.reducing(0, Integer::max)\n              )\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ));<\/pre>\n<p><strong>Kotlin<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/\ud83d\ude03 rich and uniform Collection API - even on Java collections - due to extension methods\nval maxRatingsPerProduct = products.\n      .groupBy { it.name }\n      .mapValues { (_, groupedProducts) -&gt; \/\/\ud83d\ude03 destructuring for semantic precision\n            \/\/\ud83d\ude03 built-in nullability support, and the same API for\u00a0\n            \/\/arrays like other Collections\n            groupedProducts.flatMap { it.ratings }\n                  .maxOrNull() ?: 0\u00a0\n            }\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}<\/pre>\n<p>Gracias al marco uniforme de colecciones de Kotlin, la conversi\u00f3n entre distintos tipos de colecciones es muy sencilla: <br \/><strong>Java<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">int[] numbers = {1, 3, 3, 5, 2};\n\nSet unique = Arrays.stream(numbers).boxed().collect(Collectors.toSet());\n\nMap evenOrOdd = unique.stream()\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.collect(Collectors.toMap(\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0n -&gt; n,\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0n -&gt; n % 2 == 0));<\/pre>\n<p><strong>Kotlin<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">val numbers = arrayOf(1, 3, 3, 5, 2)\n\nval unique: Set = numbers.toSet() \/\/\ud83d\ude03 simply call to to do the conversion\n\nval evenOrOdd: Map = unique.associateWith { it % 2 == 0 }<\/pre>\n<p><strong>Efecto final:<\/strong><\/p>\n<ul>\n<li><strong>API intuitiva y repleta de funcionalidades para colecciones:<\/strong> los procesos se leen de izquierda a derecha, no dentro de llamadas al recopilador anidadas.<\/li>\n<li><strong>Menos c\u00f3digo reutilizable y complejidad:<\/strong> sin Collectors.groupingBy, sin Stream, sin Optional, sin Arrays.stream.<\/li>\n<li><strong>Un modelo mental:<\/strong> tanto si empieza con <code>List<\/code>, <code>Set<\/code>, <code>Array<\/code> o una matriz primitiva, recurre a los <em>mismos<\/em> operadores de colecci\u00f3n.<\/li>\n<li><strong>Rendimiento sin obst\u00e1culos:<\/strong> el compilador inserta boxing\/unboxing solo donde es inevitable; usted escribe c\u00f3digo normal.<\/li>\n<li><strong>Seguridad frente a valores nulos integrada: <\/strong>la API de colecciones es compatible totalmente con la nulabilidad con varios asistentes que suelen llevar el sufijo <code>orNull(...)<\/code>.<\/li>\n<li><strong>Interoperabilidad fluida con Java con envolturas idiom\u00e1ticas:<\/strong> gracias a los m\u00e9todos de extensi\u00f3n, obtendr\u00e1 \u00ablo mejor de ambos mundos\u00bb: colecciones cargadas de funcionalidades adem\u00e1s de las colecciones de Java.<\/li>\n<\/ul>\n<p>En pocas palabras, Kotlin eleva las tareas cotidianas de recopilaci\u00f3n \u2014filtrado, asignaci\u00f3n, agrupaci\u00f3n, etc.\u2014 en funciones <em>componibles<\/em> de primera clase, de modo que usted expresa <em>qu\u00e9<\/em> quiere, no todo el ritual de <em>c\u00f3mo<\/em> llegar a ello.<\/p>\n<p><strong>3. No m\u00e1s excepciones comprobadas, pero el c\u00f3digo en Kotlin es m\u00e1s seguro<\/strong><\/p>\n<p>Java es uno de los \u00fanicos lenguajes que todav\u00eda admite excepciones comprobadas. Aunque inicialmente se implantaron como elemento de seguridad, no han estado a la altura de lo prometido. Su verbosidad, los bloques de captura sin sentido que no hacen nada o que vuelven a lanzar una excepci\u00f3n como una <code>RuntimeException<\/code>, y su falta de alineaci\u00f3n con las lambdas son algunas de las razones por las que resultan un estorbo en lugar de hacer que su c\u00f3digo sea m\u00e1s seguro.<\/p>\n<p>Kotlin sigue el paradigma demostrado utilizado por casi todos los dem\u00e1s lenguajes de programaci\u00f3n (C#, Python, Scala, Rust y Go) de utilizar excepciones solo para situaciones irrecuperables.<\/p>\n<p>Los siguientes ejemplos ponen de manifiesto los obst\u00e1culos que las excepciones comprobadas introducen en su c\u00f3digo, sin a\u00f1adir ninguna seguridad:<\/p>\n<p><strong>Java<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public String downloadAndGetLargestFile(List urls) {\n\u00a0\u00a0\u00a0List contents = urls.stream().map(urlStr -&gt; {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Optional optional;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0try {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0optional = Optional.of(new URI(urlStr).toURL());\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/\ud83e\udd28 Within lambdas checked exceptions are not supported and must always be caught...\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0} catch (URISyntaxException | MalformedURLException e) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0optional = Optional.empty();\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return optional;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}).filter(Optional::isPresent) \u00a0 \u00a0 \u00a0 \/\/Quite a mouthful to get rid of the Optional...\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.map(Optional::get)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.map(url -&gt; {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0try (InputStream is = url.openStream()) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return new String(is.readAllBytes(), StandardCharsets.UTF_8);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0} catch (IOException e) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/\ud83e\udd28\u2026 or re-thrown, which is annoying, I don\u2019t really care about IOE\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0throw new IllegalArgumentException(e);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}).toList();\n\u00a0\u00a0\u00a0\/\/\ud83e\udd28 An empty List results in a NoSuchElementException, so why is it not checked? The chance that the List is empty is as high as the other two cases above...\n\u00a0\u00a0\u00a0return Collections.max(contents);\n}<\/pre>\n<p><strong>Kotlin<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/\ud83d\ude03 safe return type\nfun downloadAndGetLargestFile(urls: List): String? =\n\u00a0\u00a0\u00a0urls.mapNotNull { \u00a0\u00a0\u00a0\/\/\ud83d\ude03 convenient utility methods to rid of null\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/\ud83d\ude03 try catch is possible, yet runCatching is an elegant way to convert an exception to null\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0runCatching { URI(it).toURL() }.getOrNull()\n\u00a0\u00a0\u00a0}.maxOfOrNull{ \u00a0\/\/\ud83d\ude03 safe way to retrieve the max value\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0it.openStream().use{ it.reader().readText() } \u00a0\/\/\ud83d\ude03 convenient extension methods to make java.io streams fluent\n\u00a0\u00a0\u00a0}<\/pre>\n<p><strong>4. Funciones como ciudadanos de primera clase<\/strong><\/p>\n<p>Kotlin trata las funciones como ciudadanos de primera clase, lo que puede plantearle dudas si viene de Java: \u00bfqu\u00e9 significa eso y por qu\u00e9 importa?<\/p>\n<p>La diferencia clave radica en el enfoque limitado de Java: sus capacidades funcionales se centran sobre todo en el lado de la llamada mediante lambdas, mientras que el lado de la declaraci\u00f3n sigue ligado a interfaces funcionales verbosas y menos intuitivas. En Kotlin, puede definir, pasar, devolver y componer funciones sin ning\u00fan c\u00f3digo reutilizable, lo que hace que la programaci\u00f3n funcional sea mucho m\u00e1s expresiva y natural.<\/p>\n<p><strong>Java<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public void doWithImage(\n      URL url,\u00a0\n      \/\/\ud83e\udd28 Function interfaces introduce an indirection: because we don\u2019t see the signature of a Function we don\u2019t know what a\u00a0 BiConsumer does, unless we look it up\n      BiConsumer f) throws IOException {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0f.accept(url.getFile(), ImageIO.read(url));\n}\n\n\/\/\ud83e\udd28 Same here\npublic void debug(Supplier f) {\n\u00a0\u00a0\u00a0if(isDebugEnabled()) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0logger.debug(\"Debug: \" + f.get());\n\u00a0\u00a0\u00a0}\n}\n\n\/\/\ud83e\udd28 calling no-argument lambdas is verbose\ndebug(() -&gt; \"expensive concat\".repeat(1000));<\/pre>\n<p><strong>Kotlin<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">fun doWithImage(\n\u00a0\u00a0\u00a0url: URL,\n\u00a0 \/\/\ud83d\ude03 Kotlin has a syntax for declaring functions: from the signature, we see what goes in and what goes out\u00a0\n\u00a0\u00a0\u00a0f:(String, BufferedImage) -&gt; Unit) =\u00a0\n      f(url.file, ImageIO.read(url))\n\n\u00a0\u00a0\/\/\ud83d\ude03 same here: nothing goes in, a String goes out\nfun debug(msg: () -&gt; String) {\n\u00a0\u00a0\u00a0if(isDebugEnabled) {\n            logger.debug(msg())\n\u00a0\u00a0\u00a0}\n}\n\n\/\/\ud83d\ude03 convenient syntax to pass a lambda: {}\ndebug{\"expensive concat\".repeat(1000)}<\/pre>\n<p>Kotlin proporciona una sintaxis clara y concisa para declarar funciones: solo con la firma, puede ver inmediatamente lo que entra y lo que sale, sin tener que navegar a una interfaz funcional externa.\u00a0<\/p>\n<p>Java \u00abfiltra\u00bb sus funcionalidades de programaci\u00f3n funcional a trav\u00e9s de un gran conjunto de interfaces <code>java.util.function.*<\/code> con firmas verbosas y complejas, lo que a menudo hace que la programaci\u00f3n funcional resulte engorrosa de utilizar. Kotlin, por el contrario, trata a las funciones como ciudadanos de primera clase: estas interfaces permanecen ocultas para el desarrollador, pero siguen siendo totalmente interoperables con el enfoque de Java:<\/p>\n<figure class=\"wp-block-image size-full is-resized\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-655829\" style=\"aspect-ratio: 1.1355932203389831; width: 510px; height: auto;\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/11\/unnamed-16.png\" alt=\"\" width=\"804\" height=\"708\" \/><\/figure>\n<p>Como resultado, el uso de funciones en Kotlin es bastante m\u00e1s sencillo e intuitivo, lo que reduce considerablemente el umbral para aprovechar este potente concepto de programaci\u00f3n en su propio c\u00f3digo.\u00a0<\/p>\n<p><strong>5. Simultaneidad sin complicaciones con corrutinas<\/strong><\/p>\n<p>Si necesita un alto rendimiento, un procesamiento paralelo dentro de una \u00fanica solicitud, o streaming, la \u00fanica opci\u00f3n que tiene en Java es una biblioteca reactiva, como Reactor y RxJava, disponibles en marcos de trabajo como Spring WebFlux, Vert.X, Quarkus, etc.<\/p>\n<p>El problema con estas bibliotecas es que son notoriamente complicadas, lo que le obliga a entrar en la programaci\u00f3n funcional. Como tales, tienen una curva de aprendizaje pronunciada, pero es muy f\u00e1cil cometer errores que pueden tener consecuencias nefastas cuando la aplicaci\u00f3n est\u00e1 sometida a carga. Esa es probablemente la raz\u00f3n por la que la programaci\u00f3n reactiva nunca se convirti\u00f3 en la corriente dominante.\u00a0<\/p>\n<div class=\"alert \">\n<p><strong>Nota:<\/strong> VirtualThreads no sustituye a las bibliotecas reactivas, aunque exista cierto solapamiento. Los VirtualThreads ofrecen E\/S sin bloqueo, pero no proporcionan funcionalidades como el procesamiento paralelo o los flujos reactivos. La concurrencia estructurada y los valores con \u00e1mbito tambi\u00e9n permitir\u00e1n el procesamiento paralelo una vez que los principales marcos de trabajo lo admitan. Para los flujos reactivos, siempre tendr\u00e1 que recurrir a una biblioteca reactiva.<\/p>\n<\/div>\n<p>Supongamos que usted es un desarrollador Java que utiliza Spring Boot y desea realizar una llamada paralela dentro de una \u00fanica solicitud. Esto es lo que se obtiene al final:\u00a0<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@PostMapping(\"\/users\")\n@ResponseBody\n@Transactional\npublic Mono storeUser(@RequestBody User user) {\n\u00a0\u00a0\u00a0Mono avatarMono = avatarService.randomAvatar();\n\u00a0\u00a0\u00a0Mono validEmailMono = emailService.verifyEmail(user.getEmail());\n\u00a0\u00a0\u00a0\/\/\ud83e\udd28 what does \u2018zip\u2019 do?\n\u00a0\u00a0\u00a0return Mono.zip(avatarMono, validEmailMono).flatMap(tuple -&gt;\u00a0\n\u00a0      if(!tuple.getT2()) \/\/what is getT2()? It\u2019s the validEmail Boolean\u2026\n\u00a0\u00a0\u00a0     \/\/\ud83e\udd28 why can I not just throw an exception?\n\u00a0\u00a0\u00a0      Mono.error(new InvalidEmailException(\"Invalid Email\"));\n\u00a0      else personDao.save(UserBuilder.from(user)\n                                          .withAvatarUrl(tuple.getT1()));\n\u00a0\u00a0\u00a0\u00a0\u00a0);\u00a0\u00a0\n\u00a0\u00a0}<\/pre>\n<p>Aunque, desde una perspectiva de tiempo de ejecuci\u00f3n, este c\u00f3digo funciona a la perfecci\u00f3n, la complejidad accidental introducida es enorme:\u00a0<\/p>\n<ul>\n<li>El c\u00f3digo est\u00e1 dominado por <code>Mono\/Flux<\/code> a lo largo de toda la cadena de llamadas, lo que le obliga a envolver todos los objetos de dominio.<\/li>\n<li>Hay muchos operadores complejos por todas partes, como <code>zip<\/code>, <code>flatMap<\/code>, etc.<\/li>\n<li>No puede utilizar construcciones de programaci\u00f3n est\u00e1ndar como lanzar excepciones.\u00a0<\/li>\n<li>La intenci\u00f3n empresarial de su c\u00f3digo se resiente significativamente: el c\u00f3digo se centra en <code>Monos<\/code> y <code>flatMap<\/code>, oscureciendo as\u00ed lo que realmente est\u00e1 sucediendo desde una perspectiva empresarial.<\/li>\n<\/ul>\n<p>La buena noticia es que existe un potente remedio en forma de corrutinas de Kotlin. Las corrutinas pueden enmarcarse como una implementaci\u00f3n reactiva a nivel del lenguaje. Como tales, combinan lo mejor de ambos mundos:\u00a0<\/p>\n<ul>\n<li>Usted escribe c\u00f3digo secuencial como lo hac\u00eda antes.<\/li>\n<li>El c\u00f3digo se ejecuta de forma as\u00edncrona\/en paralelo en la ejecuci\u00f3n.<\/li>\n<\/ul>\n<p>El c\u00f3digo Java anterior convertido a corrutinas tiene el siguiente aspecto:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"kotlin\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@GetMapping(\"\/users\")\n@ResponseBody\n@Transactional\nsuspend fun storeUser(@RequestBody user:User):User = coroutineScope {\n\u00a0\u00a0\u00a0val avatarUrl = async { avatarService.randomAvatar() }\n\u00a0  val validEmail = async { emailService.verifyEmail() }\n\u00a0\u00a0\u00a0if(!validEmail.await()) throw InvalidEmailException(\"Invalid email\")\n\u00a0\u00a0\u00a0personRepo.save(user.copy(avatar = avatarUrl.await()))\n}<\/pre>\n<p>La palabra clave suspender de Kotlin permite una ejecuci\u00f3n estructurada y no bloqueante de forma clara y concisa. Junto con <code>async{}<\/code> y <code>await()<\/code>, facilita el procesamiento paralelo sin necesidad de callbacks profundamente anidados o construcciones complejas como <code>Mono<\/code> o <code>CompletableFuture<\/code>.<\/p>\n<p>Por eso disminuir\u00e1 la complejidad y aumentar\u00e1 la satisfacci\u00f3n de los desarrolladores y la facilidad de mantenimiento, manteniendo exactamente las mismas caracter\u00edsticas de rendimiento.\u00a0<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-655845\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/11\/unnamed-17.png\" alt=\"\" width=\"1566\" height=\"456\" \/><\/figure>\n<p><strong>Nota<\/strong>: No todos los principales marcos de trabajo web basados en Java admiten tambi\u00e9n corrutinas. Spring hace un trabajo excelente, al igual que Micronaut, pero Quarkus ofrece actualmente una compatibilidad limitada con corrutinas.<\/p>\n<p><strong>6. Pero bueno, \u00a1Java tambi\u00e9n evoluciona!<\/strong><\/p>\n<p>Java sigue avanzando con funcionalidades como los registros, la coincidencia de patrones y los pr\u00f3ximos proyectos como Amber, Valhalla y Loom. Esta evoluci\u00f3n constante refuerza la JVM y beneficia a todo el ecosistema.<\/p>\n<p>Pero aqu\u00ed est\u00e1 el truco: la mayor\u00eda de estas \u00abnuevas\u00bb funcionalidades de Java son cosas que los desarrolladores de Kotlin han disfrutado durante a\u00f1os. La verificaci\u00f3n de valores nulos, las clases de valores, las funciones de nivel superior, los argumentos de forma predeterminada, las colecciones concisas y las funciones de primera clase se han incorporado al dise\u00f1o de Kotlin, de una forma m\u00e1s unificada y sencilla para el desarrollador. Por eso el c\u00f3digo Kotlin suele parecer m\u00e1s limpio, m\u00e1s seguro y mucho m\u00e1s productivo.<\/p>\n<p>Y a\u00fan hay m\u00e1s: Kotlin tambi\u00e9n se beneficia de la innovaci\u00f3n de Java. Los avances a nivel de JVM como Virtual Threads y Loom en general, o las mejoras de rendimiento de Valhalla se aplican sin problemas tambi\u00e9n a Kotlin.<\/p>\n<p>En resumen: Java evoluciona, pero Kotlin se dise\u00f1\u00f3 desde el primer d\u00eda para ofrecer a los desarrolladores las herramientas modernas que necesitan, lo que lo convierte en una opci\u00f3n segura, moderna y con visi\u00f3n de futuro para construir el futuro.<\/p>\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" loading=\"lazy\" class=\"wp-image-655858\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/11\/kotlin-castle-1.png\" alt=\"\" width=\"1698\" height=\"1780\" \/><\/figure>\n<p><strong>7. La ventaja evolutiva de Kotlin<\/strong><\/p>\n<p>Los lenguajes de programaci\u00f3n m\u00e1s antiguos arrastran inevitablemente un bagaje heredado en comparaci\u00f3n con las alternativas modernas. Actualizar un lenguaje al tiempo que se da soporte a bases de c\u00f3digo enormes ya existentes presenta retos \u00fanicos para los dise\u00f1adores de lenguajes. Kotlin goza de dos ventajas cruciales:<\/p>\n<p><strong>Referencias s\u00f3lidas<\/strong>: en lugar de reinventar la rueda, el equipo de dise\u00f1o inicial de Kotlin reuni\u00f3 paradigmas demostrados de los principales lenguajes de programaci\u00f3n y los unific\u00f3 en un todo cohesionado. Este enfoque maximiz\u00f3 el aprendizaje evolutivo de la comunidad de programadores en general.<\/p>\n<p><strong>Aprender de las carencias de Java<\/strong>: los dise\u00f1adores de Kotlin pudieron observar los escollos de Java y desarrollar soluciones s\u00f3lidas desde cero.<\/p>\n<p>Para profundizar en la evoluci\u00f3n de Kotlin, Andrey Breslav, del equipo de dise\u00f1o original de Kotlin, dio una excelente charla en el KotlinDevDay de \u00c1msterdam: <a href=\"https:\/\/www.youtube.com\/watch?v=7z_K-hTTeqI&amp;ab_channel=Xebia\" target=\"_blank\" rel=\"noreferrer noopener\"><em>Shoulders of Giants: Languages Kotlin Learned From<\/em> (Sobre los hombros de gigantes: lenguajes de los que aprendi\u00f3 Kotlin), de Andrey Breslav<\/a><\/p>\n<p><strong>Factores intangibles: apoyar y conectar a los desarrolladores en su recorrido hacia la adopci\u00f3n de Kotlin<\/strong><\/p>\n<h3 class=\"wp-block-heading\"><strong>1. Facilite la incorporaci\u00f3n<\/strong><\/h3>\n<p>El objetivo de los fragmentos de c\u00f3digo expresivos Java vs. Kotlin es abrir el apetito por Kotlin. Sin embargo, el c\u00f3digo por s\u00ed solo no basta para ganarse los corazones y las mentes de los desarrolladores Java. Para acelerar la adopci\u00f3n y garantizar un comienzo sin problemas, ofrezca:<\/p>\n<ul>\n<li><strong>Un proyecto de ejemplo<\/strong>: un proyecto listo para ejecutarse con c\u00f3digo Java y Kotlin en paralelo, que ofrece a los equipos una referencia pr\u00e1ctica durante la migraci\u00f3n.<\/li>\n<li><strong>Comprobaciones de calidad integradas<\/strong>: preconfigurado con herramientas como SonarQube, ktlint y detekt para favorecer un c\u00f3digo limpio, coherente y mantenible desde el primer d\u00eda. Esto le permitir\u00e1 aplicar reglas coherentes de lint, marcos de pruebas, bibliotecas y procesos de CI para reducir la fricci\u00f3n entre los equipos.<\/li>\n<li><strong>Coaching y apoyo<\/strong>: ingenieros experimentados en Kotlin disponibles para formar a los nuevos equipos, responder preguntas y proporcionar asesoramiento pr\u00e1ctico durante las primeras etapas de desarrollo.\n<ul>\n<li>Esta es especialmente importante: con solo unas horas de orientaci\u00f3n por parte de un desarrollador experimentado de otro equipo que haya pasado antes por estas etapas, se pueden evitar muchos errores y deudas t\u00e9cnicas.\u00a0<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Un poco de apoyo y orientaci\u00f3n es la mejor forma de fomentar un entusiasmo duradero por Kotlin.<\/p>\n<h3 class=\"wp-block-heading\"><strong>2. Ofrezca material de (auto)aprendizaje<\/strong><\/h3>\n<p>Especialmente cuando se viene de Java, aprender los fundamentos de Kotlin puede hacerse por cuenta propia. Proporcionar algunos recursos por adelantado facilita el camino para mejorar la productividad con Kotlin y reduce el umbral de entrada.\u00a0<\/p>\n<ul>\n<li><a href=\"https:\/\/kotlinlang.org\/docs\/getting-started.html\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>El \u00abTour of Kotlin\u00bb de JetBrains (gu\u00eda de primeros pasos)<\/strong><br \/><\/a>Un breve tutorial basado en navegador en el sitio oficial de Kotlin.<\/li>\n<li><a href=\"https:\/\/kotlinlang.org\/docs\/koans.html\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>Kotlin Koans<br \/><\/strong><\/a>Un conjunto de peque\u00f1os desaf\u00edos de codificaci\u00f3n mantenido por JetBrains.<\/li>\n<li><a href=\"https:\/\/www.udacity.com\/course\/kotlin-bootcamp-for-programmers--ud9011\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>\u00abKotlin Bootcamp for Programmers\u00bb de Udacity<\/strong><br \/><\/a>Un curso completo en v\u00eddeo creado en colaboraci\u00f3n con Google.<\/li>\n<\/ul>\n<div class=\"alert \">\n<p><strong>Nota:<\/strong> Aunque el autoaprendizaje es valioso para comprender los conceptos b\u00e1sicos, tambi\u00e9n tiene algunos inconvenientes. Uno de ellos es la opcionalidad: cuando se est\u00e1 atrapado en la vor\u00e1gine de tareas del d\u00eda a d\u00eda, es tentador saltarse el autoaprendizaje. Adem\u00e1s, al aprendiz le faltar\u00e1 la retroalimentaci\u00f3n de un profesional que conozca los matices sutiles del Kotlin idiom\u00e1tico correctamente aplicado. Es muy probable que despu\u00e9s de un curso de autoaprendizaje, escriba Kotlin al estilo Java, lo que le proporciona algunas ventajas pero no desbloquea todo el potencial del lenguaje.\u00a0<\/p>\n<\/div>\n<p>A menos que no tenga una buena mentor\u00eda, un curso cl\u00e1sico puede ser muy beneficioso. La asistencia es obligatoria; podr\u00e1 intercambiar ideas con compa\u00f1eros de su mismo nivel y obtener respuesta a sus preguntas por parte de un profesional experimentado, lo que le pondr\u00e1 al d\u00eda mucho m\u00e1s r\u00e1pido con un Kotlin menos no-idiom\u00e1tico durante la transici\u00f3n inicial.\u00a0<\/p>\n<h3 class=\"wp-block-heading\"><strong>3. Establezca una comunidad interna de Kotlin<\/strong><\/h3>\n<p>Una de las formas m\u00e1s r\u00e1pidas de aumentar los conocimientos de Kotlin en su empresa es crear y, sobre todo, alimentar una comunidad interna.<\/p>\n<ul>\n<li><strong>Lance una comunidad interna de Kotlin<\/strong>\n<ul>\n<li>Primero busque un equipo base de al menos 3-6 desarrolladores que est\u00e9n dispuestos a invertir en una comunidad Kotlin. Aseg\u00farese tambi\u00e9n de que sus superiores les dan tiempo para su tarea y cr\u00e9dito por ella.<\/li>\n<li>Una vez formado el equipo, organice una reuni\u00f3n de lanzamiento en toda la empresa con ponentes conocidos de la comunidad Kotlin. Esto encender\u00e1 la llama de Kotlin y le dar\u00e1 impulso.<\/li>\n<li>Programe reuniones peri\u00f3dicas (mensuales o quincenales) para que el impulso nunca decaiga.<\/li>\n<li>Cree un canal de chat\/wiki compartido dedicado a preguntas, fragmentos de c\u00f3digo y notas de los eventos.<\/li>\n<\/ul>\n<\/li>\n<li><strong>Invite a ponentes (externos)<\/strong>\n<ul>\n<li>Traiga a ingenieros que hayan puesto Kotlin en producci\u00f3n para que compartan sus an\u00e9cdotas.<\/li>\n<li>Alterne entre charlas t\u00e9cnicas en profundidad (corrutinas, KMP, programaci\u00f3n funcional) y estudios de casos de mayor nivel (estrategias de migraci\u00f3n, consejos sobre herramientas).<\/li>\n<\/ul>\n<\/li>\n<li><strong>Presente las lecciones aprendidas de otros proyectos internos<\/strong>\n<ul>\n<li>Pida a los jefes de proyecto que presenten lo aprendido sobre Kotlin: lo que funcion\u00f3, lo que no y los resultados cuantificables.<\/li>\n<li>Estos conocimientos pueden plasmarse en un \u00ablibro de reglas de Kotlin\u00bb que los nuevos equipos pueden consultar.<\/li>\n<\/ul>\n<\/li>\n<li><strong>D\u00e9 protagonismo a sus propios desarrolladores<\/strong>\n<ul>\n<li>Organice sesiones de charlas rel\u00e1mpago en las que cualquiera pueda mostrar en 5-10 minutos un truco ingenioso, una biblioteca o un fracaso que haya superado.<\/li>\n<li>Felicite a los colaboradores p\u00fablicamente: las menciones en los boletines internos o en los de todos los empleados fomentan el compromiso y el intercambio de conocimientos.<\/li>\n<\/ul>\n<\/li>\n<li><strong>Mantenga los bucles de retroalimentaci\u00f3n cerrados<\/strong>\n<ul>\n<li>Despu\u00e9s de cada sesi\u00f3n, haga encuestas r\u00e1pidas sobre su claridad y la utilidad, y luego modifique los programas futuros en consecuencia.<\/li>\n<li>Rote las tareas de organizaci\u00f3n para que la comunidad no dependa de un \u00fanico campe\u00f3n y se mantenga resistente a largo plazo.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><strong>Nota<\/strong>: Muchas de las sugerencias anteriores parecen sencillas. Sin embargo, no hay que subestimar el esfuerzo necesario para mantener viva y din\u00e1mica una comunidad.\u00a0<\/p>\n<h3 class=\"wp-block-heading\"><strong>4. Sea paciente\u2026<\/strong><\/h3>\n<p>El cambio cultural lleva su tiempo. El peligro de entusiasmarse con una herramienta que marca la diferencia es forzar las cosas, lo que puede ser contraproducente. Un enfoque eficaz consiste en respaldar el proceso de adopci\u00f3n con todas las actividades comentadas anteriormente, teniendo como gu\u00eda prioritaria el principio de <em>\u00abmuestre, no explique\u00bb<\/em>.<\/p>\n<h3 class=\"wp-block-heading\">Pr\u00f3xima entrega de la serie<\/h3>\n<p>Pasamos de convencer a los desarrolladores a persuadir a los responsables de la toma de decisiones. En el pr\u00f3ximo art\u00edculo mostramos c\u00f3mo elaborar unos argumentos convincentes para la adopci\u00f3n de Kotlin en la empresa, basados en datos reales y resultados medibles. Aprender\u00e1 a traducir las victorias de los desarrolladores en argumentos de gesti\u00f3n, a vincular el aumento de la productividad con el ahorro de costes y a demostrar por qu\u00e9 Kotlin es m\u00e1s que una actualizaci\u00f3n t\u00e9cnica: es un movimiento estrat\u00e9gico tanto para los equipos como para las empresas.<\/p>\n<p><em>Art\u00edculo original en ingl\u00e9s de:<\/em><\/p>\n<div class=\"about-author \">\n<div class=\"about-author__box\">\n<div class=\"row\">\n<div class=\"about-author__box-img\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/10\/a3f7-400o400o1-QYUavRYyARnAVJLCpM1m8M.webp\" alt=\"\" \/><\/div>\n<div class=\"about-author__box-text\">\n<h4>Urs Peter<\/h4>\n<p>Urs es un experimentado ingeniero de software, arquitecto de soluciones, conferenciante y formador con m\u00e1s de 20 a\u00f1os de experiencia en la creaci\u00f3n de sistemas resistentes, escalables y cr\u00edticos, principalmente con Kotlin y Scala.<\/p>\n<p>Adem\u00e1s de su trabajo como consultor, tambi\u00e9n es un formador apasionado y autor de una gran variedad de cursos que van desde cursos de los lenguajes Kotlin y Scala hasta formaciones de arquitectura como los microservicios y las arquitecturas orientadas a eventos.<\/p>\n<p>Como persona sociable por naturaleza, le encanta compartir conocimientos e inspirar y dejarse inspirar por sus compa\u00f1eros en quedadas y conferencias. Urs es un formador de Kotlin certificado por JetBrains.<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n\n    <div class=\"about-author \">\n        <div class=\"about-author__box\">\n            <div class=\"row\">\n                <div class=\"about-author__box-img\">\n                    <img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2021\/08\/photo_2021-08-03_15-27-43-200x200.jpg\" width=\"200\" height=\"200\" alt=\"Alyona Chernyaeva\" loading=\"lazy\"  class=\"avatar avatar-200 wp-user-avatar wp-user-avatar-200 photo avatar-default\">\n                <\/div>\n                <div class=\"about-author__box-text\">\n                                            <h4>Alyona Chernyaeva<\/h4>\n                                                        <\/div>\n            <\/div>\n        <\/div>\n    <\/div>\n","protected":false},"author":1086,"featured_media":671856,"comment_status":"closed","ping_status":"closed","template":"","categories":[],"tags":[],"cross-post-tag":[],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/kotlin\/671828"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/kotlin"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/types\/kotlin"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/users\/1086"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/comments?post=671828"}],"version-history":[{"count":3,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/kotlin\/671828\/revisions"}],"predecessor-version":[{"id":671878,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/kotlin\/671828\/revisions\/671878"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/media\/671856"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/media?parent=671828"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/categories?post=671828"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/tags?post=671828"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/es\/wp-json\/wp\/v2\/cross-post-tag?post=671828"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}