<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Remy Loubradou</title>
    <description>The latest articles on DEV Community by Remy Loubradou (@lbdremy).</description>
    <link>https://dev.to/lbdremy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3892814%2F0a5908d4-3eda-40c4-b57b-653dc2146ff5.jpeg</url>
      <title>DEV Community: Remy Loubradou</title>
      <link>https://dev.to/lbdremy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lbdremy"/>
    <language>en</language>
    <item>
      <title>Explicit vs. Implicit in the Age of Intelligences</title>
      <dc:creator>Remy Loubradou</dc:creator>
      <pubDate>Thu, 07 May 2026 15:06:00 +0000</pubDate>
      <link>https://dev.to/lbdremy/explicit-vs-implicit-in-the-age-of-intelligences-34jj</link>
      <guid>https://dev.to/lbdremy/explicit-vs-implicit-in-the-age-of-intelligences-34jj</guid>
      <description>&lt;p&gt;Why the implicit becomes fragile when humans and agents co-produce code.&lt;/p&gt;

&lt;p&gt;In the previous article, I defended a simple idea: code is not elegant prose. It is a system, to be judged by its robustness.&lt;/p&gt;

&lt;p&gt;But that idea calls for another one.&lt;/p&gt;

&lt;p&gt;If code is a system, then it is not enough for it to be pleasant to write, locally fluid to read, or elegant in appearance. Its structures must remain visible. Its boundaries, states, contracts, responsibilities, and effects must be understandable, revisitable, criticizable, and transformable.&lt;/p&gt;

&lt;p&gt;In other words: the system must be explicit.&lt;/p&gt;

&lt;p&gt;This is where a very contemporary tension appears. For a long time, part of software tooling has valued the implicit: conventions, framework magic, inferred behaviors, invisible structures, shortcuts that let us move faster. This has often been useful. It has sometimes even been very productive.&lt;/p&gt;

&lt;p&gt;But in the age of intelligences — human and artificial — the implicit changes in nature.&lt;/p&gt;

&lt;p&gt;The problem with the implicit is not only that it is hidden. It is that it is no longer guaranteed to be shared.&lt;/p&gt;

&lt;h2&gt;
  
  
  The implicit has long been an accelerator
&lt;/h2&gt;

&lt;p&gt;We should not caricature the implicit.&lt;/p&gt;

&lt;p&gt;The implicit is not bad by nature. It has made it possible to build more fluid tools, frameworks that are faster to adopt, and more productive conventions. It has made it possible to write less, repeat less, and move part of the work into the framework, the language, or the environment.&lt;/p&gt;

&lt;p&gt;This is often what makes a technology pleasant.&lt;/p&gt;

&lt;p&gt;A file placed in the right location automatically becomes a route. A function named in a certain way is recognized by a tool. A discreet directive changes the execution location of a piece of code. A naming convention avoids explicit configuration. A React hook makes it possible to reuse logic by connecting to a component’s lifecycle.&lt;/p&gt;

&lt;p&gt;All of this can be practical.&lt;/p&gt;

&lt;p&gt;And sometimes, this local comfort creates an impression of elegance.&lt;/p&gt;

&lt;p&gt;But we need to name what is really happening: part of the system’s structure is no longer in the code itself. It is in the prior knowledge one must possess to interpret that code correctly.&lt;/p&gt;

&lt;p&gt;The implicit works well when everyone shares the same context.&lt;/p&gt;

&lt;p&gt;It works less well when that context becomes unstable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The implicit becomes fragile when it is no longer shared
&lt;/h2&gt;

&lt;p&gt;In a stable human team, some implicit knowledge can hold for a long time.&lt;/p&gt;

&lt;p&gt;Developers know how the system works. They know the local conventions. They know why one layer must not import another. They know that a given function must only be called in a given state. They know that a given hook is fragile, that a given abstraction hides a side effect, that a given route depends on a file convention.&lt;/p&gt;

&lt;p&gt;This knowledge is not always written down. But it circulates through habit, code review, oral transmission, and familiarity with the project.&lt;/p&gt;

&lt;p&gt;In the age of agents, this situation becomes more fragile.&lt;/p&gt;

&lt;p&gt;Humans and agents do not produce code according to the same internal logic. Humans mobilize concepts, intentions, mental models, and a more or less explicit causal understanding. Agents produce a plausible continuation under constraints, then are brought back into line by the compiler, the type checker, tests, linting, and audit rules.&lt;/p&gt;

&lt;p&gt;Both can produce valid code.&lt;/p&gt;

&lt;p&gt;But they do not produce it in the same way.&lt;/p&gt;

&lt;p&gt;And above all, they do not necessarily share the same implicit knowledge.&lt;/p&gt;

&lt;p&gt;An agent can introduce a locally plausible form, compatible with immediate constraints, but unnamed, unstabilized, and unshared by the humans who will later take over the system. Another agent, or another version of the same agent, may infer something else. A human may not recognize the hidden assumption. The code may continue to work, but its collective intelligibility will have decreased.&lt;/p&gt;

&lt;p&gt;An unshared implicit becomes an invisible dependency of the system.&lt;/p&gt;

&lt;p&gt;And an invisible dependency always ends up being costly.&lt;/p&gt;

&lt;h2&gt;
  
  
  A probabilistic machine facing a system that must remain stable
&lt;/h2&gt;

&lt;p&gt;An LLM is a probabilistic machine.&lt;/p&gt;

&lt;p&gt;It produces a plausible continuation. It works from a context, learned patterns, examples, constraints, and tool feedback. It does not understand code the way a human understands a system they have designed, inhabited, corrected, maintained, and confronted with reality.&lt;/p&gt;

&lt;p&gt;And yet the code it produces must join an artifact that cannot remain probabilistic.&lt;/p&gt;

&lt;p&gt;The software system must tend toward something stable: defined states, controlled transitions, verifiable contracts, localized effects, observable errors.&lt;/p&gt;

