<?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: Ricardo Medeiros</title>
    <description>The latest articles on DEV Community by Ricardo Medeiros (@jjackbauer).</description>
    <link>https://dev.to/jjackbauer</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F757631%2F76940fdf-9f04-4bd8-9217-d577d788ffef.jpeg</url>
      <title>DEV Community: Ricardo Medeiros</title>
      <link>https://dev.to/jjackbauer</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jjackbauer"/>
    <language>en</language>
    <item>
      <title>2.1 Billion Tokens for $19: DeepSeek V4.1 Flash Changed the Economics of Agentic Software Engineering</title>
      <dc:creator>Ricardo Medeiros</dc:creator>
      <pubDate>Mon, 14 Sep 2026 10:14:11 +0000</pubDate>
      <link>https://dev.to/jjackbauer/21-billion-tokens-for-19-deepseek-v41-flash-changed-the-economics-of-agentic-software-3pbb</link>
      <guid>https://dev.to/jjackbauer/21-billion-tokens-for-19-deepseek-v41-flash-changed-the-economics-of-agentic-software-3pbb</guid>
      <description>&lt;p&gt;A week ago I published a fairly absurd number:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;612.9 million tokens for $28.35.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That was DeepSeek Harness (DSH) + DeepSeek V4 Pro working on LovelaceSharp, a real C# numerical computing project, over a visible four-day development window.&lt;/p&gt;

&lt;p&gt;The repository received 45 commits across 193 files.&lt;/p&gt;

&lt;p&gt;The point of that article was not that 612 million tokens are somehow inherently productive.&lt;/p&gt;

&lt;p&gt;It was that the economics of a persistent coding agent look very different from the economics suggested by raw token counts.&lt;/p&gt;

&lt;p&gt;DSH had a &lt;strong&gt;98.94% input cache-hit rate&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It was processing enormous amounts of context, but very little of that context was novel expensive input.&lt;/p&gt;

&lt;p&gt;Then I kept running the experiment.&lt;/p&gt;

&lt;p&gt;And DeepSeek released V4.1 Flash.&lt;/p&gt;

&lt;p&gt;The numbers got considerably more stupid.&lt;/p&gt;

&lt;p&gt;From September 10 through September 12, my actual provider export for &lt;code&gt;deepseek-flash&lt;/code&gt; shows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;V4.1 Flash&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;API requests&lt;/td&gt;
&lt;td&gt;12,253&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache-hit input&lt;/td&gt;
&lt;td&gt;2,123,399,808&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache-miss input&lt;/td&gt;
&lt;td&gt;14,976,005&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;16,114,788&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total tokens&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2,154,490,601&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input cache-hit rate&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;99.30%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API cost&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$19.22&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blended cost / 1M processed tokens&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0.00892&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Yes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.15 billion tokens. Nineteen dollars.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And before anyone starts typing "tokens are not productivity" again:&lt;/p&gt;

&lt;p&gt;I agree.&lt;/p&gt;

&lt;p&gt;So let's look at what happened to the software.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the Previous Article Stopped
&lt;/h2&gt;

&lt;p&gt;The previous benchmark ended around September 5.&lt;/p&gt;

&lt;p&gt;At that point LovelaceSharp already had arbitrary-precision arithmetic, optimized big-integer algorithms, typed N-dimensional arrays, DSP, a scripting language, a browser IDE, Native AOT support, benchmarks and a Lean reference formalization.&lt;/p&gt;

&lt;p&gt;The project was already well beyond a toy.&lt;/p&gt;

&lt;p&gt;But most of the work was still fundamentally numerical infrastructure.&lt;/p&gt;

&lt;p&gt;What happened afterward was a much larger expansion of scope.&lt;/p&gt;

&lt;p&gt;From the last September 5 commit to the current HEAD, the repository moved forward by:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;166 commits.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;During that period LovelaceSharp acquired an actual symbolic mathematics stack.&lt;/p&gt;

&lt;p&gt;Not a SymPy wrapper.&lt;/p&gt;

&lt;p&gt;A native one.&lt;/p&gt;

&lt;p&gt;The work included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;immutable hash-consed symbolic expression DAGs;&lt;/li&gt;
&lt;li&gt;canonical addition, multiplication and powers;&lt;/li&gt;
&lt;li&gt;exact rational arithmetic;&lt;/li&gt;
&lt;li&gt;assumptions with three-valued logic;&lt;/li&gt;
&lt;li&gt;conditional rewriting with explicit side conditions;&lt;/li&gt;
&lt;li&gt;symbolic differentiation;&lt;/li&gt;
&lt;li&gt;limits and series, including Laurent behavior;&lt;/li&gt;
&lt;li&gt;symbolic integration;&lt;/li&gt;
&lt;li&gt;polynomial arithmetic;&lt;/li&gt;
&lt;li&gt;factoring and square-free decomposition;&lt;/li&gt;
&lt;li&gt;real-root isolation;&lt;/li&gt;
&lt;li&gt;equation solving;&lt;/li&gt;
&lt;li&gt;parametric solution families;&lt;/li&gt;
&lt;li&gt;Gröbner bases;&lt;/li&gt;
&lt;li&gt;polynomial-system solving;&lt;/li&gt;
&lt;li&gt;symbolic matrices;&lt;/li&gt;
&lt;li&gt;conditional matrix inversion and linear solving;&lt;/li&gt;
&lt;li&gt;CSE and Horner optimization;&lt;/li&gt;
&lt;li&gt;complex symbolic/numeric evaluation;&lt;/li&gt;
&lt;li&gt;a typed computational IR called MathIR;&lt;/li&gt;
&lt;li&gt;scalar and vectorized compiled evaluation;&lt;/li&gt;
&lt;li&gt;structured result types instead of prose results;&lt;/li&gt;
&lt;li&gt;symbolic inspection in Studio;&lt;/li&gt;
&lt;li&gt;an agent-facing structured execution protocol;&lt;/li&gt;
&lt;li&gt;differential comparison against SymPy;&lt;/li&gt;
&lt;li&gt;and a significantly larger correctness infrastructure around all of it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the part I think matters when discussing agent economics.&lt;/p&gt;

&lt;p&gt;The $19 did not buy "2.1 billion tokens."&lt;/p&gt;

&lt;p&gt;Tokens are an implementation detail.&lt;/p&gt;

&lt;p&gt;It bought access to a software production process that could keep expanding the product while simultaneously expanding the machinery used to verify the product.&lt;/p&gt;

&lt;p&gt;That distinction is important.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features Without Tests Are a Terrible Agent Benchmark
&lt;/h2&gt;

&lt;p&gt;One of the easiest ways to make an AI coding demo look impressive is to count features.&lt;/p&gt;

&lt;p&gt;LLMs are very good at producing code.&lt;/p&gt;

&lt;p&gt;If I ask an agent to maximize visible feature count, it will happily oblige.&lt;/p&gt;

&lt;p&gt;That does not mean I have created valuable software.&lt;/p&gt;

&lt;p&gt;So I care much more about the relationship between feature growth and validation growth.&lt;/p&gt;

&lt;p&gt;When the first symbolic kernel landed on September 8, it already came with &lt;strong&gt;100 Symbolics tests&lt;/strong&gt; plus executable documentation examples.&lt;/p&gt;

&lt;p&gt;Then the API expanded.&lt;/p&gt;

&lt;p&gt;Relations, solution families, polynomials, matrices, compilation and Gröbner bases landed.&lt;/p&gt;

&lt;p&gt;The Symbolics suite moved past 200 tests.&lt;/p&gt;

&lt;p&gt;Then came structured APIs, assumption hardening, semantic fixes, solver work, differential oracles, property tests, metamorphic tests, protocol tests and adversarial cases.&lt;/p&gt;

&lt;p&gt;By September 10, one of the convergence commits reported:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1,971 passing tests across 14 suites.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The project kept going.&lt;/p&gt;

&lt;p&gt;The most recent full local validation recorded:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5,655 passed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;0 failed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;0 skipped.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a much more interesting development curve than simply saying "the agent added a CAS."&lt;/p&gt;

&lt;p&gt;The product surface grew, but the test surface grew with it.&lt;/p&gt;

&lt;p&gt;And the tests are not all repetitions of ordinary unit assertions either.&lt;/p&gt;

&lt;p&gt;The repository now contains things such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;property tests
differential tests
metamorphic tests
golden protocol fixtures
cross-surface consistency tests
precision-boundary tests
Native AOT smoke tests
SymPy oracle comparisons
pre-fix regression controls
determinism tests
concurrency/isolation tests
budget/cancellation tests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That changes how I think about the cost of software development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Used to Compete Economically With Features
&lt;/h2&gt;

&lt;p&gt;There is an uncomfortable reality in normal software development.&lt;/p&gt;

&lt;p&gt;Every hour spent writing tests is an hour someone is not spending implementing the next feature.&lt;/p&gt;

&lt;p&gt;Every alternative architecture you prototype and discard costs engineering time.&lt;/p&gt;

&lt;p&gt;Every benchmark takes time to construct.&lt;/p&gt;

&lt;p&gt;Every edge-case corpus has to be written.&lt;/p&gt;

&lt;p&gt;Every independent implementation used as an oracle costs more time.&lt;/p&gt;

&lt;p&gt;Every documentation example that is kept executable costs more time.&lt;/p&gt;

&lt;p&gt;Every time you say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;let's test another 50 weird cases before shipping this&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;you are spending part of a finite engineering budget.&lt;/p&gt;

&lt;p&gt;That doesn't mean those things aren't worth doing.&lt;/p&gt;

&lt;p&gt;It means they have a real opportunity cost.&lt;/p&gt;

&lt;p&gt;Agentic engineering changes this equation.&lt;/p&gt;

&lt;p&gt;Suppose a feature takes an agent another 30 million tokens to implement, test, benchmark, revise and document.&lt;/p&gt;

&lt;p&gt;At the effective blended price I observed with V4.1 Flash, 30 million processed tokens would cost roughly:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;$0.27.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Obviously token cost is not the only cost.&lt;/p&gt;

&lt;p&gt;There is compute outside the model.&lt;/p&gt;

&lt;p&gt;There is CI.&lt;/p&gt;

&lt;p&gt;There is human review.&lt;/p&gt;

&lt;p&gt;There is specification.&lt;/p&gt;

&lt;p&gt;There is the cost of accepting a bad implementation.&lt;/p&gt;

&lt;p&gt;But the inference component has become almost comically small.&lt;/p&gt;

&lt;p&gt;So the economically rational behavior changes.&lt;/p&gt;

&lt;p&gt;Instead of asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do we have time to build a differential oracle for this?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;the answer increasingly becomes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why wouldn't we?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is a much bigger change than cheaper autocomplete.&lt;/p&gt;

&lt;h2&gt;
  
  
  V4.1 Flash Changed the Curve Again
&lt;/h2&gt;

&lt;p&gt;The previous article already showed strange economics with V4 Pro.&lt;/p&gt;

&lt;p&gt;After publishing it, I have a useful second window.&lt;/p&gt;

&lt;p&gt;From September 5 through September 9, the new export contains this V4 Pro usage:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;V4 Pro&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Requests&lt;/td&gt;
&lt;td&gt;2,026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache-hit input&lt;/td&gt;
&lt;td&gt;588,642,048&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache-miss input&lt;/td&gt;
&lt;td&gt;3,595,338&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;2,847,970&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total tokens&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;595,085,356&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input cache-hit rate&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;99.39%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$20.96&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blended cost / 1M tokens&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0.0352&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Then V4.1 Flash:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;V4 Pro&lt;/th&gt;
&lt;th&gt;V4.1 Flash&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Total tokens&lt;/td&gt;
&lt;td&gt;595.1M&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.154B&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Requests&lt;/td&gt;
&lt;td&gt;2,026&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;12,253&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache-hit rate&lt;/td&gt;
&lt;td&gt;99.39%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;99.30%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;$20.96&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$19.22&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost / 1M processed tokens&lt;/td&gt;
&lt;td&gt;$0.0352&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0.00892&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The workloads are not identical, so this is &lt;strong&gt;not a controlled intelligence benchmark&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I cannot conclude:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;V4.1 Flash is 3.62× more productive than V4 Pro.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That would be nonsense.&lt;/p&gt;

&lt;p&gt;What I can measure is the economic side.&lt;/p&gt;

&lt;p&gt;Flash processed &lt;strong&gt;3.62× more tokens&lt;/strong&gt; for &lt;strong&gt;8.3% less total money&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Its effective blended cost per processed token in this workload was approximately:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.95× lower.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And the cache behavior barely changed.&lt;/p&gt;

&lt;p&gt;V4 Pro: &lt;strong&gt;99.39%&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;V4.1 Flash: &lt;strong&gt;99.30%&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So this isn't a story about DSH suddenly discovering caching.&lt;/p&gt;

&lt;p&gt;It was already doing that.&lt;/p&gt;

&lt;p&gt;The underlying inference economics changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  One Billion Tokens in a Day Is Now Boringly Affordable
&lt;/h2&gt;

&lt;p&gt;September 11 is the funniest row in the export.&lt;/p&gt;

