Recent Posts
Archives

Archive for the ‘General’ Category

PostHeaderIcon [KotlinConf2023] Dissecting Kotlin: Exploring Idiomatic Usage of Sealed Types, SAMs, and More with Huyen Tue Dao

Huyen Tue Dao, a respected Android and Kotlin developer (formerly of Trello, more recently Lead Android Developer at Adobe), returned to KotlinConf’23 with her insightful talk, “Dissecting Kotlin: Unsealing the Sealed, the SAM, and Other Syntax”. Continuing her exploration of what constitutes “idiomatic Kotlin,” Huyen examined several language and library features introduced or refined over the past few years, delving into their semantics, syntax, and underlying implementations to understand their best use cases and how they fit into Kotlin’s broader themes. She referenced Andre Breslav’s 2018 KotlinConf keynote, which emphasized Kotlin’s pragmatic goals: readability over concision, reuse over expressiveness, interoperability, and safety/tooling.

Huyen’s approach involved dissecting features to see if they guide developers toward more idiomatic Kotlin or present choices where idiomatic usage might be nuanced.

Sealed Hierarchies: Evolution and Flexibility

Huyen began by revisiting sealed classes and interfaces, a cornerstone for modeling restricted hierarchies, often used for representing states or a fixed set of types. Key evolutions she discussed include:
* Sealed Interfaces (Kotlin 1.5): Previously, sealed hierarchies were restricted to sealed class and abstract class. The introduction of sealed interface provided more flexibility, allowing classes to implement multiple sealed interfaces and enabling a wider range of domain modeling possibilities. She illustrated this by evolving a movie genre example, initially a sealed class, to use sealed interfaces for sub-genres, demonstrating how a class (e.g., a specific movie) could belong to multiple genre classifications.
* Unsealing Sealed Classes (Implicitly): While not “unsealing” in the sense of breaking the restriction, the ability for subclasses of sealed classes to be defined in different files within the same compilation unit and module (introduced before Kotlin 1.5 for sealed classes, and a natural fit for sealed interfaces) offers more organizational flexibility for larger hierarchies.
* Data Objects (Kotlin 1.9): For singleton instances within a sealed hierarchy (or elsewhere) that benefit from data class-like behavior (e.g., a meaningful toString()), Kotlin 1.9 introduced data object. This combines the singleton nature of object with the auto-generated toString, equals, and hashCode methods of data classes, providing a cleaner way to represent simple, named instances in a hierarchy.

A “bytecode break” showed that sealed classes are compiled as abstract classes with private constructors and that their permitted subclasses are often checked using instanceof and specific class metadata generated by the compiler.

Unsigned Integers and Value Classes: Expressiveness and Performance

Huyen then explored features aimed at enhancing expressiveness and performance around data representation:
* Unsigned Integer Types (UByte, UShort, UInt, ULong – Stable in Kotlin 1.5): These types provide a way to represent non-negative numbers, utilizing the full bit-width for the magnitude. This is particularly useful when interacting with native APIs (like C++) that use unsigned types, or when dealing with data where negative values are meaningless (e.g., quantities, bitmasks). They come with their own set of operations and ranges. Huyen highlighted how they avoid the complexities of two’s complement interpretation when only positive values are needed.
* Value Classes (Inline Classes became Value Classes, stable with JVM backend in Kotlin 1.5): Value classes (@JvmInline value class) are wrappers around a single underlying property. Their primary benefit is providing type safety for primitive-like data (e.g., Email, UserId, Frequency) without the runtime overhead of heap allocation for the wrapper object in many cases. When possible, the compiler “inlines” the value, using the underlying type directly in bytecode, thus avoiding object allocation and offering performance benefits similar to primitives while retaining type distinction at compile time. Huyen used an audio processing example with distinct types like Frequency, SamplingRate, and FramesPerBuffer to illustrate how value classes can prevent accidental misuse of simple types like Int or Float.

SAM Conversions and Functional Interfaces: Java Interop and Kotlin Idiom

Finally, Huyen discussed Single Abstract Method (SAM) interfaces and Kotlin’s fun interface:
* SAM Conversions for Java Interfaces: Kotlin has long supported SAM conversions for Java interfaces, allowing a lambda to be used where an instance of a Java interface with a single abstract method is expected.
* fun interface (Kotlin 1.4): To enable similar idiomatic usage for Kotlin-defined interfaces, Kotlin introduced fun interface. By marking a Kotlin interface with the fun keyword, developers explicitly opt-in to SAM conversion, allowing a lambda to be directly passed where an instance of that interface is required. This promotes a more functional style and reduces boilerplate for simple callback-like interfaces. This feature aims to provide compatible syntax between Java and Kotlin code for functional interfaces.

Huyen concluded by reiterating that while understanding syntax and semantics is helpful, “idiomatic Kotlin” ultimately is about what best solves the problem at hand for the developer and their team, aligning with Kotlin’s pragmatic principles.

Links:

PostHeaderIcon [PHPForumParis2022] Once Upon a Time… Web Browsers – Noël Macé and Pierre Tibulle

Noël Macé and Pierre Tibulle, passionate advocates for web standards, delivered a captivating narrative at PHP Forum Paris 2022, tracing the evolution of web browsers from their inception to the present day. Their talk, structured as a historical journey, began with Tim Berners-Lee’s pioneering work at CERN in 1980 and explored the technological and ethical shifts that shaped the modern web. Noël and Pierre’s engaging delivery, enriched with anecdotes, offered developers a deeper understanding of browsers’ impact on PHP development and user privacy.

The Birth of the Web