&lt;p&gt;There is therefore a central tension: a probabilistic machine participates in producing a system that must remain predictable, testable, and controllable.&lt;/p&gt;

&lt;p&gt;The explicit does not remove that tension.&lt;/p&gt;

&lt;p&gt;It reduces it.&lt;/p&gt;

&lt;p&gt;The more a system relies on implicit knowledge, the more the agent has to infer. The more it has to infer, the more likely drift becomes. Conversely, the more concepts are made visible, the less the agent has to guess what is expected.&lt;/p&gt;

&lt;p&gt;The explicit does not cancel the probabilistic nature of the model. It bounds what the model needs to guess.&lt;/p&gt;

&lt;p&gt;This is why the explicit is not only a reading aid. It is the shared language of production for a system whose authors do not reason in the same way.&lt;/p&gt;

&lt;p&gt;When the producers of code do not reason in the same way, the explicit becomes a condition of coordination.&lt;/p&gt;

&lt;h2&gt;
  
  
  The explicit creates cognitive portability
&lt;/h2&gt;

&lt;p&gt;There is another important consequence.&lt;/p&gt;

&lt;p&gt;When concepts are explicit, the language becomes partly secondary.&lt;/p&gt;

&lt;p&gt;Take a simple example: the possible states of a system.&lt;/p&gt;

&lt;p&gt;In TypeScript, they can be represented with a discriminated union:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RecorderState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;recording&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;paused&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Rust, we would rather write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;RecorderState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Idle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Recording&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;Paused&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;session_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Swift:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;RecorderState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;idle&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nf"&gt;recording&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nf"&gt;paused&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Kotlin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;RecorderState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;Idle&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RecorderState&lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Recording&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RecorderState&lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Paused&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RecorderState&lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;RecorderState&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are not the same languages.&lt;/p&gt;

&lt;p&gt;But they are the same conceptual form.&lt;/p&gt;

&lt;p&gt;We are no longer merely reading TypeScript, Rust, Swift, or Kotlin. We are reading a finite set of possible states. We are reading an intention of modeling. We are reading a structure that says: these are the cases recognized by the system.&lt;/p&gt;

&lt;p&gt;This is what I would call cognitive portability.&lt;/p&gt;

&lt;p&gt;The explicit does not only make code readable. It makes it readable independently of the language.&lt;/p&gt;

&lt;p&gt;The implicit, by contrast, travels less well. It is often local to a framework, a convention, a directive, runtime magic, or team knowledge. It can be very effective inside its own context. But as soon as one changes language, framework, agent, team, or era, it becomes more fragile.&lt;/p&gt;

&lt;p&gt;The explicit makes forms recognizable.&lt;/p&gt;

&lt;p&gt;And recognizable forms make convergence easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  A grid for analyzing the implicit
&lt;/h2&gt;

&lt;p&gt;We can then propose a simple grid.&lt;/p&gt;

&lt;p&gt;To analyze the implicit in real code, we need to cross three dimensions.&lt;/p&gt;

&lt;p&gt;The first dimension is the system concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  boundaries;&lt;/li&gt;
&lt;li&gt;  contracts;&lt;/li&gt;
&lt;li&gt;  validation;&lt;/li&gt;
&lt;li&gt;  invariants;&lt;/li&gt;
&lt;li&gt;  explicit states;&lt;/li&gt;
&lt;li&gt;  responsibility and authority;&lt;/li&gt;
&lt;li&gt;  deterministic transformations;&lt;/li&gt;
&lt;li&gt;  proof;&lt;/li&gt;
&lt;li&gt;  observability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second dimension is the layers where these concepts can appear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  the language;&lt;/li&gt;
&lt;li&gt;  the framework;&lt;/li&gt;
&lt;li&gt;  libraries;&lt;/li&gt;
&lt;li&gt;  application architecture;&lt;/li&gt;
&lt;li&gt;  team or project conventions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The third dimension is their mode of expression: explicit or implicit.&lt;/p&gt;

&lt;p&gt;Each time, the question is the same:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is this concept made visible in the code, or does it rely on a convention, magic, an abstraction, or prior knowledge?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is not a condemnation of all abstraction.&lt;/p&gt;

&lt;p&gt;A good abstraction hides noise.&lt;/p&gt;

&lt;p&gt;A bad abstraction hides the system.&lt;/p&gt;

&lt;p&gt;The difference is essential.&lt;/p&gt;

&lt;p&gt;When an abstraction hides an unimportant detail, it helps us. When it hides a boundary, a state, a responsibility, a side effect, or an invariant, it makes the system harder to understand and easier to drift.&lt;/p&gt;

&lt;p&gt;Here is a synthetic version of this grid:&lt;/p&gt;

&lt;p&gt;| Concept | Layer | Explicit form | Implicit form | Risk | | ----------------------------- | ----------------------- | ------------------------------------------------------------------- | ------------------------------------------------------- | ----------------------------------- | | Boundaries | Language | modules, visibility, input/output types, controlled imports | free imports, globals, unchecked conventions | porous boundaries | | Boundaries | Framework | &lt;code&gt;server/&lt;/code&gt;, &lt;code&gt;client/&lt;/code&gt; files, separate handlers, &lt;code&gt;server-only&lt;/code&gt; | discreet directive, colocation that masks client/server | forgetting the boundary | | Contracts | Language | strict types, interfaces, discriminated unions | &lt;code&gt;any&lt;/code&gt;, free strings, informal objects | silent assumptions | | Validation | Framework / library | validation schemas at boundaries, explicit parsing | payload accepted by convention | doubtful data in the core | | Invariants | Architecture | controlled constructor, bounded domain model, forbidden transitions | mutable objects everywhere, scattered rules | possible inconsistent state | | States | Language / architecture | state machine, statechart, discriminated unions | scattered booleans, local conditions | illegal transitions | | Responsibility / authority | Architecture | clear ownership of a resource or transition | several layers can mutate the same thing | unclear authority | | Deterministic transformations | Business code | pure functions, immutability, clear input/output | hidden side effects | behavior hard to test | | Proof | Language / tools | typecheck, exhaustiveness, tests, constraints | human trust, conventions | undetected omission | | Observability | Runtime / architecture | contextual logs, traces, correlation IDs | &lt;code&gt;console.error&lt;/code&gt;, generic error without context | impossible to understand production |&lt;/p&gt;