&lt;p&gt;That single day:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;September 11&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Requests&lt;/td&gt;
&lt;td&gt;6,463&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache-hit input&lt;/td&gt;
&lt;td&gt;1,002,941,952&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache-miss input&lt;/td&gt;
&lt;td&gt;7,388,973&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;8,712,583&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Total tokens&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1,019,043,508&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$9.81&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One billion tokens.&lt;/p&gt;

&lt;p&gt;One day.&lt;/p&gt;

&lt;p&gt;Less than ten dollars.&lt;/p&gt;

&lt;p&gt;I don't think "billions of tokens" should become a goal.&lt;/p&gt;

&lt;p&gt;If anything, that would be another terrible optimization target.&lt;/p&gt;

&lt;p&gt;But it tells us something about capacity.&lt;/p&gt;

&lt;p&gt;During the original benchmark, 612.9 million tokens over four days felt large enough to deserve an article.&lt;/p&gt;

&lt;p&gt;V4.1 Flash processed around &lt;strong&gt;1.66× that entire benchmark's token volume in one day&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For roughly one third of its inference cost.&lt;/p&gt;

&lt;p&gt;This means the number of agent iterations you can economically throw at a software problem has changed dramatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  This Is Where Software Engineering Economics Get Weird
&lt;/h2&gt;

&lt;p&gt;Traditional software economics are dominated by expensive human time.&lt;/p&gt;

&lt;p&gt;Imagine a feature requiring:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;architecture
implementation
unit tests
integration tests
benchmarking
documentation
review
bug fixing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those are competing allocations of engineering hours.&lt;/p&gt;

&lt;p&gt;Now consider the same work under an agentic harness.&lt;/p&gt;

&lt;p&gt;An implementation agent can write the feature.&lt;/p&gt;

&lt;p&gt;Another execution can build the tests.&lt;/p&gt;

&lt;p&gt;Another can benchmark competing implementations.&lt;/p&gt;

&lt;p&gt;Another can compare results against an external oracle.&lt;/p&gt;

&lt;p&gt;Another can examine the public API.&lt;/p&gt;

&lt;p&gt;Another can search for boundary cases.&lt;/p&gt;

&lt;p&gt;The original agent can then revise the implementation.&lt;/p&gt;

&lt;p&gt;The harness retains the work that happened before.&lt;/p&gt;

&lt;p&gt;And because the context is highly reusable, most of those repeated passes are being served as cache hits.&lt;/p&gt;

&lt;p&gt;In my V4.1 Flash window, the API processed more than:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.12 billion cached input tokens.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Against only:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;14.98 million cache-miss input tokens.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is the economic mechanism.&lt;/p&gt;

&lt;p&gt;The agent doesn't have to repeatedly forget the repository in order to be cheap.&lt;/p&gt;

&lt;p&gt;It can accumulate architecture, requirements, test results, previous failures and implementation decisions as reusable context.&lt;/p&gt;

&lt;p&gt;Then revisit that context extremely cheaply.&lt;/p&gt;

&lt;p&gt;This is almost the inverse of how we traditionally think about context efficiency.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Marginal Cost of Engineering Work Is Collapsing Unevenly
&lt;/h2&gt;

&lt;p&gt;This doesn't mean software development becomes free.&lt;/p&gt;

&lt;p&gt;It means different parts of software development are becoming cheap at radically different rates.&lt;/p&gt;

&lt;p&gt;Code generation is becoming cheap.&lt;/p&gt;

&lt;p&gt;Test generation is becoming cheap.&lt;/p&gt;

&lt;p&gt;Repository exploration is becoming cheap.&lt;/p&gt;

&lt;p&gt;Documentation is becoming cheap.&lt;/p&gt;

&lt;p&gt;Trying a second implementation is becoming cheap.&lt;/p&gt;

&lt;p&gt;Throwing away a failed implementation is becoming cheap.&lt;/p&gt;

&lt;p&gt;Running another agent over the same repository looking for problems is becoming cheap.&lt;/p&gt;

&lt;p&gt;The human parts aren't falling at the same rate.&lt;/p&gt;

&lt;p&gt;Understanding what the product should do is still expensive.&lt;/p&gt;

&lt;p&gt;Making architectural decisions is still valuable.&lt;/p&gt;

&lt;p&gt;Recognizing when a requirement itself is wrong still matters.&lt;/p&gt;

&lt;p&gt;Reviewing the highest-risk assumptions still matters.&lt;/p&gt;

&lt;p&gt;Taking responsibility for what ships still matters.&lt;/p&gt;

&lt;p&gt;But this changes what human engineering time should be spent on.&lt;/p&gt;

&lt;p&gt;I don't need to spend my time manually typing every test case.&lt;/p&gt;

&lt;p&gt;I need to decide which properties actually matter.&lt;/p&gt;

&lt;p&gt;I don't need to manually implement three algorithms just to compare them.&lt;/p&gt;

&lt;p&gt;I need to understand whether the benchmark used to select between them means anything.&lt;/p&gt;

&lt;p&gt;I don't need to manually write 100 edge cases.&lt;/p&gt;

&lt;p&gt;I need to notice the class of edge case the agent forgot to generate.&lt;/p&gt;

&lt;p&gt;That is a different allocation of engineering labor.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Feature/Test Ratio Can Move in the Right Direction
&lt;/h2&gt;

&lt;p&gt;There is a common fear around AI-generated code that I think is completely justified:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If generating code becomes 10× easier, won't we just create technical garbage 10× faster?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Yes.&lt;/p&gt;

&lt;p&gt;If the only thing we make cheaper is feature generation.&lt;/p&gt;

&lt;p&gt;But inference does not know that production code is special.&lt;/p&gt;

&lt;p&gt;The same cheap intelligence that generates a feature can generate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tests for it;&lt;/li&gt;
&lt;li&gt;property checks;&lt;/li&gt;
&lt;li&gt;fixtures;&lt;/li&gt;
&lt;li&gt;benchmark harnesses;&lt;/li&gt;
&lt;li&gt;differential comparisons;&lt;/li&gt;
&lt;li&gt;migration tools;&lt;/li&gt;
&lt;li&gt;documentation;&lt;/li&gt;
&lt;li&gt;fuzz inputs;&lt;/li&gt;
&lt;li&gt;failure reproductions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where I think agentic SWE becomes much more interesting than "developer autocomplete."&lt;/p&gt;

&lt;p&gt;The economically optimal feature can start carrying much more validation around it.&lt;/p&gt;

&lt;p&gt;The first LovelaceSharp symbolic implementation didn't just add symbolic differentiation.&lt;/p&gt;

&lt;p&gt;It added tests.&lt;/p&gt;

&lt;p&gt;When Gröbner bases arrived, they came with invariant tests.&lt;/p&gt;

&lt;p&gt;When MathIR gained vectorized execution, scalar-vs-batch equivalence was tested.&lt;/p&gt;

&lt;p&gt;When arbitrary precision behavior expanded, results were compared against mpmath and SymPy.&lt;/p&gt;

&lt;p&gt;When the runner became a machine interface rather than only a human CLI, its structured envelopes acquired their own contract tests.&lt;/p&gt;

&lt;p&gt;When correctness bugs were found, regression cases were added.&lt;/p&gt;

&lt;p&gt;The point is not that 5,655 tests prove LovelaceSharp is correct.&lt;/p&gt;

&lt;p&gt;They don't.&lt;/p&gt;

&lt;p&gt;The point is that &lt;strong&gt;test production is scaling with feature production instead of being economically squeezed out by it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is exactly what I want from agentic development.&lt;/p&gt;

&lt;h2&gt;
  
  
  The $40 Continuation Window
&lt;/h2&gt;

&lt;p&gt;There is another way to look at the whole period after my previous article.&lt;/p&gt;

&lt;p&gt;From September 5 through September 12, the provider export contains:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.759 billion processed tokens.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;14,304 requests.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;$40.44 total cost.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;During the corresponding repository continuation, LovelaceSharp moved &lt;strong&gt;166 commits&lt;/strong&gt; beyond the September 5 boundary.&lt;/p&gt;

&lt;p&gt;I don't think cost-per-commit is a serious productivity metric.&lt;/p&gt;

&lt;p&gt;Commits are arbitrary.&lt;/p&gt;

&lt;p&gt;An agent can trivially game that number by creating smaller commits.&lt;/p&gt;

&lt;p&gt;But just to establish the scale, if I pessimistically charge &lt;strong&gt;every dollar in that provider window&lt;/strong&gt; to LovelaceSharp, including usage that may not belong to it, that comes to:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;about $0.24 of inference per commit.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Again:&lt;/p&gt;

&lt;p&gt;That does not mean a software commit is "worth 24 cents."&lt;/p&gt;

&lt;p&gt;It means inference has become such a small component of the economic equation that counting dollars per patch starts becoming almost silly.&lt;/p&gt;

&lt;p&gt;The expensive question is whether the patches form useful software.&lt;/p&gt;

&lt;h2&gt;
  
  
  This Also Changes the Value of Failed Work
&lt;/h2&gt;

&lt;p&gt;One of my favorite observations from the original benchmark was Newton division.&lt;/p&gt;

&lt;p&gt;DSH implemented it because asymptotically it should beat Knuth division.&lt;/p&gt;

&lt;p&gt;Then it benchmarked the result.&lt;/p&gt;

&lt;p&gt;And discovered that the crossover was so far out that Knuth should remain the normal production path.&lt;/p&gt;

&lt;p&gt;From a traditional project-management perspective, you could describe that implementation as partially wasted effort.&lt;/p&gt;

&lt;p&gt;An engineer spent time implementing something primarily to discover that it should barely be used.&lt;/p&gt;

&lt;p&gt;Under agentic economics, that interpretation makes less sense.&lt;/p&gt;

&lt;p&gt;The failed hypothesis produced knowledge.&lt;/p&gt;

&lt;p&gt;And the inference cost of getting that knowledge was tiny.&lt;/p&gt;

&lt;p&gt;This effect gets stronger as inference gets cheaper.&lt;/p&gt;

&lt;p&gt;You can afford to explore more branches.&lt;/p&gt;

&lt;p&gt;You can implement competing designs.&lt;/p&gt;

&lt;p&gt;You can benchmark them.&lt;/p&gt;

&lt;p&gt;You can discard two and keep one.&lt;/p&gt;

&lt;p&gt;You can ask an agent to prove its own optimization is useful before accepting the complexity.&lt;/p&gt;

&lt;p&gt;That is closer to search than traditional implementation.&lt;/p&gt;

&lt;p&gt;And search becomes much more attractive when each branch costs cents instead of engineer-days.&lt;/p&gt;

&lt;h2&gt;
  
  
  So What Is the Unit of Productivity?
&lt;/h2&gt;

&lt;p&gt;Definitely not tokens.&lt;/p&gt;

&lt;p&gt;Probably not commits.&lt;/p&gt;

&lt;p&gt;Definitely not lines of code.&lt;/p&gt;

&lt;p&gt;I suggested this in the previous article:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;validated engineering work
──────────────────────────
      inference cost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I still like that.&lt;/p&gt;

&lt;p&gt;But this second run makes me think the interesting economic unit may eventually become something closer to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;useful product capability × confidence
──────────────────────────────────────
          total engineering cost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because an agent that implements ten features with weak validation may be economically worse than an agent that implements six features and surrounds them with enough tests, benchmarks and executable contracts that I can safely continue building on them.&lt;/p&gt;

&lt;p&gt;Cheap generation increases the numerator.&lt;/p&gt;

&lt;p&gt;Cheap validation increases the confidence multiplier.&lt;/p&gt;

&lt;p&gt;Persistent cached context reduces the inference component of the denominator.&lt;/p&gt;

&lt;p&gt;That combination is much more important than token efficiency in isolation.&lt;/p&gt;

&lt;h2&gt;
  
  
  I Am Not Claiming V4.1 Flash Is 4× Better
&lt;/h2&gt;

&lt;p&gt;To be clear, this is still a case study.&lt;/p&gt;

&lt;p&gt;I changed the model.&lt;/p&gt;

&lt;p&gt;But the project also changed.&lt;/p&gt;

&lt;p&gt;The tasks changed.&lt;/p&gt;

&lt;p&gt;The harness evolved.&lt;/p&gt;

&lt;p&gt;The later workload contains much more symbolic mathematics, validation and hardening.&lt;/p&gt;

&lt;p&gt;The request distribution is different.&lt;/p&gt;

&lt;p&gt;So the 3.95× reduction in blended token cost is an &lt;strong&gt;economic observation&lt;/strong&gt;, not a model-quality benchmark.&lt;/p&gt;

&lt;p&gt;DeepSeek claims V4.1 Flash exceeds V4 Pro on its agentic benchmarks, and the architecture is especially interesting for this workload: a 552B MoE with asymmetric activation, using only 8B active parameters on input and 16B on output. DeepSeek also says its KV-cache requirements are substantially smaller than the previous generation.&lt;/p&gt;

&lt;p&gt;That architecture is almost comically aligned with DSH.&lt;/p&gt;

&lt;p&gt;DSH is extremely input-heavy.&lt;/p&gt;

&lt;p&gt;The Flash window contained:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.138 billion input tokens.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Only:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;16.1 million output tokens.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The vast majority of the workload is the model repeatedly reading accumulated engineering context.&lt;/p&gt;

&lt;p&gt;Making input and cache reuse radically cheaper directly attacks the dominant term in the workload.&lt;/p&gt;

