<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Dr Nicole Jacqueline Martin</title>
    <description>The latest articles on Forem by Dr Nicole Jacqueline Martin (@dr_nicole).</description>
    <link>https://forem.com/dr_nicole</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F221556%2F20a80a60-d2db-4406-991d-a86140cc29af.png</url>
      <title>Forem: Dr Nicole Jacqueline Martin</title>
      <link>https://forem.com/dr_nicole</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/dr_nicole"/>
    <language>en</language>
    <item>
      <title>Building "Journal Buddy": A Custom GPT for Personal Reflection</title>
      <dc:creator>Dr Nicole Jacqueline Martin</dc:creator>
      <pubDate>Thu, 11 Apr 2024 18:18:04 +0000</pubDate>
      <link>https://forem.com/dr_nicole/building-journal-buddy-a-custom-gpt-for-personal-reflection-19ge</link>
      <guid>https://forem.com/dr_nicole/building-journal-buddy-a-custom-gpt-for-personal-reflection-19ge</guid>
      <description>&lt;p&gt;I've always wanted to be able to write a daily journal. The science is pretty clear about the &lt;a href="https://www.reflection.app/blog/benefits-of-journaling" rel="noopener noreferrer"&gt;benefits of journalling&lt;/a&gt; for mental health and wellbeing. The problem is, I'm not that good at writing and the thought of staring at a blank sheet of paper each day fills me with dread. There are other practical problems, I would need to remember to lug a notebook and pen around with me everywhere. It just seems impractical and a tricky habit to get to stick.&lt;/p&gt;

&lt;p&gt;I recently read about &lt;a href="https://platform.openai.com/docs/actions/introduction" rel="noopener noreferrer"&gt;GPT Actions&lt;/a&gt; available when you create a &lt;a href="https://openai.com/blog/introducing-gpts" rel="noopener noreferrer"&gt;Custom GPT&lt;/a&gt; on OpenAI's platform. I've become increasingly reliant on GPT-4 as a useful pair programmer in my daily work as an engineer but had not explored making GPTs. I started thinking about creating a GPT that could help me specifically with journalling. I landed on a set of requirements for the MVP:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Provides useful prompts so that journalling is more of a conversation as opposed to a blank sheet of paper.&lt;/li&gt;
&lt;li&gt;Has memory that so that it can prompt based on past events.&lt;/li&gt;
&lt;li&gt;Can challenge you if you say things that contradict previous things.&lt;/li&gt;
&lt;li&gt;Has appropriate privacy, I didn't want OpenAI using my journal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This article delves into the technical intricacies of implementing "Journal Buddy" to meet the requirements above.&lt;/p&gt;

&lt;p&gt;TLDR; It was super easy to implement and works surprisingly well.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Database
&lt;/h3&gt;

&lt;p&gt;I spun up a simple MongoDB Atlas instance to store journal entries. These are simple objects containing a date and some markdown for the entry. The idea is that it isn't a full transcript of the conversation with Journal Buddy, but a summary that Journal Buddy creates.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTTP API
&lt;/h3&gt;

&lt;p&gt;I wrote a very minimal API in Go that has a GET route that currently just gets all the summary entries and a POST route that upserts a new summary on a specific date. At some point, this will probably be extended so I can get Journal Buddy to do either weekly or monthly summaries. The idea here is to provide more fine-grained data for more recent entries when getting context. For example, Journal Buddy could retrieve the daily summary for the past month, a monthly summary for 3 months preceding that, and then a yearly summary before that. I hosted this on Heroku and chucked some basic API key auth to keep things secure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom GPT
&lt;/h3&gt;

&lt;p&gt;The final piece of the puzzle was to create the custom GPT, this was as simple as describing what I wanted it to do and providing a bit of background about myself so each new instance would have the right context. Then I had to provide it with an OpenAPI schema so it knew how to interact with my API. It still blows my mind a little that all I have to do is give it this and it can parse it and understand how to use it. To be honest, this was the most difficult step since the default schema that Gorilla kicks out is version 2 as version 3 isn't supported, I ended up having to feed it through a converter and make some manual changes to get it to work.&lt;/p&gt;

