Recent Posts
Archives

Archive for the ‘en-US’ Category

PostHeaderIcon Running Docker Natively on WSL2 (Ubuntu 24.04) in Windows 11

For many developers, Docker Desktop has long been the default solution to run Docker on Windows. However, licensing changes and the desire for a leaner setup have pushed teams to look for alternatives. Fortunately, with the maturity of Windows Subsystem for Linux 2 (WSL2), it is now possible to run the full Docker Engine directly inside a Linux distribution such as Ubuntu 24.04, while still accessing containers seamlessly from both Linux and Windows.

In this guide, I’ll walk you through a clean, step-by-step setup for running Docker Engine inside WSL2 without Docker Desktop, explain how Windows and WSL2 communicate, and share best practices for maintaining a healthy development environment.


Why Run Docker Inside WSL2?

Running Docker natively inside WSL2 has several benefits:

  • No licensing issues – you avoid Docker Desktop’s commercial license requirements.
  • Lightweight – no heavy virtualization layer; containers run directly inside your WSL Linux distro.
  • Integrated networking – on Windows 11 with modern WSL versions,
    containers bound to localhost inside WSL are automatically reachable from Windows.
  • Familiar Linux workflow – you install and use Docker exactly as you would on a regular Ubuntu server.

Step 1 – Update Ubuntu

Open your Ubuntu 24.04 terminal and ensure your system is up to date:

sudo apt update && sudo apt upgrade -y

Step 2 – Install Docker Engine

Install Docker using the official Docker repository:

# Install prerequisites
sudo apt install -y ca-certificates curl gnupg lsb-release

# Add Docker’s GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# Configure Docker repository
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Install Docker Engine
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Step 3 – Run Docker Without sudo

To avoid prefixing every command with sudo, add your user to the docker group:

sudo usermod -aG docker $USER

Restart your WSL terminal for the change to take effect, then verify:

docker --version
docker ps

Step 4 – Test Networking

One of the most common questions is:
“Will my containers be accessible from both Ubuntu and Windows?”
The answer is yes on modern Windows 11 with WSL2.
Let’s test it by running an Nginx container:

docker run -d -p 8080:80 --name webtest nginx
  • Inside Ubuntu (WSL): curl http://localhost:8080
  • From Windows (browser or PowerShell): http://localhost:8080

Thanks to WSL2’s localhost forwarding, Windows traffic to localhost is routed
into the WSL network, making containers instantly accessible without extra configuration.


Step 5 – Run Multi-Container Applications with Docker Compose

The Docker Compose plugin is already installed as part of the package above. Check the version:

docker compose version

Create a docker-compose.yml for a WordPress + MySQL stack:

version: "3.9"
services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wpuser
      MYSQL_PASSWORD: wppass
    volumes:
      - db_data:/var/lib/mysql

  wordpress:
    image: wordpress:latest
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wpuser
      WORDPRESS_DB_PASSWORD: wppass
      WORDPRESS_DB_NAME: wordpress

volumes:
  db_data:

Start the services:

docker compose up -d

Once the containers are running, open http://localhost:8080 in your Windows browser
to access WordPress. The containers are managed entirely inside WSL2,
but networking feels seamless.


Maintenance: Cleaning Up Docker Data

Over time, Docker accumulates images, stopped containers, volumes, and networks.
This can take up significant disk space inside your WSL distribution.
Here are safe maintenance commands to keep your environment clean:

Remove Unused Objects

docker system prune -a --volumes
  • -a: removes all unused images, not just dangling ones
  • --volumes: also removes unused volumes

Reset Everything (Dangerous)

If you need to wipe your Docker environment completely (images, containers, volumes, networks):

docker stop $(docker ps -aq) 2>/dev/null
docker rm -f $(docker ps -aq) 2>/dev/null
docker volume rm $(docker volume ls -q) 2>/dev/null
docker network rm $(docker network ls -q) 2>/dev/null
docker image rm -f $(docker image ls -q) 2>/dev/null

⚠️ Use this only if you want to start fresh. All data will be removed.


Conclusion

By running Docker Engine directly inside WSL2, you gain a powerful, lightweight, and license-free Docker environment that integrates seamlessly with Windows 11. Your containers are accessible from both Linux and Windows, Docker Compose works out of the box, and maintenance is straightforward with prune commands.

This approach is particularly well-suited for developers who want the flexibility of Docker without the overhead of Docker Desktop. With WSL2 and Ubuntu 24.04, you get the best of both worlds: Linux-native Docker with Windows accessibility.

