Posts Tagged ‘Kotlin’
[KotlinConf2025] Building a macOS Screen Saver with Kotlin
A captivating tale of a developer’s obsession and a journey into the less-trodden paths of Kotlin development was shared by Márton Braun, a Developer Advocate at JetBrains. It all began with a simple, yet compelling, observation at a previous KotlinConf: a screen saver featuring the bouncing Kotlin logos, reminiscent of old DVD players. Upon discovering it was merely a pre-rendered video and not a true screen saver, a challenge was born. Márton set out to build his own, a native macOS application powered by Kotlin/Native.
The project became a masterclass in interoperability and a candid exploration of the quirks of native application development. Márton detailed how Kotlin/Native’s powerful interop capabilities made it surprisingly easy to call native macOS APIs. However, this ease was often contrasted with the complexities and frustrations of working with the macOS platform itself. The development process was a constant battle, with macOS often proving to be an uncooperative partner in this creative endeavor.
Márton’s perseverance paid off, resulting in a fully functional screen saver. He even managed to create two distinct implementations: one using the traditional AppKit framework and another built with Compose Multiplatform. This dual approach not only demonstrated the capabilities of both technologies but also provided a unique learning experience. He highlighted how the Compose version allowed him to focus on the core UI logic, abstracting away the intricacies of packaging the screen saver. This is a powerful testament to Compose Multiplatform’s potential for simplifying development and improving productivity.
The screen saver project serves as an excellent case study, showcasing Kotlin’s ability to venture into unconventional domains beyond mobile and backend development. Márton successfully demonstrated that with Kotlin and the right tools, developers can create truly native applications for platforms like macOS, leveraging their existing skills and knowledge. The flexibility of Kotlin Multiplatform allows developers to share code across platforms while still delivering a native user experience.
Ultimately, this project is a celebration of the unique possibilities that Kotlin offers. It encourages developers to think creatively about how they can apply the language to solve a wide range of problems and build applications for a diverse set of platforms. Márton’s story is an inspiring reminder that sometimes the most interesting and valuable projects are born from a simple desire to see something that doesn’t exist yet come to life.
Links:
- Márton Braun on GitHub
- Márton Braun’s Blog
- JetBrains website
- Building a macOS Screen Saver with Kotlin | Márton Braun
[KotlinConf2025] Charts, Code, and Sails: Winning a Regatta with Kotlin Notebook
In the high-stakes world of competitive sailing, where every decision can mean the difference between victory and defeat, an extraordinary tool has emerged: Kotlin Notebook. Roman Belov, a distinguished member of the JetBrains team, shared a captivating account of leveraging this innovative technology to triumph in a 24-hour regatta. The narrative transcends a simple code demonstration, illustrating how interactive programming becomes a critical asset in a dynamic, unpredictable environment like the open sea.
This journey highlights the power of Kotlin Notebook as more than just a development tool; it’s a platform for real-time problem-solving. While a seasoned developer, Roman’s most cherished hat is that of a yachtsman. He uses the notebook to translate complex nautical challenges into actionable, data-driven decisions. The essence of the task is to navigate a course, which is essentially a graph with nodes representing different locations and edges representing the path between them. However, unlike a typical graph problem, the rules of sailing introduce complex variables. The boat cannot sail directly into the wind, and its speed is heavily dependent on the angle of the wind. This means the graph is constantly changing, making traditional route-planning algorithms obsolete.
The solution required a tool that could rapidly process data, visualize outcomes, and allow for on-the-fly adjustments. This is where Kotlin Notebook excelled, providing a live, interactive environment. Roman outlined how he could use the notebook to perform crucial tasks in the middle of the race: visualizing the race course on a map, calculating the fastest path based on current wind conditions, and dynamically adjusting the route as the wind shifted. This is achieved by creating a “sailable roads” model, which evaluates every potential path on the graph at regular intervals and discards any that are impossible given the wind direction. For the remaining paths, the notebook computes the optimal boat speed and time to complete that segment, effectively modeling the race in real time.
Roman then showcased the brute-force search algorithm that was used to find the optimal path. The code, written in Kotlin, was surprisingly straightforward and demonstrated the language’s elegance and readability. The algorithm, running within the notebook, would constantly iterate through the potential paths, calculating the time to finish for each one and discarding any that were slower than the best time found so far. The visual output of the notebook, which could render the different routes directly on the map, was a game-changer. It transformed abstract data and calculations into a clear, visual representation that allowed the sailors to make quick, informed decisions.
The application of Kotlin Notebook in this unconventional scenario proves its versatility beyond traditional data science or development tasks. It demonstrated how a tool designed for rapid experimentation can be applied to complex, real-world problems. The interactive nature of the notebook allowed Roman to combine data analysis, algorithm execution, and visual feedback into a single, cohesive workflow, enabling him and his crew to stay ahead of the competition and ultimately, win the race. This story is a testament to the power of a modern programming language and an adaptable toolchain, turning a challenging maritime endeavor into an exciting display of computational prowess.
Links:
- Roman Belov on JetBrains Blog
- JetBrains website
- Charts, Code, and Sails: Winning a Regatta with Kotlin Notebook | Roman Belov
[KotlinConf2024] Channels in Kotlin Coroutines: Unveiling the Redesign
At KotlinConf2024, Nikita Koval, a JetBrains concurrency expert, delved into Kotlin coroutine channels, a core communication primitive. Channels, often used indirectly via APIs like Flow, enable data transfer between coroutines. Nikita explored their redesigned implementation, which boosts performance and reduces memory usage. He detailed rendezvous and buffered channel semantics, underlying algorithms, and scalability, offering developers insights into optimizing concurrent applications and understanding coroutine internals.
Channels: The Hidden Backbone of Coroutines
Channels are fundamental to Kotlin coroutines, even if developers rarely use them directly. Nikita highlighted their role in high-level APIs like Flow. For instance, merging two Flows or collecting data across dispatchers relies on channels to transfer elements between coroutines. Channels also bridge reactive frameworks like RxJava, funneling data through a coroutine-launched channel. Unlike sequential Flows, channels enable concurrent data handling, making them essential for complex asynchronous tasks, as seen in Flow’s channelFlow builder.
Rendezvous Channels: Synchronized Data Exchange
Rendezvous channels, the default in Kotlin, ensure synchronized communication. Nikita illustrated their semantics with two producers and one consumer. When a consumer calls receive on an empty channel, it suspends until a producer sends data. Conversely, a producer’s send suspends if no consumer is waiting, preventing uncontrolled growth. This “rendezvous” ensures direct data handoff, as demonstrated when a producer resumes a waiting consumer, maintaining efficiency and safety in concurrent scenarios.
Building Efficient Channel Algorithms
Implementing rendezvous channels requires balancing efficiency, memory use, and scalability. Nikita compared concurrent queue designs to adapt for channels. A lock-based sequential queue, while fast on single threads, fails to scale due to synchronization costs. Java’s ConcurrentLinkedQueue, using a linked list, scales better but incurs high memory overhead—32 bytes per 4-byte reference. Instead, modern queue designs use a segmented array with atomic counters for enqueuing and dequeuing, minimizing memory and scaling effectively, forming the basis for channel implementation.
Buffered Channels: Flexible Data Buffering
Buffered channels extend rendezvous semantics by allowing a fixed-capacity buffer. Nikita explained that a channel with capacity k accepts k elements without suspension, suspending only when full. Using a single producer-consumer example, he showed how a producer fills an empty buffer, while a second producer suspends until the consumer extracts an element, freeing space. This design, implemented with an additional counter to track buffer boundaries, supports dynamic workloads, though cancellation semantics add complexity, detailed in JetBrains’ research papers.
Performance Gains from Redesign
The channel redesign significantly enhances performance. Nikita shared benchmarks comparing the old linked-list-based implementation to the new segmented array approach. In a multi-producer, multi-consumer test with 10,000 coroutines, the new channels scaled up to four times faster, producing less garbage. Even in sequential workloads, they were 20% quicker. Q&A revealed further tuning, like setting segment sizes to 32 elements, balancing memory and metadata overhead, ensuring scalability across 64-core systems without degradation.
Deepening Concurrency Knowledge
Understanding channel internals empowers developers to tackle performance issues, akin to knowing hash table mechanics. Nikita emphasized that while high-level APIs abstract complexity, low-level knowledge aids debugging. He invited attendees to explore further at the PDI conference in Copenhagen, where JetBrains will discuss coroutine algorithms, including schedulers and mutexes. The redesigned channels, applied to unlimited and conflated variants, offer robust, scalable communication, encouraging developers to leverage coroutines confidently in high-load applications.
Links:
Advanced Encoding in Java, Kotlin, Node.js, and Python
Encoding is essential for handling text, binary data, and secure transmission across applications. Understanding advanced encoding techniques can help prevent data corruption and ensure smooth interoperability across systems. This post explores key encoding challenges and how Java/Kotlin, Node.js, and Python tackle them.
1️⃣ Handling Special Unicode Characters (Emoji, Accents, RTL Text)
Java/Kotlin
Java uses UTF-16 internally, but for external data (JSON, databases, APIs), explicit encoding is required:
String text = "🔧 Café مرحبا";
byte[] utf8Bytes = text.getBytes(StandardCharsets.UTF_8);
String decoded = new String(utf8Bytes, StandardCharsets.UTF_8);
System.out.println(decoded); // 🔧 Café مرحبا
✅ Tip: Always specify StandardCharsets.UTF_8 to avoid platform-dependent defaults.
Node.js
const text = "🔧 Café مرحبا";
const utf8Buffer = Buffer.from(text, 'utf8');
const decoded = utf8Buffer.toString('utf8');
console.log(decoded); // 🔧 Café مرحبا
✅ Tip: Using an incorrect encoding (e.g., latin1) may corrupt characters.
Python
text = "🔧 Café مرحبا"
utf8_bytes = text.encode("utf-8")
decoded = utf8_bytes.decode("utf-8")
print(decoded) # 🔧 Café مرحبا
✅ Tip: Python 3 handles Unicode by default, but explicit encoding is always recommended.
2️⃣ Encoding Binary Data for Transmission (Base64, Hex, Binary Files)
Java/Kotlin
byte[] data = "Hello World".getBytes(StandardCharsets.UTF_8);
String base64Encoded = Base64.getEncoder().encodeToString(data);
byte[] decoded = Base64.getDecoder().decode(base64Encoded);
System.out.println(new String(decoded, StandardCharsets.UTF_8)); // Hello World
Node.js
const data = Buffer.from("Hello World", 'utf8');
const base64Encoded = data.toString('base64');
const decoded = Buffer.from(base64Encoded, 'base64').toString('utf8');
console.log(decoded); // Hello World
Python
import base64
data = "Hello World".encode("utf-8")
base64_encoded = base64.b64encode(data).decode("utf-8")
decoded = base64.b64decode(base64_encoded).decode("utf-8")
print(decoded) # Hello World
✅ Tip: Base64 encoding increases data size (~33% overhead), which can be a concern for large files.
3️⃣ Charset Mismatches and Cross-Language Encoding Issues
A file encoded in ISO-8859-1 (Latin-1) may cause garbled text when read using UTF-8.
Java/Kotlin Solution:
byte[] bytes = Files.readAllBytes(Paths.get("file.txt"));
String text = new String(bytes, StandardCharsets.ISO_8859_1);
Node.js Solution:
const fs = require('fs');
const text = fs.readFileSync("file.txt", { encoding: "latin1" });
Python Solution:
with open("file.txt", "r", encoding="ISO-8859-1") as f:
text = f.read()
✅ Tip: Always specify encoding explicitly when working with external files.
4️⃣ URL Encoding and Decoding
Java/Kotlin
String encoded = URLEncoder.encode("Hello World!", StandardCharsets.UTF_8);
String decoded = URLDecoder.decode(encoded, StandardCharsets.UTF_8);
Node.js
const encoded = encodeURIComponent("Hello World!");
const decoded = decodeURIComponent(encoded);
Python
from urllib.parse import quote, unquote
encoded = quote("Hello World!")
decoded = unquote(encoded)
✅ Tip: Use UTF-8 for URL encoding to prevent inconsistencies across different platforms.
Conclusion: Choosing the Right Approach
- Java/Kotlin: Strong type safety, but requires careful
Charsetmanagement. - Node.js: Web-friendly but depends heavily on
Bufferconversions. - Python: Simple and concise, though strict type conversions must be managed.
📌 Pro Tip: Always be explicit about encoding when handling external data (APIs, files, databases) to avoid corruption.
CTO Perspective: Choosing a Tech Stack for Mainframe Rebuild
Original post
From LinkedIn: https://www.linkedin.com/posts/matthias-patzak_cto-technology-activity-7312449287647375360-ogNg?utm_source=share&utm_medium=member_desktop&rcm=ACoAAAAWqBcBNS5uEX9jPi1JPdGxlnWwMBjXwaw
Summary of the question
As CTO for a mainframe rebuild (core banking/insurance/retail app, 100 teams/1000 people with Cobol expertise), considering Java/Kotlin, TypeScript/Node.js, Go, and Python. Key decision criteria are technical maturity/stability, robust community, and innovation/adoption. The CTO finds these criteria sound and seeks a language recommendation.
TL;DR: my response
- Team, mainframe rebuild: Java/Kotlin are frontrunners due to maturity, ecosystem, and team’s Java-adjacent skills. Go has niche potential. TypeScript/Node.js and Python less ideal for core.
- Focus now: deep PoC comparing Java (Spring Boot) vs. Kotlin on our use cases. Evaluate developer productivity, readability, interoperability, performance.
- Develop comprehensive Java/Kotlin training for our 100 Cobol-experienced teams.
- Strategic adoption plan (Java, Kotlin, or hybrid) based on PoC and team input is next.
- This balances proven stability with modern practices on the JVM for our core.
My detailed opinion
As a CTO with experience in these large-scale transformations, my priority remains a solution that balances technical strength with the pragmatic realities of our team’s current expertise and long-term maintainability.
While Go offers compelling performance characteristics, the specific demands of our core business application – be it in banking, insurance, or retail – often prioritize a mature ecosystem, robust enterprise patterns, and a more gradual transition path for our significant team. Given our 100 teams deeply skilled in Cobol, the learning curve and the availability of readily transferable concepts become key considerations.
Therefore, while acknowledging Go’s strengths in certain cloud-native scenarios, I want to emphasize the strategic advantages of the Java/Kotlin ecosystem for our primary language choice, with a deliberate hesitation and deeper exploration between these two JVM-based options.
Re-emphasizing Java and Exploring Kotlin More Deeply:
-
Java’s Enduring Strength: Java’s decades of proven stability in building mission-critical enterprise systems cannot be overstated. The JVM’s resilience, the vast array of mature libraries and frameworks (especially Spring Boot), and the well-established architectural patterns provide a solid and predictable foundation. Moreover, the sheer size of the Java developer community ensures a deep pool of talent and readily available support for our teams as they transition. For a core system in a regulated industry, this level of established maturity significantly mitigates risk.
-
Kotlin’s Modern Edge and Interoperability: Kotlin presents a compelling evolution on the JVM. Its modern syntax, null safety features, and concise code can lead to increased developer productivity and reduced boilerplate – benefits I’ve witnessed firsthand in JVM-based projects. Crucially, Kotlin’s seamless interoperability with Java is a major strategic advantage. It allows us to:
- Gradually adopt Kotlin: Teams can start by integrating Kotlin into existing Java codebases, allowing for a phased learning process without a complete overhaul.
- Leverage the entire Java ecosystem: Kotlin developers can effortlessly use any Java library or framework, giving us access to the vast resources of the Java world.
- Attract modern talent: Kotlin’s growing popularity can help us attract developers who are excited about working with a modern, yet stable, language on a proven platform.
Why Hesitate Between Java and Kotlin?
The decision of whether to primarily adopt Java or Kotlin (or a strategic mix) requires careful consideration of our team’s specific needs and the long-term vision:
- Learning Curve: While Kotlin is designed to be approachable for Java developers, there is still a learning curve associated with its new syntax and features. We need to assess how quickly our large Cobol-experienced team can become proficient in Kotlin.
- Team Preference and Buy-in: Understanding our developers’ preferences and ensuring buy-in for the chosen language is crucial for successful adoption.
- Long-Term Ecosystem Evolution: While both Java and Kotlin have strong futures on the JVM, we need to consider the long-term trends and the level of investment in each language within the enterprise space.
- Specific Use Cases: Certain parts of our system might benefit more from Kotlin’s conciseness or specific features, while other more established components might initially remain in Java.
Proposed Next Steps (Revised Focus):
- Targeted Proof of Concept (PoC) – Deep Dive into Java and Kotlin: Instead of a broad PoC including Go, let’s focus our initial efforts on a detailed comparison of Java (using Spring Boot) and Kotlin on representative use cases from our core business application. This PoC should specifically evaluate:
- Developer Productivity: How quickly can teams with a Java-adjacent mindset (after initial training) develop and maintain code in both languages?
- Code Readability and Maintainability: How do the resulting codebases compare in terms of clarity and ease of understanding for a large team?
- Interoperability Scenarios: How seamlessly can Java and Kotlin code coexist and interact within the same project?
- Performance Benchmarking: While the JVM provides a solid base, are there noticeable performance differences for our specific workloads?
- Comprehensive Training and Upskilling Program: We need to develop a detailed training program that caters to our team’s Cobol background and provides clear pathways for learning both Java and Kotlin. This program should include hands-on exercises and mentorship opportunities.
- Strategic Adoption Plan: Based on the PoC results and team feedback, we’ll develop a strategic adoption plan that outlines whether we’ll primarily focus on Java, Kotlin, or a hybrid approach. This plan should consider the long-term maintainability and talent acquisition goals.
While Go remains a valuable technology for specific niches, for the core of our mainframe rebuild, our focus should now be on leveraging the mature and evolving Java/Kotlin ecosystem and strategically determining the optimal path for our large and experienced team. This approach minimizes risk while embracing modern development practices on a proven platform.
[KotlinConf2024] Compose UI on a Light Switch: KotlinConf2024’s Embedded Adventure
At KotlinConf2024, Jake Wharton, a Kotlin enthusiast, shared his journey of running Compose UI on a smart light switch powered by embedded Linux. Sparked by a friend’s discovery of a backdoor granting root access, Jake transformed a $50 Amazon switch into a custom platform. He navigated challenges from setting up a JVM and Kotlin Native to configuring a graphics stack with Skia and handling touch inputs, culminating in a live demo of a touchable UI controlling the switch’s relay, showcasing Compose UI’s multiplatform potential.
A Side Project Ignited by a Backdoor
Jake’s project began in January 2023 when a friend revealed a smart switch’s ADB server allowed password-free root access, discovered via Home Assistant forums. The Decora-style switch, with a touchscreen, light sensor, and microphone, ran a stripped-down Linux. Jake snipped an extension cord to power it and confirmed root access via ADB, setting the stage for custom software. This accessibility, though later patched by the manufacturer, fueled his ambition to replace the Flutter-based UI with Compose UI, blending curiosity with technical challenge.
Bootstrapping the JVM and Kotlin Native
To run Compose UI, Jake first tested the JVM on the switch’s limited 150MB storage. He pushed a Linux ARM JRE and a Java “Hello World” class, confirming JVM functionality. Next, he compiled a Kotlin Native “Hello World” for Linux ARM, proving Kotlin could run natively. These steps established a foundation, but the switch’s constraints—no compiler, minimal storage—required compiling on a host machine and transferring binaries, a process complicated by the need to match the device’s library versions, like libDRM 2.4.
Wrestling with the Graphics Stack
Rendering Compose UI required a graphics stack, but the switch’s Flutter app used Linux’s Direct Rendering Manager (DRM) with OpenGL ES, not OpenGL. Jake’s initial attempt to use Compose UI Desktop failed due to missing OpenGL and X11 dependencies. He ported C-based DRM code to Kotlin Native, meticulously matching the switch’s libDRM version (2.4.87) by analyzing binaries. This process, spanning months, involved pulling headers and shared objects from the device, ensuring compatibility, and overcoming compilation hurdles, like missing toolchains for Linux ARM.
Skia: Rendering Pixels with Kotlin
To draw pixels, Jake turned to Skia, the graphics library powering Flutter and Android. JetBrains’ Skiko library, binding Skia to Kotlin, lacked Linux ARM support for OpenGL ES. Jake forked Skiko, modifying it to use EGL, and endured weeks of GitHub Actions builds to compile Skia for ARM. He integrated Skiko’s C++ and Kotlin bindings, enabling rendering of basic shapes (e.g., red backgrounds, blue circles). This step, though painful, proved Kotlin Native could handle the switch’s display, setting the stage for Compose UI.
Handling Touch Inputs
Interactivity required processing touchscreen inputs. Jake used Linux’s evtest to identify the switch’s touchscreen events, capturing X/Y positions and touch states (down/up). He implemented a single-pointer event parser in Kotlin Native, mapping raw events to a data class within the render loop. This avoided multi-touch complexity, as the switch supported only one pointer. By feeding these events to Compose UI, Jake enabled touch interactions, like button ripples, transforming the switch into a responsive interface, despite occasional crashes during live demos.
Bringing Compose UI to Life
Integrating Compose UI was surprisingly straightforward compared to prior challenges. Jake forked JetBrains’ Compose UI repository, adding a Linux ARM target and implementing expect/actual declarations for dependencies like input handling and scrolling. He replaced low-level Skiko calls with Compose UI’s entry point, passing a Skia canvas and touch events. Initial text rendering crashed due to font issues, but a simple button worked, displaying ripples on touch. Jake’s UI, controlling the switch’s relay via a Unix domain socket and Ktor, demonstrated Compose UI’s adaptability, running the same code on desktop for development.
Demo and Future Potential
Jake’s live demo, despite power converter issues, showcased a draggable switch UI toggling a light bulb, built with Compose UI and Kotlin multiplatform. An enclosure housed the switch, highlighting its real-world application. He envisioned future enhancements, like Home Assistant integration or music control, noting the project’s infancy. Community contributions, like his friend Eric’s interactive component, and public forks for Skiko and Ktor, underscore the project’s collaborative spirit. Jake cautioned against internet-connecting the switch due to security concerns, urging manufacturers to simplify hacking for innovation.
Links:
[DevoxxBE2024] Let’s Use IntelliJ as a Game Engine, Just Because We Can by Alexander Chatzizacharias
At Devoxx Belgium 2024, Alexander Chatzizacharias delivered a, lighthearted yet insightful talk on the whimsical idea of using IntelliJ IDEA as a game engine. As a Java enthusiast and self-proclaimed gamer, Alexander explored the absurdity and fun of leveraging IntelliJ’s plugin platform to create games within a codebase. His session, filled with humor and technical creativity, demonstrated how curiosity-driven projects can spark innovation while entertaining developers. From rendering Pong to battling mutable state in a Space Invaders-inspired game, Alexander’s talk was a testament to the joy of experimentation.
The Origin Story: Productivity Through Play
Alexander’s journey began with a reaction to Unity 3D’s controversial per-install pricing model in 2023, prompting him to explore alternative game engines. Inspired by a prior Devoxx talk on productivity through fun, he decided to transform IntelliJ IDEA, a powerful IDE, into a game engine using its plugin platform. Built with Kotlin and Java Swing, his approach avoided external frameworks like JavaFX or Chromium Embedded Framework to maintain authenticity. The goal was to render games within IntelliJ’s existing window, interact with code, and maximize performance, all while embracing the chaos of a developer’s curiosity. Alexander’s mantra—“productivity is messing around and having fun”—set the tone for a session that balanced technical depth with playfulness.
Pong: Proving the Concept
The first milestone was recreating Pong, the 1972 game that launched the video game industry, within IntelliJ. Using intentions (Alt+Enter context menus), Alexander rendered paddles and a ball over a code editor, leveraging Java Swing for graphics and a custom Kotlin Vector2 class inspired by Unity 3D for position and direction calculations. Collision detection was implemented by iterating through code lines, wrapping each character in a rectangle, and checking for overlaps—faking physics with simple direction reversals. This “fake it till you make it” approach ensured a functional game without complex physics, proving that IntelliJ could handle basic game logic and rendering. The demo, complete with a multiplayer jest, highlighted the feasibility of embedding games in an IDE.
State Invaders: Battling Mutable Variables
Next, Alexander tackled a backend developer’s “cardinal sin”: mutable state. He created State Invaders, a Space Invaders-inspired game where players eliminate mutable variables (var keywords) from the codebase. Using IntelliJ’s PSI (Program Structure Interface), the plugin scans for mutable fields, rendering them as enemy sprites. Players shoot these “invaders,” removing the variables from the code, humorously reducing the “chance of production crashing” from 100% to 80%. A nostalgic cutscene referencing the internet meme “All your base are belong to us” added flair. The game demonstrated how plugins can interact with code structure, offering a playful way to enforce coding best practices while maintaining a functional codebase.
Packag-Man: Navigating Dependency Mazes
Addressing another developer pain point—over-reliance on packages—Alexander built Packag-Man, a Pac-Man variant. The game generates a maze from Gradle or Maven dependency names, with each letter forming a cell. Ghosts represent past dependency mistakes, and consuming them removes the corresponding package from the build file. Sound effects, including a looped clip of a presenter saying “Java,” enhanced the experience. IntelliJ’s abstractions for dependency parsing ensured compatibility with both Gradle and Maven, showcasing the platform’s flexibility. The game’s random ghost placement added challenge, reflecting the unpredictable nature of dependency management, while reinforcing the theme of cleaning up technical debt through play.
Sonic the Test Dog and Code Hero: Unit Tests and Copy-Paste Challenges
Alexander continued with Sonic the Test Dog, a Sonic-inspired game addressing inadequate unit testing. Players navigate a vertical codebase to collect unit tests (represented as coins), with a boss battle against “Velocity Nick” in a Person.java file. Removing coins deletes tests, humorously highlighting testing pitfalls. Finally, Code Hero, inspired by Guitar Hero and OSU, tackles copy-pasting from Stack Overflow. Players type pasted code letter-by-letter to a rhythm, using open-source beat maps for timing. A live demo with an audience member showcased the game’s difficulty, proving developers must “earn” their code. These games underscored IntelliJ’s potential for creative, code-integrated interactions.
Lessons and Future Hopes
Alexander concluded with reflections on IntelliJ’s plugin platform limitations, including poor documentation, lack of MP3 and PNG support, and cumbersome APIs for color and write actions. He urged JetBrains to improve these for better game development support, humorously suggesting GIF support for explosions. Emphasizing coding as a “superpower,” he encouraged developers to experiment without fear of “bad ideas,” as the dopamine hit of a working prototype is unmatched. A final demo hinted at running Doom in IntelliJ, leaving the audience to ponder its feasibility. Alexander’s talk, blending technical ingenuity with fun, inspired attendees to explore unconventional uses of their tools.
Links:
[KotlinConf2024] Why We Can’t Have Nice Things in Kotlin: Library Challenges
Vsevolod Tolstopyatov, a Kotlin libraries team member at JetBrains, entertained KotlinConf2024 with a witty exploration of why Kotlin’s standard libraries evolve slowly. From Turkish locale bugs breaking compilers to time zone quirks skipping entire days, Vsevolod revealed the hidden complexities of API design. Through anecdotes like Twitter polls on naming and a friend’s missed alarm, he highlighted how human language, historical quirks, and real-world constraints challenge library development, urging developers to appreciate the slow, thoughtful process behind robust APIs.
Human Language: The Turkish I Debacle
Kotlin’s string functions, like toUpperCase and toLowerCase, rely on system locales, leading to unexpected issues. Vsevolod recounted a bug where code compiled in Turkey failed due to the Turkish dotted and dotless I. Uppercasing an English lowercase i in Turkish yields a dotted uppercase İ, breaking method names like intArray. This forced the deprecation of locale-dependent functions, replaced with uppercase and lowercase using a root locale. The lesson: human languages’ diversity demands careful API design to avoid breaking code across cultures.
Naming Woes: The Capitalize Conundrum
Naming APIs is deceptively hard. Vsevolod shared how the deprecated capitalize function lacked a clear replacement because “capitalize” means different things to different developers. Twitter polls revealed no consensus, and other languages like Python and Ruby use capitalize inconsistently. With all good names taken or ambiguous, Kotlin’s team struggles to craft intuitive APIs without confusing users. This naming challenge slows library updates, as new functions risk misinterpretation or overlap with existing conventions.
Time Zones: Samoa’s Missing Day
Time zone complexities plague datetime APIs. Vsevolod described a case in Samoa, which skipped December 30, 2011, to align with Australia’s time zone, jumping from UTC-10 to UTC+14. A simple date addition (e.g., December 29 + 2 days) yields inconsistent hours due to the missing day. Adding time zone parameters fixes this but complicates APIs, especially on devices crossing time zone boundaries, like aircraft. These real-world quirks force Kotlin to balance simplicity with correctness, often at the cost of elegance.
Daylight Saving Time: Bug Hunting’s Legacy
Daylight saving time (DST) adds further headaches. Vsevolod traced DST to George Hudson, a 19th-century entomologist who proposed time shifts to hunt bugs in New Zealand. During DST transitions, times like 2:30 AM may not exist (spring forward) or occur twice (fall back), breaking datetime calculations. An anecdote about Vsevolod’s friend Vlad, whose smart home set a 9:30 AM alarm instead of 8:30 AM during a DST shift, underscored the need for explicit API parameters to handle ambiguous times, sacrificing simplicity.
API Design: Slow and Steady Wins
Vsevolod concluded that Kotlin’s libraries evolve slowly to avoid mistakes. Rushed APIs lead to bugs, like Vlad’s missed alarm, requiring years of maintenance. Thoughtful design, considering edge cases like locales, time zones, and DST, ensures reliability but delays releases. Twitter polls and community feedback help, but the real world’s complexity—political, historical, and cultural—demands patience. By prioritizing robustness, Kotlin’s team crafts APIs that won’t “get anyone fired,” even if it means fewer “nice things” per release.
Links:
[KotlinConf2024] Hacking Sony Cameras with Kotlin
At KotlinConf2024, Rahul Ravikumar, a Google software engineer, shared his adventure reverse-engineering Sony’s Bluetooth Low Energy (BLE) protocol to build a Kotlin Multiplatform (KMP) remote camera app. Frustrated by Sony’s bloated apps—Imaging Edge Mobile (1.9 stars) and Creators’ App (3.3 stars)—Rahul crafted a lean solution for his Sony Alpha a7r Mark 5, focusing on remote control. Using Compose Multiplatform for desktop and mobile, and Sony’s C SDK via cinterop, he demonstrated how KMP enables cross-platform innovation. His live demo, clicking a photo with a single button, thrilled the audience and showcased BLE’s potential for fun and profit.
Reverse-Engineering Sony’s BLE Protocol
Rahul’s journey began with Sony’s underwhelming app ecosystem, prompting him to reverse-engineer the camera’s undocumented BLE protocol. BLE’s Generic Access Profile (GAP) handles device discovery, with the camera (peripheral) advertising its presence and the phone (central) connecting. The Generic Attribute Profile (GATT) manages commands, using 16-bit UUIDs for services like Sony’s remote control (FF01 for commands, FF02 for notifications). Unable to use Android’s HCI Snoop logs due to Sony’s Wi-Fi Direct reliance, Rahul employed a USB BLE sniffer and Wireshark to capture GATT traffic. He identified Sony’s company ID (0x02D01) and camera marker (0x03000) in advertising packets. Key operations—reset (0x0106), focus (0x0107), and capture (0x0109)—form a state machine, with notifications (e.g., 0x023F) confirming actions. This meticulous process, decoding hexadecimal payloads, enabled Rahul to control the camera programmatically.
Building a KMP Remote Camera App
With the protocol cracked, Rahul built a KMP app using Compose Multiplatform, targeting Android and desktop. The app’s BLE scanner filters for Sony’s manufacturer data (0x03000), ignoring irrelevant metadata like model codes. Connection logic uses Kotlin Flows to monitor peripheral state, ensuring seamless reconnections. Capturing a photo involves sending reset and focus commands to FF01, awaiting focus confirmation on FF02, then triggering capture and shutter reset. For advanced features, Rahul integrated Sony’s C SDK via cinterop, navigating its complexities to access functions like interval shooting. His live demo, despite an initially powered-off camera, succeeded when the camera advertised, and a button click took a photo, earning audience cheers. The app’s simplicity contrasts Sony’s feature-heavy apps, proving KMP’s power for cross-platform development. Rahul’s GitHub repository offers the code, inviting developers to explore BLE and KMP for their own projects.
Links:
Hashtags: #KotlinMultiplatform #BluetoothLE
[KotlinConf2024] Exploring Exposed: Kotlin’s Database Solution
At KotlinConf2024, Chantal Loncle, a JetBrains Exposed team member, introduced Exposed, an open-source Kotlin library simplifying database access. Since its 2016 debut as a JetBrains internal tool, Exposed has grown into a versatile abstraction layer, supporting multiple databases with type-safe SQL and minimal boilerplate. Chantal guided attendees through configuring connections, defining schemas, manipulating data via DSL, DAO, and plain SQL, and extending functionality with custom features, showcasing Exposed’s flexibility for Kotlin developers.
Why Exposed? Solving Database Pain Points
Exposed addresses common database access challenges, offering a balance between control and abstraction. Chantal explained that developers often need to map Kotlin objects to database records without complex SQL or frameworks requiring annotations. Exposed supports this by providing type-safe interactions, reducing boilerplate, and abstracting database differences. Its cuttlefish mascot reflects its adaptability, enabling database-agnostic apps. Whether needing high-level abstraction or low-level SQL control, Exposed’s consistent API caters to diverse needs, as seen in its growing popularity, ranking sixth among JetBrains’ GitHub repositories.
Setting Up Database Connections
Connecting to a database with Exposed is straightforward yet flexible. Chantal demonstrated the databaseConnect function, which accepts a connection URL or data source and relies on JDBC drivers. This function doesn’t establish a connection immediately but configures details for later use. Developers can set parameters via a config builder for specific database needs or create multiple connections by storing instances. This approach ensures Exposed handles underlying database variations, allowing developers to focus on application logic rather than connection management.
Transactions: The Heart of Data Operations
Transactions are central to Exposed’s data manipulation. Chantal illustrated how the transaction function wraps operations like schema creation or data inserts, accepting a database instance or defaulting to a registered one. For multiple connections, developers can set a default database or override settings per transaction. Transactions ensure atomicity, committing or rolling back changes, and Exposed’s transaction manager simplifies resource handling. This design supports both simple and complex workflows, with utility functions like SchemaUtils.create generating SQL tailored to the target database.
Defining Schemas with Table Objects
Schema definition in Exposed revolves around the Table class, which maps Kotlin data classes to database tables. Chantal used a docking bay app example, tracking ships and planets. For a Planets table, developers register columns (e.g., auto-incrementing Long for IDs, String for names) and constraints like primary keys. For a Ships table, a foreign key references Planets, establishing a one-to-many relationship. Exposed’s SchemaUtils handles table creation or updates, checking existing schemas to generate necessary SQL, ensuring compatibility across databases like PostgreSQL or MySQL.
Data Manipulation: DSL and DAO Approaches
Exposed offers two data manipulation approaches: domain-specific language (DSL) and data access object (DAO). Chantal showcased DSL’s SQL-like syntax, where extension functions like insert or selectAll on table objects build type-safe queries. For example, inserting a ship involves assigning column values, with autogenerated keys accessible post-insertion. The DAO approach, less verbose, maps records to entity classes, abstracting SQL further. Developers call new on entities instead of insert, manipulating fields directly. Both methods, switchable via configuration, support complex queries, joins, and updates, catering to different preferences.
Plain SQL and Extensibility
For developers needing direct SQL control, Exposed’s exec function runs raw SQL strings, as Chantal demonstrated with a stored function to calculate maximum planet distances. Beyond core functionality, Exposed shines in extensibility. Statement interceptors allow custom logic, like logging deletions, at specific lifecycle points. Entity hooks in DAO mode achieve similar customization. Custom column types, such as a PostgreSQL IntRange for pricing, extend Exposed to unsupported data types. These features, supported by open classes, empower developers to tailor Exposed to unique requirements, enhancing its versatility.
Future of Exposed: Roadmap and Community
Exposed’s roadmap reflects its community-driven evolution, with 43 new contributors in 2023 halving the GitHub issue backlog. Chantal highlighted plans for a stable 1.0 release, improved documentation with tutorials, and migration support via integration with tools like Flyway. IDE tooling will autogenerate table and entity classes, reducing boilerplate, while R2DBC support will enable non-blocking database operations. Community feedback remains vital, as seen in Q&A discussions on migration scripts, ensuring Exposed continues to meet developer needs across diverse applications.