&lt;p&gt;The point of this grid is not to be exhaustive. It is mainly to shift the question.&lt;/p&gt;

&lt;p&gt;We no longer ask only: “is this code clean?”&lt;/p&gt;

&lt;p&gt;We ask: “where are the important concepts of the system visible? And where have they disappeared behind implicitness?”&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: boundaries in Next.js
&lt;/h2&gt;

&lt;p&gt;Take a contemporary example: Next.js Server Actions.&lt;/p&gt;

&lt;p&gt;The problem is not that the tool is bad. Nor is the problem that it forces boundaries to be blurred. It is perfectly possible to define server actions separately, in dedicated files, and to mark the split clearly.&lt;/p&gt;

&lt;p&gt;But the framework makes possible, through a directive, a very practical form of colocation between frontend code and a server action. This local comfort can create an impression of elegance.&lt;/p&gt;

&lt;p&gt;And yet the boundary has not disappeared.&lt;/p&gt;

&lt;p&gt;It has only become more discreet.&lt;/p&gt;

&lt;p&gt;Behind this apparent simplicity, there is still a real mechanism: server functions callable over the network, authentication and authorization checks to perform again inside the action itself, captured variables sent and then returned, encryption, dependency on the build.&lt;/p&gt;

&lt;p&gt;The framework takes part of this on itself, but the abstraction does not remove the complexity. It shifts it and partially masks it.&lt;/p&gt;

&lt;p&gt;In the grid, we could say:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  concept: boundary;&lt;/li&gt;
&lt;li&gt;  layer: framework;&lt;/li&gt;
&lt;li&gt;  explicit form: clear separation between client and server;&lt;/li&gt;
&lt;li&gt;  implicit form: very practical colocation that makes the boundary less visible;&lt;/li&gt;
&lt;li&gt;  risk: forgetting the requirements specific to that boundary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Again, the problem is not the tool.&lt;/p&gt;

&lt;p&gt;The problem is how easily local comfort can make us forget a real boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example: React hooks
&lt;/h2&gt;

&lt;p&gt;React hooks are another interesting example.&lt;/p&gt;

&lt;p&gt;They brought something very powerful: the reuse of logic.&lt;/p&gt;

&lt;p&gt;Before hooks, React already made views composable. With hooks, it became possible to make local logic reusable too: state, effects, subscriptions, access to the lifecycle, shared behaviors.&lt;/p&gt;

&lt;p&gt;It was a real step forward.&lt;/p&gt;

&lt;p&gt;But that progress came with a very strong form of implicitness.&lt;/p&gt;

&lt;p&gt;Hooks are not ordinary JavaScript. They obey specific rules: constrained call order, impossibility of calling them conditionally, the &lt;code&gt;use&lt;/code&gt; prefix, dependencies to maintain in arrays, dedicated linting to flag invalid usages.&lt;/p&gt;

&lt;p&gt;Part of the system therefore lives in the implicit rules of the framework.&lt;/p&gt;

&lt;p&gt;Of course, we can learn these rules. We can tool them. We can respect them. But we must recognize what they are: prior knowledge required to correctly interpret the code.&lt;/p&gt;

&lt;p&gt;And the problem becomes clearer when hooks are used to carry complex behavior.&lt;/p&gt;

&lt;p&gt;A few &lt;code&gt;useState&lt;/code&gt;, a few &lt;code&gt;useEffect&lt;/code&gt;, a few callbacks, a few handlers, and suddenly the component no longer merely renders a view. It hides a small system: states, transitions, effects, resources, invariants, lifecycle.&lt;/p&gt;

&lt;p&gt;The view becomes the place where behavior has been mixed in.&lt;/p&gt;

&lt;p&gt;The logic is reusable, but it is not necessarily explicit.&lt;/p&gt;

&lt;p&gt;Hooks made logic reusable. They did not make it explicit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving logic out of React
&lt;/h2&gt;

&lt;p&gt;One possible direction is not to remove hooks.&lt;/p&gt;

&lt;p&gt;It is to put them back in their place.&lt;/p&gt;

&lt;p&gt;In this approach, React remains a layer of view and adaptation. The important logic lives in an explicit model outside React.&lt;/p&gt;

&lt;p&gt;The model carries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  states;&lt;/li&gt;
&lt;li&gt;  events;&lt;/li&gt;
&lt;li&gt;  transitions;&lt;/li&gt;
&lt;li&gt;  effects;&lt;/li&gt;
&lt;li&gt;  resources;&lt;/li&gt;
&lt;li&gt;  invariants;&lt;/li&gt;
&lt;li&gt;  the data exposed to the interface.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;React merely subscribes to the model and sends it user events.&lt;/p&gt;

&lt;p&gt;We could represent the architecture like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Explicit model → Snapshot / ViewModel → React view
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The hook then becomes an adapter, not the main place where logic lives.&lt;/p&gt;

&lt;p&gt;For example, for a simplified recording system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;recorderModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createRecorderModel&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;recordingApi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;uploader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;createMediaRecorder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;recorderModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;recorderModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pause&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;recorderModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resume&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;recorderModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;discard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model exposes its states and events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RecorderState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;idle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;recording&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;uploadedSegments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;paused&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;uploadedSegments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;saving&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;sessionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;saved&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;recordingId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;discarded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RecorderEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pause&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resume&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;segment-ready&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;blob&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Blob&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;save&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;discard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then React subscribes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;useRecorderModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RecorderModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSyncExternalStore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getSnapshot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getSnapshot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unmount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the component no longer carries the main behavior:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RecorderScreen&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;RecorderModel&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;recorder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRecorderModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RecorderView&lt;/span&gt;
      &lt;span class="na"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;recorder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;snapshot&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onStart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;recorder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onPause&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;recorder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pause&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onResume&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;recorder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resume&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onSave&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;recorder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;save&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="na"&gt;onDiscard&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;recorder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;discard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact details of the API matter less than the conceptual shift.&lt;/p&gt;