PostHeaderIcon [DotAI2024] DotAI 2024: Romain Huet and Katia Gil Guzman – Pioneering AI Innovations at OpenAI

Romain Huet and Katia Gil Guzman, stalwarts of OpenAI’s Developer Experience team, charted the horizon of AI integration at DotAI 2024. Huet, Head of Developer Experience with roots at Stripe and Twitter, alongside Guzman—a solutions architect turned advocate for scalable tools—illuminated iterative deployment’s ethos. Their dialogue unveiled OpenAI’s trajectory from GPT-3’s nascent API to multimodal frontiers, empowering builders to conjure native AI paradigms.

From Experimentation to Ecosystem Maturity

Huet reminisced on GPT-3’s 2020 launch: an API inviting tinkering yielded unforeseen gems like AI Dungeon’s narrative weaves or code autocompletions. This exploratory ethos, he emphasized, birthed a vibrant ecosystem—now boasting Assistants API for persistent threads and fine-tuning for bespoke adaptations.

Guzman delved into Assistants’ evolution: function calling bridges models to externalities, orchestrating tools like databases or calendars sans hallucination pitfalls. Retrieval threads embed knowledge bases, fostering context-aware dialogues that scale from prototypes to enterprises.

Their synergy underscored OpenAI’s research-to-product cadence: iterative releases, from GPT-4’s multimodal prowess to o1’s reasoning chains, democratize AGI pursuits. Huet spotlighted Pioneers Program, partnering select founders for custom fine-tunes, accelerating innovation while gleaning real-world insights.

Multimodal Horizons and Real-Time Interactions

Guzman demoed Realtime API’s alchemy: low-latency voice pipelines fuse speech-to-text with tool invocation, enabling immersive exchanges—like querying cosmic data mid-conversation, visualizing trajectories via integrated visuals. Audio’s debut heralds vision’s integration, birthing interfaces that converse fluidly across senses.

Huet envisioned this as interface reinvention: beyond text, agents navigate worlds, leveraging GPT-4’s perceptual depth for grounded actions. Early adopters, he noted, craft speech-to-speech odysseys—piloting virtual realms or debugging via vocal cues—portending conversational computing’s renaissance.

As Paris beckons with a forthcoming office, Huet and Guzman rallied the French tech vanguard: leverage these primitives to reforge software legacies into intuitive symphonies. Their clarion: wield this vanguard toolkit to author humanity’s AGI narrative.

Forging the Next Wave of AI Natives

Huet’s closing evoked a collaborative odyssey: developers as AGI co-pilots, surfacing use cases that refine models iteratively. Guzman’s parting wisdom: harness exclusivity—early access begets advantage in modality-rich vistas.

Together, they affirmed OpenAI’s mantle: not solitary savants, but enablers of collective ingenuity, where APIs evolve into canvases for tomorrow’s intelligences.

Links:

PostHeaderIcon [SpringIO2024] Making Spring Cloud Gateway Your Perfect API Gateway Solution by Dan Erez @ Spring I/O 2024

In a dynamic session at Spring I/O 2024 in Barcelona, Dan Erez, lead architect at ZIM, a global shipping company, championed Spring Cloud Gateway as a versatile and powerful API gateway solution. Drawing on his extensive experience with Java and Spring, Dan demonstrated how Spring Cloud Gateway addresses the complexities of microservices architectures, offering features like dynamic routing, rate limiting, and circuit breakers. His talk underscored the gateway’s customizability and integration with Spring, making it an ideal choice for organizations seeking to streamline API management.

The Role of API Gateways in Microservices

API gateways simplify microservices architectures by acting as a unified entry point, hiding the complexity of multiple services. Dan traced the evolution from monolithic applications to microservices, noting that while microservices enhance modularity, they introduce challenges like service discovery and load balancing. An API gateway mitigates these by routing requests, authenticating users, and managing traffic. Spring Cloud Gateway excels in these areas, supporting functionalities like caching, rate limiting, and authentication with JWT tokens. Dan highlighted its ability to integrate with service discovery tools like Eureka, ensuring seamless communication across services.

Configuring and Customizing Routes

Spring Cloud Gateway’s flexibility shines in its routing capabilities. Dan showcased two configuration approaches: declarative YAML files and code-based Java configurations. Routes can be defined based on predicates like paths, headers, or query parameters, allowing fine-grained control. For example, a route for “/orders” can direct to an internal service, while “/invoices” targets a third-party API. Dan demonstrated a simple route adding a request header, executed via WebFlux for high concurrency. This customizability, paired with Spring’s familiarity, empowers developers to tailor the gateway to specific needs without relying on external DevOps teams.