&lt;p&gt;That matters much more to me than shaving a few tokens from a prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Think Agentic SWE Actually Changes
&lt;/h2&gt;

&lt;p&gt;The easy prediction about AI coding is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;software will be cheaper because programmers will write code faster.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I think that undersells the change.&lt;/p&gt;

&lt;p&gt;The more interesting possibility is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;we will economically justify doing engineering work that was previously skipped.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;More tests.&lt;/p&gt;

&lt;p&gt;More alternative implementations.&lt;/p&gt;

&lt;p&gt;More benchmarks.&lt;/p&gt;

&lt;p&gt;More compatibility checks.&lt;/p&gt;

&lt;p&gt;More executable documentation.&lt;/p&gt;

&lt;p&gt;More migration tooling.&lt;/p&gt;

&lt;p&gt;More differential validation.&lt;/p&gt;

&lt;p&gt;More experiments that are expected to be thrown away.&lt;/p&gt;

&lt;p&gt;More maintenance of internal developer tools that were previously "not worth the sprint."&lt;/p&gt;

&lt;p&gt;More exploration before committing to an architecture.&lt;/p&gt;

&lt;p&gt;Some teams will absolutely use AI to produce the same amount of validation and ten times more code.&lt;/p&gt;

&lt;p&gt;That will be terrible.&lt;/p&gt;

&lt;p&gt;But that isn't the only equilibrium available.&lt;/p&gt;

&lt;p&gt;If the marginal cost of both &lt;strong&gt;features and verification&lt;/strong&gt; collapses, then the feature/test economics can improve rather than deteriorate.&lt;/p&gt;

&lt;p&gt;That is the part I am interested in testing.&lt;/p&gt;

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

&lt;p&gt;The first article was:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;612.9 million tokens.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;45 commits.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;$28.35.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It convinced me that cache locality could make persistent agent workloads much cheaper than raw token counts suggest.&lt;/p&gt;

&lt;p&gt;The continuation is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.759 billion additional processed tokens for $40.44.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;166 commits beyond the September 5 repository boundary.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And, inside that period, the first three complete V4.1 Flash days alone were:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2.154 billion tokens.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12,253 requests.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;99.30% input cache hit.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;$19.22.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What came out the other end was not 2.1 billion tokens worth of chat.&lt;/p&gt;

&lt;p&gt;It was a substantial expansion of a real software system: symbolic mathematics, exact rationals, Gröbner bases, system solving, MathIR compilation, structured machine-facing APIs, more numerical capabilities and a test/validation surface that eventually reached &lt;strong&gt;5,655 passing tests&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That is the benchmark artifact.&lt;/p&gt;

&lt;p&gt;The code is public.&lt;/p&gt;

&lt;p&gt;The Git history is public.&lt;/p&gt;

&lt;p&gt;The usage export is the bill.&lt;/p&gt;

&lt;p&gt;And I think the economics are starting to point somewhere important.&lt;/p&gt;

&lt;p&gt;For most of software history, implementation effort forced us to ration engineering ideas.&lt;/p&gt;

&lt;p&gt;We rationed features.&lt;/p&gt;

&lt;p&gt;We rationed tests.&lt;/p&gt;

&lt;p&gt;We rationed prototypes.&lt;/p&gt;

&lt;p&gt;We rationed benchmarks.&lt;/p&gt;

&lt;p&gt;We rationed cleanup work.&lt;/p&gt;

&lt;p&gt;We rationed experiments.&lt;/p&gt;

&lt;p&gt;Agentic engineering does not remove the need for good engineers.&lt;/p&gt;

&lt;p&gt;But it may remove a large part of the economic pressure that forced engineers to choose between many of those activities in the first place.&lt;/p&gt;

&lt;p&gt;At &lt;strong&gt;$0.0089 per million processed tokens&lt;/strong&gt;, I don't need my engineering agent to be token-efficient in the traditional sense.&lt;/p&gt;

&lt;p&gt;I need it to turn cheap inference into useful, tested software.&lt;/p&gt;

&lt;p&gt;That is a much more interesting optimization problem.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>deepseek</category>
      <category>agents</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>800 Million Tokens for $36: Benchmarking DSH + DeepSeek V4 Pro on a Real Codebase</title>
      <dc:creator>Ricardo Medeiros</dc:creator>
      <pubDate>Sat, 05 Sep 2026 12:18:24 +0000</pubDate>
      <link>https://dev.to/jjackbauer/800-million-tokens-for-36-benchmarking-dsh-deepseek-v4-pro-on-a-real-codebase-2a0o</link>
      <guid>https://dev.to/jjackbauer/800-million-tokens-for-36-benchmarking-dsh-deepseek-v4-pro-on-a-real-codebase-2a0o</guid>
      <description>&lt;p&gt;There is a problem with most benchmarks for coding agents: they are not software development.&lt;/p&gt;

&lt;p&gt;They are useful, of course. Give an agent an issue, run a test suite, check whether the patch passes. SWE-bench and similar evaluations give us a standardized way of comparing models.&lt;/p&gt;

&lt;p&gt;But this is not how I actually use agents.&lt;/p&gt;

&lt;p&gt;I don't want an agent to fix a single isolated issue and stop. I want it to spend hours inside a codebase, understand the architecture, write requirements, implement things, run tests, benchmark alternatives, discover that its first idea was wrong, revise it, document what happened, and then use that new knowledge in the next task.&lt;/p&gt;

&lt;p&gt;So, during the last few days, I accidentally created another kind of benchmark.&lt;/p&gt;

&lt;p&gt;I gave &lt;strong&gt;DeepSeek Harness (DSH) + DeepSeek V4 Pro&lt;/strong&gt; a real project and let it work.&lt;/p&gt;

&lt;p&gt;The result was:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Visible development window&lt;/td&gt;
&lt;td&gt;Aug 31 → Sep 3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Git commits&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;45&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Files changed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;193&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API requests&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3,266&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tokens processed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;612,923,681&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache-hit input&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;600,885,248&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache-miss input&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6,458,427&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Output&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5,580,006&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Input cache-hit rate&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;98.94%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API cost&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$28.35&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Yes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;612 million tokens. Twenty-eight dollars.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And before anyone starts typing "tokens are not productivity" into the comments: I agree.&lt;/p&gt;

&lt;p&gt;That is exactly why the interesting part of this experiment is not the token count.&lt;/p&gt;

&lt;p&gt;It is &lt;strong&gt;what happened to the repository&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Project
&lt;/h2&gt;

&lt;p&gt;The project is &lt;a href="https://github.com/jjackbauer/LovelaceSharp" rel="noopener noreferrer"&gt;LovelaceSharp&lt;/a&gt;, my attempt to build an arbitrary-precision mathematical environment in C#.&lt;/p&gt;

&lt;p&gt;It contains arbitrary-precision natural numbers, integers and real numbers, a scripting language, vectors and N-dimensional arrays, linear algebra, a web IDE, benchmarking tools and a Lean project for formally verifying the underlying arithmetic model.&lt;/p&gt;

&lt;p&gt;This is a useful agentic workload because it is not a CRUD application.&lt;/p&gt;

&lt;p&gt;There are plenty of opportunities for code that looks correct but isn't.&lt;/p&gt;

&lt;p&gt;Arithmetic has edge cases. Numeric algorithms have crossover points. Performance changes can destroy correctness. Array views introduce aliasing and stride semantics. Precision can leak across sessions. Formal proofs can prove something subtly different from what the optimized production implementation actually does.&lt;/p&gt;

&lt;p&gt;In other words:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;bullshit has somewhere to hide.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That makes it a much more interesting test than asking an agent to add another REST endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Establishing the Boundary
&lt;/h2&gt;

&lt;p&gt;I also got lucky with the Git history.&lt;/p&gt;

&lt;p&gt;The old work on LovelaceSharp stopped on March 17 at commit &lt;code&gt;9b26f05&lt;/code&gt;. There was then no activity until August 31, when the new DSH-driven development started.&lt;/p&gt;

&lt;p&gt;The comparison from that old baseline to the end of the visible burst contains:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;45 commits across 193 changed files.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can inspect the history and comparison directly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/jjackbauer/LovelaceSharp/commits/main" rel="noopener noreferrer"&gt;LovelaceSharp commit history&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jjackbauer/LovelaceSharp/compare/9b26f05...main" rel="noopener noreferrer"&gt;Baseline-to-current comparison&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I am &lt;strong&gt;not counting the previous implementation as work performed by DSH&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That matters.&lt;/p&gt;

&lt;p&gt;The benchmark isn't:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Look at this entire repository an AI supposedly made."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Here is the repository before this run, here is the repository after it, and here is the API bill during the days those changes landed."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My complete DeepSeek export spans Aug 30 through Sep 5 and contains roughly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;805.4M tokens&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3,931 requests&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;$36.68 of spending&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the benchmark, however, I only attribute Aug 31 through Sep 3, because those are the dates represented by the visible development burst on &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That leaves:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;612.9M tokens and $28.35&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;associated with the 45-commit comparison.&lt;/p&gt;

&lt;p&gt;So what did those $28 actually buy?&lt;/p&gt;

&lt;h2&gt;
  
  
  First: Replace the Core Number Representation
&lt;/h2&gt;

&lt;p&gt;One of the largest changes was rewriting &lt;code&gt;Natural&lt;/code&gt;, the arbitrary-precision unsigned integer implementation.&lt;/p&gt;

&lt;p&gt;The previous representation was based around decimal BCD storage.&lt;/p&gt;

&lt;p&gt;The new implementation moved the actual number representation to little-endian &lt;strong&gt;base-2^64 limbs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That is already a reasonably dangerous refactor because essentially every numerical type above it depends on &lt;code&gt;Natural&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The change included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;native carry/borrow arithmetic;&lt;/li&gt;
&lt;li&gt;schoolbook multiplication;&lt;/li&gt;
&lt;li&gt;Karatsuba multiplication;&lt;/li&gt;
&lt;li&gt;Knuth Algorithm D division;&lt;/li&gt;
&lt;li&gt;short division;&lt;/li&gt;
&lt;li&gt;divide-and-conquer conversion between decimal and binary representations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the important part is what came with it.&lt;/p&gt;

&lt;p&gt;DSH added tests specifically around limb boundaries and randomized differential testing against &lt;code&gt;System.Numerics.BigInteger&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The differential suite covers arithmetic across multiple operand sizes and adversarial values around boundaries such as &lt;code&gt;2^64&lt;/code&gt; and &lt;code&gt;2^128&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Relevant commit:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jjackbauer/LovelaceSharp/commit/e638bfd7b1c2220f622891ea20ee5f2d487b4d22" rel="noopener noreferrer"&gt;Rewrite Natural storage around 64-bit limbs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is much more interesting to me than "the model knew Knuth division."&lt;/p&gt;

&lt;p&gt;LLMs know algorithms.&lt;/p&gt;

&lt;p&gt;The useful behavior is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;change representation
        ↓
identify new failure boundaries
        ↓
construct an independent oracle
        ↓
cross-check the implementation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  Then It Made Multiplication More Complicated — for a Reason
&lt;/h2&gt;

&lt;p&gt;After moving to binary limbs, the agent added an exact two-prime &lt;strong&gt;Number Theoretic Transform&lt;/strong&gt; multiplication path for very large numbers.&lt;/p&gt;

&lt;p&gt;This wasn't simply:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NTT is asymptotically fast, therefore NTT everywhere.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It benchmarked the implementation against Karatsuba and introduced a dispatch threshold around &lt;strong&gt;100,000 combined limbs&lt;/strong&gt;, roughly the region where the NTT path actually started winning.&lt;/p&gt;

&lt;p&gt;It also cross-checked multiplication against &lt;code&gt;BigInteger&lt;/code&gt; at extremely large operand sizes.&lt;/p&gt;

&lt;p&gt;Relevant commit:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jjackbauer/LovelaceSharp/commit/04623183d72de62fb12e5f05352f5b8c0a43f788" rel="noopener noreferrer"&gt;Add NTT multiplication for huge Natural values&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This distinction matters enormously when evaluating agents.&lt;/p&gt;

&lt;p&gt;A coding model can produce complicated code all day long.&lt;/p&gt;

&lt;p&gt;A useful engineering agent must understand that an asymptotically superior algorithm can still be the wrong implementation for almost every practical input.&lt;/p&gt;

&lt;p&gt;And that became even more obvious with division.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then It Implemented an Algorithm and Discovered It Should Barely Use It
&lt;/h2&gt;

&lt;p&gt;DSH implemented Newton-reciprocal division with asymptotically better behavior for huge operands.&lt;/p&gt;

&lt;p&gt;Then it benchmarked it.&lt;/p&gt;

&lt;p&gt;And Knuth division won.&lt;/p&gt;

&lt;p&gt;Not forever, but for a surprisingly long time.&lt;/p&gt;

&lt;p&gt;The measured crossover put Newton at roughly the multi-million-decimal-digit range, so the production dispatcher retained Knuth below that region and only selected Newton for enormous inputs.&lt;/p&gt;

&lt;p&gt;Relevant commit:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jjackbauer/LovelaceSharp/commit/6f038a38a2e0e72910150f441d20dd9155400327" rel="noopener noreferrer"&gt;Add Newton reciprocal division and benchmark its crossover&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This may be my favorite part of the experiment.&lt;/p&gt;

&lt;p&gt;Because the workflow was essentially:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;hypothesis
    ↓
implementation
    ↓
measurement
    ↓
"well... that didn't work as expected"
    ↓
revised implementation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I want more agent benchmarks to measure &lt;strong&gt;this&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Not whether the model knew Newton iteration.&lt;/p&gt;

&lt;p&gt;Whether the agent was willing to prove itself wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Work Wasn't Limited to Big Integers
&lt;/h2&gt;

&lt;p&gt;During the same development burst, Lovelace gained a typed-array abstraction with concepts such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ArrayValue&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DenseArray&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;dtype metadata&lt;/li&gt;
&lt;li&gt;precision metadata&lt;/li&gt;
&lt;li&gt;slices&lt;/li&gt;
&lt;li&gt;strided views&lt;/li&gt;
&lt;li&gt;a plugin-oriented kernel contract&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The abstraction arrived with tests covering array layout and view behavior.&lt;/p&gt;

&lt;p&gt;Relevant commit:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jjackbauer/LovelaceSharp/commit/cec98d4e74d4d4454ee59268ae27f51a01b6fff8" rel="noopener noreferrer"&gt;Introduce typed array abstractions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then the scripting engine itself was migrated onto the typed representation, adding things such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;promotion;&lt;/li&gt;
&lt;li&gt;narrowing;&lt;/li&gt;
&lt;li&gt;broadcasting;&lt;/li&gt;
&lt;li&gt;slicing;&lt;/li&gt;
&lt;li&gt;views;&lt;/li&gt;
&lt;li&gt;empty-dimension behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Relevant commit:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jjackbauer/LovelaceSharp/commit/194aba887ca499bbe87c1469101890c7fe770816" rel="noopener noreferrer"&gt;Migrate Suite to the typed array representation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Around the same period, the project also acquired a web IDE, &lt;code&gt;Lovelace.Studio&lt;/code&gt;, over the common scripting engine.&lt;/p&gt;

&lt;p&gt;The initial Studio work extracted the scripting language into a shared engine and built an ASP.NET Core + browser IDE around it.&lt;/p&gt;

&lt;p&gt;Relevant commit:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jjackbauer/LovelaceSharp/commit/b80df3b262882a3aea3ded43fbcc2133893997a4" rel="noopener noreferrer"&gt;Introduce Lovelace.Studio&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A later change added isolated sessions, per-session precision, incremental computation, asynchronous progress and CodeMirror autocomplete.&lt;/p&gt;

&lt;p&gt;Relevant commit:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jjackbauer/LovelaceSharp/commit/b48186242f32a950807161028410ae17fc4d13e0" rel="noopener noreferrer"&gt;Add isolated sessions and incremental evaluation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The point is not LOC.&lt;/p&gt;

&lt;p&gt;The point is that the workload moved through:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;numerical algorithms, language implementation, web tooling, concurrency, arrays, benchmarks and formal methods&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;without changing the overall agentic workflow or treating each category as a fresh synthetic benchmark.&lt;/p&gt;

&lt;p&gt;That is much closer to the way I want an engineering agent to behave.&lt;/p&gt;

&lt;h2&gt;
  
  
  It Also Started Proving Things
&lt;/h2&gt;

&lt;p&gt;Another part of the burst introduced &lt;code&gt;Lovelace.Proofs&lt;/code&gt;, a Lean 4 project formalizing base-b arithmetic.&lt;/p&gt;

&lt;p&gt;It covers representation, addition, subtraction, multiplication and division using core Lean.&lt;/p&gt;

&lt;p&gt;Relevant commit:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jjackbauer/LovelaceSharp/commit/f342d072e8311974c6b975312be9cea58a50ded7" rel="noopener noreferrer"&gt;Add Lean proofs for core arithmetic&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is an important caveat here.&lt;/p&gt;

&lt;p&gt;The Lean proofs describe the digit-by-digit reference arithmetic.&lt;/p&gt;

&lt;p&gt;The production &lt;code&gt;Natural&lt;/code&gt; implementation was subsequently changed to binary limbs and gained optimized Knuth, NTT and Newton paths.&lt;/p&gt;

&lt;p&gt;So saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Lean proves the optimized implementation is correct"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;would be wrong.&lt;/p&gt;

&lt;p&gt;What we actually have is closer to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;a formally verified arithmetic reference model plus optimized production implementations checked through unit tests, boundary tests and differential testing.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I think that distinction is worth mentioning because this is another place where agentic development can become dangerous.&lt;/p&gt;

&lt;p&gt;An agent can add formal verification and make a project &lt;em&gt;look&lt;/em&gt; dramatically safer while proving something adjacent to the thing actually running.&lt;/p&gt;

&lt;p&gt;The human still needs to understand the correspondence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Now Let's Talk About the 612 Million Tokens in the Room
&lt;/h2&gt;

&lt;p&gt;At first glance, this workload looks horrifyingly inefficient.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;612,923,681 tokens in four days.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is around &lt;strong&gt;188K processed tokens per API request&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If your mental model of agent economics is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tokens × normal input price = bill
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this should have been expensive.&lt;/p&gt;

&lt;p&gt;But that is not what happened.&lt;/p&gt;

&lt;p&gt;Of the input sent during the benchmark window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cache hit:   600,885,248
cache miss:    6,458,427
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The resulting input cache-hit rate was:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;98.94%.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For DeepSeek V4 Pro alone during the same period, it was even higher.&lt;/p&gt;

&lt;p&gt;And this wasn't one anomalous gigantic request dominating the average. Across the complete development days, the provider-side daily numbers remained extremely cache-heavy.&lt;/p&gt;

&lt;p&gt;DeepSeek supports automatic context caching for repeated prompt prefixes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://api-docs.deepseek.com/guides/kv_cache/" rel="noopener noreferrer"&gt;DeepSeek Context Caching documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That matters a lot for a persistent harness.&lt;/p&gt;

&lt;p&gt;Long-running agent sessions naturally contain large stable prefixes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;previous prompts;&lt;/li&gt;
&lt;li&gt;repository discoveries;&lt;/li&gt;
&lt;li&gt;tool results;&lt;/li&gt;
&lt;li&gt;architectural decisions;&lt;/li&gt;
&lt;li&gt;earlier failures;&lt;/li&gt;
&lt;li&gt;requirements;&lt;/li&gt;
&lt;li&gt;test observations;&lt;/li&gt;
&lt;li&gt;existing conversation state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the harness keeps those prefixes stable enough, the provider does not have to charge them like entirely novel input every time.&lt;/p&gt;

&lt;p&gt;So the raw token count is enormous.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;novel expensive prefix&lt;/strong&gt; is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cache Hits Change the Economics Completely
&lt;/h2&gt;

&lt;p&gt;The provider export records different prices for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cache-hit input;&lt;/li&gt;
&lt;li&gt;cache-miss input;&lt;/li&gt;
&lt;li&gt;output.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For V4 Pro, cache-hit input in the export was priced at &lt;strong&gt;1/30th of cache-miss input&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That is the part that makes the economics weird.&lt;/p&gt;

&lt;p&gt;Using the actual pricing tiers recorded in my export, the DSH development window cost:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;$28.35.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now take exactly those same requests and make one artificial change:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;pretend every cached input token had instead been charged as a cache miss, preserving the same observed price bands.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The cost would have been on the order of &lt;strong&gt;hundreds of dollars rather than tens of dollars&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For the complete Aug 30 → Sep 5 export, the observed bill was &lt;strong&gt;$36.68&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Using the same thought experiment, the equivalent bill without cache reuse is roughly &lt;strong&gt;$567&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So caching reduced the total bill by approximately:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;93.5%&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;or around:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;15.4×&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;for that complete export.&lt;/p&gt;

&lt;p&gt;This is where I think the usual discussion about "token efficiency" becomes a little misleading.&lt;/p&gt;

&lt;p&gt;DSH did not optimize this workflow by minimizing how many tokens it processed.&lt;/p&gt;

&lt;p&gt;It processed a &lt;strong&gt;ridiculous&lt;/strong&gt; number of tokens.&lt;/p&gt;

&lt;p&gt;What made the economics work was that almost all of the input became cheap to revisit.&lt;/p&gt;

&lt;p&gt;There is a fundamental difference between:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;minimize context&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;maximize reusable context.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For an agent doing sustained engineering work, the second strategy can be surprisingly attractive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context Can Become an Asset Instead of a Tax
&lt;/h2&gt;

&lt;p&gt;Traditional context optimization tends to look 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;large context
    ↓
summarize
    ↓
discard details
    ↓
keep prompt small
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That makes sense when every input token is similarly expensive.&lt;/p&gt;

&lt;p&gt;With strong prefix caching, another strategy becomes possible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;accumulate useful context
    ↓
keep the stable portion stable
    ↓
reuse it repeatedly
    ↓
pay mostly cache-read pricing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This does not mean "send everything forever."&lt;/p&gt;

&lt;p&gt;Cached tokens still cost money.&lt;/p&gt;

&lt;p&gt;Irrelevant context can still hurt:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;attention;&lt;/li&gt;
&lt;li&gt;latency;&lt;/li&gt;
&lt;li&gt;model quality;&lt;/li&gt;
&lt;li&gt;tool-selection quality;&lt;/li&gt;
&lt;li&gt;reasoning focus.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A 99% hit rate can also become a vanity metric if the harness is repeatedly hauling 500K tokens it never needed.&lt;/p&gt;

&lt;p&gt;So I would not propose:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;cache hit rate = agent quality.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But I would absolutely propose:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;cache locality is a first-class agent-runtime metric.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Because once an agent starts working for hours or days instead of answering isolated prompts, context reuse becomes an economic property of the architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  And This Is Why "$ per Million Tokens" Is the Wrong Agent Benchmark
&lt;/h2&gt;

&lt;p&gt;My effective blended price during this development window was approximately:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;$0.046 per million processed tokens.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That number sounds absurd because it includes hundreds of millions of cache reads.&lt;/p&gt;

&lt;p&gt;But it also demonstrates why comparing agents using raw token consumption is increasingly questionable.&lt;/p&gt;

&lt;p&gt;Suppose Agent A uses 10 million tokens and forgets half the repository every few turns.&lt;/p&gt;

&lt;p&gt;Agent B processes 100 million tokens but 99 million of them come from stable cached context containing decisions, tests, observations, architectural constraints and previous failures.&lt;/p&gt;

&lt;p&gt;Which one is more efficient?&lt;/p&gt;

&lt;p&gt;You cannot answer that from token count.&lt;/p&gt;

&lt;p&gt;Even cost alone does not answer it.&lt;/p&gt;

&lt;p&gt;What actually matters is something closer to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;validated engineering work
──────────────────────────
      inference cost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And eventually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;validated engineering work
──────────────────────────
 human review time + inference cost
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That second denominator is probably where things get uncomfortable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The New Bottleneck Is Me
&lt;/h2&gt;

&lt;p&gt;This experiment cost &lt;strong&gt;$28.35&lt;/strong&gt; in attributable inference.&lt;/p&gt;

&lt;p&gt;The repository received 45 commits across 193 files.&lt;/p&gt;

&lt;p&gt;The agent was able to move between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;formal proofs;&lt;/li&gt;
&lt;li&gt;big-integer arithmetic;&lt;/li&gt;
&lt;li&gt;array semantics;&lt;/li&gt;
&lt;li&gt;benchmarking;&lt;/li&gt;
&lt;li&gt;performance dispatch;&lt;/li&gt;
&lt;li&gt;Native AOT work;&lt;/li&gt;
&lt;li&gt;scripting-language behavior;&lt;/li&gt;
&lt;li&gt;a browser IDE;&lt;/li&gt;
&lt;li&gt;concurrency and session isolation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point, shaving another five dollars from inference is almost irrelevant.&lt;/p&gt;

&lt;p&gt;My problem is reviewing it.&lt;/p&gt;

&lt;p&gt;Did an NTT edge case escape the differential tests?&lt;/p&gt;

&lt;p&gt;Are array aliases correct under every non-contiguous view?&lt;/p&gt;

&lt;p&gt;Does per-session precision really eliminate all shared-state races?&lt;/p&gt;

&lt;p&gt;Do the Lean theorems correspond closely enough to the optimized code paths for the documentation to describe them accurately?&lt;/p&gt;

&lt;p&gt;Those questions are now more expensive than generating another implementation.&lt;/p&gt;

&lt;p&gt;And I think this is an important transition in agentic software development.&lt;/p&gt;

&lt;p&gt;For a long time, generating code was the expensive part.&lt;/p&gt;

&lt;p&gt;Then generating &lt;em&gt;good&lt;/em&gt; code became the challenge.&lt;/p&gt;

&lt;p&gt;With cheap models, aggressive caching and persistent harnesses, we may be moving toward another bottleneck:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How much machine-generated engineering can a human responsibly validate?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is a very different problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  So Is This a Benchmark?
&lt;/h2&gt;

&lt;p&gt;Not in the SWE-bench sense.&lt;/p&gt;

&lt;p&gt;There is no controlled comparison against Claude Code, Codex, Cursor or another harness.&lt;/p&gt;

&lt;p&gt;There is no randomized task set.&lt;/p&gt;

&lt;p&gt;I cannot derive:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"DSH is X times better than Claude Code"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;from this experiment.&lt;/p&gt;

&lt;p&gt;Anyone doing that from these numbers would be abusing the data.&lt;/p&gt;

&lt;p&gt;It is better understood as a &lt;strong&gt;real-work agentic case benchmark&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It has a reproducible Git boundary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;9b26f05 → current DSH-era main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It has a public work product:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;45 commits, 193 changed files.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It has provider-side usage data:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;612.9M processed tokens, 3,266 requests.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It has provider-side cache accounting:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;98.94% input cache hit.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And it has an actual bill:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;$28.35.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most importantly, the output is available for anyone to inspect.&lt;/p&gt;

&lt;p&gt;You don't have to believe me that the work is good.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The code is the benchmark artifact.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/jjackbauer/LovelaceSharp" rel="noopener noreferrer"&gt;https://github.com/jjackbauer/LovelaceSharp&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Would Measure Next
&lt;/h2&gt;

&lt;p&gt;After seeing this run, I am much less interested in "tokens per task."&lt;/p&gt;

&lt;p&gt;For sustained agentic engineering, I think the useful metrics are going to look more like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cost per validated change;&lt;/li&gt;
&lt;li&gt;percentage of agent changes surviving human review;&lt;/li&gt;
&lt;li&gt;regression rate after integration;&lt;/li&gt;
&lt;li&gt;human review minutes per accepted change;&lt;/li&gt;
&lt;li&gt;cache-hit distribution;&lt;/li&gt;
&lt;li&gt;uncached input per accepted change;&lt;/li&gt;
&lt;li&gt;wall-clock time to accepted change;&lt;/li&gt;
&lt;li&gt;benchmark improvements that survive independent reproduction.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because a harness can cheat almost every superficial metric.&lt;/p&gt;

&lt;p&gt;It can produce fewer tokens by forgetting things.&lt;/p&gt;

&lt;p&gt;It can produce more commits by making tiny commits.&lt;/p&gt;

&lt;p&gt;It can produce more code by generating garbage.&lt;/p&gt;

&lt;p&gt;It can get a spectacular cache-hit rate by repeatedly sending irrelevant history.&lt;/p&gt;

&lt;p&gt;It is much harder to cheat:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Did the software get materially better, did the changes survive verification, and how much did that cost?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the benchmark I care about.&lt;/p&gt;

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

&lt;p&gt;I started looking at the usage dashboard because &lt;strong&gt;800 million tokens for about $36 looked ridiculous&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It is ridiculous.&lt;/p&gt;

&lt;p&gt;But the interesting result wasn't simply that DeepSeek V4 Pro is cheap.&lt;/p&gt;

&lt;p&gt;The interesting result was understanding &lt;em&gt;why&lt;/em&gt; this workload stayed cheap while maintaining enormous context.&lt;/p&gt;

&lt;p&gt;DSH + DeepSeek V4 Pro effectively turned repeated context from one of the largest costs of agentic development into a heavily amortized resource.&lt;/p&gt;

&lt;p&gt;During the cleanest observable development window, that meant:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;45 commits.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;193 files.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;612.9 million processed tokens.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;98.94% cache-hit input.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;$28.35.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are still plenty of things I don't trust without human verification.&lt;/p&gt;

&lt;p&gt;There should be.&lt;/p&gt;

&lt;p&gt;An agent writing formal mathematics and arbitrary-precision arithmetic should not earn trust because a dashboard has a nice green number.&lt;/p&gt;

&lt;p&gt;But if we want to discuss the economics of agents seriously, I think we need to stop benchmarking them as expensive autocomplete.&lt;/p&gt;

&lt;p&gt;Persistent agents behave differently.&lt;/p&gt;

&lt;p&gt;Their context behaves differently.&lt;/p&gt;

&lt;p&gt;And, apparently, their bills can behave &lt;strong&gt;very differently&lt;/strong&gt; too.&lt;/p&gt;




&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/jjackbauer/LovelaceSharp" rel="noopener noreferrer"&gt;LovelaceSharp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/deepseek-ai/deepseek-harness" rel="noopener noreferrer"&gt;DeepSeek Harness&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://api-docs.deepseek.com/guides/kv_cache/" rel="noopener noreferrer"&gt;DeepSeek Context Caching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://api-docs.deepseek.com/quick_start/pricing/" rel="noopener noreferrer"&gt;DeepSeek API Pricing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>opensource</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>You Probably Understood the Client Server Model Wrong</title>
      <dc:creator>Ricardo Medeiros</dc:creator>
      <pubDate>Thu, 11 Dec 2025 15:19:31 +0000</pubDate>
      <link>https://dev.to/jjackbauer/you-probably-understood-the-client-server-model-wrong-3ae1</link>
      <guid>https://dev.to/jjackbauer/you-probably-understood-the-client-server-model-wrong-3ae1</guid>
      <description>&lt;p&gt;Most developers intuitively grasp the client–server model. They know the backend must serve many users while the frontend runs a single isolated instance per person. The problem is not one of misunderstanding but of misapplied mental models.&lt;/p&gt;

&lt;p&gt;Too often, frontend interaction patterns quietly seep into backend architecture. This happens almost invisibly: because a user clicks a button and waits, the backend endpoint is implemented to perform the entire workflow before returning.&lt;/p&gt;

&lt;p&gt;Because the UI shows near-real-time progress, developers reach for WebSockets, SSE, or long-polling, assuming the backend must act with the same immediacy. As the interface suggests an atomic action, the backend is built to execute a full, complex sequence in a single synchronous request.&lt;/p&gt;

&lt;p&gt;These decisions feel natural when thinking from the user outward, but they ignore the fact that frontend and backend systems live under radically different constraints. The frontend exists per user, per tab, per device. If it blocks or performs work synchronously, only one person is affected.&lt;/p&gt;

&lt;p&gt;In the other hand, the backend is a shared computational surface, serving thousands of simultaneous users from a limited pool of machines. A blocking call that seems harmless in the UI becomes costly when multiplied by a large user base.&lt;/p&gt;

&lt;p&gt;This distinction is critical. For lightweight operations—like fetching a user profile or toggling a setting—mimicking the frontend’s synchronous expectations is perfectly acceptable; the resource cost is negligible. The danger arises when we apply that same 'request-response' immediacy to complex business logic or third-party integrations.&lt;/p&gt;

&lt;p&gt;When a heavy, valuable workflow is forced to fit inside the fragile lifespan of a simple HTTP request, the backend stops being a scalable coordinator and becomes a brittle bottleneck.&lt;/p&gt;

&lt;p&gt;Consequently, a heavy workflow executed synchronously does not scale when many people trigger it at once. Frontend mental models make perfect sense for the UI layer but become harmful when projected onto the backend.&lt;/p&gt;

&lt;p&gt;The first step toward correcting this misalignment is to visualize the structural asymmetry. Each user runs their own frontend instance, but a comparatively small set of backend servers must collectively serve all of them.&lt;/p&gt;

&lt;p&gt;When design decisions assume parity between these layers, the backend becomes overloaded—not because of traffic volume alone, but because of how tightly the backend’s execution model is coupled to human interactions.&lt;/p&gt;

&lt;h1&gt;
  
  
  Frontend Per User, Backend Shared by Everyone
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fijjwccx2rc2fa37vvitj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fijjwccx2rc2fa37vvitj.png" alt=" " width="800" height="899"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This diagram illustrates the heart of the issue: every user has a dedicated frontend instance, but all users share the backend. If backend routes mimic user-level workflows synchronously, they consume server resources as if each request were serving only that user.&lt;/p&gt;

&lt;p&gt;This leads to patterns where backend operations are tied to the lifetime of an HTTP request or WebSocket connection, causing servers to hold open sockets, allocate memory, keep database transactions alive, or block worker threads while waiting for slow I/O. These patterns work fine when thinking like a single UI instance, but they collapse under real-world concurrency.&lt;/p&gt;

&lt;p&gt;Even when developers use asynchronous programming constructs—such as async/await—the architecture remains synchronous if long-running work is still executed within the request lifecycle.&lt;/p&gt;

&lt;p&gt;Architectural asynchrony is not achieved by non-blocking code alone; it comes from offloading work, decoupling the response from the completion of the operation, and treating the backend as a shared coordinator of workflows rather than a synchronous executor of user-driven commands.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Shift Toward Asynchronous Endpoints
&lt;/h1&gt;

&lt;p&gt;A backend that scales must adopt a different perspective: the purpose of an endpoint is not to “complete the job” but to “accept the job.” True asynchronous architecture emerges not from code-level semantics but from systemic decoupling.&lt;/p&gt;

&lt;p&gt;The backend should perform only the minimal steps required to validate input, authenticate the caller, record the intent, and enqueue the real work elsewhere. It should return immediately—often with a 202 Accepted status—handing back a job identifier that the frontend can use to check progress.&lt;/p&gt;

&lt;p&gt;This “accept, then process” pattern changes the nature of the system entirely. Instead of backend servers waiting idly during long-running operations, the work is delegated to background processors or workers that run independently of the request lifecycle. This frees backend capacity for new incoming requests, allowing the system to serve more users without proportional increases in server count.&lt;/p&gt;

&lt;h2&gt;
  
  
  Asynchronous Workflow Sequence
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Figf8rjbe2bwj9j439ja8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Figf8rjbe2bwj9j439ja8.png" alt=" " width="800" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this design, the backend no longer mirrors the interaction model of the UI. The frontend and backend operate on independent clocks: the UI can poll for updates at its own pace, and the backend can schedule work according to resource availability. &lt;/p&gt;

&lt;p&gt;Polling, often dismissed as simplistic, becomes a powerful pattern for background workflows because it keeps servers stateless and scalable, avoids long-lived connections, and shifts the complexity of immediacy away from the backend.&lt;/p&gt;

&lt;h1&gt;
  
  
  Status Endpoints and Cache-Assisted Polling
&lt;/h1&gt;

&lt;p&gt;When the frontend receives a job identifier, it begins periodically querying a /jobs/:id endpoint for status updates. This endpoint is simple by design: it retrieves the current state of a workflow from the database or, more efficiently, from a cache.&lt;/p&gt;

&lt;p&gt;This pattern allows backend servers to remain fully stateless. As no request needs to wait for job completion, the backend can scale horizontally without sticky sessions or shared in-memory state. Caching enhances this model. A cache-aside pattern—where the API checks the cache first and falls back to the database only on a miss—is often sufficient for moderate traffic. &lt;/p&gt;

&lt;p&gt;For larger systems, a write-through approach pays off: workers update both the database and the cache when job statuses change. This ensures that nearly all frontend polling requests hit the cache rather than the database, dramatically reducing load.&lt;/p&gt;

&lt;h2&gt;
  
  
  Status Endpoint Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftpvqdakbmueq59fklbsd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftpvqdakbmueq59fklbsd.png" alt=" " width="800" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This architecture exemplifies how decoupled systems naturally scale. Backend servers focus solely on orchestrating requests and responding quickly. Workers and queues handle the heavy lifting. Polling reads mostly from cache. No part of the system depends on a long-lived user connection.&lt;/p&gt;

&lt;h1&gt;
  
  
  How Serverless Completes the Picture
&lt;/h1&gt;

&lt;p&gt;Serverless platforms elevate this model by providing isolation and elasticity at the execution level. While backend servers remain stable and responsive, serverless functions scale independently based on event volume. &lt;/p&gt;

&lt;p&gt;Each job can run in its own execution context without interfering with others, effectively giving the backend a burst capacity proportional to incoming workload rather than to the number of servers provisioned.&lt;/p&gt;

&lt;p&gt;This division of responsibilities is transformative. Backend servers become thin control planes responsible only for coordination, while serverless workers perform compute-heavy or long-running tasks. Instead of scaling servers, the system scales events. When a thousand users submit jobs simultaneously, a thousand serverless functions can execute in parallel without any user blocking the backend.&lt;/p&gt;

&lt;p&gt;Serverless architecture embodies the principle that the backend should not behave like the UI. Instead of executing workflows synchronously, backend servers delegate. Instead of waiting, they acknowledge. Instead of owning long-lived operations, they outsource them to stateless, ephemeral functions optimized for scaling.&lt;/p&gt;

&lt;h1&gt;
  
  
  A New Mental Model for Cloud-Native Backends
&lt;/h1&gt;

&lt;p&gt;Reframing the backend begins with recognizing that frontend patterns should not dictate backend structures. The UI can wait; the backend must not. The UI can block; the backend must stay available. The UI serves a single human; the backend serves everyone simultaneously.&lt;/p&gt;

&lt;p&gt;When dealing with simple CRUD-like operations that lack aggregated business logic, a synchronous model remains the simplest and most effective choice. However, when involving complex business logic, third-party integrations, or intensive traffic peaks, that same model creates a bottleneck. In those high-stakes scenarios, synchronous coupling leads to critical failures that can bring the entire system down.&lt;/p&gt;

&lt;p&gt;Once this mental shift clicks, it becomes clear why asynchronous endpoints, polling, queues, workers, caches, and serverless execution represent not advanced architectural strategies but necessary correctives to an intuitive but incorrect assumption: that backend systems should behave like the interfaces that sit on top of them.&lt;/p&gt;

&lt;p&gt;Backend architecture must reflect backend realities. Designing it with a frontend mindset is what leads to systems that stall, choke, or become expensive to operate. Designing it with asynchronous principles produces architectures that scale effortlessly, fail gracefully, and serve users far beyond what synchronous workflows could ever sustain.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Marked UUIDs Pattern</title>
      <dc:creator>Ricardo Medeiros</dc:creator>
      <pubDate>Fri, 28 Jun 2024 20:24:40 +0000</pubDate>
      <link>https://dev.to/jjackbauer/marked-uuids-pattern-3a2n</link>
      <guid>https://dev.to/jjackbauer/marked-uuids-pattern-3a2n</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;So, here I'm again. Writing after some time without doing anything like it, but I've decided to share this, because I think this solution saved a lot of work and problems that system could had. The context was this: my team was responsible for an application that was been integrated into a SAP system by another company, and, we had several PSP integrations to provide our services.&lt;/p&gt;

&lt;p&gt;Some of this PSP test enviroments didn't work at all, they were flaky and inconsistant with responses and even the types of the response properties between the test and production environment. We needed to provide a way for the SAP consultancy to be able to test the functionalities of our plataform without the instability of the PSP test enviroment, and then, we decided to add a flag to mock the PSP response to be successfull (since it was the outcome that we were more interested in).&lt;/p&gt;

&lt;p&gt;It was all great, untill we realized that we needed to test the refund functionality. Now what? As our application was built upon microsservices with domain segregation. We had an Anti-Corruption-Layer (ACL) between it and the PSP, so we had no idea of what was happening there. Both payment and refund were in the ACL, but it hadn't any persistance, as was built to be a facade between the third-party  service provider and our domain. How could we determine if a payment was done in the actual service provider test environment or was mocked by our ACL?&lt;/p&gt;

&lt;h2&gt;
  
  
  Aproaches
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Add a parameter in the response of the ACL indicating if this response is mocked or not;&lt;/li&gt;
&lt;li&gt;Add a database in the ACL to save all the payments created, and if they were mocked or not.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Aditional Parameter
&lt;/h3&gt;

&lt;p&gt;If we had chosen this path, it would require that the application consuming the ACL was changed, to consider this new information about mocking, then, this consuming application would need to save this in order to provide this information back to the ACL when refund were requested. It required to much development just to enable this, and it didn't add anything to our product, just it's testability experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Database in the ACL
&lt;/h3&gt;

&lt;p&gt;Imagine this, a service that operated without databases in production would require one to work in test enviroment. I promptly refused, even not enjoying the first option, this was way worst. Not only would require aditional infrastructure, but also add futher complexity and latency to the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoinding these pains
&lt;/h2&gt;

&lt;p&gt;So, I've started to think. How could I know this information without adding any furter infrastructure or adding parameters? Somehow, I needed to be able to split this register with the information that they already had. With that in mind, I've started to come up with a solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  UUID - The Trojan Horse
&lt;/h3&gt;

&lt;p&gt;Every transation would return an UUID that should be generated by the PSP (or not). Somehow mocking this information in a way that it would be differentiable from the PSP generated ID's wouldn't affect the transaction information, all the further information required would be maintained. With that in mind, I wen't on several experiments in order to make this possible, and that's how I've Achieved it:&lt;/p&gt;

&lt;h3&gt;
  
  
  Marked UUID
&lt;/h3&gt;

&lt;p&gt;UUIDs are pseudo-random 128-bit identifiers that are often represented as 32 hexadecimal digits, displayed in five groups separated by hyphens, in the form 8-4-4-4-12 (e.g., 123e4567-e89b-12d3-a456-426614174000). &lt;/p&gt;

&lt;h4&gt;
  
  
  UUIDv4
&lt;/h4&gt;

&lt;p&gt;UUIDv4 is one of the most commonly used versions of UUIDs. It is designed to be a universally unique identifier generated using random or pseudo-random numbers. Here's a detailed overview of UUIDv4:&lt;/p&gt;

&lt;h5&gt;
  
  
  Characteristics of UUIDv4
&lt;/h5&gt;

&lt;p&gt;Randomness: UUIDv4 relies on random or pseudo-random numbers to generate the unique identifier.&lt;br&gt;
No External Information: Unlike other versions of UUIDs, such as UUIDv1 (which incorporates timestamps and MAC addresses), UUIDv4 does not include any external information about the generating system.&lt;br&gt;
Simplicity: UUIDv4 is straightforward to implement because it only requires a good source of randomness.&lt;/p&gt;
&lt;h5&gt;
  
  
  Structure of UUIDv4
&lt;/h5&gt;

&lt;p&gt;A UUIDv4 is a 128-bit value, typically represented as a 36-character string in the format 8-4-4-4-12, separated by hyphens.&lt;/p&gt;
&lt;h5&gt;
  
  
  Example UUIDv4
&lt;/h5&gt;

&lt;p&gt;f47ac10b-58cc-4372-a567-0e02b2c3d479&lt;/p&gt;
&lt;h5&gt;
  
  
  Breakdown of UUIDv4
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;8 characters: Randomly generated 32 bits.&lt;/li&gt;
&lt;li&gt;4 characters: Randomly generated 16 bits.&lt;/li&gt;
&lt;li&gt;4 characters: Randomly generated 12 bits, and 4 bits for the version (0100 for version 4).&lt;/li&gt;
&lt;li&gt;4 characters: Two or three bits for the variant (10x for RFC 4122), and - 13 or 14 randomly generated bits.&lt;/li&gt;
&lt;li&gt;12 characters: Randomly generated 48 bits.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Marking UUIDv4
&lt;/h4&gt;

&lt;p&gt;The process to mark this ID should be something that couldn't be done by an valid UUID generation, but It should be compatible with UUID implementations in order to be stored sucesfully, avoiding any changes outter the Anti-Corruption Layer code.&lt;/p&gt;

&lt;p&gt;I've selected the last 12 characters section to mark the ID, but I needed for it to be unmistaken with real IDs, so I've devised this algorithm:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Take the ID without the last 12 characters and the hypens&lt;/li&gt;
&lt;li&gt;Use a hash algorithm like SHA-256 to creat a mark&lt;/li&gt;
&lt;li&gt;Grab the first 12 characters (48 bits) of the hash and replace the original generated 12 characters&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it. Stupidly simple, works with the language implementation (in my case was golang) and was unmistaken with a real gerenated UUID. But how can we determine if an ID is marked? It is as simple as to create one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Take the ID without the last 12 characters and the hypens&lt;/li&gt;
&lt;li&gt;Use a hash algorithm like SHA-256 to creat a mark&lt;/li&gt;
&lt;li&gt;Grab the first 12 characters (48 bits) of the hash and compare it to the IDs last 12, if they're equal, this ID was marked.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;So, how did I've employed this to solve the problem? Simple, when I had the flag to mock the PSP responses enabled, I've returned at the payment endpoint the mocked response with an marked ID. In the refund endpoint, if the flag was enabled, I checked if the ID was marked, if so, I would return a mocked refund response. If not, I would make the PSP call, as this payment was created in the PSP enviroment.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If something you gotta do seems to require too much corromption to your application, look for alternative approaches to this problem and don't be afraid to try new things out!&lt;/p&gt;

&lt;p&gt;Any sugestions, comments or corrections, fell free to reach me out at &lt;a href="https://www.linkedin.com/in/rmedio/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag__user ltag__user__id__757631"&gt;
    &lt;a href="/jjackbauer" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=150,height=150,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F757631%2F76940fdf-9f04-4bd8-9217-d577d788ffef.jpeg" alt="jjackbauer image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/jjackbauer"&gt;Ricardo Medeiros&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/jjackbauer"&gt;Staff Backend Engineer | AI Frist Migration @Context Forge&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>microservices</category>
      <category>thirdpartyintegration</category>
      <category>testenvironment</category>
      <category>webdev</category>
    </item>
    <item>
      <title>KAFKA + KSQLDB + .NET #1</title>
      <dc:creator>Ricardo Medeiros</dc:creator>
      <pubDate>Tue, 30 Nov 2021 17:19:05 +0000</pubDate>
      <link>https://dev.to/vaivoa/kafka-ksqldb-net-1-40g4</link>
      <guid>https://dev.to/vaivoa/kafka-ksqldb-net-1-40g4</guid>
      <description>&lt;p&gt;Hi, I'm &lt;a href="https://github.com/jjackbauer" rel="noopener noreferrer"&gt;Ricardo Medeiros&lt;/a&gt;, .NET back end developer @vaivoa, and today I'm going to walk you through using ksqlDB to query messages produced in kafka by a .NET/C# producer. For this example, I will be deploying my enviroment as containers, described in a docker compose file, to ensure easy reproducibility of my results.&lt;/p&gt;

&lt;p&gt;The source code used in this example is avaliable &lt;a href="https://github.com/jjackbauer/ksqlDBDemo" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Services
&lt;/h2&gt;

&lt;p&gt;First, let's talk about the docker compose environment services. the file is avaliable &lt;a href="https://github.com/jjackbauer/ksqlDBDemo/blob/main/docker-compose.yml" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  .NET API Producer
&lt;/h3&gt;

&lt;p&gt;Automaticaly generated .NET api with docker compose service&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ksqldbdemo:
    container_name: ksqldbdemo
    image: ${DOCKER_REGISTRY-}ksqldbdemo
    build:
      context: .
      dockerfile: Dockerfile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This producer service needs the .NET generated dockerfile shown below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["ksqlDBDemo.csproj", "."]
RUN dotnet restore "ksqlDBDemo.csproj"
COPY . .
WORKDIR "/src/"
RUN dotnet build "ksqlDBDemo.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "ksqlDBDemo.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "ksqlDBDemo.dll"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  ZooKeeper
&lt;/h3&gt;

&lt;p&gt;Despite not been necessary since Kafka 2.8, ZooKeeper coordinates kafka tasks, defining controllers, cluster membership, topic configuration and more. In this tutorial, it's used the confluent inc. ZooKeeper image, due to it's use in the reference material. It makes Kafka more reliable, but adds complexity into the system.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;zookeeper:
    image: confluentinc/cp-zookeeper:7.0.0
    hostname: zookeeper
    container_name: zookeeper
    ports:
      - "2181:2181"
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Kafka
&lt;/h3&gt;

&lt;p&gt;Kafka is an event streaming plataform capable of handling trillions of events a day. Kafka is based on the abstraction of an distributed commit log. Initialiy developed at LinkedIn in 2011 to work as a message queue, but it has evolved into a full-fledge event streanming platfmorm. Listed as broker in the services, is the core of this tutorial. It's configuration is tricky, but using it as follows worked well in this scenario.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; broker:
    image: confluentinc/cp-kafka:7.0.0
    hostname: broker
    container_name: broker
    depends_on:
      - zookeeper
    ports:
      - "29092:29092"
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181'
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://broker:29092,PLAINTEXT_HOST://localhost:9092
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  ksqlDB
&lt;/h3&gt;

&lt;p&gt;ksqlDB is a database built to allow distributed stream process applications. Made to work seamsly with kafka, it has a server that runs outside of kafka, with a REST API and a CLI application that can be run separatly and it's used in this tutorial.&lt;/p&gt;
&lt;h4&gt;
  
  
  ksqlDB Server
&lt;/h4&gt;

&lt;p&gt;In this example, it's used the confluent inc image of the ksqlDB server, once more, due to it's widespread usage.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ksqldb-server:
    image: confluentinc/ksqldb-server:0.22.0
    hostname: ksqldb-server
    container_name: ksqldb-server
    depends_on:
      - broker
    ports:
      - "8088:8088"
    environment:
      KSQL_LISTENERS: http://0.0.0.0:8088
      KSQL_BOOTSTRAP_SERVERS: broker:29092
      KSQL_KSQL_LOGGING_PROCESSING_STREAM_AUTO_CREATE: "true"
      KSQL_KSQL_LOGGING_PROCESSING_TOPIC_AUTO_CREATE: "true"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  ksqlDB CLI
&lt;/h4&gt;

&lt;p&gt;The same goes for the ksqlDB CLI service, that also use the confluent inc image.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ksqldb-cli:
    image: confluentinc/ksqldb-cli:0.22.0
    container_name: ksqldb-cli
    depends_on:
      - broker
      - ksqldb-server
    entrypoint: /bin/sh
    tty: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Kafdrop
&lt;/h3&gt;

&lt;p&gt;Kafdrop is a Web UI for viewing kafka topics and browsing consumer groups. It makes kafka more accessible.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kafdrop:
    container_name: kafdrop
    image: obsidiandynamics/kafdrop:latest
    depends_on:
      - broker
    ports:
      - 19000:9000
    environment:
      KAFKA_BROKERCONNECT: broker:29092
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Tutorial
&lt;/h2&gt;

&lt;p&gt;Now it's the time that you have been waiting, let's make it work!&lt;/p&gt;
&lt;h3&gt;
  
  
  Enviroment
&lt;/h3&gt;

&lt;p&gt;For this tutorial, you'll need a &lt;a href="https://docs.docker.com/get-docker/" rel="noopener noreferrer"&gt;docker desktop&lt;/a&gt; installation, either it's on a Linux distribution or on Windows with WSL and &lt;a href="https://git-scm.com/downloads" rel="noopener noreferrer"&gt;git&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Cloning the project
&lt;/h3&gt;

&lt;p&gt;A Visual Studio project is avaliable &lt;a href="https://github.com/jjackbauer/ksqlDBDemo" rel="noopener noreferrer"&gt;here&lt;/a&gt;, it has docker support and already deploys all the services needed for this demo in the IDE. However, you will be fine if you don't want or can't use Visual Studio. Just  clone it, running the following comand on the terminal and directory of your preference:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; $ git clone https://github.com/jjackbauer/ksqlDBDemo.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Use the following command to move to the project folder:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; $ cd /ksqlDBDemo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And, in the project folder, that contains the docker-compose.yml run the following command to deploy the services:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker compose up -d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;after this command, make sure that all services are running. Sometimes services fall, but it is okay. In order to see if everything is running ok, it's possible to see the services running in docker desktop, as shown bellow:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3uakexrf3p7atec8q7k9.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3uakexrf3p7atec8q7k9.PNG" alt="Docker Desktop" width="799" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or you can execute the following command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Which should output something 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;CONTAINER ID   IMAGE                               COMMAND                  CREATED       STATUS       PORTS
  NAMES
b42ce9954fd9   ksqldbdemo_ksqldbdemo               "dotnet ksqlDBDemo.d…"   2 hours ago   Up 2 hours   0.0.0.0:9009-&amp;gt;80/tcp, 0.0.0.0:52351-&amp;gt;443/tcp   ksqldbdemo
0a0186712553   confluentinc/ksqldb-cli:0.22.0      "/bin/sh"                2 hours ago   Up 2 hours
  ksqldb-cli
76519de6946e   obsidiandynamics/kafdrop:latest     "/kafdrop.sh"            2 hours ago   Up 2 hours   0.0.0.0:19000-&amp;gt;9000/tcp
  kafdrop
11c3a306ee01   confluentinc/ksqldb-server:0.22.0   "/usr/bin/docker/run"    2 hours ago   Up 2 hours   0.0.0.0:8088-&amp;gt;8088/tcp
  ksqldb-server
07cef9d69267   confluentinc/cp-kafka:7.0.0         "/etc/confluent/dock…"   2 hours ago   Up 2 hours   9092/tcp, 0.0.0.0:29092-&amp;gt;29092/tcp
  broker
3fa1b9a60954   confluentinc/cp-zookeeper:7.0.0     "/etc/confluent/dock…"   2 hours ago   Up 2 hours   2888/tcp, 0.0.0.0:2181-&amp;gt;2181/tcp, 3888/tcp     zookeeper
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  WEB API
&lt;/h3&gt;

&lt;p&gt;Now, with all services up and running, we can access the WEB API Swagger to populate our Kafka topics. The code is very simple and it's avaliable in the &lt;a href="https://github.com/jjackbauer/ksqlDBDemo" rel="noopener noreferrer"&gt;repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The WEB API swagger is deployed at &lt;a href="http://localhost:9009/swagger/index.html" rel="noopener noreferrer"&gt;http://localhost:9009/swagger/index.html&lt;/a&gt;. As shown in the image bellow, it has two endpoints and they create events that could be created by indepent microservices. One for creating an event that creates a userName in the system and another that takes an Id and generates a three digit code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F99l7s38ffu0tx1gon62r.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F99l7s38ffu0tx1gon62r.PNG" alt="Swagger Geral" width="799" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then you can create an User with the user name of your choise, as shown:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmxlhjsmfeei7wnym834g.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmxlhjsmfeei7wnym834g.PNG" alt="Request Create user" width="799" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And it will have an assigned unique Id, as demonstrated:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3g06gff8025nxw6gze9v.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3g06gff8025nxw6gze9v.PNG" alt="Response create user" width="799" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, you can get a three digit code for your user Id as displayed:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6yoezrw53wibte9baiaj.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6yoezrw53wibte9baiaj.PNG" alt="Get Code Request" width="799" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And a random code is generated for the selectd, as we can observe in the image that follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazp6yri8cy4x4day7vyu.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazp6yri8cy4x4day7vyu.PNG" alt="Get Code Response" width="799" height="426"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Kafdrop
&lt;/h3&gt;

&lt;p&gt;We can use the kafdrop UI the check if everything is okay. Kafdrop is deployed at &lt;a href="http://localhost:19000/" rel="noopener noreferrer"&gt;http://localhost:19000/&lt;/a&gt;.&lt;br&gt;
There, you will find all the brokers and topics avaliable. It should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy9v29cx12cqw5cnp19sr.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy9v29cx12cqw5cnp19sr.PNG" alt="Kafdrop" width="799" height="426"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  KSQL CLI
&lt;/h3&gt;

&lt;p&gt;After all that, you'll be able to create your streams of data and query it using ksqlDB. On your preferential terminal, use the command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker exec -it ksqldb-cli ksql http://ksqldb-server:8088
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Creating streams
&lt;/h4&gt;

&lt;p&gt;And then you are in the ksql CLI and are free to create your streams and queries. First, let's create a stream for each one of our topics:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE STREAM stream_user (Name VARCHAR, Id VARCHAR)
  WITH (kafka_topic='demo-user', value_format='json', partitions=1);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE STREAM stream_code (Id VARCHAR, code INT)
  WITH (kafka_topic='demo-code', value_format='json', partitions=1);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Create a materialized view
&lt;/h4&gt;

&lt;p&gt;You can join the client data with the most recent randomized code. to achieve this, you must create a materialized view table, that joins both streams as seen in the ksqldb script that follows:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE currentCodeView AS
&amp;gt;   SELECT user.Name,
&amp;gt;   LATEST_BY_OFFSET(code.code) AS CurrentCode
&amp;gt;   FROM stream_code code INNER JOIN stream_user user
&amp;gt;   WITHIN 7 DAYS ON code.Id = user.Id
&amp;gt;   GROUP BY user.Name
&amp;gt;EMIT CHANGES;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Making a push query
&lt;/h4&gt;

&lt;p&gt;After that, we can query this materialized view:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM currentCodeView 
  EMIT CHANGES;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This push query keep on running until you hit cntrl+c to cancel it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;In this tutorial it's demonstrated that in a kafka + ksqlDB enviroment, you can make SQL queries and also join on data that comes from different events, which is one of most complexities envolved with microsservices systems. And it is what ksqlDB solves by enabling SQL operations over Kafka topics.&lt;br&gt;
It's my goal to explore the possibilites allowed by this ecosystem and I hope to bring more knowledge on this topic in another articles here. Any sugestions, comments or corrections, fell free to reach me out at &lt;a href="https://www.linkedin.com/in/rmedio/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag__user ltag__user__id__757631"&gt;
    &lt;a href="/jjackbauer" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=150,height=150,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F757631%2F76940fdf-9f04-4bd8-9217-d577d788ffef.jpeg" alt="jjackbauer image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/jjackbauer"&gt;Ricardo Medeiros&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/jjackbauer"&gt;Staff Backend Engineer | AI Frist Migration @Context Forge&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://ksqldb.io/quickstart.html?_ga=2.218008467.482211024.1638022122-847939024.1633623088&amp;amp;_gac=1.142412294.1634140787.EAIaIQobChMIjOL6pt_H8wIVmcWaCh1KbwgwEAEYASAAEgLBFvD_BwE" rel="noopener noreferrer"&gt;ksqlDB Quickstart&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.confluent.io/platform/current/ksqldb/index.html#ksql-home" rel="noopener noreferrer"&gt;ksqlDB Overview&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.confluent.io/clients-confluent-kafka-dotnet/current/overview.html" rel="noopener noreferrer"&gt;Kafka .NET Client&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.ksqldb.io/en/latest/reference/sql/data-types/" rel="noopener noreferrer"&gt;ksqlDB Documentation - Data Types Overview&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.ksqldb.io/en/latest/operate-and-deploy/ksql-vs-ksqldb/" rel="noopener noreferrer"&gt;KSQL and ksqlDB&lt;/a&gt;&lt;br&gt;
&lt;a href="https://zookeeper.apache.org/" rel="noopener noreferrer"&gt;Welcome to Apache ZooKeeper&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dattell.com/data-architecture-blog/what-is-zookeeper-how-does-it-support-kafka/" rel="noopener noreferrer"&gt;What is ZooKeeper &amp;amp; How Does it Support Kafka?&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.confluent.io/what-is-apache-kafka/?utm_medium=sem&amp;amp;utm_source=google&amp;amp;utm_campaign=ch.sem_br.nonbrand_tp.prs_tgt.kafka_mt.xct_rgn.latam_lng.eng_dv.all_con.kafka-general&amp;amp;utm_term=apache%20kafka&amp;amp;creative=&amp;amp;device=c&amp;amp;placement=&amp;amp;gcli&lt;br&gt;%0Ad=Cj0KCQiA7oyNBhDiARIsADtGRZYDVaYjkPkoJQHNrz_xBodIq2P8ztwb8g3OTiRG_wMHXyzof1nqKEMaAoT_EALw_wcB" rel="noopener noreferrer"&gt;What is Apache Kafka®?&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ksqldb.io/" rel="noopener noreferrer"&gt;ksqlDB - The database purpose-built for stream processing applications&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ksqldb.io/overview.html" rel="noopener noreferrer"&gt;An overview of ksqlDB&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.ksqldb.io/en/latest/developer-guide/ksqldb-reference/create-table-as-select/" rel="noopener noreferrer"&gt;CREATE TABLE AS SELECT&lt;/a&gt;&lt;br&gt;
&lt;a href="https://kafka-tutorials.confluent.io/join-a-stream-to-a-stream/ksql.html" rel="noopener noreferrer"&gt;How to join a stream and a stream&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.ksqldb.io/en/latest/concepts/time-and-windows-in-ksqldb-queries/" rel="noopener noreferrer"&gt;Time and Windows in ksqlDB Queries&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.ksqldb.io/en/latest/reference/sql/time/" rel="noopener noreferrer"&gt;Time operations&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn8bndcx2jkn1jz1dy98v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn8bndcx2jkn1jz1dy98v.png" alt="linha horizontal" width="768" height="3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Disclaimer
&lt;/h1&gt;

&lt;p&gt;A VaiVoa incentiva seus Desenvolvedores em seu processo de crescimento e aceleração técnica. Os artigos publicados não traduzem a opinião da VaiVoa. A publicação obedece ao propósito de estimular o debate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1wmziqv74ghhgyi9p0om.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1wmziqv74ghhgyi9p0om.png" alt="logo vaivoa" width="548" height="122"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kafka</category>
      <category>ksqldb</category>
      <category>microservices</category>
      <category>docker</category>
    </item>
    <item>
      <title>KAFKA + KSQLDB + .NET #1</title>
      <dc:creator>Ricardo Medeiros</dc:creator>
      <pubDate>Mon, 29 Nov 2021 20:13:06 +0000</pubDate>
      <link>https://dev.to/jjackbauer/kafka-ksqldb-net-19kc</link>
      <guid>https://dev.to/jjackbauer/kafka-ksqldb-net-19kc</guid>
      <description>&lt;p&gt;Hi, I'm &lt;a href="https://github.com/jjackbauer" rel="noopener noreferrer"&gt;Ricardo Medeiros&lt;/a&gt;, .NET back end developer @vaivoa, and today I'm going to walk you through using ksqlDB to query messages produced in kafka by a .NET/C# producer. For this example, I will be deploying my enviroment as containers, described in a docker compose file, to ensure easy reproducibility of my results.&lt;/p&gt;

&lt;p&gt;The source code used in this example is avaliable &lt;a href="https://github.com/jjackbauer/ksqlDBDemo" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Services
&lt;/h2&gt;

&lt;p&gt;First, let's talk about the docker compose environment services. the file is avaliable &lt;a href="https://github.com/jjackbauer/ksqlDBDemo/blob/main/docker-compose.yml" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  .NET API Producer
&lt;/h3&gt;

&lt;p&gt;Automaticaly generated .NET api with docker compose service&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ksqldbdemo:
    container_name: ksqldbdemo
    image: ${DOCKER_REGISTRY-}ksqldbdemo
    build:
      context: .
      dockerfile: Dockerfile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This producer service needs the .NET generated dockerfile shown below:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build
WORKDIR /src
COPY ["ksqlDBDemo.csproj", "."]
RUN dotnet restore "ksqlDBDemo.csproj"
COPY . .
WORKDIR "/src/"
RUN dotnet build "ksqlDBDemo.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "ksqlDBDemo.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "ksqlDBDemo.dll"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  ZooKeeper
&lt;/h3&gt;

&lt;p&gt;Despite not been necessary since Kafka 2.8, ZooKeeper coordinates kafka tasks, defining controllers, cluster membership, topic configuration and more. In this tutorial, it's used the confluent inc. ZooKeeper image, due to it's use in the reference material. It makes Kafka more reliable, but adds complexity into the system.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;zookeeper:
    image: confluentinc/cp-zookeeper:7.0.0
    hostname: zookeeper
    container_name: zookeeper
    ports:
      - "2181:2181"
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Kafka
&lt;/h3&gt;