&lt;p&gt;The hook no longer hides a combination of states, effects, resources, and implicit rules. It connects React to an explicit model.&lt;/p&gt;

&lt;p&gt;Libraries like XState already move in this direction: the logic is externalized into an explicit model, and React mostly serves as a display and adaptation layer.&lt;/p&gt;

&lt;p&gt;XState is not the only example. Redux was already moving in that direction: taking transition logic out of components, representing changes as actions, and making state evolve through reducers that can be tested separately. Even &lt;code&gt;useReducer&lt;/code&gt;, when used with a reducer defined outside the component, can be a step toward more explicitness. The difference is therefore not between “hooks” and “no hooks.” It is between logic hidden inside the component and logic made visible in an autonomous form: reducer, store, state machine, or explicit model.&lt;/p&gt;

&lt;p&gt;The problem is not that a hook calls this logic. The problem appears when the hook itself becomes the place where state, transitions, effects, and responsibilities get mixed tog&lt;/p&gt;

&lt;p&gt;So the question is not: “should we use hooks or not?”&lt;/p&gt;

&lt;p&gt;The question is: “when does a behavior become too systemic to remain hidden inside hooks?”&lt;/p&gt;

&lt;h2&gt;
  
  
  What should not be misunderstood
&lt;/h2&gt;

&lt;p&gt;The explicit is not a religion.&lt;/p&gt;

&lt;p&gt;This is not about making everything heavy, verbose, ceremonial. It is not about rejecting conventions, frameworks, abstractions, or shortcuts.&lt;/p&gt;

&lt;p&gt;A fully explicit but poorly organized system can be unreadable. The explicit is not enough to produce clarity.&lt;/p&gt;

&lt;p&gt;We must therefore avoid the wrong conclusion: more code does not automatically mean more robustness.&lt;/p&gt;

&lt;p&gt;What matters is making explicit the concepts that truly carry the system.&lt;/p&gt;

&lt;p&gt;A local convention can work very well if it does not hide anything essential. An abstraction can be excellent if it hides noise, not a responsibility. A framework can increase robustness if it makes the right boundaries visible instead of diluting them.&lt;/p&gt;

&lt;p&gt;The goal is not to naively oppose explicit and implicit.&lt;/p&gt;

&lt;p&gt;The goal is to know where the implicit becomes dangerous.&lt;/p&gt;

&lt;p&gt;It becomes dangerous when it hides a boundary, a state, an invariant, an authority, a side effect, a security assumption, a validation rule, a business transition, or production behavior.&lt;/p&gt;

&lt;p&gt;That is where we need to make visible.&lt;/p&gt;

&lt;p&gt;That is where we need to name.&lt;/p&gt;

&lt;p&gt;That is where we need to model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion — the explicit as a support for convergence
&lt;/h2&gt;

&lt;p&gt;In the age of intelligences, the explicit is not merely a style preference.&lt;/p&gt;

&lt;p&gt;It is not merely a way to help humans read code.&lt;/p&gt;

&lt;p&gt;It is a condition of coordination between producers of code who do not necessarily share the same implicit knowledge.&lt;/p&gt;

&lt;p&gt;A human can read a system with a mental model. An agent can produce a plausible form under constraints. Another agent can produce a different one. A future maintainer can arrive without knowing the history of the project.&lt;/p&gt;

&lt;p&gt;What allows them to converge is not a shared implicit.&lt;/p&gt;

&lt;p&gt;It is a shared explicit structure.&lt;/p&gt;

&lt;p&gt;The explicit makes concepts visible. It reduces the amount of guessing. It makes forms more portable from one language to another. It makes boundaries, states, responsibilities, and effects harder to forget.&lt;/p&gt;

&lt;p&gt;It does not guarantee that the system is good.&lt;/p&gt;

&lt;p&gt;But it makes one essential thing possible: to take it up again, discuss it, correct it, make it evolve.&lt;/p&gt;

&lt;p&gt;The implicit can accelerate.&lt;/p&gt;

&lt;p&gt;The explicit allows transmission.&lt;/p&gt;

&lt;p&gt;And in a world where humans and agents write together, what cannot be transmitted eventually drifts.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Code Is a System, Not Elegant Prose</title>
      <dc:creator>Remy Loubradou</dc:creator>
      <pubDate>Tue, 28 Apr 2026 14:00:00 +0000</pubDate>
      <link>https://dev.to/lbdremy/code-is-a-system-not-elegant-prose-286o</link>
      <guid>https://dev.to/lbdremy/code-is-a-system-not-elegant-prose-286o</guid>
      <description>&lt;p&gt;Code is not elegant prose. It is a system, to be judged by its robustness.&lt;/p&gt;

&lt;p&gt;Too often, we talk about code as if we were talking about style.&lt;/p&gt;

&lt;p&gt;We say that a piece of code is &lt;em&gt;elegant&lt;/em&gt;, &lt;em&gt;beautiful&lt;/em&gt;, &lt;em&gt;refined&lt;/em&gt;, &lt;em&gt;clean&lt;/em&gt;, sometimes even &lt;em&gt;inspired&lt;/em&gt;. We attribute to it qualities that are almost literary, almost artistic, as if writing software were first and foremost an art of form. As if the quality of code were decided mainly by the way its sentences look.&lt;/p&gt;

&lt;p&gt;That is a category error.&lt;/p&gt;