Enhancing Resilience with Circuit Breakers and Caching

Resilience is critical in distributed systems, and Spring Cloud Gateway offers robust tools to handle failures. Dan illustrated circuit breakers, which redirect requests to fallback endpoints when a service is unavailable, preventing timeouts. In a demo, a delayed service triggered a fallback response, showcasing how developers can return cached data or custom errors. Caching, implemented with libraries like Caffeine, reduces database load by storing frequent responses. Dan’s example showed a cached HTTP response remaining consistent across refreshes, highlighting performance gains. These features ensure reliable and efficient API interactions.

Dynamic Rate Limiting and Cost Savings

Dan emphasized Spring Cloud Gateway’s ability to implement dynamic rate limiting, a feature that adapts to server load. In his demo, a custom filter adjusted the maximum request size based on simulated load, allowing larger requests during low traffic and restricting them during peaks. This approach maintains service availability without costly infrastructure scaling. Dan also shared a real-world use case at ZIM, where Spring Cloud Gateway enabled developers to run local services within a shared environment, routing requests dynamically to avoid conflicts. This solution saved significant costs by reducing the need for individual cloud environments.

Links:

PostHeaderIcon [GoogleIO2024] What’s New in Google Play: Enhancing Developer Success and User Engagement

In the evolving landscape of mobile ecosystems, Google Play continues to innovate, providing robust support for app creators to thrive. Mekka Okereke, alongside Yafit Becher and Hareesh Pottamsetty, outlined strategies tailored to diverse business models, emphasizing tools that foster growth, security, and monetization. This session highlighted Google’s dedication to bridging creators with global audiences, ensuring seamless experiences across apps and games.

Expanding Reach and Engagement Through Innovative Surfaces

Mekka emphasized the platform’s mission to connect audiences with compelling content, introducing enhancements that amplify visibility. The revamped Play Store adopts a content-forward design, spotlighting immersive features to captivate users. A novel surface extends beyond the store, organizing installed app content on-device for effortless continuation journeys. This facilitates deep linking into specific app sections, such as resuming entertainment or completing purchases, while promoting personalized recommendations.

Developers can integrate via the Engage SDK, a straightforward client-side tool leveraging on-device APIs. Early adopters like Spotify and Uber Eats have reported swift implementations, often within a week. For games, upgrades include multi-device scaling across mobiles, tablets, Chromebooks, and Windows PCs, with Google Play Games now in over 140 markets boasting 3,000 titles. Native PC publishing simplifies audience expansion, complemented by Play Games Services for cross-device progress synchronization.

Reinforcing Trust with Quality and Security Measures

Yafit delved into bolstering ecosystem integrity through advanced SDK management. The SDK Console, launched in 2021, enables owners to monitor usage, flag issues, and communicate directly with app teams. A new SDK index rates over 790 popular libraries across six million apps, aiding informed selections based on performance, privacy, and security metrics. This empowers creators to mitigate risks, such as outdated versions posing vulnerabilities.

Privacy enhancements include mandatory data deletion options in listings, fostering transparency. Custom store listings now support device-specific details, improving discoverability for tablets and wearables. Deep links receive upgrades via patching, allowing edits without full releases, ideal for experimentation. These measures collectively enhance user confidence, driving sustained interactions.

Optimizing Revenue for Global Expansion

Hareesh focused on commerce platform advancements, expanding payment methods to over 300 local options in 65 markets, including Pix in Brazil and enhanced UPI in India. Features like purchase requests enable family managers to buy on behalf of others, even via web links using gift cards. In India, sharing payment links extends this to non-family members, boosting gifting and accessibility.

Proactive payment setup reminders leverage Google profiles for seamless checkouts, yielding a 25% increase in enabled users and 12% better completion rates. Pricing tools auto-adjust for currency fluctuations, with flexibility up to $999 equivalents. Badges signal trending products, while installment subscriptions for annual plans increase sign-ups by 8% and spend by 4% in early tests. Upgrading to Play Billing Library 7.0 unlocks these, aligning with Android’s evolution.

These initiatives underscore Google’s commitment to scalable, secure monetization, empowering global business navigation.

Links:

PostHeaderIcon [KotlinConf2024] Lifecycles, Coroutines, and Scopes: Structuring Kotlin