&lt;p&gt;Kafka is an event streaming plataform capable of handling trillions of events a day. Kafka is based on the abstraction of an distributed commit log. Initialiy developed at LinkedIn in 2011 to work as a message queue, but it has evolved into a full-fledge event streanming platfmorm. Listed as broker in the services, is the core of this tutorial. It's configuration is tricky, but using it as follows worked well in this scenario.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; broker:
    image: confluentinc/cp-kafka:7.0.0
    hostname: broker
    container_name: broker
    depends_on:
      - zookeeper
    ports:
      - "29092:29092"
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181'
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://broker:29092,PLAINTEXT_HOST://localhost:9092
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  ksqlDB
&lt;/h3&gt;

&lt;p&gt;ksqlDB is a database built to allow distributed stream process applications. Made to work seamsly with kafka, it has a server that runs outside of kafka, with a REST API and a CLI application that can be run separatly and it's used in this tutorial.&lt;/p&gt;
&lt;h4&gt;
  
  
  ksqlDB Server
&lt;/h4&gt;

&lt;p&gt;In this example, it's used the confluent inc image of the ksqlDB server, once more, due to it's widespread usage.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ksqldb-server:
    image: confluentinc/ksqldb-server:0.22.0
    hostname: ksqldb-server
    container_name: ksqldb-server
    depends_on:
      - broker
    ports:
      - "8088:8088"
    environment:
      KSQL_LISTENERS: http://0.0.0.0:8088
      KSQL_BOOTSTRAP_SERVERS: broker:29092
      KSQL_KSQL_LOGGING_PROCESSING_STREAM_AUTO_CREATE: "true"
      KSQL_KSQL_LOGGING_PROCESSING_TOPIC_AUTO_CREATE: "true"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  ksqlDB CLI
&lt;/h4&gt;

&lt;p&gt;The same goes for the ksqlDB CLI service, that also use the confluent inc image.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ksqldb-cli:
    image: confluentinc/ksqldb-cli:0.22.0
    container_name: ksqldb-cli
    depends_on:
      - broker
      - ksqldb-server
    entrypoint: /bin/sh
    tty: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Kafdrop
&lt;/h3&gt;

&lt;p&gt;Kafdrop is a Web UI for viewing kafka topics and browsing consumer groups. It makes kafka more accessible.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kafdrop:
    container_name: kafdrop
    image: obsidiandynamics/kafdrop:latest
    depends_on:
      - broker
    ports:
      - 19000:9000
    environment:
      KAFKA_BROKERCONNECT: broker:29092
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Tutorial
&lt;/h2&gt;

&lt;p&gt;Now it's the time that you have been waiting, let's make it work!&lt;/p&gt;
&lt;h3&gt;
  
  
  Enviroment
&lt;/h3&gt;

&lt;p&gt;For this tutorial, you'll need a &lt;a href="https://docs.docker.com/get-docker/" rel="noopener noreferrer"&gt;docker desktop&lt;/a&gt; installation, either it's on a Linux distribution or on Windows with WSL and &lt;a href="https://git-scm.com/downloads" rel="noopener noreferrer"&gt;git&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Cloning the project
&lt;/h3&gt;

&lt;p&gt;A Visual Studio project is avaliable &lt;a href="https://github.com/jjackbauer/ksqlDBDemo" rel="noopener noreferrer"&gt;here&lt;/a&gt;, it has docker support and already deploys all the services needed for this demo in the IDE. However, you will be fine if you don't want or can't use Visual Studio. Just  clone it, running the following comand on the terminal and directory of your preference:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; $ git clone https://github.com/jjackbauer/ksqlDBDemo.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Use the following command to move to the project folder:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; $ cd /ksqlDBDemo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;And, in the project folder, that contains the docker-compose.yml run the following command to deploy the services:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker compose up -d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;after this command, make sure that all services are running. Sometimes services fall, but it is okay. In order to see if everything is running ok, it's possible to see the services running in docker desktop, as shown bellow:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3uakexrf3p7atec8q7k9.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3uakexrf3p7atec8q7k9.PNG" alt="Docker Desktop" width="799" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or you can execute the following command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Which should output something 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;CONTAINER ID   IMAGE                               COMMAND                  CREATED       STATUS       PORTS
  NAMES
b42ce9954fd9   ksqldbdemo_ksqldbdemo               "dotnet ksqlDBDemo.d…"   2 hours ago   Up 2 hours   0.0.0.0:9009-&amp;gt;80/tcp, 0.0.0.0:52351-&amp;gt;443/tcp   ksqldbdemo
0a0186712553   confluentinc/ksqldb-cli:0.22.0      "/bin/sh"                2 hours ago   Up 2 hours
  ksqldb-cli
76519de6946e   obsidiandynamics/kafdrop:latest     "/kafdrop.sh"            2 hours ago   Up 2 hours   0.0.0.0:19000-&amp;gt;9000/tcp
  kafdrop
11c3a306ee01   confluentinc/ksqldb-server:0.22.0   "/usr/bin/docker/run"    2 hours ago   Up 2 hours   0.0.0.0:8088-&amp;gt;8088/tcp
  ksqldb-server
07cef9d69267   confluentinc/cp-kafka:7.0.0         "/etc/confluent/dock…"   2 hours ago   Up 2 hours   9092/tcp, 0.0.0.0:29092-&amp;gt;29092/tcp
  broker
3fa1b9a60954   confluentinc/cp-zookeeper:7.0.0     "/etc/confluent/dock…"   2 hours ago   Up 2 hours   2888/tcp, 0.0.0.0:2181-&amp;gt;2181/tcp, 3888/tcp     zookeeper
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  WEB API
&lt;/h3&gt;

&lt;p&gt;Now, with all services up and running, we can access the WEB API Swagger to populate our Kafka topics. The code is very simple and it's avaliable in the &lt;a href="https://github.com/jjackbauer/ksqlDBDemo" rel="noopener noreferrer"&gt;repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The WEB API swagger is deployed at &lt;a href="http://localhost:9009/swagger/index.html" rel="noopener noreferrer"&gt;http://localhost:9009/swagger/index.html&lt;/a&gt;. As shown in the image bellow, it has two endpoints and they create events that could be created by indepent microservices. One for creating an event that creates a userName in the system and another that takes an Id and generates a three digit code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F99l7s38ffu0tx1gon62r.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F99l7s38ffu0tx1gon62r.PNG" alt="Swagger Geral" width="799" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then you can create an User with the user name of your choise, as shown:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmxlhjsmfeei7wnym834g.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmxlhjsmfeei7wnym834g.PNG" alt="Request Create user" width="799" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And it will have an assigned unique Id, as demonstrated:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3g06gff8025nxw6gze9v.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3g06gff8025nxw6gze9v.PNG" alt="Response create user" width="799" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, you can get a three digit code for your user Id as displayed:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6yoezrw53wibte9baiaj.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6yoezrw53wibte9baiaj.PNG" alt="Get Code Request" width="799" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And a random code is generated for the selectd, as we can observe in the image that follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazp6yri8cy4x4day7vyu.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazp6yri8cy4x4day7vyu.PNG" alt="Get Code Response" width="799" height="426"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Kafdrop
&lt;/h3&gt;

&lt;p&gt;We can use the kafdrop UI the check if everything is okay. Kafdrop is deployed at &lt;a href="http://localhost:19000/" rel="noopener noreferrer"&gt;http://localhost:19000/&lt;/a&gt;.&lt;br&gt;
There, you will find all the brokers and topics avaliable. It should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy9v29cx12cqw5cnp19sr.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy9v29cx12cqw5cnp19sr.PNG" alt="Kafdrop" width="799" height="426"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  KSQL CLI
&lt;/h3&gt;

&lt;p&gt;After all that, you'll be able to create your streams of data and query it using ksqlDB. On your preferential terminal, use the command:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker exec -it ksqldb-cli ksql http://ksqldb-server:8088
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Creating streams
&lt;/h4&gt;

&lt;p&gt;And then you are in the ksql CLI and are free to create your streams and queries. First, let's create a stream for each one of our topics:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE STREAM stream_user (Name VARCHAR, Id VARCHAR)
  WITH (kafka_topic='demo-user', value_format='json', partitions=1);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE STREAM stream_code (Id VARCHAR, code INT)
  WITH (kafka_topic='demo-code', value_format='json', partitions=1);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Create a materialized view
&lt;/h4&gt;

&lt;p&gt;You can join the client data with the most recent randomized code. to achieve this, you must create a materialized view table, that joins both streams as seen in the ksqldb script that follows:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE currentCodeView AS
&amp;gt;   SELECT user.Name,
&amp;gt;   LATEST_BY_OFFSET(code.code) AS CurrentCode
&amp;gt;   FROM stream_code code INNER JOIN stream_user user
&amp;gt;   WITHIN 7 DAYS ON code.Id = user.Id
&amp;gt;   GROUP BY user.Name
&amp;gt;EMIT CHANGES;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Making a push query
&lt;/h4&gt;

&lt;p&gt;After that, we can query this materialized view:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM currentCodeView 
  EMIT CHANGES;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This push query keep on running until you hit cntrl+c to cancel it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;In this tutorial it's demonstrated that in a kafka + ksqlDB enviroment, you can make SQL queries and also join on data that comes from different events, which is one of most complexities envolved with microsservices systems. And it is what ksqlDB solves by enabling SQL operations over Kafka topics.&lt;br&gt;
It's my goal to explore the possibilites allowed by this ecosystem and I hope to bring more knowledge on this topic in another articles here. Any sugestions, comments or corrections, fell free to reach me out at &lt;a href="https://www.linkedin.com/in/rmedio/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag__user ltag__user__id__757631"&gt;
    &lt;a href="/jjackbauer" class="ltag__user__link profile-image-link"&gt;
      &lt;div class="ltag__user__pic"&gt;
        &lt;img src="https://media2.dev.to/dynamic/image/width=150,height=150,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F757631%2F76940fdf-9f04-4bd8-9217-d577d788ffef.jpeg" alt="jjackbauer image"&gt;
      &lt;/div&gt;
    &lt;/a&gt;
  &lt;div class="ltag__user__content"&gt;
    &lt;h2&gt;
&lt;a class="ltag__user__link" href="/jjackbauer"&gt;Ricardo Medeiros&lt;/a&gt;Follow
&lt;/h2&gt;
    &lt;div class="ltag__user__summary"&gt;
      &lt;a class="ltag__user__link" href="/jjackbauer"&gt;Staff Backend Engineer | AI Frist Migration @Context Forge&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://ksqldb.io/quickstart.html?_ga=2.218008467.482211024.1638022122-847939024.1633623088&amp;amp;_gac=1.142412294.1634140787.EAIaIQobChMIjOL6pt_H8wIVmcWaCh1KbwgwEAEYASAAEgLBFvD_BwE" rel="noopener noreferrer"&gt;ksqlDB Quickstart&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.confluent.io/platform/current/ksqldb/index.html#ksql-home" rel="noopener noreferrer"&gt;ksqlDB Overview&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.confluent.io/clients-confluent-kafka-dotnet/current/overview.html" rel="noopener noreferrer"&gt;Kafka .NET Client&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.ksqldb.io/en/latest/reference/sql/data-types/" rel="noopener noreferrer"&gt;ksqlDB Documentation - Data Types Overview&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.ksqldb.io/en/latest/operate-and-deploy/ksql-vs-ksqldb/" rel="noopener noreferrer"&gt;KSQL and ksqlDB&lt;/a&gt;&lt;br&gt;
&lt;a href="https://zookeeper.apache.org/" rel="noopener noreferrer"&gt;Welcome to Apache ZooKeeper&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dattell.com/data-architecture-blog/what-is-zookeeper-how-does-it-support-kafka/" rel="noopener noreferrer"&gt;What is ZooKeeper &amp;amp; How Does it Support Kafka?&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.confluent.io/what-is-apache-kafka/?utm_medium=sem&amp;amp;utm_source=google&amp;amp;utm_campaign=ch.sem_br.nonbrand_tp.prs_tgt.kafka_mt.xct_rgn.latam_lng.eng_dv.all_con.kafka-general&amp;amp;utm_term=apache%20kafka&amp;amp;creative=&amp;amp;device=c&amp;amp;placement=&amp;amp;gcli&lt;br&gt;%0Ad=Cj0KCQiA7oyNBhDiARIsADtGRZYDVaYjkPkoJQHNrz_xBodIq2P8ztwb8g3OTiRG_wMHXyzof1nqKEMaAoT_EALw_wcB" rel="noopener noreferrer"&gt;What is Apache Kafka®?&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ksqldb.io/" rel="noopener noreferrer"&gt;ksqlDB - The database purpose-built for stream processing applications&lt;/a&gt;&lt;br&gt;
&lt;a href="https://ksqldb.io/overview.html" rel="noopener noreferrer"&gt;An overview of ksqlDB&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.ksqldb.io/en/latest/developer-guide/ksqldb-reference/create-table-as-select/" rel="noopener noreferrer"&gt;CREATE TABLE AS SELECT&lt;/a&gt;&lt;br&gt;
&lt;a href="https://kafka-tutorials.confluent.io/join-a-stream-to-a-stream/ksql.html" rel="noopener noreferrer"&gt;How to join a stream and a stream&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.ksqldb.io/en/latest/concepts/time-and-windows-in-ksqldb-queries/" rel="noopener noreferrer"&gt;Time and Windows in ksqlDB Queries&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.ksqldb.io/en/latest/reference/sql/time/" rel="noopener noreferrer"&gt;Time operations&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kafka</category>
      <category>ksqldb</category>
      <category>microservices</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