Noël and Pierre opened with Tim Berners-Lee’s creation of the first browser interface at CERN, designed to manage particle accelerators with a simple 24-line, 64-character display. This foundational work laid the groundwork for the World Wide Web, introduced in 1991. They described the rapid evolution of early browsers like Mosaic and Netscape, which introduced graphical interfaces, transforming the web into a user-friendly platform and setting the stage for PHP’s role in dynamic web applications.

Browser Wars and Standardization

The presenters chronicled the intense browser wars of the 1990s, where Netscape and Internet Explorer competed for dominance, often at the cost of compatibility. They highlighted the formation of the W3C and its role in standardizing web technologies, ensuring cross-browser consistency. Noël and Pierre emphasized how these standards, driven by open collaboration, enabled PHP developers to build reliable, cross-platform applications, underscoring the importance of adhering to W3C guidelines in modern development.

Privacy and Ethical Considerations

Shifting to contemporary challenges, Noël and Pierre addressed the growing importance of user privacy. They recommended tools like Privacy Badger and Firefox to mitigate tracking, noting issues like GitHub’s editor requiring data collection for basic functionality. By advocating for active engagement with the W3C’s open discussions on GitHub, they encouraged developers to influence web standards, ensuring browsers align with ethical values and support privacy-focused PHP applications.

Shaping the Future of the Web

Concluding, Noël and Pierre inspired developers to contribute to the web’s evolution by participating in W3C discussions and reporting issues to platforms like GitHub. Their call to action emphasized the developer’s role in advocating for a user-respecting web. By blending historical context with practical advice, they provided PHP developers with a roadmap to navigate browser-related challenges, fostering a more inclusive and ethical digital landscape.

Links:

PostHeaderIcon [SpringIO2023] Spring Framework 6.1: Infrastructure Revisited by Juergen Hoeller

At Spring I/O 2023 in Barcelona, Juergen Hoeller, a pivotal figure in the Spring Framework, delivered an insightful session on the upcoming Spring Framework 6.1, focusing on its alignment with cutting-edge JVM innovations. Building on themes introduced in the conference keynote, Juergen explored how Spring Framework 6.1 integrates with OpenJDK’s Project Loom (virtual threads) and CRaC (Checkpoint/Restore), empowering developers to leverage these advancements for scalable, efficient applications. With Spring Framework 6.1 and Spring Boot 3.2 set for release in November 2023, this talk offered a forward-looking perspective on infrastructure enhancements already available in snapshots and slated for the first milestone in June 2023.

Modern Java and Jakarta EE Context

Juergen set the stage by outlining the Java and Jakarta EE landscape that Spring Framework 6.1 inhabits. Spring Framework 6.0 established a JDK 17 baseline, introducing language innovations like record types, sealed classes, and pattern matching, which provide a robust foundation for modern Java development. JDK 21, a long-term support release arriving in September 2023, builds on this with further enhancements, including sequence collections and virtual threads exiting preview. Spring Framework 6.1 aligns with JDK 21, enabling developers to adopt these features seamlessly. On the Jakarta EE front, Spring Framework 6.1 supports Jakarta EE 10, with plans to align with Jakarta EE 11’s anticipated JDK 21 requirement in 2024. This ensures compatibility with evolving servlet, JPA, and bean validation APIs, positioning Spring as a bridge to future Java ecosystems.

Virtual Threads: Scalability with Simplicity

A cornerstone of Juergen’s talk was Spring Framework 6.1’s integration with virtual threads, a transformative JVM feature in JDK 21. Virtual threads, lightweight and JVM-managed, allow blocking operations without tying up platform threads, enabling massive scalability with minimal resource overhead. Juergen explained that Spring’s task executor facilities, like SimpleAsyncTaskExecutor and a dedicated VirtualThreadTaskExecutor, are now virtual thread-ready. These allow developers to replace traditional thread pool configurations with virtual thread setups, requiring minimal code changes. In Spring MVC, virtual threads are configured at the servlet container level (e.g., Tomcat or Jetty), with upcoming Tomcat releases offering first-class support. For reactive stacks like Spring WebFlux, virtual threads serve as an escape hatch for integrating blocking operations, complementing the reactive model’s efficiency. Juergen emphasized that existing Spring MVC applications can achieve higher scalability or reduced memory footprints by adopting virtual threads, with no application code changes in ideal scenarios.

Checkpoint/Restore: Revolutionizing Startup Time

Juergen also delved into Spring Framework 6.1’s support for Project CRaC, which dramatically accelerates application startup through JVM snapshotting. By capturing a fully bootstrapped application state—potentially after warmup—and restoring it on demand, CRaC reduces startup times by a factor of at least 20 compared to traditional JVM bootstrapping. Spring Framework 6.1 integrates CRaC via its lifecycle model, using the 14-year-old Lifecycle interface to manage component stop and restart signals during checkpoint and restore phases. This ensures that embedded servers, message listeners, and other components pause cleanly and resume seamlessly. Juergen noted that most Spring applications are CRaC-compatible out of the box, though some components, like Tomcat adapters, require updates. Spring Boot 3.2 may introduce standard checkpoint options post-bootstrap, simplifying adoption. Currently supported by Azul’s OpenJDK and AWS Lambda SnapStart, CRaC promises significant benefits for dynamic scaling in Linux container deployments.

Practical Adoption and Future Outlook

Juergen underscored the practical readiness of these features, with Spring Framework 6.1 M1 slated for mid-June 2023 and Spring Boot 3.2 M1 for mid-July. Release candidates are planned for October, aligning with JDK 21’s September release, ensuring developers can adopt virtual threads and CRaC promptly. He encouraged experimentation, noting that benchmarking virtual threads or CRaC with existing applications is the best way to quantify benefits like scalability or reduced startup times. Looking ahead, Juergen highlighted a Spring.Next Buff session at Spring I/O for deeper discussions on these innovations. By aligning with JDK 21 and Jakarta EE 11, Spring Framework 6.1 positions developers to embrace the Java ecosystem’s future, delivering performance and efficiency without sacrificing Spring’s hallmark simplicity.