At KotlinConf2024, Alejandro Serrano Mena, a JetBrains language evolution researcher, delivered a re-recorded talk on structured concurrency, illuminating how coroutine scopes bridge Kotlin’s concurrency model with framework lifecycles. Exploring Compose, Ktor, and Arrow libraries, Alejandro demonstrated how scopes ensure intuitive job cancellation and supervision. From view model scopes in Compose to request scopes in Ktor and resource management in Arrow, the talk revealed the elegance of scope-based designs, empowering developers to manage complex lifecycles effortlessly.

Structured Concurrency: A Kotlin Cornerstone

Structured concurrency, a pillar of Kotlin’s coroutine library, organizes jobs within parent-child hierarchies, simplifying cancellation and exception handling. Alejandro explained that unlike thread-based concurrency, where manual tracking is error-prone, scopes make concurrency a local concern. Jobs launched within a CoroutineScope are tied to its lifecycle, ensuring all tasks complete or cancel together. This model separates logical tasks (what to do) from execution (how to run), enabling lightweight job scheduling without full threads, as seen in dispatchers like Dispatchers.IO.

Coroutine Scopes: Parents and Children

A CoroutineScope acts as a parent, hosting jobs created via launch (fire-and-forget) or async (result-producing). Alejandro illustrated this with a database-and-cache example, where a root job spawns tasks like saveToDatabase and saveToCache, each with subtasks. Cancellation propagates downward—if the root cancels, all children stop. Exceptions bubble up, triggering default cancellation of siblings unless a SupervisorJob or CoroutineExceptionHandler intervenes. Scopes wait for all children to complete, ensuring no dangling tasks, a key feature for frameworks like Ktor.

Compose: View Model Scopes in Action

In Jetpack Compose, view model scopes tie coroutines to UI lifecycles. Alejandro showcased a counter app, where a ViewModel manages state and launches tasks, like fetching weather data, within its viewModelScope. This scope survives Android events like screen rotations but cancels when the activity is destroyed, preventing job leaks. Shared view models across screens maintain state during navigation, while screen-specific view models clear tasks when their composable exits, balancing persistence and cleanup in multiplatform UI development.

Ktor: Scopes for Requests and Applications

Ktor, a Kotlin HTTP framework, leverages coroutine scopes for server-side logic. Alejandro demonstrated a simple Ktor app with GET and WebSocket routes, each tied to distinct scopes. The PipelineContext scope governs individual requests, while the Application scope spans the server’s lifecycle. Launching tasks in the request scope ensures they complete or cancel with the request, enabling fast responses. Application-scoped tasks, like cache updates, persist beyond requests, offering flexibility but requiring careful cancellation to avoid lingering jobs.

Arrow: Beyond Coroutines with Resource and Saga Scopes

The Arrow library extends scope concepts beyond coroutines. Alejandro highlighted resource scopes, which manage lifecycles of database connections or HTTP clients, ensuring automatic disposal via install or autoCloseable. Saga scopes orchestrate distributed transactions, pairing actions (e.g., increment) with compensating actions (e.g., decrement). Unlike coroutine scopes, which cancel on exceptions, saga scopes execute compensations in reverse, ensuring consistent states across services. These patterns showcase scopes as a versatile abstraction for lifecycle-aware programming.

Dispatching: Scheduling with Flexibility

Coroutine scopes delegate execution to dispatchers, separating task logic from scheduling. Alejandro noted that default dispatchers inherit from parent scopes, but developers can specify Dispatchers.IO for I/O-intensive tasks or Dispatchers.Main for UI updates. This decoupling allows schedulers to optimize thread usage while respecting structured concurrency rules, like cancellation propagation. By choosing appropriate dispatchers, developers fine-tune performance without altering the logical structure of their concurrent code.

Conclusion: Think Where You Launch

Alejandro’s key takeaway—“think where you launch”—urges developers to consider scope placement. Whether in Compose’s view models, Ktor’s request handlers, or Arrow’s resource blocks, scopes simplify lifecycle management, making cancellation and cleanup intuitive. By structuring applications around scopes, Kotlin developers harness concurrency with confidence, ensuring robust, maintainable code across diverse frameworks.

Links:

PostHeaderIcon [DevoxxUK2024] Exploring the Power of AI-Enabled APIs by Akshata Sawant

