<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Casper Weiss Bang's blog]]></title><description><![CDATA[Software engineer with a huge interest in bridging the gap between domain experts and tech experts, and hopefully improving maintainability. 
Inspired by Domain]]></description><link>https://blog.cwb.dk</link><generator>RSS for Node</generator><lastBuildDate>Tue, 21 Apr 2026 07:56:38 GMT</lastBuildDate><atom:link href="https://blog.cwb.dk/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Pair Programming for Technical job interviews]]></title><description><![CDATA[I was watching Dave Farley's video on Software Developer Interview Advice - (I am not looking for jobs, I just wanted to reflect on the interviews I've helped facilitate where I work. Multiple points resonated with me and brought back memories of pri...]]></description><link>https://blog.cwb.dk/pair-programming-for-technical-job-interviews</link><guid isPermaLink="true">https://blog.cwb.dk/pair-programming-for-technical-job-interviews</guid><category><![CDATA[Technical interview]]></category><category><![CDATA[interview preparations]]></category><category><![CDATA[interview questions]]></category><category><![CDATA[pair programming]]></category><category><![CDATA[hiring]]></category><dc:creator><![CDATA[Casper Weiss Bang]]></dc:creator><pubDate>Sat, 02 Sep 2023 20:35:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/fSWOVc3e06w/upload/5598d9d2d8239fd54a167983e0fd525a.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I was watching Dave Farley's video on <a target="_blank" href="https://www.youtube.com/watch?v=osnOY5zgdMI">Software Developer Interview Advice</a> - (I am not looking for jobs, I just wanted to reflect on the interviews I've helped facilitate where I work. Multiple points resonated with me and brought back memories of prior discussions.</p>
<p><a target="_blank" href="https://www.psychologytoday.com/us/blog/insight-therapy/202008/poor-predictors-job-interviews-are-useless-and-unfair">The research says that job interviews are poor indicators</a>, but they are our best right now. You want to see if a person. and as an interviewee, you want to see if the company is a fit. In software, it is important to gauge the technical abilities too - and this motivates the dreaded technical job interviews. They are often much like verbal exams; you are mainly gauging the interviewee's ability to handle job interviews. If you want to hire great interviewees, GREAT! if you want to hire great technical people, you will have data noise from nervousness, the knowledge about the specific questions you ask, etc.</p>
<h1 id="heading-the-majority-of-technical-interviews">The majority of technical interviews</h1>
<p>The interviews will often have some sort of coding exercise, and to make them fit in a 30/45-minute timeslot you have an algorithmic problem in the employer's preferred programming language, they are often not representable for an actual work process. As Dave Farley argues, a great employer will care less if a new employee knows C# (for instance) and more so their ability to learn and work together in general; language abstracts are mere technicalities. I speak from experience; at a prior job, I had to write an application in C# (over a two-week period), but due to time pressure we ended up going through it verbally. Between you and me, I hadn't used C# for years and was quite rusty. It went well; I got the job, but it surely wasn't representable, and I was probably lucky I could hide my rust by it being a verbal technical challenge.</p>
<h1 id="heading-an-extreme-alternative">An extreme alternative</h1>
<p>The consultancy I work for, is inspired by, among other things, <a target="_blank" href="https://en.wikipedia.org/wiki/Extreme_programming">eXtreme Programming</a> (hence, the pun in the heading). This also includes pair programming. We don't use it religiously in my team, but being a remote-first company, it can be a great way to ensure team cohesion (see my other posts with perspectives on remote-first), furthermore, it is a great way to solve some of the more difficult technical or abstractional challenges.</p>
<p>Based on these inspirations, our technical interviews are also a test of how well people work in a pair-programming session. This, however, has a bunch of benefits.</p>
<h1 id="heading-how-we-run-our-technical-interviews">How we run our technical interviews</h1>
<p>Prior to the interview, the applicant is asked to prepare any small problem in any project in any programming language. <em>Any</em> is an important word here. We then, for 45 minutes work through the problem, where the applicant controls the keyboard, and works on it (Like <a target="_blank" href="https://en.wikipedia.org/wiki/Think_aloud_protocol">the think-aloud practice from UX</a>). We help solve the problems, much like we do when pair programming on actual problems for customers. We might help search relevant documentation for the applicant - spot missing semicolons or whatever might be.</p>
<p>Again - the ANY is crucial. When I had my interview I brought a C# API I was working on to familiarize myself with DDD and event sourcing. Not a tech stack that is in any way relevant to my new job. However, it gave me an opportunity to showcase myself at my best, as well as maximize the complexity of what to present. I wanted to refactor some parts of the code following TDD principles. We didn't actually finish it - it wouldn't even compile when the 45 minutes were up. But I was in a psychologically safe environment, where I was able to showcase my skills. My (now) awesome employer, was able to see how I could communicate problems, discuss different potential solutions as well as develop software "at my best". Furthermore, I got a small taste of collaborating with engineers inside the company - which I could use to influence my decision too.</p>
<h1 id="heading-the-differences-it-makes">The differences it makes</h1>
<p>The process creates an environment that is more enjoyable for the interviewee. <a target="_blank" href="https://hbr.org/2023/02/what-is-psychological-safety">Psychological safety</a>, has been on everyone's lips this year, and why not start at the very beginning? Both parties are able to experience working on an actual problem that one person is confident in - both parties experience all the pains one goes through in an actual development process and see how the other party reacts. And it's a whole lot more fun. I've learned something new after each interview, whether that be about the <a target="_blank" href="https://en.wikipedia.org/wiki/Eight_queens_puzzle">Eight queens problem</a>, <a target="_blank" href="https://en.wikipedia.org/wiki/Explainable_artificial_intelligence">Explainable AI</a>, weird biomechanical stuff that I barely even understood or just fun little frameworks in various languages.  </p>
<p>Also a small secret; it requires less preparation for us. Worst case we have a bit of reading up on a framework or project (some of my more mathematical coworkers have worked on some complex problems no amount of Wikipedia could help me understand, but that is also a great exam in communicating complex problems to simple-minded people, like me).</p>
<p>We aren't perfect though. In my opinion, we could improve our explanation of the process to the applicants - some applicants are stuck in the traditional perspective, and try to guess which tools we use, and create a problem that matches that. This has the consequence that they aren't as confident in what they are doing, and the benefits of the process are worsened. </p>
<h1 id="heading-the-core-value">The core value</h1>
<p>When we are hiring, we aren't looking for an engineer who knows the exact stack we are using. We are looking for great minds who are eager to learn and are versatile. We also want diverse perspectives - to improve our conjoint knowledge base. Our whole mission is to be at the forefront of data engineering and machine learning - if that is the case, then years of experience isn't possible not possible. It's the classic meme, that reoccurs in the software field:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://twitter.com/tiangolo/status/1281946592459853830">https://twitter.com/tiangolo/status/1281946592459853830</a></div>
<p>Let's strive to create an interview process that is comfortable for the interviewee and interviewer, which actually brings to light the skills of the interviewee.</p>
]]></content:encoded></item><item><title><![CDATA[API First? No, thank you! Schema-first, please!]]></title><description><![CDATA[I've developed a lot of APIs, and have been working API-first, with rough steps like the following:

Write a very rough API in whatever framework, returning sample responses

Generating a schema from the API, i.e. with Swashbuckle

Sharing the schema...]]></description><link>https://blog.cwb.dk/schema-first</link><guid isPermaLink="true">https://blog.cwb.dk/schema-first</guid><category><![CDATA[OpenApi]]></category><category><![CDATA[swagger]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[codegeneration]]></category><category><![CDATA[pair programming]]></category><dc:creator><![CDATA[Casper Weiss Bang]]></dc:creator><pubDate>Mon, 26 Jun 2023 19:59:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/9xms9i9YwIo/upload/73a79044c7dbf6b6fdbe5b37f55d9fd6.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I've developed a lot of APIs, and have been working <a target="_blank" href="https://www.postman.com/api-first/">API-first</a>, with rough steps like the following:</p>
<ol>
<li><p>Write a very rough API in whatever framework, returning sample responses</p>
</li>
<li><p>Generating a schema from the API, i.e. with <a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/tutorials/web-api-help-pages-using-swagger?view=aspnetcore-7.0">Swashbuckle</a></p>
</li>
<li><p>Sharing the schema with developers of a web client, so they can start working on a consumer</p>
</li>
<li><p>Implement the actual implementations of the API.</p>
</li>
</ol>
<p>This has a bunch of benefits; you have a small increment, you can get feedback on the API design early, and you don't block the development of any consumer. It's great.</p>
<p>Recently I was advised, in a project at work, to start by defining the API schema instead. It seemed stupid and tedious to write a bunch of yaml by hand.</p>
<p>I gave it a try at work, and have done so again in a hobby project. It's great!</p>
<h1 id="heading-what-is-an-api-schema">What is an API schema?</h1>
<p>Schema or specification - I'd probably use those interchangeably. It's a document of sorts, that specifies all the endpoints you have, what they can return, and how you interact with them. You have probably already experienced one artifact of them; namely an API documentation, either with <a target="_blank" href="https://petstore.swagger.io/">Swagger</a> or <a target="_blank" href="https://redocly.github.io/redoc/">Redocly</a>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687805070249/ed8d7715-77c3-4b73-978b-2e7fb4a8f6a3.png" alt="A screenshot of the swagger petstore example" class="image--center mx-auto" /></p>
<p>That's one cool aspect of it; you can have a nice interactive visualization/documentation.</p>
<p>Another neat benefit is code generation. I'll get back to that.</p>
<p><img src="https://media.giphy.com/media/zNi65ptNRm3oLhVQoR/giphy.gif" alt="Wait, wait. Hold that thought." class="image--center mx-auto" /></p>
<p>There are a bunch of different neat tools and possible artifacts. The most widely used format is the <a target="_blank" href="https://www.openapis.org/">OpenAPI specification</a>, developed by the awesome OpenApi Initiative, originally based on the <a target="_blank" href="https://www.openapis.org/about">Swagger Specification</a>. <a target="_blank" href="https://grpc.io/">gRPC</a> also utilizes a format (in <code>*.proto</code>files) to <a target="_blank" href="https://grpc.io/docs/what-is-grpc/introduction/">specify the structure of communication</a>.</p>
<p>Previously, when working API-First, I would generate an OpenAPI specification based on the defined API. Tools like Swashbuckle does this behind the scenes. <a target="_blank" href="https://www.django-rest-framework.org/">Django REST Framework</a> does <a target="_blank" href="https://www.django-rest-framework.org/topics/documenting-your-api/">the same</a>, and I imagine a wide range of tools do too.</p>
<p>So why not use the API to generate a specification? Why would you write YAML by hand?</p>
<p><img src="https://media.giphy.com/media/l4FGBq3eNviC8ljHO/giphy.gif" alt class="image--center mx-auto" /></p>
<h2 id="heading-why-write-boring-yaml-by-hand">Why write boring YAML by hand</h2>
<p>I've worked with UXers (<a target="_blank" href="https://devblogs.microsoft.com/premier-developer/ux-is-not-ui-but-ui-is-definitely-ux/">Which is not UI!</a>), in a wide range of jobs - and a key practice they always do is to work with <a target="_blank" href="https://uxdesign.cc/why-low-fidelity-wireframe-curious-in-product-design-c7bea87bc23d">Low-fidelity prototypes</a>. You want something simple, where people don't overthink specific details too much, and you have to spend less time on it; it is easier for someone to criticize a YAML file, than an API you spend a week on writing - and you'll be less pissed when they say "<em>Wait we want our api to be</em> <em>level 3 REST</em>" (Tbh, you might be pissed anyway, that is very holier-than-thou)(There is a substantial risk I'll love level 3 rest in the future, and you are welcome to mock me).</p>
<p>Furthermore, you will enable a consumer to write their clients even earlier on.</p>
<p>And you'll be able to write your API specification with real-time input from the people developing a client. Pair programming, baby! We've actually done this in the past quite often; in a planning session, we would loosely verbally agree on which endpoints we'd need, and the expected payloads. Not sure why we never wrote it down in a formal specification language.</p>
<p>There is also the benefit of having a source-controlled <em>"contract",</em> where you agree on the communication between devices. It can be discussed, read, and updated in its own right.</p>
<p>Oh and lastly, there is the whole code generation perspective (That I'll get to soon!)</p>
<p><img src="https://media.giphy.com/media/d8erixRKssVk0ZUqXi/giphy.gif" alt class="image--center mx-auto" /></p>
<h1 id="heading-how-do-you-write-it">How do you write it?</h1>
<p>The first time, we sat two people in a video call, screen sharing, as you would do in a <a target="_blank" href="https://devopedia.org/remote-pair-programming">pair programming session</a>. One person writing. We had some great discussions; "I would prefer <a target="_blank" href="https://en.wikipedia.org/wiki/Command%E2%80%93query_separation#Command_Query_Responsibility_Separation">CQRS</a>", "Could we reuse this <a target="_blank" href="https://en.wikipedia.org/wiki/Data_transfer_object">Dto</a>?" or "Hmm I would need X to solve this". It evened out a few issues we might have gotten later.</p>
<p>Yesterday, when I had to set up an API for another project, we didn't have time to get together. Instead, I wrote the specification and sent a pull request and it was reviewed with a person that visualized the spec in a <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=42Crunch.vscode-openapi">VSCode extension</a>. And due to it being a language with a formal definition, we were able to set up a CI pipeline that does <a target="_blank" href="https://redocly.com/docs/cli/commands/lint/">linting</a> with <code>redocly-cli</code>.</p>
<p>He also used some code generation to visualize the models in a class diagram, which made it easier to reason about.</p>
<p><img src="https://media.giphy.com/media/pWe8lCBvsFxRnSPO08/giphy.gif" alt class="image--center mx-auto" /></p>
<p>Another neat thing (not to jump on a hype train) is you can utilize LLMs (ChatGPT and similar) to write parts of it - or help you. In my example, I had written a bunch of domain logic, and I had this annoying big part of data classes I had to write into the schema. Chatty to the rescue:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687808149882/acf30b2a-f1c6-4939-8809-4ef815d2a637.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-code-generation">Code generation</h1>
<p>Okay, okay - Code generation.<br />So it's a formal specification that defines how a given server and client should communicate. It has typing etc. That makes it possible to generate code that follows that specification. Obviously not the actual implementation, but using tools like <a target="_blank" href="https://github.com/OpenAPITools/openapi-generator"><code>openapi-generator</code></a>, which (as of writing) has <a target="_blank" href="https://openapi-generator.tech/docs/generators">66 different client generators and 67 different server generators</a>. It can also generate <a target="_blank" href="https://plantuml.com/">PlantUML</a> code/diagrams. It's pretty neat.</p>
<p>I created a reproducible script for a project yesterday, that can regenerate my server if our specification is to change (new features, changes, etc.), which means that if I run it, my code won't compile, and if I don't implement all the new/changed endpoints. The auto-generated code is then isolated, making it easy to import and utilize as wanted. The same can be done on the client side.</p>
<h2 id="heading-whats-the-catch">What's the catch?</h2>
<p>A bunch of the code generators are a bit dated. They don't seem to have much contribution as of late. I tried to use the f# <a target="_blank" href="https://github.com/giraffe-fsharp/Giraffe">giraffe</a> generator, which <a target="_blank" href="https://github.com/OpenAPITools/openapi-generator/tree/ea2c6860d3a3f36a542affddd0e39832f09a3513/modules/openapi-generator/src/main/resources/fsharp-giraffe-server">hasn't been update for 2 years</a> and therefore doesn't seem to work well with the newest versions of F#, dotnet, or Giraffe. I've previously experienced similar issues with other generators. That is obviously a pain.</p>
<p>I am also a pedantic perfectionist developer. I ended up using a C# <a target="_blank" href="https://openapi-generator.tech/docs/generators/aspnetcore">aspnet</a> generator (A cool thing about F# is that I can define one project in C# and the rest in F#). It does work, but I am not entirely happy about the outcome; one issue is that it uses C# DataContracts, not records, meaning I can, in theory, generate invalid Dtos. Another issue is that it utilizes the <a target="_blank" href="https://learn.microsoft.com/en-us/aspnet/core/web-api/action-return-types?view=aspnetcore-7.0#iactionresult-type">IActionResult</a> return type on the API calls, which means I can, with no compile-time errors, return a different Dto than the schema defines.</p>
<p>These aren't inherently issues with OpenAPI, but more issues with difficult-to-maintain projects and ASP.nET.</p>
<p>These issues could be fixed by a (pedantic) developer (like me) that contributes time and energy to a great open-source project. I have fixed the <code>IActionResult</code> in prior projects - it requires some boilerplate but does work. Similarly, I could update the giraffe generator, or write one for f# ASP.NET (I consider doing so), but finding the time is difficult.</p>
<p>Finally, I would add that working schema-first does have a bunch of benefits even without code generation. You have a formal agreement, similar to <a target="_blank" href="https://www.montecarlodata.com/blog-data-contracts-explained/">data contracts</a>, which is all the <a target="_blank" href="https://www.linkedin.com/pulse/unlocking-potential-data-contracts-bridging-gap-between-mohit-joshi%3FtrackingId=%252BwMlad%252FqTJOYKFqXMrHy4Q%253D%253D/?trackingId=%2BwMlad%2FqTJOYKFqXMrHy4Q%3D%3D">hype</a> in the data world.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Spec-First brings numerous advantages. It feels <em>"weird"</em> at first, yet the benefits it offers, such as improved change tracking, streamlined discussions, and enhanced convenience as a long-term artifact, are substantial in my perspective.</p>
<p>Even with the drawbacks regarding community size which, you and I can help improve, I believe Spec-First has the potential to enhance the velocity, design, and communication of future APIs.</p>
]]></content:encoded></item><item><title><![CDATA[Are standups dead in a fully-remote team?]]></title><description><![CDATA[I've always been a fan of the different scrum-inspired rituals, however after working fully remote for 9 months, I start to question whether it adds value, or is simply costing us an hour of productivity each day.
What is the value of a standup?

The...]]></description><link>https://blog.cwb.dk/are-standups-dead-in-a-fully-remote-team</link><guid isPermaLink="true">https://blog.cwb.dk/are-standups-dead-in-a-fully-remote-team</guid><category><![CDATA[agile]]></category><category><![CDATA[Scrum]]></category><category><![CDATA[Scrum Master]]></category><category><![CDATA[extreme programming]]></category><category><![CDATA[experimentation]]></category><dc:creator><![CDATA[Casper Weiss Bang]]></dc:creator><pubDate>Sun, 18 Jun 2023 16:03:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/wD1LRb9OeEo/upload/6708c9fa386b779a0bc572f57df6a22f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I've always been a fan of the different scrum-inspired rituals, however after working fully remote for 9 months, I start to question whether it adds value, or is simply costing us an hour of productivity each day.</p>
<h2 id="heading-what-is-the-value-of-a-standup">What is the value of a standup?</h2>
<blockquote>
<p>The daily stand-up is a short, daily meeting to discuss progress and identify blockers. The reason it’s called a “stand-up” is because if attendees participate while standing, the meeting should be kept short. [<a target="_blank" href="https://www.atlassian.com/agile/scrum/standups">https://www.atlassian.com/agile/scrum/standups</a>]</p>
</blockquote>
<p>I imagine many developers worldwide have some form of daily status meeting - I've at least had them wherever I've worked. Ideally, they should eliminate blockers and ensure everyone is on the same page. When you have a synchronous workday, it's an excellent way to kick off the day. If you have shy team members it's a great way to make sure everyone is getting the help they need, and that everyone is on the same page; working towards a common goal.</p>
<h2 id="heading-what-is-the-problem">What is the problem?</h2>
<p>At my current job, and the one prior we all start our days at different times. I like to get up early and get my things done so that I can go home early. Others like to have a long morning with their kids, and then work throughout the night. When I worked on-prem, the standup was a great way to be in-the-know, about things that were only discussed verbally between coworkers.</p>
<p>However now, whenever anyone has an impediment they write it on Slack. If I write it early in the morning all my team members are able to see it, and any subsequent discussion is visible retroactively if you are off a given day. You are always in the know.</p>
<p>What about time? focus? It's easy to get distracted during standups, not because it's not serious, but because someone's focus is often on whatever project they work on - <a target="_blank" href="https://www.atlassian.com/blog/productivity/context-switching">Context switch is expensive</a>, and <a target="_blank" href="https://cutlefish.substack.com/p/tbm-4952-your-calendar-your-priorities">we do it a lot</a>. I have found ways to improve focus by physically going somewhere else - i.e to the couch with a cup of coffee - it helps, however, it adds a context-switching buffer before and after the standup. However, that does consume time on both ends of the standup. So we timebox a meeting for 15 minutes, but it ends up consuming possibly 20-30 minutes each day. That is about 2 hours each week per person. You could cut it shorter, and timebox it to 5-10 minutes. But a crucial benefit of standups is also that you get everyone in one room - especially working remotely, you lose the <a target="_blank" href="https://friday.app/p/water-cooler-talk"><em>water cooler chats</em></a>, and a standup can be a daily routine where everyone looks each other in the eyes. That has been a primary motivator for having an internal stand-up, and the consultancy I work at; improving team cohesion and relationship building.</p>
<h2 id="heading-so-what-about-team-cohesion">So, what about team cohesion?</h2>
<p>Since we operate fully remotely, we don't have the opportunity for casual water cooler discussions, which I genuinely miss as an extrovert. This is obviously <a target="_blank" href="https://www.forbes.com/sites/forbestechcouncil/2021/01/19/cultivating-cohesion-in-remote-teams-tips-to-maintain-openness-and-productivity/">important</a> to <a target="_blank" href="https://www.forbes.com/sites/nicolebendaly/2020/03/20/your-team-is-now-working-remotely5-ways-to-strengthen-communication-and-team-cohesion-in-the-covid-19-world/">incorporate</a> into <a target="_blank" href="https://www.invoiceberry.com/blog/how-to-foster-team-spirit-in-remote-teams/">remote</a> positions <a target="_blank" href="https://www.atlassian.com/blog/teamwork/the-importance-of-teamwork">too</a>.</p>
<p>In the consultancy I work with, we have two 30-minute gaming sessions each week. It's encouraged but optional, so you skip it if you have an important meeting or a big deadline, but for the most part, the majority of people are there.</p>
<p>It's a great way to meet everyone, small talk, and have a laugh together. We recently had to draw a bike together; the level of success is questionable, but our team spirit has never been higher:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1687103614449/0848d9d0-29e7-40c1-ac76-cb0070bb613f.png" alt class="image--center mx-auto" /></p>
<ul>
<li>A questionably drawn bike, in the game <a target="_blank" href="https://fake-artist-online.games.asta.uni-goettingen.de/">Fake Artist Online</a></li>
</ul>
<p>For me, it adds much more team cohesion, solidarity, and unity, and costs the same amount of time, something that is important for me working remotely.</p>
<p>We currently rotate on the following games:</p>
<ul>
<li><p><a target="_blank" href="https://skribbl.io/">https://skribbl.io/</a></p>
</li>
<li><p><a target="_blank" href="https://www.spyfall.app/">https://www.spyfall.app/</a></p>
</li>
<li><p><a target="_blank" href="https://fake-artist-online.games.asta.uni-goettingen.de/">https://fake-artist-online.games.asta.uni-goettingen.de/</a></p>
</li>
<li><p><a target="_blank" href="https://avalon.fun/">https://avalon.fun/</a></p>
</li>
</ul>
<h2 id="heading-am-i-just-doing-it-wrong">Am I just doing it wrong?</h2>
<p>The standup can be more than the three famous questions:</p>
<blockquote>
<ol>
<li><p>What did I work on yesterday?</p>
</li>
<li><p>What am I working on today?</p>
</li>
<li><p>What issues are blocking me?</p>
</li>
</ol>
</blockquote>
<p>It can also be a daily reflection on the <a target="_blank" href="https://www.scrum.org/resources/what-sprint-goal">sprint goal</a>, (if you are working with sprints, and/or Scrum). We have tried to incorporate that at times, and that is obviously important too; maybe not every day but once or twice a week. So we might just be doing it wrong.</p>
<p>Once again, however, I would argue that standups aren't the ideal setting to gauge confidence due to <a target="_blank" href="https://en.wikipedia.org/wiki/Anchoring_(cognitive_bias)">anchoring bias</a>. You would have to disclose them similar to <a target="_blank" href="https://blog.airbrake.io/blog/software-development/planning-poker-avoid-bias-estimation">planning poker</a>, and if that is the case, you could just as well post a survey on Slack, of <em>"How confident are you in our ability to reach [Sprint goal]",</em> which would also give you data you can reflect on retroactively.</p>
<p><img src="https://images.unsplash.com/photo-1563986768609-322da13575f3?ixlib=rb-4.0.3&amp;ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&amp;auto=format&amp;fit=crop&amp;w=1000&amp;q=80" alt="person using phone and laptop" class="image--center mx-auto" /></p>
<p>Others would argue for an <a target="_blank" href="https://friday.app/p/asynchronous-daily-standups">asynchronous daily standup</a>, and we tried that some years ago at a place I worked, where we used a bot to prompt us. It often resulted in people simply not answering, and we rarely used much time to check out each other's answers. If a standup does add value, it does solve some of the scheduling issues you might have, and that might be a solution for you. However, my core issue is that:</p>
<ol>
<li><p>As we post a request-for-review in chat, people know when I am finishing a task.</p>
</li>
<li><p>As we always write "I am finished with X, can I help anyone with their tasks?", we know who is available, needing something to do</p>
</li>
<li><p>As the first step anyone does, when they reach a wall in any regard, is to say "I am blocked by X", or "I need someone to help pair program this with me" - we will never really be blocked by the time the standup comes around</p>
</li>
</ol>
<p>Compared to the scheduled standup, which synchronizes expectation and alignment once a day, we never really go minutes without being up to date, with relevant facts. And if I am in a state of <a target="_blank" href="https://todoist.com/inspiration/deep-work">deep focused work</a>, I don't have to be interrupted by a team huddle.</p>
<h2 id="heading-are-standups-worthless">Are standups worthless?</h2>
<p>Probably not. As with <em>actual</em> Agile teams, it's not a matter of doing a specific set of steps, but rather <a target="_blank" href="https://www.goodreads.com/book/show/67833.Extreme_Programming_Explained">embracing change</a> and adapting processes for the team, rather than adapting the team around certain processes. When improving communication and transparency, standups are a great formal way of getting on the same page and having a safe space to pose questions to a relevant stakeholder or a coworker, and it can be the correct step on a ladder of progress. I am simply arguing that it might not be the final step for every team.</p>
<p>I mentioned it internally at the consultancy I work at, and we have changed it into 2 standups per week (and 2 days of gaming). Despite these adjustments, I personally still don't perceive the added value from the two internal standups, however, it does add value for some coworkers; and as long as that is the case I happily comply. Nevertheless, if your team is open to trying out new approaches and you share my sentiments, then why not try a sprint without one?</p>
]]></content:encoded></item><item><title><![CDATA[Code vs. Cells]]></title><description><![CDATA[Motivation
I like Domain-driven design, and seeing how to utilize it. A fun exercise is trying to model everyday problems while building them test driven. I've started doing that with simple problems I would previously have solved with a spreadsheet ...]]></description><link>https://blog.cwb.dk/code-vs-cells</link><guid isPermaLink="true">https://blog.cwb.dk/code-vs-cells</guid><category><![CDATA[Scripting]]></category><category><![CDATA[#Domain-Driven-Design]]></category><category><![CDATA[DDD]]></category><category><![CDATA[Python]]></category><category><![CDATA[excel]]></category><dc:creator><![CDATA[Casper Weiss Bang]]></dc:creator><pubDate>Thu, 08 Jun 2023 12:15:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1686226283587/5a72b35b-8b0f-43a3-a2ca-e6c1bd62468e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-motivation">Motivation</h2>
<p>I like <a target="_blank" href="https://en.wikipedia.org/wiki/Domain-driven_design">Domain-driven design</a>, and seeing how to utilize it. A fun exercise is trying to model everyday problems while building them test driven. I've started doing that with simple problems I would previously have solved with a spreadsheet (i.e. <a target="_blank" href="https://www.google.com/sheets/about/">Google Sheets</a>). It's great for learning, and I've realized I get a better result.</p>
<h2 id="heading-calculating-velocity">Calculating velocity</h2>
<p>I have on multiple occasions acted as <a target="_blank" href="https://www.scrum.org/resources/what-is-a-scrum-master">Scrum Master</a> (I'd argue I haven't run scrum, nor <a target="_blank" href="https://www.youtube.com/watch?v=hxXmTnb3mFU&amp;t=448s">that I want to</a>), and the question of velocity comes up. I've previously created excel sheets where each sheet was a sprint, and then I had a "front page" with the summarized calculations. It was a mess when I suddenly wanted to introduce a new datapoint, or reformat a given page - as references to specific cells would suddenly be broken. It was a mess.</p>
<p>Instead, I created Sprinthon. It's a very simple Python tool - Utilizing <a target="_blank" href="https://pydantic.dev/">Pydantic</a> I was able to fletch out the domain model rather quickly. A sprint simply consists of:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> pydantic <span class="hljs-keyword">import</span> BaseModel, validator

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SprintScope</span>(<span class="hljs-params">BaseModel</span>):</span>
    initial: Optional[StoryPoints]
    final: Optional[StoryPoints]
    burned: Optional[StoryPoints]

<span class="hljs-meta">    @property</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">growth</span>(<span class="hljs-params">self</span>) -&gt; Goal:</span>
        <span class="hljs-keyword">if</span> self.final <span class="hljs-keyword">and</span> self.initial:
            <span class="hljs-keyword">return</span> self.final - self.initial

        <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span>

<span class="hljs-meta">    @property</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">spillover</span>(<span class="hljs-params">self</span>) -&gt; Goal:</span>
        <span class="hljs-keyword">if</span> self.final <span class="hljs-keyword">and</span> self.burned:
            <span class="hljs-keyword">return</span> self.final - self.burned

        <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span>


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Sprint</span>(<span class="hljs-params">BaseModel</span>):</span>
    number: int
    scope: Optional[SprintScope] = <span class="hljs-literal">None</span>
</code></pre>
<p>And suddenly I had a list of sprints:</p>
<pre><code class="lang-python">sprints = [
    Sprint(
        number=<span class="hljs-number">2</span>,
        scope=SprintScope(
            initial=<span class="hljs-number">50</span>,
            final=<span class="hljs-number">55</span>,
            burned=<span class="hljs-number">45</span>,
        ),
        workdays=<span class="hljs-number">5</span>,
    ),
    Sprint(
        number=<span class="hljs-number">1</span>,
        scope=SprintScope(
            initial=<span class="hljs-number">60</span>,
            final=<span class="hljs-number">61</span>,
            burned=<span class="hljs-number">55</span>,
        ),
        workdays=<span class="hljs-number">5</span>,
    ),
]
</code></pre>
<p>And getting any sort of statistics out of this is pretty trivial. The average burned story points are pretty easy to get:</p>
<pre><code class="lang-python">avg_burned = avg(sprint.scope.burned <span class="hljs-keyword">for</span> sprint <span class="hljs-keyword">in</span> sprints <span class="hljs-keyword">if</span> sprint.scope),
</code></pre>
<p>One could easily make it a <a target="_blank" href="https://en.wikipedia.org/wiki/Moving_average">Rolling average</a> or something more complex if wanted.</p>
<p>Furthermore, I realized I'd want to add <code>working_days</code> to the model after we had a sprint that was partly swallowed by vacations. Easy to add to the model:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Sprint</span>(<span class="hljs-params">BaseModel</span>):</span>
    number: int
    workdays: float | <span class="hljs-literal">None</span> = <span class="hljs-literal">None</span>
    scope: Optional[SprintScope] = <span class="hljs-literal">None</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_daily_velocity</span>(<span class="hljs-params">self</span>) -&gt; float | <span class="hljs-keyword">None</span>:</span>
        <span class="hljs-keyword">if</span> self.workdays <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span> <span class="hljs-keyword">or</span> self.scope <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span> <span class="hljs-keyword">or</span> self.scope.burned <span class="hljs-keyword">is</span> <span class="hljs-literal">None</span>:
            <span class="hljs-keyword">return</span> <span class="hljs-literal">None</span>

        <span class="hljs-keyword">return</span> round(self.scope.burned / self.workdays, <span class="hljs-number">2</span>)
</code></pre>
<p>By allowing optional fields, I can easily enforce various backward and future-proofing, and having an IDE, I can easily update the sprints that don't conform. By writing a few unit tests it is easy to validate that my results are what I expect:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_has_daily_velocity</span>(<span class="hljs-params">some_sprint: Sprint</span>):</span>
    some_sprint.scope.burned = <span class="hljs-number">10</span>
    some_sprint.workdays = <span class="hljs-number">5</span>

    <span class="hljs-keyword">assert</span> some_sprint.get_daily_velocity() == <span class="hljs-number">2</span>
</code></pre>
<p>I ended up extending it to create a <code>MarkdownWriter</code> which means I can export a report of the sprints, which I can convert to PDF or whatever I'd want. That would have been a lot more work in a spreadsheet.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>I often forget how easy it is to write code. I often forget how much I enjoy writing code. By using scripting languages (I also wrote a similar tool for another purpose in F#), I can easily help automate the boring stuff. It might be what <a target="_blank" href="https://automatetheboringstuff.com/">Automate The Boring Stuff With Python</a> argues as well. But it's quite neat - and by making micro tools they might grow into an open-source package that can help others.</p>
<p>Worst case, you've solved your problem and improved your coding and problem-solving skills in the process.</p>
]]></content:encoded></item><item><title><![CDATA[Yes, IO is possible in a functional world]]></title><description><![CDATA[Whenever I share my enthusiasm regarding functional programming and pure functions, other developers are often skeptical, and I've heard the following point possibly a million times:

Functional programming might be cool in academic contexts, but in ...]]></description><link>https://blog.cwb.dk/yes-io-is-possible-in-a-functional-world</link><guid isPermaLink="true">https://blog.cwb.dk/yes-io-is-possible-in-a-functional-world</guid><category><![CDATA[Functional Programming]]></category><category><![CDATA[io]]></category><category><![CDATA[F#]]></category><category><![CDATA[pure functions]]></category><category><![CDATA[Clean Architecture]]></category><dc:creator><![CDATA[Casper Weiss Bang]]></dc:creator><pubDate>Sat, 12 Nov 2022 18:22:30 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/OUgLA2unwtg/upload/v1668264678263/dnBLCouDQ.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Whenever I share my enthusiasm regarding functional programming and pure functions, other developers are often skeptical, and I've heard the following point possibly a million times:</p>
<blockquote>
<p>Functional programming might be cool in academic contexts, but in the real world, you need side effects! Or are you simply not going to have databases or user input? Good job writing your useless code!</p>
</blockquote>
<p>It's cute. It's also misinformed. It's like saying:</p>
<blockquote>
<p>So a jigsaw is your favorite tool? Good luck getting a nail into a wall with a jigsaw</p>
</blockquote>
<p>So if you would argue the same, then I am here to help you and possibly enlighten you. If you already know, you are welcome to share this with people who don't.</p>
<h2 id="heading-pure-domain-logic">Pure domain logic</h2>
<p>The trick is to isolate your IO side effects.</p>
<p><img src="https://media2.giphy.com/media/Xg5qpmzzzp10rt01l0/giphy.gif?cid=ecf05e47ex55hl9lp523p81rnfaa5d3fdrdiyz1fekwfdh2x&amp;rid=giphy.gif&amp;ct=g" alt="A gif of the annoying reading saying gotcha" class="image--center mx-auto" /></p>
<p>I still have side effects then - I can hear you yell at your screen.</p>
<p>Well, back in my Advanced Programming course our professor had a great point:</p>
<blockquote>
<p>You can write a functional and pure framework, [enforcing/enabling only pure code], without the actual implementation thereof being functional</p>
</blockquote>
<p>You still need to know which parts can contain IO and which cannot. <a target="_blank" href="https://www.haskell.org/tutorial/io.html">Haskell has a great language construct for exactly this</a>. In other languages, you are left with discipline and (possibly) doing some code analysis (maybe? I am not aware of any tools, but it'd be cool).</p>
<p>That might sound abstract so let's get down to something more concrete.</p>
<h2 id="heading-side-effects-in-my-project">Side effects in my project</h2>
<p>As noted <a target="_blank" href="https://blog.cwb.dk/series/fanban">I'm working on creating a micro-service kanban board</a> - and here I'll obviously also have IO. I need to save when a new <a target="_blank" href="https://www.atlassian.com/agile/kanban/cards">card</a> is created or moved or well any change to the state.</p>
<p>So how do we do that?</p>
<p>Let's step back for a second. When writing applications, I (often) follow the <a target="_blank" href="https://blog.ploeh.dk/2013/12/03/layers-onions-ports-adapters-its-all-the-same/">onion architecture / ports and adapters / clean architecture</a>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668265408369/J7ISpavHj.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Essentially dependencies (etc) should only go one way. You should be able to change the database technology, or web stack without changing a single line of code within your domain model.</p>
<p>And here I personally have a very strict perspective on my domain model. All the code in my domain should be completely side-effect free.</p>
<p>That means whenever a function modifies a kanban board, it will not modify the instance but rather return a new one. I.e adding a card to the board is a function like this:</p>
<pre><code class="lang-fsharp"><span class="hljs-keyword">let</span> SetBoardName (newName: Name) (this: Board) = { this <span class="hljs-keyword">with</span> Name = newName }
</code></pre>
<p><em>The</em> <code>Name</code> type here is a <a target="_blank" href="https://en.wikipedia.org/wiki/Value_object">Value Object</a> that ensures that it's not a non-empty string, and not too long)</p>
<p>The above function is of type <code>Name -&gt; Board -&gt; Board</code> - It's a function that takes a Name and then returns a new function that takes a board and returns another. This is a general functional concept called <a target="_blank" href="https://en.wikipedia.org/wiki/Partial_application">Partial Application</a>. We can then use it like this:</p>
<pre><code class="lang-fsharp"><span class="hljs-keyword">let</span> WithBoardName (newName: Name) (this: Board) = { this <span class="hljs-keyword">with</span> Name = newName }
<span class="hljs-keyword">let</span> WithBoardNameMyBoard = WithBoardName <span class="hljs-string">"My Board"</span>

<span class="hljs-comment">// We can then use it:</span>
<span class="hljs-keyword">let</span> myBoard = withBoardNameMyBoard yourBoard
</code></pre>
<p><em>👻 spooky F# where I stole your board</em></p>
<p>This doesn't affect the <code>yourBoard</code>, but simply copies the content to <code>myBoard</code></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668272580900/03Zx61ceb.png" alt="image.png" class="image--center mx-auto" /></p>
<p>Anyway, that's an aside. Back to the topic. The domain and any processes in the domain remain pure - no side effects or anything.</p>
<h2 id="heading-accessing-a-database">Accessing a database</h2>
<p>But this doesn't write nor fetch anything to/from any database. So how do we actually do that? We accept impurities in the outer layers.</p>
<p>I've simplified how the actual API looks, and only focused on the actual logic of the endpoint, however, it presents the concept:</p>
<pre><code class="lang-fsharp"><span class="hljs-keyword">let</span> repository = InMemoryBoardRepository()

<span class="hljs-keyword">let</span> setNameEndpoint (payload : SetNamePayload) = 
  <span class="hljs-keyword">let</span> board = repository.Get payload.BoardId
  <span class="hljs-keyword">let</span> updatedBoard = withBoardName payload.NewName board
  repository.Write payload.BoardId updatedBoard

  Ok200 ()
</code></pre>
<p>Oh no! we have a side-effect in our API. But it's isolated, and it's very very localized.</p>
<p>Btw this is how the Repository looks:</p>
<pre><code class="lang-fsharp"><span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">InMemoryBoardRepository</span></span>() =
    <span class="hljs-keyword">let</span> boards = Dictionary&lt;BoardId, Board&gt;()
    <span class="hljs-keyword">member</span> this.GetAll() = boards.Values |&gt; seq

    <span class="hljs-keyword">member</span> this.Get(boardId: BoardId) =
        boards[boardId]

    <span class="hljs-keyword">member</span> this.Write(board: Board) 
        <span class="hljs-comment">// this just writes the value to the entry in the dictionary</span>
        boards[board.Id] &lt;- board
</code></pre>
<p>Yes, it has side effects, and anything that uses it will therefore also become tainted and unpure. But we can localize it and track it through dependencies. and we can keep the usage to a minimum.</p>
<p>Furthermore, this pattern of "getting, updating, saving", is something we'll probably do quite a lot, we can abstract it away and add it to our Board Repository:</p>
<pre><code class="lang-fsharp"><span class="hljs-class"><span class="hljs-keyword">type</span> <span class="hljs-title">InMemoryBoardRepository</span></span>() =
    <span class="hljs-keyword">let</span> boards = Dictionary&lt;BoardId, Board&gt;()
    <span class="hljs-keyword">member</span> this.GetAll() = boards.Values |&gt; seq

    <span class="hljs-keyword">member</span> this.Get(boardId: BoardId) =
        boards[boardId]

    <span class="hljs-keyword">member</span> this.Write(board: Board) =
        boards[board.Id] &lt;- board

    <span class="hljs-keyword">member</span> this.Update(mapper: Board -&gt; Board) (boardId: BoardId) =
        <span class="hljs-keyword">let</span> board = this.Get boardId
        this.Write (mapper board)
</code></pre>
<p>Which makes our code even simpler, and moves all the side effects into one place, leaving just this one expression in our API.</p>
<pre><code class="lang-fsharp"><span class="hljs-keyword">let</span> repository = InMemoryBoardRepository()

<span class="hljs-keyword">let</span> setNameEndpoint (payload : SetNamePayload) = 
  <span class="hljs-keyword">let</span> partialFunction =withBoardName payload.NewName
  repository.Update partialFunction payload.BoardId
</code></pre>
<p>(Partial application became relevant after all! woo!)</p>
<p><img src="https://media1.giphy.com/media/p8GJOXwSNzQPu/giphy.gif?cid=ecf05e47su6mo54jl1bb5xfrj5nlzckwtp9o261b2dhnh2a7&amp;rid=giphy.gif&amp;ct=g" alt="Gif of women saying that it's so beautiful" class="image--center mx-auto" /></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Yes, you will need side effects. But by keeping your domain pure you improve testability, readability, and a wide range of other -ilities. By centralizing your side effects you are able to do more heavy testing here while keeping the side effects as simple as possible, making the code much easier to reason about, and much less error-prone - And as our outer layer (application layer, data access, integrations) should be quite simple and very thin it should be very localized.</p>
<p>I hope the F#-parts didn't pose big readability challenges. After a few weeks, I promise it'll read like beautiful prose.</p>
<p>The next step would be to define our API simply by writing different <code>Board -&gt; Board</code> functions. Let's discuss that in a future post.</p>
]]></content:encoded></item><item><title><![CDATA[Searching for third-party details in a microservice architecture]]></title><description><![CDATA[Motivation
When you are developing a domain model, you want it to be as concise as possible - only containing abstractions related to the problem you are trying to model. This, however, can become an impediment if you want to expose a search engine w...]]></description><link>https://blog.cwb.dk/searching-for-third-party-details-in-a-microservice-architecture</link><guid isPermaLink="true">https://blog.cwb.dk/searching-for-third-party-details-in-a-microservice-architecture</guid><category><![CDATA[F#]]></category><category><![CDATA[Microservices]]></category><category><![CDATA[DDD]]></category><category><![CDATA[architecture]]></category><dc:creator><![CDATA[Casper Weiss Bang]]></dc:creator><pubDate>Thu, 27 Oct 2022 18:36:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1664817007866/rwjB0razd.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-motivation">Motivation</h2>
<p>When you are developing a <a target="_blank" href="https://en.wikipedia.org/wiki/Domain_model">domain model</a>, you want it to be as concise as possible - only containing abstractions related to the problem you are trying to model. This, however, can become an impediment if you want to expose a search engine where you can input any string, and gets any match back, even on information that is only indirectly related to your model - How does your service know if a match exists, if the info isn't directly stored in your domain model?</p>
<p>This exact case was something we experienced at my prior place of employment, and a coworker(I miss you!) and I came up with a great solution. I'll eventually reuse it in my <a target="_blank" href="https://blog.cwb.dk/series/fanban">Kanban project</a> project and wanted to explain how it works.</p>
<h2 id="heading-the-core-problem">The core problem</h2>
<p>I want to be able to search for one or more search terms and get <a target="_blank" href="https://kanbanize.com/kanban-resources/getting-started/what-is-kanban-card">Cards</a> back that match the search terms.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665900545294/V2x8x--sh.png" alt="very simple domain model simply containing a card with a title, description and author identifier" class="image--center mx-auto" /></p>
<p>One might search for word(s) that is contained in the title of the card. This is easy to implement, as the title is part of our domain - our API will simply return any matches that contain that string. What if we want to search for the name of the author? Our system is going to use a third-party authorization provider. That means the microservice won't actually know the name of the author. They'll simply know that the author is a user with id <code>75adff81-269e-412c-a1c8-fbbfb998b5e8</code>. </p>
<h3 id="heading-user-story">User story</h3>
<blockquote>
<p>When I search for a full or subpart of an author's name or part of a title, I want all cards that match all query terms, so I can find the cards I am looking for</p>
</blockquote>
<h2 id="heading-bad-solutions">Bad solution(s)</h2>
<p>You can skip this part if you just want our solution.</p>
<h3 id="heading-growing-your-domain-model">Growing your domain model</h3>
<p>You could simply argue "Well maybe the author's name is part of the domain model!". But where does that logic end? We'll quickly have to model things only indirectly related. What if we create custom integrations with different version control systems, and want to enable searching on pull-request names (or descriptions)? Are they then also part of the domain? Suddenly your domain is growing and coupled with the models of third-party systems. More coupling. More to maintain. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665900483545/YJ7asQFvV.png" alt="A domain model with dependencies on both pullrequest, documentation, author etc" class="image--center mx-auto" /></p>
<p>We'll also have to update our domain model whenever the code of third-party systems changes (which is bad for a number of reasons. Go read the <a target="_blank" href="https://www.goodreads.com/book/show/179133.Domain_Driven_Design">DDD book</a>). There will be large data movements all the time.</p>
<p><img src="https://media4.giphy.com/media/YGlRW1Am9q7e0/giphy.gif?cid=ecf05e47girzc7swsy18rc1aal6sqawfj3c1fbjx0k21rned&amp;rid=giphy.gif&amp;ct=g" alt="Gif where someone is moving a big part of a physical library to some other place as a metaphor" class="image--center mx-auto" /></p>
<h3 id="heading-transient-requests">Transient requests</h3>
<p>Rather than bringing third-party systems to us, we could bring the query to the third party.</p>
<p>Upon receiving a query request, we simply query all the third-party systems and then use that to filter the cards. Or simply go through each card and fetch the author (etc) and check if it's a match. Yes, some requests will be done a bunch of times, but we could always use caching.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665899781976/8ONslnIiO.png" alt="transient request where we request a variety of systems" class="image--center mx-auto" /></p>
<p>Great! our domain model is quite pure. But wait. One of the many requests to the third-party systems suddenly throws an error.. and the whole search fails.</p>
<p><img src="https://media0.giphy.com/media/zFb4l4CvD4MOQ/giphy.gif?cid=ecf05e47eq2ziwih77556zk1dk0f9cn7v0gedw7oic1zdthh&amp;rid=giphy.gif&amp;ct=g" alt="domino pieces falling" class="image--center mx-auto" /></p>
<p>The issue above is also that the system's ability to do searching suddenly is coupled directly with the availability of the third-party system. What if it's down? what if our cache is cold? We might end up DDoS'ing the third-party system if we have enough different cards. They might also not appreciate it. There is also the whole thing that the requests will be rather slow. </p>
<p>Code Opinion had a great video that is related (mainly the part about queries):</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/4HGsmDuxvWc?t=226">https://youtu.be/4HGsmDuxvWc?t=226</a></div>
<p>Transient requests are generally speaking not the best in microservice architectures.</p>
<p>Another issue is where to place this logic. Suddenly either the repository will have dependencies on a bunch of third-party systems, or you have to move searching into a service of sorts. It has a bunch of problems. </p>
<h3 id="heading-a-good-solution">A Good solution.</h3>
<p>This might not be the ideal solution, and I'd love to hear a comment down below if I missed something, or if one of the other solutions is better. </p>
<p>Going back to the user story. It contains a term that I want to add to our <a target="_blank" href="https://thedomaindrivendesign.io/developing-the-ubiquitous-language/">ubiquitous language</a>: <em>keyword</em>. Rather than storing specific pieces of data, what we really care about is that some card matches some keyword.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665900710527/jsc-7_njt.png" alt="a domain model where Card only relates to one object; keyword" class="image--center mx-auto" /></p>
<p>This makes it easier to reason about searching in our domain because it's less tightly bound to any specific third-party model. That an actual list of keywords might include the name of the author isn't something our model necessarily cares about. </p>
<p>These keywords, however, have to be created. For that, we need a function (or interface if you have a OO language - <a target="_blank" href="https://blog.ploeh.dk/2014/03/10/solid-the-next-step-is-functional/">it's the same</a>). We called this concept a <em>keyword provider</em>.</p>
<pre><code class="lang-fsharp">type KeywordProvider = Card -&gt; Keyword list
</code></pre>
<p>This gives us the benefit of being able to split the different keywords up into different chunks of code. We can create a very simple keyword provider, that gives us the keywords that reside in the domain:</p>
<pre><code class="lang-fsharp">let DomainKeywordProvider card = [
    Keyword (card.Id.ToString ()); 
    Keyword card.Title; 
    Keyword card.Description
  ]
</code></pre>
<p>(I hope F# isn't too scary. this is just a function that takes a card as input and returns a list of keywords.)</p>
<p>What we will eventually have is a wide range of different KeywordProviders. Some that fetch from our Auth system. Maybe from Github. What do I know? It's quite easy to create new ones. But then eventually we want to get all keywords for a given card, from all sources. For that, we can define a <code>CompositeKeywordProvider</code>:</p>
<pre><code class="lang-fsharp">let CompositeKeywordProvider (providers : KeywordProvider list) (card : Card) = 
    providers |&gt; List.collect (fun provider -&gt; provider card)
</code></pre>
<p>(👻 scary F#: It takes a list of KeyWordProviders and returns a function that takes a card and returns the keywords all the keyword providers return for that card)</p>
<p>Which can then be used like this (Assume we also defined an AuthorKeywordProvider):</p>
<pre><code class="lang-fsharp">let provider = CompositeKeywordProvider [
    DomainKeywordProvider; 
    AuthorKeywordProvider
  ]
</code></pre>
<p>We now need to call this provider. But how/where? If we simply call it whenever we get a request (i.e edit a card), that won't do. We are back at the same issues with the transient requests.</p>
<p><img src="https://media.giphy.com/media/HPA8CiJuvcVW0/giphy.gif" alt="dominos falling" class="image--center mx-auto" /></p>
<p>We instead created an asynchronous worker that fetches keywords. This decoupled the generating of keywords from both writing data as well as searching.</p>
<p>This isn't enough, as the third-party data might change without us knowing. A user might change their name, which will then create inconsistencies. We decided on accepting a model based on <a target="_blank" href="https://en.wikipedia.org/wiki/Eventual_consistency">Eventual consistency</a>.</p>
<p><img src="https://media.giphy.com/media/3o6Zt2v4kF6cDFspby/giphy.gif" alt="Gif of someone saying we'll eventually get there" class="image--center mx-auto" /></p>
<p>The icing on the cake was to utilize a <a target="_blank" href="https://en.wikipedia.org/wiki/Decorator_pattern">decorator pattern</a>, which triggered the keyword worker whenever a card changed. This made it possible to instantly search for anything you just created.</p>
<p>One might also want any changes to third-party data to instantly be reflected in searches, however, this is less critical in our cases. If it was a big issue, one would have to have an event-driven architecture throughout the ecosystem - that would enable us to run the keyword worker whenever a "user name updated" event was sent. We didn't have such an event-driven architecture and settled on updating the keywords based on a scheduled job.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Is this the best solution? not sure. It solved the problems we had and enabled us to have a great user interface with search functionality. From a development perspective, it's easier to add support for new keywords. When we expanded our domain model, it was easy to add more searching too. We and the stakeholders were happy (I was a bit proud), and it helped evolve the ubiquitous language and model to add the keyword concept. </p>
<h2 id="heading-edit">Edit:</h2>
<p>I shared the article with one of my smart friends. He pointed out that, what we ended up building was basically a <a target="_blank" href="https://en.wikipedia.org/wiki/Search_engine_indexing">Search indexing engine</a>. In that terminology, we should not use the term /keyword/ but rather /index/. We could refactor it. That would probably be the right thing to do. Whether you want to do that, is up to you.</p>
]]></content:encoded></item><item><title><![CDATA[Configuring Zsh to my liking]]></title><description><![CDATA[Motivation
I've recently started a new job, with Pop!_OS rather than Windows (yay!). After a year without using Linux day to day, I wanted to reinstall a bunch of things, one of them being zsh, my shell of choice, with Oh My Zsh and Powerline10k. 
Wh...]]></description><link>https://blog.cwb.dk/configuring-zsh-to-my-liking</link><guid isPermaLink="true">https://blog.cwb.dk/configuring-zsh-to-my-liking</guid><category><![CDATA[zsh]]></category><category><![CDATA[oh-my-zsh]]></category><category><![CDATA[Linux]]></category><category><![CDATA[setup]]></category><dc:creator><![CDATA[Casper Weiss Bang]]></dc:creator><pubDate>Sat, 01 Oct 2022 07:58:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1664611084798/vACgRROJ-.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-motivation">Motivation</h2>
<p>I've recently started a new job, with <a href="https://pop.system76.com/">Pop!_OS</a> rather than Windows (yay!). After a year without using Linux day to day, I wanted to reinstall a bunch of things, one of them being <a href="https://en.wikipedia.org/wiki/Z_shell">zsh</a>, my shell of choice, with <a href="https://ohmyz.sh/">Oh My Zsh</a> and <a href="https://github.com/romkatv/powerlevel10k">Powerline10k</a>. </p>
<p>Why?</p>
<p>It adds a bunch of features to the shell that I like:</p>
<ul>
<li>Seeing my current branch</li>
<li>Easier ways to search through history</li>
<li>Better auto completion.</li>
<li>sexiness</li>
</ul>
<p>It might, however, impact performance compared to a clean installation of i.e bash. I don't care about speed. </p>
<h2 id="heading-solution">Solution</h2>
<h3 id="heading-installing-zsh">Installing: ZSH</h3>
<p>Instaling:</p>
<pre><code class="lang-sh">sudo apt install zsh
</code></pre>
<p>Setting it as a default terminal: </p>
<pre><code class="lang-sh">chsh -s /usr/bin/zsh
</code></pre>
<p>Now reboot so the shell is changed everywhere. </p>
<p>You will now be prompted for some fault settings. They aren't super important, but you can tweak it to your needs. I went through it.</p>
<h3 id="heading-installing-oh-my-zsh">Installing: Oh My Zsh</h3>
<pre><code class="lang-sh">sh -c <span class="hljs-string">"<span class="hljs-subst">$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)</span>"</span>
</code></pre>
<p>Woo! it's now installed. I have a bunch of configurations i'd want to include. You can see my config at the end of this post.</p>
<h3 id="heading-installing-powerline10k">Installing: Powerline10K</h3>
<pre><code class="lang-sh">git <span class="hljs-built_in">clone</span> --depth=1 https://github.com/romkatv/powerlevel10k.git <span class="hljs-variable">${ZSH_CUSTOM:-<span class="hljs-variable">$HOME</span>/.oh-my-zsh/custom}</span>/themes/powerlevel10k
</code></pre>
<p>Install the relevant fonts following the guide <a href="https://github.com/romkatv/powerlevel10k#meslo-nerd-font-patched-for-powerlevel10k">here</a>. </p>
<p>Change the font in what ever terminal you are using (if gnome terminal, click the burger menu in the top right, go to profiles.. change font)</p>
<p>Then change the theme by changing the <code>ZSH_THEME</code> line to <code>ZSH_THEME="powerlevel10k/powerlevel10k"</code> in your zsh config file (<code>~/.zshrc</code>)</p>
<p>then run <code>source ~/.zshrc</code>(or restart your terminal)</p>
<p>Go through the configuration wizard (you can always open it with <code>p10k configure</code>) and there you go.</p>
<h3 id="heading-plugins-ive-installed">Plugins i've installed:</h3>
<ul>
<li><a href="https://github.com/zsh-users/zsh-autosuggestions">Zsh autosuggestions</a></li>
<li><a href="https://github.com/MichaelAquilina/zsh-autoswitch-virtualenv">Autoswitch Python Virtualenv</a></li>
</ul>
<h2 id="heading-summary">Summary</h2>
<p>The installation process was fairly easy by simply following the guides on the projects, but sometimes they can be more difficult. I've mainly written this as a reminder for the future. </p>
]]></content:encoded></item><item><title><![CDATA[Strongly typed Id in f#]]></title><description><![CDATA[Motivation
Way too often I see code where someone defines an id as a simple int or Guid or something along those lines. This is a classic case of the Primitive Obsession smell and has a variety of potential problems, as well as may pollute your code ...]]></description><link>https://blog.cwb.dk/strongly-typed-id-in-f</link><guid isPermaLink="true">https://blog.cwb.dk/strongly-typed-id-in-f</guid><category><![CDATA[F#]]></category><category><![CDATA[DDD]]></category><category><![CDATA[Functional Programming]]></category><dc:creator><![CDATA[Casper Weiss Bang]]></dc:creator><pubDate>Tue, 13 Sep 2022 08:21:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/unsplash/D44kHt8Ex14/upload/v1664626407474/zQH-qwTKq.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-motivation">Motivation</h2>
<p>Way too often I see code where someone defines an id as a simple <code>int</code> or <code>Guid</code> or something along those lines. This is a classic case of the <a target="_blank" href="https://blog.ploeh.dk/2011/05/25/DesignSmellPrimitiveObsession/">Primitive Obsession</a> smell and has a variety of potential problems, as well as may <a target="_blank" href="https://www.youtube.com/watch?v=9cr7grNWn6c">pollute your code with Guard clauses</a>. </p>
<p>I am in the process of trying to create a Kanban board to explore <a target="_blank" href="https://martinfowler.com/eaaDev/EventSourcing.html">Event Sourcing</a> and <a target="_blank" href="https://en.wikipedia.org/wiki/Domain-driven_design">Domain-Driven Design</a> and learn F#. Here I need an Id on my <code>Board</code> type, to put on Events and pass around. </p>
<h3 id="heading-in-depth-motivation">In-depth motivation</h3>
<p>You might be able to skip this part. These are just my personal key points from the articles linked above. Reasons to have a type-strong id:</p>
<ul>
<li>You don't want to be able to pass a <code>ColumnId</code> in a context where a <code>BoardId</code> is required.</li>
<li>Whether a <code>BoardId</code> is a <code>Guid</code>, <code>int</code>, <code>string</code>, or something else, is an implementation detail. Any consumer of the domain doesn't need/want to know. </li>
<li><p>It improves readability. It's quite obvious what kind of Id a method takes if it is strongly typed. </p>
</li>
<li><p>If it's an int, you probably don't want to allow a negative integer. Moving this validation into a <code>BoardId</code> type is nice.</p>
</li>
</ul>
<h2 id="heading-the-solution">The Solution</h2>
<h3 id="heading-initial-wrong-solution">Initial (WRONG) solution</h3>
<p>I initially expected to be able to do this. </p>
<pre><code class="lang-f#">type BoardId = Guid
</code></pre>
<p>It seemed like it would work initially, however you can then cast them back and forth implicitly. This is simply a <a target="_blank" href="https://fsharpforfunandprofit.com/posts/type-abbreviations/">type alias</a>, which doesn't solve any problems regarding actual encapsulation, misuse or validation.</p>
<h2 id="heading-the-minimal-solution">The (Minimal) Solution</h2>
<p>After searching for some time I found <a target="_blank" href="https://stackoverflow.com/questions/56235474/strongly-typed-ids-in-f">this StackOverflow post</a></p>
<pre><code class="lang-fsharp">[&lt;Struct&gt;]
type ProductId = ProductId of Guid
</code></pre>
<h3 id="heading-the-better-solution">The (Better) Solution</h3>
<p>Improving a bit on their result (which included helper methods), I've added additional helpers and made this a bit stronger, covering the use cases that I had. </p>
<pre><code class="lang-fsharp">namespace Fanban.Domain

open System

[&lt;Struct&gt;]
type BoardId =
    private
    | BoardId of Guid

    static member New() = BoardId(Guid.NewGuid())
    static member Parse (value: string) = BoardId(Guid.Parse(value))
    static member TryParse (value: string) =
        let couldParse, result = Guid.TryParse(value)
        if couldParse then Some (BoardId result) else None
    member this.Value = let (BoardId i) = this in i
    override this.ToString() = this.Value.ToString()
</code></pre>
<p>This makes it possible to write code like:</p>
<pre><code class="lang-fsharp">let CreateBoardEvent name (columns: ColumnName list) =
    { Id = BoardId.New()
      Name = name
      ColumnNames = columns }
</code></pre>
<p>and types can define the id type very explicitly:</p>
<pre><code class="lang-fsharp">and SetBoardNameEvent =
    { BoardId: BoardId
      Name: string }
</code></pre>
]]></content:encoded></item></channel></rss>