Links:

PostHeaderIcon [DevoxxBE 2023] Introducing Flow: The Worst Software Development Approach in History

In a satirical yet insightful closing keynote at Devoxx Belgium 2023, Sander Hoogendoorn and Kim van Wilgen, seasoned software development experts, introduced “Flow,” a fictional methodology designed to expose the absurdities of overly complex software development practices. With humor and sharp critique, Sander and Kim drew from decades of experience to lampoon methodologies like Waterfall, Scrum, SAFe, and Spotify, blending real-world anecdotes with exaggerated principles to highlight what not to do. Their talk, laced with wit, ultimately transitioned to earnest advice, advocating for simplicity, autonomy, and human-centric development. This presentation offers a mirror to the industry, urging developers to critically evaluate methodologies and prioritize effective, enjoyable work.

The Misadventure of Methodologies

Sander kicked off with a historical detour, debunking the myth of Waterfall’s rigidity. Citing Winston Royce’s 1970 paper, he revealed that Waterfall was meant to be iterative, allowing developers to revisit phases—a concept ignored for decades, costing billions. This set the stage for Flow, a methodology born from a tongue-in-cheek desire to maximize project duration for consultancy profits. Kim explained how they cherry-picked the worst elements from existing frameworks: endless sprints from Scrum, gamification to curb autonomy, and an alphabet soup of roles from SAFe.

Their critique was grounded in real-world failures. Sander shared a Belgian project where misestimated sprints and 300 outsourced developers led to chaos, exacerbated by documentation in Dutch and French. Kim highlighted how methodologies like SAFe balloon roles, sidelining customers and adding complexity. By naming Flow with trendy buzzwords—Kaizen, continuous disappointment, and pointless—they mocked the industry’s obsession with jargon over substance.

The Flow Framework: A Recipe for Dysfunction

Flow’s principles, as Sander and Kim outlined, are deliberately counterproductive. Sprints, renamed “mini-Waterfalls,” ensure repeated failures, with burn charts (not burn-down charts) showing growing work without progress. Meetings, dubbed “Flow meetings,” are scheduled to disrupt developers’ focus, with random topics and high-placed interruptions—like a 2.5-meter-tall CEO bursting in. Kim emphasized gamification, stripping teams of real autonomy while offering trivial perks like workspace decoration, exemplified by a ball pit job interview at a Dutch e-commerce firm.

The Flow Manifesto, a parody of the Agile Manifesto, prioritizes “extensive certification over hands-on experience” and “meetings over focus.” Sander recounted a project in France with a 20-column board so confusing that even AI couldn’t decipher its French Post-its. Jira, mandatory in Flow, becomes a tool for obfuscation, with requirements buried in lengthy tickets. Open floor plans and Slack further stifle communication, with “pair slacking” replacing collaboration, ensuring developers remain distracted and disconnected.

Enterprise Flow: Scaling the Absurdity

In large organizations, Flow escalates into the Big Flow Framework (BFF), starting at version 3.0 to sound innovative. Kim critiqued the blind adoption of Spotify’s model, designed for 8x annual growth, which saddles banks with excessive managers—sometimes a 1:1 ratio with developers. Sander recounted a client renaming managers as “tech leads,” adding 118 unnecessary roles to a release train. Certifications, costing €10,000 per recertification, parody the industry’s profit-driven training schemes.

Flow’s tooling, like boards with incomprehensible columns and Jira’s dual Scrum-Kanban confusion, ensures clients remain baffled. Kim highlighted how Enterprise Flow thrives on copying trendy startups like Basecamp, debating irrelevant issues like banning TypeScript or leaving public clouds. Research, they noted, shows no methodology—including SAFe or LeSS—outperforms having none, underscoring Flow’s satirical point: complexity breeds failure.

A Serious Turn: Principles for Better Development

After the laughter, Sander and Kim pivoted to their true beliefs, advocating for a human-centric approach. Software, they stressed, is built by people, not tools or methodologies. Teams should evolve their own practices, using Scrum or Kanban as starting points but adapting to context. Face-to-face communication, trust, and psychological safety are paramount, as red sprints and silencing voices drive talent away.

Focus is sacred, requiring quiet spaces and flexible hours, as ideas often spark outside 9–5. Continuous learning, guarded by dedicating at least one day weekly, prevents stagnation. Autonomy, though initially uncomfortable, empowers teams to make decisions, as Sander’s experience with reluctant developers showed. Flat organizations with minimal hierarchy foster trust, while experienced developers, like those born in the ’60s and ’70s, mentor through code reviews rather than churning out code.

Conclusion: Simplicity and Joy in Development

Sander and Kim’s Flow is a cautionary tale, urging developers to reject bloated methodologies and embrace simplicity. By reducing complexity, as Albert Einstein suggested, teams can deliver value effectively. Above all, they reminded the audience to have fun, celebrating software development as the best industry to be in. Their talk, blending satire with wisdom, inspires developers to craft methodologies that empower people, foster collaboration, and make work enjoyable.

Hashtags: #SoftwareDevelopment #Agile #Flow #Methodologies #DevOps #SanderHoogendoorn #KimVanWilgen #SchubergPhilis #iBOOD #DevoxxBE2023

PostHeaderIcon [DevoxxBE 2023] The Great Divergence: Bridging the Gap Between Industry and University Java