Akshata Sawant, a Senior Developer Advocate at Salesforce, delivered an insightful presentation at DevoxxUK2024, illuminating the transformative potential of AI-enabled APIs. With a career spanning seven years in API development and a recent co-authored book on MuleSoft for Salesforce developers, Akshata expertly navigates the convergence of artificial intelligence and application programming interfaces. Her talk explores how AI-powered APIs are reshaping industries by enhancing automation, data analysis, and user experiences, while also addressing critical ethical and security considerations. Through practical examples and a clear framework, Akshata demonstrates how these technologies synergize to create smarter, more connected systems.

The Evolution of APIs and AI Integration

Akshata begins by likening APIs to a waiter, facilitating seamless communication between disparate systems, such as a customer ordering food and a kitchen preparing it. This analogy underscores the fundamental role of APIs in enabling interoperability across applications. She traces the evolution of APIs from the cumbersome Enterprise JavaBeans (EJB) and SOAP-based systems to the more streamlined REST APIs, noting their pervasive adoption across industries. The advent of AI has further accelerated this evolution, leading to what Akshata terms “API sprawling,” where APIs are integral to integration ecosystems. She introduces three key aspects of AI-enabled APIs: consuming pre-built AI APIs, using AI to streamline API development, and embedding AI models into custom APIs to enhance functionality.

Practical Applications of AI-Enabled APIs

The first aspect Akshata explores is the use of pre-built AI APIs, which are readily available from providers like Google Cloud and Microsoft Azure. These APIs, encompassing generative AI, text, language, image, and video processing, allow developers to integrate advanced capabilities without building complex models from scratch. For instance, Google Cloud’s AI APIs offer use-case-specific endpoints that can be embedded into applications, enabling rapid deployment of intelligent features. Akshata highlights the accessibility of these APIs, which come with pricing models and trial options, making them viable for businesses seeking to enhance automation or data processing. She engages the audience by inquiring about their experience with such APIs, emphasizing their growing relevance in modern development.

The second dimension involves leveraging AI to accelerate API development. Akshata describes the API management lifecycle—designing, simulating, publishing, and documenting APIs—as a complex, iterative process. AI tools can simplify these stages, particularly in generating OpenAPI specifications and documentation. She provides an example where a simple prompt to an AI model produces a comprehensive OpenAPI specification for an order management system, streamlining a traditionally time-consuming task. Additionally, AI-driven intelligent document processing can scan invoices or purchase orders, extract relevant fields, and generate REST APIs with GET and POST methods, complete with auto-generated documentation. This approach significantly reduces manual effort and enhances efficiency.

Embedding AI into Custom APIs

The third aspect focuses on embedding AI models, such as large language models (LLMs) or custom co-pilot solutions, into APIs to create sophisticated applications. Akshata showcases Salesforce’s Einstein Assistant, which integrates with OpenAI’s models to process natural language requests. For example, querying “customer details for Mark” triggers an API call that matches the request to predefined actions, retrieves relevant data, and delivers a response. This seamless integration exemplifies how AI can elevate APIs beyond mere data transfer, enabling dynamic, context-aware interactions. Akshata emphasizes that such embeddings allow developers to create tailored solutions that enhance user experiences, such as personalized customer service or automated workflows.

Ethical and Security Considerations

While celebrating the potential of AI-enabled APIs, Akshata candidly addresses their challenges. She underscores the importance of ethical considerations, such as ensuring unbiased AI outputs and protecting user privacy. Security is another critical concern, as integrating AI into APIs introduces vulnerabilities that must be mitigated through robust authentication and data encryption. Akshata’s balanced perspective highlights the need for responsible development practices to maximize benefits while minimizing risks, ensuring that AI-driven solutions remain trustworthy and secure.

Links:

PostHeaderIcon [NDCOslo2024] Designing for Change with Vertical Slice Architecture – Chris Sainty

In the ever-shifting sands of software demands, where agility trumps rigidity and evolution outpaces stasis, Chris Sainty, a distinguished software architect and Microsoft MVP, advocates for a paradigm that embraces flux: Vertical Slice Architecture (VSA). With a wealth of experience in .NET ecosystems, Chris dissects the frailties of conventional layered paradigms, illuminating how VSA fosters adaptability, accelerates onboarding, and scales with success. His exposition, laced with pragmatic examples, challenges developers to reimagine structures that prioritize features over foundations, ensuring applications remain responsive to the inexorable tide of transformation.

