Latest 5 Posts

  1. Java 25 After the Hype: 5 Features That Actually Matter

    ~ cat post <<

    Java 25 After the Hype: 5 Features That Actually Matter

    When a new Java LTS drops, the internet goes through its usual cycle: launch posts, conference talks, YouTube thumbnails screaming “GAME CHANGER,” and LinkedIn hot takes about how everything has changed forever.

    Then reality settles in.

    A few months after the release of Java 25, most teams aren’t rewriting their systems. They’re shipping features, fixing bugs, and trying to keep production stable. That’s when we can finally answer a more interesting question:

    Which Java 25 features are still being discussed and actually used?

    This isn’t a launch recap. This is a “post-hype” filter. Here are five Java 25 features that have proven they’re more than marketing bullets.

    1. Structured Concurrency: Concurrency That Reads Like Logic

    For years, Java concurrency meant juggling ExecutorService, Future, timeouts, and cancellation semantics that were easy to get wrong.

    Structured Concurrency changes the mental model. Instead of spawning detached tasks and hoping everything is cleaned up properly, you treat concurrent tasks as a single logical unit.

    Before

    ExecutorService executor = Executors.newFixedThreadPool(2);
    
    Future<User> userFuture = executor.submit(() -> fetchUser());
    Future<Orders> ordersFuture = executor.submit(() -> fetchOrders());
    
    User user = userFuture.get();
    Orders orders = ordersFuture.get();
    
  2. Spring Boot 4: Brief Upgrade Guide and Code Comparison

    ~ cat post <<

    Spring Boot 4 vs. 3: Brief Upgrade Guide and Code Comparison

    If you’ve been following my blog, you know I love a good migration story. Whether it’s moving to TanStack Start or refining shadcn/ui forms, the goal is always the same: better developer experience and more robust code.

    Today, we’re looking at the big one. Spring Boot 4.0 is officially out, and it’s arguably the most important release since 3.0. It moves the baseline to &Java 17 (with a massive push for Java 25), adopts Jakarta EE 11, and introduces features that finally kill off years of boilerplate.

    Let’s look at exactly what changed and how your code will look before and after the upgrade.

    1. Native API Versioning

    For years, versioning an API in Spring meant custom URL paths, header filters, or complex RequestCondition hacks. Spring Boot 4 brings this into the core framework.

    The Spring Boot 3 Way (Manual Pathing)

    // You had to manually manage the path segments
    @RestController
    @RequestMapping("/api/v1/orders")
    public class OrderControllerV1 { ... }
    
    @RestController
    @RequestMapping("/api/v2/orders")
    public class OrderControllerV2 { ... }
    

    The Spring Boot 4 Way (Native Mapping)

    Now, versioning is a first-class citizen. You can keep the path clean and let Spring handle the routing logic via headers, query params, or path segments.

  3. JSON is Making You Lose Money!!! Slash LLM Token Costs with TOON Format

    ~ cat post <<

    JSON vs TOON Token Explosion

    Let's be real: every time you shove a bloated JSON blob into an LLM prompt, you're literally burning cash. Those curly braces, endless quotes, and repeated keys? They're token vampires sucking your OpenAI/Anthropic/Cursor bill dry. I've been there – cramming user data, analytics, or repo stats into prompts, only to hit context limits or watch costs skyrocket.

    But what if I told you there's a format that cuts tokens by up to 60%, boosts LLM accuracy, and was cleverly designed for exactly this problem? Meet TOON (Token-Oriented Object Notation), the brainchild of Johann Schopplich – a dev who's all about making AI engineering smarter and cheaper.

    Johann nailed it with TOON over at his original TypeScript repo: github.com/johannschopplich/toon. It's not just another serialization format; it's a lifeline for anyone building AI apps at scale.

    Why JSON is Robbing You Blind in LLM Prompts

    JSON is great for APIs and config files. But for LLM context? It's a disaster:

    • Verbose AF: Braces {}, brackets [], quotes around every key and string – all eating tokens.
    • Repeated Keys: In arrays of objects, every row repeats the same field names. 100 users? That's 100x "id", "name", etc.
    • No Built-in Smarts: LLMs have to parse all that noise, leading to higher error rates on retrieval tasks.
    • Token Explosion at Scale: A modest dataset can balloon to thousands of unnecessary tokens.

    Result? Higher costs, slower responses, and more "context too long" errors. If you're querying GPT-5-nano or Claude with tabular data, JSON is quietly making you poor.

  4. Demystifying Object-Oriented Programming: Pt. 2

    ~ cat post <<

    Demystifying Object-Oriented Programming: Pt. 2

    Welcome back! At the end of our last post, we hit a bit of a roadblock. We had successfully organized our F1, PickupTruck, and SUV classes to inherit from a base Car class. But then, we were faced with a new challenge:

    A bicycle, a speedboat, and an electric car. They are all vehicles, but trying to force them into a single Vehicle inheritance hierarchy would be a nightmare. A speedboat doesn't have wheels, and a bicycle doesn't have an engine in the traditional sense. A simple extends Vehicle starts to feel clunky and wrong. How do we model things that share behaviors but are fundamentally different things?

    The answer lies in moving beyond the idea that everything must share a common ancestor and instead thinking about what they can DO.

    Interfaces: A Contract of Behavior

    Let’s ask a different question. Instead of asking what these objects are, let's ask what they have in common from a user's perspective. A person can:

    • Steer them
    • Make them go forward
    • Slow them down

    In Object-Oriented Programming, when we want to guarantee that different classes share a common set of behaviors, we use an INTERFACE. Think of an interface not as a blueprint for an object, but as a contract. It’s a list of methods that a class promises to implement. It defines WHAT a class can do, but not HOW it does it.

    Let's create a contract for anything that can be driven. We'll call it Drivable.

    // Interface
    public interface Drivable {
      void turnLeft(double degrees);
      void turnRight(double degrees);
      void accelerate();
      void brake();
    }
    
  5. [UPDATED!] Seamless Forms with shadcn/ui and TanStack Form

    ~ cat post <<

    Seamless Forms with shadcn/ui and TanStack Form

    In my post, "Life after Next.js: A New and Sunny Start," I talked about my journey migrating to TanStack Start and the freedom it brought. One of the loose ends I mentioned was the form situation. I'm a big fan of the aesthetics and developer experience of shadcn/ui, but its default form component is built on react-hook-form. As I'm going all-in on the TanStack ecosystem, I naturally wanted to use TanStack Form.

    This presented a classic developer dilemma: do I stick with a component that doesn't quite fit my new stack, or do I build something better? The answer was obvious. I couldn't find a clean, existing solution that married the beauty of shadcn/ui with the power and type-safety of TanStack Form. So, I decided to build it myself.

    Today, I'm excited to share the result: a component that seamlessly integrates shadcn/ui with TanStack Form, preserving the core principles of both libraries. It's type-safe, easy to use, and maintains that clean shadcn/ui look and feel.

    You can check out the component's website and find the full source code on the GitHub repository.

    Why Bother?

    TanStack Form offers incredible power with its framework-agnostic, type-safe approach to form state management. shadcn/ui, on the other hand, provides beautiful, accessible, and unopinionated components. The goal was to get the best of both worlds without any compromises. This component acts as the bridge, giving you:

    • Full Type-Safety: Infer types directly from your validation schemas (like Zod, Valibot, etc.).
    • Seamless TanStack Integration: Leverage TanStack Form’s state management and validation logic.
    • Consistent shadcn/ui Styling: Use the form components you already know and love.
~ <<

8 more posts can be found in the archive .