At Devoxx Belgium 2023, Felipe Yanaga, a teaching assistant at the University of North Carolina at Chapel Hill and a Robertson Scholar, delivered a compelling presentation addressing the growing disconnect between the vibrant use of Java in industry and its outdated perception in academia. As a student with internships at Amazon and Google, and a fellow at UNC’s Computer Science Experience Lab, Felipe draws on his unique perspective to highlight how universities lag in teaching modern Java practices. His talk explores the reasons behind this divergence, the negative perceptions students hold about Java, and actionable steps to revitalize its presence in academic settings.

Java’s Strength in Industry

Felipe begins by emphasizing Java’s enduring relevance in the professional world. Far from the “Java is dead” narrative that periodically surfaces online, the language thrives in industry, powered by innovations like Quarkus, GraalVM, and a rapid six-month release cycle. Companies sponsoring Devoxx, such as Red Hat and Oracle, exemplify Java’s robust ecosystem, leveraging frameworks and tools that enhance developer productivity. For instance, Felipe references the keynote by Brian Goetz, which outlined Java’s roadmap, showcasing its adaptability to modern development needs by drawing inspiration from other languages. This continuous evolution ensures Java remains a cornerstone for enterprise applications, from microservices to large-scale systems.

However, Felipe points out a troubling trend: despite its industry strength, Java’s popularity is declining in metrics like GitHub’s language rankings and the TIOBE Index. While JavaScript and Python have surged, Java’s share of relevant Google searches has dropped from 26% in 2002 to under 10% by 2023. Felipe attributes this partly to a shift in academic settings, where the foundation for programming passion is often laid. The disconnect between industry innovation and university curricula is a critical issue that needs addressing to sustain Java’s future.

The Academic Lag: Java’s Outdated Image

In universities, Java’s reputation suffers from outdated teaching practices. Felipe notes that many institutions, including top U.S. universities, have shifted introductory courses from Java to Python, citing Java’s perceived complexity and age. A 2017 quote from a Stanford professor illustrates this sentiment, claiming Java “shows its age” and prompting a move to Python for introductory courses. Surveys of 70 leading U.S. universities confirm this trend, with Python now dominating as the primary teaching language, while Java is relegated to data structures or object-oriented programming courses.

Felipe’s own experience at UNC-Chapel Hill reflects this shift. A decade ago, Java dominated the curriculum, but by 2023, Python had overtaken introductory and database courses. This transition reinforces a perception among students that Java is verbose, bloated, and outdated. Felipe conducted a survey among 181 students in a software engineering course, revealing stark insights: 42% believed Python was in highest industry demand, 67% preferred Python for building REST APIs, and terms like “tedious,” “boring,” and “outdated” dominated a word cloud describing Java. One student even remarked that Java is suitable only for maintaining legacy code, a sentiment that underscores the stigma Felipe aims to dismantle.

The On-Ramp Challenge: Simplifying Java’s Introduction

A significant barrier to Java’s adoption in academia is its steep learning curve for beginners. Felipe contrasts Python’s straightforward “hello world” with Java’s intimidating boilerplate code, such as public static void main. This complexity overwhelms novices, who grapple with concepts like classes and static methods without clear explanations. Instructors often dismiss these as “magic,” which disengages students and fosters a negative perception. Felipe highlights Java’s JEP 445, which introduces unnamed classes and instance main methods to reduce boilerplate, as a promising step to make Java more accessible. By simplifying the initial experience, such innovations could align Java’s on-ramp with Python’s ease, engaging students early and encouraging exploration.

Beyond the language itself, the Java ecosystem poses additional challenges. Installing Java is daunting for beginners, with multiple Oracle websites offering conflicting instructions. Felipe recounts his own struggle as a student, only navigating this thanks to his father’s guidance. Tools like SDKMan and JBang simplify installation and scripting, but these are often unknown to students outside the Java community. Similarly, choosing an IDE—IntelliJ, Eclipse, or VS Code—adds another layer of complexity. Felipe advocates for clear, standardized guidance, such as recommending SDKMan and IntelliJ, to streamline the learning process and make Java’s ecosystem more approachable.

Bridging the Divide: Community and Mentorship

To reverse the declining trend in academia, Felipe proposes actionable steps centered on community engagement. He emphasizes the need for industry professionals to connect with universities, citing examples like Tom from Info Support, who collaborates with local schools to demonstrate Java’s real-world applications. By mentoring students and updating professors on modern tools like Maven, Gradle, and Quarkus, industry can reshape Java’s image. Felipe also encourages inviting students to Java User Groups (JUGs), where they can interact with professionals and discover tools that enhance Java development. These initiatives, he argues, plant seeds of enthusiasm that students will share with peers, amplifying Java’s appeal.

Felipe stresses that small actions, like a 10-minute conversation with a student, can make a significant impact. By demystifying stereotypes—such as Java being slow or bloated—and showcasing frameworks like Quarkus with hot reload capabilities, professionals can counter misconceptions. He also addresses the lack of Java-focused workshops compared to Python and JavaScript, urging the community to actively reach out to students. This collective effort, Felipe believes, is crucial to ensuring the next generation of developers sees Java as a vibrant, modern language, not a relic of the past.

Links:

  • University of North Carolina at Chapel Hill

  • Duke University

Hashtags: #Java #SoftwareDevelopment #Education #Quarkus #GraalVM #UNCChapelHill #DukeUniversity #FelipeYanaga

PostHeaderIcon [NodeCongress2023] Building a Modular Monolith in Node.js: The Fastify Architecture for Scalable Development

Lecturer: Matteo Collina

