Arun Pandian M

Arun Pandian M

Android Dev | Full-Stack & AI Learner

Written by: Arun Pandian M•Published on: Oct 3, 2025

🍕 Building a Pizza Like Jetpack Compose: A Modifier Story

https://storage.googleapis.com/lambdabricks-cd393.firebasestorage.app/compose_pizza.webp?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=firebase-adminsdk-fbsvc%40lambdabricks-cd393.iam.gserviceaccount.com%2F20260717%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20260717T064047Z&X-Goog-Expires=3600&X-Goog-SignedHeaders=host&X-Goog-Signature=60a4113bb4433060232b06b967053fb07a27fd33e378347c72bc6a4f5e03dddd156346b991b441e673b4e3439d8655639a8d4d5c772cd7d6df16800b626360b4c114e24f4749f95325caafc9dea9c73bf867c18a844162e9e28fdd6191c9670e912abffd881ce24179d7f9b6548aac1b5419a8a3b4855c5b93c3eec6c5d2b61589456910025bc51d9526ff3ac62991d71330b751507f679bd229cfb999c375789b21917a2e36880964ccaf0c6e3a32993305e5806ca764a50695905105a69f482682177582471ebe4fd1c539827f214bf93fa13527f6c21e262350c7630963271607506f600675701ae5f6ed28d567158690cd265a7141fe5a19c8dd90af5e44
Just like the LEGO pieces add toppings and a crust to this pizza, modifiers allow you to customize a Composable with styling, layout, and behavior

I love pizza. And I love Jetpack Compose. Turns out, they have a lot in common. Stick with me, and I’ll show you why building a pizza can teach you how Compose modifiers actually work.

Modifiers: The Secret Sauce

In Compose, every UI element — a Text, a Box, a Column — can be decorated with modifiers. Think of a modifier as a little instruction: “Add padding here,” or “Make this background red.” You can chain these modifiers:

Modifier
    .padding(8.dp)
    .background(Color.Red)

Each modifier is applied in sequence, just like adding ingredients to a pizza.

So I decided: why not make a Pizza DSL using the same concept?

Step 1: Building the Chain

I created a Chain interface — our version of Compose’s Modifier. Each step, like adding dough, sauce, or cheese, is a ChainUnit. And just like Compose, we can chain them with then():

Chain.pizzaDough("Thin Crust")
    .pizzaSauce("Tomato Basil")
    .pizzaTopping("Mushroom")
    .pizzaCheese("Mozzarella")

Here’s the magic:

  • ChainUnit = a single modification (like Modifier.padding)
  • then() = “do this, then that”
  • fold() = actually apply all the steps in order
  • Without fold, we just have a list of instructions. Fold executes them, building the final pizza.

    Step 2: Fold — The Assembly Line

    Think of fold like an assembly line in a pizza shop:

    1. Dough chef lays down the crust

    2.Sauce chef spreads the sauce

    3.Topping chef sprinkles mushrooms

    4.Cheese chef adds mozzarella

    Each chef doesn’t need to know about the others — they just follow the sequence. This is exactly what fold() does

    chain.fold(Pizza()) { pizza, unit ->
        when(unit) {
            is Dough -> pizza.dough = unit
            is Sauce -> pizza.sauce = unit
            is Topping -> pizza.toppings.add(unit)
            is Cheese -> pizza.cheese = unit
        }
        pizza
    }

    Order matters. Fold ensures the pizza is assembled step by step, just like Compose applies modifiers in order.

    Step 3: Scope-Specific Modifiers

    Some pizzas are special. Pizza Hut likes stuffed crust, and Dominos loves double cheese. We can model this using scopes, similar to BoxScope or ColumnScope in Compose:

    PizzaHutScope().run {
        Chain
            .pizzaDough("Thin Crust")
            .pizzaSauce("Marinara")
            .pizzaTopping("Pepperoni")
            .pizzaCheese("Mozzarella")
            .stuffedCrust()  // only valid in PizzaHutScope
            .let { Pizza.compose(it) }
    }
    

    Step 4: Why Functional Chains Beat Builders

    You might wonder, “Why not just use a builder?” Builders mutate objects step by step, which is fine for small things. But functional chains shine when:

  • You want reusable sequences of modifiers
  • You want predictable order without side effects
  • You want a DSL that reads naturally
  • Compare:

    // Builder pattern
    PizzaBuilder().setDough(...).setSauce(...).addTopping(...).build()
    
    // Functional chain
    Chain.pizzaDough(...).pizzaSauce(...).pizzaTopping(...).fold(Pizza()) { ... }
    

    The chain reads like a recipe. It’s declarative, composable, and fits perfectly with scopes.

    Step 5: Putting It All Together

    Here’s a Pizza Hut example:

    val pizzaHut = PizzaHutScope().run {
        Chain
            .pizzaDough("Thin Crust")
            .pizzaSauce("Marinara")
            .pizzaTopping("Pepperoni")
            .pizzaCheese("Mozzarella")
            .stuffedCrust()
            .let { Pizza.compose(it) }
    }
    
    println(pizzaHut.describe())

    See how naturally it reads? You assemble a pizza step by step, respecting scope rules, just like Compose applies modifiers to UI elements.

    🔑 Takeaways

    Modifiers are just small, reusable steps
    Chains and fold ensure order and composability
    Scope-level extensions enforce context rules
    Functional chain > builder for readability and reuse
    DSL = human-readable recipe, like Compose modifiers reading like a story

    In short, building a pizza like this feels like Compose in action. You can chain, scope, and fold ingredients — or modifiers — creating a final product that’s perfectly layered, predictable, and reusable.

    You’ve seen how we can build a pizza step by step using fold-based chains, scope-specific modifiers, and a Compose-inspired DSL. If you want to play with the code yourself, experiment, or tweak it, I’ve put the entire Kotlin sample in a GitHub Gist.

    Go ahead, copy it, run it, and make your own pizza combinations: https://gist.github.com/arunpandian22/3ae30ee154a223a4137cf64f13732659

    Have fun exploring, and may your pizza — and your code — always come out perfectly! 🍕👩‍💻

    #jetpack_compose#compose_modifiers#kotlin_dsl#functional_programming_kotlin#compose_ui#android_development#compose_patterns#declarative_ui#kotlin_tutorial#compose_best_practices#compose_modifier_chain#android_kotlin#software_design_patterns#kotlin_functional_style#developer_storytelling
    LAMBDA BRICKS