Chris commences by lauding the endurance of layered architectures—presentation atop business logic atop data—yet probes their perils in contemporary contexts. As customer whims whirl and scaling surges demand swift pivots, layers ossify into obstacles, encumbering change with cross-tier tangles. VSA, conversely, carves applications into self-contained verticals—end-to-end features encapsulating all concerns—streamlining modifications and magnifying modularity. This feature-centric ethos, Chris argues, aligns with modern mandates: rapid iterations, effortless extensions, and intuitive ingress for new contributors.

Deconstructing Layers: Pitfalls of Traditional Tiering

Layered designs, Chris elucidates, excel in abstraction but falter in flux. Modifications ripple across strata—tweaking data access mandates presentation perturbations—breeding brittle bonds. Scaling amplifies agony: monolithic services swell, onboarding overwhelms with navigational nightmares. Chris recounts teams ensnared in “god classes,” where logic leeches into controllers, defying single-responsibility tenets.

VSA liberates by slicing vertically: each feature owns its orchestration, from input validation to persistence, minimizing interdependencies. In ASP.NET Core, MediatR handlers embody this, encapsulating requests with validators, mappers, and repositories. Chris demonstrates: a “Create Order” vertical integrates all facets sans layer leaks, easing evolution as requirements refine.

Trade-offs temper triumph: VSA risks redundancy in shared utilities, yet Chris counters with judicious extraction—domain entities for rules, infrastructure abstractions for emails—preserving purity without proliferation. His verdict: layers for legacy, VSA for vitality.

Embracing Verticals: Accelerating Agility and Onboarding

VSA’s virtues shine in speed: altering a feature confines chaos to its silo, slashing cycle times. Chris illustrates with e-commerce: updating checkout logic spans one slice, not sprawling services. Onboarding accelerates—newcomers grasp endpoints holistically, sans layer labyrinths—fostering faster fluency.

Scaling surges seamlessly: verticals deploy independently, microservices materialize modularly. Chris cautions misconceptions: VSA isn’t anarchy—tests tether slices, conventions coerce cohesion. In .NET, minimal APIs map verticals directly, ditching controllers for clarity.

His horizon: VSA as mindset, marrying DDD’s domains with feature focus, empowering teams to thrive amid tumult.

Navigating Nuances: Sharing Savvy and Strategic Choices

Code sharing, a VSA specter, resolves via domains: encapsulate business invariants—aggregates, entities—reusable across verticals, insulating infrastructure. Chris debunks duplication dogmas: external concerns like databases or notifications warrant abstraction, not replication, ensuring efficiency without entanglement.

Strategic selection: VSA suits volatile domains; layers linger in stable spheres. Chris’s compass: assess change cadence—frequent flux favors verticals.

Forging Forward: Building for the Inevitable

Chris’s capstone: architectures architect for alteration. VSA, with its slice-centric simplicity, equips ensembles to navigate novelty, nurturing nimble, navigable codebases that celebrate change.

Links:

PostHeaderIcon [NodeCongress2024] Deep Dive into Undici: Architecture, Performance, and the Future of HTTP in Node.js

Lecturer: Matteo Collina

Matteo Collina is an internationally recognized expert in Node.js and open-source architecture, serving as the Co-Founder and CTO of Platformatic. He holds a Ph. D. in “Application Platforms for the Internet of Things”. A member of the Node.js Technical Steering Committee (TSC), he is a major contributor to the platform’s core, with a focus on streams, diagnostics, and the HTTP stack. He is the original author of the highly successful, high-performance web framework Fastify and the ultra-fast JSON logger Pino. His open-source modules are downloaded billions of times annually.

Abstract

This article presents a technical analysis of Undici, the high-performance, standards-compliant HTTP/1.1 client that serves as the foundation for the native fetch() API in Node.js. It explains the motivation for Undici’s creation—addressing critical performance and protocol deficiencies in the legacy Node.js stack. The article details the core architectural components, particularly the Client and Dispatcher abstractions, and explains how Undici achieves superior efficiency through advanced connection management and HTTP/1.1 pipelining. The final analysis explores the methodological implications of Undici’s modularity, including enabling zero-overhead internal testing and powering highly efficient modular monolith and microservice runtimes.

Context: Limitations of the Legacy Node.js HTTP Stack

The legacy Node.js HTTP client suffered from several long-standing limitations, primarily in performance and compliance with modern standards. Specifically, it lacked proper support for HTTP/1.1 pipelining—the ability to send multiple requests sequentially over a single connection without waiting for the first response. Furthermore, its connection pool management was inefficient, often failing to enforce proper limits, leading to potential resource exhaustion and performance bottlenecks. Undici was developed to resolve these architectural deficiencies, becoming the native engine for fetch() within Node.js core.

