<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://ted.dev/">
  <title>Ted M. Young&#39;s Confident Coding Blog</title>
  <subtitle>I write about automated developer tests, test-driven development, refactoring, testable architectures, and other ways to be more confident in your code.</subtitle>
  <link href="https://ted.dev/feed.xml" rel="self"/>
  <link href="https://ted.dev/"/>
  <updated>2026-07-04T03:01:41Z</updated>
  <id>https://ted.dev/</id>
  <author>
    <name>Ted M. Young</name>
    <email>rssfeed@ted.dev</email>
  </author>
  <entry>
    <title>Live Coding Journal - Apr 15, 2026</title>
    <link href="https://ted.dev/articles/2026/04/15/live-coding-journal-apr-15-2026/"/>
    <updated>2026-04-15T10:00:00Z</updated>
    <id>https://ted.dev/articles/2026/04/15/live-coding-journal-apr-15-2026/</id>
    <content xml:lang="en" type="html">&lt;div class=&quot;meta-notes-card&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All the code I’m working on in my live coding stream is available at &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced&quot;&gt;https://github.com/jitterted/jitterticket-event-sourced&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Notes from the last two weeks of streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/04/02/live-coding-journal-apr-2-2026/&quot;&gt;Apr 2, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/04/06/live-coding-journal-apr-6-2026/&quot;&gt;Apr 6, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/04/07/live-coding-journal-apr-7-2026/&quot;&gt;Apr 7, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/04/13/live-coding-journal-apr-13-2026/&quot;&gt;Apr 13, 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;notes-from-today%E2%80%99s-live-coding-session&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/15/live-coding-journal-apr-15-2026/#notes-from-today%E2%80%99s-live-coding-session&quot;&gt;Notes from Today’s Live Coding Session&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;coordinator-and-concurrency&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/15/live-coding-journal-apr-15-2026/#coordinator-and-concurrency&quot;&gt;Coordinator and Concurrency&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This stream was mostly focused on transitioning to the new Projector design, where the &lt;code&gt;DomainProjector&lt;/code&gt; is responsible for both caching its state (this speeds up handling new events) and tracking changes, or “delta” (so changes in its state can be easily persisted).
It brought up some issues around what code is responsible for initializing the projector, i.e., loading its initial state.
In the “old” &lt;code&gt;ProjectionCoordinator&lt;/code&gt;, this was done in its constructor.
I didn’t care for doing so much work in the constructor, i.e., catching up on possibly thousands of events if the projector is new, but it worked.
Now that the &lt;code&gt;ProjectionCoordinator&lt;/code&gt; seems to be dissolving, the initialization will move to some Factory-like class, so that it can be called by Configuration as well as from tests.&lt;/p&gt;
&lt;p&gt;I’ve been concerned about the potential concurrency issues with the &lt;code&gt;NewDomainProjector&lt;/code&gt;’s &lt;code&gt;flush()&lt;/code&gt; method–where it has to return both the delta and the Checkpoint value in one call (now as a &lt;code&gt;CheckpointedDelta&lt;/code&gt; record), but as I continued to work on other aspects, I wonder if that’s an actual problem.
The question about concurrency brought up by viewer &lt;em&gt;@postmodernusturup&lt;/em&gt; (around 54m48s in the video) triggered deeper thought into this area.&lt;/p&gt;
&lt;h3 id=&quot;reverse-olive-maneuver&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/15/live-coding-journal-apr-15-2026/#reverse-olive-maneuver&quot;&gt;Reverse-Olive Maneuver&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You may be familiar with what I call an “Olive Test”, i.e., a test that fails, but for the (predicted) correct reason.
In today’s stream, I did the reverse (inverse?) of this (around 2h00m): modifying the code (changing it or commenting it out) and successfully predicting how the test would fail.
It’s very much like mutation testing but focused on a specific piece of code and just a test or two.
The underlying principle is the same: making sure we understand how the code behaves and how the tests are checking that behavior.&lt;/p&gt;
&lt;h3 id=&quot;repurposing-tests-as-specification&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/15/live-coding-journal-apr-15-2026/#repurposing-tests-as-specification&quot;&gt;Repurposing Tests as Specification&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I also showed (around 2h04m) how sometimes you can use tests against one implementation (&lt;code&gt;ProjectionCoordinator&lt;/code&gt;) as a specification for a different implementation (&lt;code&gt;NewProjectionCoordinator&lt;/code&gt;), but that it isn’t TDD.
Though you will likely enable one new test at a time (vs. trying to get the implementation to pass all the specification tests at once), you’re no longer using the tests to drive the exploration of the design space.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/15/live-coding-journal-apr-15-2026/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’ll finish moving the initialization of the Projector, wire it up to the Spring configuration, and check if everything still works.
Then it’s probably time to see if we like the new design and, if so, get rid of the old implementations.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Join me on my next stream, which I usually do Monday through Thursday, starting at 19:00 UTC on Twitch: &lt;a href=&quot;https://jitterted.stream/&quot;&gt;https://jitterted.stream&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Live Coding Journal - Apr 13, 2026</title>
    <link href="https://ted.dev/articles/2026/04/13/live-coding-journal-apr-13-2026/"/>
    <updated>2026-04-13T10:00:00Z</updated>
    <id>https://ted.dev/articles/2026/04/13/live-coding-journal-apr-13-2026/</id>
    <content xml:lang="en" type="html">&lt;div class=&quot;meta-notes-card&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All the code I’m working on in my live coding stream is available at &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced&quot;&gt;https://github.com/jitterted/jitterticket-event-sourced&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Notes from the last two weeks of streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/03/30/live-coding-journal-mar-30-2026/&quot;&gt;Mar 30, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/04/02/live-coding-journal-apr-2-2026/&quot;&gt;Apr 2, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/04/06/live-coding-journal-apr-6-2026/&quot;&gt;Apr 6, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/04/07/live-coding-journal-apr-7-2026/&quot;&gt;Apr 7, 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;notes-from-today%E2%80%99s-live-coding-session&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/13/live-coding-journal-apr-13-2026/#notes-from-today%E2%80%99s-live-coding-session&quot;&gt;Notes from Today’s Live Coding Session&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Today’s stream was mostly mundane (and a bit frustrating) refactoring.
At one point (around 1h32m) I did a revert to redo the refactoring as I had painted myself in a bit of a corner.&lt;/p&gt;
&lt;p&gt;One thing I did realize is that while the &lt;code&gt;flush()&lt;/code&gt; method in the “new” Domain Projector returns the “delta” state, that state should not include the Checkpoint.
The Checkpoint is a property of the Projector, not the state, so instead it should return Delta+Checkpoint, aka &lt;code&gt;CheckpointedDelta&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;NewDomainProjector&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;STATE&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DELTA &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ProjectionDelta&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;EventHandler&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;STATE&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;currentState&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;/**
   * Returns any uncommitted changes in the projection,
   * clearing it as a result.
   *
   * @return uncommitted changes since the last time flush was called,
   * or since the projector was instantiated
   */&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DELTA&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;flush&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token comment&quot;&gt;/**
   * Checkpoint for the most recent event sequence processed by this projector.
   *
   * @return the last event sequence processed, or Checkpoint.INITIAL if none have been processed
   */&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Checkpoint&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;checkpoint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/13/live-coding-journal-apr-13-2026/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Finish up the “new” projection coordinator persistence and then see what’s left to do before (finally!) returning to work on the TDD Game online version.&lt;/p&gt;
&lt;p&gt;Join me on my next stream, which I usually do Monday through Thursday, starting at 19:00 UTC on Twitch: &lt;a href=&quot;https://jitterted.stream/&quot;&gt;https://jitterted.stream&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Live Coding Journal - Apr 7, 2026</title>
    <link href="https://ted.dev/articles/2026/04/07/live-coding-journal-apr-7-2026/"/>
    <updated>2026-04-07T10:00:00Z</updated>
    <id>https://ted.dev/articles/2026/04/07/live-coding-journal-apr-7-2026/</id>
    <content xml:lang="en" type="html">&lt;div class=&quot;meta-notes-card&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All the code I’m working on in my live coding stream is available at &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced&quot;&gt;https://github.com/jitterted/jitterticket-event-sourced&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Notes from the last two weeks of streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/03/24/live-coding-journal-mar-24-2026/&quot;&gt;Mar 24, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/03/25/live-coding-journal-mar-25-2026/&quot;&gt;Mar 25, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/03/30/live-coding-journal-mar-30-2026/&quot;&gt;Mar 30, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/04/02/live-coding-journal-apr-2-2026/&quot;&gt;Apr 2, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/04/06/live-coding-journal-apr-6-2026/&quot;&gt;Apr 6, 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;notes-from-today%E2%80%99s-live-coding-session&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/07/live-coding-journal-apr-7-2026/#notes-from-today%E2%80%99s-live-coding-session&quot;&gt;Notes from Today’s Live Coding Session&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;moving-away-from-aggregate-focused-types&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/07/live-coding-journal-apr-7-2026/#moving-away-from-aggregate-focused-types&quot;&gt;Moving Away from Aggregate-Focused Types&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I started the stream innocently enough, renaming &lt;code&gt;EventConsumer&lt;/code&gt; to the better-named &lt;code&gt;EventStreamConsumer&lt;/code&gt;, since it is responsible for handling a potential Stream of Events, as shown by its interface:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;EventStreamConsumer&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Stream&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; eventStream&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This better separates its responsibility from &lt;code&gt;EventHandler&lt;/code&gt;, which is responsible for implementing individual &lt;code&gt;handle()&lt;/code&gt; methods for specific Event types.&lt;/p&gt;
&lt;p&gt;You may have noticed that I dropped the generic &lt;code&gt;EVENT&lt;/code&gt; type, replacing it with &lt;code&gt;? extends Event&lt;/code&gt;).
This is a step in moving away from an Aggregate-centric view of things, where a hierarchy of events relates to specific Aggregates.
For example, where &lt;code&gt;ConcertEvent&lt;/code&gt;, associated with the Aggregate &lt;code&gt;Concert&lt;/code&gt;, is the parent class of &lt;code&gt;ConcertScheduled&lt;/code&gt;, &lt;code&gt;TicketsSold&lt;/code&gt;, etc., and &lt;code&gt;CustomerEvent&lt;/code&gt; (for &lt;code&gt;Customer&lt;/code&gt;) is the parent of &lt;code&gt;CustomerRegistered&lt;/code&gt;, &lt;code&gt;TicketsPurchased&lt;/code&gt;, etc.
As I continue to move towards an Event-centric view, the generic type gets in the way, since, for example, we may have &lt;code&gt;EventStreamConsumer&lt;/code&gt;s that want to consume both &lt;code&gt;ConcertScheduled&lt;/code&gt; and &lt;code&gt;CustomerRegistered&lt;/code&gt; (for whatever reason).
Eventually this will ripple out so that there is only one &lt;code&gt;EventStore&lt;/code&gt; instance, instead of having one per Aggregate, e.g., &lt;code&gt;EventStore&amp;lt;Concert,...&amp;gt;&lt;/code&gt; and &lt;code&gt;EventStore&amp;lt;Customer,...&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;eventstore-subscription-for-desired-events&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/07/live-coding-journal-apr-7-2026/#eventstore-subscription-for-desired-events&quot;&gt;EventStore Subscription for Desired Events&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;My main goal this stream was to have all &lt;code&gt;EventStreamConsumer&lt;/code&gt; subscriptions to the EventStore specify their desired events to improve performance, as well as making it clear in the code which events it wants:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;subscribe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;EventStreamConsumer&lt;/span&gt; eventStreamConsumer&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
               &lt;span class=&quot;token class-name&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; desiredEvents&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and deprecating the existing &lt;code&gt;subscribe(EventStreamConsumer)&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An “Olive” Failure Moment&lt;/strong&gt; (1h01m)&lt;/p&gt;
&lt;p&gt;During test-driving this change, Predictive TDD (predicting precisely how a test would fail) once again saved the day.
In my test, I was using my &lt;code&gt;MakeEvents&lt;/code&gt; builder to set up the events for the test, and then passed those events to the EventStore’s &lt;code&gt;save(ID aggregateId, Stream&amp;lt;EVENT&amp;gt; uncommittedEvents)&lt;/code&gt; method.
However, instead of expecting the test to fail by sending all events to the consumer (as I hadn’t yet implemented the filtering), no events were sent at all.
This was surprising, because I had thought that &lt;code&gt;save()&lt;/code&gt; method would send the events along to any consumers.
It turns out, the &lt;code&gt;save(AGGREGATE aggregate)&lt;/code&gt; method (that takes an entire Aggregate) is what sends events on to consumers.
The &lt;code&gt;save(ID, Stream&amp;lt;Event&amp;gt;)&lt;/code&gt; is more of an internal method, but because it is currently &lt;code&gt;public&lt;/code&gt;, I had a misunderstanding of its responsibility.
Once I changed the test to use &lt;code&gt;save(AGGREGATE)&lt;/code&gt;, the test failed as expected (aka an “Olive”), which allowed me to move forward on implementing the filtering.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TDD Heuristic: Use Test Failures to Examine Your Design&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As I said in today’s stream, “TDD is not about writing tests. It’s about exploring the design space.”
Tests fail, but it’s when they fail for the wrong reason (or perhaps don’t fail at all), that it’s a good opportunity to step back and examine why that happened.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;the-new-projection-coordinator-(2h28m)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/07/live-coding-journal-apr-7-2026/#the-new-projection-coordinator-(2h28m)&quot;&gt;The New Projection Coordinator (2h28m)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With the Event Store supporting filtering events for consumers, it was time to migrate the &lt;code&gt;ProjectionCoordinator&lt;/code&gt; to use filtering for both the catch-up portion (asking the Event Store for all events after a checkpoint event sequence) and for the subscription.
This wasn’t a trivial migration, though, since the &lt;code&gt;NewDomainProjector&lt;/code&gt; is now stateful, vs. the stateless/functional implementation in the (old) &lt;code&gt;DomainProjector&lt;/code&gt;.
This means that the &lt;code&gt;NewDomainProjector&lt;/code&gt; not only holds onto the projection (like a cache), but also needs to track the Checkpoint (latest event sequence processed).
In addition, to prevent race conditions, the projector has to return the projection and the checkpoint as part of the &lt;code&gt;flush()&lt;/code&gt; method’s return value.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/07/live-coding-journal-apr-7-2026/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Next time I’ll finish the &lt;code&gt;NewProjectionCoordinator&lt;/code&gt; and &lt;code&gt;NewDomainProjector&lt;/code&gt; so that the coordinator lets the projector handle the cache of the projection and the checkpoint.&lt;/p&gt;
&lt;p&gt;Join me on my next stream, which I usually do Monday through Thursday, starting at 19:00 UTC on Twitch: &lt;a href=&quot;https://jitterted.stream/&quot;&gt;https://jitterted.stream&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Live Coding Journal - Apr 6, 2026</title>
    <link href="https://ted.dev/articles/2026/04/06/live-coding-journal-apr-6-2026/"/>
    <updated>2026-04-06T10:00:00Z</updated>
    <id>https://ted.dev/articles/2026/04/06/live-coding-journal-apr-6-2026/</id>
    <content xml:lang="en" type="html">&lt;div class=&quot;meta-notes-card&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All the code I’m working on in my live coding stream is available at &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced&quot;&gt;https://github.com/jitterted/jitterticket-event-sourced&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Notes from the last two weeks of streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/03/23/live-coding-journal-mar-23-2026/&quot;&gt;Mar 23, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/03/24/live-coding-journal-mar-24-2026/&quot;&gt;Mar 24, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/03/25/live-coding-journal-mar-25-2026/&quot;&gt;Mar 25, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/03/30/live-coding-journal-mar-30-2026/&quot;&gt;Mar 30, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/04/02/live-coding-journal-apr-2-2026/&quot;&gt;Apr 2, 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;notes-from-today%E2%80%99s-live-coding-session&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/06/live-coding-journal-apr-6-2026/#notes-from-today%E2%80%99s-live-coding-session&quot;&gt;Notes from Today’s Live Coding Session&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;splitting-eventconsumer&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/06/live-coding-journal-apr-6-2026/#splitting-eventconsumer&quot;&gt;Splitting EventConsumer&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It turned out that in trying to make the single &lt;code&gt;EventConsumer&lt;/code&gt; interface apply to both Projectors and the &lt;code&gt;ProjectionCoordinator&lt;/code&gt; didn’t quite fit.
Pure Domain Projectors need to advertise the events they want (“desired events”), and do so by implementing one or more &lt;code&gt;handle()&lt;/code&gt; methods with a specific event type.
However, the Projector needs the persistence and catch-up support provided by the &lt;code&gt;ProjectionCoordinator&lt;/code&gt;.
I couldn’t figure out a way to make it work without doing delegation of the &lt;code&gt;handle()&lt;/code&gt; methods, which makes no sense.
Solved this by splitting it into an &lt;code&gt;EventConsumer&lt;/code&gt; (perhaps a better name is &lt;code&gt;EventStreamConsumer&lt;/code&gt;), which implements a &lt;code&gt;handle(Stream&amp;lt;? extends Event&amp;gt; events)&lt;/code&gt; method and &lt;code&gt;EventHandler&lt;/code&gt;, which is where the specific &lt;code&gt;handle()&lt;/code&gt; methods would be implemented, and provides a &lt;code&gt;Set&amp;lt;Class&amp;lt;? extends Event&amp;gt;&amp;gt; handledEventTypes()&lt;/code&gt; that uses reflection to collect the desired events.&lt;/p&gt;
&lt;p&gt;Now, &lt;code&gt;ProjectionCoordinator&lt;/code&gt; implements &lt;code&gt;EventConsumer&lt;/code&gt; and is in charge of (among other things), catching up with the event store and subscribing to new events.
Once &lt;code&gt;EventStore&lt;/code&gt; supports desired events for &lt;code&gt;subscribe&lt;/code&gt;, &lt;code&gt;ProjectionCoordinator&lt;/code&gt; could do this on startup:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; desiredEvents &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; domainProjector&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handledEventTypes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// the following now works across all event store implementations&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;Stream&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;EVENT&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; eventStream &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; eventStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;allEventsAfter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cachedCheckpoint&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; desiredEvents&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;updateProjection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;eventStream&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;// we&#39;ll do this next time&lt;/span&gt;
eventStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;subscribe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; desiredEvents&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;new-domain-projector-design&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/06/live-coding-journal-apr-6-2026/#new-domain-projector-design&quot;&gt;New Domain Projector Design&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Since the Projector implements individual event &lt;code&gt;handle()&lt;/code&gt; methods instead of routing all events through a single method, it is no longer a stateless/functional implementation.
It has to retain state across (potentially) multiple invocations of the various &lt;code&gt;handle()&lt;/code&gt; methods, but that’s fine.
Squinting a bit, this change makes a Projector look a lot like the current Aggregate implementations, where the initial state is loaded from the event store, events are applied to evolve the state, and we can ask for new “uncommitted” events that are generated.
And now a Projector gets its initial state loaded from persistence, events are applied via the “handle” methods, and we want to ask it for changes to its state.
This is good, as Aggregates have always been a projection of events, centered around the properties of the Aggregate.&lt;/p&gt;
&lt;p&gt;Once I realized that, I wanted to change the Domain Projector’s method that returns the delta (changes) to &lt;code&gt;uncommittedChanges()&lt;/code&gt;, but unlike Aggregates which get thrown away once they’ve done their job, Projectors cache their Projections in memory.
This meant I needed to “reset” the changes, so I initially thought I’d need a separate &lt;code&gt;flush()&lt;/code&gt; method that would clear it, and added it (but didn’t implement it!) while test-driving (2h17m46s in the video).
However, this could lead to issues where the changes were retrieved, but the flush was never called, potentially corrupting the persisted projection.
@Suigi suggested returning the changes as part of the &lt;code&gt;flush()&lt;/code&gt; and get rid of &lt;code&gt;uncommittedChanges()&lt;/code&gt; and that’s what I did instead.
Even though this violates Command-Query Separation (CQS), it turned out to be a better match for supporting persistence.
And I’d argue that this is one of the rare exceptions to CQS, much like a Stack’s &lt;code&gt;pop()&lt;/code&gt; both modifies the stack and returns a value.&lt;/p&gt;
&lt;h3 id=&quot;moving-away-from-aggregates-%E2%80%93-someday&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/06/live-coding-journal-apr-6-2026/#moving-away-from-aggregates-%E2%80%93-someday&quot;&gt;Moving Away from Aggregates – Someday&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I’ve been dropping the generic &lt;code&gt;EVENT&lt;/code&gt; during these changes, since the original intention of that generic type was to capture the base class for events related to a specific Aggregate, e.g., &lt;code&gt;ConcertEvent&lt;/code&gt; that is the parent of all Concert-specific events.
As I move away from this Aggregate-centric way of looking at things, the generic type gets in the way and, instead, we use the event filtering (“desired events”) to capture the events that Projectors, Processors, and (eventually) Aggregates are interested in.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/06/live-coding-journal-apr-6-2026/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Finish the conversion of the &lt;code&gt;ProjectionCoordinator&lt;/code&gt; to use the NewDomainProjector, and update the Event Store’s &lt;code&gt;subscribe()&lt;/code&gt; method to accept desired events.
Then I’ll convert the &lt;code&gt;AvailableConcertsProjector&lt;/code&gt; to this new model and see how it fits.&lt;/p&gt;
&lt;p&gt;Join me on my next stream, which I usually do Monday through Thursday, starting at 19:00 UTC on Twitch: &lt;a href=&quot;https://jitterted.stream/&quot;&gt;https://jitterted.stream&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Live Coding Journal - Apr 2, 2026</title>
    <link href="https://ted.dev/articles/2026/04/02/live-coding-journal-apr-2-2026/"/>
    <updated>2026-04-02T10:00:00Z</updated>
    <id>https://ted.dev/articles/2026/04/02/live-coding-journal-apr-2-2026/</id>
    <content xml:lang="en" type="html">&lt;div class=&quot;meta-notes-card&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All the code I’m working on in my live coding stream is available at &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced&quot;&gt;https://github.com/jitterted/jitterticket-event-sourced&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Notes from the last two weeks of streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/03/23/live-coding-journal-mar-23-2026/&quot;&gt;Mar 23, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/03/24/live-coding-journal-mar-24-2026/&quot;&gt;Mar 24, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/03/25/live-coding-journal-mar-25-2026/&quot;&gt;Mar 25, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/03/30/live-coding-journal-mar-30-2026/&quot;&gt;Mar 30, 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;notes-from-today%E2%80%99s-live-coding-session&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/02/live-coding-journal-apr-2-2026/#notes-from-today%E2%80%99s-live-coding-session&quot;&gt;Notes from Today’s Live Coding Session&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;consuming-only-desired-events&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/02/live-coding-journal-apr-2-2026/#consuming-only-desired-events&quot;&gt;Consuming Only Desired Events&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I finally started on a big optimization, mainly for Projectors that need to catch up on lots of events (because they’re new or changed), where Event Consumers only fetch/receive events that they’re interested in.
For example, the &lt;code&gt;AvailableConcerts&lt;/code&gt; projector only needs to know about events relating to availability of customers to buy tickets.
There’s no point in it fetching or receiving events like &lt;code&gt;TicketsSold&lt;/code&gt; or event &lt;code&gt;CustomerRegistered&lt;/code&gt;, especially since the large majority of events would be about ticket sales.
The question was: how do consumers “publicize” which events they want?&lt;/p&gt;
&lt;p&gt;The options were:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Have an &lt;code&gt;interestedIn()&lt;/code&gt; method that all consumers must implement, returning a list of event classes they want.&lt;/li&gt;
&lt;li&gt;Register desired events when the consumer registers itself with the Event Store&lt;/li&gt;
&lt;li&gt;Like #1, but using a code generator to generate the method (and other boilerplate, like the switch block for handling the events)&lt;/li&gt;
&lt;li&gt;Similar to #1, but using Annotations&lt;/li&gt;
&lt;li&gt;Have the Event Consumer create &lt;code&gt;handle()&lt;/code&gt; methods, overloaded for each desired event, which reflection can find.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I decided to go with #5, as it’s straightforward to do, and unlike #1/#3, does not repeat the same information, which could lead to forgetting to publicize a desired event.
I didn’t like #2, because as above, it’s easy to forget to update the configuration when desired events change, especially since configuration is in a separate file.
I generally don’t like annotations, but #4 suffers from the same problem as above: having to update the annotation to indicate desired events.&lt;/p&gt;
&lt;p&gt;Using reflection also allows me to handle implementation problems such as methods that might be &lt;code&gt;handle()&lt;/code&gt; methods, but perhaps were misspelled (e.g., &lt;code&gt;handel(ConcertScheduled event)&lt;/code&gt;), or if no methods handle events at all.
I also added in extra checks for the case where somehow the consumer is getting events that it wasn’t interested in, which would indicate a bug elsewhere.&lt;/p&gt;
&lt;p&gt;Moving to selective event consuming also means dropping the generic type from the &lt;code&gt;NewEventConsumer&lt;/code&gt;, which helps as I continue to move away from an aggregate-focused design.&lt;/p&gt;
&lt;h3 id=&quot;void-vs.-void&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/02/live-coding-journal-apr-2-2026/#void-vs.-void&quot;&gt;&lt;code&gt;Void&lt;/code&gt; vs. &lt;code&gt;void&lt;/code&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This was a (not) fun troubleshooting session, took a long time to figure out why I couldn’t use MethodHandle.lookup().findVirtual() for the &lt;code&gt;handle&lt;/code&gt; methods that return void.
It turns out, &lt;code&gt;Void.class&lt;/code&gt; is &lt;strong&gt;not&lt;/strong&gt; the same as &lt;code&gt;void.class&lt;/code&gt; (yes, a class from the “primitive” void)!
After struggling through the rest of reflection to get the methods and try out invoking them, I got the prototype to work. However, it was much more painful and frustrating than it should have been thanks to docs that aren’t great.&lt;/p&gt;
&lt;h2 id=&quot;background-thoughts-on-projection-design&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/02/live-coding-journal-apr-2-2026/#background-thoughts-on-projection-design&quot;&gt;Background Thoughts on Projection Design&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Over the weekend, I’ve been thinking about Projections and how I’m currently caching them in memory to make updating their state fast.
I was reminded of earlier thoughts where some Projections could use the database to perform the summary calculations (e.g., the Sales Projection).
This is another reason in favor of consolidating the Projection persistence into the Projection code itself instead of the current “wrapper” way that I’m currently doing in the &lt;code&gt;ProjectionCoordinator&lt;/code&gt;.
Not only that, the persisting of the projection might be different depending on how “risky” it is to have it catch up if the system crashes or needs to restart.
On the other hand, I want to implement a deferred-write mechanism for persisting projections, so having a standard way to deal with deferred writes (after a timeout or deferred data exceeds a threshold) might be easier with a &lt;code&gt;ProjectionCoordinator&lt;/code&gt; design.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/04/02/live-coding-journal-apr-2-2026/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With the &lt;code&gt;NewEventConsumer&lt;/code&gt; completed, I’ll be working on converting the &lt;code&gt;RegisteredCustomersProjector&lt;/code&gt; to use it.
If time allows, I’ll also convert the &lt;code&gt;AvailableConcertsProjector&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Join me on my next stream, which I usually do Monday through Thursday, starting at 19:00 UTC on Twitch: &lt;a href=&quot;https://jitterted.stream/&quot;&gt;https://jitterted.stream&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Live Coding Journal - Mar 30, 2026</title>
    <link href="https://ted.dev/articles/2026/03/30/live-coding-journal-mar-30-2026/"/>
    <updated>2026-03-30T10:00:00Z</updated>
    <id>https://ted.dev/articles/2026/03/30/live-coding-journal-mar-30-2026/</id>
    <content xml:lang="en" type="html">&lt;div class=&quot;meta-notes-card&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All the code I’m working on in my live coding stream is available at &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced&quot;&gt;https://github.com/jitterted/jitterticket-event-sourced&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Notes from the last two weeks of streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/03/23/live-coding-journal-mar-23-2026/&quot;&gt;Mar 23, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/03/24/live-coding-journal-mar-24-2026/&quot;&gt;Mar 24, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/03/25/live-coding-journal-mar-25-2026/&quot;&gt;Mar 25, 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;notes-from-today%E2%80%99s-live-coding-session&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/30/live-coding-journal-mar-30-2026/#notes-from-today%E2%80%99s-live-coding-session&quot;&gt;Notes from Today’s Live Coding Session&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;clarifying-event-in-event-sourcing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/30/live-coding-journal-mar-30-2026/#clarifying-event-in-event-sourcing&quot;&gt;Clarifying Event in Event-Sourcing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once again I caught myself not being clear (to myself!) about what an event is in event-sourcing.
Not only is it something that has happened (a “fact”), but it &lt;strong&gt;must&lt;/strong&gt; be related to some “thing”.
Whether that thing is an Aggregate (Concert, Customer), or an Entity (Ticket?), or some other concept, in order for it to be a fact, it must be related to something &lt;strong&gt;identifiable&lt;/strong&gt;.
This is why an event like “CalendarDayEnded” makes no sense for event-sourcing: which thing are we talking about?
What thing’s state has changed as a result?
(If no state has changed, then it can’t be an event in event-sourcing!)&lt;/p&gt;
&lt;p&gt;It’s fine for “CalendarDayEnded” to be a &lt;em&gt;Collaboration Event&lt;/em&gt;, i.e., for communicating information across processes.
In that case it might trigger a “Translator” to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do a query for all Concerts that have a show date of the day that ended, and&lt;/li&gt;
&lt;li&gt;For each Concert (only one for our single-venue system), issue a &lt;em&gt;Command&lt;/em&gt; to the Concert to “close”.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then we’d end up with a “ConcertClosed” event (with the ID for that particular Concert), but only because of the &lt;em&gt;Command&lt;/em&gt; that was issued by the Translator.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;“Event Must Have ID” Heuristic&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Any event that represents a change in state, i.e., an event in an event-sourcing system, must have some &lt;strong&gt;identifier&lt;/strong&gt; that associates the change in state with the “entity” or value that changed (the &lt;strong&gt;identifiable state&lt;/strong&gt;).
Events without an identifier can exist, but they must be some other type of event, e.g., &lt;em&gt;Collaboration&lt;/em&gt; or &lt;em&gt;Integration&lt;/em&gt; event that communicates information across process boundaries.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;separating-%E2%80%9Ctickets-on-sale%E2%80%9D-from-%E2%80%9Cconcert-scheduled%E2%80%9D&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/30/live-coding-journal-mar-30-2026/#separating-%E2%80%9Ctickets-on-sale%E2%80%9D-from-%E2%80%9Cconcert-scheduled%E2%80%9D&quot;&gt;Separating “Tickets On Sale” from “Concert Scheduled”&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In the current implementation, tickets become available for purchase as soon as the concert is scheduled.
In the real world, this is not always (or even often?) the case.
This will give me an opportunity to explore event (or “schema”) evolution when adding a new feature, especially when it’s modifying the contents of an event.
In this case, we’ll need to add the “on-sale” date and time to the &lt;code&gt;ConcertScheduled&lt;/code&gt; event.
This is the somewhat easier case, since we’re only adding new properties to an existing event (vs. changing or removing properties, which is harder).
As is typical for adding new properties, we need good defaults to “fill in” values for events created prior to this change.&lt;/p&gt;
&lt;h3 id=&quot;improving-catch-up-processing-via-filtering-event-types&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/30/live-coding-journal-mar-30-2026/#improving-catch-up-processing-via-filtering-event-types&quot;&gt;Improving Catch-Up Processing via Filtering Event Types&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Since “on sale” is very similar to “stop sales”, in that both require a future alarm to be set for when that date/time come around, I looked at the &lt;code&gt;ConcertStartedProcessor&lt;/code&gt; to see what would need to change.
As I examined how the alarms get set, I realized that since the alarms are not persisted, the Processor needs to catch up from the beginning of the entire event stream every time.
Since it only cares about scheduling and rescheduling concerts and stopping ticket sales, that would be fast, except for the fact that the &lt;code&gt;EventStore&lt;/code&gt; doesn’t support asking for events of specific types, only the parent class that relates to each aggregate, i.e., &lt;code&gt;Customer&lt;/code&gt; and &lt;code&gt;Concert&lt;/code&gt;.
This means in addition to the ~hundreds of &lt;code&gt;ConcertScheduled&lt;/code&gt; events that we care about, we’d get thousands (or hundreds of thousands) of &lt;code&gt;TicketsSold&lt;/code&gt; events that would be ignored.
In one of my sets of sample data, where there were ~5MM events, this took over 2 minutes to load!
(Yes, there are probably some improvements to make that faster.)
However, we end up ignoring almost all of them, making it extremely wasteful.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When I hacked in this change, it took 4 seconds to load and process 101,000 events for the &lt;code&gt;RegisteredCustomers&lt;/code&gt; Projector, significantly faster and much less wasteful than loading 5MM.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;redesign-of-eventconsumer-interface&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/30/live-coding-journal-mar-30-2026/#redesign-of-eventconsumer-interface&quot;&gt;Redesign of EventConsumer Interface&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I spent around 90 minutes (around 17m to 1h47m in the video) adding the ability to specify specific events to load through the event store’s &lt;code&gt;allEventsAfter()&lt;/code&gt; method.
Once I proved that it would drastically increase performance (that 4 minutes is now around 2 seconds), I looked at how that would fit with the design of the &lt;code&gt;EventConsumer&lt;/code&gt; interface, which both Projectors and Processors implement.
The main question is: how should an event consumer signal that it’s only interested in specific events?
I think there are only two options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;When the consumer registers/subscribes with whatever publishes the events (&lt;code&gt;EventStore&lt;/code&gt; in this case), it sends a list of events along with the subscription.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;EventConsumer&lt;/code&gt; interface defines a &lt;code&gt;List&amp;lt;Event&amp;gt; interestedEvents()&lt;/code&gt; method that gets called from the publisher when the consumer is registered.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The problem with option 1 is that this happens during startup and separates where the consumer is registered with the &lt;code&gt;EventStore&lt;/code&gt; (in configuration) from where they’re processed (in the consumer).
While I’m not fond of callbacks like this, I’m less fond of having this knowledge of the events separated.&lt;/p&gt;
&lt;h3 id=&quot;projectioncoordinator-disappears%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/30/live-coding-journal-mar-30-2026/#projectioncoordinator-disappears%3F&quot;&gt;&lt;code&gt;ProjectionCoordinator&lt;/code&gt; Disappears?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Looking at redesigning &lt;code&gt;EventConsumer&lt;/code&gt; led to an exploration of the &lt;code&gt;ProjectionCoordinator&lt;/code&gt; design.
The coordinator is a persistence “wrapper” and cache around the actual projection code (a &lt;code&gt;DomainProjector&lt;/code&gt;) that does the actual processing of events (and has no state itself).
It works nicely, because the &lt;code&gt;DomainProjector&lt;/code&gt; doesn’t need to know about peristence (or caching of the projection), or even that persistence is happening, other than returning changes since the previous time it ran (the Delta), which makes the persistence easier.
However, since a Projection is a Cache of computed values, maybe the cached projection should be &lt;em&gt;inside&lt;/em&gt; the Projector?
In other words, turn it inside out.
This would mean the &lt;code&gt;ProjectionPersistencePort&lt;/code&gt; would be injected into the Projector, and the &lt;code&gt;ProjectionCoordinator&lt;/code&gt; would go away.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/30/live-coding-journal-mar-30-2026/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Since it’s unclear which design (wrapper vs. injecting persister into the projector) is better, next time I’ll try out the injection into a new &lt;code&gt;PersistedProjector&lt;/code&gt; for the Registered Customers and Scheduled Concerts projectors and see which one looks better.&lt;/p&gt;
&lt;p&gt;Join me on my next stream, which I usually do Monday through Thursday, starting at 19:00 UTC on Twitch: &lt;a href=&quot;https://jitterted.stream/&quot;&gt;https://jitterted.stream&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Live Coding Journal - Mar 25, 2026</title>
    <link href="https://ted.dev/articles/2026/03/25/live-coding-journal-mar-25-2026/"/>
    <updated>2026-03-25T10:00:00Z</updated>
    <id>https://ted.dev/articles/2026/03/25/live-coding-journal-mar-25-2026/</id>
    <content xml:lang="en" type="html">&lt;div class=&quot;meta-notes-card&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All the code I’m working on in my live coding stream is available at &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced&quot;&gt;https://github.com/jitterted/jitterticket-event-sourced&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Notes from the last two weeks of streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/03/23/live-coding-journal-mar-23-2026/&quot;&gt;Mar 23, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/03/24/live-coding-journal-mar-24-2026/&quot;&gt;Mar 24, 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;notes-from-today%E2%80%99s-live-coding-session&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/25/live-coding-journal-mar-25-2026/#notes-from-today%E2%80%99s-live-coding-session&quot;&gt;Notes from Today’s Live Coding Session&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;avro-encoding-dead-end&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/25/live-coding-journal-mar-25-2026/#avro-encoding-dead-end&quot;&gt;Avro Encoding Dead-End&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I spent almost 2 hours working on serializing events using Avro instead of JSON in the hope that it’d increase performance.
It was a bit of a frustrating process, especially the requirements for a no-arg constructor for events, which I didn’t really want to add.
After running some simple benchmarks, I realized that the JSON (de)serialization itself is probably not the performance bottleneck, and so gave up on the Avro spike.
I’ll revisit performance at some point by doing more profiling of the application, but for now I need to focus on functionality that extends my learning around event-sourcing.&lt;/p&gt;
&lt;h3 id=&quot;concertcompleted%3A-not-real%3F-projection-%3D-cache&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/25/live-coding-journal-mar-25-2026/#concertcompleted%3A-not-real%3F-projection-%3D-cache&quot;&gt;ConcertCompleted: Not Real? Projection = Cache&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I decided to look at what it would take to add a new event, to see what the process now looks like so I can simplify it if necessary.
It turns out, the event I wanted to add, &lt;code&gt;ConcertCompleted&lt;/code&gt;, may not make any sense.
I spent almost an hour thinking out loud about it and decided that it seemed a bit “fake” to create a whole Use Case (a Screen/UI, a Command, and an Event) just to basically “evict” the (now completed) Concert from the “Scheduled Concerts” Projection.
Since Projections are cached queries against the entire event stream, spending effort to remove an entry–when there will only be on the order of hundreds of entries–just isn’t worth it.
If I need to “garbage collect” the concerts that are no longer in the future, I can just regenerate the projection or check if I need to drop old concerts whenever a new one is added (this was option #4 on my list of ways to deal with this).
Once Projections can query for specific event types (e.g., &lt;code&gt;ConcertScheduled&lt;/code&gt; and &lt;code&gt;ConcertRescheduled&lt;/code&gt;, instead of all events after a checkpoint), this becomes much more feasible.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Heuristic&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I think it’s important to ensure that ID-based projections don’t grow completely unbounded,
i.e., there should be some event that “evicts” entries.
For Summary Projections (those that do some kind of summing or aggregation across events),
this doesn’t apply, since they’re like a “reduce” and would not grow nearly as fast.
However, even for a Summary Projection like the Concert Sales Projection, there’s probably no business reason to keep sales information for a 3-year-old concert.
(Unless you want to forecast sales of the same band for a future concert, in which case it’s fine to have it stick around.)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The thought process did reveal the biggest issue with my event-sourcing infrastructure: the focus on Aggregate IDs.
I wanted to try having an “end-of-day event” generator that Projections could consume to do things that are calendar related, but saving an event (through the &lt;code&gt;EventStore&lt;/code&gt;) requires an ID (which becomes a primary key in the database table).
This leads to the question of, what ID would I use for such a general event?
Does this kind of event make sense from an event-sourcing system?
I think not, or at least it should not be persisted.
It might be fine if it’s treated as a Command/Trigger/Action, but such a Command would need to be executed against one (or more) actual Concerts to generate &lt;code&gt;ConcertCompleted&lt;/code&gt; events.&lt;/p&gt;
&lt;p&gt;Since I didn’t feel like that would be a useful next step, from either a learning or functionality standpoint, I decided to table it and move on to something else.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/25/live-coding-journal-mar-25-2026/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I decided to implement a new feature: the ability to set an “on sale” date/time for tickets, instead of them going on sale as soon as the concert is scheduled.
This will be interesting, not only because it’s a change in behavior, but also (as @Suigi mentioned), all of the existing scheduled concerts need to be dealt with.
And the &lt;code&gt;AvailableConcerts&lt;/code&gt; projection (the one used to show customers what concerts they can buy tickets for) will need to change, further separating it from the &lt;code&gt;ScheduledConcerts&lt;/code&gt; projection that is used to detect scheduling conflicts.&lt;/p&gt;
&lt;p&gt;Join me on my next stream, which I usually do Monday through Thursday, starting at 19:00 UTC on Twitch: &lt;a href=&quot;https://jitterted.stream/&quot;&gt;https://jitterted.stream&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Live Coding Journal - Mar 24, 2026</title>
    <link href="https://ted.dev/articles/2026/03/24/live-coding-journal-mar-24-2026/"/>
    <updated>2026-03-24T10:00:00Z</updated>
    <id>https://ted.dev/articles/2026/03/24/live-coding-journal-mar-24-2026/</id>
    <content xml:lang="en" type="html">&lt;div class=&quot;meta-notes-card&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All the code I’m working on in my live coding stream is available at &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced&quot;&gt;https://github.com/jitterted/jitterticket-event-sourced&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Notes from the last two weeks of streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/03/23/live-coding-journal-mar-23-2026/&quot;&gt;Mar 23, 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;notes-from-today%E2%80%99s-live-coding-session&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/24/live-coding-journal-mar-24-2026/#notes-from-today%E2%80%99s-live-coding-session&quot;&gt;Notes from Today’s Live Coding Session&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;exception-vs.-result-pattern&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/24/live-coding-journal-mar-24-2026/#exception-vs.-result-pattern&quot;&gt;Exception vs. Result Pattern&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Today I reviewed my decision (around 10min into the video) to use an Exception for when there’s a scheduling conflict for concerts (trying to schedule a concert on a date where one was already scheduled) by looking at what the code would for something like &lt;a href=&quot;https://vavr.io/&quot;&gt;Vavr’s&lt;/a&gt; &lt;code&gt;Try&lt;/code&gt; (“Result” pattern) vs. a normal &lt;code&gt;try..catch&lt;/code&gt;.
I think an Exception is just as readable and, since this isn’t in a tight processing loop, any performance implications of throwing an Exception are irrelevant since the result is an HTTP response (redirect).
If we were validating hundreds or thousands of lines of input, then there might be some noticeable impact, but that’s not the case here.&lt;/p&gt;
&lt;h3 id=&quot;external-validation%3A-scheduling-conflicts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/24/live-coding-journal-mar-24-2026/#external-validation%3A-scheduling-conflicts&quot;&gt;External Validation: Scheduling Conflicts&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once I figured out where the scheduling validation check should go (sketching the call in the &lt;code&gt;Commands.createScheduleCommand()&lt;/code&gt; method), I determined (around 24m) that the (cached) projection state (&lt;code&gt;ScheduledConcerts&lt;/code&gt; record) has the knowledge to execute the conflict-check query.
Having the cached projection state execute the query is fine if there aren’t thousands of concerts to check.
For something like email uniqueness where there may be many thousands (or millions?) of entries, we would want to run a query against the database, though we could optimize using a Bloom filter if we wanted.
However, even in a production system, there wouldn’t be a problem with this cache unless the system was handling tickets for many venues (vs. just one).
A nice benefit of the conflict check inside a simple record is that TDDing the implementation was straightforward.&lt;/p&gt;
&lt;h3 id=&quot;value-objects%3A-smallest-consistency-boundary%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/24/live-coding-journal-mar-24-2026/#value-objects%3A-smallest-consistency-boundary%3F&quot;&gt;Value Objects: Smallest Consistency Boundary?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At 2:51:20 in the video I ponder the common code &lt;code&gt;ensureNoConflictFor(showDateTime)&lt;/code&gt; between the validation for Schedule New Concert and Reschedule Existing Concert actions:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CommandWithParams&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RescheduleParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createRescheduleCommand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; commandExecutorFactory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wrapWithParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reschedule&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token class-name&quot;&gt;LocalDateTime&lt;/span&gt; showDateTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; reschedule&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;showDateTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;ensureNoConflictFor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;showDateTime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                concert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rescheduleTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                        showDateTime&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        reschedule&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;doorsTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CreateWithParams&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ScheduleParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createScheduleCommand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; commandExecutorFactory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wrapForCreation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            scheduleParams &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;token class-name&quot;&gt;LocalDateTime&lt;/span&gt; showDateTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; scheduleParams&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;showDateTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token class-name&quot;&gt;LocalTime&lt;/span&gt; doorsTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; scheduleParams&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;doorsTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token function&quot;&gt;ensureNoConflictFor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;showDateTime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;schedule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                        &lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createRandom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        scheduleParams&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;artist&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        scheduleParams&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ticketPrice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        showDateTime&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        doorsTime&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        scheduleParams&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;capacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                        scheduleParams&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;maxTicketsPerPurchase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With Command-Consistency Boundaries replacing Aggregates, the question is: what is the smallest consistency boundary that makes sense?
It seems like Value Objects are the minimum boundary, as anything smaller probably wouldn’t need to change simultaneously.
For example, there’s no need for one user to make a change to a Concert’s “Doors Time” at the same time as another user making a change to the “Show Time”.
Both of those are linked (there’s even validation for Doors Time that depends on the Show Time, as I implement later in the stream), so that’s the minimal consistency boundary.
Similarly for an address, there’s no point in allowing changes to the City by one user and the State for another user.
An Address is a Value Object and is a complete unit of consistency.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/24/live-coding-journal-mar-24-2026/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With the validation out of the way, the next step is to try Avro as a serialization format and see how performance compares with the current JSON implementation.&lt;/p&gt;
&lt;p&gt;Join me on my next stream, which I usually do Monday through Thursday, starting at 19:00 UTC on Twitch: &lt;a href=&quot;https://jitterted.stream/&quot;&gt;https://jitterted.stream&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Live Coding Journal - Mar 23, 2026</title>
    <link href="https://ted.dev/articles/2026/03/23/live-coding-journal-mar-23-2026/"/>
    <updated>2026-03-23T10:00:00Z</updated>
    <id>https://ted.dev/articles/2026/03/23/live-coding-journal-mar-23-2026/</id>
    <content xml:lang="en" type="html">&lt;div class=&quot;meta-notes-card&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All the code I’m working on in my live coding stream is available at &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced&quot;&gt;https://github.com/jitterted/jitterticket-event-sourced&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Notes from the &lt;a href=&quot;https://ted.dev/articles/2026/02/19/live-coding-journal-feb-19-2026/&quot;&gt;last stream&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;notes-from-today%E2%80%99s-live-coding-session&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/23/live-coding-journal-mar-23-2026/#notes-from-today%E2%80%99s-live-coding-session&quot;&gt;Notes from Today’s Live Coding Session&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’m back from my break! I was at &lt;a href=&quot;https://devnexus.com/&quot;&gt;DevNexus&lt;/a&gt; in Atlanta, where I gave a talk on automated refactorings in IntelliJ IDEA. Last week I attended the always awesome JavaOne conference a few miles down the road in Redwood Shores, California. I mentioned a few of the talks that I encourage folks to watch out for when they appear on YouTube.&lt;/p&gt;
&lt;h3 id=&quot;consistency-boundaries&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/23/live-coding-journal-mar-23-2026/#consistency-boundaries&quot;&gt;Consistency Boundaries&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After getting back into the JitterTicket codebase (and upgrading to the newly released JDK 26), I continued my thought process around Aggregates in event-sourcing vs. DCB (Dynamic Consistency Boundaries).
I’ve decided to use the term “Command Consistency Boundaries” instead of DCB, because the boundary isn’t all &lt;em&gt;that&lt;/em&gt; dynamic, it is based on the needs of each command. (See around 41:00 in the video.)
This comes into play with the validation I’m adding for the &lt;em&gt;Scheduling Concert&lt;/em&gt;.
There are generally three kinds of validations/rules that are evaluated when deciding to execute a command:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Parameter validation&lt;/strong&gt;: are the parameters in range (parse &#39;em into Value Objects to make sure!) and internally consistent (across multiple parameters, such as City+State+Postal Code matching)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internal validation&lt;/strong&gt;: often these are the Domain Rules that use the state of the entity, e.g., does the Concert have sufficient tickets available to fulfill the number of tickets being purchased?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;External validation&lt;/strong&gt;: requires information from outside of the entity, possibly even outside of the process (system), e.g., is this email address unique, does this concert date conflict with one already scheduled, or does this user have authorization to take this action in the first place?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;What I find so interesting about the CCB (command-consistency boundary) is that we can gather precisely (no more, no less) the inputs required for all these decisions to be made, instead of loading more information than we might need (via an Aggregate) and then, separately, getting the external information (e.g., query a database for email addresses). (See around 2:50:00 in the video.)&lt;/p&gt;
&lt;h3 id=&quot;heuristics-for-missing-events&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/23/live-coding-journal-mar-23-2026/#heuristics-for-missing-events&quot;&gt;Heuristics for Missing Events&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I came up with a couple of heuristics that might indicate missing events.
One is if a projection requires access to the current date or other out-of-process information that’s not in any event.
An example here (around 1:35 in the video) is discarding concerts that already took place in the past when projecting Scheduled Concerts (to be used when looking for scheduling conflicts).
In this case, I’m missing a &lt;code&gt;ConcertCompleted&lt;/code&gt; event that would drop the concert from the projection of scheduled concerts.
After all, there’s no need to look for conflicts when scheduling a new concert against concerts that happened in the past, since you can’t schedule a new concert in the past!&lt;/p&gt;
&lt;p&gt;The second is if you find the projection having unbound growth, mainly that nothing ever gets deleted/removed from the projection.
This is a weaker heuristic, because for things like Customer Emails, it will obviously grow as long as your adding more customers.
However, there will be customers who close their accounts or change their emails, so if you’re not removing emails from the projection, you might be missing a &lt;code&gt;CustomerEmailChanged&lt;/code&gt; or &lt;code&gt;CustomerAccountClosed&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;event-serialization-(encoding)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/23/live-coding-journal-mar-23-2026/#event-serialization-(encoding)&quot;&gt;Event Serialization (Encoding)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In our &lt;a href=&quot;https://ted.dev/bookclub&quot;&gt;book club&lt;/a&gt;, we’re reading &lt;em&gt;Designing Data-Intensive Applications&lt;/em&gt;, and we just finished the chapter that explored different ways of serializing (encoding) in-memory data structures to disk.
I had done some profiling on JitterTicket and found that a fair amount of time is being spent on decoding the JSON to Event objects, so I’m going to try encoding the event using &lt;a href=&quot;https://avro.apache.org/&quot;&gt;Avro&lt;/a&gt; to see how much of a difference it makes.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/03/23/live-coding-journal-mar-23-2026/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We’ll implement the external validation for scheduling concerts and then work on Avro encoding for event payloads.&lt;/p&gt;
&lt;p&gt;Join me on my next stream, which I usually do Monday through Thursday, starting at 19:00 UTC on Twitch: &lt;a href=&quot;https://jitterted.stream/&quot;&gt;https://jitterted.stream&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Live Coding Journal - Feb 19, 2026</title>
    <link href="https://ted.dev/articles/2026/02/19/live-coding-journal-feb-19-2026/"/>
    <updated>2026-02-19T10:00:00Z</updated>
    <id>https://ted.dev/articles/2026/02/19/live-coding-journal-feb-19-2026/</id>
    <content xml:lang="en" type="html">&lt;div class=&quot;meta-notes-card&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All the code I’m working on in my live coding stream is available at &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced&quot;&gt;https://github.com/jitterted/jitterticket-event-sourced&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Notes from the last two weeks of streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/05/live-coding-journal-feb-5-2026/&quot;&gt;Feb 5, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/09/live-coding-journal-feb-9-2026/&quot;&gt;Feb 9, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/10/live-coding-journal-feb-10-2026/&quot;&gt;Feb 10, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/11/live-coding-journal-feb-11-2026/&quot;&gt;Feb 11, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/12/live-coding-journal-feb-12-2026/&quot;&gt;Feb 12, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/16/live-coding-journal-feb-16-2026/&quot;&gt;Feb 16, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/18/live-coding-journal-feb-18-2026/&quot;&gt;Feb 18, 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;notes-from-today%E2%80%99s-live-coding-session&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/19/live-coding-journal-feb-19-2026/#notes-from-today%E2%80%99s-live-coding-session&quot;&gt;Notes from Today’s Live Coding Session&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;spring-boot-4.0.3-upgrade&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/19/live-coding-journal-feb-19-2026/#spring-boot-4.0.3-upgrade&quot;&gt;Spring Boot 4.0.3 Upgrade&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Before doing any more functional work, I wanted to (finally!) upgrade from Spring Boot 3.5.9 to 4.0.3.&lt;/p&gt;
&lt;p&gt;I wanted to try out using the &lt;a href=&quot;https://docs.arconia.io/arconia-cli/latest/&quot;&gt;Arconia CLI&lt;/a&gt; to drive the OpenRewrite migration scripts.
I ran it, but nothing seemed to happen.
Apparently I missed the fact that you needed to type &lt;code&gt;arconia help&lt;/code&gt; to get the list of commands and options.
I think this is a poor starting user experience as &lt;code&gt;-h&lt;/code&gt;, &lt;code&gt;--help&lt;/code&gt;, typical options for CLI tools, produced stack traces, where I expected to see some sort of help.
Most CLI tools will at least display something when you run them, so it’s strange that Arconia doesn’t display anything at all.&lt;/p&gt;
&lt;p&gt;Following the migration guide, before doing the actual upgrade, I did a minor upgrade to 3.5.11, the latest in the 3.5.x series, and made sure all the tests passed (they did).
What was confusing for a bit was that I had an override property to ensure that I was using JUnit 5.14, as I was using the recent Parameterized Classes feature.
I removed the override thinking that Spring Boot 3.5.11 had a recent enough version of JUnit, but it only had 5.12.2, which wasn’t recent enough.&lt;/p&gt;
&lt;p&gt;Once I got that cleared up, I ran the Arconia migration scripts and, unsurprisingly, code relating to how I configure the Jackson (JSON) ObjectMapper no longer worked.
I say unsurprising because Spring Boot 4.0.x uses Jackson 3 instead of Jackson 2, where enough has changed that the migration scripts currently don’t handle all the necessary changes.
The biggest annoyance was figuring out how to configure &lt;code&gt;INCLUDE_SOURCE_IN_LOCATION&lt;/code&gt;, which was way more difficult to solve than it should have been.
I’ll be writing up a deeper post on this, with perhaps some ideas for additional OpenRewrite recipes to cover the situation.&lt;/p&gt;
&lt;p&gt;Once I got past the compilation issues, I ran all the tests and noticed a failure in the CSV tests that were sensitive to changes in JSON serialization.
Apparently, the default way that dates and times are serialized in Jackson 3 is ISO-8601, which is a much better format, but different from the previous default.
I was glad that tests caught this, but dismayed that it was only caught as a part of a CSV test instead of a dedicated serialization test.
I wrote the missing serialization test as a characterization test, and then fixed the failing CSV tests to use the new date/time format.&lt;/p&gt;
&lt;p&gt;After finishing the Jackson migration, all the Spring-related tests failed with a weird &lt;code&gt;NoSuchMethodException&lt;/code&gt; for &lt;code&gt;computeIfAbsent&lt;/code&gt; in the &lt;code&gt;SpringExtension&lt;/code&gt;.
I quickly realized that I had forgotten to take out the JUnit version property, which was now forcing an old version (5.14.0) instead of letting Spring Boot pull in the 6.0.3 that it needed.&lt;/p&gt;
&lt;h3 id=&quot;projection-misconfiguration&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/19/live-coding-journal-feb-19-2026/#projection-misconfiguration&quot;&gt;Projection Misconfiguration&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once I got the application running again, I realized there was a problem with the concerts shown on the “On-Sale Events” page (around 1h12m into the stream).
The problem was that one of the concerts shown should not have been on sale because its show date/time was in the past.
I realized that I had miswired the projection when plugging in the “All Concerts” projection in a previous stream (to fix the event viewer).
Because both the “All Concerts” and “Available Concerts” projections use the same types for the projection contents (I took a shortcut by reusing &lt;code&gt;AvailableConcerts&lt;/code&gt; for both), I didn’t realize I was injecting the wrong projection into the on-sale page.
It wasn’t a difficult fix, but in a production system, I would have been more disciplined about making sure that the two projections used completely separate types.&lt;/p&gt;
&lt;h3 id=&quot;extending-commandexecutorfactory-for-creation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/19/live-coding-journal-feb-19-2026/#extending-commandexecutorfactory-for-creation&quot;&gt;Extending CommandExecutorFactory for Creation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I thought adding the “creation” command type to the &lt;code&gt;CommandExecutorFactory&lt;/code&gt; was going to be complex, but it turned out to be straightforward once I realized that calling a static method (to do the creation) was no different than calling an instance method.
Once again, getting my head wrapped around the generics needed for the &lt;code&gt;wrap&lt;/code&gt; and the command execution took a bit of time, but was happy with the result:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CreateWithParams&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ScheduleParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wrapForCreation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;CreateWithParams&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ScheduleParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; command&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; scheduleParams &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt; concert &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; command&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;scheduleParams&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        concertEventStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; concert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;with the concrete “schedule” command defined like this:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CreateWithParams&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ScheduleParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createScheduleCommand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;CreateWithParams&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ScheduleParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; command &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
            commandExecutorFactory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wrapForCreation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                    scheduleParams &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;schedule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                            &lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createRandom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            scheduleParams&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;artist&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            scheduleParams&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ticketPrice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            scheduleParams&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;showDateTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            scheduleParams&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;doorsTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            scheduleParams&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;capacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            scheduleParams&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;maxTicketsPerPurchase&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; command&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The expectation is that any creation command is going to return the ID of the created aggregate, since the client doesn’t supply the ID but would need to know it.
For example, we probably want to display the created aggregate to confirm that the creation worked, so we need the ID to use as part of an HTTP redirection.
I ended up not bothering with that, since this is an example app, and so simply redirected back to the on-sale concerts page.&lt;/p&gt;
&lt;h3 id=&quot;the-test-fixture-is-inside-the-controller!&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/19/live-coding-journal-feb-19-2026/#the-test-fixture-is-inside-the-controller!&quot;&gt;The Test Fixture is Inside the Controller!&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With the “inside” of the schedule functionality complete, I test-drove the UI to wire it up.
On the way, instead of putting the test fixture for the &lt;code&gt;ScheduleConcertController&lt;/code&gt; in the test, @Suigi suggested going the &lt;a href=&quot;https://www.jamesshore.com/v2/projects/nullables/testing-without-mocks#nullables&quot;&gt;Nullables&lt;/a&gt; route.
At first, I didn’t think it’d work, because the test needed access to the &lt;code&gt;EventStore&lt;/code&gt; Test Double as well as the controller, and Java doesn’t have a way to return multiple values.
The way I typically do this in the test context is to use Extract Method, and then IntelliJ IDEA creates a record containing the objects the test needs as the return value.
However, there’s no reason not to do this in the production controller class!
Test code in a production class?
Blasphemy, I know.&lt;/p&gt;
&lt;p&gt;Here’s what it looks like:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Fixture&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createForTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; concertEventStore &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;InMemoryEventStore&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forConcerts&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;ScheduleConcertController&lt;/span&gt; scheduleConcertController &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ScheduleConcertController&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Commands&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;CommandExecutorFactory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertEventStore&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createScheduleCommand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Fixture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertEventStore&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; scheduleConcertController&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;record&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Fixture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;EventStore&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ConcertEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; concertEventStore&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
               &lt;span class=&quot;token class-name&quot;&gt;ScheduleConcertController&lt;/span&gt; controller&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So now the test can call &lt;code&gt;createForTest()&lt;/code&gt; and access the in-memory EventStore as well as the controller:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;postScheduleNewConcertCreatesConcert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; fixture &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ScheduleConcertController&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createForTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; redirect &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; fixture&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;controller&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scheduleNewConcert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ScheduleConcertController&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ScheduleForm&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Daylight Noise&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;35&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2026-03-14&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;19:00&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;18:00&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;75&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;redirect&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isEqualTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;redirect:/concerts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fixture&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concertEventStore&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;allEventsAfter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Checkpoint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;INITIAL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasExactlyElementsOfTypes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertScheduled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And if a test doesn’t need to see the EventStore, it can just ignore it.&lt;/p&gt;
&lt;h3 id=&quot;projection-vs.-read-model-vs.-query-and-validation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/19/live-coding-journal-feb-19-2026/#projection-vs.-read-model-vs.-query-and-validation&quot;&gt;Projection vs. Read-Model vs. Query and Validation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At around 3h35 in the stream, I discussed the similarities and differences in the terms “Projection”, “Read Model”, and “Query”, especially as it relates to Event Modeling.
It’s a bit confusing, because I see “Query” as a major component and none of the Event Models I see incorporate it.
This was all part of figuring out the next feature, which is validating the Schedule Concert to ensure that we’re not double-booking artists for the same date.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/19/live-coding-journal-feb-19-2026/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Next time we’ll dig into implementing the validation, as I think it’s important functionality that I haven’t tackled yet in this event-sourcing example application.&lt;/p&gt;
&lt;p&gt;Join me on my next stream, which I usually do Monday through Thursday, starting at 20:00 UTC on Twitch: &lt;a href=&quot;https://jitterted.stream/&quot;&gt;https://jitterted.stream&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Live Coding Journal - Feb 18, 2026</title>
    <link href="https://ted.dev/articles/2026/02/18/live-coding-journal-feb-18-2026/"/>
    <updated>2026-02-18T10:00:00Z</updated>
    <id>https://ted.dev/articles/2026/02/18/live-coding-journal-feb-18-2026/</id>
    <content xml:lang="en" type="html">&lt;div class=&quot;meta-notes-card&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All the code I’m working on in my live coding stream is available at &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced&quot;&gt;https://github.com/jitterted/jitterticket-event-sourced&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Notes from previous streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/04/live-coding-journal-feb-4-2026/&quot;&gt;Feb 4th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/05/live-coding-journal-feb-5-2026/&quot;&gt;Feb 5th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/09/live-coding-journal-feb-9-2026/&quot;&gt;Feb 9th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/10/live-coding-journal-feb-10-2026/&quot;&gt;Feb 10th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/11/live-coding-journal-feb-11-2026/&quot;&gt;Feb 11th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/12/live-coding-journal-feb-12-2026/&quot;&gt;Feb 12th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/16/live-coding-journal-feb-16-2026/&quot;&gt;Feb 16th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;notes-from-today%E2%80%99s-live-coding-session&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/18/live-coding-journal-feb-18-2026/#notes-from-today%E2%80%99s-live-coding-session&quot;&gt;Notes from Today’s Live Coding Session&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;refactoring-to-granular-reader-and-writer&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/18/live-coding-journal-feb-18-2026/#refactoring-to-granular-reader-and-writer&quot;&gt;Refactoring to Granular Reader and Writer&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;On today’s stream, I spent some time refactoring the use case/command/application layer code, i.e., the command and query for rescheduling concerts.
Instead of the typical case where I’d pass in a service class, or perhaps a full Repository (or in this case, the entire &lt;code&gt;EventStore&lt;/code&gt;), I now pass in more specific interfaces for doing a query for concerts (read) and the command object for rescheduling it (write).
Before the refactoring, the code looked like this:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@GetMapping&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/reschedule/{concertId}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rescheduleConcertView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@PathVariable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;concertId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; concertId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                                    &lt;span class=&quot;token class-name&quot;&gt;Model&lt;/span&gt; model&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt; concert &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; concertEventStore
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;orElseThrow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RuntimeException&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Could not find concert with id: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;  concertId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;concert&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ConcertView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;rescheduleForm&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RescheduleForm&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;reschedule-concert&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@PostMapping&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/reschedule/{concertId}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rescheduleConcert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@PathVariable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;concertId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; concertId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                                &lt;span class=&quot;token class-name&quot;&gt;RescheduleForm&lt;/span&gt; rescheduleForm&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;CommandExecutorFactory&lt;/span&gt; commandExecutorFactory &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CommandExecutorFactory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertEventStore&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; command &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; commandExecutorFactory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wrapWithParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reschedule&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                    concert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rescheduleTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                            reschedule&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;showDateTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            reschedule&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;doorsTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Reschedule&lt;/span&gt; rescheduleParams &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Reschedule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            rescheduleForm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;newShowLocalDateTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            rescheduleForm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;newDoorsLocalTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    command&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    rescheduleParams&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;redirect:/reschedule/&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; concertId&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After the refactoring, which included adding a factory method to &lt;code&gt;ConcertId&lt;/code&gt; that takes a UUID as string, it now looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@GetMapping&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/reschedule/{concertId}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rescheduleConcertView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@PathVariable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;concertId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; concertId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                                    &lt;span class=&quot;token class-name&quot;&gt;Model&lt;/span&gt; model&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt; id &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt; concert &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; concertQuery&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concertQueryFind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;concert&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ConcertView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;rescheduleForm&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RescheduleForm&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;reschedule-concert&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@PostMapping&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/reschedule/{concertId}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rescheduleConcert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@PathVariable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;concertId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; concertId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                                &lt;span class=&quot;token class-name&quot;&gt;RescheduleForm&lt;/span&gt; rescheduleForm&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    rescheduleCommand&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                              rescheduleForm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;asCommandParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;redirect:/reschedule/&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; concertId&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So much cleaner!
And just as easy to test as before, if not easier, because the &lt;code&gt;ConcertQuery&lt;/code&gt; has a single method that’s easier to replace with a test double if needed.&lt;/p&gt;
&lt;p&gt;I moved the creation of the command object to a new class, &lt;code&gt;Commands&lt;/code&gt;, where all new command objects will live:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Commands&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CommandExecutorFactory&lt;/span&gt; commandExecutorFactory&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Commands&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;CommandExecutorFactory&lt;/span&gt; commandExecutorFactory&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;commandExecutorFactory &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; commandExecutorFactory&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CommandWithParams&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Reschedule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createRescheduleCommand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token class-name&quot;&gt;CommandWithParams&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Reschedule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; command &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; commandExecutorFactory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wrapWithParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
              &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reschedule&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                      concert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rescheduleTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                              reschedule&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;showDateTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                              reschedule&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;doorsTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; command&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I still have some package reorganization to do, but I’m pretty happy with how this is set up.&lt;/p&gt;
&lt;h3 id=&quot;all-concert-aggregates-projection&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/18/live-coding-journal-feb-18-2026/#all-concert-aggregates-projection&quot;&gt;All Concert Aggregates Projection&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I then (around 3h04m) worked on fixing the problem where my event viewer was only showing &lt;code&gt;Concert&lt;/code&gt; objects that were available, i.e., tickets can be purchased.
That’s fine for showing the list of concerts to a customer, but for viewing the underlying events, I want to see all &lt;code&gt;Concert&lt;/code&gt; aggregates that ever existed.
For that, I needed a new projection.
It’s almost exactly like the &lt;code&gt;AvailableConcertsProjection&lt;/code&gt;, so I cheated a bit and copied it, leaving only the event it cares about: &lt;code&gt;ConcertScheduled&lt;/code&gt;.
It’s tempting to reuse the same projection for different situations, but since projections are cheap to code and create, it’s better to avoid potentially dangerous coupling.
I didn’t even bother test-driving it, since the code I extracted it from was well tested.
After updating the configuration to use the &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced/blob/f0813703ed62836bfdd8c4251eacf85517729e4f/src/main/java/dev/ted/jitterticket/eventsourced/application/AllConcertsProjector.java&quot;&gt;&lt;code&gt;AllConcertsProjection&lt;/code&gt;&lt;/a&gt;, everything just worked.&lt;/p&gt;
&lt;h3 id=&quot;event-modeling-tool-tryout&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/18/live-coding-journal-feb-18-2026/#event-modeling-tool-tryout&quot;&gt;Event Modeling Tool Tryout&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I’ve been using &lt;a href=&quot;http://tldraw.com/&quot;&gt;tldraw.com&lt;/a&gt; for my diagramming, which is a great tool, but since it’s a generic drawing tool, it can be a bit painful to create more structured diagrams, such as event models.
I spent about 90 minutes (starting around 1h30m into the video) trying out two tools: one was from @Suigi (aka Daniel Ranner), who create a tool called &lt;a href=&quot;https://github.com/Suigi/slicr&quot;&gt;Slicr&lt;/a&gt;.
Like PlantUML and Mermaid, it uses the text-to-diagram method, where you type structured text and the diagram is drawn from that description.
I think it’s so much better to create diagrams that way, since they’re much easier to make global changes to and easily diff between revisions.
It turns out LLMs are pretty good at it too, since it’s “just text”.
I built out the Purchase Tickets slice of JitterTicket (you can see it at 2h20m) and once I got the syntax down (though it uses YAML, sigh), it was straightforward to use.&lt;/p&gt;
&lt;p&gt;I then (around 2h32m) looked at &lt;a href=&quot;https://ismaelcelis.com/&quot;&gt;Ismael Celis’&lt;/a&gt; &lt;a href=&quot;https://eventlanes.app/&quot;&gt;EventLanes app&lt;/a&gt;.
(It was neat to report a bug on stream and have Ismael fix it right away!)
Event Lanes is in beta, but has some really nice features around schemas that define the data elements used in read models, commands, and UIs.
I also created the Purchase Tickets slice and added the Concert Started Processor to the diagram (see 3h02m).
The tool itself is event-sourced, so you can look at the history and time-travel to see what the diagram was at any point.
It’s also multi-user and (like many tools these days) has an &lt;a href=&quot;https://modelcontextprotocol.io/&quot;&gt;MCP Server&lt;/a&gt; so an LLM can control it more directly.
I look forward to spending more time with this tool, especially when looking at how to use the diagram text for code generation.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/18/live-coding-journal-feb-18-2026/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I want to add some concert scheduling validation, where the system ensures that you can’t schedule two concerts for the same date.
This will need yet another projection, but those are straightforward to create.
That will require implementing the “creator” command, which will be tricky because creation happens via static methods, so I’m unsure how to fit that into the current code.&lt;/p&gt;
&lt;p&gt;Before I do any of that, however, I’ll be upgrading (finally!) to Spring Boot 4.0.3.&lt;/p&gt;
&lt;p&gt;Join me on my next stream, which I usually do Monday through Thursday, starting at 20:00 UTC on Twitch: &lt;a href=&quot;https://jitterted.stream/&quot;&gt;https://jitterted.stream&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Live Coding Journal - Feb 16, 2026</title>
    <link href="https://ted.dev/articles/2026/02/16/live-coding-journal-feb-16-2026/"/>
    <updated>2026-02-16T10:00:00Z</updated>
    <id>https://ted.dev/articles/2026/02/16/live-coding-journal-feb-16-2026/</id>
    <content xml:lang="en" type="html">&lt;div class=&quot;meta-notes-card&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All the code I’m working on in my live coding stream is available at &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced&quot;&gt;https://github.com/jitterted/jitterticket-event-sourced&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Notes from previous streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/04/live-coding-journal-feb-4-2026/&quot;&gt;Feb 4th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/05/live-coding-journal-feb-5-2026/&quot;&gt;Feb 5th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/09/live-coding-journal-feb-9-2026/&quot;&gt;Feb 9th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/10/live-coding-journal-feb-10-2026/&quot;&gt;Feb 10th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/11/live-coding-journal-feb-11-2026/&quot;&gt;Feb 11th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/12/live-coding-journal-feb-12-2026/&quot;&gt;Feb 12th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;notes-from-today%E2%80%99s-live-coding-session&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/16/live-coding-journal-feb-16-2026/#notes-from-today%E2%80%99s-live-coding-session&quot;&gt;Notes from Today’s Live Coding Session&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;olive-tests-%3D-test-list%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/16/live-coding-journal-feb-16-2026/#olive-tests-%3D-test-list%3F&quot;&gt;Olive Tests = Test List?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Today I realized that the way I use Olive Tests, where the test fails as predicted, as I take small steps to get it to fail in a new, but still expected, way, is very much like Kent Beck’s &lt;a href=&quot;https://tidyfirst.substack.com/i/139601698/1-test-list&quot;&gt;Test List&lt;/a&gt;.
However, Instead of spreading the steps across multiple tests, I’m spreading it across multiple assertions and using the idea of an Olive Test to allow me to know when to move forward to get the next assertion to pass.&lt;/p&gt;
&lt;h3 id=&quot;concert-started-processor-is-doing-its-job&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/16/live-coding-journal-feb-16-2026/#concert-started-processor-is-doing-its-job&quot;&gt;Concert Started Processor is Doing its Job&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When I ran all the tests for the first time since last week, I was initially confused by a test failure that checked available concerts in the sample data, where it found 9 instead of the 10 that the sample data populator creates.
It turned out to be the &lt;code&gt;ConcertStartedProcessor&lt;/code&gt; that I finished last week was doing its job by stopping ticket sales on one of the sample concert events, and therefore no longer appeared in the list of “available concerts”!&lt;/p&gt;
&lt;h3 id=&quot;reschedule-concert-use-case-complete&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/16/live-coding-journal-feb-16-2026/#reschedule-concert-use-case-complete&quot;&gt;Reschedule Concert Use Case Complete&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I finished the UI for “Reschedule Concert” and as is often the case, when I ran the application, it just worked.
I did cheat a bit and reused an existing screen by adding a “reschedule” link to the “Concerts” view page, and after a Reschedule Concert is submitted, I redirect back to the Reschedule page instead of creating a new confirmation page.
It’s not the way I’d do things if this were a production app, but this is an example learning app—despite its ever-increasing scope—so I’m OK with such shortcuts.&lt;/p&gt;
&lt;h3 id=&quot;design-aspects-of-command-execution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/16/live-coding-journal-feb-16-2026/#design-aspects-of-command-execution&quot;&gt;Design Aspects of Command Execution&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I really like the way command method invocations are wrapped in a “unit of work”, like this code from the &lt;code&gt;RescheduleConcertController&lt;/code&gt;’s &lt;code&gt;POST&lt;/code&gt; handler:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@PostMapping&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/reschedule/{concertId}&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rescheduleConcert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@PathVariable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;concertId&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; concertId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                                &lt;span class=&quot;token class-name&quot;&gt;RescheduleForm&lt;/span&gt; rescheduleForm&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;CommandExecutorFactory&lt;/span&gt; commandExecutorFactory &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; 
            &lt;span class=&quot;token class-name&quot;&gt;CommandExecutorFactory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertEventStore&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; command &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; commandExecutorFactory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wrapWithParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reschedule&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;
                    concert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rescheduleTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                            reschedule&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;showDateTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                            reschedule&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;doorsTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token class-name&quot;&gt;Reschedule&lt;/span&gt; rescheduleParams &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Reschedule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            rescheduleForm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;newShowLocalDateTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            rescheduleForm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;newDoorsLocalTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    command&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fromString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                    rescheduleParams&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;redirect:/reschedule/&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; concertId&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code needs to be refactored, but the issue I’m struggling with is where the &lt;code&gt;command&lt;/code&gt; creation (which is a stateless command object) would go.
I don’t have a general design pattern for this kind of code, usually I have a “service” or “application” layer class that would handle the infrastructure work for multiple different commands. For example, see &lt;a href=&quot;https://github.com/tedyoung/moborg/blob/5ef6f55646f8c9ff26a3c29960c2c96ca27d6d28/src/main/java/com/jitterted/mobreg/application/EnsembleService.java#L147&quot;&gt;&lt;code&gt;EnsembleService#joinAsParticipant()&lt;/code&gt;&lt;/a&gt;) in my Ensembler application.
Note that even there I refactored to an “execute around” method (see line 179 in the same file), so that aspect isn’t new to me.&lt;/p&gt;
&lt;p&gt;It seems like this controller method should map directly to one of those command objects, requiring some (“service”) class needs to provide a way to get the “Reschedule” command object, which would encapsulate the &lt;code&gt;create()&lt;/code&gt; and &lt;code&gt;wrapWithParams()&lt;/code&gt; that I’m doing above.
Maybe the &lt;code&gt;RescheduleForm&lt;/code&gt; would encapsulate the command, since it already has the information needed (new show date/time, etc.).
I’ll start playing with some ideas for refactoring this on the next stream.&lt;/p&gt;
&lt;h3 id=&quot;deciders-vs.-processors&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/16/live-coding-journal-feb-16-2026/#deciders-vs.-processors&quot;&gt;Deciders vs. Processors&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After doing all this event-sourcing work with &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced&quot;&gt;JitterTicket&lt;/a&gt;, I’m starting to get more precise about how I think and talk about the concepts.
For example (at timestamp 3:04:50), I describe a &lt;strong&gt;Decider&lt;/strong&gt; as something that takes existing &lt;em&gt;State&lt;/em&gt; (projected from a series of events), makes a Decision using the state as input, and outputting an &lt;em&gt;Event&lt;/em&gt;.
I think of this as a &lt;strong&gt;Stateful Decider&lt;/strong&gt; because it requires the input &lt;em&gt;State&lt;/em&gt; in order to make a decision (&lt;em&gt;am I allowing this command to succeed&lt;/em&gt;?).
I haven’t (yet) come across a &lt;strong&gt;Stateless Decider&lt;/strong&gt;, where the decision doesn’t require existing &lt;em&gt;State&lt;/em&gt;, but that’s not to say it couldn’t exist.
(If you know of an example, please &lt;a href=&quot;https://ted.dev/about&quot;&gt;share it with me&lt;/a&gt;!)&lt;/p&gt;
&lt;p&gt;It’s possible a command that creates an entity (say, registering a new customer) is a &lt;strong&gt;Stateless Decider&lt;/strong&gt;, but I think of it more explicitly as a &lt;strong&gt;Creator&lt;/strong&gt;.
However, if its creation has rules (e.g., customer email must be unique), then &lt;em&gt;State&lt;/em&gt; is required (again from some projection, e.g., all active customer emails), so does that make it a &lt;strong&gt;Stateful Decider&lt;/strong&gt;?
From an event-sourcing point of view, creation is no different from any other event, so maybe it is?&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;Stateless Processor&lt;/strong&gt; on the other hand, takes an &lt;em&gt;Event&lt;/em&gt; as input, and uses that to make a decision, and outputs a &lt;em&gt;Command&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;And I guess a &lt;strong&gt;Projector&lt;/strong&gt; takes an event (or stream of events) and outputs a &lt;strong&gt;Projection&lt;/strong&gt;, i.e., &lt;em&gt;State&lt;/em&gt;.
It might persist the previous state as a cache, but I see that as a &lt;em&gt;Snapshot&lt;/em&gt; for optimization, something that &lt;strong&gt;Stateful Deciders&lt;/strong&gt; could do as well, especially since a &lt;strong&gt;Stateful Decider&lt;/strong&gt; is a &lt;strong&gt;Projection&lt;/strong&gt; plus a &lt;strong&gt;Decider&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/16/live-coding-journal-feb-16-2026/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We’ll refactor the Reschedule command object and then create an “All Concert Aggregates” Projector to use when examining the underlying events with the event viewer.
We need this because the current event viewer uses the “Available” concerts projection, which drops concerts that we might want to examine.&lt;/p&gt;
&lt;p&gt;Join me on my next stream, which I usually do Monday through Thursday, starting at 20:00 UTC on Twitch: &lt;a href=&quot;https://jitterted.stream/&quot;&gt;https://jitterted.stream&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Live Coding Journal - Feb 12, 2026</title>
    <link href="https://ted.dev/articles/2026/02/12/live-coding-journal-feb-12-2026/"/>
    <updated>2026-02-12T10:00:00Z</updated>
    <id>https://ted.dev/articles/2026/02/12/live-coding-journal-feb-12-2026/</id>
    <content xml:lang="en" type="html">&lt;div class=&quot;meta-notes-card&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All the code I’m working on in my live coding stream is available at &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced&quot;&gt;https://github.com/jitterted/jitterticket-event-sourced&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Notes from previous streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/04/live-coding-journal-feb-4-2026/&quot;&gt;Feb 4th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/05/live-coding-journal-feb-5-2026/&quot;&gt;Feb 5th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/09/live-coding-journal-feb-9-2026/&quot;&gt;Feb 9th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/10/live-coding-journal-feb-10-2026/&quot;&gt;Feb 10th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/11/live-coding-journal-feb-11-2026/&quot;&gt;Feb 11th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;notes-from-today%E2%80%99s-live-coding-session&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/12/live-coding-journal-feb-12-2026/#notes-from-today%E2%80%99s-live-coding-session&quot;&gt;Notes from Today’s Live Coding Session&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;don%E2%80%99t-use-an-sdk-when-a-post-will-do&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/12/live-coding-journal-feb-12-2026/#don%E2%80%99t-use-an-sdk-when-a-post-will-do&quot;&gt;Don’t Use an SDK When a POST Will Do&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I spent far too long trying to replace the email service in my &lt;a href=&quot;https://github.com/jitterted/ensembler/&quot;&gt;Ensembler tool&lt;/a&gt; from SendGrid (who started charging even for minimal usage) to Brevo.
It was a terrible experience, with inconsistent documentation, a vendor-supplied Java SDK with many problems, a third-party SDK that was overkill, and a support chat LLM that provided completely wrong information.
I really should have looked closer at what I needed, because a single HTTP &lt;code&gt;POST&lt;/code&gt; would have been sufficient.
However, I’m &lt;strong&gt;extremely&lt;/strong&gt; displeased at Brevo’s use of LLM for support chat, since it is &lt;strong&gt;well known&lt;/strong&gt; that they provide wrong answers.
It’s likely I’ll try out Postmark (using straight HTTP requests) unless Brevo decides to kick the LLM chatbot off the site—I refuse to support companies that waste my time in that way.&lt;/p&gt;
&lt;h3 id=&quot;generics-and-lambdas-break-my-brain&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/12/live-coding-journal-feb-12-2026/#generics-and-lambdas-break-my-brain&quot;&gt;Generics and Lambdas Break My Brain&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The main task for the rest of the stream was to expand the use of lambda-based Command Objects for executing command methods against the &lt;code&gt;Concert&lt;/code&gt; aggregate.
I had a nice &lt;code&gt;wrap&lt;/code&gt; method that returned a “unit of work” composed object:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wrap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; concertCommand&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; concertId &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; concertEvents &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; concertEventStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;eventsForAggregate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt; concert &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reconstitute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertEvents&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        concertCommand&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        concertEventStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, this was only for methods (like &lt;code&gt;.stopTicketSales()&lt;/code&gt;) that take no parameters.
I wanted to implement the Reschedule Concert command similarly, but it takes two parameters, and it took a surprising amount of time for me to get that working.
Around 1:47:42 is when the struggle began and, after a number of false starts, @Suigi comes through (again) and reminds me to revert the lambda I was trying to write into an anonymous inner class.
That made everything so much more clear, and was able to get where I wanted:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CommandWithParams&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Reschedule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wrapWithParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;CommandWithParams&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Reschedule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; command&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reschedule&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; concertEvents &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; concertEventStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;eventsForAggregate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt; concert &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reconstitute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertEvents&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    command&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reschedule&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    concertEventStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I wasn’t ready to ship it yet, because (around 2:28:40) as I was writing a test for the code (a rare code-first episode) I started to realize something was wrong with the unit work of work code wrapping the command, i.e., reconstituting the &lt;code&gt;Concert&lt;/code&gt; by loading the events and calling the &lt;code&gt;.reconstitute()&lt;/code&gt; static method: if the Concert didn’t exist, we’d try to reconstitute it from an empty list of events!
Oops, that won’t work, and, in fact, that’s an important missing validation in the &lt;code&gt;reconstitute()&lt;/code&gt; method! I added a quick validation for that:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;reconstitute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; concertEvents&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertEvents&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isEmpty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IllegalArgumentException&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Can not reconstitute from an empty list of ConcertEvents.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertEvents&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I then updated the code to properly call the event store’s &lt;code&gt;findById()&lt;/code&gt; method instead:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CommandWithParams&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Reschedule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;wrapWithParams&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;CommandWithParams&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Reschedule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; command&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reschedule&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt; concert &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; concertEventStore
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;findById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;orElseThrow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IllegalArgumentException&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Could not find Concert with ID &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; concertId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    command&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reschedule&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    concertEventStore&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once again, thinking through things to predict how the test would fail revealed a problem even before I had a failing test, but then the test still failed in a &lt;em&gt;different&lt;/em&gt; way, which revealed a problem with the test.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One thing I hadn’t realized until I was writing these notes is that I need to go back and fix the no-arg &lt;code&gt;wrap()&lt;/code&gt; to also use &lt;code&gt;findById()&lt;/code&gt;!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;event-modeling-for-reschedule-concert&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/12/live-coding-journal-feb-12-2026/#event-modeling-for-reschedule-concert&quot;&gt;Event Modeling for Reschedule Concert&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Around 3:00:30, I do a quick event model for rescheduling concerts, and then decide not to build a completely new UI for it. The list of concerts to display for scheduling is the same as the list of concerts for purchasing, so I decided to just add another button for “reschedule”.
Then I did the usual test-driving of a new UI endpoint, though it had been a while since I wrote one of those, so I made some silly mistakes.
I ended the stream with an Olive test (fails as expected) that I’ll pick up on the next stream.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/12/live-coding-journal-feb-12-2026/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For next time, I’ll:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fix &lt;code&gt;wrap()&lt;/code&gt; to use &lt;code&gt;findById()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Finish the Olive test for the reschedule controller&lt;/li&gt;
&lt;li&gt;Look at a tool for doing event-modeling?&lt;/li&gt;
&lt;li&gt;Maybe figure out in which package the &lt;code&gt;CommandExecutorFactory&lt;/code&gt; should live&lt;/li&gt;
&lt;li&gt;Generify &lt;code&gt;CommandExecutorFactory&lt;/code&gt; so I can use it with the &lt;code&gt;Customer&lt;/code&gt; aggregate&lt;/li&gt;
&lt;li&gt;And maybe look at how to design aggregate-slices (Deciders) that can leverage the command objects, which might help in converting the &lt;code&gt;PurchaseTicketsUseCase&lt;/code&gt; to use the &lt;code&gt;CommandExecutorFactory&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Join me on my next stream, which I usually do Monday through Thursday, starting at 20:00 UTC on Twitch: &lt;a href=&quot;https://jitterted.stream/&quot;&gt;https://jitterted.stream&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Live Coding Journal - Feb 11, 2026</title>
    <link href="https://ted.dev/articles/2026/02/11/live-coding-journal-feb-11-2026/"/>
    <updated>2026-02-11T10:00:00Z</updated>
    <id>https://ted.dev/articles/2026/02/11/live-coding-journal-feb-11-2026/</id>
    <content xml:lang="en" type="html">&lt;div class=&quot;meta-notes-card&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All the code I’m working on in my live coding stream is available at &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced&quot;&gt;https://github.com/jitterted/jitterticket-event-sourced&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Notes from previous streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/04/live-coding-journal-feb-4-2026/&quot;&gt;Feb 4th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/05/live-coding-journal-feb-5-2026/&quot;&gt;Feb 5th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/09/live-coding-journal-feb-9-2026/&quot;&gt;Feb 9th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/10/live-coding-journal-feb-10-2026/&quot;&gt;Feb 10th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;notes-from-today%E2%80%99s-live-coding-session&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/11/live-coding-journal-feb-11-2026/#notes-from-today%E2%80%99s-live-coding-session&quot;&gt;Notes from Today’s Live Coding Session&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Today I finished the final piece of the &lt;code&gt;ConcertStartedProcessor&lt;/code&gt; where the &lt;code&gt;Concert.stopTicketSales()&lt;/code&gt; command method is called as a result of the &lt;code&gt;ScheduledFuture&lt;/code&gt; being executed by the &lt;code&gt;ScheduledExecutorService&lt;/code&gt;.
It took a bit of sketching code to figure out what the types should be for the nested lambdas (you might be amused to find me writing some old skool anonymous inner classes!), which turned out to be very much like defining partial functions.
The three levels of nesting of the lambdas didn’t make things any easier.&lt;/p&gt;
&lt;h3 id=&quot;command-executor-factory&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/11/live-coding-journal-feb-11-2026/#command-executor-factory&quot;&gt;Command Executor Factory&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is where I ended up with the &lt;code&gt;CommandExecutorFactory&lt;/code&gt;, which is a “Unit of Work Composer”:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The outermost lambda is the &lt;code&gt;Runnable&lt;/code&gt; that is passed to the &lt;code&gt;ScheduledExecutorService&lt;/code&gt; when scheduling the “alarm” that will be executed at the concert’s show date and time.&lt;/li&gt;
&lt;li&gt;The next level is the “infrastructure” or “unit of work” wrapper that does the work of loading the &lt;code&gt;Concert&lt;/code&gt; aggregate from the event store, calling the inner lambda, and the persisting any changes back to the event store.&lt;/li&gt;
&lt;li&gt;The innermost level is the command method, in this case the literal method handle &lt;code&gt;Concert::stopTicketSales&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And this is what it looks like in the code when creating one of these wrappers for testing purposes:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// create the factory configured with the event store for Concerts&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;CommandExecutorFactory&lt;/span&gt; factory &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CommandExecutorFactory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertEventStore&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// create the innermost lambda that executes the desired command method on Concert&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; command &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stopTicketSales&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;// ask the factory to wrap (compose) the method-level command with the infrastructure handling code&lt;/span&gt;
&lt;span class=&quot;token class-name&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; commandExecutor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; factory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wrap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;command&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, when I want to wrap any &lt;code&gt;Concert&lt;/code&gt; command method that needs the infrastructure to handle persistence, everything is the same except for the innermost &lt;code&gt;Command&amp;lt;Concert&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is what the &lt;code&gt;ConcertStartedProcessor&lt;/code&gt; does when scheduling that command in the &lt;code&gt;scheduleAlarm&lt;/code&gt; method:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;ScheduledFuture&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; scheduledFuture &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; scheduledExecutorService
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;schedule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; commandExecutorFactory
                          &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;wrap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stopTicketSales&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                          &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                  &lt;span class=&quot;token function&quot;&gt;delayFromNowInMinutes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;showDateTime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                  &lt;span class=&quot;token class-name&quot;&gt;TimeUnit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MINUTES&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where that first parameter is the outermost lambda—a &lt;code&gt;Runnable&lt;/code&gt;—that will invoke the unit of work to stop ticket sales.&lt;/p&gt;
&lt;p&gt;I still have work to do to generalize this command-method invocation, because &lt;code&gt;stopTicketSales&lt;/code&gt; doesn’t take any parameters, but the other command methods (e.g., schedule, reschedule) need at least a couple of parameters.
I’ll also need to deal with the different unit of work around command methods that do “creation” of the aggregate, e.g., &lt;code&gt;Concert.schedule()&lt;/code&gt; and &lt;code&gt;Customer.register()&lt;/code&gt;, since neither one has an aggregate to load from persistence (they still need to save, of course).&lt;/p&gt;
&lt;h3 id=&quot;tedbits&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/11/live-coding-journal-feb-11-2026/#tedbits&quot;&gt;Tedbits&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After some weirdness with resetting the database so I could create sample data that would demonstrate that the scheduled futures actually get executed, I was able to see the processor doing its job, because a concert that started 10 seconds after the application started no longer appeared in the “Available Concerts” projection.
This was actually a problem because my event viewer for Concerts was using the same projection!
Oops, I’ll have to create another projection that has all Concerts ever scheduled.
Luckily they’re straightforward to write now that the infrastructure wrapper for them (the &lt;code&gt;ProjectionCoordinator&lt;/code&gt;) exists.&lt;/p&gt;
&lt;p&gt;We had some good side discussions about &lt;a href=&quot;https://www.jamesshore.com/v2/projects/nullables/testing-without-mocks#nullables&quot;&gt;James Shore’s “Nullables”&lt;/a&gt; and how they might &lt;em&gt;seem&lt;/em&gt; to violate the “don’t put test code in production code” rule.
As I said on the stream:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“The reason why you want to put these creation methods in the production code is the production code knows more about what it needs [and what its dependencies need] and is more resilient in the face of refactorings.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/11/live-coding-journal-feb-11-2026/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Besides the new projection for all Concerts, and the further generalization of the CommandExecutorFactory, I want to add a UI for both the Schedule Concert and Reschedule Concert use cases.
I hadn’t needed them when my focus was on figuring out Event-Sourcing, but it’ll be good to get the entire process implemented to see where I might have holes in the implementation.
(This is the downside of doing inside-out development, you don’t know what might be needed by the outer layers of the application until they’re implemented.)&lt;/p&gt;
&lt;p&gt;Join me on my next stream, which I usually do Monday through Thursday, starting at 20:00 UTC on Twitch: &lt;a href=&quot;https://jitterted.stream/&quot;&gt;https://jitterted.stream&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Live Coding Journal - Feb 10, 2026</title>
    <link href="https://ted.dev/articles/2026/02/10/live-coding-journal-feb-10-2026/"/>
    <updated>2026-02-10T10:00:00Z</updated>
    <id>https://ted.dev/articles/2026/02/10/live-coding-journal-feb-10-2026/</id>
    <content xml:lang="en" type="html">&lt;div class=&quot;meta-notes-card&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All the code I’m working on in my live coding stream is available at &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced&quot;&gt;https://github.com/jitterted/jitterticket-event-sourced&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Notes from previous streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/04/live-coding-journal-feb-4-2026/&quot;&gt;Feb 4th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/05/live-coding-journal-feb-5-2026/&quot;&gt;Feb 5th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/09/live-coding-journal-feb-9-2026/&quot;&gt;Feb 9th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;notes-from-today%E2%80%99s-live-coding-session&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/10/live-coding-journal-feb-10-2026/#notes-from-today%E2%80%99s-live-coding-session&quot;&gt;Notes from Today’s Live Coding Session&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;another-precursor-to-primitive-obsession&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/10/live-coding-journal-feb-10-2026/#another-precursor-to-primitive-obsession&quot;&gt;Another Precursor to Primitive Obsession&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In the &lt;code&gt;ConcertStartedProcessor&lt;/code&gt;, the &lt;code&gt;alarms()&lt;/code&gt; query method now returns a &lt;code&gt;Map&amp;lt;ConcertId, ConcertAlarm&amp;gt;&lt;/code&gt;, but refactoring from the previous map type of &lt;code&gt;Map&amp;lt;ConcertId, LocalDateTime&amp;gt;&lt;/code&gt; was made difficult because the “primitive” Map type (I define primitive as a type that is not constrained, such as a &lt;code&gt;long&lt;/code&gt;, &lt;code&gt;String&lt;/code&gt;, or collection class) rippled throughout the tests, whereas creating a domain-specific &lt;code&gt;Alarms&lt;/code&gt; class that encapsulated the Map would have prevented the rippling.&lt;/p&gt;
&lt;p&gt;What I call “second-level thinking” is also important when determining who’s responsible for a certain behavior.
For example, with the &lt;code&gt;cancelAlarm()&lt;/code&gt; command method, should the caller check whether the alarm is in the map before attempting to cancel it, or should &lt;code&gt;cancelAlarm()&lt;/code&gt; ignore the call if the concert isn’t in the map.
In this case, operations like “cancel” should be &lt;em&gt;idempotent&lt;/em&gt;, meaning that if a caller happens to call it twice, (or many times), the result is that the alarm is canceled, and further calls should be ignored.&lt;/p&gt;
&lt;h3 id=&quot;using-olive-tests-as-stepping-stones-to-green&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/10/live-coding-journal-feb-10-2026/#using-olive-tests-as-stepping-stones-to-green&quot;&gt;Using OLIVE Tests as Stepping Stones to Green&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I really like calling the tests that are “failing, but for the right reason” as “olive”, because it means I can treat it as a “passing” test when doing things like refactoring. See the video timestamp around 1h35m for an example.&lt;/p&gt;
&lt;h3 id=&quot;date-time-math-is-hard&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/10/live-coding-journal-feb-10-2026/#date-time-math-is-hard&quot;&gt;Date-Time Math is Hard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;And how. Converting a future date (the concert’s show date and time, which uses the Java Date/Time API) into a delay amount with time units (Java Concurrent’s way of specifying a Duration) is harder than it should be. Time zones made it harder, but after extracting out the date-time factory methods into a separate class, and letting it use the &lt;code&gt;Clock&lt;/code&gt; interface to define what “now()” is, made it easier.&lt;/p&gt;
&lt;h3 id=&quot;tedbits&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/10/live-coding-journal-feb-10-2026/#tedbits&quot;&gt;Tedbits&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Clever is often not better. When implementing the &lt;code&gt;cancelAlarm()&lt;/code&gt; method, I originally tried to use the &lt;code&gt;computeIfPresent()&lt;/code&gt; method, where I could cancel the ScheduledFuture, and then return null to have the map remove the entry, and while that worked, the straightforward if-null check on the &lt;code&gt;remove()&lt;/code&gt; method was simpler.
These are the two options:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt; &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cancelAlarm&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt; concertId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    alarmMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;computeIfPresent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            concertId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; concertAlarm&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                concertAlarm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cancel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;vs.&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt; &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cancelAlarm&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt; concertId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;ConcertAlarm&lt;/span&gt; removedAlarm &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; alarmMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;removedAlarm &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        removedAlarm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cancel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We all agreed that the second option was much easier to read.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/10/live-coding-journal-feb-10-2026/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In my next live coding stream, I’ll fix the last edge case that @Suigi suggested, where a concert rescheduled from the future to the past should cancel the alarm.
Then I’ll work on the actual Runnable task that will be passed to the &lt;code&gt;ScheduledExecutorService&lt;/code&gt;, which will require the &lt;code&gt;StopTicketSalesCommand&lt;/code&gt; to be implemented.&lt;/p&gt;
&lt;p&gt;Join me on my streams, which I usually do Monday through Thursday, starting at 20:00 UTC on Twitch: &lt;a href=&quot;https://jitterted.stream/&quot;&gt;https://jitterted.stream&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Live Coding Journal - Feb 9, 2026</title>
    <link href="https://ted.dev/articles/2026/02/09/live-coding-journal-feb-9-2026/"/>
    <updated>2026-02-09T10:00:00Z</updated>
    <id>https://ted.dev/articles/2026/02/09/live-coding-journal-feb-9-2026/</id>
    <content xml:lang="en" type="html">&lt;div class=&quot;meta-notes-card&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All the code I’m working on in my live coding stream is available at &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced&quot;&gt;https://github.com/jitterted/jitterticket-event-sourced&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Notes from previous streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/04/live-coding-journal-feb-4-2026/&quot;&gt;Feb 4th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/05/live-coding-journal-feb-5-2026/&quot;&gt;Feb 5th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;notes-from-today%E2%80%99s-live-coding-session&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/09/live-coding-journal-feb-9-2026/#notes-from-today%E2%80%99s-live-coding-session&quot;&gt;Notes from Today’s Live Coding Session&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;aggregates%2C-deciders%2C-and-projections&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/09/live-coding-journal-feb-9-2026/#aggregates%2C-deciders%2C-and-projections&quot;&gt;Aggregates, Deciders, and Projections&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I continued to refine my mental model around Aggregates as a bundle of related Deciders that use an internal Projection to use as the input state to the domain logic when executing a Command. For example, when the &lt;code&gt;Concert&lt;/code&gt; aggregate is loaded, it replays all events having to do with that specific aggregate (scheduled, rescheduled, tickets sold, ticket sales stopped), even if the Command being executed (say, rescheduling) only needs part of the &lt;code&gt;Concert&lt;/code&gt;’s state, e.g., just the Show Date &amp;amp; Time. We could break down the Aggregate into Deciders, which have the minimal state needed to make the decision, which therefore means playing back (processing) fewer events. As a long time DDD and OOP developer, I’m not sure I’d like having to handle Deciders as more granular objects, but I’ll experiment with it at some point to explore how it feels.&lt;/p&gt;
&lt;h3 id=&quot;processor-vs.-aggregate-(decider)&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/09/live-coding-journal-feb-9-2026/#processor-vs.-aggregate-(decider)&quot;&gt;Processor vs. Aggregate (Decider)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I’m still trying to figure out the heuristic for when to use a Processor to execute a Command (and therefore generate an Event) vs. using the Aggregate to handle the decision-making and generate the Event. It feels similar to Domain Services vs. Aggregates in that Domain Services are used when state from multiple Aggregates is needed to make a decision, or the state change affects multiple Aggregates. It’s still unclear to me how I would implement the functionality of refunding tickets to all customers that purchased tickets to a Concert that was then canceled. It could certainly be done with the Use Case (or Command Object, see below), but I could also see it being done with a Processor, especially since it doesn’t have to be done synchronously with the cancellation process.&lt;/p&gt;
&lt;h3 id=&quot;two-types-of-projections%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/09/live-coding-journal-feb-9-2026/#two-types-of-projections%3F&quot;&gt;Two Types of Projections?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After thinking about Processors vs. Aggregates (around the 12-minute mark in the video), it really seems like there are two types of Projections: those that are used as “read (only) models”, e.g., for reporting or display on a UI, and those that are used as input state for automated decision-making, i.e., for Processors. It also led me to think about Processors that make decisions solely on the input Event, which turns out to be what some folks call “Translators”. I think it’s really useful to separate those two, as Processors need the Projections as “accumulated state”, whereas Translators are truly functional and require no state.&lt;/p&gt;
&lt;h3 id=&quot;use-case-vs.-command-object&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/09/live-coding-journal-feb-9-2026/#use-case-vs.-command-object&quot;&gt;Use Case vs. Command Object&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I’ve been implementing the Application-level Use Cases as stateless service objects, but when I started thinking about the implementation for the next use case (around the 2h56m mark in the video), stopping ticket sales, I realized that the structure of that code follows the same pattern:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Load the &lt;code&gt;Concert&lt;/code&gt; Aggregate from the Concert Event Store.&lt;/li&gt;
&lt;li&gt;Invoke the Command method on the &lt;code&gt;Concert&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Have the Concert Event Store persist the generated Events (if any).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Creating a Command class that follows the Composite pattern where it takes the event store and the Concert ID would be very handy. I also decided that a Command Factory configured with the Event Store would make it easier to create Commands for a specific Concert, as I wouldn’t have to pass the Event Store each time I want a Command. It also means fewer generics to deal with for the Command itself.&lt;/p&gt;
&lt;h3 id=&quot;concertstartedprocessor&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/09/live-coding-journal-feb-9-2026/#concertstartedprocessor&quot;&gt;ConcertStartedProcessor&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I made good progress on the &lt;code&gt;ConcertStartedProcessor&lt;/code&gt;, test-driving the implementation step-by-step, handling a new event each time around the TDD loop. I also implemented ignoring Concerts that had a Show Date &amp;amp; Time in the past, as there’s no reason to track them as they’ve already happened. The refactoring along the way was interesting, because I went from an ugly &lt;code&gt;if&lt;/code&gt; block to a &lt;code&gt;switch&lt;/code&gt; statement, then to a &lt;code&gt;switch&lt;/code&gt; expression, but then back to a &lt;code&gt;switch&lt;/code&gt; statement as I fleshed out the events that it handles. At the end of the refactoring, I noticed that I had two methods:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cancelAlarm&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt; concertId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    alarmMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;remove&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scheduleAlarm&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConcertId&lt;/span&gt; concertId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LocalDateTime&lt;/span&gt; showDateTime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;showDateTime&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isAfter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;LocalDateTime&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        alarmMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;put&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concertId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; showDateTime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This triggered my mental “Primitive Obsession” heuristic, because both methods (which are command methods) take the same parameter, &lt;code&gt;ConcertId&lt;/code&gt;. Any time I see a pattern like that, I consider creating a wrapper object that encapsulates the parameter and provides those command methods on the new object. Something like &lt;code&gt;ConcertAlarm.scheduled(LocalDateTime showDateTime)&lt;/code&gt; and &lt;code&gt;ConcertAlarm.cancel()&lt;/code&gt; are what I’d want instead.&lt;/p&gt;
&lt;p&gt;I didn’t do that refactoring, because I already had in mind a &lt;code&gt;ConcertAlarm&lt;/code&gt; class, but I’m not yet sure what else it would contain, so I’ll delay the refactoring until I know more.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Precursor to Primitive Obsession&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When multiple methods take the same parameter, that’s a sign that there you’re missing a wrapper object that encapsulates the parameter and provides those methods.&lt;/p&gt;
&lt;p&gt;I talk about this in-depth in my online presentation &lt;a href=&quot;https://ted.dev/articles/2023/05/30/your-classes-are-too-big-talk/&quot;&gt;“Stop Obsessing About Primitives”&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/09/live-coding-journal-feb-9-2026/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In my next live coding stream, I’ll dig into the actual scheduling of the alarms, using Java’s &lt;code&gt;ScheduledExecutorService&lt;/code&gt;. I still need to figure out the right “seam” for separating the I/O (which are the &lt;code&gt;ScheduledFuture&lt;/code&gt;s) from the processor logic.&lt;/p&gt;
&lt;p&gt;Join me on my streams, which I usually do Monday through Thursday, starting at 20:00 UTC on Twitch: &lt;a href=&quot;https://jitterted.stream/&quot;&gt;https://jitterted.stream&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Live Coding Journal - Feb 5, 2026</title>
    <link href="https://ted.dev/articles/2026/02/05/live-coding-journal-feb-5-2026/"/>
    <updated>2026-02-05T12:00:00Z</updated>
    <id>https://ted.dev/articles/2026/02/05/live-coding-journal-feb-5-2026/</id>
    <content xml:lang="en" type="html">&lt;div class=&quot;meta-notes-card&quot;&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;All the code I’m working on in my live coding stream is available at &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced&quot;&gt;https://github.com/jitterted/jitterticket-event-sourced&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Notes from previous streams:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2026/02/04/live-coding-journal-feb-4-2026/&quot;&gt;Feb 4th, 2026&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id=&quot;notes-from-today%E2%80%99s-live-coding-session&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/05/live-coding-journal-feb-5-2026/#notes-from-today%E2%80%99s-live-coding-session&quot;&gt;Notes from Today’s Live Coding Session&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;pumpkins&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/05/live-coding-journal-feb-5-2026/#pumpkins&quot;&gt;Pumpkins&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Today I introduced the idea of saying the word “pumpkin” during my stream so that when I write these notes, I can easily search through the text transcription of the stream for all instances of where I say “pumpkin”.
This way, when I have an aha moment, or mention something I want to note here, including mistakes, learnings, etc., I can easily find them by searching for “pumpkin” as the marker or anchor.
I loved this so much, I’m now calling these highlights “pumpkins”.
So, enjoy today’s pumpkins!&lt;/p&gt;
&lt;h3 id=&quot;testing-a-tiny-feature-the-wrong-way&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/05/live-coding-journal-feb-5-2026/#testing-a-tiny-feature-the-wrong-way&quot;&gt;Testing A Tiny Feature the Wrong Way&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At around the 1-hour mark, I was working on adding a small feature to the &lt;code&gt;Concert&lt;/code&gt; aggregate, where I could stop ticket sales for the concert by calling a command method &lt;code&gt;stopTicketSales()&lt;/code&gt;.
However, I temporarily forgot that I was using event-sourcing, so when I wrote the test like this:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;stopTicketSalesGeneratesTicketSalesStopped&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt; concert &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ConcertFactory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createConcert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    concert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stopTicketSales&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;canSellTickets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isFalse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and was about to start writing the code to make it pass, I realized I was testing the non-event-sourced way!
(And that’s despite the fact that the test name specifically says the event I expect to be generated!)
Sigh.
I quickly realized my mistake and changed the assertion to check that the &lt;code&gt;TicketSalesStopped&lt;/code&gt; was generated:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;stopTicketSalesGeneratesTicketSalesStopped&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt; concert &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ConcertFactory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createConcert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    concert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stopTicketSales&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;uncommittedEvents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;containsExactly&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TicketSalesStopped&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I predicted that the test would fail because I didn’t write the code to generate the event yet, but it failed for the wrong reason!
Once again, “calling my shot” (predicting precisely how the test would fail) saved me from a bad test.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TDD Prediction Principle:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It’s not good enough to just have a failing test, it has to fail for &lt;em&gt;precisely&lt;/em&gt; the right reason, i.e., because the code doesn’t implement the behavior that you want to add, not because of some other problem (such as the wrong test setup or a misunderstanding of the codebase’s current behavior).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The problem here is that the &lt;code&gt;ConcertFactory.createConcert()&lt;/code&gt; helper method creates an unsaved &lt;code&gt;Concert&lt;/code&gt; object, which means that when I check the &lt;code&gt;uncommittedEvents()&lt;/code&gt;, it isn’t empty, but instead has the &lt;code&gt;ConcertScheduled&lt;/code&gt; event.
Oops.
Changing the test setup to create a “reconstituted” &lt;code&gt;Concert&lt;/code&gt; object fixed the problem:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;stopTicketSalesGeneratesTicketSalesStopped&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt; concert &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Concert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reconstitute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                    &lt;span class=&quot;token class-name&quot;&gt;ConcertFactory&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Events&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scheduledConcert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    concert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stopTicketSales&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;uncommittedEvents&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;containsExactly&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TicketSalesStopped&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;concert&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lesson Learned:&lt;/strong&gt;
The test setup and assertions for the events is still a bit clunky, despite the factory methods and builders that I have.
At some point I need to move to a higher level of abstraction for the setup and assertions.
One way to go is to use strings to describe the events, but that loses compile-time safety, and more importantly, doesn’t let me auto-complete.
Likely the next thing I try is some nested builders, but I need to do more experimentation to find the right structure that helps with autocomplete, but is also readable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;red-test-does-not-mean-new-test&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/05/live-coding-journal-feb-5-2026/#red-test-does-not-mean-new-test&quot;&gt;Red Test Does Not Mean New Test&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Something I often talk about in my TDD courses (as well as on my stream) is that the “red” (failing test) in “Red-Green-Refactor” (the high-level TDD cycle) doesn’t require a new test.
In fact, probably 20–30% of the time, my first failing test is a modification of an existing test that is currently passing.&lt;/p&gt;
&lt;p&gt;I think most often this happens when I’m adding functionality to a class, like when I added the ability to stop ticket sales to the &lt;code&gt;Concert&lt;/code&gt; aggregate.
Before I could implement the functionality of stopping the ticket sales, I had to make sure that the behavior for a new &lt;code&gt;Concert&lt;/code&gt; was that ticket sales were allowed.
I didn’t need a new test, I already had the &lt;code&gt;concertScheduledUpdatesConcertDetails()&lt;/code&gt; test, so I just needed to add an assertion to check that the &lt;code&gt;canSellTickets()&lt;/code&gt; method returned &lt;code&gt;true&lt;/code&gt;.
(This was technically the “zero” case in the Zero/One/Many guideline, aka ZOMBIES.)&lt;/p&gt;
&lt;h2 id=&quot;feature-envy-trap&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/05/live-coding-journal-feb-5-2026/#feature-envy-trap&quot;&gt;Feature Envy Trap&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After I added the &lt;code&gt;stopTicketSales()&lt;/code&gt; method, and the internal &lt;code&gt;canSellTickets&lt;/code&gt; boolean, I realized that I had a code smell heuristic that I hadn’t articulated before (around the 1h33m point):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Precursor to Feature Envy Heuristic&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If an entity has state that it’s not using internally to make decisions, then why is it holding onto that state?
If it’s only exposing it and not using it, that’s just ripe for future feature envy, where a client of the entity uses that information to make a decision.&lt;/p&gt;
&lt;p&gt;Resolution: either the entity needs to use that state internally, or it should be removed (or moved) to an entity that needs it to make a decision.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once I noticed this (awareness of these things is 90% of the battle!), I realized I was missing a necessary business rule where if tickets sales were stopped, we should not allow the &lt;code&gt;sellTickets()&lt;/code&gt; command method to succeed.
(I decided not to implement that yet, since I wanted to get to the core of the Concert Sales Processor.)&lt;/p&gt;
&lt;h2 id=&quot;who%E2%80%99s-job-is-it%3F-processor-vs.-aggregate&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/05/live-coding-journal-feb-5-2026/#who%E2%80%99s-job-is-it%3F-processor-vs.-aggregate&quot;&gt;Who’s Job Is It? Processor vs. Aggregate&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My main goal for today’s stream was to build my first Event Sourced Processor and had chosen the idea of a separate “Processor” whose job was to track ticket sales. When a concert sells its last ticket, the processor would invoke the &lt;code&gt;stopTicketSales()&lt;/code&gt; command on the &lt;code&gt;Concert&lt;/code&gt; aggregate.
After some back-and-forth thinking out loud and discussion with the stream viewers (thanks chillMute!), I realized that I was about to design a Processor that needed information that the &lt;code&gt;Concert&lt;/code&gt; aggregate already had! Concert already knows about ticket sales and precisely when the last ticket is sold (via the &lt;code&gt;sellTickets()&lt;/code&gt; command method).&lt;/p&gt;
&lt;p&gt;I admit to being a bit disappointed that there was no need for the “Concert Sold Out Processor”, but I’m still learning about this aspect of Event Sourcing, and the discussion of “who’s responsible” was really useful.
Luckily, I already had other Processors that I wanted to implement.&lt;/p&gt;
&lt;p&gt;We dug into the details of the “Concert Started Processor”, which would be responsible for tracking when a concert starts (based on its Show Date/Time), and invoke &lt;code&gt;stopTicketSales()&lt;/code&gt; on &lt;code&gt;Concert&lt;/code&gt; when that time comes around.
Figuring out how to implement this took us down a few dead-ends (e.g., Spring’s scheduling support was not the right mechanism), and ended up deciding to use Java’s built-in &lt;code&gt;ScheduledExecutorService&lt;/code&gt; to schedule the stopping of ticket sales along with a &lt;code&gt;Map&amp;lt;ConcertId, ScheduledFuture&amp;gt;&lt;/code&gt; to keep track of the concerts (so we can reschedule the futures if the concert itself gets rescheduled).
It’s annoying that &lt;code&gt;ScheduledExecutorService&lt;/code&gt; doesn’t have an easy way to specify a specific date/time to execute the task (it requires a duration from “now”), but it’s just a bit of simple date math to figure this out.&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/05/live-coding-journal-feb-5-2026/#next-steps&quot;&gt;Next Steps&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We ended with a failing test for the new &lt;code&gt;ConcertStartedProcessor&lt;/code&gt;, and a design plan for how it’ll probably be implemented, along with a few tests (a &lt;a href=&quot;https://tidyfirst.substack.com/i/139601698/1-test-list&quot;&gt;Test List&lt;/a&gt;!) that we’ll start with.&lt;/p&gt;
&lt;p&gt;I hope you’ll join me on my next stream, usually starting at 20:00 UTC on Monday thru Thursday on Twitch: &lt;a href=&quot;https://jitterted.stream/&quot;&gt;https://jitterted.stream&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Live Coding Journal - Feb 4, 2026</title>
    <link href="https://ted.dev/articles/2026/02/04/live-coding-journal-feb-4-2026/"/>
    <updated>2026-02-04T12:00:00Z</updated>
    <id>https://ted.dev/articles/2026/02/04/live-coding-journal-feb-4-2026/</id>
    <content xml:lang="en" type="html">&lt;h2 id=&quot;notes-from-today%E2%80%99s-live-coding-session&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2026/02/04/live-coding-journal-feb-4-2026/#notes-from-today%E2%80%99s-live-coding-session&quot;&gt;Notes from Today’s Live Coding Session&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’m back from vacation and resumed my live coding streams where I’m working on “JitterTicket”, an example Event Sourcing application in the Concert Ticketing domain. (Code is at &lt;a href=&quot;https://github.com/jitterted/jitterticket-event-sourced.&quot;&gt;https://github.com/jitterted/jitterticket-event-sourced.&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;I’ve been working on the “available concerts” projection, which is used (as a read model) to show customers what concerts are available for ticket purchase. Before my vacation, we decided on a new event, “ConcertCompleted” that would stop ticket sales. Today I decided that this event name was too broad, so instead used &lt;code&gt;TicketSalesStopped&lt;/code&gt;. The creation of that event was mostly mechanical, especially since it doesn’t need anything other than the Concert ID (which is already inherited from the base ConcertEvent).&lt;/p&gt;
&lt;p&gt;I’m glad I did the work manually (instead of letting the Junie LLM do the work) as I discovered some weirdness with creating an otherwise “empty” event class. (Mostly on code-generating the equals and hashcode.)&lt;/p&gt;
&lt;p&gt;I was also taking notes on the process so that in the future, I can create a code generator (no point in using an LLM for something that’s basically a template) for adding new events, since there’s more than just the event classes that need to be created.&lt;/p&gt;
&lt;p&gt;Adding the new event was a straightforward TDD process, though the first “failing test” was a “fail to compile” due to the pattern-matching switch statements that I use. It had been a while since the last time I added a new event and forgot that I had JSON round-trip tests, which failed—thankfully! Adding the new event and the appropriate Jackson “mix in” classes was also mechanical.&lt;/p&gt;
&lt;p&gt;Once the event itself was in place, it was time to update the “Available Concerts” projector to drop concerts from the projection when it sees a “TicketSalesStopped” event.&lt;/p&gt;
&lt;p&gt;Since I was doing bottom-up development, i.e., creating the event first, and then adding behavior elsewhere, I decided not to modify Concert (the aggregate generating the TicketSalesStopped event and having a “canSellTickets” state), as I wanted to focus on the projection first.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Side note: Every time I think about a boolean state, I’m always thinking, is this really a boolean, or is it really a state machine with multiple states? Or maybe it’s an effective timestamp? I’ll have to write that up at some point.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;With the event work done, I moved on to the first new (failing!) test of the projector (which is so easy to test as it’s stateless code): If there’s already a concert available in the projection (cache), stopping ticket sales removes it, leaving the Available Concerts empty.&lt;/p&gt;
&lt;p&gt;The code for that was easy, but then things got tricky as I had to handle the catch-up projection scenario, where ConcertScheduled and TicketSalesStopped already happened for a concert, so the projection needs to just ignore that concert. What makes this complicated is the projector produces two results: a new projection cache as well as a “delta”, which is used for persistence and split into upserts &amp;amp; deletes.&lt;/p&gt;
&lt;p&gt;Before the TicketSalesStopped event came on the scene, I didn’t worry about deletions, but also internally tracked inserts and updates in a single upserts map. However, I couldn’t tell when to &lt;code&gt;put&lt;/code&gt; a concert into the “deletions” list because Scheduled and Rescheduled looked alike.&lt;/p&gt;
&lt;p&gt;They’re not! If I see a Scheduled+TicketSalesStopped in the list of events being handled, it’s a no-op (cache remains the same, delta is empty). A Rescheduled+Stopped, however, &lt;em&gt;is&lt;/em&gt; a deletion (because a Scheduled already happened some time in the past).&lt;/p&gt;
&lt;p&gt;I ended up doing a refactor to split the internal upsert map into two lists to track inserts (Scheduled) and updates (Rescheduled) separately. I got the tests to continue passing, but it was clear that lists were the wrong data structure, so replaced them with maps (much nicer).&lt;/p&gt;
&lt;p&gt;I’m pretty happy with my current design of the Projectors as it made tests relatively easy to write. I am feeling the pain of generating the stream of test events, so that’s something I’ll focus on once I work on the last component of the app: Processors.&lt;/p&gt;
&lt;p&gt;I stream for 3–4 hours starting at 20:00 UTC on Monday thru Thursday, unless I’m at a conference or otherwise occupied, so I hope you’ll tune in at &lt;a href=&quot;https://jitterted.stream/&quot;&gt;https://jitterted.stream&lt;/a&gt; to watch, help me out, ask questions, or even heckle.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>What Project Should I Work On?</title>
    <link href="https://ted.dev/articles/2024/07/09/what-project-should-i-work-on/"/>
    <updated>2024-07-09T10:00:00Z</updated>
    <id>https://ted.dev/articles/2024/07/09/what-project-should-i-work-on/</id>
    <content xml:lang="en" type="html">&lt;h2 id=&quot;improving-your-skills&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2024/07/09/what-project-should-i-work-on/#improving-your-skills&quot;&gt;Improving Your Skills&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Just about every week on my &lt;a href=&quot;https://jitterted.stream/&quot;&gt;live-coding stream&lt;/a&gt;, I get asked “how do I learn Java/Spring Boot/etc.”?
Often this is asked by someone relatively new to coding, but I also hear it from experienced folks who are unsure how to learn something new.
For example, they’re good at Python, but now want to learn Java and Spring Boot.&lt;/p&gt;
&lt;p&gt;My response is always: work on a &lt;strong&gt;Learning Project&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;learning-projects&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2024/07/09/what-project-should-i-work-on/#learning-projects&quot;&gt;Learning Projects&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Q:&lt;/strong&gt; What is a Learning Project?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; It’s a project that starts very small and is one you will add to over time (not a “one and done”).&lt;/p&gt;
&lt;p&gt;I coach lots of developers
where you’ll learn skills as they come up as needed by what you want the application to do.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;If possible, make it useful for you or your family. That way you’ll be motivated to work on it and get real-world feedback for things to change/add.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Focus on interesting BEHAVIOR.
Why “behavior”? Well, it depends on what kinda of work you like, but for me, I like rich and interesting domains (hence my fondness for domain-driven design), vs. just integrating things (valuable for sure!).
Some projects are just about data, which is a good start, but doesn’t build up skills in working on code that’s at the core of complex business (or game or industrial) processes.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For that, you need something “meaty”. Writing a To-Do app? That’s fine! But what can it do for you?
Do you want it to remind you of things as well? I know I heavily rely on reminders. That’ll pull in the (dreaded) Date and Time aspects (how will you test that??).&lt;/p&gt;
&lt;p&gt;Dependencies between items? Or things that you do in one place (like shopping)? Hey, a shopping list!
A shopping list organized by grocery aisle! Maybe there are certain items you buy on a regular basis, that’s behavior, too.&lt;/p&gt;
&lt;p&gt;There’s a whole class of “bespoke” or just-for-you apps waiting to be written. It’s only for you, so only needs to satisfy you.
I created a whole app that just manages my son’s virtual “piggy bank” (cuz we were tired of scraps of paper and a spreadsheet that wasn’t easy to use on the phone). I learned &lt;em&gt;so much&lt;/em&gt; by creating that. And 4+ years later, it’s STILL running and being used.&lt;/p&gt;
&lt;h2 id=&quot;change-one-thing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2024/07/09/what-project-should-i-work-on/#change-one-thing&quot;&gt;Change One Thing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;See &lt;a href=&quot;https://twitter.com/kchironis/status/1569108508507009025&quot;&gt;https://twitter.com/kchironis/status/1569108508507009025&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;mash-up&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2024/07/09/what-project-should-i-work-on/#mash-up&quot;&gt;Mash Up&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My take:&lt;/p&gt;
&lt;p&gt;Great advice!
Also applies to learning coding in general: take that tutorial you just followed and change one thing.
Then another thing.
Add something personal or funny.
Invert/reverse what the thing does.
Make it your own.
Mash up two tutorials (tic-tac-toe + to-do list?).&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Playing to Learn Predictive TDD</title>
    <link href="https://ted.dev/articles/2024/02/20/playing-to-learn-predictive-tdd/"/>
    <updated>2024-02-20T10:00:00Z</updated>
    <id>https://ted.dev/articles/2024/02/20/playing-to-learn-predictive-tdd/</id>
    <content xml:lang="en" type="html">&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/playing-jitterted-tdd-game.jpg&quot; alt=&quot;Slide from the presentation that says &#39;JitterTed&#39;s TDD Game&#39; with a picture of the board game being played&quot; width=&quot;50%&quot;&gt;&lt;figcaption&gt;Playing the Game&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;the-video&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2024/02/20/playing-to-learn-predictive-tdd/#the-video&quot;&gt;The Video&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On the Agile Lunch &amp;amp; Learn channel, I gave a talk about “Predictive” Test-Driven Development as an introduction to &lt;a href=&quot;https://tdd.cards/&quot;&gt;JitterTed’s TDD Game&lt;/a&gt;. I describe Predictive TDD, give a bit of history of the game, and then demonstrate playing the game itself.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Thanks to &lt;a href=&quot;https://markshead.com/&quot;&gt;Mark Shead&lt;/a&gt; and the &lt;a href=&quot;https://events.xeric.net/&quot;&gt;AgileLnL&lt;/a&gt; community for hosting me!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/live/P8eRY2c8NFY&quot;&gt;https://www.youtube.com/live/P8eRY2c8NFY&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;download-the-slides&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2024/02/20/playing-to-learn-predictive-tdd/#download-the-slides&quot;&gt;Download the Slides&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Click &lt;a href=&quot;https://ted.dev/assets/Predictive%20Test-Driven%20Development%20with%20the%20TDD%20Game%20(Feb%202024%20-%20Agile%20LnL).pdf&quot;&gt;here&lt;/a&gt; to download the slides from the presentation.&lt;/p&gt;
&lt;h2 id=&quot;discuss&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2024/02/20/playing-to-learn-predictive-tdd/#discuss&quot;&gt;Discuss&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Want to talk about the presentation, TDD, or the game? Have questions? Join us on the &lt;a href=&quot;https://ted.dev/discord&quot;&gt;Discord&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Your Classes are Too Big (Talk)</title>
    <link href="https://ted.dev/articles/2023/05/30/your-classes-are-too-big-talk/"/>
    <updated>2023-05-30T19:00:00Z</updated>
    <id>https://ted.dev/articles/2023/05/30/your-classes-are-too-big-talk/</id>
    <content xml:lang="en" type="html">&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/domain-free_number_vs_wager.png&quot; alt=&quot;Slide from the presentation that shows a domain-free integer vs. a domain-specific Wager&quot; width=&quot;100%&quot;&gt;&lt;figcaption&gt;Slide from the Primitive Obsession presentation&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;the-video&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2023/05/30/your-classes-are-too-big-talk/#the-video&quot;&gt;The Video&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Recently at the Seattle Software Crafters meetup (remote), I gave a new version of my talk on Primitive Obsession. I show how you can easily (almost mechanically) split your large classes by identifying where it’s suffering from Primitive Obsession.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Thanks to &lt;a href=&quot;https://www.linkedin.com/in/stevekuo/&quot;&gt;Steve Kuo&lt;/a&gt;, &lt;a href=&quot;https://www.linkedin.com/in/paige-watson-b817564/&quot;&gt;Paige Watson&lt;/a&gt; and the &lt;a href=&quot;https://www.meetup.com/seattle-software-craftsmanship/&quot;&gt;Seattle Software Crafters&lt;/a&gt; community for hosting me and asking great questions!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://youtu.be/hcx6DUjU24A&quot;&gt;https://youtu.be/hcx6DUjU24A&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;download-the-slides&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2023/05/30/your-classes-are-too-big-talk/#download-the-slides&quot;&gt;Download the Slides&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Click &lt;a href=&quot;https://ted.dev/assets/Stop%20Obsessing%20About%20Primitives%20-%20Meetup%20-%20May%202023.pdf&quot;&gt;here&lt;/a&gt; to download the slides from the presentation.&lt;/p&gt;
&lt;h2 id=&quot;discuss&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2023/05/30/your-classes-are-too-big-talk/#discuss&quot;&gt;Discuss&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Want to talk about the presentation? Have questions? Join us on the &lt;a href=&quot;https://ted.dev/discord&quot;&gt;Discord&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Make sure to sign up for my newsletter (see below), so you don’t miss future Ted Talks!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>I&#39;m Done with Unit and Integration Tests</title>
    <link href="https://ted.dev/articles/2023/04/02/i-m-done-with-unit-and-integration-tests/"/>
    <updated>2023-04-02T10:00:00Z</updated>
    <id>https://ted.dev/articles/2023/04/02/i-m-done-with-unit-and-integration-tests/</id>
    <content xml:lang="en" type="html">&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/unit-or-integration-how-about-no-bear.jpg&quot; alt=&quot;The &#39;how about no&#39; bear meme. Top text: Unit or Integration? Bottom text: How About No&quot; width=&quot;100%&quot;&gt;&lt;figcaption&gt;Does &#39;No&#39; sound good to you?&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;i%E2%80%99m-done-with-unit-and-integration-tests&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2023/04/02/i-m-done-with-unit-and-integration-tests/#i%E2%80%99m-done-with-unit-and-integration-tests&quot;&gt;I’m Done with Unit and Integration Tests&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’ve been writing developer tests for a very long time. Lately, I’ve been reflecting on the types of tests I write, and why some are easier than others. When teaching and coaching others how to write tests, I almost always explain what I mean by “Unit Tests” and “Integration Tests”: Unit Tests don’t touch hardware, don’t do I/O, etc.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2023/04/02/i-m-done-with-unit-and-integration-tests/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;, and test against a single object or group of objects&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2023/04/02/i-m-done-with-unit-and-integration-tests/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;. I’d then demonstrate what I meant, like this:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fullDeckHas52Cards&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Deck&lt;/span&gt; deck &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Deck&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deck&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isEqualTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;52&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;drawCardFromDeckReducesDeckSizeByOne&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Deck&lt;/span&gt; deck &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Deck&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    deck&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deck&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isEqualTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;51&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These are both “unit” tests (neither touch hardware nor do I/O) and are &lt;em&gt;Solitary&lt;/em&gt; (the tests only reference the &lt;code&gt;Deck&lt;/code&gt; class).&lt;/p&gt;
&lt;p&gt;Later on, we’d need to write tests against code that may do I/O, often a database or an external service (usually over the network). I’d explain that those were “Integration Tests”, because we were &lt;em&gt;integrating&lt;/em&gt; our code with someone else’s code (the database code or the other service’s code) through I/O. However, calling someone else’s code that’s supplied as a library (e.g., a JAR file) that doesn’t do I/O (such as &lt;a href=&quot;https://github.com/ben-manes/caffeine&quot;&gt;Caffeine&lt;/a&gt;, a caching library) can also be considered integration. Even using Java’s Collection classes (e.g., &lt;code&gt;ArrayList&lt;/code&gt;) is using someone else’s code, though we don’t usually think of that as &lt;em&gt;integration&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;hard-to-redefine-terms-with-lots-of-baggage&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2023/04/02/i-m-done-with-unit-and-integration-tests/#hard-to-redefine-terms-with-lots-of-baggage&quot;&gt;Hard to Redefine Terms With Lots of Baggage&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Over the past few years, I’ve become more frustrated with the terms “unit” and “integration” because:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I have to explain what Unit and Integration mean before I can use them&lt;/li&gt;
&lt;li&gt;Everyone has their own internal definition of what they mean, which is often different from mine and other folks in the room&lt;/li&gt;
&lt;li&gt;Differences in definitions often led to long discussions&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2023/04/02/i-m-done-with-unit-and-integration-tests/#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt; that aren’t useful&lt;/li&gt;
&lt;li&gt;Folks don’t remember how I define it, and fall back to their own definitions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I finally decided to do something about it, and come up with different names. But first, I had to answer the question: why does it matter? What about Unit (doesn’t do I/O) and Integration (may do I/O?) is important for the way I approach development?&lt;/p&gt;
&lt;h2 id=&quot;no-i%2Fo-%3D-predictable-%26-fast&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2023/04/02/i-m-done-with-unit-and-integration-tests/#no-i%2Fo-%3D-predictable-%26-fast&quot;&gt;No I/O = Predictable &amp;amp; Fast&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you create an object, and call a method that only accesses internal properties (fields) and any parameters to the method, it must be predictable. Any logic or calculations the code is doing is deterministic. What makes code not predictable? I/O. Accessing a file is unpredictable, because the file could’ve changed without you knowing, the drive could fail intermittently, could be out of space, etc. Accessing a remote service involves not only the network (unreliable), but also the remote service (unpredictable). I include access to anything outside of memory, such as random number generation and the current date &amp;amp; time as I/O, because they are also unpredictable. By eliminating all I/O, you make the code under test, and therefore the test, deterministic.&lt;/p&gt;
&lt;p&gt;Not accessing I/O also means your tests will run extremely fast&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2023/04/02/i-m-done-with-unit-and-integration-tests/#fn4&quot; id=&quot;fnref4&quot;&gt;[4]&lt;/a&gt;&lt;/sup&gt;, with most of the time spent getting the tests ready to run: compiling, starting, etc. Everything else, from instantiating objects to running the code, is almost instantaneous. There’s no reason you can’t have many thousands of tests run in a few seconds. By the way, this speed is critical for doing test-driven development, which is why I focus on these kinds of tests.&lt;/p&gt;
&lt;p&gt;Now when it comes to code that &lt;em&gt;does&lt;/em&gt; interact with the outside world, such as getting the current date &amp;amp; time, or fetching information from a database or external service, I still want tests that don’t do I/O. This is where &lt;em&gt;Test Doubles&lt;/em&gt; come into play. In &lt;a href=&quot;https://ted.dev/articles/2023/02/21/more-testable-code-with-hexagonal-architecture-talk/&quot;&gt;Hexagonal Architecture&lt;/a&gt;, that might mean a &lt;em&gt;Stub&lt;/em&gt; or a &lt;em&gt;Fake&lt;/em&gt; in place of a concrete Adapter, or I might use &lt;a href=&quot;https://www.jamesshore.com/v2/projects/nullables/a-light-introduction-to-nullables&quot;&gt;Nullable Infrastructure Wrappers&lt;/a&gt;, which is Stub-like implementation embedded in your production code.&lt;/p&gt;
&lt;p&gt;The idea is that we’re still not touching I/O, so everything is still &lt;em&gt;Predictable &amp;amp; Fast&lt;/em&gt;. These are a form of &lt;em&gt;Sociable&lt;/em&gt; tests, where we’re testing a larger set of collaborating classes, but explicitly not testing the I/O itself.&lt;/p&gt;
&lt;p&gt;I want 80-90% of my tests to be these kinds of tests. Of course, it’ll vary widely depending on how much your system is doing things vs. integrating with other things.&lt;/p&gt;
&lt;h2 id=&quot;i%2Fo-%3D-unpredictable-%26-slower&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2023/04/02/i-m-done-with-unit-and-integration-tests/#i%2Fo-%3D-unpredictable-%26-slower&quot;&gt;I/O = Unpredictable &amp;amp; Slower&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At some point, though, you want to have some sort of test that touches I/O. Things like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Check the database schema is valid&lt;/li&gt;
&lt;li&gt;Ensure the ORM can read and write from the database and create well-formed objects&lt;/li&gt;
&lt;li&gt;Call an external service API and ensure you get a valid response&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are hard to write, because, like I said, they’re unpredictable. Databases are often managed (“owned/defined”) by the application, so those can use tools like Docker and &lt;a href=&quot;https://testcontainers.com/&quot;&gt;Testcontainers&lt;/a&gt; to allow your tests to use real databases. They’re slower, but you won’t be running them nearly as often as the other tests.&lt;/p&gt;
&lt;p&gt;When it comes to calling external services, if it’s a service that you can run inside a container (maybe it’s Kafka, or it’s a custom service created by another team that provides an executable), then you can do the same thing as with the database above. But if it’s a public service (like GitHub or Google), or any service that you can’t run locally or in a container, you’re not going to be able to run automated tests that are predictable. Yes, you could run against a “sandbox” environment, but for me that falls under “unpredictable” based on my experiences (maybe yours work better?). So, if I write these tests, I run them manually, or have other ways of checking that my code works (like good monitoring and observability in production).&lt;/p&gt;
&lt;h2 id=&quot;naming-attempts&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2023/04/02/i-m-done-with-unit-and-integration-tests/#naming-attempts&quot;&gt;Naming Attempts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Naming is hard, as we all know. Trying to find a name that is descriptive and memorable, but with little or no baggage, is quite a task.&lt;/p&gt;
&lt;h3 id=&quot;first-attempt&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2023/04/02/i-m-done-with-unit-and-integration-tests/#first-attempt&quot;&gt;First Attempt&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;During a discussion of the problem with &lt;a href=&quot;https://www.linkedin.com/in/willem-larsen-8a005514/&quot;&gt;Willem Larsen&lt;/a&gt;, he proposed using words from a different language (e.g., Japanese) for the same terms (or at least what they meant to me). However, not being able to speak Japanese, I had to rely on less than perfect translation systems. Not only did I want to find a word or phrase that had the intent I wanted, but it also had to be relatively short. For months, I played with different translations, but wasn’t happy with the results, so I shelved the idea.&lt;/p&gt;
&lt;h3 id=&quot;pure-and-impure&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2023/04/02/i-m-done-with-unit-and-integration-tests/#pure-and-impure&quot;&gt;Pure and Impure&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In Functional Programming, the terms “Pure” and “Impure” have somewhat similar meanings to my usage of “Unit” and “Integration”. In FP, a &lt;em&gt;pure function&lt;/em&gt; is a function that doesn’t cause any side effects, and always produces the same output for a given input. I tried using this terminology for a while, but it had two problems:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I still had to define “pure” as not accessing I/O&lt;/li&gt;
&lt;li&gt;I got objections from FP folks, because of the misuse of the term “pure” in the context of testing stateful object-oriented code (methods accessing internal state could never be “pure”)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Honestly, #1 was the more annoying aspect for me, though it did have the benefit of not coming with much baggage (except for folks familiar with FP).&lt;/p&gt;
&lt;p&gt;I do use the term “purify” when I’m talking about the process of separating the I/O code from the logic, e.g., “let’s purify this code, making it I/O-Free”.&lt;/p&gt;
&lt;h3 id=&quot;i%2Fo-free-and-i%2Fo-dependent&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2023/04/02/i-m-done-with-unit-and-integration-tests/#i%2Fo-free-and-i%2Fo-dependent&quot;&gt;I/O-Free and I/O-Dependent&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;So here we are. The two main kinds of tests I write. The majority are &lt;strong&gt;I/O-Free&lt;/strong&gt; tests, and when I hit the I/O boundary and need to test against some real external service, I use &lt;strong&gt;I/O-Dependent&lt;/strong&gt; tests (or &lt;strong&gt;I/O-Based&lt;/strong&gt;).&lt;/p&gt;
&lt;p&gt;I further split &lt;em&gt;I/O-Free&lt;/em&gt; tests into &lt;em&gt;Domain&lt;/em&gt;, &lt;em&gt;Application&lt;/em&gt;, and other buckets, depending on the application architecture (e.g., &lt;em&gt;Domain&lt;/em&gt; tests never have Test Doubles), but that’s another article.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What do you think? Let me know on my &lt;a href=&quot;https://ted.dev/discord&quot;&gt;Discord&lt;/a&gt;, on &lt;a href=&quot;https://sfba.social/@jitterted&quot;&gt;Mastodon&lt;/a&gt;, or on &lt;a href=&quot;https://twitter.com/jitterted&quot;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;This should sound familiar to some of you, as it’s the same idea as the set of &lt;a href=&quot;https://www.artima.com/weblogs/viewpost.jsp?thread=126923&quot;&gt;unit testing rules&lt;/a&gt; by Michael Feathers written in 2005. &lt;a href=&quot;https://ted.dev/articles/2023/04/02/i-m-done-with-unit-and-integration-tests/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I use the terms &lt;em&gt;Sociable&lt;/em&gt; and &lt;em&gt;Solitary&lt;/em&gt; to differentiate between the different kinds of “unit” tests, as defined by Jay Fields in &lt;a href=&quot;https://leanpub.com/wewut&quot;&gt;Working Effectively with Unit Tests&lt;/a&gt;, with an excerpt found &lt;a href=&quot;http://blog.jayfields.com/2014/07/solitary-unit-test.html&quot;&gt;here&lt;/a&gt;. &lt;a href=&quot;https://ted.dev/articles/2023/04/02/i-m-done-with-unit-and-integration-tests/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;If I have one more debate over what “unit” means, I’m gonna scream. It’s especially annoying, since I don’t think defining a “unit” is a useful exercise. &lt;a href=&quot;https://ted.dev/articles/2023/04/02/i-m-done-with-unit-and-integration-tests/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn4&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Yes, there is code that performs lengthy calculations that run completely in memory, but I’m not talking about that. &lt;a href=&quot;https://ted.dev/articles/2023/04/02/i-m-done-with-unit-and-integration-tests/#fnref4&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>More Testable Code with Hexagonal Architecture (Talk)</title>
    <link href="https://ted.dev/articles/2023/02/21/more-testable-code-with-hexagonal-architecture-talk/"/>
    <updated>2023-02-21T10:00:00Z</updated>
    <id>https://ted.dev/articles/2023/02/21/more-testable-code-with-hexagonal-architecture-talk/</id>
    <content xml:lang="en" type="html">&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/scion-t.png&quot; alt=&quot;Slide from the presentation that has the acronym SCION-T, which stands for Separating Concerns of I/O and Non-I/O for Testability&quot; width=&quot;100%&quot;&gt;&lt;figcaption&gt;Slide from the presentation&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;the-video&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2023/02/21/more-testable-code-with-hexagonal-architecture-talk/#the-video&quot;&gt;The Video&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Recently at PhillyXP (remote), I gave an updated version of my talk on how Hexagonal Architecture—primarily its separation of concerns—helps make code more testable. If you’ve seen past versions of this, you’ll want to see this one. I’ve shifted the focus a bit to focus more on tests and what we want out of them. I’m also using my new language for describing tests: &lt;strong&gt;I/O-Free Tests&lt;/strong&gt; (sometimes known as &lt;em&gt;unit tests&lt;/em&gt;) and &lt;strong&gt;I/O Tests&lt;/strong&gt; (sometimes matches what people call &lt;em&gt;integration tests&lt;/em&gt;). I’ll be writing more about the difference, because I think we often get too hung up on “what’s a unit?” instead of “what kind of test would be useful here?”&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Thanks to &lt;a href=&quot;https://anthonysciamanna.com/&quot;&gt;Anthony&lt;/a&gt; and the &lt;a href=&quot;https://www.meetup.com/phillyxp/&quot;&gt;PhillyXP&lt;/a&gt; community for hosting me and asking great questions!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://youtu.be/NLCp_fUrqf8&quot;&gt;https://youtu.be/NLCp_fUrqf8&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-course&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2023/02/21/more-testable-code-with-hexagonal-architecture-talk/#the-course&quot;&gt;The Course&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There’s only so much I can fit in an hour or so, and so I built a &lt;a href=&quot;https://ted.dev/refactoring-to-hexagonal-architecture.html?utm_medium=web&amp;amp;utm_source=teddev&amp;amp;utm_campaign=mtchaap&quot;&gt;15+ hour course&lt;/a&gt; that dives deep into all aspects of making code more testable and refactoring to Hexagonal Architecture. Sign up &lt;a href=&quot;https://r2ha.com/&quot;&gt;here&lt;/a&gt; to find out when the course is on sale again.&lt;/p&gt;
&lt;h2 id=&quot;download-the-slides&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2023/02/21/more-testable-code-with-hexagonal-architecture-talk/#download-the-slides&quot;&gt;Download the Slides&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Click &lt;a href=&quot;https://ted.dev/assets/Hexagonal%20Testable%20Architecture%20by%20Ted%20M.%20Young%20-%20Feb%202023.pdf&quot;&gt;here&lt;/a&gt; to download the slides from the presentation.&lt;/p&gt;
&lt;h2 id=&quot;discuss&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2023/02/21/more-testable-code-with-hexagonal-architecture-talk/#discuss&quot;&gt;Discuss&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Want to talk about the presentation? Have questions? Join us on the &lt;a href=&quot;https://ted.dev/discord&quot;&gt;Discord&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Top Five &quot;Forever&quot; Books for Coders</title>
    <link href="https://ted.dev/articles/2022/09/07/top-five-forever-books-for-coders/"/>
    <updated>2022-09-07T10:00:00Z</updated>
    <id>https://ted.dev/articles/2022/09/07/top-five-forever-books-for-coders/</id>
    <content xml:lang="en" type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/09/07/top-five-forever-books-for-coders/#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On my &lt;a href=&quot;https://jitterted.live/&quot;&gt;live coding stream&lt;/a&gt;, the question often comes up: “what books would you recommend?” about various topics. Since it’s such a common question, I decided to set aside time on my stream to pull together my recommendations and discuss them with my viewers. At first, I was going to write one of those standard “Top 10” lists, but I realized my recommendations are more nuanced than that (and that I have way more than 10 that I want to mention), so I’m dividing the “top” list into several, more focused lists. As we were discussing the book candidates on the stream, I realized there are “classics” that I think are required reading for any coder who wants to really step up their ability to write more maintainable and testable code, so those are the books in this first list: the “Forever” Books.&lt;/p&gt;
&lt;p&gt;This list has books that have been around for 15-20 years and will likely apply for 15-20 more. They came out during the “golden” period of 1995-2005 when Design Patterns, Refactoring, and eXtreme Programming (XP) broke through and started becoming well-known. Future lists will cover more recent books on developer testing, object-oriented design, and tech-specific books (e.g., Java, Spring framework, etc.).&lt;/p&gt;
&lt;h3 id=&quot;how-to-read&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/09/07/top-five-forever-books-for-coders/#how-to-read&quot;&gt;How to Read&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Instead of just listing the books, I provide a recommendation on how I’d read the book, since some of them, like the 883-page xUnit Test Patterns book, are quite large (and heavy if you have the physical book), and you don’t need to read every page. Even if they’re not that long, not all of these books are meant to be read cover-to-cover and serve as cookbook-like references. These books also have quite a bit of code and I tend to skip over most of that on my first read-through. Unlike most people it seems, I actually enjoy reading the Preface and Introduction chapters of books and since they often provide their own “how to read this book” advice, it’s worth taking the extra time to read.&lt;/p&gt;
&lt;p&gt;If you can, read these books as part of a Study Group. I was lucky to be part of a group (the Silicon Valley Patterns Group) that met weekly to discuss these books (and many more), chapter by chapter, and followed the patterns described &lt;a href=&quot;https://www.industriallogic.com/blog/pools-of-insight-study-groups/&quot;&gt;here&lt;/a&gt;. We were also lucky enough to get access to the in-progress books (such as WELC and DDD) and provide feedback to the authors.&lt;/p&gt;
&lt;h3 id=&quot;disclaimer&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/09/07/top-five-forever-books-for-coders/#disclaimer&quot;&gt;Disclaimer&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;This list has affiliate links where I might make a few cents on your purchase, but in addition to the typical Amazon links, I’ve included links (IndieBound) that would help support local and independent bookstores, without which the world would be a poorer place. You can also buy from indie bookstores online by following the link to BookShop.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;the-forever-list&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/09/07/top-five-forever-books-for-coders/#the-forever-list&quot;&gt;The Forever List&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;And now, on to the list! These are my Top 5 “forever” (aka “classic”) books that I strongly recommend folks buy and have on their shelf. They are not in any particular order, so I’m not numbering them. Except for &lt;em&gt;eXtreme Programming eXplained&lt;/em&gt;, they’re not books that are meant to be read linearly all the way through, but contain a catalog of recipes to be slowly learned over time.&lt;/p&gt;
&lt;h3 id=&quot;%E2%80%9Cworking-effectively-with-legacy-code%E2%80%9D-by-michael-feathers&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/09/07/top-five-forever-books-for-coders/#%E2%80%9Cworking-effectively-with-legacy-code%E2%80%9D-by-michael-feathers&quot;&gt;&lt;em&gt;“Working Effectively with Legacy Code”&lt;/em&gt; by Michael Feathers&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is the book that most people reference when discussing dealing with legacy code, which, let’s be honest, is probably all of us. Usually referred to by the &lt;em&gt;initialism&lt;/em&gt; WELC.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read Chapters 1-4&lt;/li&gt;
&lt;li&gt;Skip Chapter 5 (Tools)&lt;/li&gt;
&lt;li&gt;Read Chapter 6 (I Don’t Have Much Time and I Have to Change It)&lt;/li&gt;
&lt;li&gt;Skim the rest of the book, that way you’re aware of techniques to use when you run into those situations. Or maybe you’re already in those situations? If so, read on!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://www.indiebound.org/book/9780131177055?aff=jitterted&quot;&gt;Buy WELC on IndieBound&lt;/a&gt;
&lt;a href=&quot;https://amzn.to/2UMIoep&quot;&gt;Buy WELC on Amazon&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;%E2%80%9Cxunit-test-patterns%E2%80%9D-by-gerard-meszaros&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/09/07/top-five-forever-books-for-coders/#%E2%80%9Cxunit-test-patterns%E2%80%9D-by-gerard-meszaros&quot;&gt;&lt;em&gt;“xUnit Test Patterns”&lt;/em&gt; by Gerard Meszaros&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This book’s subtitle is “Refactoring Test Code”, but I think it’s much more than that, as it got me to really think about how I write and structure automated tests.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read Introduction through Chapter 6. No really, read the Introduction.&lt;/li&gt;
&lt;li&gt;Skip Chapter 7 if you know JUnit/xUnit etc.&lt;/li&gt;
&lt;li&gt;Skip Chapters 8, 9 on Fixture Management – I don’t think it’s as important as other chapters.&lt;/li&gt;
&lt;li&gt;Read Chapter 10 for how to verify (assert) – you might be surprised what you learn from this chapter.&lt;/li&gt;
&lt;li&gt;Read Chapter 11 at least twice(!) about “Test Doubles”
&lt;ul&gt;
&lt;li&gt;Forget everything you knew about mocks and learn this terminology.&lt;/li&gt;
&lt;li&gt;Eventually this will become second-nature, but if you overuse mocks in your current codebases, learning the different kinds of Test Doubles will help you wean off of them.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Skip Chapters 12-14, unless you’re really not sure how to organize your tests. Not that it’s not important, it’s more that this isn’t the main problem that I see in teams that I coach and train.&lt;/li&gt;
&lt;li&gt;Skim the rest of the Chapters for Test Code Smells (Chapter 15ff) and Test Strategy Patterns (Chapter 18ff).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://www.indiebound.org/book/9780131495050?aff=jitterted&quot;&gt;Buy xUnit on IndieBound&lt;/a&gt;
&lt;a href=&quot;https://amzn.to/2YAWBfy&quot;&gt;Buy xUnit on Amazon&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;%E2%80%9Crefactoring%3A-improving-the-design-of-existing-code%E2%80%9D-by-martin-fowler&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/09/07/top-five-forever-books-for-coders/#%E2%80%9Crefactoring%3A-improving-the-design-of-existing-code%E2%80%9D-by-martin-fowler&quot;&gt;&lt;em&gt;“Refactoring: Improving the Design of Existing Code”&lt;/em&gt; by Martin Fowler&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are two editions of this book: the First Edition, from 1999, uses Java, whereas the Second Edition came out in 2018 and switched to JavaScript for the code examples (as well as being tailored towards JavaScript idioms, such as using &lt;em&gt;function&lt;/em&gt; instead of &lt;em&gt;method&lt;/em&gt;). There are obviously more significant changes than just the code, as described by Martin &lt;a href=&quot;https://martinfowler.com/articles/refactoring-2nd-changes.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So which edition to buy? If you’re not a Java developer, then the Second Edition is what you want. However, if you &lt;strong&gt;are&lt;/strong&gt; a Java developer, then maybe both? The First Edition is available used for around US$15-20 used, and the Second Edition is about US$30, so I don’t think that’s too much to spend on one of the most valuable books you can get. The First Edition is nice to have available to see the refactorings in a more familiar language, and the Second Edition has improved and updated the “code smells” and principles text.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read Chapters 1, 2&lt;/li&gt;
&lt;li&gt;Skim Chapter 3 (identifies code smells)&lt;/li&gt;
&lt;li&gt;Can skip Chapter 4 (Test)&lt;/li&gt;
&lt;li&gt;Skim through the list of Refactorings (Chapter 6 through to the end) – this is the refactoring “catalog”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://www.biblio.com/9780201485677&quot;&gt;Buy Refactoring 1st Edition on Biblio&lt;/a&gt;
&lt;a href=&quot;https://amzn.to/2UMAl13&quot;&gt;Buy Refactoring 1st Edition on Amazon&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.indiebound.org/book/9780134757599?aff=jitterted&quot;&gt;Buy Refactoring 2nd Edition on IndieBound&lt;/a&gt;
&lt;a href=&quot;https://amzn.to/2B7ZFHY&quot;&gt;Buy Refactoring 2nd Edition on Amazon&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;%E2%80%9Cdomain-driven-design%E2%80%9D-by-eric-evans&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/09/07/top-five-forever-books-for-coders/#%E2%80%9Cdomain-driven-design%E2%80%9D-by-eric-evans&quot;&gt;&lt;em&gt;“Domain-Driven Design”&lt;/em&gt; by Eric Evans&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I use the patterns and the principles from this book &lt;strong&gt;all the time&lt;/strong&gt;. If you’ve ever heard me speak in person or on stream, you’ll hear me use terms such as “ubiquitous language” and “context boundary” and “repository pattern” quite a bit. This is not the easiest book to understand, not because it’s poorly written, but because there’s a lot packed into it, and it’s written in a certain Pattern Language style that can take a bit of getting used to. The main point that you should take away is thinking about your applications Domain First (what should the system be &lt;em&gt;doing&lt;/em&gt;) instead of Data[base] First (what &lt;em&gt;data&lt;/em&gt; are we keeping track of). The more you try to use these concepts and patterns, the more you’ll start to see ways of applying them – it’s a virtuous cycle.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read all the way through&lt;/li&gt;
&lt;li&gt;On your second read-through, start with Part IV “Strategic Design” and work your way, Part by Part towards the beginning of the book.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://www.indiebound.org/book/9780321125217?aff=jitterted&quot;&gt;Buy Domain-Driven Design on IndieBound&lt;/a&gt;
&lt;a href=&quot;https://amzn.to/3e6Gc8X&quot;&gt;Buy Domain-Driven Design on Amazon&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;5.-%E2%80%9Cextreme-programming-explained%E2%80%9D-by-kent-beck&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/09/07/top-five-forever-books-for-coders/#5.-%E2%80%9Cextreme-programming-explained%E2%80%9D-by-kent-beck&quot;&gt;5. &lt;em&gt;“eXtreme Programming Explained”&lt;/em&gt; by Kent Beck&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This book (also known as XP Explained) had such a huge impact on the way I, and soon enough the teams I worked with, developed software. The idea of pair programming was mind-blowing for me, and the emphasis on developer testing, something I was doing anyway, was reassuring. The flattening of the “Cost of Change” curve was also surprising as it went against what I had learned about project management of software development projects: earlier is better, later is badder. That assumption is wrong and is the cause of premature flexibility (You Ain’t Gonna Need It, aka YAGNI) that makes software &lt;em&gt;less&lt;/em&gt; flexible rather than more.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The links are for the 2nd Edition, which is almost a full rewrite of the 1st, but retains the overall thrust of XP:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;XP is a style of software development focusing on excellent application of programming techniques, clear communication, and teamwork which allows us to accomplish things we previously could not even imagine.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Read the whole thing&lt;/li&gt;
&lt;li&gt;Discuss with your colleagues&lt;/li&gt;
&lt;li&gt;Read it again&lt;/li&gt;
&lt;li&gt;Repeat on a regular basis&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://www.indiebound.org/book/9780321278654?aff=jitterted&quot;&gt;Buy eXtreme Programming Explained 2nd Ed. on IndieBound&lt;/a&gt;
&lt;a href=&quot;https://amzn.to/3hwyBTn&quot;&gt;Buy eXtreme Programming Explained 2nd Ed. on Amazon&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Event Bus: Inside or Outside the Hexagon?</title>
    <link href="https://ted.dev/articles/2022/07/29/event-bus-inside-or-outside-the-hexagon/"/>
    <updated>2022-07-29T10:00:00Z</updated>
    <id>https://ted.dev/articles/2022/07/29/event-bus-inside-or-outside-the-hexagon/</id>
    <content xml:lang="en" type="html">&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/external-event-hexagon.png&quot; alt=&quot;Diagram of a hexagonal architecture, which contains Application Layer and Domain Layer inside the hexagon, and adapters on the outside&quot; width=&quot;100%&quot;&gt;&lt;figcaption&gt;Hexagonal Architecture: The Hexagon&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p class=&quot;mb-4 text-lg&quot;&gt;&lt;span class=&quot;text-3xl font-bold mr-4 float-left&quot;&gt;Q. &lt;/span&gt; In Hexagonal Architecture, where does a Message/Event Bus belong?&lt;/p&gt;
&lt;p class=&quot;mb-4 text-lg&quot;&gt;&lt;span class=&quot;text-3xl font-bold mr-4 float-left&quot;&gt;A. &lt;/span&gt; It depends! (Because of course it does.)&lt;/p&gt;
&lt;p&gt;In Hexagonal Architecture, we can often rely on the question of: “does it do I/O to support its work or run out-of-process?”
If not, then it can live inside the Hexagon, otherwise it’s on the outside (in adapters).
Note that you need to include all of its dependencies when answering this question.&lt;/p&gt;
&lt;h2 id=&quot;examples&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/07/29/event-bus-inside-or-outside-the-hexagon/#examples&quot;&gt;Examples&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;.fa-secondary%7Bopacity%3A.4%7D-in-process-eventbus&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/07/29/event-bus-inside-or-outside-the-hexagon/#.fa-secondary%7Bopacity%3A.4%7D-in-process-eventbus&quot;&gt;&lt;svg class=&quot;h-6 w-6 flex-none stroke-3 float-left mr-3 mt-1&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 512 512&quot;&gt;&lt;defs&gt;&lt;style&gt;.fa-secondary{opacity:.4}&lt;/style&gt;&lt;/defs&gt;&lt;path class=&quot;fa-primary fill-green-900&quot; d=&quot;M371.8 172.2C382.7 183.1 382.7 200.9 371.8 211.8L243.8 339.8C232.9 350.7 215.1 350.7 204.2 339.8L140.2 275.8C129.3 264.9 129.3 247.1 140.2 236.2C151.1 225.3 168.9 225.3 179.8 236.2L224 280.4L332.2 172.2C343.1 161.3 360.9 161.3 371.8 172.2V172.2z&quot;&gt;&lt;/path&gt;&lt;path class=&quot;fa-secondary fill-green-400&quot; d=&quot;M108.5 66.56C121.5 45.1 144.9 32 169.1 32H342C367.1 32 390.5 45.1 403.5 66.56L496 218.6C510 241.6 510 270.4 496 293.4L403.5 445.4C390.5 466.9 367.1 480 342 480H169.1C144.9 480 121.5 466.9 108.5 445.4L15.96 293.4C1.962 270.4 1.962 241.6 15.96 218.6L108.5 66.56zM371.8 211.8C382.7 200.9 382.7 183.1 371.8 172.2C360.9 161.3 343.1 161.3 332.2 172.2L224 280.4L179.8 236.2C168.9 225.3 151.1 225.3 140.2 236.2C129.3 247.1 129.3 264.9 140.2 275.8L204.2 339.8C215.1 350.7 232.9 350.7 243.8 339.8L371.8 211.8z&quot;&gt;&lt;/path&gt;&lt;/svg&gt; In-Process EventBus&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You want to use a library to do lightweight Domain Events publishing.
The code is in a single EventBus Jar&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2022/07/29/event-bus-inside-or-outside-the-hexagon/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;, and it doesn’t do any I/O, nor any out-of-process communication.
All events are “broadcast” to listeners by calling methods defined in a Listener interface (aka the &lt;em&gt;Observer Pattern&lt;/em&gt;) as they happen.
As long as it is easy to instantiate and Test-Double the EventBus (for testability, of course!), then &lt;strong&gt;it can go inside the Hexagon&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;.fa-secondary%7Bopacity%3A.4%7D-spring-framework%E2%80%99s-event-publisher&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/07/29/event-bus-inside-or-outside-the-hexagon/#.fa-secondary%7Bopacity%3A.4%7D-spring-framework%E2%80%99s-event-publisher&quot;&gt;&lt;svg class=&quot;h-6 w-6 flex-none stroke-3 float-left mr-3 mt-1&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 512 512&quot;&gt;&lt;defs&gt;&lt;style&gt;.fa-secondary{opacity:.4}&lt;/style&gt;&lt;/defs&gt;&lt;path class=&quot;fa-primary fill-red-800&quot; d=&quot;M255.1 222.1L303 175C312.4 165.7 327.6 165.7 336.1 175C346.3 184.4 346.3 199.6 336.1 208.1L289.9 255.1L336.1 303C346.3 312.4 346.3 327.6 336.1 336.1C327.6 346.3 312.4 346.3 303 336.1L255.1 289.9L208.1 336.1C199.6 346.3 184.4 346.3 175 336.1C165.7 327.6 165.7 312.4 175 303L222.1 255.1L175 208.1C165.7 199.6 165.7 184.4 175 175C184.4 165.7 199.6 165.7 208.1 175L255.1 222.1z&quot;&gt;&lt;/path&gt;&lt;path class=&quot;fa-secondary fill-red-300&quot; d=&quot;M108.5 66.56C121.5 45.1 144.9 32 169.1 32H342C367.1 32 390.5 45.1 403.5 66.56L496 218.6C510 241.6 510 270.4 496 293.4L403.5 445.4C390.5 466.9 367.1 480 342 480H169.1C144.9 480 121.5 466.9 108.5 445.4L15.96 293.4C1.962 270.4 1.962 241.6 15.96 218.6L108.5 66.56zM175 208.1L222.1 255.1L175 303C165.7 312.4 165.7 327.6 175 336.1C184.4 346.3 199.6 346.3 208.1 336.1L255.1 289.9L303 336.1C312.4 346.3 327.6 346.3 336.1 336.1C346.3 327.6 346.3 312.4 336.1 303L289.9 255.1L336.1 208.1C346.3 199.6 346.3 184.4 336.1 175C327.6 165.7 312.4 165.7 303 175L255.1 222.1L208.1 175C199.6 165.7 184.4 165.7 175 175C165.7 184.4 165.7 199.6 175 208.1V208.1z&quot;&gt;&lt;/path&gt;&lt;/svg&gt; Spring Framework’s Event Publisher&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You want to take advantage of Spring’s Application Event support.
In order to publish an event, you need a reference to an &lt;code&gt;ApplicationEventPublisher&lt;/code&gt;, which is in Spring’s context module.
This brings in the Spring Framework as a dependency, and, well, that means it &lt;strong&gt;cannot go inside the Hexagon&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;.fa-secondary%7Bopacity%3A.4%7D-async-job-runner&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/07/29/event-bus-inside-or-outside-the-hexagon/#.fa-secondary%7Bopacity%3A.4%7D-async-job-runner&quot;&gt;&lt;svg class=&quot;h-6 w-6 flex-none stroke-3 float-left mr-3 mt-1&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 512 512&quot;&gt;&lt;defs&gt;&lt;style&gt;.fa-secondary{opacity:.4}&lt;/style&gt;&lt;/defs&gt;&lt;path class=&quot;fa-primary fill-red-800&quot; d=&quot;M255.1 222.1L303 175C312.4 165.7 327.6 165.7 336.1 175C346.3 184.4 346.3 199.6 336.1 208.1L289.9 255.1L336.1 303C346.3 312.4 346.3 327.6 336.1 336.1C327.6 346.3 312.4 346.3 303 336.1L255.1 289.9L208.1 336.1C199.6 346.3 184.4 346.3 175 336.1C165.7 327.6 165.7 312.4 175 303L222.1 255.1L175 208.1C165.7 199.6 165.7 184.4 175 175C184.4 165.7 199.6 165.7 208.1 175L255.1 222.1z&quot;&gt;&lt;/path&gt;&lt;path class=&quot;fa-secondary fill-red-300&quot; d=&quot;M108.5 66.56C121.5 45.1 144.9 32 169.1 32H342C367.1 32 390.5 45.1 403.5 66.56L496 218.6C510 241.6 510 270.4 496 293.4L403.5 445.4C390.5 466.9 367.1 480 342 480H169.1C144.9 480 121.5 466.9 108.5 445.4L15.96 293.4C1.962 270.4 1.962 241.6 15.96 218.6L108.5 66.56zM175 208.1L222.1 255.1L175 303C165.7 312.4 165.7 327.6 175 336.1C184.4 346.3 199.6 346.3 208.1 336.1L255.1 289.9L303 336.1C312.4 346.3 327.6 346.3 336.1 336.1C346.3 327.6 346.3 312.4 336.1 303L289.9 255.1L336.1 208.1C346.3 199.6 346.3 184.4 336.1 175C327.6 165.7 312.4 165.7 303 175L255.1 222.1L208.1 175C199.6 165.7 184.4 165.7 175 175C165.7 184.4 165.7 199.6 175 208.1V208.1z&quot;&gt;&lt;/path&gt;&lt;/svg&gt; Async Job Runner&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;What about &lt;a href=&quot;https://jobrunr.io/&quot;&gt;JobRunr&lt;/a&gt;?
It’s a dedicated library for running jobs asynchronously, on a regular schedule, etc.
Usually you would use it with a real database (for persistence and potential scaling), but you can run it with an &lt;code&gt;InMemoryStorageProvider&lt;/code&gt;.
Technically, you &lt;strong&gt;might be able to run it within the Hexagon&lt;/strong&gt;, but it’s complex enough—and deals with concurrency/threads—that I’d push it outside the Hexagon.
I’d use an &lt;em&gt;Outbound Port&lt;/em&gt; to initiate scheduling jobs, and an &lt;em&gt;Inbound Adapter&lt;/em&gt; to handle execution of scheduled jobs.
Since a mere configuration change could cause it to depend on a real database, that would completely &lt;strong&gt;eliminate it from running inside the Hexagon&lt;/strong&gt;.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Note: Guava’s EventBus is now recommended not to be used. I found this out when I was looking at using an in-memory/in-process event bus. See the &lt;a href=&quot;https://guava.dev/releases/31.1-jre/api/docs/com/google/common/eventbus/EventBus.html&quot;&gt;EventBus API page&lt;/a&gt; for details. &lt;a href=&quot;https://ted.dev/articles/2022/07/29/event-bus-inside-or-outside-the-hexagon/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Removing a Feature is a Change in Behavior</title>
    <link href="https://ted.dev/articles/2022/07/21/removing-a-feature-is-a-change-in-behavior/"/>
    <updated>2022-07-21T10:00:00Z</updated>
    <id>https://ted.dev/articles/2022/07/21/removing-a-feature-is-a-change-in-behavior/</id>
    <content xml:lang="en" type="html">&lt;p&gt;On &lt;a href=&quot;https://ted.dev/discord&quot;&gt;my Discord&lt;/a&gt;, @Oye recently asked about removing a feature from a codebase using Test-Driven Development (TDD).
I love this question, because it hits the heart of one of the misunderstandings about that I see:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;TDD is only good for adding features by adding new, failing tests and adding code to make them pass.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In fact, TDD is great for making any behavior change in your code.
Adding and removing behavior are all changes.&lt;/p&gt;
&lt;p&gt;If you’ve read my article on &lt;a href=&quot;https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/&quot;&gt;Clarifying the Goal of Behavior Change&lt;/a&gt;, you’ll see that the first thing I do when starting my TDD process is define:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;What should the application do?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;How will you know it did it?&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When removing behavior, you can negate these statements:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;What does it currently do that it should &lt;strong&gt;stop&lt;/strong&gt; doing?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;How will you know it’s &lt;strong&gt;no longer&lt;/strong&gt; doing it?&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But really, it’s the same thing!&lt;/p&gt;
&lt;p&gt;For example, if your application currently shows an option to “ship today”, but the business says that’s too expensive (and unlikely to be solved soon), it needs to go. The next step is to answer those two questions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;It should stop showing the “Ship Today” option.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The test against the UI or API should ensure “Ship Today” doesn’t show up.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you TDD’d the original implementation, then there should be a test that was written when the “Ship Today” option was first added. Go into that test, and instead of asserting that it is there, assert that it’s not there.&lt;/p&gt;
&lt;p&gt;If you didn’t originally TDD it, or you never wrote a test for that behavior, now’s the time to do so. Write a test that looks at all the options for shipping and asserts that “Ship Today” is not there.&lt;/p&gt;
&lt;h3 id=&quot;cascading-deletes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/07/21/removing-a-feature-is-a-change-in-behavior/#cascading-deletes&quot;&gt;Cascading Deletes&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To get that (now) failing test to pass, you’ll likely delete code.
Propagate those deletions until everything is passing.
It’ll also mean you’ll change other tests as you follow the code across different objects and layers.
The goal is to stay out of the situation where a lot of tests are failing, and it’s taking a long time to delete/change the code to get them all passing.&lt;/p&gt;
&lt;p&gt;As you finish removing the feature, you may find that the “negative” tests are all that’s left of the feature.
You can decide to remove those (treat them as &lt;em&gt;scaffolding&lt;/em&gt;), or, if there’s risk that the behavior might resurface in some way, then leave them.
Or, it could be left in the test code as a useful trail of documentation.&lt;/p&gt;
&lt;p&gt;Sometimes you may find that entire objects are no longer needed, depending on how large the feature is.
And then, of course, entire test classes for those objects can also be deleted.
As @Suigi says in the &lt;a href=&quot;https://ted.dev/discord&quot;&gt;Discord&lt;/a&gt;, if an entire endpoint is going away, then remove it—and the test that then fails—and look for unused code. Delete that, and “cascade” that delete until all unused code (and tests) is removed.&lt;/p&gt;
&lt;h3 id=&quot;removal-is-change&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/07/21/removing-a-feature-is-a-change-in-behavior/#removal-is-change&quot;&gt;Removal is Change&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Again, there’s little difference in the TDD process for removing, because removing something is a change in behavior as much as adding something. Your tests define the behavior you want, then you change the code to make that test pass. Whether you add code or delete code, all that matters is getting that test to pass.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Improving Perceived Performance, Hexagonally</title>
    <link href="https://ted.dev/articles/2022/07/11/improving-perceived-performance-hexagonally/"/>
    <updated>2022-07-11T10:00:00Z</updated>
    <id>https://ted.dev/articles/2022/07/11/improving-perceived-performance-hexagonally/</id>
    <content xml:lang="en" type="html">&lt;h2 id=&quot;why-ensembler-is-slow&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/07/11/improving-perceived-performance-hexagonally/#why-ensembler-is-slow&quot;&gt;Why Ensembler is Slow&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’ve been trying to figure out how to make &lt;em&gt;Ensembler&lt;/em&gt;, my scheduling application for group programming sessions (aka &lt;a href=&quot;https://https//github.com/jitterted/mobreg&quot;&gt;MobReg&lt;/a&gt;), more responsive.
It’s an MPA (Multi-Page App, aka old-school web app), so when you click a button, the server does some work, then redirects you to a new page to see the result.
I want that work to not take any time (or at least not hold up the redirect), unless it must be completed in order to display the results on the next page.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/ensembler-member-view.png&quot; alt=&quot;Screenshot from the Ensembler app showing upcoming ensembles&quot; width=&quot;100%&quot;&gt;&lt;figcaption&gt;Member view of Ensembles&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;For Members (users of Ensembler), the main buttons they can click are &lt;strong&gt;Accept&lt;/strong&gt; and &lt;strong&gt;Decline&lt;/strong&gt; (to accept or decline attending a scheduled Ensemble session).
The time spent on the back-end here is mostly sending a single confirmation email (after an &lt;em&gt;Accept&lt;/em&gt;), which is around 100-300ms (depending on the response time of SendGrid).
The time to persist their RSVP takes almost no time.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/ensembler-admin-view.png&quot; alt=&quot;Screenshot from the Ensembler app showing Admin view of ensembles&quot; width=&quot;100%&quot;&gt;&lt;figcaption&gt;Admin view of Ensembles, with a Create Ensemble form&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;However, for me, the admin, it can take several seconds to do actions, such as “create a new Ensemble” due to blocking delays in two places:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Sending emails to members:&lt;/strong&gt; When a new Ensemble is scheduled, Ensembler doesn’t send an email in bulk to every member.
Instead, it sends a customized email to each member so it contains the date/time of the Ensemble in their time zone&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2022/07/11/improving-perceived-performance-hexagonally/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;. This means it’s linear to:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;number of members * ~200ms&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;There are currently ~15 members, which will only grow, so this is the biggest time sink.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Creating the Zoom meeting:&lt;/strong&gt; only done once. Takes about 500ms.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Neither of those actions needs to be completed to return a refreshed administration page, so they can both be async.
That is, both the email sending and Zoom meeting creation can run on a background thread, while the server returns from the HTTP request.
The persistence (via &lt;code&gt;ensembleRepository.save()&lt;/code&gt;) of the newly scheduled &lt;code&gt;Ensemble&lt;/code&gt; needs to be synchronous (otherwise I might not see what I just scheduled!), but it takes less than 50ms, so it’s fine.&lt;/p&gt;
&lt;h2 id=&quot;completable-futures-to-the-rescue&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/07/11/improving-perceived-performance-hexagonally/#completable-futures-to-the-rescue&quot;&gt;Completable Futures to the Rescue&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To make the two actions happen “in the background”, I figured I could wrap those actions in &lt;code&gt;CompletableFuture&lt;/code&gt;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2022/07/11/improving-perceived-performance-hexagonally/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; objects, which makes it easy to run a fragment of code on a separate thread&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2022/07/11/improving-perceived-performance-hexagonally/#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;, without having to write complex exception-handling code.&lt;/p&gt;
&lt;p&gt;To do this, I’d change the application service (&lt;code&gt;EnsembleService&lt;/code&gt;) so that the calls to the &lt;code&gt;Notifier&lt;/code&gt;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2022/07/11/improving-perceived-performance-hexagonally/#fn4&quot; id=&quot;fnref4&quot;&gt;[4]&lt;/a&gt;&lt;/sup&gt; and the &lt;code&gt;VideoConferenceScheduler&lt;/code&gt;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2022/07/11/improving-perceived-performance-hexagonally/#fn5&quot; id=&quot;fnref5&quot;&gt;[5]&lt;/a&gt;&lt;/sup&gt; are wrapped in &lt;code&gt;CompletableFuture&lt;/code&gt;s using the &lt;code&gt;runAsync()&lt;/code&gt; method.
Like this:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;runAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; notifier&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ensembleScheduled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
                ensemble&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token constant&quot;&gt;URI&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;https://mobreg.herokuapp.com/&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Easy to do, but I worried that tests checking for a method call (using a pre-programmed &lt;em&gt;Mock&lt;/em&gt;) might not &lt;em&gt;see&lt;/em&gt; it, as the whole point is to return from the method before the action was complete.
In other words, the test might finish before the async action had a chance to complete.
I was right.
It turns out the &lt;code&gt;ensembleScheduledWithMeetingLinkThenScheduledNotificationIsSent&lt;/code&gt; test fails:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;org&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;opentest4j&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;AssertionFailedError&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; 
        &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ensembleScheduled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; should have been called &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
         but was called &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; times&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

at &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;com&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jitterted&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mobreg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;application
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;EnsembleServiceEnsembleScheduledNotificationTest&lt;/span&gt;$&lt;span class=&quot;token class-name&quot;&gt;MockEnsembleScheduledNotifier&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;verify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;EnsembleServiceEnsembleScheduledNotificationTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;85&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
at &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;com&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;jitterted&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;mobreg&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;application
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;/span&gt;EnsembleServiceEnsembleScheduledNotificationTest&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ensembleScheduledWithMeetingLinkThenScheduledNotificationIsSent
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;EnsembleServiceEnsembleScheduledNotificationTest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;java&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;59&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Adding a &lt;code&gt;Thread.sleep(10)&lt;/code&gt; before the test verifies the method call is enough to get it to pass (yes, only 10ms!), but that is the &lt;em&gt;Wrong Way&lt;/em&gt; to verify async behavior in a test (any &lt;code&gt;Thread.sleep()&lt;/code&gt; is a test smell).
There are various &lt;em&gt;Right Ways&lt;/em&gt; to do this: inject the executor, get access to the &lt;code&gt;CompletableFuture&lt;/code&gt; (so you can &lt;code&gt;.join()&lt;/code&gt; it), etc.&lt;/p&gt;
&lt;h2 id=&quot;violating-hexagonal-architecture%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/07/11/improving-perceived-performance-hexagonally/#violating-hexagonal-architecture%3F&quot;&gt;Violating Hexagonal Architecture?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In a way, though, it feels like I’ve violated Hexagonal Architecture.
Why does the &lt;code&gt;EnsembleService&lt;/code&gt; take so long to do its job?
Because of infrastructure (calls to remote services).
If we make the Outbound Adapters return immediately (and do their work on a separate thread, perhaps leveraging Spring’s &lt;code&gt;@Async&lt;/code&gt;, or &lt;code&gt;Future&lt;/code&gt;s), then the problem goes away.&lt;/p&gt;
&lt;p&gt;Or does it? 🤔&lt;/p&gt;
&lt;p&gt;What if I need the Zoom meeting information returned by the API call in order to include it in the emails I send?
Then I can’t let the &lt;code&gt;ZoomScheduler&lt;/code&gt; do its work later, on a separate thread.
In that case, I need to wait on the answer in order to send the emails with the link.
Obviously, I also need to save the Zoom link in the database, so I have to wait for it anyway, but that doesn’t need to hold up the redirect (so doesn’t affect perceived performance).&lt;/p&gt;
&lt;p&gt;It seems like this is a decision that the Application Services Layer might need to make, and possibly even the Domain Layer.
In order to make it possible for the App or Domain layers to use the information, whether they run in the background would be left up to them.&lt;/p&gt;
&lt;p&gt;If we define the Port interface so that the methods wrap the return value in a &lt;code&gt;CompletableFuture&lt;/code&gt;, e.g., instead of:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Notifier&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ensembleScheduled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Ensemble&lt;/span&gt; ensemble&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URI&lt;/span&gt; registrationLink&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We do:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Notifier&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ensembleScheduled&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Ensemble&lt;/span&gt; ensemble&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;URI&lt;/span&gt; registrationLink&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we can ignore the return value (it’s just &lt;code&gt;void&lt;/code&gt;), letting it run and finish in the background.
Or, we can do a &lt;code&gt;.join()&lt;/code&gt; to block until the notifier completes.&lt;/p&gt;
&lt;p&gt;For the Zoom meeting creation, we can change:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VideoConferenceScheduler&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;ConferenceDetails&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createMeeting&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Ensemble&lt;/span&gt; ensemble&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to be:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;VideoConferenceScheduler&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;token class-name&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;ConferenceDetails&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;createMeeting&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Ensemble&lt;/span&gt; ensemble&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then use &lt;code&gt;supplyAsync()&lt;/code&gt; and &lt;code&gt;.thenAccept()&lt;/code&gt; to update the meeting link in the &lt;code&gt;Ensemble&lt;/code&gt; object&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2022/07/11/improving-perceived-performance-hexagonally/#fn6&quot; id=&quot;fnref6&quot;&gt;[6]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;CompletableFuture&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;supplyAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; videoConferenceScheduler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createMeeting&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ensemble&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;thenAccept&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;conferenceDetails &lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;token comment&quot;&gt;// update ensemble with info from details&lt;/span&gt;
                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;application-services-coordinate-%26-orchestrate&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/07/11/improving-perceived-performance-hexagonally/#application-services-coordinate-%26-orchestrate&quot;&gt;Application Services Coordinate &amp;amp; Orchestrate&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Doing this means the service only has to &lt;em&gt;coordinate&lt;/em&gt; those futures, but doesn’t need to &lt;em&gt;execute&lt;/em&gt; them—they’re already running on their own thread.
Coordination is hard enough, so letting the &lt;em&gt;Outbound Adapter&lt;/em&gt; implementation decide how it’s going to run seems like the right split.
I think that’s more in the spirit of Hexagonal Architecture.&lt;/p&gt;
&lt;p&gt;This will be one of the things I implement on a future Live Coding stream on &lt;a href=&quot;https://jitterted.stream/&quot;&gt;Twitch&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What do you think?
Are there other ways to handle time-consuming operations in your infrastructure without blocking?
Let me know on &lt;a href=&quot;https://twitter.com/JitterTed&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://ted.dev/discord&quot;&gt;my Discord&lt;/a&gt;.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Yes, there are ways to do this in a single API call, but let’s assume there isn’t, or the time for the API call to return is linear to the number of emails. &lt;a href=&quot;https://ted.dev/articles/2022/07/11/improving-perceived-performance-hexagonally/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;See the API docs: &lt;a href=&quot;https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/CompletableFuture.html&quot;&gt;https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/CompletableFuture.html&lt;/a&gt; &lt;a href=&quot;https://ted.dev/articles/2022/07/11/improving-perceived-performance-hexagonally/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;It will either create and manage a new &lt;code&gt;Thread&lt;/code&gt; for you, or use the &lt;a href=&quot;https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/ForkJoinPool.html#commonPool()&quot;&gt;&lt;code&gt;ForkJoinPool.commonPool()&lt;/code&gt;&lt;/a&gt;. &lt;a href=&quot;https://ted.dev/articles/2022/07/11/improving-perceived-performance-hexagonally/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn4&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;An &lt;em&gt;Outbound Port&lt;/em&gt; interface implemented by &lt;code&gt;SendGridNotifier&lt;/code&gt; to send emails via SendGrid’s Java SDK. &lt;a href=&quot;https://ted.dev/articles/2022/07/11/improving-perceived-performance-hexagonally/#fnref4&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn5&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;A different &lt;em&gt;Outbound Port&lt;/em&gt; interface implemented by &lt;code&gt;ZoomScheduler&lt;/code&gt; to create meetings via Zoom’s API. &lt;a href=&quot;https://ted.dev/articles/2022/07/11/improving-perceived-performance-hexagonally/#fnref5&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn6&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Of course, you would have to use a separate transaction to update the Ensemble’s information. &lt;a href=&quot;https://ted.dev/articles/2022/07/11/improving-perceived-performance-hexagonally/#fnref6&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Tightening Our Assertions</title>
    <link href="https://ted.dev/articles/2022/06/22/tightening-our-assertions/"/>
    <updated>2022-06-22T10:00:00Z</updated>
    <id>https://ted.dev/articles/2022/06/22/tightening-our-assertions/</id>
    <content xml:lang="en" type="html">&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/vise-clamp-squeeze-assertions-750x500.jpg&quot; alt=&quot;A blue vise clamp is squeezing a wooden block that has the word &#39;Assertions&#39; written on it.&quot; width=&quot;100%&quot;&gt;&lt;figcaption&gt;Really Squeeze &#39;Em&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;specifying%2C-or-over-specifying%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#specifying%2C-or-over-specifying%3F&quot;&gt;Specifying, or Over-specifying?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://ted.dev/articles/2022/05/09/implementing-the-feature/&quot;&gt;Last time&lt;/a&gt;, we were test-driving our Blackjack game. We got all the tests to pass, but there were questions around the precision of our assertion. Here’s the test we ended with:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;playerWithTwoCardsDrawsCardResultsInThreeCards&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Game&lt;/span&gt; game &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Game&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;initialDeal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;playerDrawCardFromDeck&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token function&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;playerCards&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasSize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;alternative-solution&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#alternative-solution&quot;&gt;Alternative Solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Last time, our solution:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;playerDrawCardFromDeck&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   playerHand&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deck&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;was copied from the implementation in the &lt;code&gt;initialDeal()&lt;/code&gt; method:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;initialDeal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// player gets card first due to rules of Blackjack&lt;/span&gt;
    playerHand&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;drawCardFrom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deck&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    dealerHand&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;drawCardFrom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deck&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token comment&quot;&gt;// everyone gets two cards, so deal another round&lt;/span&gt;
    playerHand&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;drawCardFrom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deck&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    dealerHand&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;drawCardFrom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deck&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What if we didn’t already have a copy-and-paste solution? What would’ve been the least effort implementation? How about:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;playerDrawCardFromDeck&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    playerHand&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That would still get the test to pass, as there would be 3 entries in the player’s list of cards. How? Well, &lt;code&gt;null&lt;/code&gt; counts as a card!&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; This certainly isn’t what we want in our game, though. Perhaps we’re missing some assertions? Let’s look back at our original specification:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Given a &lt;span class=&quot;smcap&quot;&gt;PLAYER&lt;/span&gt; with a &lt;span class=&quot;smcap&quot;&gt;HAND&lt;/span&gt; containing 2 &lt;span class=&quot;smcap&quot;&gt;CARD&lt;/span&gt;s,&lt;/p&gt;
&lt;p&gt;When the &lt;span class=&quot;smcap&quot;&gt;PLAYER&lt;/span&gt; &lt;span class=&quot;smcap&quot;&gt;DRAW&lt;/span&gt;s a &lt;span class=&quot;smcap&quot;&gt;CARD&lt;/span&gt; from the &lt;span class=&quot;smcap&quot;&gt;DECK&lt;/span&gt;,&lt;/p&gt;
&lt;p&gt;Then the &lt;span class=&quot;smcap&quot;&gt;HAND&lt;/span&gt; should have 3 &lt;span class=&quot;smcap&quot;&gt;CARD&lt;/span&gt;s.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The highlighted part of “from the &lt;span class=&quot;smcap&quot;&gt;DECK&lt;/span&gt;” is something that we’re not asserting. We’re also not ensuring the cards in the player’s hand are valid instances, without any nulls. So let’s fix that.&lt;/p&gt;
&lt;h2 id=&quot;tightening-our-assertions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#tightening-our-assertions&quot;&gt;Tightening Our Assertions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Sometimes “loose” assertions are fine, as they specify just enough of the behavior we need to get a failing test, like we did by asserting the hand had 3 things in it.
Then we can use our &lt;em&gt;professional judgment&lt;/em&gt; of the implemented code to determine if the assertions are appropriate.&lt;/p&gt;
&lt;p&gt;In this case, we see that our “add null” implementation passes the test, but isn’t what we want&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;.
Let’s adjust that by going through a “tightening phase”, ratcheting up the precision of the assertions one at a time.  Note that each tightening step will still follow the Red-Green part of the TDD cycle.&lt;/p&gt;
&lt;h3 id=&quot;hand-should-have-3-(non-null)-cards&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#hand-should-have-3-(non-null)-cards&quot;&gt;Hand Should Have 3 (Non-Null) Cards&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;First, let’s make sure that what’s in the player’s list of cards are all actually instances of &lt;code&gt;Card&lt;/code&gt;.
We could examine each element to see if it’s an instance of &lt;code&gt;Card&lt;/code&gt;, but since the list can only hold &lt;code&gt;Card&lt;/code&gt; objects (yay generics), we can get away with just making sure there are no &lt;code&gt;null&lt;/code&gt;s in the list.
Here we’ll use AssertJ’s handy &lt;code&gt;doesNotContainNull()&lt;/code&gt; assertion&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token function&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;playerCards&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;doesNotContainNull&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasSize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since we’ve changed what this test asserts, according to &lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/&quot;&gt;Predictive TDD&lt;/a&gt;, we need to state our failure prediction precisely:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This test will fail, because there is indeed a &lt;code&gt;null&lt;/code&gt; in the list, and we assert there aren’t any.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;text-red-800 font-bold mt-4 p-2&quot;&gt;
java.lang.AssertionError:
Expecting actual:
[Card {suit=♠, rank=A}, Card {suit=♦, rank=2}, null]
not to contain null elements
&lt;/pre&gt;
&lt;p&gt;Success! It fails as expected. Now let’s get the test to pass by writing the least effort code&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#fn4&quot; id=&quot;fnref4&quot;&gt;[4]&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;playerDrawCardFromDeck&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    playerHand&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Card&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;♦&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;8&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Creating a &lt;code&gt;Card&lt;/code&gt; out of thin air is allowed, and certainly requires little effort. We know it’ll be temporary, but if the test passes, then we know the test is doing its job enforcing the list to have no &lt;code&gt;null&lt;/code&gt; object references.&lt;/p&gt;
&lt;p&gt;We can now predict the test will pass, and it does.&lt;/p&gt;
&lt;h3 id=&quot;even-tighter%3A-card-comes-from-the-deck&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#even-tighter%3A-card-comes-from-the-deck&quot;&gt;Even Tighter: Card Comes From the Deck&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let’s make our assertions even more precise and enforce the requirement that the newly added &lt;code&gt;Card&lt;/code&gt; actually comes from the &lt;code&gt;Deck&lt;/code&gt; (no cheating by pulling a card out of your sleeve!). How do we do this? The &lt;code&gt;Game&lt;/code&gt; code does not provide a way to directly access the &lt;code&gt;Deck&lt;/code&gt; object, nor a way to pass it into its constructor&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#fn5&quot; id=&quot;fnref5&quot;&gt;[5]&lt;/a&gt;&lt;/sup&gt;. This is not a test problem, but a &lt;em&gt;code&lt;/em&gt; (possibly design) problem. At this point, we have three choices:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Just change the implementation to take a &lt;code&gt;Card&lt;/code&gt; from the &lt;code&gt;Deck&lt;/code&gt; instead of instantiating a new &lt;code&gt;Card&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a new public query method that returns either:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;a)&lt;/strong&gt; The &lt;code&gt;Deck&lt;/code&gt; instance, where we can assert that its size has been reduced by 1, or,&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;b)&lt;/strong&gt; Just the size of the deck, since we don’t need any other information about the deck.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add a &lt;code&gt;Game&lt;/code&gt; constructor that takes a &lt;code&gt;Deck&lt;/code&gt; instance, which allows us the option of asserting .&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id=&quot;option-1%3A-just-change-it&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#option-1%3A-just-change-it&quot;&gt;Option 1: Just change it&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;This might seem like skipping a step, but we are allowed to use our &lt;em&gt;professional judgment&lt;/em&gt;.
We can look at the code, see that it would be correct, and make the change.
It’s one line of code, and we’re replacing something “fake” (directly instantiating a &lt;code&gt;Card&lt;/code&gt;) with something real (drawing the &lt;code&gt;Card&lt;/code&gt; from a &lt;code&gt;Deck&lt;/code&gt;). We don’t &lt;strong&gt;always&lt;/strong&gt; have to have a failing test when doing something obvious (in our judgment) like this&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#fn6&quot; id=&quot;fnref6&quot;&gt;[6]&lt;/a&gt;&lt;/sup&gt;. With this option, we would replace &lt;code&gt;new Card(&amp;quot;♦&amp;quot;, &amp;quot;8&amp;quot;)&lt;/code&gt; with &lt;code&gt;deck.draw()&lt;/code&gt;, run the test (which would pass) and call it done.&lt;/p&gt;
&lt;h4 id=&quot;option-2%3A-add-test-specific-methods&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#option-2%3A-add-test-specific-methods&quot;&gt;Option 2: Add test-specific methods&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Options 2a and 2b seem wrong, because we’d add public methods purely for testing. It might be appropriate as a stepping stone towards improving the overall design, but by itself it means the state is changing &lt;em&gt;somewhere&lt;/em&gt; that we’re not able to observe. What’s worse, even with that information, we still wouldn’t know for sure that the &lt;code&gt;Card&lt;/code&gt; drawn from the &lt;code&gt;Deck&lt;/code&gt; was added to the player’s hand. The following implementation would make it seem (to an outside observer, like our test) that the right thing happened:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;playerDrawCardFromDeck&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
     deck&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// reduces the number of cards in the Deck&lt;/span&gt;
     playerHand&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Card&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;♦&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;8&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// adds a different card&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, we could use our professional judgment and decide we wouldn’t do something silly like that. So we could add a method to &lt;code&gt;Game&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;deckSize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
     &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;deck&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and assert in our test that this is the expected size, like this:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token function&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;deckSize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isEqualTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;52&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
         &lt;span class=&quot;token comment&quot;&gt;// 52: original size of the `Deck`&lt;/span&gt;
         &lt;span class=&quot;token comment&quot;&gt;// subtract 4: 2 cards dealt each to player &amp;amp; dealer&lt;/span&gt;
         &lt;span class=&quot;token comment&quot;&gt;// subtract 1: the player drew a card from the deck&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, providing a test-only query method like this is a &lt;em&gt;code smell&lt;/em&gt;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#fn7&quot; id=&quot;fnref7&quot;&gt;[7]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h4 id=&quot;option-3%3A-inject-deck-into-game&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#option-3%3A-inject-deck-into-game&quot;&gt;Option 3: Inject &lt;code&gt;Deck&lt;/code&gt; into &lt;code&gt;Game&lt;/code&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Option 3 is ultimately the better way to go. We can provide &lt;code&gt;Game&lt;/code&gt; with a &lt;code&gt;Deck&lt;/code&gt; that we construct in our test, so that we know that the &lt;code&gt;Card&lt;/code&gt; in the player’s hand is the one that came directly from the &lt;code&gt;Deck&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We’ll see how to do this next time, leveraging some automated refactorings that IntelliJ IDEA provides. We’ll also dismantle our &lt;code&gt;null&lt;/code&gt;-checking scaffolding once it’s done serving its purpose.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Even though the hand is a genericized &lt;code&gt;List&lt;/code&gt; that only holds &lt;code&gt;Card&lt;/code&gt; instances, &lt;code&gt;null&lt;/code&gt; is allowed. &lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;And possibly not even a reasonable implementation, despite it being “least effort code”. &lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Interested in learning more about &lt;a href=&quot;https://assertj.com/&quot;&gt;AssertJ&lt;/a&gt;’s powerful—and seemingly unending—set of assertions? Let me know on &lt;a href=&quot;https://twitter.com/JitterTed&quot;&gt;Twitter&lt;/a&gt; or on &lt;a href=&quot;https://ted.dev/discord&quot;&gt;my Discord&lt;/a&gt;. &lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn4&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Using a “literal” is almost always the least effort code. I consider &lt;code&gt;new Card(&amp;quot;♦&amp;quot;, &amp;quot;8&amp;quot;)&lt;/code&gt; to be a literal, because it’s not computed and no logic is used in its creation, and the Suit and Rank that make it up are themselves literals. You could call it a constant, but I often associate that with a &lt;em&gt;named&lt;/em&gt; constant, e.g. &lt;code&gt;MAX_CACHE_SIZE&lt;/code&gt;. &lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#fnref4&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn5&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;That’s right, &lt;em&gt;dependency injection&lt;/em&gt;, a fancy way to say “pass in an object as a parameter to the constructor”. &lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#fnref5&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn6&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;As GeePaw Hill &lt;a href=&quot;https://twitter.com/GeePawHill/status/1517370621742747648&quot;&gt;says&lt;/a&gt;, “Always suspect ‘always’ and ‘never’”. &lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#fnref6&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn7&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;And no, adding some annotation like &lt;code&gt;@VisibleForTesting&lt;/code&gt; on the &lt;code&gt;deckSize()&lt;/code&gt; method does not help. We might do this as &lt;em&gt;scaffolding&lt;/em&gt; (a temporary helping structure) to get us to somewhere better, but only if there’s no other way to go. &lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/#fnref7&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>How I Think About Builders</title>
    <link href="https://ted.dev/articles/2022/06/19/how-i-think-about-builders/"/>
    <updated>2022-06-19T10:00:00Z</updated>
    <id>https://ted.dev/articles/2022/06/19/how-i-think-about-builders/</id>
    <content xml:lang="en" type="html">&lt;p&gt;For the GoF Builder, use the &lt;a href=&quot;https://github.com/kdl-org/kdl&quot;&gt;KDL language&lt;/a&gt; as the “director” and then implementations that can create an HTML document, a PDF, or even &lt;a href=&quot;https://github.com/kdl-org/kdl/blob/main/JSON-IN-KDL.md&quot;&gt;JSON&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Bloch Builder
For Configuration&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Pardon the Clutter</title>
    <link href="https://ted.dev/articles/2022/05/19/pardon-the-clutter/"/>
    <updated>2022-05-19T10:00:00Z</updated>
    <id>https://ted.dev/articles/2022/05/19/pardon-the-clutter/</id>
    <content xml:lang="en" type="html">&lt;h2 id=&quot;welcome-to-the-new-ted.dev&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/05/19/pardon-the-clutter/#welcome-to-the-new-ted.dev&quot;&gt;Welcome to The New TED.DEV&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you’ve stopped by here before, you may have noticed that the domain &lt;a href=&quot;https://ted.dev/&quot;&gt;&lt;code&gt;TED.dev&lt;/code&gt;&lt;/a&gt; no longer redirects to &lt;a href=&quot;https://tedmyoung.com/&quot;&gt;&lt;code&gt;tedmyoung.com&lt;/code&gt;&lt;/a&gt;, which is my old (and non-responsive, yucky) website. In fact, if you stopped by in the past couple of weeks, you might’ve noticed a single, lonely article, and nothing else. That’s because I redirected the domain thinking that I’d have the site ready quickly. Yep. 🤷‍♂️&lt;/p&gt;
&lt;h2 id=&quot;static-site-generation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/05/19/pardon-the-clutter/#static-site-generation&quot;&gt;Static Site Generation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A long time ago, I used WordPress, but always thought it was too awkward and slow. I moved to Publii (which is what &lt;a href=&quot;https://tedmyoung.com/&quot;&gt;&lt;code&gt;tedmyoung.com&lt;/code&gt;&lt;/a&gt; is still running on as of June 2022), which churns out HTML, so is fast, but it was also awkward. I played with &lt;a href=&quot;https://gridsome.org/&quot;&gt;Gridsome&lt;/a&gt;, which is based on Vue.js, but is not &lt;em&gt;actively&lt;/em&gt; developed and hasn’t gotten to a 1.0 release. I also don’t (yet?) need the power of a front-end framework like Vue. I’ve tried &lt;a href=&quot;https://gohugo.io/&quot;&gt;Hugo&lt;/a&gt; many times over the years, but something about it didn’t work for me. (It isn’t at 1.0 either, but is actively developed.)&lt;/p&gt;
&lt;p&gt;I’ve had my eye on &lt;a href=&quot;https://ted.dev/articles/2022/05/19/pardon-the-clutter/11ty.dev&quot;&gt;11ty&lt;/a&gt; (“Eleventy”) for a while, and with its recent 1.0 release, I decided to give it a closer look. I had learned a lot about it from &lt;a href=&quot;https://andy-bell.co.uk/&quot;&gt;Andy Bell&lt;/a&gt;’s &lt;a href=&quot;https://learneleventyfromscratch.com/&quot;&gt;“Learn Eleventy from Scratch”&lt;/a&gt; course, which is now &lt;a href=&quot;https://piccalil.li/blog/learn-eleventy-from-scratch-is-now-open-source/&quot;&gt;open source&lt;/a&gt;. And while Andy ported his 11ty-based site back into WordPress, I like the simplicity and control I now have with 11ty&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2022/05/19/pardon-the-clutter/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id=&quot;goodbye-substack&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/05/19/pardon-the-clutter/#goodbye-substack&quot;&gt;Goodbye Substack&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;My goal is to gather all the various (and dead) sites I’ve left strewn about the internet, and put them here.
However, the main impetus behind the move is two-fold:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Get my content off of &lt;a href=&quot;https://jitterted.substack.com/&quot;&gt;Substack&lt;/a&gt;: I’m very much a believer in “own your platform” when it comes to content, and Substack was meant to be temporary anyway. Mainly, I needed to consolidate my email list to prepare for…&lt;/li&gt;
&lt;li&gt;Launching my self-paced course: “Refactoring to Hexagonal Architecture”! Shh! I haven’t officially announced it. To stay updated, subscribe to my newsletter &lt;a href=&quot;https://mycmt.dev/&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Not having a pleasant website for my writing has also meant I’ve been less motivated to write. Now I can write more, including about new courses that I’m excited about.&lt;/p&gt;
&lt;p&gt;In the meantime, I’ll migrate all my past Substack newsletter articles to this site, and then start moving things from elsewhere and publishing new articles.&lt;/p&gt;
&lt;h2 id=&quot;the-future&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/05/19/pardon-the-clutter/#the-future&quot;&gt;The Future&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There’s still a lot of content to add, not just articles, but also information about my classes, technical coaching, etc. There’s also “design” work to do: larger excerpts for articles on the front page, a “better” front page, different fonts (now &lt;em&gt;there’s&lt;/em&gt; a rat hole!), tweaks to the footnoting, etc. And internally, more 11ty shortcuts and plugins to help with things like images, etc. However, I now have a good foundation to build upon.&lt;/p&gt;
&lt;h2 id=&quot;community&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/05/19/pardon-the-clutter/#community&quot;&gt;Community&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Do you know I run a &lt;a href=&quot;https://ted.dev/discord&quot;&gt;Discord community&lt;/a&gt;? It’s a place where folks discuss Java (and PHP and C#), object-oriented programming and design, unit testing, test-driven development (TDD), Hexagonal Architecture, and more. I’d always wanted a place where I could talk to folks about code and design at a deeper level than you’d find on places like Reddit. It also supports the “live coding” that I do &lt;a href=&quot;https://jitterted.stream/&quot;&gt;on Twitch&lt;/a&gt;. If that sounds interesting, join us using this Discord invitation link: &lt;a href=&quot;https://discord.gg/9XDfBSZ&quot;&gt;https://discord.gg/9XDfBSZ&lt;/a&gt;.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Not that it was easy to get to this point. In fact, aspects were &lt;em&gt;much&lt;/em&gt; harder than expected. Ask me if you want to know more details, maybe I’ll write an article or two about the experience. &lt;a href=&quot;https://ted.dev/articles/2022/05/19/pardon-the-clutter/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Implementing the Feature</title>
    <link href="https://ted.dev/articles/2022/05/09/implementing-the-feature/"/>
    <updated>2022-05-09T10:00:00Z</updated>
    <id>https://ted.dev/articles/2022/05/09/implementing-the-feature/</id>
    <content xml:lang="en" type="html">&lt;h2 id=&quot;implementing-the-feature&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/05/09/implementing-the-feature/#implementing-the-feature&quot;&gt;Implementing the Feature&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Continuing from &lt;a href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/&quot;&gt;last time&lt;/a&gt;, we’re now ready to &lt;strong&gt;write code&lt;/strong&gt;!&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/write-code-card.png&quot; alt=&quot;The &amp;ldquo;Write Code&amp;rdquo; card from JitterTed&#39;s TDD Game&quot; width=&quot;25%&quot;&gt;&lt;figcaption&gt;The &amp;ldquo;Write Code&amp;rdquo; Card from &lt;a href=&quot;https://tdd.cards/&quot;&gt;JitterTed&#39;s TDD Game&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h3 id=&quot;predictive-tdd&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/05/09/implementing-the-feature/#predictive-tdd&quot;&gt;Predictive TDD&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As a reminder, the high-level steps of PTDD are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Precisely define the desired change in behavior&lt;/li&gt;
&lt;li&gt;Write a test that fails in the &lt;em&gt;precisely&lt;/em&gt; predicted way&lt;/li&gt;
&lt;li&gt;Implement (with minimal effort) the behavior to make the test pass&lt;/li&gt;
&lt;li&gt;Increase the Changeability of the code by Refactoring&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In &lt;a href=&quot;https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/&quot;&gt;Part 1&lt;/a&gt;, we defined the behavior change we wanted to see. Remember that new functionality (or the rare removal of functionality) is a change in behavior. In &lt;a href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/&quot;&gt;Part 2&lt;/a&gt;, we wrote a test and made it fail in the way we wanted and expected. In this part, we can finally write code to implement that new behavior and Get To Green!&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/ptdd-cycle-least-code-to-pass.png&quot; alt=&quot;Flowchart with 4 hexagons that says, from left to right: &amp;quot;Write least amount of code to pass&amp;quot;, &amp;quot;Predict test passes&amp;quot;, &amp;quot;Run test&amp;quot;, &amp;quot;Test passes!&amp;quot;&quot; width=&quot;75%&quot;&gt;&lt;figcaption&gt;Least Amount of Code Flowchart&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;write-less-code&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/05/09/implementing-the-feature/#write-less-code&quot;&gt;Write Less Code&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One of the difficult aspects of learning TDD (and we’re always learning when doing TDD) is writing the &lt;em&gt;absolute minimum&lt;/em&gt; amount of code to get the (currently failing) test to pass&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2022/05/09/implementing-the-feature/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;. Most of us were taught, or learned along the way, to write generalized code that captures multiple, different scenarios. This habit leads us to write code that handles situations that the test isn’t testing. It’s hard to break this habit, but taking tiny steps is the key to success with TDD.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/less-code-card.png&quot; alt=&quot;Picture of the &amp;ldquo;Less Code&amp;rdquo; card from JitterTed&#39;s TDD Game&quot; width=&quot;25%&quot;&gt;&lt;figcaption&gt;The &amp;ldquo;Less Code&amp;rdquo; Card from &lt;a href=&quot;https://tdd.cards/&quot;&gt;JitterTed&#39;s TDD Game&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Writing less code means the code will more likely be correct. If it’s not, and the test continues to fail (or other tests fail!), there will be less code to troubleshoot. It’s much easier to find a bug in 3 lines of code than 10, let alone 50.&lt;/p&gt;
&lt;p&gt;By focusing on just getting the test to pass, and not concerning ourselves with how “elegant” or “beautiful” the code is, we can use all our precious cognitive energy to solve the problem. Later on, we can transform the code into something better through the refactoring process, but let’s make it work first.&lt;/p&gt;
&lt;h2 id=&quot;blackjack-game%3A-player-draws-a-card&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/05/09/implementing-the-feature/#blackjack-game%3A-player-draws-a-card&quot;&gt;Blackjack Game: Player Draws a Card&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In Part 2, we wrote a failing test for the behavior where a Player “draws” (takes) a single card from the deck of cards in a game of Blackjack. Here’s that test:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;playerWithTwoCardsDrawsCardResultsInThreeCards&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Game&lt;/span&gt; game &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Game&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;initialDeal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;playerDrawCardFromDeck&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;token function&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;playerCards&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
               &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasSize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After a bit of work, we were able to get the test to run and fail as expected. The player gets 2 cards from the &lt;code&gt;initialDeal()&lt;/code&gt;, and since the &lt;code&gt;playerDrawCardFromDeck()&lt;/code&gt; doesn’t (yet) do anything, we ended up with 2 cards instead of the 3 that we want.&lt;/p&gt;
&lt;h3 id=&quot;implement-the-behavior&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/05/09/implementing-the-feature/#implement-the-behavior&quot;&gt;Implement the Behavior&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To get the test to compile (so we could watch it fail for the right reason), we created the &lt;code&gt;playerDrawCardFromDeck()&lt;/code&gt; method, but purposely left the implementation empty. Now we (finally!) fill in the desired behavior.&lt;/p&gt;
&lt;p&gt;Our instincts might lead us to writing an implementation that looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;playerDrawCardFromDeck&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
   playerHand&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deck&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This may not look like much, but just in this one line we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;playerHand&lt;/code&gt;, and knowing what it is (it’s a &lt;code&gt;List&amp;lt;Card&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;List&lt;/code&gt;’s &lt;code&gt;add()&lt;/code&gt; method (which takes a &lt;code&gt;Card&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;deck (an instance of the &lt;code&gt;Deck&lt;/code&gt; class)&lt;/li&gt;
&lt;li&gt;The deck’s &lt;code&gt;draw()&lt;/code&gt; method (which returns a &lt;code&gt;Card&lt;/code&gt;, matching the &lt;code&gt;add()&lt;/code&gt; parameter)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s &lt;strong&gt;4&lt;/strong&gt; different things to think about, which can be a lot if you’re not familiar with the code. However, since we are (at least I am) familiar with it, it’s fine. In fact, this code was copy-pasted from elsewhere in the &lt;code&gt;Game&lt;/code&gt; class. We copied it from the &lt;code&gt;initialDeal()&lt;/code&gt; method, where cards are dealt to the player and dealer, so this counts as “less effort code”.&lt;/p&gt;
&lt;h2 id=&quot;predict-success&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/05/09/implementing-the-feature/#predict-success&quot;&gt;Predict Success&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that we have a test that failed for the right reason and implemented the least effort code that we think will make the test pass, it’s time to run the test. This time, instead of predicting failure, we’re predicting the failing test will now pass, so we run it.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/ptdd-3-test-passes.png&quot; alt=&quot;Screenshot showing all tests passing with a green checkmark&quot; width=&quot;90%&quot;&gt;&lt;figcaption&gt;Success!&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;And it does indeed pass—ship it!&lt;/p&gt;
&lt;h2 id=&quot;assertion-precision&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/05/09/implementing-the-feature/#assertion-precision&quot;&gt;Assertion Precision&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Should we celebrate yet? Our assertion that the player ends up with 3 cards is necessary, but is it sufficient? And while we got the tests to pass—we’re in “The Green”—we’re not yet done with our TDD cycle, as we haven’t looked for Refactoring opportunities.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/&quot;&gt;Next time&lt;/a&gt;, we’ll “ratchet up” (make more precise) what asserting, and then we can move on to the last step: Refactoring. Subscribe below to make sure you don’t miss it!&lt;/p&gt;
&lt;h2 id=&quot;the-tdd-intro-series&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/05/09/implementing-the-feature/#the-tdd-intro-series&quot;&gt;The TDD Intro Series&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2021/02/27/red-green-or-refactoring-first/&quot;&gt;Red-Green or Refactoring First?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/&quot;&gt;Clarifying the Goal of Behavior Change&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/&quot;&gt;Predicting the Failing Test&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implementing the Feature&lt;/strong&gt; (this article)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/&quot;&gt;Tightening Our Assertions&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I often refer to this as “least effort code,” because sometimes copying and pasting 5 lines of code is the least effort, but possibly not the least &lt;em&gt;amount&lt;/em&gt; of code. &lt;a href=&quot;https://ted.dev/articles/2022/05/09/implementing-the-feature/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Remote Learning Ensembles</title>
    <link href="https://ted.dev/articles/2022/01/15/remote-learning-ensembles/"/>
    <updated>2022-01-15T10:00:00Z</updated>
    <id>https://ted.dev/articles/2022/01/15/remote-learning-ensembles/</id>
    <content xml:lang="en" type="html">&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;2023-10-09&lt;/em&gt;: Added “Spectator” role information, added Retrospective details&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;2023-03-27&lt;/em&gt;: Added some Driver etiquette around not blocking information, closing unneeded windows, etc.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;2022-06-09&lt;/em&gt;: This article was originally published on &lt;a href=&quot;http://dev.to/&quot;&gt;Dev.to&lt;/a&gt;, but it’s time to bring it here, and add some updates.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;2022-03-22&lt;/em&gt;: Updates since I first wrote this can be found as bracketed &amp;amp; italic remarks inline.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;how-i-run-remote-learning-ensembles&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/01/15/remote-learning-ensembles/#how-i-run-remote-learning-ensembles&quot;&gt;How I Run Remote Learning Ensembles&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Ensemble&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2022/01/15/remote-learning-ensembles/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; sessions that I’ve been running for the past few &lt;s&gt;months&lt;/s&gt; years are centered around improving developer skills in test-driven development (TDD), domain-driven design (DDD), and Hexagonal Architecture, with a focus on taking small, safe steps, and frequent refactoring. Since the codebase is Java, it’s turned out that all attendees are using IntelliJ IDEA, so an additional focus has been learning its shortcuts and the less common automated refactorings (such as &lt;em&gt;Move Method&lt;/em&gt;).&lt;/p&gt;
&lt;h3 id=&quot;facilitate-from-the-outside&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/01/15/remote-learning-ensembles/#facilitate-from-the-outside&quot;&gt;Facilitate From the Outside&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Since the focus is on learning skills and not necessarily getting “work” done, I stay out of the rotation, observing and providing guidance and advice along the way. I also serve as the “customer” providing direction on the features being developed. [&lt;em&gt;However, if there’s only 2 attendees, I’ll participate in the rotation.&lt;/em&gt;]&lt;/p&gt;
&lt;p&gt;Below you’ll find information on how I currently run the Learning Ensembles. Much of this was gathered from various sources, some adapted, and some learned by trial and error.&lt;/p&gt;
&lt;h3 id=&quot;handing-off&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/01/15/remote-learning-ensembles/#handing-off&quot;&gt;Handing Off&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I’ve found that using GitHub-based hand-offs, using the awesome command-line tool &lt;a href=&quot;https://mob.sh/&quot;&gt;mob.sh&lt;/a&gt;, to work better than other mechanisms that I’ve tried. It allows people to use their own computer and IDE, which means they’re not only comfortable using tools that they’re used to, but they’re building skills (such as shortcut keys) in their “natural” environment. The downside is that there’s a bit of disruption during the hand-off, mainly around the new &lt;span class=&quot;smcap&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2022/01/15/remote-learning-ensembles/#driver&quot;&gt;Driver&lt;/a&gt;&lt;/span&gt; taking over. They may need to rearrange editor windows and open up files, though this tends to be less of a problem after a complete cycle of turns.&lt;/p&gt;
&lt;h2 id=&quot;roles&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/01/15/remote-learning-ensembles/#roles&quot;&gt;Roles&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We call the person at the keyboard (and the one sharing their screen) the &lt;span class=&quot;smcap&quot;&gt;Driver&lt;/span&gt; and the person directing them the &lt;span class=&quot;smcap&quot;&gt;Navigator&lt;/span&gt;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2022/01/15/remote-learning-ensembles/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;. I’ve gone back and forth about the role names (e.g., Typist, Director), but have found that metaphor of getting to a destination using the roles of &lt;span class=&quot;smcap&quot;&gt;Driver&lt;/span&gt; and &lt;span class=&quot;smcap&quot;&gt;Navigator&lt;/span&gt; to be well-suited.&lt;/p&gt;
&lt;h3 id=&quot;driver&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/01/15/remote-learning-ensembles/#driver&quot;&gt;Driver&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;When starting your turn, clearly state that you’re ready for the Navigator’s instructions by saying “I’m Ready” out loud.&lt;/p&gt;
&lt;p&gt;This is needed because the &lt;span class=&quot;smcap&quot;&gt;Driver&lt;/span&gt; needs time to run the &lt;code&gt;mob start&lt;/code&gt; command (to get the latest code on their machine) and arrange the IDE windows as needed.&lt;/p&gt;
&lt;p&gt;[&lt;em&gt;We’ve standardized on having the IDE split the screen into left &amp;amp; right panes, with the test code on the left, and the feature code on the right. This way the test “drives” the code from left to right.&lt;/em&gt;]&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;span class=&quot;smcap&quot;&gt;Driver&lt;/span&gt;’s job is to carry out the &lt;span class=&quot;smcap&quot;&gt;Navigator&lt;/span&gt;’s intent. Note: there is only one &lt;span class=&quot;smcap&quot;&gt;Navigator&lt;/span&gt; navigating at a time, otherwise the &lt;span class=&quot;smcap&quot;&gt;Driver&lt;/span&gt; can get confused by too many requests.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If the &lt;span class=&quot;smcap&quot;&gt;Driver&lt;/span&gt; is unsure what to do next, or how to do it, they ask the &lt;span class=&quot;smcap&quot;&gt;Navigator&lt;/span&gt; for clarification.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It’s often helpful for the &lt;span class=&quot;smcap&quot;&gt;Driver&lt;/span&gt; to offer choices “do you want me to extract the whole block, or just line 24?”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Avoid having a &lt;em&gt;Runaway Driver&lt;/em&gt; where the &lt;span class=&quot;smcap&quot;&gt;Driver&lt;/span&gt; does more than (or different things from) what was asked.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Don’t scroll around, unless the &lt;span class=&quot;smcap&quot;&gt;Driver&lt;/span&gt; requests it, as it can be disorienting to the &lt;span class=&quot;smcap&quot;&gt;Navigator&lt;/span&gt; (and the rest of the ensemble).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Avoid leaving popups visible as they can block important information.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Close window panes that aren’t needed, especially the Terminal and Project windows. Give as much room to the tests and code as possible.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;navigator&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/01/15/remote-learning-ensembles/#navigator&quot;&gt;Navigator&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Declares intent at the highest level first, only providing more detail if the &lt;span class=&quot;smcap&quot;&gt;Driver&lt;/span&gt; asks, e.g.:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Start with intent&lt;/strong&gt;: “extract the loop to a new method named Process Transactions”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Provide more detail&lt;/strong&gt;: “select lines 24 through 28, use Refactor, then Extract Method.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Even more detail&lt;/strong&gt;: “click on the word ‘for’ on line 24, press the expand-selection key a few times, now click on…”&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Avoid micro-managing (“backseat driving”) the fixing of syntax errors or typos.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On the other hand, it’s very important that the &lt;span class=&quot;smcap&quot;&gt;Navigator&lt;/span&gt; pay close attention to what the &lt;span class=&quot;smcap&quot;&gt;Driver&lt;/span&gt; actually did as a result of their instructions. Did they type the correct thing? Did they extract the correct lines into a new method? This is &lt;strong&gt;not easy&lt;/strong&gt;, as &lt;span class=&quot;smcap&quot;&gt;Navigators&lt;/span&gt; tend to think about the next step, and assume their previous intent was carried out correctly. It’s common for the &lt;span class=&quot;smcap&quot;&gt;Driver&lt;/span&gt; to do something different from what was asked, but about 20% of the time, the &lt;span class=&quot;smcap&quot;&gt;Navigator&lt;/span&gt; didn’t notice, causing problems or confusion. As facilitator, I’ll often step in at this point, if nobody else pointed out the discrepancy.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Communication is hard, and the only way a &lt;span class=&quot;smcap&quot;&gt;Navigator&lt;/span&gt; knows that they were understood is if the &lt;span class=&quot;smcap&quot;&gt;Driver&lt;/span&gt; did what was desired.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When the turn is over, inform the next &lt;span class=&quot;smcap&quot;&gt;Navigator&lt;/span&gt; of what you had in mind. However, it’s up to the new &lt;span class=&quot;smcap&quot;&gt;Navigator&lt;/span&gt; to either continue down that road, or try something else.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;onboarding-new-participants&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/01/15/remote-learning-ensembles/#onboarding-new-participants&quot;&gt;Onboarding New Participants&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Get their GitHub username&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Add the username as collaborator to the repository that will be used for the Ensemble&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;They’ll need to accept the invite, so do this enough in advance&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Participants will need to install and verify that these work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The &lt;a href=&quot;http://mob.sh/&quot;&gt;mob.sh&lt;/a&gt; tool (which requires &lt;code&gt;git&lt;/code&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Zoom, especially share screen privileges&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Do audio check, video check is optional&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Whatever IDE they’re comfortable with&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Increase font size of IDE to at least 16px for screen sharing readability (sometimes 18px is needed!)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Correct version of Java (11 or later)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Clone the repository via SSH if possible (this makes it easier to push)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Build and run all of the tests&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Do a test &lt;code&gt;mob start&lt;/code&gt; and &lt;code&gt;mob next&lt;/code&gt; to ensure privileges are set up correctly&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;facilitator-preparation&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/01/15/remote-learning-ensembles/#facilitator-preparation&quot;&gt;Facilitator Preparation&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Fill out names in the Mob timer&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;We use &lt;a href=&quot;https://mobti.me/&quot;&gt;https://mobti.me&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Make sure to rotate so folks aren’t always in the same order or are navigating the same driver&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify participants have accepted GitHub repo invitations&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify repository has the latest code (all changes since last session pushed)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Review retrospective and Mission notes from prior sessions&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I keep these notes in the same repository as the project code&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ensure goals (I called this the “Mission”) for the upcoming session are clear&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Send a link to the Zoom that we’ll be using (even if it’s the same one, people like/need the reminder)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;I use my &lt;a href=&quot;https://github.com/jitterted/ensembler&quot;&gt;Ensembler&lt;/a&gt; tool to handle this for me, among other things&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-session&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/01/15/remote-learning-ensembles/#the-session&quot;&gt;The Session&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is based on my experience with 90-105 minute-long sessions [&lt;em&gt;I’ve found 105-115 minutes—just under 2 hours—better for groups that only get together once a week, or less, in order to remember and/or understand the context&lt;/em&gt;]. We cap the size to 5 active participants, with turn times of 5 minutes each.&lt;/p&gt;
&lt;p&gt;We have two main roles: &lt;span class=&quot;smcap&quot;&gt;Driver&lt;/span&gt; and &lt;span class=&quot;smcap&quot;&gt;Navigator&lt;/span&gt; (as described above). When the turn is over (after the 5-minute timer has expired), the &lt;span class=&quot;smcap&quot;&gt;Navigator&lt;/span&gt; becomes the new &lt;span class=&quot;smcap&quot;&gt;Driver&lt;/span&gt; and the &lt;span class=&quot;smcap&quot;&gt;Driver&lt;/span&gt; goes back into the general crowd. [&lt;em&gt;We now go the other way: Driver becomes Navigator, and Navigator returns to the crowd, as the Driver has the code already in their head/fingers.&lt;/em&gt;]&lt;/p&gt;
&lt;h3 id=&quot;the-huddle&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/01/15/remote-learning-ensembles/#the-huddle&quot;&gt;The Huddle&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;[&lt;em&gt;Added details on The Huddle&lt;/em&gt;]&lt;/p&gt;
&lt;p&gt;The starting Huddle is a way for the group to sync up and understand where things are and what the next task is. This is important as people haven’t seen the code for a week or more (or never!). Once the first &lt;span class=&quot;smcap&quot;&gt;Navigator&lt;/span&gt; agrees that they have a sense of what to do, the Huddle ends.&lt;/p&gt;
&lt;p&gt;During the Ensemble, people can get lost, can disagree on which way to go, etc., and so anyone can call for a Huddle. The timer is stopped and discussion starts. It’s important to get back to the code, so if the discussion becomes too detailed (or too abstract!), it’s time to see if there’s enough understanding to take the next step, without worrying about the steps after that. As the saying goes, “discuss in code”! In other words, trying out an idea by writing actual code, is better at demonstrating what approach is better/worse than just talking about it.&lt;/p&gt;
&lt;h3 id=&quot;agenda&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/01/15/remote-learning-ensembles/#agenda&quot;&gt;Agenda&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Introduce anyone who’s new&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Provide the mob timer link (if a separate one like &lt;a href=&quot;https://mobti.me/&quot;&gt;mobti.me&lt;/a&gt; is used)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Remind folks of any Code of Conduct&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;At a minimum, remind them that this is a learning experience and to be compassionate and curious&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create (or update) a &lt;code&gt;participants.txt&lt;/code&gt; file with the date, and start a list with the facilitator’s name as the 0th entry. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Session #10 - Friday, May 28, 2021
----------------------------------
0. Ted
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;[&lt;em&gt;I stopped putting my name as facilitator, and now it starts with the first participant.&lt;/em&gt;]&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Do one rotation by having each participant do the steps below when it’s their turn. The purpose of this exercise it to ensure everyone can share their screen, update their local copy of the repo, and push changes to the repo, as well as a check of their audio and font size. Doing it at the beginning means that it won’t interrupt the Ensemble’s flow during the actual work:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Share their screen (I make sure that Zoom allows participants to “steal” or “grab” the screen sharing from the current sharer)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Execute a &lt;code&gt;mob start&lt;/code&gt;, once it completes…&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Type their name in the &lt;code&gt;participants.txt&lt;/code&gt; file (if it doesn’t show up, or is missing other participants, you know something’s not quite right), e.g.:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Participants from Ensemble #50 on March 4, 2022
-----------------------------------------------
1. Hoffman
2. Moxie
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Execute a &lt;code&gt;mob next&lt;/code&gt; and once it completes…&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Announce “Ready for next DRIVER”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Next driver takes over and repeats from step 1 until everyone has had a turn&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Explain/review the mission for the session&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I keep this in a text file in the same repository as the project code&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Team does a “huddle”, where they discuss the mission, make sure they understand it, and define the next task or two.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The first &lt;span class=&quot;smcap&quot;&gt;Driver&lt;/span&gt; shares their screen, does a “mob start” and when complete declares “I’m ready”&lt;/p&gt;
&lt;p&gt;[&lt;em&gt;Usually they’ll start by running all the tests&lt;/em&gt;]&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;span class=&quot;smcap&quot;&gt;Navigator&lt;/span&gt; provides instructions to the Driver&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;When the turn is over (the timer has gone off), the &lt;span class=&quot;smcap&quot;&gt;Navigator&lt;/span&gt; relays their intent (what they were trying to achieve) to the next Navigator&lt;/p&gt;
&lt;p&gt;[&lt;em&gt;If the Navigator/Driver pair are almost done with a task, I’ll usually let them finish it before moving to the next person.&lt;/em&gt;]&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Things that need to be done (delete that test, rename that class, fix that flaky test) are dropped into chat&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Side-comments about the work, such as naming suggestions or questions, are also dropped into chat&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After each full cycle (everyone has taken their turn once), the facilitator runs a “mini-retrospective”, if the ensemble feels that things are in a good flow, the mini-retro can be skipped.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Often the 2nd time around, folks feel the need to hold a mini-retro to regroup and gain perspective.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;[&lt;em&gt;With a more experienced group, I’ve found explicitly taking time for a mini-retro unnecessary, as folks learn to call for a Huddle as needed&lt;/em&gt;]&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The final turn ends when there’s 15-20 minutes left in the scheduled ensemble time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Conclude with a retrospective, where each person in the rotation provides thoughts, observations, things they learn, etc., until everyone has run out of things to say. Then, things to do more or less of, what went well/not so well, etc., are noted in an outline or mind map.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Facilitator shares observations (the more specific and concrete, the better), such as “I noticed it took 3 turns to finally get from red to green” or questions, such as “how did it feel to leave have that test continue to be flaky”, or “was anyone uncomfortable with the poor code formatting in that method?”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Session ends with cleaning up of the pending tasks, collecting undone ones from chat, checking off those that are done, etc.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Everyone waves goodbye!&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&quot;ch-ch-ch-ch-changes&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2022/01/15/remote-learning-ensembles/#ch-ch-ch-ch-changes&quot;&gt;Ch-ch-ch-ch-changes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Note that we have changed how we run the Ensembles over time, because of things brought up in our Retrospectives and the freedom to experiment. I’ll follow up with additional articles as I learn. One non-trivial change was the order of Driver-Navigator. When we swapped that order, we found less of a need to “hand-off” intentions.&lt;/p&gt;
&lt;p&gt;Let me know about your experiences with Ensembles by &lt;a href=&quot;https://ted.dev/discord&quot;&gt;joining my Discord&lt;/a&gt; or tweeting at me on &lt;a href=&quot;https://twitter.com/jitterted&quot;&gt;Twitter&lt;/a&gt;.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Like others, I prefer to use the term &lt;span class=&quot;smcap&quot;&gt;Ensemble&lt;/span&gt; instead of Mob Programming, as it’s a “friendlier” term. &lt;a href=&quot;https://ted.dev/articles/2022/01/15/remote-learning-ensembles/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;These roles come from Pair Programming terminology, and we specifically follow the “strong-style” pairing method from &lt;a href=&quot;https://llewellynfalco.blogspot.com/2014/06/llewellyns-strong-style-pairing.html&quot;&gt;Llewellyn Falco&lt;/a&gt;. &lt;a href=&quot;https://ted.dev/articles/2022/01/15/remote-learning-ensembles/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Fooled By the Failure to Fail</title>
    <link href="https://ted.dev/articles/2021/11/23/fooled-by-the-failure-to-fail/"/>
    <updated>2021-11-23T10:00:00Z</updated>
    <id>https://ted.dev/articles/2021/11/23/fooled-by-the-failure-to-fail/</id>
    <content xml:lang="en" type="html">&lt;p&gt;In &lt;a href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/&quot;&gt;Part 2&lt;/a&gt; of my “Predictive Test-Driven Development” series, I talked about how predicting the failure of a test is not always enough. Predicting &lt;em&gt;precisely&lt;/em&gt;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/11/23/fooled-by-the-failure-to-fail/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; how the test will fail helps me stay alert for tests that fail for a different reason, or perhaps don’t fail at all (i.e., they pass). I want to share another example of what can happen when you ignore the &lt;span class=&quot;smcap&quot;&gt;Predicted Failure&lt;/span&gt;. This happened during one of my “Refactoring to Testable Code” training classes&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/11/23/fooled-by-the-failure-to-fail/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;, which again shows that experts make mistakes!&lt;/p&gt;
&lt;h2 id=&quot;test-driving-an-http-endpoint&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/11/23/fooled-by-the-failure-to-fail/#test-driving-an-http-endpoint&quot;&gt;Test-Driving an HTTP Endpoint&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the third session of the class, I demonstrate how to test-drive a new web-based user interface using Spring MVC and the Thymeleaf templating engine. The code I’m working with is a single-player Blackjack game. In preparing for this particular class, I had updated the Spring Boot dependency to the most recent version—something I usually avoid because it’s risky. I felt OK doing it this time, because I used the same version in other projects with no problems&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/11/23/fooled-by-the-failure-to-fail/#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;I start with a few cycles of TDD, where I create Spring MVC tests to drive the creation of code to handle incoming requests. I get to a point where a template is returned to show the state of the game when it starts, triggered by a button (using &lt;span class=&quot;smcap&quot;&gt;POST&lt;/span&gt;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/11/23/fooled-by-the-failure-to-fail/#fn4&quot; id=&quot;fnref4&quot;&gt;[4]&lt;/a&gt;&lt;/sup&gt;). I continue to follow the process, first creating a failing test like this:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;postToStartGameEndpointIsStatus200Ok&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    mockMvc&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;perform&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/start-game&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
           &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;andExpect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isOk&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, the test wants to verify a successful response when requesting (via &lt;span class=&quot;smcap&quot;&gt;POST&lt;/span&gt;) the page at the endpoint /start-game. Before I run the test, I state my &lt;span class=&quot;smcap&quot;&gt;Precise Prediction&lt;/span&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This test will fail with a &lt;span class=&quot;smcap&quot;&gt;404 (Not Found)&lt;/span&gt; status instead of the desired &lt;span class=&quot;smcap&quot;&gt;200 (OK)&lt;/span&gt; status.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is because there’s no code responding to the endpoint, and Spring MVC will default to returning a &lt;span class=&quot;smcap&quot;&gt;404&lt;/span&gt; in that case. I run the test, and it fails in the predicted way:&lt;/p&gt;
&lt;pre class=&quot;text-red-800 font-bold mt-4 p-2&quot;&gt;
java.lang.AssertionError: Status expected:&lt;200&gt; but was:&lt;404&gt;
Expected :200
Actual   :404
&lt;/pre&gt;
&lt;p&gt;My next step is actually &lt;strong&gt;not&lt;/strong&gt; to make the test pass, but to write just enough code to make it &lt;em&gt;fail for a different reason&lt;/em&gt;. This is because writing enough code to make it pass does too much in one step. The two steps I want are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;No more &lt;span class=&quot;smcap&quot;&gt;404&lt;/span&gt;: Spring MVC calls the method I want for the &lt;code&gt;/start-game&lt;/code&gt; endpoint, and&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Return a valid template name that Thymeleaf can find and process.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I want to write just enough code so #1 works, but still fails for #2, because the template file matching the name I return (&lt;code&gt;blackjack&lt;/code&gt;) doesn’t yet exist. Once the test fails for reason #2, I can drop in the template file into the &lt;code&gt;templates&lt;/code&gt; directory, and finally watch the test pass&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/11/23/fooled-by-the-failure-to-fail/#fn5&quot; id=&quot;fnref5&quot;&gt;[5]&lt;/a&gt;&lt;/sup&gt;. The code I write next (in the &lt;code&gt;@Controller&lt;/code&gt; class) is:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@PostMapping&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;/start-game&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;startGame&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;blackjack&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now my prediction is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This test will fail with a Thymeleaf exception, complaining that it can’t find the template named &lt;code&gt;blackjack&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I run the test, and it passes. I am appropriately surprised by this, given my prediction! Note that I have done this exact scenario every time I’ve taught this class, well over 30 times by this point, and it &lt;em&gt;always&lt;/em&gt; failed for the expected reason.&lt;/p&gt;
&lt;h2 id=&quot;watch-out-for-the-availability-heuristic&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/11/23/fooled-by-the-failure-to-fail/#watch-out-for-the-availability-heuristic&quot;&gt;Watch Out for the Availability Heuristic&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You may have heard of the &lt;a href=&quot;https://thedecisionlab.com/biases/availability-heuristic&quot;&gt;Availability Heuristic&lt;/a&gt;, a cognitive bias that leads us to believe “the correctness of a hypothesis based on &lt;em&gt;how easily&lt;/em&gt; that hypothesis…comes to mind”. Well, the most “available” hypothesis that came to mind for me was: “oh no, I shouldn’t have upgraded the Spring Boot dependency, something must have changed, and now it just works”. I ignored the fact that the test didn’t fail, and continued with the next step in the TDD cycle: I copied the Thymeleaf &lt;code&gt;blackjack&lt;/code&gt; template into the correct directory, and told the class “now we can run the application to see the generated page”.&lt;/p&gt;
&lt;p&gt;You might guess what happened: I got an error page that said:&lt;/p&gt;
&lt;pre class=&quot;text-red-800 font-bold mt-4 p-2&quot;&gt;

There was an unexpected error (type=Not Found, status=404).

&lt;/pre&gt;
&lt;p&gt;Now I’m confused. The test passed (when I didn’t expect it to), but at runtime it’s failing in a way I can’t explain. 🤔&lt;/p&gt;
&lt;p&gt;At this point, I go into troubleshooting mode: I turn on debug-level logging, rerun the application, and notice a lack of Thymeleaf code anywhere in the output. 💡 I now have a new hypothesis, one grounded in observation (rather than guessing or availability): do I have the Thymeleaf dependency in my project’s Maven file?&lt;/p&gt;
&lt;p&gt;Of course, I don’t. 😯 Somehow it got dropped when I initially added Spring Boot dependencies to the project during my demonstration. I added the missing dependency and “rewound” things. I restated the prediction:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The test will fail with a Thymeleaf exception, as it can’t find the &lt;code&gt;blackjack&lt;/code&gt; template.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Then ran the test. It now failed for the &lt;em&gt;right reason&lt;/em&gt;:&lt;/p&gt;
&lt;pre class=&quot;text-red-800 font-bold mt-4 p-2&quot;&gt;
Caused by: org.thymeleaf.exceptions.TemplateInputException: 
  Error resolving template [blackjack], template might not exist
  or might not be accessible by any of the configured Template Resolvers
at org.thymeleaf.engine.TemplateManager.resolveTemplate(TemplateManager.java:869)
&lt;/pre&gt;
&lt;p&gt;With a sigh of relief at the correct failure, I continued on.&lt;/p&gt;
&lt;h2 id=&quot;lessons-for-everyone&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/11/23/fooled-by-the-failure-to-fail/#lessons-for-everyone&quot;&gt;Lessons For Everyone&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What did I learn?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Don’t ignore tests that fail for the wrong reason, or pass unexpectedly. You could be making a wrong assumption. It’s worth the extra time to track down and understand why it didn’t fail as expected.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go back to a known state. I could have changed the version of Spring back to the one I had been using for months to eliminate that as a cause.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Don’t update dependencies right before teaching a class. If I hadn’t, I would have searched for other reasons for the problem much earlier, as the upgrade of the dependency would not have been my most “available” hypothesis.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Making mistakes is OK (even in front of an audience). Often those mistakes make great content for articles and future classes. I now &lt;strong&gt;make this mistake on purpose&lt;/strong&gt; to show how valuable it is to pay attention to unexpectedly passing tests.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I’m thinking of renaming my process to Precisely Predictive TDD (PPTDD)! &lt;a href=&quot;https://ted.dev/articles/2021/11/23/fooled-by-the-failure-to-fail/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Find out about the next public offering of this class by signing up to &lt;a href=&quot;https://mycmt.dev/&quot;&gt;my mailing list&lt;/a&gt;. &lt;a href=&quot;https://ted.dev/articles/2021/11/23/fooled-by-the-failure-to-fail/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;This fact becomes important later… &lt;a href=&quot;https://ted.dev/articles/2021/11/23/fooled-by-the-failure-to-fail/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn4&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I know we shouldn’t return content via &lt;span class=&quot;smcap&quot;&gt;POST&lt;/span&gt; here for a Web App, this is something we fix later in the class. &lt;a href=&quot;https://ted.dev/articles/2021/11/23/fooled-by-the-failure-to-fail/#fnref4&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn5&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Note that I don’t directly test the &lt;em&gt;content&lt;/em&gt; of the page generated by Thymeleaf, which would have been helpful. &lt;a href=&quot;https://ted.dev/articles/2021/11/23/fooled-by-the-failure-to-fail/#fnref5&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Predicting the Failing Test</title>
    <link href="https://ted.dev/articles/2021/11/05/predicting-the-failing-test/"/>
    <updated>2021-11-05T10:00:00Z</updated>
    <id>https://ted.dev/articles/2021/11/05/predicting-the-failing-test/</id>
    <content xml:lang="en" type="html">&lt;p&gt;Way back in &lt;a href=&quot;https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/&quot;&gt;March 2021&lt;/a&gt;, I started explaining my &lt;em&gt;Predictive Test-Driven Development&lt;/em&gt; process. The whole process looks like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/full-detailed-tdd-cycle-prediction.png&quot; alt=&quot;Flowchart of steps in the process&quot; width=&quot;100%&quot;&gt;&lt;figcaption&gt;My Entire PTDD Process. &lt;a href=&quot;https://tdd.cards/&quot;&gt;Now available as a game!&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;In part 1, we looked at the beginning of the process, answering the questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;What should it do?&lt;/strong&gt; and&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;How will you know it did it?&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These questions help clarify our goal for the next bit of behavior change, i.e., what we want our system to do that it currently doesn’t. We need this clarity to take the next step: writing a failing test.&lt;/p&gt;
&lt;h2 id=&quot;the-failing-test&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/#the-failing-test&quot;&gt;The Failing Test&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Our next major goal is to create a test and watch it fail. These next three steps in the process get us closer:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/detailed-tdd-cycle-2-test-compiles.png&quot; alt=&quot;Flowchart of steps in the process&quot; width=&quot;83%&quot;&gt;&lt;figcaption&gt;Getting Test to Compile&lt;/figcaption&gt;&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Write Test for Code Yet-to-Be:&lt;/strong&gt; this reminds us that we’re writing test code for behavior that doesn’t yet exist. Or, it’s different from what exists now, such as a bug.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Fails to Compile:&lt;/strong&gt; when testing new behavior, we may need to create a new method, or even a new class.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Write Least Amount of Code to Compile:&lt;/strong&gt; for any non-existent methods or classes, our job here is to only create them, not implement them. Treat this like a game: how little code can you write to get the code to compile?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s look at the example from the domain of a single-player version of the Blackjack card game from Part 1:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Given a &lt;span class=&quot;smcap&quot;&gt;PLAYER&lt;/span&gt; with a &lt;span class=&quot;smcap&quot;&gt;HAND&lt;/span&gt; containing 2 &lt;span class=&quot;smcap&quot;&gt;CARD&lt;/span&gt;s,&lt;/p&gt;
&lt;p&gt;When the &lt;span class=&quot;smcap&quot;&gt;PLAYER&lt;/span&gt; &lt;span class=&quot;smcap&quot;&gt;DRAW&lt;/span&gt;s a &lt;span class=&quot;smcap&quot;&gt;CARD&lt;/span&gt; from the &lt;span class=&quot;smcap&quot;&gt;DECK&lt;/span&gt;,&lt;/p&gt;
&lt;p&gt;Then the &lt;span class=&quot;smcap&quot;&gt;HAND&lt;/span&gt; should have 3 &lt;span class=&quot;smcap&quot;&gt;CARD&lt;/span&gt;s.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The new behavior here is having the player draw (take) a card from the deck&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;. Here’s a JUnit test that implements our example:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;playerWith2CardsDrawsCardThenHas3Cards&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Game&lt;/span&gt; game &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Game&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;playerDrawCardFromDeck&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;playerCards&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasSize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, the method &lt;code&gt;playerDrawCardFromDeck()&lt;/code&gt;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; does not yet exist, so it doesn’t compile (and shows as red in my development environment). Now we do the &lt;em&gt;minimum work possible&lt;/em&gt; to get the code to compile. We do that by creating the missing method in the &lt;code&gt;Game&lt;/code&gt; class:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;playerDrawCardFromDeck&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice it’s empty. We don’t implement anything yet, we write just enough code to compile so we can watch the test (hopefully!) fail. Next, let’s run the test.&lt;/p&gt;
&lt;h2 id=&quot;predict-how-the-test-fails&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/#predict-how-the-test-fails&quot;&gt;Predict How the Test Fails&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Stop! Don’t run that test yet!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/detailed-tdd-cycle-3-fails-as-predicted.png&quot; alt=&quot;Flowchart of steps in the process&quot; width=&quot;83%&quot;&gt;&lt;figcaption&gt;Predict Before Running&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;It’s tempting to go from getting the test to compile to running it and watching it fail, but you’d be missing an important part: prediction.&lt;/p&gt;
&lt;p&gt;For many years, I happily did TDD without predicting how the test would fail, and was successful at it. At some point, I noticed a common mistake: assuming the failing test failed for the expected reason: the yet-to-be-written production code. What if it failed for a &lt;em&gt;different&lt;/em&gt; reason? What if it failed because you misunderstood the existing code? Or the test setup (the “when”) was incorrect? If you assumed the test failed because of missing behavior, you’d be confused when the test continued to fail even after implementing that behavior.&lt;/p&gt;
&lt;p&gt;In our example, we expect the test to fail because &lt;code&gt;playerDrawCardFromDeck()&lt;/code&gt; does nothing. That should mean the number of cards the player has is two and not three. Let’s run the test with that prediction, i.e., the assertion will fail because our expected result of 3 is not the actual result of 2.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/unexpected-assertion-failure.png&quot; alt=&quot;Test failed with: java.lang.AssertionError: Expected size: 3 but was: 0 in: []&quot; width=&quot;50%&quot;&gt;&lt;figcaption&gt;Test Failed for the Wrong Reason&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Uh oh. That’s not what we predicted (expected). The test is failing (yay!), but for the &lt;em&gt;wrong reason&lt;/em&gt; (boo!). Why does the player have 0 cards? Let’s look at our test again:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;playerWith2CardsDrawsCardThenHas3Cards&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token class-name&quot;&gt;Game&lt;/span&gt; game &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Game&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;playerDrawCardFromDeck&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token function&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;playerCards&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasSize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Oops. We forgot to tell the &lt;code&gt;Game&lt;/code&gt; to do the &lt;em&gt;initial deal&lt;/em&gt;, which deals two cards each to the player and dealer. Let’s fix that:&lt;/p&gt;
&lt;pre class=&quot;language-diff-java&quot;&gt;&lt;code class=&quot;language-diff-java&quot;&gt;&lt;span class=&quot;token unchanged language-java&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;   &lt;span class=&quot;token annotation punctuation&quot;&gt;@Test&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;   &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;playerWith2CardsDrawsCardThenHas3Cards&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;       &lt;span class=&quot;token class-name&quot;&gt;Game&lt;/span&gt; game &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Game&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token inserted-sign inserted language-java&quot;&gt;&lt;span class=&quot;token prefix inserted&quot;&gt;+&lt;/span&gt;       game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;initialDeal&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;token unchanged language-java&quot;&gt;&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;       
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;       game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;playerDrawCardFromDeck&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;       
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;       &lt;span class=&quot;token function&quot;&gt;assertThat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;playerCards&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;           &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasSize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token prefix unchanged&quot;&gt; &lt;/span&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s run the test again – but wait! Let’s repeat our prediction: we will expect 3, but the actual result will be 2.&lt;/p&gt;
&lt;pre class=&quot;text-red-800 font-bold mt-4 p-2&quot;&gt;
java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
at java.base/java.util.ArrayList.remove(ArrayList.java:536)
at com.jitterted.ebp.blackjack.domain.Deck.draw(Deck.java:24)
at com.jitterted.ebp.blackjack.domain.Hand.drawFrom(Hand.java:45)
at com.jitterted.ebp.blackjack.domain.Game.dealRoundOfCards(Game.java:71)
at com.jitterted.ebp.blackjack.domain.Game.initialDeal(Game.java:64)
&lt;/pre&gt;
&lt;p&gt;Oh no, that’s even worse. What’s going on?&lt;/p&gt;
&lt;p&gt;A closer look at &lt;code&gt;initialDeal()&lt;/code&gt; reveals that we had some code leftover from an experiment and forgot to remove it. And we forgot to run &lt;strong&gt;all&lt;/strong&gt; of the tests before we started this session. Even us “experts” make silly mistakes like this&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;. However, our prediction prepared us to be on the lookout for anything out of the ordinary.&lt;/p&gt;
&lt;p&gt;Let’s clean up &lt;code&gt;initialDeal()&lt;/code&gt;, and, before we run the tests, we repeat our prediction so it’s fresh in our mind: we expect a size of 3, but the actual size will be 2.&lt;/p&gt;
&lt;pre class=&quot;text-red-800 font-bold mt-4 p-2&quot;&gt;
java.lang.AssertionError: 
Expected size: 3 but was: 2 in:
[Card {suit=CLUBS, rank=A}, Card {suit=CLUBS, rank=5}]
&lt;/pre&gt;
&lt;p&gt;Success! Now it’s failing for the &lt;em&gt;correct&lt;/em&gt; reason. It’s still failing, but at this point of the TDD process, we &lt;em&gt;want&lt;/em&gt; it to fail&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/#fn4&quot; id=&quot;fnref4&quot;&gt;[4]&lt;/a&gt;&lt;/sup&gt;. And, just as important, we want it to fail due to the missing behavior, and not some other reason.&lt;/p&gt;
&lt;h2 id=&quot;prediction-prepares-us-for-surprises&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/#prediction-prepares-us-for-surprises&quot;&gt;Prediction Prepares Us for Surprises&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Over the years, I’ve found this extra prediction step invaluable in fighting the tendency to make assumptions&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/#fn5&quot; id=&quot;fnref5&quot;&gt;[5]&lt;/a&gt;&lt;/sup&gt;. By stating our prediction before we run the test, we are better prepared to notice any slight difference. I often state the prediction &lt;em&gt;out loud&lt;/em&gt;, because it’s easy to lie to ourselves by thinking “oh yeah, that’s what I thought would happen” when we predict only in our heads.&lt;/p&gt;
&lt;p&gt;Assumptions lead us astray so easily, and are frustrating because we’re trying to solve what we &lt;em&gt;think&lt;/em&gt; is the problem instead of the &lt;em&gt;actual&lt;/em&gt; problem. The prediction step won’t prevent all wrong assumptions, but it eliminates enough of them to make it well worth the effort.&lt;/p&gt;
&lt;h2 id=&quot;next-up&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/#next-up&quot;&gt;Next Up&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the &lt;a href=&quot;https://ted.dev/articles/2022/05/09/implementing-the-feature/&quot;&gt;next part&lt;/a&gt;, we can finally write some production code! Stay tuned. If you have questions or want to discuss PTDD, &lt;a href=&quot;https://ted.dev/discord&quot;&gt;join my free Discord community&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-tdd-intro-series&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/#the-tdd-intro-series&quot;&gt;The TDD Intro Series&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2021/02/27/red-green-or-refactoring-first/&quot;&gt;Red-Green or Refactoring First?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/&quot;&gt;Clarifying the Goal of Behavior Change&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Predicting the Failing Test&lt;/strong&gt; (this article)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2022/05/09/implementing-the-feature/&quot;&gt;Implementing the Feature&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/&quot;&gt;Tightening Our Assertions&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;In the real world, players don’t take cards, they signal the dealer that they want another card. This is called “hit” in the language of Blackjack. Object-oriented programming doesn’t always mean simulating the real world as-is. &lt;a href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;You might wonder where the &lt;code&gt;Deck&lt;/code&gt; is. In this example, the &lt;code&gt;Game&lt;/code&gt; already has a reference to a &lt;code&gt;Deck&lt;/code&gt;. &lt;a href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;If you want to see me make more mistakes, just watch me &lt;a href=&quot;https://jitterted.stream/&quot;&gt;live code on Twitch&lt;/a&gt;. &lt;a href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn4&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;And so even though the test is failing, it’s actually a &lt;em&gt;success&lt;/em&gt;. This is why &lt;a href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/#predict-how-the-test-fails&quot;&gt;the diagram&lt;/a&gt; shows this step in green and not red! &lt;a href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/#fnref4&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn5&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;There’s also research to back this up. See this study: &lt;em&gt;&lt;a href=&quot;https://link.springer.com/article/10.3758/s13423-021-01904-1&quot;&gt;Predicting as a learning strategy&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/#fnref5&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Faster Feedback Using In-Memory Repositories</title>
    <link href="https://ted.dev/articles/2021/11/03/faster-feedback-using-in-memory-repositories/"/>
    <updated>2021-11-03T10:00:00Z</updated>
    <id>https://ted.dev/articles/2021/11/03/faster-feedback-using-in-memory-repositories/</id>
    <content xml:lang="en" type="html">&lt;p&gt;One of my &lt;a href=&quot;https://jitterted.stream/&quot;&gt;Twitch&lt;/a&gt; viewers was confused about the “Fake” and “In-Memory” Repositories I use, and wanted to know more about them. These are implementations of the &lt;span class=&quot;smcap&quot;&gt;Repository&lt;/span&gt; persistence pattern (from Domain-Driven Design), where we define an interface with methods to store and retrieve objects&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/11/03/faster-feedback-using-in-memory-repositories/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;, but don’t specify &lt;em&gt;how&lt;/em&gt; they’ll be stored. Here’s an example from my &lt;a href=&quot;https://github.com/jitterted/mobreg&quot;&gt;Ensemble registration system&lt;/a&gt; (aka MobReg):&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;
&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MemberRepository&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;token class-name&quot;&gt;Member&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Member&lt;/span&gt; member&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token class-name&quot;&gt;Optional&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Member&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findByGithubUsername&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt; githubUsername&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token class-name&quot;&gt;Optional&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Member&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;MemberId&lt;/span&gt; memberId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Member&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;findAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In-Memory repositories store objects in memory, instead of writing them to a database. They’re not suitable for production, but they are important for developing and testing your applications. If they’re used exclusively for unit testing, they’re called &lt;span class=&quot;smcap&quot;&gt;Fakes&lt;/span&gt;.&lt;/p&gt;
&lt;h2 id=&quot;faking-it-for-testing&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/11/03/faster-feedback-using-in-memory-repositories/#faking-it-for-testing&quot;&gt;Faking It for Testing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;smcap&quot;&gt;Fakes&lt;/span&gt; are a type of &lt;a href=&quot;https://martinfowler.com/articles/mocksArentStubs.html#TheDifferenceBetweenMocksAndStubs&quot;&gt;Test Double&lt;/a&gt; used exclusively for tests that need to read and write to another object, like our Repository. We can isolate the code under test from the slowness and complexity of a real database repository by having the Fake store objects in memory.&lt;/p&gt;
&lt;p&gt;I may write the Fake to only store a single object if that’s all the test needs (see &lt;a href=&quot;https://github.com/tedyoung/kid-bank/blob/e2f0e5a758f8ecbc34683e3714c9654321e2ee6d/src/test/java/com/learnwithted/kidbank/domain/FakeUserProfileRepository.java&quot;&gt;this example&lt;/a&gt; from my Kid Money Manager project). Otherwise, I’ll use a &lt;code&gt;Map&lt;/code&gt; implementation to store multiple objects, as in &lt;a href=&quot;https://github.com/jitterted/mobreg/blob/27874d2a9cb631b00cb86eb92ff88bee11d29f65/src/main/java/com/jitterted/mobreg/application/port/InMemoryMemberRepository.java#L12&quot;&gt;this example&lt;/a&gt;. Since a Fake mimics the real thing, there’s no need to alter any tests (or code) when we switch to the real thing for production. However, there may be subtle differences between our Fake and a database implementation (often around transactions), so I’ll write (only a few) tests to ensure the code works with both.&lt;/p&gt;
&lt;p&gt;I’ll go deeper into developing database Repositories using Fakes in a future article.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/11/03/faster-feedback-using-in-memory-repositories/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2 id=&quot;fast-feedback&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/11/03/faster-feedback-using-in-memory-repositories/#fast-feedback&quot;&gt;Fast Feedback&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The In-Memory Repository is intended to substitute for the database Repository at runtime, so the application can be used in a realistic way. I use an In-Memory Repository under two conditions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;When the application domain is changing a lot, &lt;em&gt;and&lt;/em&gt;,&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I’m not ready to commit to the database schema I need for production.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I can get quick feedback on changes to the Domain objects without spending the time to constantly update the database Repository code.&lt;/p&gt;
&lt;p&gt;At a minimum, the in-memory implementation needs a way to find objects by their ID. Using a &lt;code&gt;ConcurrentHashMap&lt;/code&gt; makes this easy and protects against potential race conditions. If the Repository interface has other “finder” methods, e.g., &lt;code&gt;findByFirstName()&lt;/code&gt;, I will manually write those (as in &lt;a href=&quot;https://github.com/jitterted/mobreg/blob/27874d2a9cb631b00cb86eb92ff88bee11d29f65/src/main/java/com/jitterted/mobreg/application/port/InMemoryMemberRepository.java#L28-L31&quot;&gt;this example&lt;/a&gt;). If I’m concerned the “finder” methods are complicated&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/11/03/faster-feedback-using-in-memory-repositories/#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt; and might not work correctly, I’ll write them via test-driven development (TDD).&lt;/p&gt;
&lt;p&gt;Once I’m happy with the way the application works, I can switch to writing the database version. I’ll create migration scripts for the database and test them, usually using &lt;a href=&quot;https://www.testcontainers.org/&quot;&gt;Test Containers&lt;/a&gt;. Finally, I’ll change the configuration to use these “real” Repository implementations, and manually check the application for any issues. I rarely find any at this point, so I then push to production. I’ve had zero bugs in production following this process, as part of my overall test-driven development process.&lt;/p&gt;
&lt;h2 id=&quot;should-they-stay%2C-or-go%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/11/03/faster-feedback-using-in-memory-repositories/#should-they-stay%2C-or-go%3F&quot;&gt;Should They Stay, or Go?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While developing &lt;a href=&quot;https://github.com/jitterted/mobreg&quot;&gt;MobReg&lt;/a&gt;, I found I switched to in-memory repositories so often that I created a specific &lt;a href=&quot;https://github.com/jitterted/mobreg/blob/c04de854f51f0dea72a5411f1d4198ffbd59deaf/src/main/java/com/jitterted/mobreg/MobRegApplication.java?_pjax=%23js-repo-pjax-container%2C%20div%5Bitemtype%3D%22http%3A%2F%2Fschema.org%2FSoftwareSourceCode%22%5D%20main%2C%20%5Bdata-pjax-container%5D#L33&quot;&gt;configuration option&lt;/a&gt; to make it easier. Eventually, I’ll remove the in-memory versions once the object structure becomes stable (though that may not happen for a while!). For now, the quick feedback cycles are worth the minimal overhead of maintaining them.&lt;/p&gt;
&lt;p&gt;If you want to watch me work on MobReg, or ask questions, join &lt;a href=&quot;https://ted.dev/discord&quot;&gt;my Discord community&lt;/a&gt;.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Technically &lt;span class=&quot;smcap&quot;&gt;Repositories&lt;/span&gt; store and retrieve &lt;span class=&quot;smcap&quot;&gt;Aggregates&lt;/span&gt;, but that’s a whole separate article. Or three. &lt;a href=&quot;https://ted.dev/articles/2021/11/03/faster-feedback-using-in-memory-repositories/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Want to see this article sooner? Let me know on &lt;a href=&quot;https://twitter.com/JitterTed&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://ted.dev/discord&quot;&gt;Discord&lt;/a&gt;. &lt;a href=&quot;https://ted.dev/articles/2021/11/03/faster-feedback-using-in-memory-repositories/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Be careful, if you find yourself implementing complicated Fake Repositories, you might be doing too much, or you may need to limit testing that aspect of the Repository to a real database. &lt;a href=&quot;https://ted.dev/articles/2021/11/03/faster-feedback-using-in-memory-repositories/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Refactoring Tests</title>
    <link href="https://ted.dev/articles/2021/10/31/refactoring-tests/"/>
    <updated>2021-10-31T10:00:00Z</updated>
    <id>https://ted.dev/articles/2021/10/31/refactoring-tests/</id>
    <content xml:lang="en" type="html">&lt;p&gt;As you may know, I code live on &lt;a href=&quot;https://jitterted.stream/&quot;&gt;Twitch&lt;/a&gt; whenever I can. I generally work on real-world projects, such as my &lt;em&gt;Ensemble Programming Registration System&lt;/em&gt; (aka &lt;a href=&quot;https://github.com/jitterted/mobreg&quot;&gt;MobReg&lt;/a&gt;). I do this for many reasons, one of which is to show folks what it looks like to do test-driven development on a small, but real-world codebase (mistakes and all). I also enjoy chatting with my viewers, and getting feedback and suggestions while I’m coding.&lt;/p&gt;
&lt;p&gt;I recently took the time to refactor some test code, as the setup sections of tests were starting to get verbose and awkward. This video is an excerpt from my stream, where I create a test data builder for the &lt;code&gt;Member&lt;/code&gt; object&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/10/31/refactoring-tests/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;. While the video is unedited, I hope you find it useful. If you’d like to see more of these excerpts, let me know on &lt;a href=&quot;https://twitter.com/JitterTed&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://ted.dev/discord&quot;&gt;Discord&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://youtu.be/qTJzOlVebdw&quot;&gt;youtu.be/qTJzOlVebdw&lt;/a&gt;&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I plan to write about &lt;span class=&quot;smcap&quot;&gt;Test Data Builders&lt;/span&gt; in more detail. If you want to see it sooner, let me know on &lt;a href=&quot;https://twitter.com/JitterTed&quot;&gt;Twitter&lt;/a&gt; or &lt;a href=&quot;https://ted.dev/discord&quot;&gt;Discord&lt;/a&gt;. &lt;a href=&quot;https://ted.dev/articles/2021/10/31/refactoring-tests/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Naming Conventions for DTOs</title>
    <link href="https://ted.dev/articles/2021/10/30/naming-conventions-for-dtos/"/>
    <updated>2021-10-30T10:00:00Z</updated>
    <id>https://ted.dev/articles/2021/10/30/naming-conventions-for-dtos/</id>
    <content xml:lang="en" type="html">&lt;blockquote&gt;
&lt;p&gt;This article comes from a question asked in my Discord.
If you want to discuss topics like this, come and &lt;a href=&quot;https://ted.dev/discord&quot;&gt;join us&lt;/a&gt;, it’s free!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;naming-conventions&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/10/30/naming-conventions-for-dtos/#naming-conventions&quot;&gt;Naming Conventions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Today, someone asked me about naming conventions for Data Transfer Objects (&lt;span class=&quot;smcap&quot;&gt;DTO&lt;/span&gt;s). I primarily use &lt;span class=&quot;smcap&quot;&gt;DTO&lt;/span&gt;s to carry information from my “domain” to and from the outside world. &lt;span class=&quot;smcap&quot;&gt;DTO&lt;/span&gt;s are a core part of the Hexagonal Architecture that I use for organizing code. (You can watch my video on the topic on YouTube&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/10/30/naming-conventions-for-dtos/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;.)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://youtu.be/ujb_O6myknY&quot;&gt;https://youtu.be/ujb_O6myknY&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Somewhere there needs to be code that transforms (or translates, or “maps”) the internal domain objects into strings and numbers that can be sent to (or received from) the outside world. Some folks put that code in separate mapper classes, but I prefer to put it directly in the &lt;span class=&quot;smcap&quot;&gt;DTO&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;I usually use a static &lt;code&gt;from()&lt;/code&gt; method that converts a &lt;span class=&quot;smcap&quot;&gt;Domain&lt;/span&gt; object to the &lt;span class=&quot;smcap&quot;&gt;DTO&lt;/span&gt;, like this:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UserProfileDto&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;UserProfile&lt;/span&gt; userProfile&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UserProfileDto&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;userProfile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                              userProfile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                              userProfile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;phoneNumber&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;asRaw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                              userProfile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                              userProfile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;role&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The downside to using &lt;code&gt;from()&lt;/code&gt; is that it can look odd when using it in a stream-map context, like this:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;token generics&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;UserProfileDto&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; dtos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; userProfiles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                                        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;UserProfileDto&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
                                        &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Collectors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toList&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;but I’ve gotten used to it. The alternative is to use &lt;code&gt;toDto()&lt;/code&gt;, but I don’t think that’s clearer. I no longer name my &lt;span class=&quot;smcap&quot;&gt;DTO&lt;/span&gt; classes with a &lt;code&gt;Dto&lt;/code&gt; suffix, unless I can’t think of anything more descriptive. These days I create objects with names like &lt;code&gt;MemberView&lt;/code&gt; for something displayed in a browser (see below), or &lt;code&gt;CreateMemberRequest&lt;/code&gt; for an incoming request&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/10/30/naming-conventions-for-dtos/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; to create a member.&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MemberView&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;Member&lt;/span&gt; member&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MemberView&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;member&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                          member&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                          member&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;githubUsername&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                          &lt;span class=&quot;token class-name&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;,&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; member&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;roles&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;persistence-with-dbos&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/10/30/naming-conventions-for-dtos/#persistence-with-dbos&quot;&gt;Persistence with &lt;span class=&quot;smcap&quot;&gt;DBO&lt;/span&gt;s&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When I need to transform a &lt;span class=&quot;smcap&quot;&gt;DTO&lt;/span&gt; back into a domain object, I’ll create an &lt;code&gt;as&lt;em&gt;DomainObject&lt;/em&gt;()&lt;/code&gt; instance method, like this:&lt;/p&gt;
&lt;pre class=&quot;language-java&quot;&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;UserProfile&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;asUserProfile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;UserProfile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;id&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                           name&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                           &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;PhoneNumber&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;phone&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                           email&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                           &lt;span class=&quot;token class-name&quot;&gt;Role&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;valueOf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;role&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Often the &lt;span class=&quot;smcap&quot;&gt;DTO&lt;/span&gt; comes from a database or other persistence mechanism. I mostly use ORMs like Spring Data JPA or JDBC, where my naming convention for objects stored in the database is now &lt;code&gt;Dbo&lt;/code&gt; (DataBase Object) as the suffix (e.g., &lt;code&gt;UserProfileDbo&lt;/code&gt; or &lt;a href=&quot;https://github.com/jitterted/mobreg/blob/4364ff9f008ed5851b70ec5c8d204d3bf091f09a/src/main/java/com/jitterted/mobreg/adapter/out/jdbc/MemberDbo.java#L12&quot;&gt;&lt;code&gt;MemberDbo&lt;/code&gt;&lt;/a&gt;). This makes it clear that the &lt;span class=&quot;smcap&quot;&gt;DBO&lt;/span&gt;s match the structure of the database and are not Domain Objects. It also helps me differentiate them from other &lt;span class=&quot;smcap&quot;&gt;DTO&lt;/span&gt;s.&lt;/p&gt;
&lt;h2 id=&quot;setters-%26-getters&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/10/30/naming-conventions-for-dtos/#setters-%26-getters&quot;&gt;Setters &amp;amp; Getters&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The rest of the &lt;span class=&quot;smcap&quot;&gt;DTO&lt;/span&gt; consists of getters and setters to allow libraries (such as Spring and Jackson) to access the &lt;span class=&quot;smcap&quot;&gt;DTO&lt;/span&gt;’s properties programmatically&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/10/30/naming-conventions-for-dtos/#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;. This is, in fact, a standard that goes way back to the JavaBean specification defined in 1997. Having getters and setters in domain code, however, is a no-no, which I’ll talk about in future articles.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;This video is a bit dated, but my course on &lt;a href=&quot;https://r2ha.com/&quot;&gt;Refactoring to Hexagonal Architecture&lt;/a&gt; goes into detail about this. &lt;a href=&quot;https://ted.dev/articles/2021/10/30/naming-conventions-for-dtos/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;This kind of &lt;span class=&quot;smcap&quot;&gt;DTO&lt;/span&gt; is often translated from a web form or JSON automatically by a framework, such as Spring. &lt;a href=&quot;https://ted.dev/articles/2021/10/30/naming-conventions-for-dtos/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Records can be used instead, with some exceptions, as of Java 14. See &lt;a href=&quot;https://github.com/jitterted/mobreg/blob/4364ff9f008ed5851b70ec5c8d204d3bf091f09a/src/main/java/com/jitterted/mobreg/adapter/in/web/admin/MemberView.java#L5&quot;&gt;MemberView&lt;/a&gt; for an example. &lt;a href=&quot;https://ted.dev/articles/2021/10/30/naming-conventions-for-dtos/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Favorite IntelliJ IDEA Plugins</title>
    <link href="https://ted.dev/articles/2021/04/21/favorite-intellij-idea-plugins/"/>
    <updated>2021-04-21T10:00:00Z</updated>
    <id>https://ted.dev/articles/2021/04/21/favorite-intellij-idea-plugins/</id>
    <content xml:lang="en" type="html">&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;2023-02-21&lt;/em&gt;: Added the &lt;a href=&quot;https://ted.dev/articles/2021/04/21/favorite-intellij-idea-plugins/#custom-postfix-templates&quot;&gt;Custom Postfix Templates&lt;/a&gt; plugin.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;2023-02-02&lt;/em&gt;: This article was originally published on &lt;a href=&quot;http://dev.to/&quot;&gt;Dev.to&lt;/a&gt;, but it’s time to bring it here, as well as bring it up to date.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As a software developer, Java instructor, and experienced &lt;a href=&quot;https://www.jetbrains.com/idea/&quot;&gt;IntelliJ IDEA&lt;/a&gt; user (some might say fanatic) for over 20 years, I’m often asked about the plugins that I use. To be honest, I don’t use a lot of plugins, I find myself mostly focused on improving the quality and testability of code by using IntelliJ IDEA’s powerful automated refactorings, along with its Live Template and Postfix features. However, there are some very useful plugins that are “standard equipment” for me when I install it on a new machine. Note that I use many of the built-in plugins from JetBrains, which I’m not including in this list.&lt;/p&gt;
&lt;h2 id=&quot;tab-shifter&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/04/21/favorite-intellij-idea-plugins/#tab-shifter&quot;&gt;Tab Shifter&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Rating:&lt;/strong&gt; ⭐️⭐️⭐️⭐️⭐️ (5/5 Stars) Great if you like splitting your screen in various ways.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Plugin Page:&lt;/strong&gt; &lt;a href=&quot;https://plugins.jetbrains.com/plugin/7475-tab-shifter&quot;&gt;https://plugins.jetbrains.com/plugin/7475-tab-shifter&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/split-screen@2x.png&quot; alt=&quot;Screenshot of IntelliJ IDEA with the screen split vertically, showing two editor panes side-by-side.&quot; width=&quot;100%&quot;&gt;&lt;figcaption&gt;Side-by-side Editor Panes&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I do a lot of teaching and live coding, where we’re doing Test-Driven Development (TDD). This means we’re constantly moving back and forth between the tests and the code. Splitting the editor to show both test and production code makes it easier for those viewing my screen to retain the full context of what we’re doing. If I’m coding by myself, I can switch tabs quickly (using CMD+E/CTRL+E or CTRL+TAB) when I need to. But when coding with others (pairing, ensembling, etc.), it’s great to see both all the time.&lt;/p&gt;
&lt;p&gt;IntelliJ IDEA has splitting built-in, but it doesn’t have keyboard shortcuts assigned to the actions. Tab Switcher adds sensible shortcuts that are easy to memorize: e.g., &lt;code&gt;CTRL+OPT+]&lt;/code&gt; to move the current file to the right side and &lt;code&gt;CTRL+OPT+[&lt;/code&gt; to move it to the left side.&lt;/p&gt;
&lt;h2 id=&quot;presentation-assistant&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/04/21/favorite-intellij-idea-plugins/#presentation-assistant&quot;&gt;Presentation Assistant&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Rating:&lt;/strong&gt; ⭐️⭐️⭐️⭐️⭐️ (5/5 Stars) Required if you share your screen with others during pair programming, ensembling, teaching, etc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Plugin Page:&lt;/strong&gt; &lt;a href=&quot;https://plugins.jetbrains.com/plugin/7345-presentation-assistant&quot;&gt;https://plugins.jetbrains.com/plugin/7345-presentation-assistant&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/presentation-assistant.png&quot; alt=&quot;Screenshot of the Presentation Assistant showing the Context Actions shortcut at the bottom of the screen.&quot; width=&quot;100%&quot;&gt;&lt;figcaption&gt;Presentation Assistant plugin in action&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Pretty much what it says in its description: “shows name and Win/Mac shortcuts of any action you invoke”. As an instructor and live coder, I always have this installed and activated. I like how it shows both Mac and Windows &amp;amp; Linux shortcuts so those who are watching can learn the shortcuts for their platform. It’s also helpful when I’m writing how to use the shortcuts since I don’t have to search for the shortcuts for the other platforms (I use a Mac), I just hit the keys and &lt;strong&gt;Presentation Assistant&lt;/strong&gt; shows me the keys for Windows/Linux.&lt;/p&gt;
&lt;h2 id=&quot;custom-postfix-templates&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/04/21/favorite-intellij-idea-plugins/#custom-postfix-templates&quot;&gt;Custom Postfix Templates&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Rating:&lt;/strong&gt; ⭐️⭐️⭐️⭐️⭐️ (5/5 Stars) JetBrains make this plugin a part of IntelliJ IDEA itself. If you like Postfix, you want this plugin.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Plugin Page:&lt;/strong&gt; &lt;a href=&quot;https://plugins.jetbrains.com/plugin/9862-custom-postfix-templates&quot;&gt;https://plugins.jetbrains.com/plugin/9862-custom-postfix-templates&lt;/a&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/custom-postfix-templates.png&quot; alt=&quot;Screenshot of the Custom Postfix Templates configuration page.&quot; width=&quot;100%&quot;&gt;&lt;figcaption&gt;Custom Postfix Templates Preferences&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I had come across this plugin a long time ago and was recently reminded of it when I was trying to create a Postfix template that combined &lt;code&gt;.new&lt;/code&gt; and &lt;code&gt;.var&lt;/code&gt;, i.e., one template that would take a class like &lt;code&gt;Game&lt;/code&gt; and turn it into &lt;code&gt;Game game = new Game();&lt;/code&gt;. I do this so often in tests that a shortcut would be very useful, but the built-in Postfix functionality doesn’t allow for this. I briefly looked at writing my own Postfix plugin, and instead rediscovered this plugin—problem solved!&lt;/p&gt;
&lt;p&gt;The plugin not only makes creating custom Postfix templates easy, but also comes with hundreds of templates for all sorts of situations, including popular libraries. It also makes it easy to share templates with others.&lt;/p&gt;
&lt;h2 id=&quot;plantuml&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/04/21/favorite-intellij-idea-plugins/#plantuml&quot;&gt;PlantUML&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Rating:&lt;/strong&gt; ⭐️⭐️⭐️⭐️⭐️ (5/5 Stars) If you know PlantUML syntax, this is a must-have.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Plugin Page:&lt;/strong&gt; &lt;a href=&quot;https://plugins.jetbrains.com/plugin/7017-plantuml-integration&quot;&gt;https://plugins.jetbrains.com/plugin/7017-plantuml-integration&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I love drawing diagrams, but I hate using visual drawing tools, because I spend so much time fiddling with the little things. I’ve been using &lt;strong&gt;&lt;a href=&quot;https://plantuml.com/&quot;&gt;PlantUML&lt;/a&gt;&lt;/strong&gt; for years to draw sequence, class, and state machine diagrams by describing it in a text file. Having it as a plugin in IntelliJ IDEA makes it that much more valuable, especially with the quick view updates as I make changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Be sure to install the correct plugin, there are similarly named ones that aren’t as good.&lt;/p&gt;
&lt;h2 id=&quot;git-toolbox&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/04/21/favorite-intellij-idea-plugins/#git-toolbox&quot;&gt;Git ToolBox&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Rating:&lt;/strong&gt; ⭐️⭐️⭐️⭐️⭐️ (5/5 Stars) If you use Git in a team environment, install this plugin.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Plugin Page:&lt;/strong&gt; &lt;a href=&quot;https://plugins.jetbrains.com/plugin/7499-gittoolbox&quot;&gt;https://plugins.jetbrains.com/plugin/7499-gittoolbox&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For better or worse (I think worse, but that’s a separate rant), Git is the de facto standard for version control. IntelliJ IDEA’s support for Git is great, but the plugin &lt;strong&gt;GitToolBox&lt;/strong&gt; makes it even better. I rarely find myself using Git from the command line anymore, which I’m very happy about.&lt;/p&gt;
&lt;h2 id=&quot;sonarlint&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/04/21/favorite-intellij-idea-plugins/#sonarlint&quot;&gt;SonarLint&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Rating:&lt;/strong&gt; ⭐️⭐️⭐️ (3/5 Stars) Worth trying out, and can be especially useful in a team environment if customized.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Plugin Page:&lt;/strong&gt; &lt;a href=&quot;https://plugins.jetbrains.com/plugin/7973-sonarlint&quot;&gt;https://plugins.jetbrains.com/plugin/7973-sonarlint&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I try to like &lt;strong&gt;&lt;a href=&quot;https://www.sonarlint.org/&quot;&gt;SonarLint&lt;/a&gt;&lt;/strong&gt;. It’s not that it’s not a powerful tool (it is), it’s just that I find myself constantly telling it to stop bugging me about things that I turn it off when teaching, and then forget to turn it back on when I’m just coding. Perhaps some more fine-tuning would get it to the right level of nudging, but I’m not there yet. However, it has saved me from some silly mistakes, so it’s worth installing and trying out.&lt;/p&gt;
&lt;h2 id=&quot;floobits&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/04/21/favorite-intellij-idea-plugins/#floobits&quot;&gt;Floobits&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;2022-02-01&lt;/em&gt; I previously recommended this tool, but it hasn’t been updated in years, so would recommend trying &lt;a href=&quot;https://www.codetogether.com/&quot;&gt;CodeTogether&lt;/a&gt; instead.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Rating:&lt;/strong&gt; ⭐️⭐️⭐️ (2/5 Stars) If you need to share the ability to share the editor, it’s worth trying, but can’t really recommend as it unreliable and hasn’t been updated in years.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Plugin Page:&lt;/strong&gt; &lt;a href=&quot;https://plugins.jetbrains.com/plugin/7389-floobits&quot;&gt;https://plugins.jetbrains.com/plugin/7389-floobits&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The holy grail of synchronous editing of a project by multiple people has not quite been solved, but of the tools I’ve tried out (Floobits, CodeTogether, Code With Me, and GitDuck), &lt;strong&gt;&lt;a href=&quot;https://floobits.com/&quot;&gt;Floobits&lt;/a&gt;&lt;/strong&gt; has come closest to what I want: the ability to use the full power of IntelliJ IDEA, and let the other people use whatever tool they want. It’s not perfect and sometimes things get out of sync or just don’t sync in the first place, but when it works, it’s great. In the Mob Programming groups that I lead, though, I have shifted to using &lt;a href=&quot;https://mob.sh/&quot;&gt;mob.sh&lt;/a&gt; as it’s much more reliable.&lt;/p&gt;
&lt;h2 id=&quot;what-about-you%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/04/21/favorite-intellij-idea-plugins/#what-about-you%3F&quot;&gt;What About You?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What plugins do you find &lt;strong&gt;indispensable?&lt;/strong&gt; Let me know on &lt;a href=&quot;https://ted.dev/discord&quot;&gt;my Discord&lt;/a&gt;, on Twitter (as &lt;a href=&quot;https://twitter.com/jitterted&quot;&gt;@JitterTed&lt;/a&gt;), or on Mastodon (as &lt;a href=&quot;https://sfba.social/@jitterted&quot;&gt;@jitterted@sfba.social&lt;/a&gt;).&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Clarifying the Goal of Behavior Change</title>
    <link href="https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/"/>
    <updated>2021-03-05T10:00:00Z</updated>
    <id>https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/</id>
    <content xml:lang="en" type="html">&lt;h2 id=&quot;change-behavior-with-predictive-tdd&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/#change-behavior-with-predictive-tdd&quot;&gt;Change Behavior with Predictive TDD&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In my &lt;a href=&quot;https://ted.dev/articles/2021/02/27/red-green-or-refactoring-first&quot;&gt;last post&lt;/a&gt;, I talked about the two main activities of Test-Driven Development&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Change Behavior:&lt;/strong&gt; adding capabilities and features to a system, or, perhaps, fixing bugs. The goal is improving the lives of the folks that the system serves.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Increase Changeability:&lt;/strong&gt; refactoring, or re-organizing the code to make it easier for us, the developers, to understand the code and make it easier to Change Behavior (now or later).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We’ll first look at the &lt;strong&gt;&lt;em&gt;Change Behavior&lt;/em&gt;&lt;/strong&gt; part of the cycle, often represented by the “Red-Green” parts of the TDD diagram:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/tdd-cycle-change-behavior.png&quot; alt=&quot;TDD Cycle: circles with the words Red (colored red), Green (colored green), and Refactor (colored pale light blue) written inside and arrows pointing from one to the next in a clockwise order. Red and Green circles are highlighted and have text to the right: &#39;Change Behavior&#39;. Refactor circle has text above it: &#39;Increase Changeability&#39;.&quot; width=&quot;75%&quot;&gt;&lt;figcaption&gt;TDD Cycle: Focus on Behavior Change&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;When I do (and teach&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;) the Red-Green part of the TDD cycle, the steps I &lt;em&gt;actually&lt;/em&gt; perform are more than two:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/full-detailed-tdd-cycle-prediction.png&quot; alt=&quot;Flowchart of steps in the process&quot; width=&quot;100%&quot;&gt;&lt;figcaption&gt;More Than Just Red-Green&lt;/figcaption&gt;&lt;/figure&gt;
&lt;h2 id=&quot;clarifying-your-goal&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/#clarifying-your-goal&quot;&gt;Clarifying Your Goal&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Let’s start with the first two steps, which seem simple enough…&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/detailed-tdd-cycle-1-what-and-how.png&quot; alt=&quot;First two steps of my TDD process: What Should It Do? and How Will You Know It Did It?&quot; width=&quot;75%&quot;&gt;&lt;figcaption&gt;Requires Thinking First&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Before I did TDD on a regular basis, it always amazed me how much code I could write without being clear about the behavior I was adding. This became really obvious after I resumed my training work years ago. It was common for students to get stuck, so I’d ask them “what are you trying to do here?” Often, they couldn’t explain it, or did so in a way that was vague. After some back and forth, once they were able to verbalize the goal clearly, all of a sudden they knew what was wrong and how to proceed&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h3 id=&quot;thinking-first-helps&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/#thinking-first-helps&quot;&gt;Thinking First Helps&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Therefore, being clear and precise—in a way that a unit test requires—helps you make sure you know exactly what you need to do. However, that’s not enough for a unit test. You have to be able to &lt;em&gt;observe&lt;/em&gt; that the system does what you want it to do, i.e., you have to answer the second question: &lt;strong&gt;How Will You Know It Did It&lt;/strong&gt;?&lt;/p&gt;
&lt;p&gt;For example, if you’re thinking about the micro-feature (or “story” if you prefer):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The player gets a new card when they draw one from the deck&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;How will you know this worked? What, exactly, is the expected (and observable) outcome? Can you access that observation by directly asking an object for information, or do you have to dig into 3 separate objects for details? We’ll need to clarify the assumptions in order to really know.&lt;/p&gt;
&lt;p&gt;Let’s start by rephrasing this story in Given-When-Then format&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/#fn4&quot; id=&quot;fnref4&quot;&gt;[4]&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Given a &lt;span class=&quot;smcap&quot;&gt;PLAYER&lt;/span&gt; with a &lt;span class=&quot;smcap&quot;&gt;HAND&lt;/span&gt; containing 2 &lt;span class=&quot;smcap&quot;&gt;CARD&lt;/span&gt;s,&lt;/p&gt;
&lt;p&gt;When the &lt;span class=&quot;smcap&quot;&gt;PLAYER DRAW&lt;/span&gt;s a &lt;span class=&quot;smcap&quot;&gt;CARD&lt;/span&gt; from the &lt;span class=&quot;smcap&quot;&gt;DECK&lt;/span&gt;,&lt;/p&gt;
&lt;p&gt;Then the &lt;span class=&quot;smcap&quot;&gt;HAND&lt;/span&gt; should have 3 &lt;span class=&quot;smcap&quot;&gt;CARD&lt;/span&gt;s.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Note the use of our &lt;span class=&quot;smcap&quot;&gt;DOMAIN&lt;/span&gt; terminology: player, hand, card, draw, and deck. Talking, thinking, writing, and discussing the functionality in those terms will not only help us figure out the desired behavior, but make sure we’re using the language correctly with our domain experts.&lt;/p&gt;
&lt;p&gt;Now we have precisely defined the behavior we want to add—player draws a card—as well as how we can observe that it happened, by checking that the size of the hand is 3 cards, when it started with 2. (How do we know we started with 2? Sounds like a separate test!)&lt;/p&gt;
&lt;p&gt;That’s a lot of work and thinking, but it’s exactly (and only) what we need to get to the next step, which is writing the actual unit test. We’ll look at that in &lt;a href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/&quot;&gt;the next part of this series&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-tdd-intro-series&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/#the-tdd-intro-series&quot;&gt;The TDD Intro Series&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2021/02/27/red-green-or-refactoring-first/&quot;&gt;Red-Green or Refactoring First?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clarifying the Goal of Behavior Change&lt;/strong&gt; (this article)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/&quot;&gt;Predicting the Failing Test&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2022/05/09/implementing-the-feature/&quot;&gt;Implementing the Feature&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/&quot;&gt;Tightening Our Assertions&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I’ve had people say that the two main activities of TDD are writing a failing test and then making it pass, but that’s only a part of TDD and misses the other equally important activity: refactoring. &lt;a href=&quot;https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;I use &lt;a href=&quot;https://ted.dev/products/jitterted-tdd-game&quot;&gt;JitterTed’s TDD Game&lt;/a&gt; to help teach this process. &lt;a href=&quot;https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;We often refer to solving problems by talking about them out loud, perhaps to a rubber duck sitting on our monitor, as Rubber Duck Debugging, or sometimes just Rubber Ducking. No human necessary. &lt;a href=&quot;https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn4&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;This way of thinking about the desired behavior comes from &lt;a href=&quot;https://martinfowler.com/bliki/GivenWhenThen.html&quot;&gt;Behavior-Driven Development&lt;/a&gt;, which, as we’ll see in future posts, is very much TDD, working at different boundaries. &lt;a href=&quot;https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/#fnref4&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Red-Green or Refactoring First?</title>
    <link href="https://ted.dev/articles/2021/02/27/red-green-or-refactoring-first/"/>
    <updated>2021-02-27T10:00:00Z</updated>
    <id>https://ted.dev/articles/2021/02/27/red-green-or-refactoring-first/</id>
    <content xml:lang="en" type="html">&lt;p&gt;When it comes to Test-Driven Development, we often see it as a cycle consisting of three parts: &lt;span class=&quot;smcap&quot;&gt;RED&lt;/span&gt;, &lt;span class=&quot;smcap&quot;&gt;GREEN&lt;/span&gt;, and &lt;span class=&quot;smcap&quot;&gt;REFACTOR&lt;/span&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/red-green-refactor-tdd-cycle.png&quot; alt=&quot;Three circles in a triangular formation. A red one at the top labeled &#39;red&#39;, a green one labeled &#39;green&#39; at the lower-right, and a blue one labeled &#39;refactor&#39; at the lower-left. Arrows point from red to green to refactor and back to red.&quot; width=&quot;50%&quot;&gt;&lt;figcaption&gt;Typical Red-Green-Refactor TDD Cycle&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;I think about the process as two high-level activities:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Changing the behavior of the system via coded expectations: this is the &lt;span class=&quot;smcap&quot;&gt;RED-GREEN&lt;/span&gt; part of the cycle. We do this for “them”, i.e., the folks who asked us to solve their problem (or perhaps implement their solution) and make their lives better (we hope).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Preserving the behavior and making the code easier to understand. Can also be adapting it to the next thing we’re about to implement, i.e., the &lt;span class=&quot;smcap&quot;&gt;REFACTOR&lt;/span&gt; part. We do this for us, the humans working with the code, to make our lives better; to increase the changeability of the system&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/02/27/red-green-or-refactoring-first/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;However, we don’t always need to start with a change in behavior (i.e., step 1), sometimes we start with making the code easier to work with via &lt;span class=&quot;smcap&quot;&gt;REFACTOR&lt;/span&gt;, which looks like this:&lt;/p&gt;
&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/refactor-oriented-tdd-cycle.png&quot; alt=&quot;Three circles similar to the previous diagram, this time with the blue one labeled &#39;refactor&#39; at the top, followed by the red one labeled &#39;red&#39; at the lower-right, and the green one labeled &#39;green&#39; at the lower-left.&quot; width=&quot;50%&quot;&gt;&lt;figcaption&gt;Starting the TDD Cycle with Refactoring&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;TDD is a cycle, after all, with a choice of where to begin. Though I treat each time we land in &lt;span class=&quot;smcap&quot;&gt;GREEN&lt;/span&gt; and &lt;span class=&quot;smcap&quot;&gt;REFACTOR&lt;/span&gt; as safe stopping points (where I’ll try to commit to version control). This is related to “Small Steps” and “Ready Points” (&lt;a href=&quot;https://www.geepawhill.org/2021/10/26/mmmss-a-closer-look-at-steps/&quot;&gt;GeePaw Hill&lt;/a&gt;), which I’ll talk more about in a future essay.&lt;/p&gt;
&lt;p&gt;Over the next several articles I’ll dive deeper into these two parts: &lt;strong&gt;Change Behavior&lt;/strong&gt; (the &lt;span class=&quot;smcap&quot;&gt;RED-GREEN&lt;/span&gt; part) and &lt;strong&gt;Increase Changeability&lt;/strong&gt; (the &lt;span class=&quot;smcap&quot;&gt;REFACTOR&lt;/span&gt; part).&lt;/p&gt;
&lt;h2 id=&quot;the-tdd-intro-series&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/02/27/red-green-or-refactoring-first/#the-tdd-intro-series&quot;&gt;The TDD Intro Series&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Red-Green or Refactoring First? (this article)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2021/03/05/clarifying-the-goal-of-behavior-change/&quot;&gt;Clarifying the Goal of Behavior Change&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2021/11/05/predicting-the-failing-test/&quot;&gt;Predicting the Failing Test&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2022/05/09/implementing-the-feature/&quot;&gt;Implementing the Feature&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ted.dev/articles/2022/06/22/tightening-our-assertions/&quot;&gt;Tightening Our Assertions&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;How do you think about the TDD Cycle? Let me know on &lt;a href=&quot;https://twitter.com/JitterTed&quot;&gt;Twitter&lt;/a&gt; or join &lt;a href=&quot;https://ted.dev/discord&quot;&gt;my Discord&lt;/a&gt; to discuss this and other topics!&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Note that this is not the same as &lt;em&gt;premature flexibility&lt;/em&gt; or &lt;em&gt;&lt;a href=&quot;https://xp123.com/articles/speculative-generality/&quot;&gt;speculative generality&lt;/a&gt;&lt;/em&gt;. &lt;a href=&quot;https://ted.dev/articles/2021/02/27/red-green-or-refactoring-first/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Domain vs. Technical</title>
    <link href="https://ted.dev/articles/2021/02/25/domain-vs-technical/"/>
    <updated>2021-02-25T10:00:00Z</updated>
    <id>https://ted.dev/articles/2021/02/25/domain-vs-technical/</id>
    <content xml:lang="en" type="html">&lt;p&gt;I was recently reminded (thanks to Jon Reid &lt;a href=&quot;https://twitter.com/qcoding&quot;&gt;@qcoding&lt;/a&gt;) of a tweet I wrote back in July 2020:&lt;/p&gt;
&lt;div class=&quot;my-4&quot;&gt;
&lt;blockquote class=&quot;twitter-tweet&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;When doing #TDD and writing unit tests, I try to write my expectations in the language of the domain (Ubiquitous Language from DDD) instead of primitives and collections. E.g., &amp;ldquo;dice roll contains four of the same kind&amp;rdquo; and not &amp;ldquo;list has four integers of the same value&amp;rdquo;.&lt;/p&gt;&amp;mdash; Ted M. Young #BlackLivesMatter #HexArch (@jitterted) &lt;a href=&quot;https://twitter.com/jitterted/status/1281295963865268224?ref_src=twsrc%5Etfw&quot;&gt;July 9, 2020&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;
&lt;/div&gt;
&lt;p&gt;At the time, I had just started teaching my new online class&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/02/25/domain-vs-technical/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;, where this came up in a somewhat unexpected way. In the class, we’re working on fixing some &lt;em&gt;Code Smells&lt;/em&gt; in the code of a console-based Blackjack card game. As part of the refactoring process, we extract code that compares the value of two &lt;code&gt;Hand&lt;/code&gt;s—the player’s and the dealer’s—to see if one of them &lt;em&gt;Beats&lt;/em&gt; the other. We do the same for another method that compares the hands to see if they have the same value&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://ted.dev/articles/2021/02/25/domain-vs-technical/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;, called a &lt;em&gt;Push&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;When extracting these methods, the temptation is to name these methods with &lt;span class=&quot;smcap&quot;&gt;TECHNICAL&lt;/span&gt; terminology, i.e., using &lt;code&gt;compareTo()&lt;/code&gt; for the comparison method, and &lt;code&gt;equals()&lt;/code&gt; for the one checking for hands having the same value. However, there are two problems with these names:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;compareTo()&lt;/code&gt; has a specific usage in Java: for sorting, or with data structures that need ordering (such as &lt;code&gt;TreeMap&lt;/code&gt;). Since &lt;code&gt;Hand&lt;/code&gt; instances have no need to be ordered, using &lt;code&gt;compareTo()&lt;/code&gt; would be misleading to readers of the code. Similarly, &lt;code&gt;equals()&lt;/code&gt; has a specific technical meaning, but it would also be incorrect to say that two different &lt;code&gt;Hand&lt;/code&gt; instances are &lt;em&gt;equal&lt;/em&gt; if they happen to have the same total value of their cards.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If we’re defining public methods on a &lt;code&gt;Hand&lt;/code&gt; class (a class concerned with an aspect of the Blackjack domain) that forms its API (what I call its “surface area”), those methods need to “speak” in the language of Blackjack. &lt;code&gt;compareTo()&lt;/code&gt; and &lt;code&gt;equals()&lt;/code&gt; are &lt;span class=&quot;smcap&quot;&gt;TECHNICAL&lt;/span&gt; names, so instead we prefer to use &lt;span class=&quot;smcap&quot;&gt;DOMAIN&lt;/span&gt; terms in the names: &lt;code&gt;beats()&lt;/code&gt; and &lt;code&gt;pushes()&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;benefits&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/02/25/domain-vs-technical/#benefits&quot;&gt;Benefits&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The benefit of using &lt;span class=&quot;smcap&quot;&gt;DOMAIN&lt;/span&gt; terms is that it reinforces that the class implements &lt;em&gt;domain&lt;/em&gt; behavior. It also makes the code easier to understand, even for non-coders. For me, the biggest benefit is that it helps keep the public API of the class at the appropriate level of abstraction. So, my tests are testing &lt;span class=&quot;smcap&quot;&gt;DOMAIN&lt;/span&gt; behavior, not &lt;span class=&quot;smcap&quot;&gt;TECHNICAL&lt;/span&gt; behavior. This allows the code to be more easily refactored, as domain terms are often at a higher level of abstraction than technical terms, and less prone to arbitrary change.&lt;/p&gt;
&lt;h3 id=&quot;example&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/02/25/domain-vs-technical/#example&quot;&gt;Example&lt;/a&gt;&lt;/h3&gt;
&lt;figure&gt;&lt;img src=&quot;https://ted.dev/assets/hand-contains-has-ace-example.png&quot; alt=&quot;Two test code listings, the first one asserting hand.contains(aceCard), the second asserting that hand.hasAce()&quot; width=&quot;83%&quot;&gt;&lt;figcaption&gt;Technical vs. Domain Methods&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Here, the first example uses a &lt;span class=&quot;smcap&quot;&gt;TECHNICAL&lt;/span&gt; method, &lt;code&gt;contains()&lt;/code&gt;, which works, but asking (querying) the &lt;code&gt;Hand&lt;/code&gt; whether it &lt;code&gt;hasAce()&lt;/code&gt; is much clearer. If you do have a &lt;span class=&quot;smcap&quot;&gt;DOMAIN&lt;/span&gt; need to find out if a &lt;code&gt;Hand&lt;/code&gt; has an arbitrary &lt;code&gt;Card&lt;/code&gt;, you might want to look deeper at the domain meaning of such a query.&lt;/p&gt;
&lt;h2 id=&quot;domain-knowledge&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/02/25/domain-vs-technical/#domain-knowledge&quot;&gt;Domain Knowledge&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All this assumes that, as a developer, you are familiar with the domain you’re working in. If it’s a Blackjack game, you should know the terms “busted”, “pushes”, “hit”, “surrender”, etc. If it’s an accounting system, you’ll need to know the meaning of “credit”, “debit”, “journal”, “ledger”, etc. While you can write code without much knowledge of the domain, the more you deeply understand it, and the better you can work with those who define what the system needs to do.&lt;/p&gt;
&lt;h2 id=&quot;what-do-you-think%3F&quot; tabindex=&quot;-1&quot;&gt;&lt;a class=&quot;header-anchor&quot; href=&quot;https://ted.dev/articles/2021/02/25/domain-vs-technical/#what-do-you-think%3F&quot;&gt;What Do You Think?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What domains do you work in? Does your code reflect the domain, or are methods more technical? How does that affect the testability of the code or the “brittleness” of the tests? Let me know on &lt;a href=&quot;https://twitter.com/JitterTed&quot;&gt;Twitter&lt;/a&gt; or join &lt;a href=&quot;https://ted.dev/discord&quot;&gt;my Discord&lt;/a&gt; to discuss this and other topics.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Now called &lt;em&gt;Refactoring to Testable Code&lt;/em&gt;. &lt;a href=&quot;https://mycmt.dev/&quot;&gt;Subscribe to my newsletter&lt;/a&gt;, so you don’t miss future classes. &lt;a href=&quot;https://ted.dev/articles/2021/02/25/domain-vs-technical/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;In Blackjack, each hand has a numeric value based on the cards it has. For details, see &lt;a href=&quot;https://github.com/tedyoung/mycmt1-blackjack-baseline#rules-of-blackjack&quot;&gt;the rules&lt;/a&gt; from my Blackjack game code that I use in my course. &lt;a href=&quot;https://ted.dev/articles/2021/02/25/domain-vs-technical/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Human Learning (Video)</title>
    <link href="https://ted.dev/articles/2018/10/30/human-learning-video/"/>
    <updated>2018-10-30T10:00:00Z</updated>
    <id>https://ted.dev/articles/2018/10/30/human-learning-video/</id>
    <content xml:lang="en" type="html">&lt;p&gt;Back in October 2018, I gave my 3rd iteration of my talk: “Human Learning: How We Learn &amp;amp; Why It Matters” at the Silicon Valley Code Camp.
The video recording of the talk is on YouTube here:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://youtu.be/SdvmMPcXK0Q&quot;&gt;https://youtu.be/SdvmMPcXK0Q&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Slides are available &lt;a href=&quot;https://www.dropbox.com/s/4r4uolqmyx15jj3/Human%20Learning%20-%20Ted%20M%20Young%20-%20SV%20Code%20Camp%20-%20October%202018.pdf?dl=0&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
</content>
  </entry>
</feed>