&lt;p&gt;The problem is not the word &lt;em&gt;elegant&lt;/em&gt; in itself. The problem is everything it carries when it is used in a romantic, literary, aesthetic sense: the idea that good code would first and foremost be code admired for its formal poise, its grace, a kind of almost autonomous inner beauty.&lt;/p&gt;

&lt;p&gt;And yet code is not a text to be contemplated. Code runs in the world.&lt;/p&gt;

&lt;p&gt;It runs in machines, networks, browsers, phones, databases, message queues, distributed systems, human organizations. It encounters latency, outages, incomplete responses, side effects, inconsistent users, imperfect environments, intermediate states, unstable dependencies.&lt;/p&gt;

&lt;p&gt;The real world does not applaud the beauty of an abstraction. It punishes the absence of guardrails.&lt;/p&gt;

&lt;p&gt;That is why the right vocabulary is not, first and foremost, the vocabulary of elegance. It is the vocabulary of robustness.&lt;/p&gt;

&lt;p&gt;One thing must be made clear, however: I am not arguing here against elegance in the sense some engineers mean it — clarity, sound decomposition, the right simplicity. That tradition is valuable. What I am aiming at is another way of talking about code: a more romantic, more aesthetic way, one that judges it first by its appearance rather than by how well it holds up in the real world.&lt;/p&gt;

&lt;p&gt;What is often celebrated as “elegant” is not always a structural quality. It is sometimes a quality of local comfort: less code, more fluidity, more colocation, more convention, more implicitness. And yet what is practical to write or pleasant to read locally is not always what makes a system more explicit, more stable, or more transmissible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Robustness as the real criterion
&lt;/h2&gt;

&lt;p&gt;I use the word &lt;strong&gt;robustness&lt;/strong&gt; here in a broad sense.&lt;/p&gt;

&lt;p&gt;Robust code is not simply code that “doesn’t break.” Robust code is code that is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;intelligible&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;resilient&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;observable&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That definition changes the very way we judge software.&lt;/p&gt;

&lt;p&gt;The question is no longer: &lt;em&gt;is this code beautiful?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The question becomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Can a human understand it without taking a leap of faith?&lt;/li&gt;
&lt;li&gt;  Can a machine reason about it without guessing?&lt;/li&gt;
&lt;li&gt;  Does it absorb failures and deviations from the real world cleanly?&lt;/li&gt;
&lt;li&gt;  Can we know what it did, in what state, and why?&lt;/li&gt;
&lt;li&gt;  Can we take it up again, extend it, audit it, without weakening the whole?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is where the real shift lies.&lt;/p&gt;

&lt;p&gt;We should not judge code first as an aesthetic object. We should judge it as a system exposed to reality.&lt;/p&gt;

&lt;p&gt;That does not mean every piece of code requires the same level of formalization everywhere, but that the right compass is not how code looks: it is the level of robustness the situation actually requires.&lt;/p&gt;

&lt;p&gt;These tools have a cost as well. A prototype still looking for its problem does not need the same level of formalization as a critical system. The discipline is not to structure everything everywhere, but to know what deserves to be structured, when, and for what risk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Intelligible, because it must be possible to read it without guessing
&lt;/h2&gt;

&lt;p&gt;Robustness begins with intelligibility. And in this article, what I call intelligible depends first on one property: the explicit. Visible boundaries, clear responsibilities, named states, stated contracts, declared transitions, but also clear names, understandable flows, localized transformations, and stable conventions. A system does not become automatically simple merely because it is explicit. But without explicitness, it forces us to guess — and a system that forces us to guess quickly becomes costly.&lt;/p&gt;

&lt;p&gt;But today, that is no longer enough.&lt;/p&gt;

&lt;p&gt;Code must also be intelligible to machines.&lt;/p&gt;

&lt;p&gt;We are entering an era in which code is no longer read only by developers. It is also read, audited, transformed, completed, explained, and sometimes generated by intelligences. Ambiguous, implicit code, full of unstated conventions, does not merely become painful for a human colleague: it also becomes fragile for an agent. It forces it to guess.&lt;/p&gt;

&lt;p&gt;And as soon as a system relies on guesswork, it becomes costly to maintain and dangerous to modify.&lt;/p&gt;

&lt;p&gt;Intelligibility is therefore not a luxury of style. It is an operational property. And here, it depends largely on making the system explicit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resilient, because the world deviates
&lt;/h2&gt;

&lt;p&gt;Good code is not code that assumes everything will go well. It is code designed in the knowledge that not everything will go as planned.&lt;/p&gt;

&lt;p&gt;I use “resilient” here in a broad sense. A resilient system does not merely survive a failure. It absorbs deviations from the real world: latency, incomplete responses, unstable dependencies, replays, temporary unavailability, side effects, partial interruptions, variations in context.&lt;/p&gt;

&lt;p&gt;As soon as a system touches the outside world, it encounters that uncertainty: a network response may arrive late, an API may change shape, a user may send absurd data, a database may be temporarily unavailable, an event may be processed twice, a state may be partially updated.&lt;/p&gt;

&lt;p&gt;A robust system does not deny that reality. It frames it.&lt;/p&gt;

&lt;p&gt;It distinguishes what is reliable from what is not.&lt;/p&gt;

&lt;p&gt;It limits the places where side effects occur.&lt;/p&gt;

&lt;p&gt;It makes error cases and degraded cases explicit.&lt;/p&gt;

&lt;p&gt;It accepts that failure is part of the system’s normal behavior.&lt;/p&gt;

&lt;p&gt;Robustness is therefore not an extra layer you add afterward with a few &lt;code&gt;try/catch&lt;/code&gt; blocks. It is a way of designing software from the outset.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observable, because in production we never see everything in advance
&lt;/h2&gt;

&lt;p&gt;Even a well-designed system will encounter cases in production that nobody had fully anticipated.&lt;/p&gt;

&lt;p&gt;That is inevitable.&lt;/p&gt;