Architecture and Methodology of Undici

Undici’s design is centered around optimizing connection usage and abstracting the request lifecycle:

  • The Client and Connection Pools: The core component is the Client, which is scoped to a single origin (protocol, hostname, and port). The Client manages a pool of TCP connections and is responsible for implementing the efficiency of the HTTP protocol.
  • Pipelining for Performance: Undici explicitly implements HTTP/1.1 pipelining. This methodology permits the efficient use of the network and is essential for maximum HTTP/1.1 performance, particularly when connecting to modern servers that support the feature.
  • The Dispatcher Abstraction: Undici utilizes a pluggable Dispatcher interface. This abstraction governs the process of taking a request, managing connection logic, and writing the request to a socket. Key Dispatcher implementations include the standard Client (for a single origin) and the Agent (for multiple origins).
  • Connection Management: The pooling mechanism employs a strategy to retire connections gracefully to allow DNS changes and resource rotation, contrasting with legacy systems that often held connections indefinitely.

Consequences and Architectural Innovations

Undici’s modular and abstracted architecture has led to significant innovations beyond core HTTP performance:

  1. In-Process Request Testing: The Dispatcher model allows for the implementation of a MockClient (accessible via the light-my-request module), which completely bypasses the network stack. This permits the injection of HTTP requests directly into a running Node.js server within the same process, enabling zero-overhead, high-speed unit and integration testing without opening any actual sockets.
  2. Internal Mesh Networking: The architecture enables a unique pattern for running multiple microservices within a single process. Using a custom dispatcher (fastify-undici-dispatcher), internal HTTP requests can be routed directly to other services (e.g., Fastify instances) running in the same process via an in-memory mesh network, completely bypassing the network layer for inter-service communication. This methodology, employed in the Platformatic runtime, allows developers to transition from a modular monolith to a microservice architecture with minimal code changes, retaining maximum performance for inter-service calls.

Links

Hashtags: #Undici #NodeJS #HTTPClient #Fastify #Microservices #PerformanceEngineering #Platformatic

PostHeaderIcon [DotJs2024] Thinking About Your Code: Push vs Pull

Navigating the currents of performant code demands a lens attuned to flow dynamics, where producers and consumers dance in tandem—or discord. Ben Lesh, a veteran of high-stakes web apps from Netflix’s infrastructure dashboards to RxJS stewardship, shared this paradigm at dotJS 2024. With roots in rendering millions of devices across North America’s bandwidth, Lesh distilled decades of collaboration with elite engineers into a quartet of concepts: producers, consumers, push, pull. These primitives illuminate code’s underbelly, spotlighting concurrency pitfalls, backpressure woes, and optimal primitives for JavaScript’s asynchronous tapestry.

Lesh’s entrée was a bespoke live demo: enlisting audience volunteer Jessica Sachs to juggle M&Ms, embodying production-consumption. Pull—Jessica grabbing at will—affords control but falters asynchronously; absent timely M&Ms, hands empty. Push—Lesh feeding sequentially—frees producers for factories but risks overload, manifesting backpressure as frantic consumption. Code mirrors this: a getValue() invocation pulls synchronously, assigning to a consumer like console.log; for loops iterate pulls from arrays. Yet, actors abound: functions produce, variables consume; callbacks push events, observables compose them.

JavaScript’s arsenal spans quadrants. Pure pull: functions and intervals yield eager values. Push: callbacks for one-offs, observables for streams—RxJS’s forte, enabling operators like map or mergeMap for event orchestration. Pull-then-push hybrids: promises (function returning deferred push) and async iterables (yielding promise-wrapped results), ideal for paced delivery via for await...of, mitigating backpressure in slow consumers. Push-then-pull inverts: signals—Ember computeds, Solid observables, Angular runes—notify changes, deferring reads until render. Lesh previewed TC39 signals: subscribe for pushes, get for pulls, birthing dependency graphs that lazy-compute, tracking granular ties for efficient diffing.

This framework unveils pathologies: thread lockups from unchecked pushes, concurrency clashes in nested callbacks. Lesh advocated scanning code for actors—spotting producers hidden in APIs—and matching primitives to intent. Pull suits sync simplicity; push excels in async firehoses; hybrids temper throughput; signals orchestrate reactive UIs. As frameworks like React lean on signals for controlled reads pre-render, developers gain foresight into bottlenecks, fostering resilient, scalable architectures.