Matteo Collina is the Co-Founder and Chief Technology Officer (CTO) of Platformatic.dev, focusing on reducing friction in backend development. He is a prominent figure in the JavaScript and Node.js open-source communities, serving as a member of the Node.js Technical Steering Committee (TSC), concentrating on streams, diagnostics, and HTTP. Dr. Collina is the creator and maintainer of several foundational Node.js projects, including the high-performance web framework Fastify and the super-fast JSON logger Pino. He completed his Ph.D. in 2014, with his thesis focusing on “Application Platforms for the Internet of Things”.

Abstract

This article explores the architectural pattern of the modular monolith as a superior alternative to monolithic or premature microservice designs in the Node.js ecosystem, using the Fastify framework as the primary methodology. The analysis highlights how Fastify’s plugin system allows developers to create well-organized, testable, and maintainable applications by enforcing clear separation of concerns and rigorously avoiding the anti-pattern of global Singletons. Furthermore, it details how this architectural choice establishes a robust foundation that facilitates a near-frictionless migration to a microservices architecture when required.

Context: The Challenge of Free-Form Development

The inherent flexibility of the Node.js development model—while powerful—often leads to organizational and structural issues in large codebases, frequently resulting in “big ball of mud” monoliths. A key contributor to this technical debt is the liberal use of Singletons, global objects (like a database connection or configuration store) that hide dependencies and make components non-reusable and difficult to test in isolation.

Methodology: Fastify and the Modular Monolith

The proposed solution is the modular monolith, implemented using Fastify’s architectural features:

  • Fastify Plugin System: Fastify’s core design dictates that any component (routes, business logic, configuration) must be encapsulated as a plugin. This system is fundamentally based on a Directed Acyclic Graph (DAG) architecture.
  • Encapsulation and Scoping: When a plugin registers a dependency (e.g., a database connection), it gets its own encapsulated scope. Subsequent plugins registered underneath it inherit that dependency, but plugins registered in parallel do not. This rigorous encapsulation is the mechanism that prevents global Singletons, ensuring clear dependency flow and isolation of modules.
  • Code-First Configuration: Using tools like platformatic/service, the structure of the application—including plugins, databases, and general configuration—can be defined declaratively in a single configuration file.

Analysis of Implications

The modular monolith, when built with this methodology, offers significant consequences for engineering workflow and application lifecycle:

  • Improved Testability and Organization: The strict encapsulation ensures that each module (plugin) can be tested in isolation, knowing precisely its inputs and outputs, leading to a codebase that can “stand the test of time”.
  • Production Readiness: The architecture easily accommodates production-level features such as automatic OpenAPI documentation and Prometheus metrics integration via simple configuration toggles.
  • Seamless Microservice Migration: By maintaining clear separation of concerns and avoiding shared state (i.e., a “share nothing architecture”), the architectural components created as Fastify plugins are already structurally prepared to be extracted into independent microservices. The transition is reduced to primarily a configuration step, validating the modular monolith as an intelligent starting point.

Conclusion

The use of Fastify to architect a modular monolith is a powerful and pragmatic solution for scalable Node.js development. It resolves the core issues of structural degradation and hidden dependencies inherent in free-form Node.js development by leveraging a robust plugin system that enforces encapsulation. This pattern ensures maintainability, simplifies testing, and provides a clear, low-friction pathway for future transition to a fully distributed microservices architecture.

Relevant links and hashtags

Hashtags: #ModularMonolith #Fastify #NodeJSArchitecture #Microservices #SoftwareDesign #OpenSource #NodeCongress

PostHeaderIcon [KotlinConf’2023] Coroutines and Loom: A Deep Dive into Goals and Implementations

The advent of OpenJDK’s Project Loom and its virtual threads has sparked considerable discussion within the Java and Kotlin communities, particularly regarding its relationship with Kotlin Coroutines. Roman Elizarov, Project Lead for Kotlin at JetBrains, addressed this topic head-on at KotlinConf’23 in his talk, “Coroutines and Loom behind the scenes”. His goal was not just to answer whether Loom would make coroutines obsolete (the answer being a clear “no”), but to delve into the distinct design goals, implementations, and trade-offs of each, clarifying how they can coexist and even complement each other. Information about Project Loom can often be found via OpenJDK resources or articles like those on Baeldung.

Roman began by noting that Project Loom, introducing virtual threads to the JVM, was nearing stability, targeted for Java 21 (late 2023). He emphasized that understanding the goals behind each technology is crucial, as these goals heavily influence their design and optimal use cases.

Project Loom: Simplifying Server-Side Concurrency

Project Loom’s primary design goal, as Roman Elizarov explained, is to preserve the thread-per-request programming style prevalent in many existing Java server-side applications, while dramatically increasing scalability. Traditionally, assigning one platform thread per incoming request becomes a bottleneck due to the high cost of platform threads. Virtual threads aim to solve this by providing lightweight, JVM-managed threads that can run existing synchronous, blocking Java code with minimal or no changes. This allows legacy applications to scale much better without requiring a rewrite to asynchronous or reactive patterns.

Loom achieves this by “unmounting” a virtual thread from its carrier (platform) thread when it encounters a blocking operation (like I/O) that has been integrated with Loom. The carrier thread is then free to run other virtual threads. When the blocking operation completes, the virtual thread is “remounted” on a carrier thread to continue execution. This mechanism is largely transparent to the application code. However, Roman pointed out a potential pitfall: if blocking operations occur within synchronized blocks or native JNI calls that haven’t been adapted for Loom, the carrier thread can get “pinned,” preventing unmounting and potentially negating some of Loom’s benefits in those specific scenarios.

Kotlin Coroutines: Fine-Grained, Structured Concurrency

In contrast, Kotlin Coroutines were designed with different primary goals:

  1. Enable fine-grained concurrency: Allowing developers to easily launch tens of thousands or even millions of concurrent tasks without performance issues, suitable for highly concurrent applications like UI event handling or complex data processing pipelines.
  2. Provide structured concurrency: Ensuring that the lifecycle of coroutines is managed within scopes, simplifying cancellation and preventing resource leaks. This is particularly critical for UI applications where tasks need to be cancelled when UI components are destroyed.

Kotlin Coroutines achieve this through suspendable functions (suspend fun) and a compiler-based transformation. When a coroutine suspends, it doesn’t block its underlying thread; instead, its state is saved, and the thread is released to do other work. This is fundamentally different from Loom’s approach, which aims to make blocking calls non-problematic for virtual threads. Coroutines explicitly distinguish between suspending and non-suspending code, a design choice that enables features like structured concurrency but requires a different programming model than traditional blocking code.

Comparing Trade-offs and Performance

Roman Elizarov presented a detailed comparison:

  • Programming Model: Loom aims for compatibility with existing blocking code. Coroutines introduce a new model with suspend functions, which is more verbose for simple blocking calls but enables powerful features like structured concurrency and explicit cancellation. Forcing blocking calls into a coroutine world requires wrappers like withContext(Dispatchers.IO), while Loom handles blocking calls transparently on virtual threads.
  • Cost of Operations:
    • Launching: Launching a coroutine is significantly cheaper than starting even a virtual thread, as coroutines are lighter weight objects.
    • Yielding/Suspending: Suspending a coroutine is generally cheaper than a virtual thread yielding (unmounting/remounting), due to compiler optimizations in Kotlin for state machine management. Roman showed benchmarks indicating lower memory allocation and faster execution for coroutine suspension compared to virtual thread context switching in preview builds of Loom.
  • Error Handling & Cancellation: Coroutines have built-in, robust support for structured cancellation. Loom’s virtual threads rely on Java’s traditional thread interruption mechanisms, which are less integrated into the programming model for cooperative cancellation.
  • Debugging: Loom’s virtual threads offer a debugging experience very similar to traditional threads, with understandable stack traces. Coroutines, due to their state-machine nature, can sometimes have more complex stack traces, though IDE support has improved this.

Coexistence and Future Synergies

Roman Elizarov concluded that Loom and coroutines are designed for different primary use cases and will coexist effectively.

  • Loom excels for existing Java applications using the thread-per-request model that need to scale without major rewrites.
  • Coroutines excel for applications requiring fine-grained, highly concurrent operations, structured concurrency, and explicit cancellation management, often seen in UI applications or complex backend services with many interacting components.

He also highlighted a potential future synergy: Kotlin Coroutines could leverage Loom’s virtual threads for their Dispatchers.IO (or a similar dispatcher) when running on newer JVMs. This could allow blocking calls within coroutines (those wrapped in withContext(Dispatchers.IO)) to benefit from Loom’s efficient handling of blocking operations, potentially eliminating the need for a large, separate thread pool for I/O-bound tasks in coroutines. This would combine the benefits of both: coroutines for structured, fine-grained concurrency and Loom for efficient handling of any unavoidable blocking calls.

Links:

Hashtags: #Kotlin #Coroutines #ProjectLoom #Java #JVM #Concurrency #AsynchronousProgramming #RomanElizarov #JetBrains

PostHeaderIcon [KotlinConf’23] The Future of Kotlin is Bright and Multiplatform

KotlinConf’23 kicked off with an energizing keynote, marking a highly anticipated return to an in-person format in Amsterdam. Hosted by Hadi Hariri from JetBrains, the session brought together key figures from both JetBrains and Google, including Roman Elizarov, Svetlana Isakova, Egor Tolstoy, and Grace Kloba (VP of Engineering for Android Developer Experience at Google), to share exciting updates and future directions for the Kotlin language and its ecosystem. The conference also boasted a global reach with KotlinConf Global events held across 41 countries. For those unable to attend, the key announcements from the keynote are also available in a comprehensive blog post on the official Kotlin blog.

The keynote began by celebrating Kotlin’s impressive growth, with compelling statistics underscoring its widespread adoption, particularly in Android development where it stands as the most popular language, utilized in over 95% of the top 1000 Android applications. A significant emphasis was placed on the forthcoming Kotlin 2.0, which is centered around the revolutionary new K2 compiler. This compiler promises significant performance improvements, enhanced stability, and a robust foundation for the language’s future evolution. The K2 compiler is nearing completion and is slated for release as Kotlin 2.0. Additionally, the IntelliJ IDEA plugin will also adopt the K2 frontend, ensuring alignment with IntelliJ releases and a consistent developer experience.

The Evolution of Kotlin: K2 Compiler and Language Features

The K2 compiler was a central theme of the keynote, signifying a major milestone for Kotlin. This re-architected compiler frontend, which also powers the IDE, is designed to be faster, more stable, and to enable quicker development of new language features and tooling capabilities. Kotlin 2.0, built upon the K2 compiler, is set to bring these profound benefits to all Kotlin developers, improving both compiler performance and IDE responsiveness.

Beyond the immediate horizon of Kotlin 2.0, the speakers provided a glimpse into potential future language features that are currently under consideration. These exciting prospects included:

Prospective Language Enhancements

  • Static Extensions: This feature aims to allow static resolution of extension functions, which could potentially improve performance and code clarity.
  • Collection Literals: The introduction of a more concise syntax for creating collections, such as using square brackets for lists, with efficient underlying implementations, is on the cards.
  • Name-Based Destructuring: Offering a more flexible way to destructure objects based on property names rather than simply their positional order.
  • Context Receivers: A powerful capability designed to provide contextual information to functions in a more implicit and structured manner. This feature, however, is being approached with careful consideration to ensure it aligns well with Kotlin’s core principles and doesn’t introduce undue complexity.
  • Explicit Fields: This would provide developers with more direct control over the backing fields of properties, offering greater flexibility in certain scenarios.

The JetBrains team underscored a cautious and deliberate approach to language evolution, ensuring that any new features are meticulously designed and maintainable within the Kotlin ecosystem. Compiler plugins were also highlighted as a powerful mechanism for extending Kotlin’s capabilities without altering its core.

Kotlin in the Ecosystem: Google’s Investment and Multiplatform Growth

Grace Kloba from Google took the stage to reiterate Google’s strong and unwavering commitment to Kotlin. She shared insights into Google’s substantial investments in the Kotlin ecosystem, including the development of Kotlin Symbol Processing (KSP) and the continuous emphasis on Kotlin as the default choice for Android development. Google officially championed Kotlin for Android development as early as 2017, a pivotal moment for the language’s widespread adoption. Furthermore, the Kotlin DSL is now the default for Gradle build scripts within Android Studio, significantly enhancing the developer experience with features such as semantic syntax highlighting and advanced code completion. Google also actively contributes to the Kotlin Foundation and encourages community participation through initiatives like the Kotlin Foundation Grants Program, which specifically focuses on supporting multiplatform libraries and frameworks.

Kotlin Multiplatform (KMP) emerged as another major highlight of the keynote, emphasizing its increasing maturity and widespread adoption. The overarching vision for KMP is to empower developers to share code across a diverse range of platforms—Android, iOS, desktop, web, and server-side—while retaining the crucial ability to write platform-specific code when necessary for optimal integration and performance. The keynote celebrated the burgeoning number of multiplatform libraries and tools, including KMM Bridge, which are simplifying KMP development workflows. The future of KMP appears exceptionally promising, with ongoing efforts to further enhance the developer experience and expand its capabilities across even more platforms.

Compose Multiplatform and Emerging Technologies

The keynote also featured significant advancements in Compose Multiplatform, JetBrains’ declarative UI framework for building cross-platform user interfaces. A particularly impactful announcement was the alpha release of Compose Multiplatform for iOS. This groundbreaking development allows developers to write their UI code once in Kotlin and deploy it seamlessly across Android and iOS, and even to desktop and web targets. This opens up entirely new avenues for code sharing and promises accelerated development cycles for mobile applications, breaking down traditional platform barriers.

Finally, the JetBrains team touched upon Kotlin’s expansion into truly emerging technologies, such as WebAssembly (Wasm). JetBrains is actively developing a new compiler backend for Kotlin specifically targeting WebAssembly, coupled with its own garbage collection proposal. This ambitious effort aims to deliver high-performance Kotlin code directly within the browser environment. Experiments involving the execution of Compose applications within the browser using WebAssembly were also mentioned, hinting at a future where Kotlin could offer a unified development experience across an even broader spectrum of platforms. The keynote concluded with an enthusiastic invitation to the community to delve deeper into these subjects during the conference sessions and to continue contributing to Kotlin’s vibrant and ever-expanding ecosystem.

Hashtags: #Keynote #JetBrains #Google #K2Compiler #Kotlin2 #Multiplatform #ComposeMultiplatform #WebAssembly

PostHeaderIcon [DevoxxBE2023] A Deep Dive into Advanced TypeScript: A Live Coding Expedition by Christian Wörz

Christian Wörz, a seasoned full-stack engineer and freelancer, captivated the Devoxx Belgium 2023 audience with a hands-on exploration of advanced TypeScript features. Through live coding, Christian illuminated powerful yet underutilized constructs like mapped types, template literals, conditional types, and recursion, demonstrating their practical applications in real-world scenarios. His session, blending technical depth with accessibility, empowered developers to leverage TypeScript’s full potential for creating robust, type-safe codebases.

Mastering Mapped Types and Template Literals

Christian kicked off with mapped types, showcasing their ability to dynamically generate type-safe structures. He defined an Events type with add and remove properties and created an OnEvent type to prefix event keys with “on” (e.g., onAdd, onRemove). Using the keyof operator and template literal syntax, he ensured that OnEvent mirrored Events, enforcing consistency. For instance, adding a move event to Events required updating OnEvent to onMove, providing compile-time safety. He enhanced this with TypeScript’s intrinsic Capitalize function to uppercase property names, ensuring precise naming conventions.

Template literals were explored through a chessboard example, where Christian generated all possible positions (e.g., A1, B2) by combining letter and number types. He extended this to a CSS validator, defining a GapCSS type for properties like margin-left and padding-top, paired with valid CSS sizes (e.g., rem, px). This approach narrowed string types to enforce specific formats, preventing errors like invalid CSS values at compile time.

Leveraging Conditional Types and Never for Safety

Christian delved into conditional types and the never type to enhance compile-time safety. He introduced a NoEmptyString type that prevents empty strings from being assigned, using a conditional check to return never for invalid inputs. Applying this to a failOnEmptyString function ensured that only non-empty strings were accepted, catching errors before runtime. He also demonstrated exhaustive switch cases, using never to enforce complete coverage. For a getCountryForLocation function, assigning an unhandled London case to a never-typed variable triggered a compile-time error, ensuring all cases were addressed.

Unraveling Types with Infer and Recursion

The infer keyword was a highlight, enabling Christian to extract type information dynamically. He created a custom MyReturnType to mimic TypeScript’s ReturnType, inferring a function’s return type (e.g., number for an addition function). This was particularly useful for complex type manipulations. Recursion was showcased through an UnnestArray type, unwrapping deeply nested arrays to access their inner types (e.g., extracting string from string[][][]). He also built a recursive Tuple type, generating fixed-length arrays with specified element types, such as a three-element RGB tuple, with an accumulator to collect elements during recursion.