&lt;p&gt;The question, then, is not whether errors will occur. The question is whether, when they do occur, the system will give us the means to understand what happened.&lt;/p&gt;

&lt;p&gt;Observable code produces useful traces. It makes important transitions, significant failures, useful contexts, external interactions, abnormal delays, and relevant business states visible.&lt;/p&gt;

&lt;p&gt;It does not merely fail. It fails while leaving usable clues behind.&lt;/p&gt;

&lt;p&gt;Observability is not a secondary concern reserved for operations or infrastructure. It is a software design concern. A poorly structured system is hard to observe because it already struggles to describe what it is doing. A well-structured system, by contrast, naturally makes it possible to attach traces to boundaries, contracts, validations, state transitions, and domain errors.&lt;/p&gt;

&lt;p&gt;Observing a system is not a matter of adding lamps to an obscure machine. It is a matter of building a machine whose mechanisms can be inspected.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes code robust
&lt;/h2&gt;

&lt;p&gt;Once we accept that robustness is the real criterion, another family of concepts becomes central.&lt;/p&gt;

&lt;p&gt;No longer the concepts of style, but the concepts of system.&lt;/p&gt;

&lt;p&gt;And these concepts do not simply sit side by side. They follow one another.&lt;/p&gt;

&lt;p&gt;This sequence is an order of exposition, not a strict order of construction. In practice, these dimensions respond to one another, correct one another, and are co-constructed. But to think about them clearly, it is useful to unfold them this way.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Boundaries
&lt;/h2&gt;

&lt;p&gt;Everything begins with &lt;strong&gt;boundaries&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A robust system must know where it begins, where it ends, and where its zones of uncertainty lie.&lt;/p&gt;

&lt;p&gt;Boundaries separate, for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  the internal from the external;&lt;/li&gt;
&lt;li&gt;  the domain from the infrastructure;&lt;/li&gt;
&lt;li&gt;  pure logic from side effects;&lt;/li&gt;
&lt;li&gt;  trusted data from data that is still suspect.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without boundaries, everything communicates with everything else. Responsibilities blur, causes spread, and errors become hard to localize.&lt;/p&gt;

&lt;p&gt;Boundaries are therefore not just there to “organize code well.” They are there to contain uncertainty.&lt;/p&gt;

&lt;p&gt;A contemporary example: in web applications, some frameworks make client/server interactions feel very fluid. Next.js Server Actions, for example, do not force us to blur boundaries: they can perfectly well be defined separately, with the split clearly marked. But the framework makes possible, through a simple directive, a very practical form of colocation between frontend code and the server action. That local comfort can create an impression of elegance. And yet the boundary has not disappeared: it has merely become less visible. Behind that apparent simplicity lies a whole real mechanism: server functions callable over the network, authentication and authorization checks that must be performed again inside the action itself, captured variables sent out and then sent back, encrypted, and tied to a given build. The framework takes part of that on itself, but this abstraction does not remove the complexity: it shifts it and partially masks it. The problem is not the tool. The problem is how easily local comfort can make us forget the boundary, its requirements, and the operational burden that still exists behind it.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Contracts
&lt;/h2&gt;

&lt;p&gt;As soon as a boundary exists, we need to define what is allowed to cross it.&lt;/p&gt;

&lt;p&gt;That is the role of &lt;strong&gt;contracts&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A contract states what is expected, what is guaranteed, and under what conditions. It can take several forms: a type, an interface, a schema, a protocol, an explicit convention. The exact form does not matter. What matters is that it reduces ambiguity.&lt;/p&gt;

&lt;p&gt;The logic is simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;boundary → contract&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We do not let just anything circulate between two zones of the system.&lt;/p&gt;

&lt;p&gt;A system without contracts rests on assumptions. And assumptions fail silently.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Validation
&lt;/h2&gt;

&lt;p&gt;A contract that is never checked remains wishful thinking.&lt;/p&gt;

&lt;p&gt;That is why &lt;strong&gt;contracts&lt;/strong&gt; call for &lt;strong&gt;validation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As soon as data crosses a boundary, it must be validated. This applies to user input, an environment variable, an API response, an imported file, a message consumed from a queue, a network payload.&lt;/p&gt;

&lt;p&gt;To validate is to refuse to pretend that every input is legitimate.&lt;/p&gt;

&lt;p&gt;A robust system does not trust too early. It validates at the boundaries. It turns the unknown into the known.&lt;/p&gt;

&lt;p&gt;That is especially true when we consume an external system. The mere fact that it advertises a contract never removes the need to verify what actually comes in. An API may drift, be incorrectly implemented, or occasionally violate its own promise. Without validation at the point of entry, we let data into the system that is treated as true even though it is not.&lt;/p&gt;

&lt;p&gt;The chain then becomes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;boundaries → contracts → validation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And that chain is essential, because it prevents uncertainty from the outside world from silently contaminating the core of the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Invariants
&lt;/h2&gt;

&lt;p&gt;Once inputs have been framed and validated, the system can begin to protect its internal truths.&lt;/p&gt;

&lt;p&gt;That is the role of &lt;strong&gt;invariants&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;An invariant is something that must remain true.&lt;/p&gt;

&lt;p&gt;For example: a paid order does not become pending again; an authenticated user always has a valid identifier; an object in a given state cannot trigger a given transition; data marked as validated actually conforms to the expected schema.&lt;/p&gt;

&lt;p&gt;Invariants give the system anchor points. They reduce the space of possibilities. And reducing the space of possibilities is what makes the system more intelligible and safer.&lt;/p&gt;

&lt;p&gt;An invariant is not merely an abstract truth; it is also something that must be protected against the system’s real behavior. If a payment webhook is replayed, for example, the system should not behave as if a brand-new event had arrived. Without idempotency guardrails, the same signal can produce multiple effects and make the state drift instead of stabilizing it.&lt;/p&gt;

