Skip to main content

Posts

From Monoliths to AI Proxies: Real-World Strategy for Testing and Evolving LLM Integrations

Integrating Large Language Models (LLMs) into production systems presents unique architectural, testing, and operational challenges. This article shares practical insights and solutions from real-world experience integrating LLMs into a customer interaction platform. It covers the evolution from a monolithic to a more modular AI Proxy architecture pattern, strategies for testing, deploying and monitoring LLMs, and the emerging Model Context Protocol (MCP) standard. Application developers and software architects will learn proven practices to build robust, reliable and responsible LLM-powered systems.

Kotlin Extensions for LangChain4j

Discover Kotlin extensions for LangChain4j designed to transform the synchronous LangChain4j API into a modern, non-blocking experience with Kotlin Coroutines. Learn about key features including coroutine support for ChatLanguageModels, Kotlin Flow for streaming responses, external customizable prompt templates, and non-blocking document processing. Enhance your Kotlin programming skills and improve application efficiency by leveraging these powerful new tools.

Keeping Your Software Healthy: The Critical Role of Dependency Updates

Discover best practices for effective dependency management in software development and learn strategies to keep your projects secure, efficient, and free of technical debt. This comprehensive guide covers the critical importance of regularly updating dependencies, utilizing automated tools and processes to streamline dependency management, fostering a culture of proactive updates through incentives and education, and implementing organization-wide dependency management strategies at scale. Whether you’re an application developer, software architect, or engineering manager, this article provides actionable insights to help you master dependency updates and ensure your software stays healthy and high-performing.

Spring Boot Starters

This post discusses Spring Boot Starters and their importance to developers, who want to make the setup and configuration of Spring Boot applications a whole lot easier. It keeps dependencies organized, increases development speed, and grants you numerous options for customization and extension. This basically makes them indispensable in building all manner of applications with Spring Boot - from simple web applications to data access and security services. I showcase, with a practical example, how to create a custom Spring Boot Starter that consolidates logging configurations and standard dependencies across microservices. This guide provides step-by-step instructions on how to create and use a custom starter.

Code-Review Best Practices

Code review is a crucial practice in software development. One can design and write great software, but we are humans after all. And all humans make mistakes, so another pair of eyes is always helpful.

The review process might seem straightforward, but there are useful tips to make it less painful is some cases.

Running Testcontainers On Dynamic Ports

Running integration tests locally with Docker can be challenging when fixed ports are unavailable due to conflicts. This issue is compounded in shared CI environments where multiple workers are in use. However, using testcontainers can help overcome these obstacles by enabling the startup of Docker containers that listen on random ports.

Kotlin Playground Shortcode for Hugo

Kotlin Playground is HTML component which creates Kotlin-aware editors capable of running code from HTML block elements. Here I explain how to embed runnable Kotlin code block in your Hugo-powered blog.

Spring Boot Configuration Best Practices

Spring Boot comes with very neat configuration mechanism. Default application configuration is defined in one configuration file and environment specific setting in separate files. But still, this mechanism is often not used properly resulting in verbose and unmaintainable configurations.

Building Data Pipeline with Kotlin Coroutines Actors

This blog post demonstrates how to build a data processing pipeline using Kotlin coroutines and actors, showing both single-threaded and parallel implementations. It walks through creating a simple data pipeline using Kotlin’s channel and actor abstractions for clean concurrent programming. The post includes practical code examples of handling message passing between actors, managing thread pools, implementing back-pressure, and scaling from a basic sequential pipeline to a parallel version that processes data more efficiently. The explanation is backed by detailed logging output that illustrates how messages flow through the system and how parallel processing improves overall performance.