&lt;p&gt;Here's a screenshot of the final product:&lt;/p&gt;

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

&lt;p&gt;You just have a chat to it and it prompts you with questions that help you reflect on your day and how you're feeling. It then summarises the conversation and stores it back in your private database.&lt;/p&gt;

&lt;p&gt;You can even ask it to remind you of things that happened in the past, which is great for someone like me who is always forgetting things!&lt;/p&gt;

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

&lt;p&gt;Overall, I'm super happy with Journal Buddy! I think someone even with fairly basic software experience could put something similar together. I'm interested in what other things I can do with GPT Actions, next on the list is to try and give a GPT eyes and a body by connecting one to a robot 🤖.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>go</category>
      <category>learning</category>
      <category>api</category>
    </item>
    <item>
      <title>Pattern matching 💖 decision tables</title>
      <dc:creator>Dr Nicole Jacqueline Martin</dc:creator>
      <pubDate>Wed, 10 Aug 2022 08:03:00 +0000</pubDate>
      <link>https://forem.com/dr_nicole/pattern-matching-decision-tables-f8f</link>
      <guid>https://forem.com/dr_nicole/pattern-matching-decision-tables-f8f</guid>
      <description>&lt;p&gt;Have you ever found yourself writing a massive nested if statement and thinking, 🤮? If so, this might be the post for you.&lt;/p&gt;

&lt;p&gt;First, lets talk about the problem. It's not uncommon when developing systems to have to implement some business logic that can be represented abstractly by a flow chart or decision tree. Below is an example of a fairly simple tree/chart to use as an example. Obviously it's likely that your own problem could be much more complicated that this, but hopefully it will serve to illustrate the point:&lt;/p&gt;

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

&lt;p&gt;This decision tree represents the business logic behind which type of apostrophe you should use (or not) in any given situation. It isn't uncommon for Domain Experts to illustrate their business logic through the use of a decision tree similar to this.&lt;/p&gt;

&lt;p&gt;Decision trees can be directly mapped to my preffered way of displaying this type of information, a decision table. In a decision table, we take the question nodes in the tree and put them along the top row. Then we create an extra column on the right of the table and fill in the "actions" we should take, these are the leaf nodes in our decision tree. Then we fill in all of the different possibile ansers to our question node, in our case &lt;strong&gt;true&lt;/strong&gt; (✔️) &lt;strong&gt;false&lt;/strong&gt; (❌) or &lt;strong&gt;either&lt;/strong&gt; (🤷). &lt;/p&gt;

&lt;p&gt;Decision tables (and trees) are composable, so it's possible to nest them into smaller subtables (or trees). Here are three tables that represent the decision tree above.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Plural?&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Single letter?&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Abbreviation?&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;See Possessive table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;Apostrophe + s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;Apostrophe + s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;No Apostrophe&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Plural table&lt;/em&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Possessive?&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Is it "it"?&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;"it is" or "it has"?&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;name ending in s?&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;plural name?&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;ends in s?&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;See Contraction table&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;Apostrophe + s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;No Apostrophe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;Apostrophe at end&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;Apostrophe at end&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;Apostrophe at end&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Apostrophe + s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Possessive table&lt;/em&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Contraction?&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Pronoun?&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;with a verb?&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;No Apostrophe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;Use Apostrophe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;🤷&lt;/td&gt;
&lt;td&gt;Use Apostrophe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;✔️&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;No Apostrophe&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Contraction table&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If your working with a Domain Expert who likes to use decision trees consider asking them to switch over to using tables instead.&lt;/p&gt;

&lt;p&gt;Okay, so we've got the logic for our Domain, now how do we implement this in code? We could choose to write a fairly large nested if statement. Or alternatively, if we're given a tree, why not represent this information as a tree? We could create a tree structure with nodes, edges and leaves and model this directly.&lt;/p&gt;