&lt;p&gt;We can put it like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;validation protects invariants&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Explicit states
&lt;/h2&gt;

&lt;p&gt;As soon as a system depends on time, stages, permissions, sequences, events, transitions, or temporality, its &lt;strong&gt;state&lt;/strong&gt; must be made explicit.&lt;/p&gt;

&lt;p&gt;As soon as a resource exists over time, it also has a &lt;strong&gt;lifecycle&lt;/strong&gt;. Thinking about that lifecycle explicitly means refusing to let it be scattered across a multitude of local, implicit, or contradictory conditions.&lt;/p&gt;

&lt;p&gt;And in practice, making state explicit means modeling it.&lt;/p&gt;

&lt;p&gt;We then mobilize conceptual tools such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;state machines&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;statecharts&lt;/strong&gt;, when we need to add hierarchy, parallelism, or communication.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why are they useful? Because they force us to name the possible states, define the allowed transitions, make triggering events explicit, and limit illegal moves.&lt;/p&gt;

&lt;p&gt;They replace diffuse logic with a declared structure.&lt;/p&gt;

&lt;p&gt;The progression then becomes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;invariants → explicit states → allowed transitions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And that is often where a system really begins to hold together. Not because it becomes more “intelligent,” but because it becomes less blurry.&lt;/p&gt;

&lt;p&gt;Take an audio or video recording system. Before anything even starts, the user can choose a camera, a microphone, a background, check a preview. Then they start recording, can pause, resume, turn the camera off, change certain settings, while in the background the system creates a server-side trace, listens to devices, and uploads segments. At the end, they can delete or save. Without explicit states, all of this quickly gets scattered across local conditions and contradictory flags. With a state machine, we name the phases, constrain the transitions, and finally make coherent what the user sees, what the system does, and what the server receives.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Responsibility and authority
&lt;/h2&gt;

&lt;p&gt;Once states have been made explicit, another question becomes unavoidable: &lt;strong&gt;who&lt;/strong&gt; is allowed to act on what, at what moment, and with what responsibilities?&lt;/p&gt;

&lt;p&gt;Here, the question becomes one of &lt;strong&gt;responsibility&lt;/strong&gt; and &lt;strong&gt;authority&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A system becomes blurry when multiple parties can create, modify, transition, or destroy the same resource without a clear rule. By contrast, a robust system knows who owns what in the operational sense: who is responsible for a piece of data, a process, a resource, a transition, a cleanup, a closure.&lt;/p&gt;

&lt;p&gt;Lifecycle tells us in which states something may exist over time. Responsibility and authority tell us who may act on that thing, when, and under what conditions.&lt;/p&gt;

&lt;p&gt;This point is essential, because an explicit state without explicit authority still leaves room for drift. We then know what may happen, but not who is legitimate to make it happen.&lt;/p&gt;

&lt;p&gt;The progression is therefore enriched as follows:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;explicit states → responsibility and authority → controlled transitions&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Deterministic transformations
&lt;/h2&gt;

&lt;p&gt;Once boundaries are in place, contracts defined, validations in place, invariants protected, and states made explicit, another question becomes central: how do we make the system’s local behavior as readable and predictable as possible?&lt;/p&gt;

&lt;p&gt;That is the point at which the question of &lt;strong&gt;deterministic transformations&lt;/strong&gt; arises.&lt;/p&gt;

&lt;p&gt;Whenever possible, we want transformations whose behavior is stable, understandable, and testable. We want, as much as possible, pure functions, immutability, composition, and isolated side effects.&lt;/p&gt;

&lt;p&gt;Not out of doctrinal taste, nor to signal allegiance to a school, but because this makes the core of the system more robust.&lt;/p&gt;

&lt;p&gt;Ideas from functional programming are valuable here. They do not replace boundaries, contracts, invariants, or explicit states. They simply make internal behavior more predictable.&lt;/p&gt;

&lt;p&gt;A pure function does not, by itself, constitute a system invariant. It does, however, provide a local unit of predictability. Same input, same output, no hidden side effects. And those local units of predictability are extremely valuable when one wants to build a whole that is readable, testable, and reliable.&lt;/p&gt;

&lt;p&gt;In practice: at the boundaries, we validate; in the core of the system, we seek purity as much as possible; as soon as time, permissions, or transitions matter, we make state explicit.&lt;/p&gt;

&lt;p&gt;That search for local determinism does not replace system thinking. It complements it.&lt;/p&gt;

&lt;p&gt;And it naturally prepares the next step: proof.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. Proof
&lt;/h2&gt;

&lt;p&gt;Once boundaries are in place, contracts defined, validations in place, invariants protected, and states made explicit, one question remains: what still depends solely on human discipline?&lt;/p&gt;

&lt;p&gt;The question of &lt;strong&gt;proof&lt;/strong&gt; then appears.&lt;/p&gt;

&lt;p&gt;In software, proof is not always formal in the mathematical sense. But there are several degrees of proof:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  types;&lt;/li&gt;
&lt;li&gt;  schemas;&lt;/li&gt;
&lt;li&gt;  tests;&lt;/li&gt;
&lt;li&gt;  exhaustiveness;&lt;/li&gt;
&lt;li&gt;  compile-time constraints;&lt;/li&gt;
&lt;li&gt;  the structural impossibility of certain states or certain transitions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The central idea is simple: everything that can be guaranteed structurally should not rest solely on habit, caution, or a team’s memory.&lt;/p&gt;

&lt;p&gt;We can summarize it this way:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;contracts + invariants + explicit states → forms of proof&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The more a system replaces implicit discipline with explicit guarantees, the more robust it becomes.&lt;/p&gt;

&lt;p&gt;An important nuance must be added, however: proof here is not limited to the most common and accessible forms of structural guarantee. In some contexts, it can go as far as &lt;strong&gt;formal verification&lt;/strong&gt;, using languages, proof assistants, and methods capable of demonstrating that a program satisfies certain specifications. This path remains demanding and uncommon in day-to-day development, but its existence reminds us that “proof” is not merely a convenient metaphor. In some cases, it can become a real technical objective.&lt;/p&gt;