Decoding Flow Primitives in JavaScript

Lesh partitioned primitives into a revealing matrix: pull for immediacy (functions pulling values), push for autonomy (observables dispatching relentlessly). Hybrids like promises bridge, returning handles for eventual pushes; async iterables extend, pacing via awaits. Signals, the push-pull hybrid, notify sans immediate computation—perfect for UI graphs where effects propagate selectively, as in Solid’s fine-grained reactivity or Angular’s zoned eschewal.

Navigating Backpressure and Optimization

Backpressure—producers overwhelming consumers—Lesh dramatized via M&M deluge, solvable by hybrids throttling intake. Signals mitigate via lazy evals: update signals, compute only on get, weaving dependency webs that prune cascades. Lesh urged: interrogate code’s flows—who pushes/pulls?—to preempt issues, leveraging RxJS for composition, signals for reactivity, ensuring apps hum under load.

Links:

PostHeaderIcon [SpringIO2024] Text-to-SQL: Chat with a Database Using Generative AI by Victor Martin & Corrado De Bari @ Spring I/O 2024

At Spring I/O 2024 in Barcelona, Victor Martin, a product manager for Oracle Database, delivered a compelling session on Text-to-SQL, a transformative approach to querying databases using natural language, powered by generative AI. Stepping in for his colleague Corrado De Bari, who was unable to attend, Victor explored how Large Language Models (LLMs) and Oracle’s innovative tools, including Spring AI and Select AI, enable business users with no SQL expertise to interact seamlessly with databases. The talk highlighted practical implementations, security considerations, and emerging technologies like AI Vector Search, offering a glimpse into the future of database interaction.

The Promise of Text-to-SQL

Text-to-SQL leverages LLMs to translate natural language queries into executable SQL, democratizing data access for non-technical users. Victor began by posing a challenge: how long would it take to build a REST endpoint for a business user to query a database using plain text? Traditionally, this task required manual SQL construction, schema validation, and error handling. With modern frameworks like Spring Boot and Oracle’s Select AI, this process is streamlined. Select AI, integrated into Oracle Database 19c and enhanced in 23 AI, supports features like RUN_SQL to execute generated queries, NARRATE to return results as human-readable text, and EXPLAIN_SQL to detail query reasoning. Victor emphasized that these tools reduce development time, enabling rapid deployment of user-friendly database interfaces.

Configuring Oracle Database for Text-to-SQL

Implementing Text-to-SQL requires minimal configuration within Oracle Database. Victor outlined the steps: first, set up an Access Control List (ACL) to allow external LLM calls, specifying the host and port. Next, create credentials for the LLM service (e.g., Oracle Cloud Infrastructure Generative AI, Open AI, or Azure Open AI) using the DBMS_CLOUD_AI package. Finally, define a profile linking the schema, tables, and chosen LLM. This profile is selected per session to ensure queries use the correct context. Victor demonstrated this with a Spring Boot application, where the profile is set before invoking Select AI. The simplicity of this setup, combined with Spring AI’s abstraction, makes it accessible even for developers new to AI-driven database interactions.

Enhancing Queries with Schema Annotations

A key challenge in Text-to-SQL is ensuring LLMs interpret ambiguous schemas correctly. Victor highlighted that table and column names like “C1” or “Table1” can confuse models. To address this, Oracle Database supports annotations—comments on tables and columns that provide business context. For example, annotating a column as “process status” with possible values clarifies its purpose, aiding the LLM in generating accurate joins and filters. These annotations, which don’t affect production queries, are created collaboratively by DBAs and business stakeholders. Victor shared a real-world example from Oracle’s telecom applications, where annotated schemas improved query precision, enabling complex queries without manual intervention.

AI Vector Search: Querying Unstructured Data

Victor introduced AI Vector Search, a cutting-edge feature in Oracle Database 23 AI, which extends Text-to-SQL to unstructured data. Unlike traditional SQL, which queries structured data, vector search encodes text, images, or audio into high-dimensional vectors representing semantic meaning. These vectors, stored as a new VECTOR data type, enable similarity-based queries. For instance, a job search query for “software engineer positions in New York” can combine structured filters (e.g., location) with vector-based matching of job descriptions and resumes. Victor explained how embedding models, deployed via Oracle’s DBMS_DATA_MINING package, generate these vectors, with metrics like cosine similarity determining relevance. This capability opens new use cases, from document search to personalized recommendations.

Links: