<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Laurent Gaches</title>
    <subtitle>Backend developer focused on AI applications, RAG pipelines, and DevOps.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://www.laurentgaches.dev/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://www.laurentgaches.dev"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-05-09T00:00:00+00:00</updated>
    <id>https://www.laurentgaches.dev/atom.xml</id>
    <entry xml:lang="en">
        <title>Rust Forces Me to Think</title>
        <published>2026-05-09T00:00:00+00:00</published>
        <updated>2026-05-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Laurent Gaches
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.laurentgaches.dev/posts/rust-forces-me-to-think-unfortunately/"/>
        <id>https://www.laurentgaches.dev/posts/rust-forces-me-to-think-unfortunately/</id>
        
        <content type="html" xml:base="https://www.laurentgaches.dev/posts/rust-forces-me-to-think-unfortunately/">&lt;h1 id=&quot;rust-forces-me-to-think&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#rust-forces-me-to-think&quot; aria-label=&quot;Anchor link for: rust-forces-me-to-think&quot;&gt;Rust Forces Me to Think&lt;&#x2F;a&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;I like Rust because it forces me to think.&lt;&#x2F;p&gt;
&lt;p&gt;This is deeply inconvenient.&lt;&#x2F;p&gt;
&lt;p&gt;Most of the time, when I write code, I have a vague but confident feeling that I know what I am doing. Rust has a talent for interrupting that feeling. It asks small, annoying questions like:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;who owns this data?&lt;&#x2F;li&gt;
&lt;li&gt;how long should this reference live?&lt;&#x2F;li&gt;
&lt;li&gt;are you sure this value can be shared here?&lt;&#x2F;li&gt;
&lt;li&gt;did you really mean to clone that?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Rude, honestly.&lt;&#x2F;p&gt;
&lt;p&gt;But also useful.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;data-has-to-go-somewhere&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#data-has-to-go-somewhere&quot; aria-label=&quot;Anchor link for: data-has-to-go-somewhere&quot;&gt;Data Has to Go Somewhere&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;One thing I appreciate about Rust is that it makes data flow visible.&lt;&#x2F;p&gt;
&lt;p&gt;When data moves from one function to another, from one module to another, or across a boundary in the system, Rust makes me be explicit about it. I cannot just wave my hands and hope everything remains fine because the code compiled and the test that happened to run passed.&lt;&#x2F;p&gt;
&lt;p&gt;The ownership model can feel strict at first, but I like what it does to the shape of the code. It pushes me to ask where data should live, who should be allowed to change it, and what a function really needs in order to do its job.&lt;&#x2F;p&gt;
&lt;p&gt;That sounds serious. In practice, it often means I spend ten minutes arguing with the compiler and then realize the compiler was right, which is an emotionally complicated experience.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;less-waste-is-a-feature&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#less-waste-is-a-feature&quot; aria-label=&quot;Anchor link for: less-waste-is-a-feature&quot;&gt;Less Waste Is a Feature&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I also like that Rust does not need much to run well.&lt;&#x2F;p&gt;
&lt;p&gt;It is fast, yes, but the part I care about more is that it can be efficient without a lot of ceremony. Less memory, less CPU, fewer oversized containers doing heroic work to serve three requests and a health check.&lt;&#x2F;p&gt;
&lt;p&gt;That matters for cost. When systems scale, waste becomes a line item. A small inefficiency repeated enough times becomes infrastructure, invoices, dashboards, meetings, and then someone says &quot;optimization pass&quot; with a straight face.&lt;&#x2F;p&gt;
&lt;p&gt;It also matters environmentally. I am not pretending that choosing Rust saves the planet by itself. That would be a very intense claim for a programming language. But using fewer resources is still better than using more resources for no reason.&lt;&#x2F;p&gt;
&lt;p&gt;If I can build something reliable, fast, and cheaper to run, I am not going to pretend that is a difficult choice.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;clippy-my-strict-little-colleague&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#clippy-my-strict-little-colleague&quot; aria-label=&quot;Anchor link for: clippy-my-strict-little-colleague&quot;&gt;Clippy, My Strict Little Colleague&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Then there is Clippy.&lt;&#x2F;p&gt;
&lt;p&gt;I like Clippy. I also sometimes wonder if Clippy is okay.&lt;&#x2F;p&gt;
&lt;p&gt;Enable enough lints and it becomes the kind of colleague who reviews your code and says, &quot;This is fine, but have you considered being a better person?&quot;&lt;&#x2F;p&gt;
&lt;p&gt;Some suggestions are obvious. Some are genuinely helpful. Some make me stare at the screen for a moment and quietly accept that yes, technically, the machine has a point.&lt;&#x2F;p&gt;
&lt;p&gt;What I like is that Clippy catches small habits before they become style, and style before it becomes architecture. It nudges the code toward clearer intent. It also teaches the language in a practical way, one mildly judgmental hint at a time.&lt;&#x2F;p&gt;
&lt;p&gt;Should every lint be enabled? Probably not, unless the goal is personal growth through controlled irritation. But I like having that tool available. It makes the codebase feel less like a pile of opinions and more like something with pressure in the right places.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;i-still-like-python-and-swift&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#i-still-like-python-and-swift&quot; aria-label=&quot;Anchor link for: i-still-like-python-and-swift&quot;&gt;I Still Like Python and Swift&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;This is not me saying Rust is the only good language. I still like Python. I like how quickly it lets me explore an idea, glue things together, and move from thought to working code without too much negotiation.&lt;&#x2F;p&gt;
&lt;p&gt;I also like Swift. It has a nice balance between expressiveness and structure, especially when building iOS applications. There is a real pleasure in writing Swift when the APIs line up well and the model feels right.&lt;&#x2F;p&gt;
&lt;p&gt;Rust gives me a different kind of satisfaction. It is slower at the beginning, but often calmer later. It asks for decisions early, which can be annoying, but those decisions tend to make the rest of the code easier to trust.&lt;&#x2F;p&gt;
&lt;p&gt;That tradeoff fits the kind of backend and infrastructure work I enjoy.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-part-i-keep-coming-back-to&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-part-i-keep-coming-back-to&quot; aria-label=&quot;Anchor link for: the-part-i-keep-coming-back-to&quot;&gt;The Part I Keep Coming Back To&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The main reason I like Rust is not performance, safety, or any of the usual brochure words, even if those things matter.&lt;&#x2F;p&gt;
&lt;p&gt;I like it because it makes the important parts harder to ignore.&lt;&#x2F;p&gt;
&lt;p&gt;Data movement. Ownership. Boundaries. Resource usage. Error handling. The small decisions that quietly define whether a system remains understandable six months later.&lt;&#x2F;p&gt;
&lt;p&gt;Rust does not magically make me write good software. That would be convenient, and therefore suspicious.&lt;&#x2F;p&gt;
&lt;p&gt;But it does make some bad shortcuts harder to take by accident.&lt;&#x2F;p&gt;
&lt;p&gt;So yes, Rust makes me think. Terrible feature. Very effective.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Orchestrator and Executor: A Practical Architectural Split</title>
        <published>2026-04-28T00:00:00+00:00</published>
        <updated>2026-04-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Laurent Gaches
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.laurentgaches.dev/posts/orchestrator-executor-architecture/"/>
        <id>https://www.laurentgaches.dev/posts/orchestrator-executor-architecture/</id>
        
        <content type="html" xml:base="https://www.laurentgaches.dev/posts/orchestrator-executor-architecture/">&lt;h1 id=&quot;orchestrator-and-executor-a-practical-architectural-split&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#orchestrator-and-executor-a-practical-architectural-split&quot; aria-label=&quot;Anchor link for: orchestrator-and-executor-a-practical-architectural-split&quot;&gt;Orchestrator and Executor: A Practical Architectural Split&lt;&#x2F;a&gt;&lt;&#x2F;h1&gt;
&lt;p&gt;Many AI systems begin with a single service that handles everything: request parsing, planning, tool calls, retries, and response formatting.
This is often a reasonable starting point because it keeps delivery fast and implementation simple.&lt;&#x2F;p&gt;
&lt;p&gt;As workflows become more complex, this approach can become harder to maintain.
The orchestrator&#x2F;executor pattern addresses that by separating two concerns:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Orchestrator&lt;&#x2F;strong&gt;: decides what should happen next&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Executor&lt;&#x2F;strong&gt;: performs a specific action&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This article looks at that split from an architecture perspective: why it helps, where it costs, and when it may not be necessary.&lt;&#x2F;p&gt;
&lt;script src=https:&#x2F;&#x2F;www.laurentgaches.dev&#x2F;js&#x2F;mermaid.js&gt;&lt;&#x2F;script&gt;

&lt;pre class=&quot;mermaid&quot;&gt;
  flowchart LR
    Request[User request] --&gt; Orchestrator[Orchestrator]
    Orchestrator --&gt; Retrieval[Retrieval executor]
    Orchestrator --&gt; Generation[Generation executor]
    Orchestrator --&gt; Validation[Validation executor]
    Retrieval --&gt; Orchestrator
    Generation --&gt; Orchestrator
    Validation --&gt; Orchestrator
    Orchestrator --&gt; Response[Response]
&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;the-core-idea&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-core-idea&quot; aria-label=&quot;Anchor link for: the-core-idea&quot;&gt;The Core Idea&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The orchestrator is the decision layer.
It manages flow-level concerns such as sequencing, routing, fallback choices, and stop conditions.&lt;&#x2F;p&gt;
&lt;p&gt;Executors are capability-focused components.
Each executor is responsible for one type of work, such as retrieval, tool invocation, transformation, or validation.&lt;&#x2F;p&gt;
&lt;p&gt;In simple terms, the orchestrator owns coordination, while executors own execution.&lt;&#x2F;p&gt;
&lt;p&gt;This separation is useful when systems need to evolve without every change touching the full workflow.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-the-split-holds-up&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#why-the-split-holds-up&quot; aria-label=&quot;Anchor link for: why-the-split-holds-up&quot;&gt;Why the Split Holds Up&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The value of this architecture is not that every team should adopt it.
The value is that it gives a complex system clearer lines of responsibility.&lt;&#x2F;p&gt;
&lt;p&gt;When the same component decides the flow and performs the work, it becomes harder to understand which part of the system is responsible for a behavior.
A failure may come from the decision logic, the execution logic, or the way both were mixed together.&lt;&#x2F;p&gt;
&lt;p&gt;Separating the orchestrator from executors makes that boundary more visible.
The orchestrator can focus on sequencing, routing, fallback choices, and stop conditions.
Executors can focus on doing specialized work well.&lt;&#x2F;p&gt;
&lt;p&gt;This also creates more room for change.
A model provider can be replaced. A retrieval strategy can be improved. A validation step can become stricter.
Those changes still require care, but they do not need to reshape the whole workflow if the contracts remain stable.&lt;&#x2F;p&gt;
&lt;p&gt;The split also helps with operational control.
Policies such as timeouts, retry limits, cost limits, and safety checks can be handled consistently at the orchestration level.
This does not remove complexity, but it gives that complexity a clearer place to live.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-the-architecture-gives-you&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-the-architecture-gives-you&quot; aria-label=&quot;Anchor link for: what-the-architecture-gives-you&quot;&gt;What the Architecture Gives You&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The first benefit is readability at system level.
When looking at the workflow, you can see where decisions are made and where work is delegated.
This makes the system easier to discuss, review, and evolve.&lt;&#x2F;p&gt;
&lt;p&gt;The second benefit is replaceability.
An executor can change internally without changing the whole orchestration path.
This matters in AI systems because models, tools, and providers evolve quickly.&lt;&#x2F;p&gt;
&lt;p&gt;The third benefit is consistent governance.
If cost limits, safety policies, or retry rules are spread across many executors, behavior becomes harder to predict.
Keeping these controls close to the orchestrator makes them easier to apply consistently.&lt;&#x2F;p&gt;
&lt;p&gt;There is also a scaling benefit.
Some executors may be expensive or slow. Others may be lightweight.
Keeping them separate allows different runtime and scaling strategies.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;where-it-becomes-expensive&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#where-it-becomes-expensive&quot; aria-label=&quot;Anchor link for: where-it-becomes-expensive&quot;&gt;Where It Becomes Expensive&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The architecture has real costs.&lt;&#x2F;p&gt;
&lt;p&gt;Every additional boundary adds coordination work.
Inputs and outputs need clear contracts. Errors need shared semantics. Versions need to be managed.
Without that discipline, the separation becomes another source of friction.&lt;&#x2F;p&gt;
&lt;p&gt;Latency can also become a concern.
A workflow with many orchestration steps can be slower than a simpler direct path.
This does not mean the pattern is wrong, but latency needs to be part of the design, not an afterthought.&lt;&#x2F;p&gt;
&lt;p&gt;Observability becomes more important.
In a single component, logs may be enough for basic debugging.
In an orchestrated system, you need to understand the full path of a request across decisions and executors.
Tracing, correlation IDs, and step-level metrics become part of the architecture.&lt;&#x2F;p&gt;
&lt;p&gt;In practice, a clean two-layer split is often harder to hold than it appears.
Real systems frequently need an intermediate coordination layer between the orchestrator and the executors.
This tier handles concerns that are too operational for the orchestrator and too general for any single executor: routing tool calls to the right handler, managing concurrent task queues, propagating state between steps, and skipping dependent tasks when a prerequisite fails.
This coordination layer is not a design failure. It reflects genuine work that does not belong cleanly in either layer.
The cost is that the system now has three conceptual tiers to reason about rather than two, and the boundaries between them require the same discipline as the original split.&lt;&#x2F;p&gt;
&lt;p&gt;The main risk is that the orchestrator becomes too broad.
If every new rule, exception, and domain decision ends up there, the orchestrator becomes difficult to change.
At that point, the system has only moved complexity from one place to another.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-boundary-that-matters&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-boundary-that-matters&quot; aria-label=&quot;Anchor link for: the-boundary-that-matters&quot;&gt;The Boundary That Matters&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The most important design question is not &quot;do we have an orchestrator?&quot;
It is &quot;what is the orchestrator allowed to know?&quot;&lt;&#x2F;p&gt;
&lt;p&gt;A healthy orchestrator understands workflow state, routing rules, policies, and failure strategy.
It should know which capability is needed next.&lt;&#x2F;p&gt;
&lt;p&gt;It should not own the internal details of every capability.
A retrieval executor should own retrieval strategy.
A validation executor should own validation logic.
A generation executor should own the details of prompt execution and model interaction.&lt;&#x2F;p&gt;
&lt;p&gt;This boundary keeps executors meaningful.
It also keeps the orchestrator from becoming a central dependency for every product detail.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;when-the-pattern-is-useful&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#when-the-pattern-is-useful&quot; aria-label=&quot;Anchor link for: when-the-pattern-is-useful&quot;&gt;When the Pattern Is Useful&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;This architecture fits best when the workflow has real branching, multiple capabilities, and meaningful failure handling.&lt;&#x2F;p&gt;
&lt;p&gt;For example, an AI workflow may need to retrieve context, decide whether the context is sufficient, call a model, validate the result, retry with different parameters, or escalate to another path.
In that kind of system, orchestration gives structure to complexity.&lt;&#x2F;p&gt;
&lt;p&gt;It is less useful when the workflow is simple and linear.
If one service can handle the work cleanly, adding an orchestration layer may only add overhead.&lt;&#x2F;p&gt;
&lt;p&gt;The pattern should respond to actual pressure in the system: changing capabilities, growing workflows, reliability needs, policy enforcement, or team ownership boundaries.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#conclusion&quot; aria-label=&quot;Anchor link for: conclusion&quot;&gt;Conclusion&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;The orchestrator&#x2F;executor pattern is not a universal requirement.
It is a way to separate decision-making from execution when a system becomes difficult to evolve as one unit.&lt;&#x2F;p&gt;
&lt;p&gt;Its strength is clarity: clear flow control, clear execution boundaries, and clear places for policy and failure handling.&lt;&#x2F;p&gt;
&lt;p&gt;Its cost is coordination: contracts, latency, observability, and governance of the orchestrator itself.&lt;&#x2F;p&gt;
&lt;p&gt;Used carefully, the split can help AI systems grow without turning every workflow change into a full-system change.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