&lt;p&gt;These could would work, but have a couple of issues. If our Domain Expert comes back and tells us that the business logic has changed and provides a new tree. It's not so easy to translate the new logic into the code with either of these two methods. There's no direct mapping and in general it can be hard to look at a large nested if statement (assuming you can fit on a single screen) and easily determin the logic behind it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pattern matching FTW!
&lt;/h3&gt;

&lt;p&gt;Using pattern matching is my prefered solution to this problem. We can take our decision table(s) and directly map them to code in a way that looks and feels much very similar to the original information.&lt;/p&gt;

&lt;p&gt;Lets take the tables above and illustrate them as an example. I'm going to use &lt;a href="https://www.rust-lang.org/" rel="noopener noreferrer"&gt;Rust&lt;/a&gt; because it has a great type system and pattern matching built-in. Most languages now support this kind of syntax (I don't think JavaScript does... 🤨).&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The whitespace formatting I've chosen is here to help illustrate how closely linked the two concepts are and to help read the table, it's a personal preference thing though.&lt;/p&gt;

&lt;p&gt;If you're using a language with a good type system and compiler, then the added benefit of using pattern matching is that you get compile time checking of your logic. Unlike a series of if statements, you'll be warned if one of your patterns (table rows) are unreachable or if you've missed any cases. In C# you'll get a compiler warning with a nice hint suggesting cases that you've missed. It's not uncommon to include a catch-all case at the end where you can decide what to - perhaps throw an error.&lt;/p&gt;

&lt;p&gt;That's all really! Let me know in the comments what you think of this patern, have you used it before? Would you use it? Are there any other solutions you've found that work better?&lt;/p&gt;

</description>
      <category>programming</category>
      <category>tutorial</category>
      <category>rust</category>
      <category>discuss</category>
    </item>
    <item>
      <title>A more functional approach to Event Sourcing and DDD</title>
      <dc:creator>Dr Nicole Jacqueline Martin</dc:creator>
      <pubDate>Mon, 11 Jul 2022 21:32:04 +0000</pubDate>
      <link>https://forem.com/dr_nicole/a-more-function-approach-to-event-sourcing-and-ddd-491d</link>
      <guid>https://forem.com/dr_nicole/a-more-function-approach-to-event-sourcing-and-ddd-491d</guid>
      <description>&lt;p&gt;I've spent a bit of time outside of my day-to-day work playing around with functional languages, F# being my favourite so far. In particular the book &lt;a href="https://www.amazon.co.uk/Domain-Modeling-Made-Functional-Domain-Driven/dp/1680502549" rel="noopener noreferrer"&gt;Domain Driven Design Made Functional&lt;/a&gt; by Scott Wlaschin is well worth a read, whether you are into functional programming or not. Scott is also the author of the excellent &lt;a href="https://fsharpforfunandprofit.com/" rel="noopener noreferrer"&gt;F# for fun and profit&lt;/a&gt; website.&lt;/p&gt;

&lt;p&gt;I decided I wanted to use some of the benefits of functional programming in a C# project. C# 9 has seen some great additions to the language, including pattern matching and record types. These along with some patterns borrowed from functional programming play really nicely when developing Domain Models. Many of the ideas I'm going to talk about here have been inspired by Scott, but also Greg Young.&lt;/p&gt;

&lt;p&gt;The full source code can be found &lt;a href="https://github.com/n1ckdm/rockpaperscissors/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Rock 🪨, Paper 📃, Scissors ✂️
&lt;/h4&gt;

&lt;p&gt;I wanted a simple domain to test out these concepts, so I went with the game Rock Paper Scissors. In this game, we only have two commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create Game: A new game instance is started with a UUID&lt;/li&gt;
&lt;li&gt;Make Move: The players take it in turns to make a move, each player has one move&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the second move has been made, an end game state is reached with either one of the players winning or the game is tied.&lt;/p&gt;

&lt;p&gt;The first departure from "regular" Domain Driven Design is in how we raise and process Domain Events. In most examples I've found online, Domain events are raised by either storing them inside the aggregate root in some List structure, or outside in the Application layer, usually by injecting something into the method. Here we use a different technique, each command &lt;em&gt;returns&lt;/em&gt; a list of events. Many people will immediately jump to the fact that this is against CQRS and the "Tell Don't Ask" principal. In this case however, we're not returning part of the object state to manipulate somewhere else (which is what these principals were design to prevent). Instead, we're returning a list of events that describe how the state should be changed. Importantly, we've already carried out the business logic to check if these events are viable, now they are just facts that &lt;em&gt;must&lt;/em&gt; be applied to our aggregate or entity. The example below is the Handle method for the Make Move event.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As you can see, I'm using a command handler pattern, where state isn't mutated inside the aggregate at all, but the business logic for whether or not these events &lt;em&gt;can&lt;/em&gt; be raised still resides here.&lt;/p&gt;

&lt;p&gt;Typically, we would then apply these events to the aggregate so that the state can be mutated. In this approach though, instead of mutating the state, a new instance of the &lt;code&gt;Game&lt;/code&gt; aggregate is returned based on the event in question. Here, there aren't that many events to worry about, so I have a single static method, with a pattern matching switch statement to deal with each event type. It would also be possible to create separate methods to deal with specific events.&lt;/p&gt;

&lt;p&gt;How do we deal with the domain events when they're returned? These events are handled at the application layer, where they should be, since the details of what happens to them shouldn't be of concern to the Domain Model. In fact, we can prescribe a very clear set of steps that should be the same for every task:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retrieve a list of domain events from the store relating to the aggregate in question.&lt;/li&gt;
&lt;li&gt;Apply a left fold over the events to get the current state of the aggregate.&lt;/li&gt;
&lt;li&gt;Issue the command to the aggregate in order to get a new set of events.&lt;/li&gt;
&lt;li&gt;Append those new events to the store.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In code, this looks something like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As it should be clear now, a left fold is where we apply an accumulator function recursively to a sequence. In C# we can achieve this result using the built-in &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.aggregate?view=net-6.0" rel="noopener noreferrer"&gt;Aggregate&lt;/a&gt; method.&lt;/p&gt;

&lt;p&gt;Overall, these techniques should help make a codebase more declarative and easier to reason about. I wont go into all of the other advantages here - although there are plenty. One of those benefits is in how we can start to do application level integration tests. The following snippet shows the test for a game that results in a tie:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Hopefully this shows how, just because you don't explicitly keep track of the state of your application, you can still test for the required behaviour and in a way that in my opinion make testing simple.&lt;/p&gt;

&lt;p&gt;There are a few more things I'd like to do to with this code, including converting the domain model to F# and looking at a multi paradigm approach to the application. I'm still fairly new to the world of functional programming (and ES/DDD!), so would be very happy to receive feedback in the comments for how I can improve things.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>csharp</category>
      <category>ddd</category>
      <category>eventdriven</category>
    </item>
    <item>
      <title>Dealing with imposter syndrome</title>
      <dc:creator>Dr Nicole Jacqueline Martin</dc:creator>
      <pubDate>Mon, 11 Jul 2022 18:53:32 +0000</pubDate>
      <link>https://forem.com/dr_nicole/dealing-with-imposter-syndrome-557b</link>
      <guid>https://forem.com/dr_nicole/dealing-with-imposter-syndrome-557b</guid>
      <description>&lt;p&gt;I have spent two decades solving problems by writing code and developing software. Despite this, I still find it hard to not feel like I'm both under-qualified for my role as a software developer and that I'm fraud, who has managed to pull the wool over the eyes of the people I work with. In other words, I am susceptible to feelings of &lt;a href="https://en.wikipedia.org/wiki/Impostor_syndrome" rel="noopener noreferrer"&gt;imposter syndrome&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I want to start by saying that I'm not a an expert on imposter syndrome. This post is a reflection on the experiences I've had throughout my career. I hope that perhaps by reading this it might help others, particularly those earlier in their career who might have similar struggles. That being said, if you're looking for help on imposter syndrome or want to learn more about it, then I'd recommend taking a look at &lt;a href="https://www.ted.com/talks/elizabeth_cox_what_is_imposter_syndrome_and_how_can_you_combat_it?language=en" rel="noopener noreferrer"&gt;this&lt;/a&gt; TED talk by Elizabeth Cox as well as &lt;a href="https://www.ted.com/talks/mike_cannon_brookes_how_you_can_use_impostor_syndrome_to_your_benefit?language=en" rel="noopener noreferrer"&gt;this&lt;/a&gt; one by Mike Cannon.&lt;/p&gt;

&lt;p&gt;This post depicts how imposter syndrome has effected me as a white, straight, cis man. Imposter syndrome is a gendered and racialised issue meaning its impact can be &lt;a href="https://www.bbc.com/worklife/article/20200724-why-imposter-syndrome-hits-women-and-women-of-colour-harder" rel="noopener noreferrer"&gt;far more profound for minoritised groups&lt;/a&gt;. As a final disclaimer, I want to add that the intention of this post is not to suggest there's a problem with individuals or that individuals hold the solution, there are systemic issues that need addressing.&lt;/p&gt;

&lt;p&gt;I first got hooked on writing software when I was doing my A-levels (aged 16 in the UK) and my Maths teacher gave me a numerical methods project and I wrote a little application to solve equations using &lt;a href="https://en.wikipedia.org/wiki/Newton%27s_method" rel="noopener noreferrer"&gt;Newton's Method&lt;/a&gt;. I remember thinking how it was almost like magic how the computer did what I commanded it - a feeling that I still get even today!&lt;/p&gt;

&lt;p&gt;I studied Aerospace Engineering at University. I took additional modules that would allow me to broaden coding skills, mostly with Fortran and with the engineering focus we also learnt Matlab. I tried to cram as much coding into every module I could. The Computer Aided Design module I took, where typically you learn how to use a specific piece of software, I chose to use the built-in scripting languages to build my models in a fully parametrised way. I graduated with the highest degree in my year and won awards for my dissertation. I went on to do a PhD, where through the ever increasing amount of online resources available I taught myself Python, C++ and LabView (an intriguing visual language for interacting with hardware).&lt;/p&gt;

&lt;p&gt;When choosing a career after my PhD it seemed like a no brainer that I should go into Engineering and work as an engineer. The idea of a self-taught person doing "real" software development didn't seem possible to me. So I got a job in the aerodynamics department of a Formula 1 team. However, I quite quickly realised that both my passion to develop software and the lack of software developers in the department meant that I quickly started "side hustling" as developer. I constantly felt like I was having to justify to myself as well as to my superiors the software work I was doing. Despite this, my main contributions to the department in my time there, where all based around these specific projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developing data visualisation tools.&lt;/li&gt;
&lt;li&gt;Replacing legacy excel worksheets with "proper" software.&lt;/li&gt;
&lt;li&gt;Designing Machine Learning models of the aerodynamic forces on the car.&lt;/li&gt;
&lt;li&gt;Implementing new software systems to drive and process data from the Wind Tunnel.&lt;/li&gt;
&lt;li&gt;Using software to automate the use of Particle Imaging Velocimetry during testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I learnt lots in my time working in F1 and the experience underlined my love of developing software. What's more, the work I did helped the aerodynamics department see the importance of having "full time" software developers as opposed to engineers doing some software "on the side". But when the time came for me to step up and fully take on such a role, I was overlooked. Part of the reason for this was because despite now having "proved myself" there was a voice inside me saying - but you're not a software developer, you don't have any qualifications, you're self taught, you're a fraud, you can't do it. So instead of putting myself forwards, I stepped back.&lt;/p&gt;

&lt;p&gt;Not too long after this happened, my wife and I decided to relocate 400 kilometres north to another part of the country. Remote working wasn't really a thing back then, I had to find a new job outside of Formula 1. I brushed off my CV and decided I had two options really: return to academia after a long stint in industry or follow a new (sort of) career in software development.&lt;/p&gt;

&lt;p&gt;Every software developer interview I had I remember immediately sitting down and feeling like a fraud. When I passed technical interviews and got feedback on how I was doing I could hardly believe that it was positive and that most places even wanted to hire me! In the end I had a few roles to choose from, including one at a University, which would see me returning to academia. I sat talking through the options with my wife. Looking back on that conversation now, I managed to convince myself that I should go with the role in academia because "I was using my PhD" - which in hindsight is a terrible reason. In my heart I knew I wanted to write code, that's my passion, that's what I love. But I wouldn't allow myself to do that because of my imposter syndrome.&lt;/p&gt;

&lt;p&gt;Taking the job at the university was the worst decision I've ever made in my career. Coming back to academia and building up your research, whilst also having a heavy teaching workload are not easy and this coupled with some workplace bullying did not make for a fulfilling experience. That aside, even in this role, I looked for ways to itch my never ending need to develop software. I based my research around projects that would involve me writing code and I used numerical methods to bolster the pure maths that I taught in the classical mechanics lectures. After a year of working the hardest and longest hours that I have ever in my career with no positive feedback or support from the institution I worked for, I quit.&lt;/p&gt;

&lt;p&gt;I went from the worst career decision of my life, to the best. I have a very vivid memory of it, it was a Friday morning and I was reading about a local company when I was on the metro to work. They were called &lt;a href="https://tharsus.com/" rel="noopener noreferrer"&gt;Tharsus&lt;/a&gt; and their business was to design and manufacture robots and smart machines. After what I can only describe as the worst line manager meeting I've ever had, I came back home feeling depressed, spoke to my wife, who promptly told me "you need to quit and get a new job". Remembering the company I had read about on the metro, I pulled open my laptop and surfed up their careers page. There was an opening for a data scientist role. I wouldn't class myself as a data scientist, but the job description seemed to focus mostly on writing and implementing software.&lt;/p&gt;

&lt;p&gt;To cut a very long story short(er) I got the job at Tharsus and within weeks it was clear that my skills lay squarely as a software developer and I've never looked back. I've been working there for three and a half years now. We do incredible stuff, work with new technologies and on a variety of domains.&lt;/p&gt;

&lt;p&gt;Despite everything I've been through there are still times when I feel like I'm a fraud. When I feel like someone will see through the smoke and mirrors carefully constructed around me. Like I'll be "found out" and told I shouldn't be doing what I'm doing because I'm not up to the job. This doesn't happen as often as it used to - and to be clear, objectively I know this not to be the case. But when I'm having a bad day or something else in my life outside of work is on my mind, I can feel these nagging thoughts start to creep in.&lt;/p&gt;

&lt;p&gt;My advice for anyone else who has these feelings is to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tell someone close whose opinion you trust. They will be able to tell you how it really is (you're not a fraud) and hearing it from someone else is sometimes all you need.&lt;/li&gt;
&lt;li&gt;Write down objectively why you should be doing what you do. Going through the exercise of writing this post, I can see objectively that there's no reason I should feel imposter syndrome&lt;/li&gt;
&lt;li&gt;Don't let your own opinion of yourself get in the way of trying new things. If you want to try a different career, let the people hiring decide if you can do it or not. Otherwise, be confident in your own abilities.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>discuss</category>
      <category>programming</category>
      <category>mentalhealth</category>
      <category>career</category>
    </item>
    <item>
      <title>Improving code using the Trinity of Quality</title>
      <dc:creator>Dr Nicole Jacqueline Martin</dc:creator>
      <pubDate>Thu, 30 Jun 2022 08:26:32 +0000</pubDate>
      <link>https://forem.com/n1ckdm/improving-code-using-the-trinity-of-quality-25ie</link>
      <guid>https://forem.com/n1ckdm/improving-code-using-the-trinity-of-quality-25ie</guid>
      <description>&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/TWBEi4ZcLu4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I watched this YouTube video recently by &lt;a href="https://www.youtube.com/c/minutephysics"&gt;Minute Physics&lt;/a&gt; (who I highly recommend subscribing to) on the Trinity of Quality, a concept I had not heard of before, but I think it maps directly onto something I think about most days: how to improve the quality of mine and my teams code.&lt;/p&gt;

&lt;p&gt;The Trinity of Quality according to Henry Reich (the creator of Minute Physics) is a triangle, made up of three corners:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Quality&lt;/strong&gt;: How good something actually is&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Taste&lt;/strong&gt;: How good you think something should be&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discernment&lt;/strong&gt;: How well you can determine Quality&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll briefly talk about what these mean in more detail, but I suggest you watch the video for a more in depth look at each of the corners.&lt;/p&gt;

&lt;h4&gt;
  
  
  Quality
&lt;/h4&gt;

&lt;p&gt;How good is the thing your looking at? This can be both objective or subjective. The quality of your code is made up of a multitude of different factors, some of these are very objective: do you have a syntax error, will this function pass it's unit tests, is it even possible to test the code? Some are less subjective: how whitespace has been used, how granular functions are, the naming of variables.&lt;/p&gt;

&lt;h4&gt;
  
  
  Taste
&lt;/h4&gt;

&lt;p&gt;Or preference. This is a personal viewpoint about the Quality of something. Are you a code perfectionist, do you think all of the metrics that define code quality should be at their highest or do you care more about the function of the code? If it does what it needs to do and passes all it's unit tests, who cares what it looks like under the hood?&lt;/p&gt;

&lt;p&gt;So Quality is how good something is on a scale, while Taste is where we think it should be:&lt;/p&gt;

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

&lt;p&gt;Focusing just on how to make something is good is where we usually go when trying to improve our code. But the problem with this is that there is a more useful skill: How good are you at determining how good something is?&lt;/p&gt;

&lt;h4&gt;
  
  
  Discernment
&lt;/h4&gt;

&lt;p&gt;This is the most under-looked, but potentially the most important corner of the Trinity. If Quality is where your code is on a scale and Taste is where you want it to be, then Discernment is how good you are at being able to determine how good your code is, it's your error bars on your code checking skills. If they are wide, then even if we have high standards (Taste) we wont necessarily be able to determine if our code meets those or we might think that it has even when it hasn't:&lt;/p&gt;

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

&lt;p&gt;While there are plenty of rules of thumb or even best practices for how good our code is, these don't always work and sometimes we don't really know &lt;em&gt;why&lt;/em&gt; code is good.&lt;/p&gt;

&lt;p&gt;Someone who is more discerning than me who has the same Taste (or preference or standards) might deem my code not to of high enough quality to meet their taste:&lt;/p&gt;

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

&lt;p&gt;Being more discerning as software developers allows us to be better judges on both on how good our own code is, but also on other people's code when we do code reviews.&lt;/p&gt;

&lt;p&gt;Taste and Discernment are linked but are not the same. Training yourself to be more discerning might lead you to change your Taste, but there's always an underlying truth, so improving ability to Discern the Quality of code is an important skill. In the video, Henry describes a number of ways that differing discernment between people can lead to issues when working together with others. Not to mention that being more discerning in general should improve your code Quality, how can you improve if you aren't able to reliably measure that?&lt;/p&gt;

&lt;p&gt;There are ways to improve your discernment, here are some tips you can apply:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Give yourself time to do code reviews, don't rush them.&lt;/li&gt;
&lt;li&gt;Speak to others, don't do your code reviews in isolation&lt;/li&gt;
&lt;li&gt;Try to concentrate on objective, rather than subjective Qualities when reviewing code.&lt;/li&gt;
&lt;li&gt;Conduct your own code reviews, do this regularly throughout your development cycle.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But overall, I think it's just important when reviewing your code or others, to remember the Trinity of Quality. Is the reason you don't feel someone's code is of the correct Quality because of your Taste (or standards) or is it because you aren't be discerning enough to know?&lt;/p&gt;

&lt;p&gt;Cover art by &lt;a href="https://unsplash.com/@johnschno?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;John Schnobrich&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>agile</category>
      <category>codequality</category>
      <category>career</category>
    </item>
    <item>
      <title>Show Spotify Now Playing in Twitch Studio</title>
      <dc:creator>Dr Nicole Jacqueline Martin</dc:creator>
      <pubDate>Sun, 26 Jun 2022 22:08:24 +0000</pubDate>
      <link>https://forem.com/dr_nicole/show-spotify-now-playing-in-twitch-studio-2eml</link>
      <guid>https://forem.com/dr_nicole/show-spotify-now-playing-in-twitch-studio-2eml</guid>
      <description>&lt;p&gt;I decided recently that I would start live coding my personal projects outside of work on &lt;a href="https://www.twitch.tv/" rel="noopener noreferrer"&gt;Twitch&lt;/a&gt;🚀. It's something I've always considered and after reading about how it can help improve your productivity I thought I'd give it a go (here's &lt;a href="https://www.twitch.tv/n1ckdm" rel="noopener noreferrer"&gt;my channel&lt;/a&gt; 😎).&lt;/p&gt;