Branded Types for Enhanced Type Safety

Christian concluded with branded types, a technique to distinguish specific string formats, like emails, without runtime overhead. By defining an Email type as a string intersected with an object containing a _brand property, he ensured that only validated strings could be assigned. A type guard function, isValidEmail, checked for an @ symbol, allowing safe usage in functions like sendEmail. This approach maintained the simplicity of primitive types while enforcing strict validation, applicable to formats like UUIDs or custom date strings.

Links:

PostHeaderIcon Secure Development with Docker: DockerCon 2023 Workshop

The DockerCon 2023 workshop, “Secure Development with Docker,” delivered by Yves Brissaud, James Carnegie, David Dooling, and Christian Dupuis from Docker, offered a comprehensive exploration of securing the software supply chain. Spanning over three hours, this session addressed the tension between developers’ need for speed and security teams’ focus on risk mitigation. Participants engaged in hands-on labs to identify and remediate common vulnerabilities, leverage Docker Scout for actionable insights, and implement provenance, software bills of materials (SBOMs), and policies. The workshop emphasized Docker’s developer-centric approach to security, empowering attendees to enhance their workflows without compromising safety. By integrating Docker Scout, attendees learned to secure every stage of the software development lifecycle, from code to deployment.

Tackling Common Vulnerabilities and Exposures (CVEs)

The workshop began with a focus on Common Vulnerabilities and Exposures (CVEs), a critical starting point for securing software. David Dooling introduced CVEs as publicly disclosed cybersecurity vulnerabilities in operating systems, dependencies like OpenSSL, or container images. Participants used Docker Desktop 4.24 and the Docker Scout CLI to scan images based on Alpine 3.14, identifying vulnerabilities in base images and added layers, such as npm packages (e.g., Express and its transitive dependency Qs). Hands-on exercises guided attendees to update base images to Alpine 3.18, using Docker Scout’s recommendations to select versions with fewer vulnerabilities. The CLI’s cve command and Desktop’s vulnerability view provided detailed insights, including severity filters and package details, enabling developers to remediate issues efficiently. This segment underscored that while scanning is essential, it’s only one part of a broader security strategy, setting the stage for a holistic approach.

Understanding Software Supply Chain Security

The second segment, led by Dooling, introduced the software supply chain as a framework encompassing source code, dependencies, build processes, and deployment. Drawing an analogy to brewing coffee—where beans, water, and equipment have their own supply chains—the workshop highlighted risks like supply chain attacks, as outlined by CISA’s open-source security roadmap. These attacks, such as poisoning repositories, differ from CVEs by involving intentional tampering. Participants explored Docker Scout’s role as a supply chain management tool, not just a CVE scanner. Using the workshop’s GitHub repository (dc23-secure-workshop), attendees set up environment variables and Docker Compose to build images, learning how Scout tracks components across the lifecycle. This segment emphasized the need to secure every stage, from code creation to deployment, to prevent vulnerabilities and malicious injections.

Leveraging Docker Scout for Actionable Insights

Docker Scout was the cornerstone of the workshop, offering a developer-friendly interface to manage security. Yves Brissaud guided participants through hands-on labs using Docker Desktop and the Scout CLI to analyze images. Attendees explored vulnerabilities in a front-end image (using Express) and a Go-based back-end image, applying filters to focus on critical CVEs or specific package types (e.g., npm). Scout’s compare command allowed participants to assess changes between image versions, such as updating from Alpine 3.14 to 3.18, revealing added or removed packages and their impact on vulnerabilities. Desktop’s visual interface displayed recommended fixes, like updating base images or dependencies, while the CLI provided detailed outputs, including quick views for rapid assessments. This segment demonstrated Scout’s ability to integrate into CI/CD pipelines, providing early feedback to developers without disrupting workflows.

Implementing Provenance and Software Bill of Materials (SBOM)

The third segment focused on provenance and SBOMs, critical for supply chain transparency. Provenance, aligned with the SALSA framework’s Build Level 1, documents how an image is built, including base image tags, digests, and build metadata. SBOMs list all packages and their versions, ensuring consistency across environments. Participants rebuilt images with the --provenance and --sbom flags using BuildKit, generating attestations stored in Docker Hub. Brissaud demonstrated using the imagetools command to inspect provenance and SBOMs, revealing details like build timestamps and package licenses. The workshop highlighted the importance of embedding this metadata at build time to enable reproducible builds and accurate recommendations. By integrating Scout’s custom SBOM indexer, attendees ensured consistent vulnerability reporting across Desktop, CLI, and scout.docker.com, enhancing trust in the software’s integrity.

Enforcing Developer-Centric Policies

The final segment introduced Docker Scout’s policy enforcement, designed with a developer mindset to avoid unnecessary build failures. Dooling explained Scout’s “first do no harm” philosophy, rooted in Kaizen’s continuous improvement principles. Unlike traditional policies that block builds for existing CVEs, Scout compares new builds to production images, allowing progress if vulnerabilities remain unchanged. Participants explored four out-of-the-box policies in Early Access: fixing critical/high CVEs, updating base images, and avoiding deprecated tags. Using the scout policy command, attendees evaluated images against these policies, viewing compliance status on Desktop and scout.docker.com. The workshop also previewed upcoming GitHub Action integrations for pull request policy checks, enabling developers to assess changes before merging. This approach ensures security without hindering development, aligning with Docker’s mission to empower developers.

Hashtags: #DockerCon2023 #SoftwareSupplyChain #DockerScout #SecureDevelopment #CVEs #Provenance #SBOM #Policy #YvesBrissaud #JamesCarnegie #DavidDooling #ChristianDupuis