&lt;p&gt;We can also see this in more ordinary forms of proof. Between a state stored as a simple string and an exhaustive type that forces the compiler to handle every case, the difference is clear: in one case, we hope; in the other, we make certain omissions structurally impossible.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Observability, as the extension of the system into the real world
&lt;/h2&gt;

&lt;p&gt;And finally, everything that has been structured conceptually must be made visible when it is actually running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observability&lt;/strong&gt; returns here, no longer as a simple general criterion, but as the concrete extension of the system’s entire architecture.&lt;/p&gt;

&lt;p&gt;A well-structured system makes it possible to observe:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  what enters through its boundaries;&lt;/li&gt;
&lt;li&gt;  what is accepted or rejected by validation;&lt;/li&gt;
&lt;li&gt;  which contracts were violated;&lt;/li&gt;
&lt;li&gt;  which invariants were protected or threatened;&lt;/li&gt;
&lt;li&gt;  what state it is in;&lt;/li&gt;
&lt;li&gt;  which transition took place;&lt;/li&gt;
&lt;li&gt;  which external interaction failed;&lt;/li&gt;
&lt;li&gt;  which abnormal delays or behaviors were encountered.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Observability is not something added at the end like technical decoration. It is attached to the very structure of the system.&lt;/p&gt;

&lt;p&gt;The full logic then becomes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;boundaries → contracts → validation → invariants → explicit states → responsibility and authority → deterministic transformations → proof → observability&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At that point, we are no longer talking merely about organized code. We are talking about a system that can be understood, constrained, evolved, and inspected.&lt;/p&gt;

&lt;p&gt;The difference becomes obvious very quickly in production. A log that only says “500 error” signals a problem, but rarely helps us understand it. A log or trace carrying a correlation ID, the current business state, the attempted transition, and the rejected input is already telling part of the system’s story. Useful observability is not about producing more noise, but about making the system’s behavior intelligible when it deviates.&lt;/p&gt;

&lt;h2&gt;
  
  
  In the age of intelligences, blur becomes more costly
&lt;/h2&gt;

&lt;p&gt;In the age of intelligences, system thinking becomes even more important. The issue is not merely that agents produce code. The issue is that this code must be able to circulate between several forms of intelligence: human and artificial today; often intertwined tomorrow. We do not merely want a machine to write code. We want it to write a system that a human can reread, understand, critique, and validate. And conversely, we want humans to produce structures that machines can follow without guessing.&lt;/p&gt;

&lt;p&gt;When several humans and several agents intervene in the same code, the absence of boundaries, contracts, invariants, explicit states, and clear authorities opens the way to every kind of drift: drift of meaning, drift of architecture, drift of behavior. The code may continue to function, but it gradually stops forming a system. Conversely, a well-structured system does not merely make maintenance easier: it contains distortions, makes deviations visible, and allows transformation to remain controlled.&lt;/p&gt;

&lt;p&gt;For a long time, a small team could compensate for blurry code through familiarity. Someone knew “how it really works.” An implicit, collective, more or less artisanal understanding made it possible to patch over the gaps.&lt;/p&gt;

&lt;p&gt;That era is eroding.&lt;/p&gt;

&lt;p&gt;Today, code circulates between more actors: developers, reviewers, newcomers, analysis tools, pipelines, assistants, agents. Every zone of ambiguity becomes a multiplied cost. Every implicit convention becomes heavier debt. Every porous boundary, every missing contract, every poorly modeled state reduces the ability of a human or an agent to intervene safely.&lt;/p&gt;

&lt;p&gt;There is another important shift as well. For a long time, some forms of modeling seemed too costly to write, maintain, or even justify. We settled instead for more implicit, lighter, sometimes blurrier forms. With the productivity gains brought by intelligences, that trade-off changes. Implementation cost drops in many cases. What becomes more costly instead is understanding, validation, testability, and control of drift. As a result, more explicit structures — which might have seemed too heavy yesterday — become good investments instead, because they make the system more readable, more controllable, and more transmissible.&lt;/p&gt;

&lt;p&gt;Such code is easier to take over, audit, instrument, and transform, not because it is “prettier,” but because it exposes its logic and reduces the amount of guesswork.&lt;/p&gt;

&lt;p&gt;And this is perhaps one of the great shifts of our time: blurry code is no longer merely difficult to maintain. It is also much harder to evolve properly with intelligences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Code is not elegant prose. It is a system, to be judged by its robustness.&lt;/p&gt;

&lt;p&gt;And robustness here is not a vague word. It refers to something precise: code that is intelligible, resilient, and observable.&lt;/p&gt;

&lt;p&gt;To get there, we need to think less in terms of style and more in terms of structure: make the system more explicit, set boundaries, define contracts, validate at points of contact, protect invariants, make states explicit, clarify responsibilities and authorities, build forms of proof, and attach observability to the architecture itself.&lt;/p&gt;

&lt;p&gt;If we still want to speak of elegance, then we need to shift our gaze. What deserves admiration is not code that impresses. It is code that forms a system.&lt;/p&gt;

&lt;p&gt;Elegance is a vocabulary of the surface. Robustness is a vocabulary of the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  David Parnas — on modularity and boundaries&lt;/li&gt;
&lt;li&gt;  Bertrand Meyer — &lt;em&gt;Design by Contract&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;  David Harel — on statecharts&lt;/li&gt;
&lt;li&gt;  Eric Evans — &lt;em&gt;Domain-Driven Design&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;  John Hughes and Philip Wadler — on the functional tradition&lt;/li&gt;
&lt;li&gt;  Charity Majors, Liz Fong-Jones, George Miranda — on modern observability&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>architecture</category>
      <category>softwaredesign</category>
      <category>ai</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