&lt;p&gt;Obviously, before actually starting my first stream I had to procrastinate a little.. so I spent some time getting everything setup. I had originally planned on using &lt;a href="https://obsproject.com/" rel="noopener noreferrer"&gt;OBS&lt;/a&gt; as my streaming software, but ended up choosing Twitch's own software "Twitch Studio" as it seemed to be more user friendly for the newbie streamer. For the most part it is, but I quickly ran into a problem.&lt;/p&gt;

&lt;p&gt;I managed to get everything setup apart from the ability to display my currently playing song from Spotify. While this is a little bit of an unnecessary addition to my overlay - I thought a tiny bit of extra effort to get it right would be worth it.&lt;/p&gt;

&lt;p&gt;Turns out it's not that straight forward to setup 🙄. I couldn't easily find a solution without writing my own HTML page - so that's what I did. I thought I'd post what I came up with here to save someone else 30 minutes of their life...&lt;/p&gt;

&lt;p&gt;The full HTML page is saved in a &lt;a href="https://gist.github.com/n1ckdm/6eb52bee0950596ecf802e2ecc2109ed" rel="noopener noreferrer"&gt;Gist &lt;/a&gt;on GitHub (sorry for my terrible JavaScript):&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The JS just uses the last.fm API to grab your most recently played track(s) from their API. It continues to ping it every 10 seconds (which is fast enough for a Now playing feed). I made a little card to display it nicely.&lt;/p&gt;

&lt;p&gt;To get it up and running, just add a Browser Source Layer to the scene you want your feed to appear in and then open the HTML file (which you should save locally). You'll need to edit the HTML to include your own Auth Token from LastFM - which you can grab from their API documentation easily enough. You will also need to hook up your Spotify account to LastFM. Obviously you shouldn't host this page anywhere or people could steal your Token...&lt;/p&gt;

&lt;p&gt;A brief note as well that you shouldn't stream with any copyrighted music or you could get banned from Twitch. There are lots of playlists you can choose from, two of my favourites are &lt;a href="https://open.spotify.com/playlist/3zR71nMKdPoFo46SYKxFhf" rel="noopener noreferrer"&gt;this one&lt;/a&gt; and &lt;a href="https://open.spotify.com/playlist/7KacetCAhxUX5la5Kj88Ld?si=fa88dca2373e41e8" rel="noopener noreferrer"&gt;this one&lt;/a&gt; 🦄.&lt;/p&gt;

&lt;p&gt;That's all really, not too much to it!&lt;/p&gt;

&lt;p&gt;Cover art by &lt;a href="https://unsplash.com/@der_maik_?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Maik Jonietz&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>spotify</category>
      <category>twitch</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
