<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Blog on Pensive Ibex</title><link>https://pensiveibex.com/blog/</link><description>Recent content in Blog on Pensive Ibex</description><generator>Hugo -- gohugo.io</generator><language>en-uk</language><managingEditor>luk@pensiveibex.com (Luk Weyens)</managingEditor><webMaster>luk@pensiveibex.com (Luk Weyens)</webMaster><lastBuildDate>Mon, 16 Feb 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://pensiveibex.com/blog/index.xml" rel="self" type="application/rss+xml"/><item><title>Irregular ramblings</title><link>https://pensiveibex.com/blog/2026/2/irregular-ramblings/</link><pubDate>Mon, 16 Feb 2026 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2026/2/irregular-ramblings/</guid><description>
<![CDATA[<p>I see everyone doing weeknotes or monthly recaps, and I want in. Except, I don&rsquo;t want to tie myself down to a weekly or monthly format, so instead, these kind of posts will just appear randomly whenever I feel I have something to say. This will just be some sort of freeform rambling. I want to lower the bar as much as I can for myself, to just write these things and talk about stuff I&rsquo;ve done, without paying too much attention to sentence structures or word count.</p>
<h3 id="hard-75">Hard 75</h3>
<p>A colleague of mine talked me into starting one of those Hard 75 challenges. The rules for this one are as follows:</p>
<ol>
<li>Write your goals down every morning</li>
<li>Lift at least 3 days a week</li>
<li>Track every workout</li>
<li>Progress every session in some way</li>
<li>Walk at least 8000 steps a day</li>
<li>Follow a clean diet (no junkfood, sweeteners, cheat meals, alcohol)</li>
<li>Only drink water, black coffee, tea, coconut water or fresh made juice</li>
<li>Progress picture once a week</li>
<li>Sleep at least 7 hours a day</li>
<li>Complete your habit tracker every day.</li>
</ol>
<p>Since I do Crossfit, points 2 through 4 are something I already did. Walking 8000 steps are easily achievable, as I also walk daily with my dog, Pedro (obligatory derpy pic). Rule 1 is something I&rsquo;ve never actively done, I have set goals for myself in the past, and I would repeat them to myself in my head. But writing them down, actually makes it more ingrained in your pattern and keeps the focus on why you&rsquo;re doing this. My personal goal for this challenge is doing a single strict Bar Muscle-up at the end.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2026/2/irregular-ramblings/pedro.png" class="lightbox">
		<img src="/blog/2026/2/irregular-ramblings/pedro_hu_8ec2f860e37c602b.png" class="center " loading="lazy">
	</a>
	
</figure></p>
<p>Honestly, what I&rsquo;ve been struggling most with is getting enough sleep. I usually wake up around 7 in the morning. Even if I went to bed at 1AM. So, I&rsquo;ve had to cut time short when meeting friends to get my hours of sleep, which is something I usually never did and just kind of sucked it up. I do feel this having a positive impact on my overall performance already.</p>
<h3 id="dungeon-crawler-carl">Dungeon Crawler Carl</h3>
<p>I&rsquo;ve been recommended <a href="https://en.wikipedia.org/wiki/Dungeon_Crawler_Carl">Dungeon Crawler Carl</a> and started the first book last week. I read the whole thing in a couple of days and highly recommend it to anyone. I&rsquo;ve sang its praises to my friends left, right and center. It&rsquo;s such a great read, without spoiling anything, Carl suddenly finds himself in a fucked up videogame world and you following along as he is trying to wrap is head around the rules of the dungeon, getting achievements, opening lootboxes and fighting mobs. The worldbuilding is more vast than you might think at first glance.</p>
<h3 id="mewgenics">Mewgenics</h3>
<p>After 15 long years, Mewgenics finally sees the light of day. Ever since it was first announced, I was hyped for more Binding of Isaac madness in a different setting. I&rsquo;ve played about 20 hours or so since release and will probably to a more in-depth review at some point. I&rsquo;ve enjoyed my run with the game a lot so far. Though Dungeon Crawler Carl is taking up more of my free time, and I genuinally find it hard to put the books down (even writing this blog post is a miracle!)</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2026/2/irregular-ramblings/mewgenics.png" class="lightbox">
		<img src="/blog/2026/2/irregular-ramblings/mewgenics_hu_ddcff90b50df943f.png" class="center " loading="lazy">
	</a>
	
</figure></p>
<h3 id="magic-the-gathering">Magic the Gathering</h3>
<p>I&rsquo;ve recently really become more invested in Magic the Gathering, since a leave of absence of almost 20 years (with maybe a tiny relapse 8-10 years ago). I have a Pauper Tournament planned this Friday with a bunch of friends, and I&rsquo;m still struggling to decide whether I&rsquo;m going to play Gruul Cascade or Rakdos Madness. Both decks are very fun to play, I&rsquo;ll probably do some more playtesting in the next couple of days and might report back on the results of the tournament.</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Irregular%20ramblings">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Earth Must Die</title><link>https://pensiveibex.com/blog/2026/2/earth-must-die/</link><pubDate>Mon, 09 Feb 2026 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2026/2/earth-must-die/</guid><description>
<![CDATA[<p>You might have heard of Size Five Games, they&rsquo;re the creators of other silly entertaining point-and-click games like <a href="https://store.steampowered.com/app/37400/Time_Gentlemen_Please_and_Ben_There_Dan_That_Special_Edition__Double_Pack/">Ben There, Dan That!</a>, <a href="https://store.steampowered.com/app/37400/Time_Gentlemen_Please_and_Ben_There_Dan_That_Special_Edition__Double_Pack/">Time Gentlemen, Please!</a> and <a href="https://store.steampowered.com/app/1060600/Lair_of_the_Clockwork_God/">Lair of the Clockwork God</a>. I played the first two ages ago, and the last one is still on my to-do list. We&rsquo;ll see when I get round to playing that one. Even though I knew the developer of Earth Must Die (even though they were still called Zombie Cow Studios back then). The reason this game got on my radar was because of the <a href="https://www.youtube.com/watch?v=RtgXzAiGw-I">pormotional trailer</a> with Alex Horne!</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2026/2/earth-must-die/alex-horne.png" class="lightbox">
		<img src="/blog/2026/2/earth-must-die/alex-horne_hu_93dd6aed720d07bf.png" class="center " loading="lazy">
	</a>
	
</figure></p>
<p>If you&rsquo;ve never heard of Alex Horne, you&rsquo;re in for a treat! He&rsquo;s the creative genius behind <a href="https://en.wikipedia.org/wiki/Taskmaster_(TV_series)">Taskmaster</a>. One of my all-time favourite shows. So when I heard he was involved in this project, I was immediately curious to see what it was all about. Alex Horne is not the only comedian who took part in voicing the characters, some other heavy-hitters also lend their voice like: Mike Wozniak, Sophie Duker and Tom Lawrinson. It was only much later I realized Ben Starr also appears in the game! Special shout-out as well to Joel Fry for voicing Vvalak and Martha Howe-Douglas for voicing Milky.</p>
<p>Truly, the voice acting in this game is absolutely stellar. The game is filled with jokes that will make you laugh out loud, or sigh in disbelief. I found the comedy in the game to be on the edge of a sword, some jokes landed very well with me, others didn&rsquo;t. The main character, Vvalak Lizardtongue, mispronounces several words, which irritated me a bit at the start. But ended up becoming the most hilarious part in the narrative. Everytime Vvalak opens his mouth, I&rsquo;m left wondering which simple-to-pronounce word will be disfigured next.</p>
<p>You play as Vvalak Lizardtongue and are followed by Milky, your milkbot, your only friend. Your milkbot companion even offers you with lore of the world you find yourself in, in the form of the Milkypedia. Some of its entries are crucial to solve puzzles in the game, but more than that I loved reading what the larger world of The Tyryth Ascendancy looks like. The game is very linear, whenever you enter a location, you can&rsquo;t leave it before solving the puzzle in that location. Which got me fooled at first. I didn&rsquo;t expect I wouldn&rsquo;t be able to freeroam, but it does give you the knowledge that you have all the tools you need to solve any puzzles that come across your path.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2026/2/earth-must-die/mayor-bentik.png" class="lightbox">
		<img src="/blog/2026/2/earth-must-die/mayor-bentik_hu_3395fc4da2e0b32e.png" class="center " loading="lazy">
	</a>
	
</figure></p>
<p>None of the puzzles are exceptionally hard. The only ones I was ever stuck on, was one were I had to repeat a certain action multiple times. Any other puzzles can be solved by logical interactions, or bruteforcing if that is your thing. There is also no inventory to work with. So everything can be solved by interacting with your environment directly. Or should I say indirectly? Vvalak dislikes touching things, so he orders Milky to interact with the world in his stead&hellip;</p>
<p>There&rsquo;s a part in Act 2 of the game, where you can pick your mission, which is the only part of the game where it isn&rsquo;t completely linear and you have some say in what you do. I haven&rsquo;t gone back to check if picking a different order has any effect, but from Vvalak&rsquo;s comments and from what I&rsquo;ve read from the developer in some other situations, I&rsquo;m sure there will be some small changes. In fact, the game gives you a beautiful illusion of agency. The decisions you make, usually make a reappearance somewhere down the line. The overall structure of the story doesn&rsquo;t change, but the flavour does. And it&rsquo;s a treat seeing the different callbacks.</p>
<p>There&rsquo;s one more thing that really stood out during my playsessions, which are the beautifully drawn art and camera angles. It&rsquo;s not your typical point-and-click adventure game, with a single fixed camera angle for every shot, but instead throws in some cinematic angles for extra effect. I guess it&rsquo;s something you don&rsquo;t see a lot because of the pixel art in other games.</p>
<p>In closing, if you&rsquo;ve liked any of Size Five Games&rsquo; previous titles, you&rsquo;re also going to like this one. If you know any of the <a href="https://www.imdb.com/title/tt39709029/fullcredits/">voice actors</a> you&rsquo;ll love recognizing their voices in this game. Be prepared for silliness and whimsy.</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Earth%20Must%20Die">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Cryptmaster</title><link>https://pensiveibex.com/blog/2026/1/cryptmaster/</link><pubDate>Sat, 31 Jan 2026 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2026/1/cryptmaster/</guid><description>
<![CDATA[<p>What do you get when you cross a dungeon crawler with a typing game? It&rsquo;s Cryptmaster! The premise is simple, you play as a party of four heroes that get resurrected by a powerful necromancer, the Cryptmaster. Your party is down in the depths of the earth and aims to reach the top.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2026/1/cryptmaster/goggo.png" class="lightbox">
		<img src="/blog/2026/1/cryptmaster/goggo_hu_4da6bfb90a338a28.png" class="center " loading="lazy">
	</a>
	
</figure></p>
<p>The visuals of this game are truly stunning. I love the sketchy black-and-white art style. Every character (even the humans) make you feel slightly awkward, slightly unnerving. It really elevates the narrative and the tone of the story. Honestly it&rsquo;s one of the key selling points for this game for me personally.</p>
<p>The core game mechanic is typing words. The only thing that deviates from this path is navigation. And because you need all lettered keys to type words, navigation is done with the arrow keys instead of the classic WASD. To be fair, it would be a pain of navigation was done through written word as well. Movement is your classic 1 block movement you see in plenty of dungeon crawlers. You do have the option of a free cam to look around. But when you leave freecam your view gets snapped back to one of the cardinal directions.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2026/1/cryptmaster/keep-off.png" class="lightbox">
		<img src="/blog/2026/1/cryptmaster/keep-off_hu_1aa293e2705f312b.png" class="center " loading="lazy">
	</a>
	
</figure></p>
<p>You start the game with just a single keyword per character to use in combat. Joro can <code>HIT</code>, Syn can <code>JAB</code>, etc&hellip; In order to unlock new actions, you have to guess the word that is obfuscated below that character. Once you&rsquo;ve guessed it, that character now obtains that skill and gives you more possibilities during combat. Letters from those words will reveal themselves be interacting with the world. And this is really where the game design aspect shines, because the whole world is built on the foundation of words and given you rewards for typing. Every enemy has a name, and once you kill them you will get rewarded with a pick of 2-3 letters from their name. If any of those letters match any of the words hidden beneath Joro, Syn, Maz or Nix then they will get revealed. Not only that, but the healthbar of an enemy IS their name. Every hit chips away letter from their name, and once you have erased their name, they die. This also applies to your own party. Once Maz takes three hits, down he goes and you&rsquo;ll have to find an altar to rez him.</p>
<p>Once you have guessed a fair amount of words for a character, they get to level up, and you can add a letter to their name! Which is such a cool mechanic. Honestly, I&rsquo;m so impressed with the systemic game design of Cryptmaster. A lot of thought and effort was put to make the typing aspect of the game feel as natural within its world as they possibly could. Apart from stealing letters from defeated foes, you can also gain letters by solving riddles, opening chests or catching fish. Unlocking some words give you new abilities, others give you some backstory of the characters.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2026/1/cryptmaster/riddle.png" class="lightbox">
		<img src="/blog/2026/1/cryptmaster/riddle_hu_47ff9747ef80f142.png" class="center " loading="lazy">
	</a>
	
</figure></p>
<p>I only got through halfway all unlockable words for each character in a single playthrough. You&rsquo;ll have to do a lot of grinding in order to unlock everything. Which isn&rsquo;t for me, the story length was fine, and I even skipped some enemies in the last level in order to finish the game. That doesn&rsquo;t mean I didn&rsquo;t enjoy the game, but it does get stale a little too fast? Combat is dynamic in that every other enemy blocks a certain letter, or gets buffed when a certain letter is typed. Which forces you to use other skills, than the standard set you&rsquo;re used to using. Instead of a challenge, this felt to me like a bother. There&rsquo;s no way I can remember the 10+ skills of every character I had unlocked near the end, and instead of using my favourite set of abilities and rotate between them, I had to spend my time looking through every character&rsquo;s abilities in order to find a new ability that wouldn&rsquo;t screw anything up. This takes you out of the action of combat and slows things down. Really what it does is throwing the tension of combat out of the window, while you&rsquo;re flicking through a dictionary of words in order to find the one that is valid to use.</p>
<p>I&rsquo;m somewhat torn about commenting on the writing, because I really liked it. But some points of the story structure I didn&rsquo;t really like. Every spoken line is great, I love how the Cryptmaster disses your party. When I tried to improvise and do an action without the game prompting me to take that action, then the Cryptmaster would make a comment about it like: &ldquo;Speak? You won&rsquo;t speak, unless I allow you to.&rdquo; He&rsquo;s a witty character who really likes to make sarcastic observations about what you are doing as a player. And these comments really hit. But, then there&rsquo;s the story, the Cryptmaster wants to reach the surface, and because you have been reanimated by the Cryptmaster, you&rsquo;re forced to go along with it. At some point in Act 3, you&rsquo;re talking to a countess and you&rsquo;re sent on a fetch quest before you are granted passage. This bit of the story really made me feel like it didn&rsquo;t quite hit home. Maybe a different structure could have been set up, because it fell kind of flat here.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2026/1/cryptmaster/whatever.png" class="lightbox">
		<img src="/blog/2026/1/cryptmaster/whatever_hu_3920db6a17220406.png" class="center " loading="lazy">
	</a>
	
</figure></p>
<p>What is an RPG without a great card game? Cryptmaster has it, and I really liked it! You can invite people to play cards with it, by saying its name <code>WHATEVER</code> in conversation. Which prompts a lot of funny responses. The game itself is very straightforward. You draw four cards and pick a set of two connected letters in the bar below it. If any of these letters appear on any of your cards, their attack is triggered. When you complete a card, its ability is triggered and the card will be replaced with a new one. The black letters in the bar are wild and will change every turn. The premise is so very simple, and the game is that hard to win, but I have spent more time than I should have playing this game-in-a-game.</p>
<p>If you&rsquo;re interested this game is available on Steam, GOG and itch.io (as well as Xbox and Playstation, but a physical keyboard is somewhat of a must). Go check it out!</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Cryptmaster">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>How did you become who you are</title><link>https://pensiveibex.com/blog/2025/6/how-did-you-become-who-you-are/</link><pubDate>Mon, 09 Jun 2025 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2025/6/how-did-you-become-who-you-are/</guid><description>
<![CDATA[<p>A friend of mine hit me with a question a couple of days ago. I don&rsquo;t quite remember how it came up, but the question was: <em>&ldquo;Do you know how the stuff that happened in your childhood influenced how you became the person you are today?&rdquo;</em></p>
<p>This is such an important question that tells so much about who you are and what your stance in life is. It explains your struggles, your triumphs, and also how you interact with others, especially your own children. I believe everyone should at least think about this question, it might enlighten some aspects of your life of which you didn&rsquo;t know they were rooted in your childhood. Here&rsquo;s my story.</p>
<p>As a kid my parents quickly caught wind that I was more advanced for my age compared to other children. As they tell it, I was able to write my name on the computer before I could write. I was also able to read before primary school. So my parents took me to take some exams and I passed and got to skip the last year of kindergarten and started primary school a year early. I didn&rsquo;t know any kids in that year, and for as long as I can remember in my school career most people addressed me as Lukske (which kind of translates to Little Luk). I didn&rsquo;t mind it much at the time, but I was always the youngest in class and somehow felt I had to prove I deserved to be there. Especially in primary school I took immense pride in showing off. I was very good at maths, and whenever I had the opportunity in a test or quiz, I would try to finish as fast as possible, feeling a rush of adrenaline to get done as fast as possible. I never double-checked my answers, which did end up costing me in the long run. It&rsquo;s a habit I&rsquo;ve had to stamp out in my adult life, where I learned that I&rsquo;m more valuable as a software developer when I deliver qualitative work instead of fast work.</p>
<p>During my primary school period I scored pretty good on my report cards, everything I was talented in (maths, languages, and anything logic based) scored 8-10/10 and stuff I had to memorize which (at the time) didn&rsquo;t interest me, scored somewhat lower 6-7/10. Mostly because I was able to memorize just about enough of what was said that I didn&rsquo;t have to put any extra work in. Some kids at school talked about cramming for school for 2-3 hours per day, whereas I came home, dropped my backpack and turned on my computer and started playing video games. My mom would occasionally ask me if I didn&rsquo;t have any homework, but I was usually done with all my homework by the time my parents picked me up from school. School ended between 3PM and 4PM, and I got picked up at around 6PM. We would usually eat &ldquo;as a family&rdquo; when my dad came home at around 8PM. Eating as a family at our place meant, all of us sitting around the same table, while my dad chose his favourite TV program to watch for the evening.</p>
<p>We never talked much. My parents often talked amongst each other in French when me or my sister weren&rsquo;t meant to understand anything they were saying. I remember jumping in a conversation they were having and asking about something they were talking about that I didn&rsquo;t fully understand. They were baffled that I picked up their secret language which wasn&rsquo;t intended to be understood by us little people. They jokingly said they&rsquo;d have to start talking in English to each other so I wouldn&rsquo;t understand them. But by that time, with all the TV I had been consuming and all English programs were subtitled in Dutch, I had enough of a basis to understand and reply as well. I think they just waited until we went to bed before talking about stuff I wasn&rsquo;t supposed to overhear. Although they frequently kept talking to each other in French, for which I&rsquo;m grateful, it did develop my French more.</p>
<p>I wasn&rsquo;t that popular as a kid. I did have some friends I played with in school, but often I brought crosswords or wordsearches with me to school to solve during breaks instead of socializing with other kids. I never thought it odd the time, my parents often encouraged this. This behaviour was kind of fine during primary school, but in secondary school this was obviously the kind of thing bullies would pick up on. There were times where I felt like a rock star in primary school. I remember in 5th grade I had a competition with my teacher to look up the definition of some words in the dictionary as fast as possible, which I won and the whole class applauded. Secondary school was a whole different beast. Everything that made me special in primary school, made me a target in secondary school.</p>
<p>I started purposely putting in less effort in order to not stand out. This had an obvious impact on my grades, which I then had to explain to my parents. Although it took me 4 years to come clean and tell them that I got bullied and this was a conscious effort of me to not stand out (which btw, did not help at all). It was around this time I started rebelling myself, and whenever I did anything wrong at home my mom would not hesitate to remind me to &ldquo;wait until your dad hears about this!&rdquo;. I didn&rsquo;t see my dad often, he came home late and we had to go to bed early, so some days I didn&rsquo;t even see him. Which fed upon the idea that my dad was the bogeyman, the man you had to fear. Because anything you did wrong would go straight to him and punishment would follow. It might not be the very next day, but it would. Punishment was never physical, I never got mistreated, my dad knew perfectly how to get to me. Just take away my computer and sure enough that felt like the worst thing that could happen to me.</p>
<p>It was around this period that I started dabbling in programming some more. I did some BASIC in primary school on an old Commodore 64 we had, but didn&rsquo;t do a whole lot with it. During secondary school I learned Visual Basic and the WYSIWYG editor of Winforms, which opened so many possibilities. I wrote many programs which I don&rsquo;t have anymore, like a arithmetic exercise program for my younger sister, or an algorithm to solve the board game Clue in as few steps as possible. Which kind of took the fun out of the boardgame, but it was fun writing it. Whenever I got stuck on anything my dad would remind me that &ldquo;if Einstein gave up, we wouldn&rsquo;t have the theory of relativity now&rdquo;. Which kind of sums it all up really well. My parents weren&rsquo;t (and still aren&rsquo;t) great with sharing feelings. I have not had a lot of affection as a child, I wasn&rsquo;t told I was loved, and no one ever told me they were proud of me. Instead, what I heard most often was: &ldquo;You could do more with the talents you&rsquo;ve been given&rdquo;, often followed by &ldquo;it would be a shame to let them go to waste&rdquo;. It even is what I still hear my grandfather say to me on his deathbed.</p>
<p>I wouldn&rsquo;t see this scarred me, but I did take this with me for most of my adult life. Seeking validation of others for the work I did. Constantly trying to up my game to get more praise, until I couldn&rsquo;t anymore. Whereas I&rsquo;ve worked on these problems for many years and feel that my life as a whole has become a lot better ever since I started reflecting on my own situation and how my actions affected myself and others. I still think the lack of motivation I find for actually finishing personal projects where I&rsquo;m the only key stakeholder stems from this need of external validation. Kudos, to all solo devs who work for years their passion project and actually finish their project.</p>
<p>On the other hand, the lack of empathy and affection I got as a child resulted in a deep interest in human psychology and behaviour. I&rsquo;ve become a big fan of communicating from my own needs to my partner and friends, instead of communicating about the frustration their actions cause me. Whenever I get frustrated, angry or disappointed, I remind myself that my reaction is a direct consequence of my own needs and values, and not a result of someone else&rsquo;s actions. This realization in itself gives so much meaning and allows for so much growth in ones life.</p>
<p>So, this might not be the whole story of how I became the person I am today, but it does underline the most troublesome, but also the most valuable aspects of my character. If you find you have some free time for self reflection, ask yourself: &ldquo;How did you become who you are today?&rdquo; Share your thoughts for others, or don&rsquo;t, in any event I&rsquo;m almost certain you&rsquo;ll (re)discover something important about yourself.</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to How%20did%20you%20become%20who%20you%20are">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Clair Obscur: Expedition 33</title><link>https://pensiveibex.com/blog/2025/6/clair-obscur-expedition-33/</link><pubDate>Sun, 25 May 2025 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2025/6/clair-obscur-expedition-33/</guid><description>
<![CDATA[<div class="haiku">
    <blockquote>
        Brush strokes in the sky<br />
        The Paintress calls for gommage<br />
        When tomorrow comes
    </blockquote>
</div>
<p>I try very hard not to write any spoilers about the games I played when writing a review for them. As a player I like to know as little about the story of a game as possible before going in, I like going in blind and being completely enraptured by the game. The following two paragraphs contain some very minor spoilers (nothing more than what plays in the introductory sequence of the game). If you want to avoid anything story-related, you may want to skip the next two paragraphs.</p>
<p>Clair Obscur sets a scene in a alternate world where every year The Paintress strokes her brush through the air and subtracts the number, visible on the horizon, by one. This then also triggers the gommage (erasure) of all people older than the visible number. When the game starts, you see the number go from 34 to 33. Meaning no one lives to be older than 33. As I am 37, this would have made me very much dead. All willing citizens of Lumière that would be erased by next year go on an Expedition. This expedition sets out to kill The Paintress and remove her curse from the world.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2025/6/clair-obscur-expedition-33/gustave.png" class="lightbox">
		<img src="/blog/2025/6/clair-obscur-expedition-33/gustave_hu_fc2b5a32c5a4ae7a.png" class="center " loading="lazy">
	</a>
	
</figure></p>
<p>Outside the borders of Lumière live huge monstrosities called Nevrons. These huge creatures aren&rsquo;t to be reasoned with and just attack mindlessly. The people of Lumière know this and each year they prepare for an expedition to stop the Paintress and learn from the expeditions that came before them. This year, Gustave invented the Lumina Converter, a device that enables expedition members to harness Chroma and use Pictos more effectively.</p>
<p>Chroma is something weird, its both a life force in the world of Clair Obscur ánd a currency used to buy weapons, Pictos, outfits and haircuts. You gain Chroma from defeating enemies and also by collecting it through exploration. Going through all the different paths and finding all hidden places in a level gets rewarded. You&rsquo;ll find Chroma, Lumina, Pictos or even weapons if you&rsquo;re lucky. Either that or you&rsquo;ll find a unique enemy what extra powerful abilities.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2025/6/clair-obscur-expedition-33/lights.png" class="lightbox">
		<img src="/blog/2025/6/clair-obscur-expedition-33/lights_hu_1aba63410b982804.png" class="center " loading="lazy">
	</a>
	
</figure></p>
<p>Combat in Clair Obscur is clearly inspired by several other games, yet combines these skilfully to bring a unique experience for each enemy. Each enemy sports a different attack pattern, which you can either try to dodge or parry. Dodging has a more forgiving window of opportunity, but parries really need to be timed perfectly. But when you do, you not only block the attack, but you attack in return. Either dodging or parrying attacks always made me feel like I achieved something special. You could say this ability to time a parry or dodge comes from perfect timing comes from Dark Souls, but in this genre of turn-based RPG mechanics I think it has more in common with the Mario &amp; Luigi RPG series. <a href="https://www.pcgamer.com/games/rpg/clair-obscur-expedition-33-didnt-invent-final-frenchtasy-or-the-jrpg-the-newly-dubbed-subgenre-has-a-long-and-complicated-history">PC Gamer</a> has a nice article on Clair Obscur&rsquo;s inspirations, as well as the <a href="https://www.sandfall.co/team">Team page</a> on Sandfall&rsquo;s  website listing all devs favourite games.</p>
<p>As for the party of heroes, you get a certain number of AP (Attack Points) per turn and you can spend these to perform actions during your turn. You can clearly see the influence that Persona had on Clair Obscur with the ability to shoot enemies. You can use this ability to hit certain Nevrons in their weak spot, dealing additional damage. For some enemies this mechanic is more elaborate and you can use your shoot ability to prevent an enemy from performing an attack. At first I thought the ability was tacked on, seemingly inspired by Persona and just putting it in for the sake of the idea. But it&rsquo;s really well done, allowing for interesting character builds and surprising enemy interactions if you&rsquo;re open to look for them.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2025/6/clair-obscur-expedition-33/monolith.png" class="lightbox">
		<img src="/blog/2025/6/clair-obscur-expedition-33/monolith_hu_7cee314e440a2741.png" class="center " loading="lazy">
	</a>
	
</figure></p>
<p>The other thing you can spend your AP on is an ability set that is unique for each character. Gustave builds up charges, Maelle has different sword stances, Lune has elemental stains  she creates and consumes with every attack. Sure this isn&rsquo;t exactly new, but it&rsquo;s a whole lot more fun than classic JRPG&rsquo;s that had different classes where the only thing that changed is which spell you cast and the MP cost. Combat in Clair Obscur lives, breathes and occasionally kicks you in the balls.</p>
<p>If this wasn&rsquo;t enough to create a versatile playstyle for you, then Sandfall cooked up another modifier. Pictos. These are abilities that you unlock with Lumina, another currency that can be found by exploration and through combat rewards, in camp you can spend Lumina on different party members to increase their capacity to equip Pictos. Every character can equip 3 Pictos, these do not cost any Lumina and after 4 encounters the Pictos is mastered, which allows any party member to equip its ability, but it&rsquo;ll cost Lumina to equip it. These Pictos allow you to gain AP after killing an enemy, or when dodging an attack. But they might also increase your shoot damage, or set your enemies on fire. Pictos is what will make your time in Clair Obscur different from anyone else playing. While you might have some overlap with others, there are so many Pictos to choose from that you&rsquo;ll definitely find some interesting combinations to accommodate your playstyle.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2025/6/clair-obscur-expedition-33/baguette.png" class="lightbox">
		<img src="/blog/2025/6/clair-obscur-expedition-33/baguette_hu_96233c8a1ba81fee.png" class="center " loading="lazy">
	</a>
	
</figure></p>
<p>There&rsquo;s so much more to say about Clair Obscur, especially the story, that is where the game really shines for me. I play games for the same reason I watch movies or series, for a great story. I have some genre preferences, but the story is what will make or break a game for me. And Clair Obscur is a gem. I haven&rsquo;t had so much fun playing a JRPG since Final Fantasy X as a kid. I love doing optional stuff and being rewarded for it. I&rsquo;m not a completionist anymore, because I lose interest in a game more quickly than before if the story arch is done, but I still love going back to places I&rsquo;ve already been and finding new stuff. That itch really got scratched here. Some optional stuff even provide more background to the overall story which is a real nice thing. It makes all content feel grounded in the world, instead of a sequence that can be skipped.</p>
<p>I found it hard to put this game down, so much so that I missed the deadline for finishing Old Skies for the Adventure Game Club month of May. If I had a top 100 list of games of all time, Clair Obscur would find its place in it. Kudos to the team that made it. I won&rsquo;t go into <a href="https://www.rockpapershotgun.com/no-clair-obscur-expedition-33-wasnt-made-by-30-people">the debate</a> about the team size and the outsourcing of aspects of the game. I&rsquo;m here to review the game, and if a team of 30 people outsourced a bunch of stuff and made this game, good on them. I love the end result, so I can only assume they made good decisions and were able to juggle the output of all other studio&rsquo;s in a game that&rsquo;s very polished.</p>
<div class="row">
    <div class="column pros border-right">
        <h4 style="display: flex; justify-content: center;">Likes</h4>
        <ul>
        
        <li>Interactive combat</li>
        
        <li>Story that keeps you guessing</li>
        
        <li>Great voice cast</li>
        
    </ul>
    </div>
    <div class="column cons">
        <h4 style="display: flex; justify-content: center;">Dislikes</h4>
        <ul>
            
            <li>My only remark is on the pronunciation of putain and merde by some of the voice cast</li>
            
        </ul>
    </div>
</div>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Clair%20Obscur%3a%20Expedition%2033">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>The abundance of choice</title><link>https://pensiveibex.com/blog/2025/5/the-abundance-of-choice/</link><pubDate>Sat, 17 May 2025 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2025/5/the-abundance-of-choice/</guid><description>
<![CDATA[<p>As a preamble to this post, let me start off by saying, I agree. Yes, this is first-world problem. I realize how lucky I am, for this to even be a thing in my life.</p>
<p>So generally there are two things that motivate my choices in life. Time and interest.</p>
<p>The former is the finite resource of our existence. I&rsquo;m 37, and for some years now I have come to value time a lot more than I used to. A typical workday looks something like this for me:</p>
<ul>
<li>15 minutes getting up</li>
<li>45 minutes walking the dogs</li>
<li>15 minutes breakfast</li>
<li>10-15 minutes commute</li>
<li>4 hours work</li>
<li>1.5-2 hours working out (commute and shower included)</li>
<li>4 hours work</li>
<li>10-15 minutes commute</li>
<li>30-45 minutes making dinner</li>
<li>10-15 minutes doing the dishes</li>
</ul>
<p>By the end of this routine, it&rsquo;s usually somewhere between 19h30 and 20h30, depending on various circumstances. Which leaves me between 1.5-2.5 hours of free time. What I do in those hours is <em>very</em> important to me. But choosing <em>what</em> to do in those hours is tremendously hard.</p>
<p>On one hand, I want to develop more skills. Either drawing, playing music, coding, writing, &hellip; On the other hand I want to relax, like reading a book, playing video games, writing this blog, solving puzzles, &hellip; To top it all off, I want to spend time with the people I love.</p>
<p>I can&rsquo;t fit all of these things in the time window I have. Ideally I would be doing everything that piqued my interest if time weren&rsquo;t an issue. Since this isn&rsquo;t an option, and I have too many interests, all I&rsquo;m left with is a choice. Would I be rather doing one thing or another? And how can I possibly rank one activity above another?</p>
<p>How do you rank meeting up with a friend over playing a videogame? Both give me joy in very different ways. Both fulfill different needs. There&rsquo;s no possible quantification for these activities.</p>
<p>Last September I went to Canada on 4-week trip. During that time, I&rsquo;ve read about half a dozen books. Since then, I&rsquo;ve read two&hellip; I love reading for the exact same reason I love video games, I enjoy good narratives and like being swept away in another world. Feel what they feel, live amongst the characters, experience the highs and lows of their journey. Yet for some reason reading had taken a back seat to all other activities, for reasons that are not clear to me.</p>
<p>It&rsquo;s not that I haven&rsquo;t done anything productive with the time I had, far from it. I can convincingly say that I don&rsquo;t feel like I have wasted time. Yet I still have more interests than time. I have this feeling in the back of my head that there are só many things to enjoy, to learn, to discover, to experience and so little time to do them in.</p>
<p>However, there are some criteria for stuff to be allowed in my free time bubble.</p>
<p>If I don&rsquo;t enjoy it, I won&rsquo;t power through and keep pushing to see if I might enjoy it at the end. I&rsquo;ll drop that experience and replace it for something I know I will enjoy. Prime example is a book, if I&rsquo;m not engrossed after 30-50 pages (and I don&rsquo;t have evidence that it will get better), then I&rsquo;ll drop it in favor of another book.</p>
<p>If my time isn&rsquo;t respected, I&rsquo;ll drop it. Like in a video game, if I have to grind for hours on end to achieve something you actually can&rsquo;t do without, that is something I&rsquo;m not open to anymore.</p>
<p>If I get frustrated, I&rsquo;ll drop it. This is mostly when developing new skills, if I&rsquo;m hitting a wall and making the same mistakes again and again. Then it&rsquo;s time to take a break and revisit the issue another day. No point in banging my head against the wall over and over.</p>
<p>These seem obvious. And I&rsquo;m sure they probably are to many, but it took me longer than I&rsquo;d care to admit that dropping an activity is just as important as picking one up.</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to The%20abundance%20of%20choice">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Blue Prince</title><link>https://pensiveibex.com/blog/2025/4/blue-prince/</link><pubDate>Sat, 19 Apr 2025 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2025/4/blue-prince/</guid><description>
<![CDATA[<div class="haiku">
    <blockquote>
        Shifting halls unfold<br />
        Looking for Room 46<br />
        Steps gone, dawn resets
    </blockquote>
</div>
<p>Ever since it was announced, I was really excited for Blue Prince. In Blue Prince you play as Simon, a young adolescent boy (I&rsquo;m not sure if his age is mentioned in the game) who just inherited the manor estate of his uncle. However, Simon&rsquo;s uncle has laid out a challenge for Simon. In order for Simon to become the new baron, he has to find Room 46 in a mansion with 45 rooms.</p>
<p>This isn&rsquo;t the only quirk, the mansion&rsquo;s layout changes every day, and every time you enter a door you draft the next room from a choice of three. It&rsquo;s a simple game mechanic that&rsquo;s beautifully executed. The manor is laid out in a 5x9 grid. You start in the middle on the bottom rung and the only other revealed room on the map is in the middle of the top rung. So that&rsquo;s your first and only clue, get from the Entrance Hall to the room at the top.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2025/4/blue-prince/entrance-hall.png" class="lightbox">
		<img src="/blog/2025/4/blue-prince/entrance-hall_hu_7000989539b76879.png" class="center " loading="lazy" title="Where every day starts...">
	</a>
	
		<figcaption>Where every day starts...</figcaption>
	
</figure></p>
<p>Not all rooms you draft are the same, some are dead ends, others have only one other door, if you&rsquo;re lucky you&rsquo;ll draft a room with 3-4 doors leaving you with several options of where to go, which is the first thing you&rsquo;ll have to think about in Blue Prince. &lsquo;Cause if you have no more doors to go through, then that&rsquo;s it. End of the day, start over!</p>
<p>That&rsquo;s not the only thing you have to look for in a room, there&rsquo;s different types of rooms. Bedrooms which grant you extra steps. Oh, didn&rsquo;t I mention? Yeah, you get 50 steps, every time you enter a room (even if you already visited it previously) you lose a step. Once all steps are gone, that&rsquo;s it. End of the day, start over! Some rooms require gems to draft, so you might want to gather some of those as well. And some rooms are locked! So better make sure you gather enough keys to progress throughout the mansion!</p>
<p>What really gets me, though, is the drafting mechanic is part of the narrative. Which is an absolute stroke of genius. They could have just as easily left it out, not explaining anything about it. By making it a part of the game&rsquo;s story, it grounds the mechanic in the game world. Having the fantasy of the mansion being this magical place where whenever you open a door you have to pick one of three rooms to enter really made it shine for me.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2025/4/blue-prince/residents-picture.png" class="lightbox">
		<img src="/blog/2025/4/blue-prince/residents-picture_hu_28ae11b7dad66cd6.png" class="center " loading="lazy" title="The former residents">
	</a>
	
		<figcaption>The former residents</figcaption>
	
</figure></p>
<p>The mechanic gets referenced in several letters and notes strewn around the mansion, written by several different people. I remember chuckling at a certain note of someone mentioning: <em>&ldquo;How anyone gets any work done around here, is beyond me&rdquo;</em>. This also lays out a core concept of the game, notes, images and letters are all over the place. And because you&rsquo;re not guaranteed to encounter the same room again any time soon, you gotta take notes! I&rsquo;m a gamer that used to make handdrawn maps as a kid for platformers like <a href="https://www.mobygames.com/game/66937/top-hat-willy">Top Hat Willy</a> and adventure games like <a href="https://www.mobygames.com/game/13132/valhalla-and-the-lord-of-infinity/">Valhalla</a>. Feeling the need to take notes during a game really takes me back, I love the mixing and matching of game and real world skills to progress.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2025/4/blue-prince/notes.png" class="lightbox">
		<img src="/blog/2025/4/blue-prince/notes_hu_c355ac4e0d6e1431.png" class="center " loading="lazy" title="Blurred so I can show them off spoiler free!">
	</a>
	
		<figcaption>Blurred so I can show them off spoiler free!</figcaption>
	
</figure></p>
<p>When you start out, there&rsquo;s so much information coming at you, you&rsquo;ve got loose threads everywhere and it&rsquo;s fantastic. Because even though you don&rsquo;t know which rooms will pop up in the mansion, there&rsquo;s always one thread you get to progress. One piece of new information that brings you closer to a solution.</p>
<p>It&rsquo;s a great feeling to figure out a puzzle and only later get a hint for that puzzle in a room you hadn&rsquo;t discovered yet. This is a great game design decision, make some puzzles solvable from the get-go, but give hints about those puzzles in different rooms in case players didn&rsquo;t notice those puzzles are weren&rsquo;t able to solve them yet.</p>
<p>The game really, REALLY got me. The first weekend it was available I must have played about 14 hours. I was just really enthralled in the game and wanted to discover all nooks and crannies of the mansion and its mysteries. I finished the game this weekend by reaching Room 46. There&rsquo;s still stuff to find, mind you. But I&rsquo;m not sure if I&rsquo;m still interested in finding it. You see, the game has a decent amount of RNG because of the room drafting, and to finish certain puzzles you have to get somewhat lucky with a combination of rooms. And I&rsquo;m not sure I&rsquo;m comfortable with hoping to get those combinations in order to progress any further. I love puzzles and I would really love knowing how they unfold, but I don&rsquo;t like them feeling like a chore. Which most of the post-game content of Blue Prince feels like to me.</p>
<div class="row">
    <div class="column pros border-right">
        <h4 style="display: flex; justify-content: center;">Likes</h4>
        <ul>
        
        <li>Mysteries upon mysteries</li>
        
        <li>Interconnectedness of rooms within mansion</li>
        
        <li>Elaborate puzzles</li>
        
    </ul>
    </div>
    <div class="column cons">
        <h4 style="display: flex; justify-content: center;">Dislikes</h4>
        <ul>
            
            <li>Roguelike elements hinder post-game puzzle enjoyment</li>
            
        </ul>
    </div>
</div>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Blue%20Prince">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>The Darkest Files</title><link>https://pensiveibex.com/blog/2025/4/the-darkest-files/</link><pubDate>Sat, 05 Apr 2025 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2025/4/the-darkest-files/</guid><description>
<![CDATA[<div class="haiku">
    <blockquote>
        Shadows of the past<br />
        Justice sought in truth untold<br />
        Secrets now revealed
    </blockquote>
</div>
<p>I backed this game on Kickstarter a while back, something I haven&rsquo;t done a lot for videogames. But this one caught my eye, because I love playing detective and it&rsquo;s roots in true history really resonated with me. At the time I thought this would be my very first video game credit. Little did I know at the time, how things would work out, as I am now working as a <a href="/blog/2025/1/new-opportunity">game developer</a>!</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2025/4/the-darkest-files/the-darkest-files-credits.png" class="lightbox">
		<img src="/blog/2025/4/the-darkest-files/the-darkest-files-credits_hu_b05d3386d43659cb.png" class="center " loading="lazy" title="That&#39;s me!">
	</a>
	
		<figcaption>That&#39;s me!</figcaption>
	
</figure></p>
<p>The Darkest Files is a game set after the second World War. You join the team of Fritz Bauer, prosecuting the many crimes committed during the Nazi regime. All characters, except for Fritz Bauer are works of fiction, but all cases actually happened.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2025/4/the-darkest-files/the-darkest-files-fritz-bauer-ingame.png" class="lightbox">
		<img src="/blog/2025/4/the-darkest-files/the-darkest-files-fritz-bauer-ingame_hu_d9eca8d35069074.png" class="center " loading="lazy">
	</a>
	
</figure></p>
<p>The game presents two real life cases in a puzzle format. Two seems like a very low number, but completing the game still took me about 11 hours. The gameplay is well thought out, you start a case with a bit of background information about it and a single viewpoint. You then get the interview other witnesses to the crime and ask them about what happened. This all happens in a flashback scene of the event. The story unfolds linearly, but you get to ask extra questions by highlighting other objects in the scene.</p>
<p>At some crucial points you&rsquo;ll be able to interrupt the witness and try to refute their statement. You do this by presenting a certain paragraph in your case file that is linked to what the witness is telling you. If you get it right (and you only get one try) then new information is unlocked which might prove helpful to the case. Although, there is a difficulty setting which might help you, if you go for the lower difficulty then you just need the present the right page instead of the right paragraph.</p>
<p>After you&rsquo;ve seen all witnesses and gathered all the documents (more get added as days pass and you require more information from witnesses), you can then start recreating the crime on a blueprint. The cases is divided in 5 parts, for each of these parts you have to place all actors in the correct room and assign a person to an action. For example, you might have to determine who made a phone call, so you place the marker for that person in the correct room and assign it the action &ldquo;Made phone call&rdquo;. You do this for all 5 parts. Then you have to dig through your case files, and back up your claims by highlighting the correct paragraph in 3 different documents to present your conclusion.</p>
<p>Once you&rsquo;ve done all your prep work, you take your case to court and present your findings, if you&rsquo;ve done a good job, you&rsquo;ll pass with flying colours. I didn&rsquo;t. In my first case, I missed three conclusions. In my second case I missed one. I did however had a bug in my first case where I didn&rsquo;t get any retries for failed conclusions (you normally get 3 or 4 retries, I can&rsquo;t remember). The game did succeed in not making me feel stupid, it was challenging, I got some stuff right and the feeling for getting something right trumped the letdown of not knowing what to provide to prove my point when I got something wrong.</p>
<p>The puzzles and gameplay were excellent, I don&rsquo;t have any remarks there and wholeheartedly recommend the game for this aspect alone. However, there are some points that made it somewhat harder to enjoy the narrative. The voice actors are all German, but the in-game voice is English. Which lead to a lot of mispronunciations, not to mention grammatical mistakes. I&rsquo;m sure this is a minor point for most, but it really affected my immersion. I think I would have preferred German voices with English subtitles.</p>
<p>The only other point of critique on the voice is the blending of different voice lines. Imagine two characters talking:</p>
<blockquote>
<p>&ldquo;I&rsquo;m not sure that&hellip;&rdquo; said A.</p>
<p>&ldquo;Hold it!&rdquo; Shouted B.</p>
</blockquote>
<p>When you read this, you expect B to interrupt A. What happens in the game is that both voice lines are seperated by a long pause. As if there&rsquo;s some kind of technical issue preventing from voice lines from being played immediately. This really grinds the narrative to a halt. What was supposed to be a tense moment is completely lost on the player. This is a shame, because the writing of the cases in the game is great, but doesn&rsquo;t get to shine either because of these issues are because of voice actors being forced to speak in a non-native language.</p>
<p>The visuals of the game are stunning. I loved the aesthetic, it really helped solidify the game&rsquo;s narrative to the historical setting. It seems almost a shame that I should bring up a piece of critique on the visuals, because it&rsquo;s so minor in comparison to all the lovely work that has been put into it. But I guess that&rsquo;s what you do in a review, so here goes. Most of the game you&rsquo;re set in a fixed point of view toward other characters. So you don&rsquo;t really notice that most of these are actually 2D sprites. Except in the court room, for some reason, most of the time in the court room consists of many different camera angles and moving shots, which leads to a real jarring effect when you see the 2D models slightly sideways. It would be fine if this was part of the aesthetic of the whole game, but here it feels very out of place.</p>
<p>Last point is about the ending of the game. After finishing the two cases, there&rsquo;s an epilogue. In the epilogue some of the story that has been sprinkled in on the side during the main two cases come to a head. Except, not. It&rsquo;s so very anticlimactic I wonder what the point was. There&rsquo;s a choice you have to make, which <em>should</em> feel meaningful. And it did at the point of making the choice. But there was no follow-through. You made the choice, but you didn&rsquo;t get to see any of the consequences. What was the point in making that choice then?</p>
<p>So, play the game for the detective work and the puzzles. They are really, really good. Not to mention that both cases are real. The game doesn&rsquo;t dwell a lot on the horrors of the holocaust, but does dig deep in the surrounding events of the holocaust. The game serves as a great reminder to the many atrocities that have been committed at the time.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2025/4/the-darkest-files/the-darkest-files-fritz-bauer-quote.png" class="lightbox">
		<img src="/blog/2025/4/the-darkest-files/the-darkest-files-fritz-bauer-quote_hu_7e43f103ddeee489.png" class="center " loading="lazy">
	</a>
	
</figure></p>
<p>At the very end of the game, you&rsquo;re presented by a quote by Fritz Bauer that I&rsquo;d like to share, because it rings so true. It&rsquo;s very easy to go with the pack, saying things are out of your hands. Whereas his comment clearly is linked to the events of the holocaust, it can be applied to many things. My personal pet peeve is climate change. It&rsquo;s easy to shove the blame on other people, corporations or governments. And it might even be true. But that doesn&rsquo;t mean you can&rsquo;t do anything. Small things like not opening the tap fully, but adjusting the handle to use a smaller stream <em>does</em> have an impact. It starts with you.</p>
<div class="row">
    <div class="column pros border-right">
        <h4 style="display: flex; justify-content: center;">Likes</h4>
        <ul>
        
        <li>Great puzzles</li>
        
        <li>Digging through relevant and irrelevant info is fun</li>
        
        <li>Doesn&#39;t make you feel stupid if you miss</li>
        
        <li>History lesson</li>
        
    </ul>
    </div>
    <div class="column cons">
        <h4 style="display: flex; justify-content: center;">Dislikes</h4>
        <ul>
            
            <li>Voice actually holds back the narrative</li>
            
            <li>Visuals in the courtroom bring you out of the atmosphere</li>
            
            <li>Disappointing ending</li>
            
        </ul>
    </div>
</div>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to The%20Darkest%20Files">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Unavowed</title><link>https://pensiveibex.com/blog/2025/3/unavowed/</link><pubDate>Sun, 16 Mar 2025 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2025/3/unavowed/</guid><description>
<![CDATA[<div class="haiku">
    <blockquote>
        Hidden by the veil<br />
        The Unavowed stand strong<br />
        Protecting mundanes
    </blockquote>
</div>
<p>It&rsquo;s the game of the month over at the <a href="https://discord.com/invite/esAaKxbMwC">Adventure Game Club</a>. Since Avowed (which I&rsquo;ve also played and probably will write a review for somewhere next week) came out this month, it seems only fitting to play Unavowed as well.</p>
<p>As the game starts you&rsquo;re immediately pulled into the action, the story never misses a beat and I was engrossed from the start. Honestly, it was such a relief from the regular gentle introduction I didn&rsquo;t know I needed. You find out that you&rsquo;ve been possessed by a demon and spend the rest of the game undoing your former self&rsquo;s evil deeds.</p>
<p>Your joined in your quest by the two veteran members of the Unavowed, Eli (a fire mage) and Mandana (a half-djinn). Later in the game, you pick up more members, each have their respective unique characteristics. For example, Mandana has a superhuman strength and has the ability to tell if people are telling the truth. Eli can set things on fire and can read burnt letters or books. At the start of each mission you get to pick two companions to bring along. You can&rsquo;t change your choice, once you&rsquo;ve committed to it. And every mission can be completed with any set of companions.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2025/3/unavowed/unavowed.png" class="lightbox">
		<img src="/blog/2025/3/unavowed/unavowed_hu_6b15c2feb6e8551a.png" class="center " loading="lazy">
	</a>
	
</figure></p>
<p>This was such a genius move, you always know you can complete the puzzles and don&rsquo;t have to bother with backtracking or revisiting a mission with a different set of companions. It does somewhat take away the meaningfulness of choosing the companions you take with you. But I only discovered that it really didn&rsquo;t matter after the first 4-5 missions, so the illusion does hold for a long time. What&rsquo;s really great about it, though, is the level and game design it took to reach this point. Having 4 companions in total, means you have 6 different combinations of companions you can bring along on any given mission. That means 6 different sets of somewhat overlapping dialogues that have to make sense for the story to reach their possible conclusions.</p>
<p>All of the companion&rsquo;s abilities fit well within the story and despite having several branching paths to completing puzzles it doesn&rsquo;t ever feel forced. During the several missions you bring your companion&rsquo;s along you also get to know them better. You get a peek into their minds and what they struggle with. Dialogue options usually have 3 different variations, sometimes worded in specific ways that even though the meaning behind the dialogue lines may vary wildly, the same response from an NPC can be used to answer all three dialogue options. I don&rsquo;t think it happens that often, but was noticeable at some points.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2025/3/unavowed/unavowed-portrait.png" class="lightbox">
		<img src="/blog/2025/3/unavowed/unavowed-portrait_hu_7661e69cbbfc2173.png" class="center " loading="lazy" title="The portrait art is gorgeous throughout!">
	</a>
	
		<figcaption>The portrait art is gorgeous throughout!</figcaption>
	
</figure></p>
<p>The game&rsquo;s puzzles aren&rsquo;t very hard. I never got stuck, it was always pretty obvious what the next step should be. More often than not this involved revisiting NPC&rsquo;s with new information you picked up from some other place. This is a tricky mechanic in point-and-click games. I usually think that talking to a person and going through all dialogue options marks the NPC as completed and they won&rsquo;t ever have any new information for me. However, in Unavowed, new information is given frequently, usually hinted at by one of your companions mentioning you should go back to X or Y to ask them about it. Which is a great addition, since it makes sense for them to comment about it storywise, and directs the player on where to go next naturally.</p>
<p>Every line in the game (except for the players chosen dialogue options) are voiced, and the acting is done exceptionally well. I should mention though, that there was one character (Chipman, the owner of the doughnut shop) where the quality of the voice lines noticeably dropped. It&rsquo;s as if they were recorded on a remote laptop. Which is a bit of a shame, as it stands out as a sore thumb amidst all the other voice acting. Luckily, he doesn&rsquo;t have a lot of voice lines!</p>
<p>This game popped my Wadjet Eye cherry. And boy has it whet my appetite. Every other game in their catalog has just seen a bump in my backlog of games to get to. I mentioned at the start of this review that I also played Avowed this month. I liked that game, but I loved this one. It has grounded me that I much prefer the mix of narrative and puzzle genre, AAA titles are filled with so much faff. They have a much larger audience and need to cater to most of them. Unavowed is much more contained, there&rsquo;s no deviating from the story, you can&rsquo;t just decide to leave all these people who count on you to wait until you&rsquo;ve looted the contents of their house. Unavowed sucks you in, and keeps you entertained. I completed the game in two sittings and found the length exactly long enough for my tastes.</p>
<div class="row">
    <div class="column pros border-right">
        <h4 style="display: flex; justify-content: center;">Likes</h4>
        <ul>
        
        <li>Very engaging story</li>
        
        <li>Several ways to approach puzzles</li>
        
        <li>Great voice acting</li>
        
    </ul>
    </div>
    <div class="column cons">
        <h4 style="display: flex; justify-content: center;">Dislikes</h4>
        <ul>
            
            <li>Easy puzzles</li>
            
            <li>Chipman&#39;s voice</li>
            
        </ul>
    </div>
</div>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Unavowed">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Indiana Jones and the Great Circle</title><link>https://pensiveibex.com/blog/2025/2/indiana-jones-and-the-great-circle/</link><pubDate>Sun, 16 Feb 2025 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2025/2/indiana-jones-and-the-great-circle/</guid><description>
<![CDATA[<div class="haiku">
    <blockquote>
        His whip cracks the air<br />
        Indiana seeks the path<br />
        Fedora secured
    </blockquote>
</div>
<p>I&rsquo;ve always had a soft spot for Indiana Jones. The Indiana Jones franchise is (along with Star Wars) one I&rsquo;ve been introduced to by my parents. They named me after Luke Skywalker and named our second dog Indy. Just goes to show how much of a fan we all are. After first hearing about the Indy game a while back, I was sceptical. After all, I hadn&rsquo;t forgotten <a href="https://www.rottentomatoes.com/m/indiana_jones_and_the_kingdom_of_the_crystal_skull">the Kingdom of the Crystal Skull</a> fiasco just yet&hellip;</p>
<p>Somewhat atypically, I avoid trailers. I prefer going into a game or a movie completely blind. Having every experience fresh. I do check opencritic or rottentomatoes if a game or movie is generally worth my time. Either one of those sources, or a friend recommendation is enough to get my attention. Indiana Jones and the Great Circle had both. Opencritic gives it a Mighty rating (which means the average of top critics is above 90%) ánd friends recommended it to me. Roy Tang also played the game recently and wrote <a href="https://roytang.net/2025/01/indiana-jones-great-circle/">his review</a> about it.</p>
<p>The intro sequence is amazing. If you don&rsquo;t know already, hurray! Go play it, and find out why it&rsquo;s so amazing. If you know the intro sequence, how awesome was that, right?! Read on, if you can live with spoilers.</p>
<p>I recognized the intro to Raiders of the Lost Ark immediately, even though it was more than 10 years since I last saw the movie. I initially had the plan to rewatch the Indy movies (sans the movie that shall no longer be named), but I couldn&rsquo;t persuade my girlfriend to watch them with me. Eventually we&rsquo;ve gotten around watching Raiders, and she wasn&rsquo;t a fan. I kind of see why though. If you haven&rsquo;t seen the movie when it was released during the zeitgeist of that time, some things might irk you (for one Marion initially being portrayed as a woman that can stand her own, only to scream for Indy&rsquo;s help a couple of scenes later).</p>
<p>Anyway, the intro choice was fantastic, not only does a serve as a great tutorial, it also succeeds in immediately putting you in the shoes of Indy. You immediately get a feel of the character he is and what he stand for. After that, the story really kicks in. Indy gets wrapped in an archaeological search for The Great Circle. During this search Indy meets Gina. An Italian reporter that is trying to find her sister. Indy, being the charmer he is, takes it upon himself to help Gina (even though she kind of imposes herself at times). They visit multiple locations around the world, fighting Nazi&rsquo;s along the way.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2025/2/indiana-jones-and-the-great-circle/dont-just-leave-an-eaten-apple.png" class="lightbox">
		<img src="/blog/2025/2/indiana-jones-and-the-great-circle/dont-just-leave-an-eaten-apple_hu_2debb182447273dd.png" class="center " loading="lazy" alt="At least throw it in the trash. Come on, Indy!">
	</a>
	
</figure></p>
<p>What I really liked about the game is that you get encouraged to explore and look around. I used to be a completionist by nature. But as I grew older more and more I ask myself if this game is worth my time going through all the collectibles. And The Great Circle ticks all of those boxes for me. I haven&rsquo;t yet gotten all collectibles, I did finish the main story but still have to go back here and there to collect a few things. The game really gives you the feeling of finding an exceptionally rare item. Even though it&rsquo;s made pretty easy, just by buying maps in-game all locations of the collectibles are marked on the map, there are still plenty of collectibles hidden behind puzzles for you to find. And I love puzzles.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2025/2/indiana-jones-and-the-great-circle/historically-accurate-armour.png" class="lightbox">
		<img src="/blog/2025/2/indiana-jones-and-the-great-circle/historically-accurate-armour_hu_ad815bed1cbd7a12.png" class="center " loading="lazy" alt="Polish Hussar armour, active in the 16th and 17th century.">
	</a>
	
</figure></p>
<p>This is what makes it so enticing for me. I don&rsquo;t mind having a map guiding me to where I have to go (hell, if it didn&rsquo;t I would have definitely been switched off). It takes away the tedious part of finding stuff and gives you the satisfaction of earning the collectible by locking it behind a puzzle. Sometimes these puzzles are easy, you get some notes lying around and one of them just gives the code. Other times, you have to visit other locations to find the solution. And other times there&rsquo;s subtle environmental stuff happening (flicking a light off to reveal a code, genius).</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2025/2/indiana-jones-and-the-great-circle/fine-leather-jackets.png" class="lightbox">
		<img src="/blog/2025/2/indiana-jones-and-the-great-circle/fine-leather-jackets_hu_11392e50686a2218.png" class="center " loading="lazy" alt="I was yearning for this reference, thank you!">
	</a>
	
</figure></p>
<p>Speaking of, instead of going head on with enemies, Indy can cleverly disguise himself to blend in and avoid fisticuffs. Although in the later part of the game, I found myself jumping into fights more quickly. It&rsquo;s easier to look around in a Nazi camp if everyone is knocked out, instead of stealthing your way through and avoiding those pesky higher-uppers who see through you disguise.</p>
<p>The game has a lot going for it. If you like Indy, or you like exploring in games, this has a ton of value for you.</p>
<div class="row">
    <div class="column pros border-right">
        <h4 style="display: flex; justify-content: center;">Likes</h4>
        <ul>
        
        <li>Rewards for exploration fits the archaeological theme</li>
        
        <li>It&#39;s Indy!</li>
        
        <li>Puzzles of varying difficulty</li>
        
    </ul>
    </div>
    <div class="column cons">
        <h4 style="display: flex; justify-content: center;">Dislikes</h4>
        <ul>
            
            <li>Storyline is akin to a WYSIWYG tool</li>
            
        </ul>
    </div>
</div>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Indiana%20Jones%20and%20the%20Great%20Circle">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>New opportunity</title><link>https://pensiveibex.com/blog/2025/1/new-opportunity/</link><pubDate>Mon, 06 Jan 2025 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2025/1/new-opportunity/</guid><description>
<![CDATA[<p>It&rsquo;s been a bit quiet around here. That has mostly to do with two things. First, the Belgian deparment of defense releases its <a href="https://beldefnews.mil.be/eindejaarspuzzel-take-the-challenge/">end-of-year puzzle</a> (kind of like <a href="https://www.gchq.gov.uk/news/gchq-christmas-challenge-2024">GCHQ</a> does for the UK). This is the 7th year of the puzzle, and the 7th year I&rsquo;m competing. What started is a fun thing I did with my dad, has turned into a group of 4 people that I got to know through doing the puzzle, with each our own complementary strengths.</p>
<p>It is said, and I have to agree, that it&rsquo;s the hardest puzzle of the year. That is basically why I like participating. It&rsquo;s a way to put all my skills to the test and really dig deep to get to solve a puzzle. Some are solved at first glance, if you&rsquo;re lucky enough to get the right idea on the first go. Others might take days or weeks of researching, code breaking, throwing things against the wall until something sticks to break. The feeling you get when breaking a puzzle is terrific. The contest runs until 28th of January. So a lot of my free time is spent puzzling.</p>
<p>The other thing that&rsquo;s changed recently, is my job. I am now part of <strong>Bolt Blaster Games</strong>, the team behind <a href="https://store.steampowered.com/app/2904000/The_Spell_Brigade/">The Spell Brigade</a>. I can&rsquo;t really express how happy I am to call myself a game dev and actually do this for a living. It feels unreal even talking about it here. I started this week, and it has been a real joy. Looking forward to creating content in the game and seeing it played and enjoyed by people around the world.</p>
<p>I will definitely continue my Ultima Underworld playthrough! But it&rsquo;s somewhat on the backburner for now.</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to New%20opportunity">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Ultima Underworld</title><link>https://pensiveibex.com/blog/2024/12/ultima-underworld/</link><pubDate>Sun, 08 Dec 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/12/ultima-underworld/</guid><description>
<![CDATA[<p><a href="https://brainbaking.com">Wouter</a> roped me into playing Ultima Underworld. It&rsquo;s the <a href="https://www.dosgameclub.com/">DOS Game Club</a> of the months december, january and february. I haven&rsquo;t played any Ultima game before. So now, here I am, playing a DOS game on a Linux machine. Oh how turns have tabled.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/12/ultima-underworld/ultima-underworld.png" class="lightbox">
		<img src="/blog/2024/12/ultima-underworld/ultima-underworld_hu_e51a42e1c0f9be17.png" class="center " loading="lazy">
	</a>
	
</figure></p>
<p>I had to do a little tweaking, I installed the <a href="https://johnglassmyer.github.io/UltimaHacks/patcher-site/">hack</a> for easier movement in the game. Then <a href="https://www.pcgamingwiki.com/wiki/Ultima_Underworld:_The_Stygian_Abyss#Piano_footstep_sounds">PCGamingWiki</a> helped me fix my sound in-game (by installing Sound Blaster Pro).</p>
<p>After that it was smooth sailing. If you&rsquo;re interested in joining me on my journey through the Stygian Abyss you can find a narrated playthrough <a href="">right here</a>.</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Ultima%20Underworld">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Test code smells</title><link>https://pensiveibex.com/blog/2024/11/test-code-smells/</link><pubDate>Thu, 28 Nov 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/11/test-code-smells/</guid><description>
<![CDATA[<div class="quote">
    <blockquote>
        It&#39;s just test code.
    </blockquote>
    <p class="author">
        <strong>-Anonymous</strong>
    </p>
</div>
<p>Have you ever heard this phrase? I can&rsquo;t wrap my head around the reason why test code should be treated with any less respect and care as production code. Our test code ensures production code keeps working as expected, thus it&rsquo;s our duty to maintain the test code as meticulously as the production code it guards.</p>
<p>Here are the 5 most common test code smells I&rsquo;ve seen you might want to look out for in your own projects.</p>
<h2 id="1-unstructured-tests">1. Unstructured tests</h2>
<p>Tests should follow a neat structure of Arrange-Act-Assert, first mentioned by <a href="https://xp123.com/3a-arrange-act-assert/">Bill Wake</a> in 2001 and popularized by Kent Beck in <a href="https://www.oreilly.com/library/view/test-driven-development/0321146530/">Test Driven Development: By Example</a>. Do check out the excellent post by Bill Wake on the reasoning for this.</p>
<p>I&rsquo;ll briefly summarize it here, you want to group your test code in three blocks. Arrange, where you set up the state for the part of the application that you are testing. Act, where you call production code. Assert, where you check the results of the code that is being tested.</p>
<p>A personal preference of mine is to leave a blank line between the Arrange, Act and Assert blocks. No need to annotate those blocks with comments, a simple blank line suffices in most cases. In more complex cases you might want to refactor the Arrange blocks to their own function(s).</p>
<p>Typically if you can&rsquo;t describe a test in the Arrange-Act-Assert pattern, you might want to create multiple tests for the different states you&rsquo;re trying to write a test for.</p>
<h3 id="bad">BAD</h3>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-csharp" data-lang="csharp"><span style="display:flex;"><span><span style="color:#a6e22e">[Test]</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> Period_ExtendsAndShortensPeriodIfProvidedDatesAreLargerOrShorterThanCurrentEndDateRespectively() 
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">var</span> period = <span style="color:#66d9ef">new</span> Period(<span style="color:#66d9ef">new</span> DateTime(<span style="color:#ae81ff">2024</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">1</span>), <span style="color:#66d9ef">new</span> DateTime(<span style="color:#ae81ff">2024</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">31</span>));
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">var</span> extendDate = <span style="color:#66d9ef">new</span> DateTime(<span style="color:#ae81ff">2024</span>, <span style="color:#ae81ff">11</span>, <span style="color:#ae81ff">15</span>);
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    period.ExtendTo(extendDate);
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    Assert.That(period.End, Is.EqualTo(extendDate));
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//another arrange</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">var</span> shortenDate = <span style="color:#66d9ef">new</span> DateTime(<span style="color:#ae81ff">2024</span>, <span style="color:#ae81ff">11</span>, <span style="color:#ae81ff">10</span>);
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//another act</span>
</span></span><span style="display:flex;"><span>    period.ShortenTo(shortenDate);
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//another assert</span>
</span></span><span style="display:flex;"><span>    Assert.That(period.End, Is.EqualTo(shortenDate));
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div><h3 id="good">GOOD</h3>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-csharp" data-lang="csharp"><span style="display:flex;"><span><span style="color:#a6e22e">[Test]</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> Period_ExtendTo_ExtendsPeriodToTheNewDateIfNewDateIsLargerThanCurrentEndDate() 
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">var</span> period = <span style="color:#66d9ef">new</span> Period(<span style="color:#66d9ef">new</span> DateTime(<span style="color:#ae81ff">2024</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">1</span>), <span style="color:#66d9ef">new</span> DateTime(<span style="color:#ae81ff">2024</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">31</span>));
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">var</span> extendDate = <span style="color:#66d9ef">new</span> DateTime(<span style="color:#ae81ff">2024</span>, <span style="color:#ae81ff">11</span>, <span style="color:#ae81ff">15</span>);
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    period.ExtendTo(extendDate);
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    Assert.That(period.End, Is.EqualTo(extendDate));
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">
</span></span></span><span style="display:flex;"><span><span style="color:#a6e22e">[Test]</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> Period_Shorten_ShortensPeriodToTheNewDateIfNewDateIsSmallerThanCurrentEndDate()
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">var</span> period = <span style="color:#66d9ef">new</span> Period(<span style="color:#66d9ef">new</span> DateTime(<span style="color:#ae81ff">2024</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">1</span>), <span style="color:#66d9ef">new</span> DateTime(<span style="color:#ae81ff">2024</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">31</span>));
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">var</span> shortenDate = <span style="color:#66d9ef">new</span> DateTime(<span style="color:#ae81ff">2024</span>, <span style="color:#ae81ff">11</span>, <span style="color:#ae81ff">10</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    period.ShortenTo(shortenDate);
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    Assert.That(period.End, Is.EqualTo(shortenDate));
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div><h2 id="2-general-names">2. General Names</h2>
<p>As with production code, the most important thing to think about is clear communication of what you&rsquo;re doing. As we are writing code, the best way to do that is for us to write meaningful method and variable names.</p>
<p>It doesn&rsquo;t suffice mentioning in a test name that an error is expected. You have to be more specific. Under which circumstances? What kind of error? Being specific creates for robust tests with clear boundaries. It adds to the living documentation of your application, clearly documenting the possibilities of the API which can be found by searching for all references of the method in any modern IDE.</p>
<p>If a <code>CausesFailure</code> test fails on my local branch or CI, I&rsquo;ll have a hard time trying to figure out why it failed, and why it shouldn&rsquo;t fail. By giving tests a clear and specific name, you&rsquo;re giving future developers a leg up in being able to maintain the tests you have written to ensure the application keeps running smoothly.</p>
<h3 id="bad-1">BAD</h3>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#75715e">//Test name unclear, why does it fail?</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestPeriodExtendToFailure</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">period</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">period</span>.<span style="color:#a6e22e">New</span>(<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Date</span>(<span style="color:#ae81ff">2024</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">UTC</span>), <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Date</span>(<span style="color:#ae81ff">2024</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">31</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">UTC</span>))
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">period</span>.<span style="color:#a6e22e">ExtendTo</span>(<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Date</span>(<span style="color:#ae81ff">2024</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">15</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">UTC</span>))
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">require</span>.<span style="color:#a6e22e">ErrorIs</span>(<span style="color:#a6e22e">t</span>, <span style="color:#a6e22e">err</span>, <span style="color:#a6e22e">ErrDateIsBeforeCurrentEndDate</span>)
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div><h3 id="good-1">GOOD</h3>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">TestPeriodExtendToFailsIfProvidedDateIsBeforeCurrentEndDate</span>(<span style="color:#a6e22e">t</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">testing</span>.<span style="color:#a6e22e">T</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">period</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">period</span>.<span style="color:#a6e22e">New</span>(<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Date</span>(<span style="color:#ae81ff">2024</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">UTC</span>), <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Date</span>(<span style="color:#ae81ff">2024</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">31</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">UTC</span>))
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">period</span>.<span style="color:#a6e22e">ExtendTo</span>(<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Date</span>(<span style="color:#ae81ff">2024</span>, <span style="color:#ae81ff">10</span>, <span style="color:#ae81ff">15</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">UTC</span>))
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">require</span>.<span style="color:#a6e22e">ErrorIs</span>(<span style="color:#a6e22e">t</span>, <span style="color:#a6e22e">err</span>, <span style="color:#a6e22e">ErrDateIsBeforeCurrentEndDate</span>)
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div><h2 id="3-assert-all-the-things">3. Assert all the things</h2>
<p>Your test should only contain assertions that are related to the condition that you are testing. The point of a test is to have a clear boundary of what you are testing, if code fails in this engineered very specific case, I know exactly what the cause is and where I should look.</p>
<p>If a test contains more than one assert, it might be unclear why test fails. I&rsquo;ve seen this happen, mostly when a test is created by copy pasting an already existing test. The assertions aren&rsquo;t removed but instead are added to.</p>
<p>I have also seen this at times, as sanity assertions. Where developers have added extra assertions in code to make sure a certain state is guaranteed within this test, even though these conditions are covered in other tests. Not only is this unnecessary clutter in the test when reading and understanding the test, it also causes the test to fail for reasons unrelated to the test condition.</p>
<h3 id="bad-2">BAD</h3>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#a6e22e">describe</span>(<span style="color:#e6db74">&#39;Period tests&#39;</span>, () =&gt; {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">it</span>(<span style="color:#e6db74">&#39;should initialize the class correctly&#39;</span>, () =&gt; {
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">begin</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Date(<span style="color:#e6db74">&#34;2024-10-01&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">end</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Date(<span style="color:#e6db74">&#34;2024-10-31&#34;</span>);
</span></span><span style="display:flex;"><span>        
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">period</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">Period</span>(<span style="color:#a6e22e">begin</span>, <span style="color:#a6e22e">end</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">expect</span>(<span style="color:#a6e22e">period</span>.<span style="color:#a6e22e">Start</span>).<span style="color:#a6e22e">toEqual</span>(<span style="color:#a6e22e">begin</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">expect</span>(<span style="color:#a6e22e">period</span>.<span style="color:#a6e22e">End</span>).<span style="color:#a6e22e">toEqual</span>(<span style="color:#a6e22e">end</span>);
</span></span><span style="display:flex;"><span>    })
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">it</span>(<span style="color:#e6db74">&#39;should return the correct number of days in the given period&#39;</span>, () =&gt; {
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">begin</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Date(<span style="color:#e6db74">&#34;2024-10-01&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">end</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Date(<span style="color:#e6db74">&#34;2024-10-31&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">period</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">Period</span>(<span style="color:#a6e22e">begin</span>, <span style="color:#a6e22e">end</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">//Unnecessary assertions copied from the test above it
</span></span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">expect</span>(<span style="color:#a6e22e">period</span>.<span style="color:#a6e22e">Start</span>).<span style="color:#a6e22e">toEqual</span>(<span style="color:#a6e22e">begin</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">expect</span>(<span style="color:#a6e22e">period</span>.<span style="color:#a6e22e">End</span>).<span style="color:#a6e22e">toEqual</span>(<span style="color:#a6e22e">end</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">expect</span>(<span style="color:#a6e22e">period</span>.<span style="color:#a6e22e">Days</span>()).<span style="color:#a6e22e">toEqual</span>(<span style="color:#ae81ff">31</span>);
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>});</span></span></code></pre></div><h3 id="good-2">GOOD</h3>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#a6e22e">describe</span>(<span style="color:#e6db74">&#39;Period tests&#39;</span>, () =&gt; {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">it</span>(<span style="color:#e6db74">&#39;should initialize the class correctly&#39;</span>, () =&gt; {
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">begin</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Date(<span style="color:#e6db74">&#34;2024-10-01&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">end</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Date(<span style="color:#e6db74">&#34;2024-10-31&#34;</span>);
</span></span><span style="display:flex;"><span>        
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">period</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">Period</span>(<span style="color:#a6e22e">begin</span>, <span style="color:#a6e22e">end</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">expect</span>(<span style="color:#a6e22e">period</span>.<span style="color:#a6e22e">Start</span>).<span style="color:#a6e22e">toEqual</span>(<span style="color:#a6e22e">begin</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">expect</span>(<span style="color:#a6e22e">period</span>.<span style="color:#a6e22e">End</span>).<span style="color:#a6e22e">toEqual</span>(<span style="color:#a6e22e">end</span>);
</span></span><span style="display:flex;"><span>    })
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">it</span>(<span style="color:#e6db74">&#39;should return the correct number of days in the given period&#39;</span>, () =&gt; {
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">begin</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Date(<span style="color:#e6db74">&#34;2024-10-01&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">end</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> Date(<span style="color:#e6db74">&#34;2024-10-31&#34;</span>);
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">period</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">new</span> <span style="color:#a6e22e">Period</span>(<span style="color:#a6e22e">begin</span>, <span style="color:#a6e22e">end</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">expect</span>(<span style="color:#a6e22e">period</span>.<span style="color:#a6e22e">Days</span>()).<span style="color:#a6e22e">toEqual</span>(<span style="color:#ae81ff">31</span>);
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>});</span></span></code></pre></div><h2 id="4-arrange-noise">4. Arrange noise</h2>
<p>I&rsquo;m a big fan of using the <code>Builder</code> pattern for creating setup data in tests. By default, the builder contains a valid object definition that you can just <code>.Build()</code> out of the box, but you can pass in multiple overrule statements, to mold the data to your needs.</p>
<p>The drawback of this approach is the human nature of copy pasting, and not cleaning up the parts they don&rsquo;t need for the test they&rsquo;re writing. When the test does fail at some point, this leaves the reader needing more mental capacity to understand what is being set up in the Arrange block of the test.</p>
<p>As mentioned previously, in order to maintain the clear boundaries of the test, you want to cut the fluff. Get rid of all the parts that aren&rsquo;t strictly needed to write your test.</p>
<h3 id="bad-3">BAD</h3>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-csharp" data-lang="csharp"><span style="display:flex;"><span><span style="color:#a6e22e">[Test]</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> IsAvailable_ReturnsTrueIfBookIsInStock()
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//Title and author don&#39;t matter for this test, they can be omitted for their default values</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">var</span> book = BookBuilder.NewBook()
</span></span><span style="display:flex;"><span>                            .WithTitle(<span style="color:#e6db74">&#34;The Martian&#34;</span>)
</span></span><span style="display:flex;"><span>                            .WithAuthor(<span style="color:#e6db74">&#34;Andy Weir&#34;</span>)
</span></span><span style="display:flex;"><span>                            .WithISBN(<span style="color:#e6db74">&#34;9780804139021&#34;</span>)
</span></span><span style="display:flex;"><span>                            .Build();
</span></span><span style="display:flex;"><span>    Db.Insert(book);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    Assert.That(service.IsAvailable(book.ISBN), Is.True);
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div><h3 id="good-3">GOOD</h3>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-csharp" data-lang="csharp"><span style="display:flex;"><span><span style="color:#a6e22e">[Test]</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> IsAvailable_ReturnsTrueIfBookIsInStock()
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">var</span> book = BookBuilder.NewBook()
</span></span><span style="display:flex;"><span>                            .WithISBN(<span style="color:#e6db74">&#34;9780804139021&#34;</span>)
</span></span><span style="display:flex;"><span>                            .Build();
</span></span><span style="display:flex;"><span>    Db.Insert(book);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    Assert.That(service.IsAvailable(book.ISBN), Is.True);
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div><h2 id="5-test-god-class">5. Test God class</h2>
<p>Production code isn&rsquo;t the only place where you might come into contact with the God Class smell. I&rsquo;ve seen test files where a clean and simple setup method has been written, which has seen several additions as new test code is added to the same class. And at some point, a developer comes along and asks himself, I don&rsquo;t really need all the setup code provided by this class for my test. In fact, it even interferes with what I&rsquo;m trying to test. I&rsquo;ll just clear the database in my test (or parts of it) and write my own little setup to keep my test self-contained.</p>
<p>It&rsquo;s a good reflex, but wrong execution. It might be better to leverage this code in its own file, which probably should have been done with the other test cases in the God class as well, and might otherwise be an indication that the class that is under test might be a God class itself.</p>
<h3 id="bad-4">BAD</h3>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">suite</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">BookServiceTestSuite</span>) <span style="color:#a6e22e">SetupTest</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">suite</span>.<span style="color:#a6e22e">user</span> = <span style="color:#a6e22e">UserBuilder</span>.<span style="color:#a6e22e">New</span>().<span style="color:#a6e22e">Build</span>()
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">suite</span>.<span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Create</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">user</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">book1</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">BookBuilder</span>.<span style="color:#a6e22e">New</span>().
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">WithTitle</span>(<span style="color:#e6db74">&#34;The Martian&#34;</span>).
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">WithAuthor</span>(<span style="color:#e6db74">&#34;Andy Weir&#34;</span>).
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">WithISBN</span>(<span style="color:#e6db74">&#34;9780804139021&#34;</span>).
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">WithStatusCheckedOut</span>(<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>(), <span style="color:#a6e22e">suite</span>.<span style="color:#a6e22e">user</span>).
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">Build</span>()
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">book2</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">BookBuilder</span>.<span style="color:#a6e22e">New</span>().
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">WithTitle</span>(<span style="color:#e6db74">&#34;The Theory of Everything Else&#34;</span>).
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">WithAuthor</span>(<span style="color:#e6db74">&#34;Dan Schreiber&#34;</span>).
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">WithISBN</span>(<span style="color:#e6db74">&#34;9780063259195&#34;</span>).
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">Build</span>()
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">suite</span>.<span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Create</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">book1</span>, <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">book2</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">suite</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">BookServiceTestSuite</span>) <span style="color:#a6e22e">TestReturnBookWithLateFeesShouldSubtractFeesFromUserBalance</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">//Clear all previous setup and create our own</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">suite</span>.<span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Delete</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">Book</span>{})
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">book</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">BookBuilder</span>.<span style="color:#a6e22e">New</span>().
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">WithTitle</span>(<span style="color:#e6db74">&#34;Flowers for Algernon&#34;</span>).
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">WithAuthor</span>(<span style="color:#e6db74">&#34;Daniel Keyes&#34;</span>).
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">WithISBN</span>(<span style="color:#e6db74">&#34;9780575116740&#34;</span>).
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">WithStatusCheckedOut</span>(<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>().<span style="color:#a6e22e">Add</span>(<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#f92672">-</span><span style="color:#ae81ff">60</span>), <span style="color:#a6e22e">suite</span>.<span style="color:#a6e22e">user</span>).
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">Build</span>()
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">suite</span>.<span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Create</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">book</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">user</span>.<span style="color:#a6e22e">balance</span> = <span style="color:#a6e22e">Book</span>.<span style="color:#a6e22e">LATE_FEE</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">suite</span>.<span style="color:#a6e22e">service</span>.<span style="color:#a6e22e">Return</span>(<span style="color:#a6e22e">book</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">assert</span>.<span style="color:#a6e22e">Equal</span>(<span style="color:#a6e22e">t</span>, <span style="color:#ae81ff">0</span>, <span style="color:#a6e22e">user</span>.<span style="color:#a6e22e">balance</span>)
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div><h3 id="good-4">GOOD</h3>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">suite</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">BookServiceTestSuite</span>) <span style="color:#a6e22e">SetupTest</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">suite</span>.<span style="color:#a6e22e">user</span> = <span style="color:#a6e22e">UserBuilder</span>.<span style="color:#a6e22e">New</span>().<span style="color:#a6e22e">WithBalance</span>(<span style="color:#a6e22e">book</span>.<span style="color:#a6e22e">LATE_FEE</span>).<span style="color:#a6e22e">Build</span>()
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">suite</span>.<span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Create</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">user</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">book</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">BookBuilder</span>.<span style="color:#a6e22e">New</span>().
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">WithTitle</span>(<span style="color:#e6db74">&#34;Flowers for Algernon&#34;</span>).
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">WithAuthor</span>(<span style="color:#e6db74">&#34;Daniel Keyes&#34;</span>).
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">WithISBN</span>(<span style="color:#e6db74">&#34;9780575116740&#34;</span>).
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">WithStatusCheckedOut</span>(<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Now</span>().<span style="color:#a6e22e">Add</span>(<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">0</span>, <span style="color:#f92672">-</span><span style="color:#ae81ff">60</span>), <span style="color:#a6e22e">suite</span>.<span style="color:#a6e22e">user</span>).
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">Build</span>()
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">suite</span>.<span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Create</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">book</span>)
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">suite</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">BookServiceTestSuite</span>) <span style="color:#a6e22e">TestReturnBookWithLateFeesShouldSubtractFeesFromUserBalance</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">suite</span>.<span style="color:#a6e22e">service</span>.<span style="color:#a6e22e">Return</span>(<span style="color:#a6e22e">book</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">assert</span>.<span style="color:#a6e22e">Equal</span>(<span style="color:#a6e22e">t</span>, <span style="color:#ae81ff">0</span>, <span style="color:#a6e22e">user</span>.<span style="color:#a6e22e">balance</span>)
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div>
        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Test%20code%20smells">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Chants of Sennaar</title><link>https://pensiveibex.com/blog/2024/11/chants-of-sennaar/</link><pubDate>Wed, 20 Nov 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/11/chants-of-sennaar/</guid><description>
<![CDATA[<div class="haiku">
    <blockquote>
        I don&#39;t understand<br />
        Please repeat and make gestures<br />
        Now I understand
    </blockquote>
</div>
<p>So I&rsquo;ve had this interest for constructed languages ever since I&rsquo;ve read <a href="https://app.thestorygraph.com/books/ac3ea915-993d-4f30-8632-0f91e4ad0704">Project Hail Mary</a>. Chants of Sennaar was one of the games that came up in my search of games that also did something with learning and discovering new languages. The other two I&rsquo;m still interested in, but will have to be looked at later are <a href="https://opencritic.com/game/7591/heavens-vault">Heaven&rsquo;s Vault</a> and <a href="https://www.ifwiki.org/The_Edifice">The Edifice</a>.</p>
<p>Anyway, in Chants of Sennaar you&rsquo;re a nameless speechless character where everybody is just desperate to speak to you and communicate, ignorant to the fact that you don&rsquo;t speak their language, or any language really. As far as immersion goes, this hasn&rsquo;t really been addressed in the game&rsquo;s story. Many games have main characters that never utter a single word, but in a game that is focussed around communication and language this was a bit ironic.</p>
<p>All characters talk to each other using unique glyphs. Where each glyph equals a word. You collect all these glyphs in a small compendium. Whenever you have investigated enough points of interest in the game, the book unlocks a new page with a couple of drawings, where you have to couple them with the correct glyphs. If all glyphs are correct for the current page the meaning of the glyphs is permanently unlocked and is visible as translation when talking to the different inhabitants of the tower.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/11/chants-of-sennaar/chants-of-sennaar-book.png" class="lightbox">
		<img src="/blog/2024/11/chants-of-sennaar/chants-of-sennaar-book_hu_54b4bbf4129ae87.png" class="center " loading="lazy" alt="Book with glyphs">
	</a>
	
</figure></p>
<p>Before unlocking the glyphs, you have the option to assign a word to a glyph with your keyboard. Which makes it easy to keep track of assumptions and guesses. Some glyphs were bang on the money immediately and didn&rsquo;t pose much of a challenge. Others I was way off for a while. I think I had the most trouble when entering the third level of the tower. I was bombarded by a whole set of new glyphs and it took me the most time to translate the glyphs and find their meaning.</p>
<p>What was somewhat frustrating is that after finding new glyphs, I immediately jumped to the notebook to translate the glyphs to their supposed meaning. You can do this action during a conversation or examination of a POI. Jumping out of an examination or dialogue triggers the unlock of a new page with drawings to link your glyphs. My eagerness to immediately note my findings in my little booklet felt wasted as I would be unlocking their confirmed meaning just a few moments later.</p>
<p>Another small gripe, which I have to admit I am guilty of, is guessing the last glyph of a page. There were a couple of times I was extremely sure of two of three glyphs I had to link to a drawing and just went through the remaining glyphs one by one for the final unlock of the page. It&rsquo;s not pretty, and I&rsquo;m not sure the developers should have addressed it, as it is just laziness on the player&rsquo;s side. And even though I knew it was deriving me from the full gratification of  unlocking the glyphs using my own brainpower, abusing the system was just too easy and allowed me to progress faster. Which in the end was the aim of the game, right? Translate, explore, rinse and repeat.</p>
<p>Learning each language in isolation was pretty fun, and fairly straight forward. The languages themselves could have been more diverse from each other, the only real core difference between languages was mostly how words are pluralized. If you do some research into modern languages you find plenty of different constructs that could have made every language feel more unique instead of just a new set of glyphs. Nevertheless finding out what each glyph meant and putting it all together was still an engaging and gratifying activity.</p>
<p>What wasn&rsquo;t fun was the stealth gameplay sprinkled in. There are a couple of segments in the game where you can&rsquo;t be seen by the inhabitants and you have to stealth your way to the next screen. It felt out of place in an otherwise very enjoyable game. I&rsquo;m sure this is a personal thing, it wasn&rsquo;t particularly hard, but I still dreaded these segments. I guess they&rsquo;re just not my cup of tea. I am thankful to the devs for providing many savepoints throughout the stealth segments. I would have been a very frustrated camper if I had to restart every stealth segment.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/11/chants-of-sennaar/chants-of-sennaar-stealth.png" class="lightbox">
		<img src="/blog/2024/11/chants-of-sennaar/chants-of-sennaar-stealth_hu_b9669e21ae95df23.png" class="center " loading="lazy" alt="Stealth segment">
	</a>
	
</figure></p>
<p>A bit further into the game, you had a chase scene with another AI-driven character. I really liked that, there were clear &ldquo;rules&rdquo; to the chase. Lighted areas couldn&rsquo;t be entered and you had to work your way through without it reaching you. There was a bit of stealth here too, but due to the clear restrictions it felt more like a puzzle traversing the screen. Instead of just waiting for patrolling guards to turn their backs and moving at the right time. The latter providing no real challenge, just a tedious waiting game.</p>
<p>In order to fully complete the game, you have to make the inhabitants of the different floors of the tower understand each other. You do this by translating one set of language glyphs to another. This is another small gripe I had with the game, but is mostly forgiven. Which is that you can&rsquo;t really take long breaks from the game. Leaving too much time between play sessions, will result in forgetting the grammar rules of language x or y, which makes translation all the harder. The game provides you with the little book which is a vocabulary of all each language. But if you have forgotten the grammar, you&rsquo;ll have to go back to talk to people to remember how it was meant to be spoken. Since it&rsquo;s a short game, this isn&rsquo;t a huge problem as I could reach the end in little over a week of sporadic gaming.</p>
<p>I&rsquo;ve had some minor irritations with the game, but would still recommend it to anyone who likes a puzzle game with some interest in linguistics. The constructed languages could have been made more diverse, but the core gameplay of learning each language and translating for different denizens of the tower was fun and I would love to see a game expand on this some more.</p>
<div class="row">
    <div class="column pros border-right">
        <h4 style="display: flex; justify-content: center;">Likes</h4>
        <ul>
        
        <li>Learning new languages is fun</li>
        
        <li>Semi-optional challenging content</li>
        
        <li>Little handholding creates satisfaction</li>
        
    </ul>
    </div>
    <div class="column cons">
        <h4 style="display: flex; justify-content: center;">Dislikes</h4>
        <ul>
            
            <li>Stealth segments</li>
            
            <li>Guessing solutions takes away part of the gratification</li>
            
        </ul>
    </div>
</div>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Chants%20of%20Sennaar">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Building a walk-in closet</title><link>https://pensiveibex.com/blog/2024/11/building-a-walk-in-closet/</link><pubDate>Tue, 05 Nov 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/11/building-a-walk-in-closet/</guid><description>
<![CDATA[<p>As part of the move to the new house, there was still one little project that needed finishing. We decided instead of being regular closets and cabinets that we&rsquo;d turn a room into a walk-in closet.</p>
<p>About a month ago we started the drawing out plans and schematics of what it might look like. We went through three or four drafts before settling on the current configuration. It&rsquo;s a mix of using scaffolding bars and shelves. The wood was ordered in a local woodshop, where to cut and finished every plank according to my instructions. The scaffolding bars were ordered online.</p>
<p>Next I needed the fixtures to fixate the shelves to the wall. And plugs and accompanying screws. The fixtures were definitely the most expensive thing of the whole list. Here is a little breakdown of the cost of all required materials.</p>
<table>
  <thead>
      <tr>
          <th style="text-align: left"></th>
          <th></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: left">Shelves</td>
          <td style="text-align: right">€304.07</td>
      </tr>
      <tr>
          <td style="text-align: left">Scaffolding</td>
          <td style="text-align: right">€251.07</td>
      </tr>
      <tr>
          <td style="text-align: left">Fixtures</td>
          <td style="text-align: right">€227.94</td>
      </tr>
      <tr>
          <td style="text-align: left">Plugs &amp; screws</td>
          <td style="text-align: right">€100.00</td>
      </tr>
      <tr>
          <td style="text-align: left"><strong>GRAND TOTAL</strong></td>
          <td style="text-align: right"><strong>€883.08</strong></td>
      </tr>
  </tbody>
</table>
<p>Still cheaper than Ikea wardrobes of the same size.</p>
<p>I grabbed my tools and went to work. I borrowed a laser from a buddy of mine, which really helped a lot for mounting the initial bottom shelf. I set the laser to the correct height, and mounted the fixtures to the wall, checked if the shelf was still level after mounting and <strong>huzzah!</strong> The shelf was perfectly level and I had to confidence to keep going. For the shelves that needed to go above it, I figured I would measure the distance between the two and then use my level the align it just right. I&rsquo;ve had to redo a measure more times than I care to admit, because I left my pencil somewhere out of reach. I really should get me one of this fancy <a href="https://www.walmart.com/ip/Mens-Workwear-Trousers-Cargo-Utility-Work-Pants-with-Cordura-Knee-Reinforcement/558357765">worker&rsquo;s pants</a>.</p>
<p>I finished putting the shelves against the first wall after an afternoon of work. Which was mostly a lot of measuring, doubting myself, remeasuring and checking every little step of the process before doing anything I couldn&rsquo;t undo.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/11/building-a-walk-in-closet/first-shelves.png" class="lightbox">
		<img src="/blog/2024/11/building-a-walk-in-closet/first-shelves_hu_f2f706e21e48c5b1.png" class="center " loading="lazy" alt="The first shelves">
	</a>
	
</figure></p>
<p>I decided to call it quits that day, because the natural light was starting to dim and I was getting tired. The next wall would be a difficult one, I knew, and I didn&rsquo;t want to risk making mistakes due to exhaustion. I took a day off from work to work on the project again, and about everything that could go wrong that day, did. You just can&rsquo;t have a DIY project without stuff going wrong, it&rsquo;s how you deal with those hick-ups that is the real fun part.</p>
<p>I started off by installing the bottom shelf that had to align with the bottom shelf of the other wall. I knew the height, I used the laser to align it perfectly with the already hanging shelf. I installed all the fixtures, they&rsquo;re all level, great. I lay the shelf on top of the fixtures, lo and behold, it&rsquo;s about a centimeter higher than the already hanging shelf. <em>Sigh</em>. I figured there wasn&rsquo;t really anything I could do about it now. I wasn&rsquo;t going to redo the fixtures, and thought I could fix it be attaching a small wooden plank to the bottom of the lower shelf to lift it up and match the height of the other one.</p>
<p>Next came the top shelf. This one also needed to match the height of the top shelf of the wall I had already installed. I did about the same thing as I did with the bottom shelf. Measured everything out, even more meticulously this time. You guessed it, they didn&rsquo;t match. This time. The shelf was lower than the other one. That&rsquo;s two for two on the failed-to-match-the-same-height list. It was at this point that I also realized I forgot to buy some small fixtures to attach both shelves to each other. No way they would match height exactly, you need to attach them to each other. This wasn&rsquo;t an expensive purchase, a little under €4 for 4 brackets.</p>
<p>Next up was the first scaffolding bar to mount to the wall. It&rsquo;s a long bar. Just over 2 meters. Handling this by myself was not smart. I measured where all the wall fixtures had to go, set them all level. Attached everything. Then when I took the bar and wanted to attach it to the wall, it didn&rsquo;t fit. Because of course it didn&rsquo;t. Honestly, what was I expecting? The day had been frought with mistake after mistake, so why not add another one to the list? I missed the mark by about 2.5 centimeters.</p>
<p>I had it at that point. I left all my stuff in the room, closed the door behind me and went home. I had to come back to this with a fresh head. I asked my buddy if I got borrow his grinding machine, because I would need to cut off a bit of the scaffolding in order to make it fit. He also gave me some advice on how to fix the shelves of varying heights. Instead of using more wood to fix the height difference, he recommended using plastic wedges, which he also had in excess that I could borrow.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/11/building-a-walk-in-closet/shelves-and-scaffolding.png" class="lightbox">
		<img src="/blog/2024/11/building-a-walk-in-closet/shelves-and-scaffolding_hu_2faa329c20698fea.png" class="center " loading="lazy" alt="Unfortunately I didn&rsquo;t take a picture of the errors, but here&rsquo;s the finished wall">
	</a>
	
</figure></p>
<p>My girlfriend called me stubborn to do that part on my own. It&rsquo;s true, I am. So for the next and last part of the walk-in closet, she came to help me.</p>
<p>We first fixed the shelves of varying heights with the wedges. Which was a fairly easy process. Instant fix. The wedges came in different colours though. Each colour was associated with a thickness. The ones we needed for the top shelf were the yellow ones. And unfortunately that was quite visible when looking at the shelves. Luckily, I remembered I still had some black graffiti paint in a can. So after a quick spray-up<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> outside, I now had the wedges in a colour that would blend in well with the black fixtures of the shelves.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/11/building-a-walk-in-closet/wedges.png" class="lightbox">
		<img src="/blog/2024/11/building-a-walk-in-closet/wedges_hu_46b320a491f9612b.png" class="center " loading="lazy" alt="Perfection">
	</a>
	
</figure></p>
<p>Next up, sawing off 2.5cm of scaffolding. This went extremely smooth. I was glad to have some ear protectors from a previous project lying around, so that hellish scream of grinding metal wouldn&rsquo;t pierce my ears. Sparks were flying everywhere<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> - including my bare arms, which was not very smart. But I didn&rsquo;t singe or burn any hairs so, all&rsquo;s well that ends well, eh?</p>
<p>With that done, this wall was completely done and looking good! The wall facing the outside of the house was next, which didn&rsquo;t need a whole lot of work. Just two scaffolding bars. However, when drawing our design, we seemed to not have taken into account the curtain rod. The bars were too long. Again. At least I&rsquo;ve had some practice sawing one bar already, right? This time, 9cm needed to go off both bars. This time, I wore my sweater, just in case.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/11/building-a-walk-in-closet/scaffolding.png" class="lightbox">
		<img src="/blog/2024/11/building-a-walk-in-closet/scaffolding_hu_2edff5c2aa346ed.png" class="center " loading="lazy" alt="Scaffolding">
	</a>
	
</figure></p>
<p>Some assembly later, both bars are fixed to the wall, only for the next problem to pop up. We hung a coat hanger from the bar, and it bumped into the bar of the other wall. <em>Sigh</em>. After debating which option is the best, we decided to shorten the long bar by 4.5cm. That way I could move the wall support, so that I could reuse two of the four holes.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/11/building-a-walk-in-closet/holes-still-to-fix.png" class="lightbox">
		<img src="/blog/2024/11/building-a-walk-in-closet/holes-still-to-fix_hu_948a137e0029a10b.png" class="center " loading="lazy" alt="The holes I still need to fix">
	</a>
	
</figure></p>
<p>By this time, I felt like a real champ with the grinding machine. I&rsquo;ve used it once before to cut stone and it slipped out of my hands then, so I was a bit apprehensive to use it again. But everything went well, thank all the Gods above. The wall mount got moved and the bar was refitted. Just one more wall with 7 shelves and 2 bars and that would be the end of it.</p>
<p>Not a whole lot went wrong here. Apart from the very bottom shelf where I made an measuring error and had to rehang a fixture everything went smooth. Tubular<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>!</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/11/building-a-walk-in-closet/more-shelves.png" class="lightbox">
		<img src="/blog/2024/11/building-a-walk-in-closet/more-shelves_hu_50a6ada6856380e5.png" class="center " loading="lazy" alt="The final wall">
	</a>
	
</figure></p>
<p>And there you have it. I just need to fill and repaint some holes and that&rsquo;s it. This was the last hurdle to move in to the house, and we&rsquo;re preparing everything for the actual move somewhere this week. Let&rsquo;s go!</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://youtu.be/iDDLdcmFOek?t=127">GTA-Style</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>I later learned that the tiny metal particles flying around after grinding are called <a href="https://en.wikipedia.org/wiki/Swarf">swarf</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Let&rsquo;s bring it back!&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Building%20a%20walk-in%20closet">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>October 2024 recap</title><link>https://pensiveibex.com/blog/2024/11/october-2024-recap/</link><pubDate>Fri, 01 Nov 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/11/october-2024-recap/</guid><description>
<![CDATA[<h2 id="private-life">Private life</h2>
<p>I&rsquo;m finally moving into the new house in about a week or so. Just finishing up building the walk-in closet and after that my girlfriend, our dogs and I will be moving into the new house! Exciting times! I&rsquo;ll be happy to have my own little room to myself again.</p>
<p>Apart from that I&rsquo;ve been dabbling with Godot a bit recently. Currently remaking the classic breakout from scratch. Will probably try to add some twists to the game, to kind of learn the engine. I have that hunkering to make a game, but for now I&rsquo;m keeping the scope intentionally small so I can finish this in a reasonable amount of time.</p>
<p>I&rsquo;ve also started keeping track of my time with an app on my mobile. I&rsquo;ll have graphs of that to share in next month&rsquo;s recap.</p>
<h2 id="series">Series</h2>
<h3 id="the-oa"><a href="https://www.rottentomatoes.com/tv/the_oa">The OA</a></h3>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/11/october-2024-recap/the-oa.png" class="lightbox">
		<img src="/blog/2024/11/october-2024-recap/the-oa_hu_e809d4a54024eae.png" class="center " loading="lazy" alt="The OA">
	</a>
	
</figure></p>
<p><em>ONGOING</em></p>
<p>I love the weird titles. This one has such a great premise, all outlandish ideas are presented in a believable way. As a viewer I was still kind of thinking &ldquo;sure, the writers are just using this as a Deus Ex Machina plot device&rdquo;. But it still left me intrigued, we&rsquo;re currently in season 2 where everything just got turned upside down. And I&rsquo;m told the ending isn&rsquo;t satisfactory as Netflix canceled the show.</p>
<h2 id="movies">Movies</h2>
<h3 id="rebel-ridge"><a href="https://www.rottentomatoes.com/m/rebel_ridge">Rebel Ridge</a></h3>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/11/october-2024-recap/rebel-ridge.png" class="lightbox">
		<img src="/blog/2024/11/october-2024-recap/rebel-ridge_hu_eeca9dff65e0ef23.png" class="center " loading="lazy" alt="Rebel Ridge">
	</a>
	
</figure></p>
<p>If you had given the script of this movie to any old director, this would have turned into a Hollywood action-packed movie. Instead Saulnier turned this into a story that never loses its suspense. You can feel the tension in the movie from the very first moment and it never lets up. I feel like the movie is a mirror being held up, showing what society can feel like for the black community.</p>
<h3 id="it"><a href="https://www.rottentomatoes.com/m/its_whats_inside">It&rsquo;s What&rsquo;s Inside</a></h3>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/11/october-2024-recap/its-whats-inside.png" class="lightbox">
		<img src="/blog/2024/11/october-2024-recap/its-whats-inside_hu_fc592f0075880eb4.png" class="center " loading="lazy" alt="It&rsquo;s What&rsquo;s Inside">
	</a>
	
</figure></p>
<p>I don&rsquo;t know how we found this movie, but again, such a great premise! I won&rsquo;t spoil anything, because I went into it not knowing what the movie was about and really enjoyed the discovery of the plot. The only thing I would say is that I would also be interested in watching a movie, that delved more into the psychology of what was happening in the movie.</p>
<p>It&rsquo;s a difficult topic to pull off, cinematographically, that is. And I think it was well portrayed and very enjoyable.</p>
<h2 id="books">Books</h2>
<p>Since my last post in July I have actually started, read and finished a bunch of books. A lot of this was due to my trip to Canada, where I had plenty of time in the evenings to read. Something I&rsquo;m more envious about now I&rsquo;m back in Belgium, as I seem to not have as much free time to do that. I won&rsquo;t be listing all the books I&rsquo;ve read during that time, back you can check them out and my reviews over on <a href="https://app.thestorygraph.com/profile/weyensl">my StoryGraph page</a>.</p>
<h3 id="the-algebraist-by-iain-m-banks"><a href="https://app.thestorygraph.com/books/89271571-50ca-4316-9d00-4fd74d3f6b8d">The Algebraist, by Iain M. Banks</a></h3>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/11/october-2024-recap/the-algebraist.png" class="lightbox">
		<img src="/blog/2024/11/october-2024-recap/the-algebraist_hu_aa11bb04557221b8.png" class="center " loading="lazy" alt="The Algebraist">
	</a>
	
</figure></p>
<p><em>READING</em></p>
<p>Can&rsquo;t say a whole lot about this book yet. It&rsquo;s my read-before-bed book. And I haven&rsquo;t been able to read a lot, usually falling asleep after finishing maybe one page.</p>
<h3 id="typeset-in-the-future-by-dave-addey"><a href="https://app.thestorygraph.com/books/9d6aa8bb-3337-4b57-b7cb-b87722af7746">Typeset in the Future, by Dave Addey</a></h3>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/11/october-2024-recap/typeset-in-the-future.png" class="lightbox">
		<img src="/blog/2024/11/october-2024-recap/typeset-in-the-future_hu_af39cc7375cc640f.png" class="center " loading="lazy" alt="Typeset in the Future">
	</a>
	
</figure></p>
<p><em>READING</em></p>
<p>This is the novelization of <a href="https://typesetinthefuture.com/">Dave Addey&rsquo;s blog</a> and it&rsquo;s great. I&rsquo;m loving every moment of the book, his attention to detail in every scene of the movies he talks about is extraordinary. For example, did you know that the keyboard during the self-destruct scene in Alien contains a lot of hints to buddhism? The amount of research that went into this is amazing. Hats off, tremendously entertaining!</p>
<h3 id="fairy-tale-by-stephen-king"><a href="https://app.thestorygraph.com/books/ac3ea915-993d-4f30-8632-0f91e4ad0704">Fairy Tale, by Stephen King</a></h3>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/11/october-2024-recap/fairy-tale.png" class="lightbox">
		<img src="/blog/2024/11/october-2024-recap/fairy-tale_hu_3e0afe889a95fafc.png" class="center " loading="lazy" alt="Fairy Tale">
	</a>
	
</figure></p>
<p><em>LISTENING</em></p>
<p>I still had an Audible credit lying around after my free Prime subscription for a month and decided to pick this book up. I have read The Dark Tower series in the past by Stephen King and haven&rsquo;t really read a lot else by him. I&rsquo;m not that into horror stories, on which he normally focuses. This is more of a fantasy book that&rsquo;s grounded in reality. I&rsquo;m about half-way through the book, the first part was pretty mundane plot-wise. I didn&rsquo;t think I was going to enjoy it, but I kept wanting to go back and know what would happen next. Stephen King is a fantastic story teller and I&rsquo;m interested where the story will go next.</p>
<h2 id="games">Games</h2>
<h3 id="the-longest-journey"><a href="https://www.metacritic.com/game/the-longest-journey/">The Longest Journey</a></h3>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/11/october-2024-recap/the-longest-journey.png" class="lightbox">
		<img src="/blog/2024/11/october-2024-recap/the-longest-journey_hu_286471f9d771e602.png" class="center " loading="lazy" alt="The Longest Journey">
	</a>
	
</figure></p>
<p><em>FINISHED</em></p>
<p>The Longest Journey, indeed. With a steep 20+ hours, I can&rsquo;t remember the last time I spent this many hours in a point-and-click adventure game. It&rsquo;s definitely above the curve. I think the story was great, any story that has a decent amount of worldbuilding will instantly suck me in. What I especially liked are the diary entries April writes during the game. Usually I just read those as a recap to know where I was in the story in between gaming sessions. But these entries felt so fresh. They give insights into how April thinks about situations that you might not have gotten if you just played the game. Every time the icon came up that a new diary page was available, I couldn&rsquo;t wait to read her personal thoughts on the situation.</p>
<p>I&rsquo;ll tell you what I could&rsquo;ve done without, though. The needlessly long walks. Holy moly! Some screens take 10+ seconds to traverse, that actually don&rsquo;t serve a purpose anymore after the initial setting of the scene. No more interactables on those screens, except for the person you have to go talk to all the way at the end. A double-click insta-traverse would have been very much welcome, and might have even shaved off an hour of game time.</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to October%202024%20recap">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Gas pedal controls</title><link>https://pensiveibex.com/blog/2024/10/gas-pedal-control/</link><pubDate>Fri, 18 Oct 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/10/gas-pedal-control/</guid><description>
<![CDATA[<p>Here&rsquo;s a new post category I&rsquo;ve dubbed <em>&ldquo;Here&rsquo;s a thought&rdquo;</em>. These are posts that originated as an idea, which I found fun to think about and research.</p>
<p>So&hellip; <strong>Here&rsquo;s a thought</strong>, what if the gas pedal of your car worked differently? I drive a Tesla Model Y since I started my career as a freelance IT consultant. One of the mechanics I had to get used to at first, was the engine braking when releasing the gas pedal. It&rsquo;s a mechanism that is actually integral for battery regeneration and thus allowing for more mileage. But I found it more finnicky to work than classic Diesel cars to maintain the same speed.</p>
<p>Depressing the pedal further, gives more gas. Releasing the pedal actively brakes. It&rsquo;s hard to find the middle ground and find the correct position to leave your gas pedal for the speed you want to drive. Why not use cruise control<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> to dictate the speed limit, you ask? I find, the adaptive cruise control implementation by Tesla to brake far too often compared to my previous cars. I don&rsquo;t know whether this is due to Belgian roads not being as straight-forward (quite literally with all the twists and turns) than in America or Canada. But it just boils down to a less than ideal experience. So I prefer to control the gas myself for a more smooth driving experience.</p>
<p>Given the way gas pedals work in electric cars, it might be worth considering to have a fixed speed setting midway through. Like a physical click the gas pedal stays in about halfway through. If you want to make the car go faster you depress the pedal to get more speed. Releasing the pedal between the bottom position and the half-way point does not make the car brake, you only use it to increase the speed of the car. If you release the pedal beyond the half-way point, the car does brake and allows you to come to a halt.</p>
<p>Here&rsquo;s a crude picture of what that might look like:</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/10/gas-pedal-control/gas-pedal-mechanic.png" class="lightbox">
		<img src="/blog/2024/10/gas-pedal-control/gas-pedal-mechanic_hu_2c3b8f839b08075f.png" class="center " loading="lazy" alt="Gas pedal controls">
	</a>
	
</figure></p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Did you know modern cruise control mechanics were invented in 1948? See the original patent <a href="https://web.archive.org/web/20190922164137/https://pdfpiw.uspto.gov/.piw?Docid=02519859&amp;homeurl=http://patft.uspto.gov/netacgi/nph-Parser%3FSect2%3DPTO1%2526Sect2%3DHITOFF%2526p%3D1%2526u%3D/netahtml/PTO/search-bool.html%2526r%3D1%2526f%3DG%2526l%3D50%2526d%3DPALL%2526S1%3D2519859.PN.%2526OS%3DPN/2519859%2526RS%3DPN/2519859&amp;PageNum=&amp;Rtype=&amp;SectionNum=&amp;idkey=NONE&amp;Input=View+first+page">via the Wayback Machine</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Gas%20pedal%20controls">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>The Weird</title><link>https://pensiveibex.com/blog/2024/10/the-weird/</link><pubDate>Fri, 11 Oct 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/10/the-weird/</guid><description>
<![CDATA[<p>First of all, apologies for the lack of content here. I&rsquo;ve been to Canada in September and have had some projects I&rsquo;ve been working on ever since (including all the prep work for moving house). I&rsquo;ll do a more detailed post on what I&rsquo;ve been up to exactly sometime later. For now, I&rsquo;d like to take a minute to talk about fringe science<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.</p>
<p>I remember my dad telling me stories as a kid about how he was interested in paranormal activity. I wouldn&rsquo;t say he&rsquo;s a believer, but he certainly is in the curious side of things. Being open to the unknown, and if not being able to explain things, being open to <em>experience</em> them. I haven&rsquo;t talked to him about it in ages. I guess I really should talk to him about it again. Over the past few years I&rsquo;ve been rekindling to the idea of <em>the weird</em> and it would be really interesting talking to him about how far his beliefs hold.</p>
<p>That said, I&rsquo;m not a full believer myself. At least not for the big ones (like ghosts, premonitions, telepathy, etc&hellip;), I&rsquo;d love for all of that to be a thing. I would love to live in a world where the seemingly unimaginable would be commonplace. Thought, that being said, it would only feel as something special if I had first experienced a world where those things would not exist&hellip; So that&rsquo;s somewhat of a catch 22 to really appreciate that.</p>
<p>A story I remember my dad telling me, and mind, stories are far and few between. My dad isn&rsquo;t the guy who endlessly bores you with the same stories. You get the story and that&rsquo;s it. You&rsquo;re supposed to know it now. It won&rsquo;t see the light of the day again, unless you explicitly bring it up again. He always told me, he could never confirm any paranormal activity, except for one occasion he could not explain. He told me about an experiment he did, about how he would leave a tape to record a certain frequency of sound. The tape would just be there, recording static most of the time. But at some point, it recorded a single word. It was a nonsense word. For the life of me, I can&rsquo;t remember what it was, and I&rsquo;ll have to ask my dad about it. But there it was, clear as day, amidst a whole load of nothingness.</p>
<p>It&rsquo;s not completely unthinkable to give reason to this. Someone in the neighbourhood might have been broadcasting on that frequency or one adjacent enough so that it might get picked up by the receiver. It&rsquo;s an obvious explanation. But somehow, I&rsquo;ve always liked that story for the mystery it presented to me as a child. To believe in an unknown world. A world of experiences that can&rsquo;t be rationally explained, and to be open to experiences that are unknown to us, and might remain unknowable for quite some time.</p>
<p>I&rsquo;m deeply envious for anyone who has these kind of experiences. The closest thing I have to something unexplainable is déjà vu, which I experience on a bi-frequently basis. The funny thing about this sense of déjà vu is that when I experience it, it might feel like something that has happened a day ago, or some weeks ago. But it might also be a memory of years ago. In fact, I&rsquo;ve been thinking about déjà vu a lot lately. The most prevalent theory<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> of déjà vu is that it is your brain preparing yourself for a situation your anxious about<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>. If anything, science has definitively proven that your brain is capable of making you believe things that aren&rsquo;t actually there. There are multiple studies that prove that we can&rsquo;t always trust are <a href="https://www.psychologytoday.com/us/blog/a-buoyant-life/202407/can-you-trust-your-memories">own memories</a>, our <a href="https://www.youtube.com/watch?v=ZflIMBxyIak">own eyes</a>, our <a href="https://www.youtube.com/watch?v=DphlhmtGRqI0">touch</a>. Basically, our senses can&rsquo;t be trusted. So I was wondering, if déjà vu really comes stems from anxiety and our brain tricks us into preparing for that situation, can déjà vu be triggered? Can an experiment be created where a subject is treated in such a way that it would trigger déjà vu? I&rsquo;ll have to get back to you on that&hellip;</p>
<p>This blog post has been inspired by <a href="https://sheldrake.org/">Rupert Sheldrake</a>. I first became aware of him through the podcast <a href="https://podcastindex.org/podcast/6365618">We Can Be Weirdos</a> by <a href="https://www.instagram.com/schreiberland/">Dan Schreiber</a>. I absolutely love that he is out there researching these and other phenomena that other scientists wouldn&rsquo;t touch with a ten-foot pole. I might not agree with all his theories, but they fascinate me. The unknown fascinates me, and I thought that was what science was all about. Realizing we don&rsquo;t yet know everything and being open to ideas that might seem completely out there. In some future generation people will look back at us and be amazed that we had no idea how the sense of being stared at<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>, for example, works. Much like we know look back to past generations and cannot believe that some things that are now taught in primary school weren&rsquo;t common knowledge in the past.</p>
<p>In a remarkable case of coincidence I hadn&rsquo;t realized that Merlin Sheldrake is Rupert&rsquo;s son. You may have heard of Merlin Sheldrake from writing <a href="https://app.thestorygraph.com/books/e8391742-77da-4a9c-aabd-f37975d2705b">Entangled Life</a> which launches the concept of the Wood Wide Web (and sits on my bookshelf). His other son, Cosmo Sheldrake is a musician, and his music has been playing on the background while this post has been written. <a href="https://open.spotify.com/artist/6hV6oxGLeLFw17DGjIPkYD?si=hYl6qCKFRSaE17nzgxJREQ">Go check him out!</a></p>
<p>I&rsquo;d like to end this post with a call to remember something that happened to you that you can&rsquo;t fully explain. Share that story what your partner or friends, what do they think? If you would be so willing my mailbox is open to any of your stories (particularly déjà vu).</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p><a href="https://www.rottentomatoes.com/tv/fringe">Fringe</a> is also a TV series I was a huge fan of. And I just should <em>definitely</em> give it another watch. I&rsquo;m sure I would be able to appreciate the theories presented in the series more now than at the I watched it.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>I should really preface this with the most prevalent theory in mainstream science&hellip; Which is not to say that it should be dismissed. The only caveat really is, that it might be too reductive, since mainstream science isn&rsquo;t open to ideas that might defy all logic. By which I don&rsquo;t mean to say that any idea is worth pursuing. I feel like I&rsquo;m talking in circles here&hellip; I guess to bottom line is, to be open to every possibility.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>The <a href="https://psychiatryonline.org/doi/full/10.1176/jnp.14.1.6">other one</a> being it&rsquo;s a misfiring of neurons or a temporary malfunction of an otherwise healthy brain&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4">
<p>Which is the title of one Rupert Sheldrake&rsquo;s <a href="https://app.thestorygraph.com/books/275c7122-a0e4-48c6-95df-7b179b83ef3a">books</a> and an <a href="https://sheldrake.org/research/sense-of-being-stared-at">active area of research</a> of him.&#160;<a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to The%20Weird">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Fancy doors</title><link>https://pensiveibex.com/blog/2024/8/fancy-doors/</link><pubDate>Wed, 14 Aug 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/8/fancy-doors/</guid><description>
<![CDATA[<p>A couple of weeks ago, my girlfriend had the idea to spruce up her doors. &ldquo;Great!&rdquo; I said, &ldquo;sounds like a fun project!&rdquo; At first it was just going to be a paint job, then it evolved into something more. The doors were going to be adorned with some frames. She googled<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> around a bit and found some sets that were pre-made on Amazon. Problem was, that not all doors had the same width, and most sets had a fixed width of 60cm<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>. The smallest door has a total width of 67cm, so that would leave just 3.5cm on both sides. Aesthetically not very pleasing.</p>
<p>So I started drawing a bit and we tested out several different possibilities and layouts. We ended up with a rectangle of 50x60cm, with a smaller 50x30cm one below it, then another 50x60cm again. For the outside doors, she wanted some colour as well. So we experimented a bit, to get the creative juices flowing. You can&rsquo;t get yourself too attached to the colours you see on a screen, when choosing paint you either have to pick whatever colours they have or have them mix a colour. Most brands do support <a href="https://en.wikipedia.org/wiki/List_of_RAL_colours">RAL colours</a> which have sRGB approximations, but it might still have some slight deviation. When we looked at it together she settled for some pastel colours, but the next when I came home from work she was ecstatic about the flashy blue, yellow and orange colours she choose. Hey, if she&rsquo;s happy, I&rsquo;m happy.</p>
<p>To make the rectangle frames for the doors, we ordered slats of 270cm online. Of course, this was a lot cheaper than if we ordered the premade kits. But this did mean I had to get my hands dirty, so to speak. Every slat had to be cut into pieces of either 30, 50 or 60cm. And they all had to have outward angles of 45 degrees. Easy enough, I have the tools to do this. Oh wait, I don&rsquo;t&hellip; They&rsquo;re still in the moving container. Luckily, my dad came to the rescue and I could borrow his saw. Some quick napkin math, We needed 2 rectangles of 50x60 and 1 rectangle of 50x30. 8 Doors needed these fancy frames, so that&rsquo;s 8*(4*(50+60)+2*(50+30))=4800cm. In total we needed 48 pieces of 50cm, 32 pieces of 60cm and 16 pieces of 30cm. In order to know how many slats we had to order, I needed to know how many pieces fit in one slat and how much waste is in one slat. I figured I would start with 2 pieces of 50, 2 pieces of 60 and 1 piece of 30cm. That leaves us with 20cm of waste. So after 16 slats I have all the pieces of 60 and 30cm done. And still need 16 pieces of 50cm, of which I could get 5 per slat. So, by that reasoning we needed 20 slats.</p>
<p>If this were a movie instead of a blog, this is where a montage would be cut of the sawing process and painting of the slats. I sawed them in angles of 45 degrees and my girlfriend painted them over the course of several days. Then came the most precise process of sticking the slats to the doors. The slats have to be equidistant to both sides of the doors. and equidistant from each other. When I first measured the distances with the slats in hand, I noticed something. The slats I carefully sawed were flawed. They weren&rsquo;t 50cm, but rather 49.5 or 49.3cm, I don´t know what I did wrong or how it happened. But there it is. Luckily, this slight difference doesn&rsquo;t really matter, as long as the slats are in the center of the door. So we paired all the slats so that we had two of the same length. Then paired them again, so we had three pairs per door.</p>
<p>This brings me to what I find most fun about DIY projects. It&rsquo;s a lot of fun to work towards a certain result, but to me it&rsquo;s also about dealing with unexpected problems. DIY is more about problem-solving than it is about doing. It&rsquo;s rolling with the punches. It&rsquo;s trying something, hoping for the best, but adapting if it doesn&rsquo;t pan out.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/8/fancy-doors/glue.png" class="lightbox">
		<img src="/blog/2024/8/fancy-doors/glue_hu_8b51e7fd34169ad8.png" class="center " loading="lazy" alt="Glue">
	</a>
	
</figure></p>
<p>I used regular montage glue and the process was fairly straightforward. It just took a longer time than I expected and more glue than I anticipated. I thought I would be done after 3-4 hours and 1 can of glue would be enough. In the end, it took about 10 hours and 4 cans of glue. One thing I&rsquo;ve learned about this project,  you can glue 12m of slats with 1 can of glue.</p>
<p>Here&rsquo;s the final result:</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/8/fancy-doors/fancy-doors-interior.png" class="lightbox">
		<img src="/blog/2024/8/fancy-doors/fancy-doors-interior_hu_417821e5d62c660d.png" class="center " loading="lazy" alt="Fancy doors interior">
	</a>
	
</figure></p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/8/fancy-doors/fancy-doors-exterior.png" class="lightbox">
		<img src="/blog/2024/8/fancy-doors/fancy-doors-exterior_hu_aebeeb8d38cdf286.png" class="center " loading="lazy" alt="Fancy doors exterior">
	</a>
	
</figure></p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Or should I be saying qwant? Qwanted? Qwunt? Is qwanting a regular or irregular verb? In case you haven&rsquo;t heard of it. <a href="https://qwant.com">You&rsquo;re welcome.</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Sorry Americans, my blog isn&rsquo;t popular enough to justify me translating metric units to imperial. Although it would seem fun to write a plugin that would translate units to the one that is most popular based on geographical location. Kind of like locale, but for units.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Fancy%20doors">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Hello from Arch Linux</title><link>https://pensiveibex.com/blog/2024/8/hello-from-arch/</link><pubDate>Sat, 10 Aug 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/8/hello-from-arch/</guid><description>
<![CDATA[<p>My <a href="https://frame.work/be/en/products/laptop16-diy-amd-7040">Framework 16</a> laptop arrived earlier this week and I finally had the time to put it together! I bought the DIY edition, and to be honest, I expected more DIY. The installation process was extremely smooth. I&rsquo;ve setup desktop towers before and installing a PC like that took me way longer than it did for this laptop. Some things do come preinstalled. For example, the motherboard and CPU are already fit snuggly in place. The graphics module was already attached to the laptop. The only thing I had to do, was lift the mid-cover, install RAM and storage, put it all back and cover the whole thing with the mouse trackpad and keyboard. Then turn it over and install the extension ports. Oh yeah, I also had to attach the bezel.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/8/hello-from-arch/framework16-expansion-ports.png" class="lightbox">
		<img src="/blog/2024/8/hello-from-arch/framework16-expansion-ports_hu_24e8bd3f2d2ea07c.png" class="center " loading="lazy" alt="Expansion ports">
	</a>
	
</figure>

<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/8/hello-from-arch/framework16-expansion-ports-zoomed.png" class="lightbox">
		<img src="/blog/2024/8/hello-from-arch/framework16-expansion-ports-zoomed_hu_8b4f9e267857fd7d.png" class="center " loading="lazy" alt="Expansion ports zoomed in">
	</a>
	
</figure></p>
<p>All of the connectors are magnetic, so it just fits in place easily, no fiddling with connectors or screws. The overall process was laughably easy. I&rsquo;m not sure why anyone would want to be the prebuilt edition. I bought my own set of storage and RAM, because I found the framework options to be too expensive. For storage you can&rsquo;t really go wrong, so I went with the tried and true <a href="https://www.tomshardware.com/reviews/wd-black-sn850x-ssd-review-back-in-black">WD Black SN850X 2TB M.2 SSD</a>. Memory is another beast, you can&rsquo;t just plug in any old memory module and expect it to work. Framework has <a href="https://knowledgebase.frame.work/en_us/what-dram-memory-is-supported-by-framework-laptop-16-ryS2Xr3ch">a list</a> with all the tested memory modules, I cross-referenced this list with user experiences on Tweakers (a Dutch techies forum) and ended up with Kingston DDR5 FURY Impact 2x16GB 5600.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/8/hello-from-arch/framework16-mousetrackpad.png" class="lightbox">
		<img src="/blog/2024/8/hello-from-arch/framework16-mousetrackpad_hu_e179399ec781cd75.png" class="center " loading="lazy" alt="Trackpad in my hands">
	</a>
	
</figure></p>
<p>After putting it all together, it booted up flawlessly first time. Excellent! Next step? Install Arch Linux. I had to borrow a USB stick from a friend, because I&rsquo;m still temporarily living in my girlfriend&rsquo;s appartment and all my stuff is stored in a big container somewhere. Luckily, he came through. I did have some issues getting to boot from the USB stick, but it turned out this didn&rsquo;t have anything to do with the stick itself, but with the Secure Boot option in the BIOS. Arch Linux did mention this on their wiki, I just glanced over it (didn&rsquo;t even know I had Secure Boot).</p>
<p>The installation process was fairly easy if you have some commandline and/or Linux experience. The last time I had a Linux boot on my personal machines was back in 2006-2009 when I had a Ubuntu dual boot. This marked the first time that I actually choose all the different components for setting up my Linux boot. I followed all the steps from the installation guide dilligently, didn&rsquo;t get any unexpected errors and was able to boot to the default bash shell of Arch Linux. When I wanted to install some more packages, I did come to the uneasy conclusion that I didn&rsquo;t install a network manager, so I couldn&rsquo;t configure an internet connection&hellip; D&rsquo;oh! Cursing to myself, I was ready to retry the whole installation from scratch. Luckily, the second thought that came to mind was booting from the live USB, mounting the Arch Linux system and installing the network manager from the live USB. It worked and I was up and running.</p>
<p>Shortly after that I downloaded <a href="https://wayland.freedesktop.org/">Wayland</a> and <a href="https://kde.org/">KDE</a>. I know my way around a terminal, but having a desktop environment is a bit more user friendly for my needs. Every free moment I have is spent browsing through settings and configuring my environment to my likings. I&rsquo;m still discovering new nooks and crannies and like it a lot. I&rsquo;m probably not all there yet, but I&rsquo;m getting there. This blog post is written from Arch Linux!</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Hello%20from%20Arch%20Linux">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>July 2024 recap</title><link>https://pensiveibex.com/blog/2024/8/july-2024-recap/</link><pubDate>Thu, 01 Aug 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/8/july-2024-recap/</guid><description>
<![CDATA[<h2 id="series">Series</h2>
<h3 id="sherlock"><a href="https://www.rottentomatoes.com/tv/sherlock">Sherlock</a></h3>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/8/july-2024-recap/sherlock.png" class="lightbox">
		<img src="/blog/2024/8/july-2024-recap/sherlock_hu_d5823002c326abba.png" class="center " loading="lazy" alt="Sherlock">
	</a>
	
</figure></p>
<p><em>FINISHED</em></p>
<p>Absolutely lovely. I love the universe, I love the characters, and Benedict Cumberbatch&rsquo;s and Martin Freeman&rsquo;s representation of those characters are phenomenal. I guess if I had to give a point of criticism, it&rsquo;s that visualization of Sherlock&rsquo;s deduction throughout the series isn&rsquo;t consistent.
It&rsquo;s a very minor gripe in an otherwise stellar series. But it did bother me.</p>
<h2 id="movies">Movies</h2>
<h3 id="dungeons--dragons-honor-among-thieves"><a href="https://www.rottentomatoes.com/m/dungeons_and_dragons_honor_among_thieves">Dungeons &amp; Dragons: Honor Among Thieves</a></h3>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/8/july-2024-recap/dungeons-and-dragons-honor-among-thieves.png" class="lightbox">
		<img src="/blog/2024/8/july-2024-recap/dungeons-and-dragons-honor-among-thieves_hu_1b7daad5cd25f68a.png" class="center " loading="lazy" alt="Dungeons &amp; Dragons: Honor Among Thieves">
	</a>
	
</figure></p>
<p>Released over a year ago and I remember not really being into the hype of wanting to see it in the cinema. I stick with that decision, it&rsquo;s a good movie, it&rsquo;s entertaining, it gave me some laughs. The plot just is okay, not surprising, not particularly gripping and somewhat predictable. To be fair, I&rsquo;m a bit done with the amiable, witty &ldquo;I don&rsquo;t really know what I&rsquo;m doing&rdquo; protagonists.</p>
<h3 id="howl"><a href="https://www.rottentomatoes.com/m/howls_moving_castle">Howl&rsquo;s Moving Castle</a></h3>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/8/july-2024-recap/howls-moving-castle.png" class="lightbox">
		<img src="/blog/2024/8/july-2024-recap/howls-moving-castle_hu_dc00f9217d6bd738.png" class="center " loading="lazy" alt="Howl&rsquo;s Moving Castle">
	</a>
	
</figure></p>
<p>The first, Studio Ghibli film I&rsquo;ve seen, shocking I know. Nearly all of them have been on my to-watch list for ages now and I&rsquo;m extremely glad I finally got round to watching this one. The ending is somewhat of a letdown, personally, but the overall story and animation quality are excellent!</p>
<h2 id="books">Books</h2>
<h3 id="last-argument-of-kings"><a href="https://app.thestorygraph.com/books/6e953625-ee91-4f6c-8d7b-4425ab33f4d4">Last Argument of Kings</a></h3>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/8/july-2024-recap/last-argument-of-kings.png" class="lightbox">
		<img src="/blog/2024/8/july-2024-recap/last-argument-of-kings_hu_b2037a4c5986206c.png" class="center " loading="lazy" alt="Last Argument of Kings">
	</a>
	
</figure></p>
<p><em>READING</em></p>
<p>Reserved as my book-before-bed. About halfway through, but since I only read it just before bed, and I&rsquo;ve been exhausted for the most part of the month, I haven&rsquo;t made a lot of progress yet.</p>
<h3 id="waarom-niemand-kwantum-begrijpt"><a href="https://app.thestorygraph.com/books/bceb1031-61d4-4de3-80b9-fb72b5d1c0cb">Waarom niemand kwantum begrijpt</a></h3>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/8/july-2024-recap/waarom-niemand-kwantum-begrijpt.png" class="lightbox">
		<img src="/blog/2024/8/july-2024-recap/waarom-niemand-kwantum-begrijpt_hu_a391bb8e431658cf.png" class="center " loading="lazy" alt="Waarom niemand kwantum begrijpt">
	</a>
	
</figure></p>
<p><em>FINISHED</em></p>
<p>Started reading last month and finished it this month. I&rsquo;m fascinated by science and really like it when things are explained well. This book takes you through the history of quantum physics from its conception to the current state of affairs where we&rsquo;re trying to figure out quantum computing on a usable scale. Would recommend to any science nerds (only available in Dutch, sorry)</p>
<h3 id="from-hell"><a href="https://app.thestorygraph.com/books/d7ccd765-59e1-4b64-84e6-c1c4ddf67f56">From Hell</a></h3>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/8/july-2024-recap/from-hell.png" class="lightbox">
		<img src="/blog/2024/8/july-2024-recap/from-hell_hu_580821d1dd0d08c.png" class="center " loading="lazy" alt="From Hell">
	</a>
	
</figure></p>
<p><em>READING</em></p>
<p>Alan Moore&rsquo;s tale of Jack the Ripper has been on my list for a while. And I&rsquo;m extremely glad I picked it up. Whenever I have some free time, I like to read a chapter, and just love admiring the artwork. The drawings are made up of harsh lines, which add to the eerie picture more is painting of Jack&rsquo;s story. I&rsquo;m excited to read where the story will be taking me.</p>
<h3 id="project-hail-mary"><a href="https://app.thestorygraph.com/books/ac3ea915-993d-4f30-8632-0f91e4ad0704">Project Hail Mary</a></h3>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/8/july-2024-recap/project-hail-mary.png" class="lightbox">
		<img src="/blog/2024/8/july-2024-recap/project-hail-mary_hu_2fb64ae826861ebd.png" class="center " loading="lazy" alt="Project Hail Mary">
	</a>
	
</figure></p>
<p><em>LISTENING</em></p>
<p>I picked this up as an audiobook. I&rsquo;ve heard great things about it, and found myself with ample time to listen to things but no time to read things. So I decided to get an audiobook and get some more books read/listened that have been on my to-read shelf for a while now. So far, it&rsquo;s a great listen. Hard science-fiction, I like it.</p>
<h2 id="games">Games</h2>
<h3 id="neofeud"><a href="https://www.metacritic.com/game/neofeud/">Neofeud</a></h3>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/8/july-2024-recap/neofeud.png" class="lightbox">
		<img src="/blog/2024/8/july-2024-recap/neofeud_hu_b5b1f2830abb8a3a.png" class="center " loading="lazy" alt="Neofeud">
	</a>
	
</figure></p>
<p><em>FINISHED</em></p>
<p>The game of the month of July of the <a href="https://dosgame.club/@adventure/112663249491056004">Adventure Gaming Club</a>. A lot to unpack here. I kind of liked it? The premise of the story is good, great in fact. There&rsquo;s a narrative, a well thought out narrative and I liked the ideas that were put forward. But it was all just a stream of consciousness from a single guy in his bedroom, so to speak.</p>
<p>The voice acting was&hellip; bad. I&rsquo;m sorry, there&rsquo;s no other word for it. I would have much preferred if this game didn&rsquo;t have any narration. I listened to every dialogue for a third of the game, and just started reading and skipping voice after that. Dialogue sequences can sometimes last 5-10 minutes easily if you leave the characters talking and don&rsquo;t skip the voice acting. Which I would be okay with, if it weren&rsquo;t that bad.</p>
<p>Puzzles, not many and not that hard. The game clearly indicates what you have to do and how you have to achieve it. Multiple times it won&rsquo;t even let you leave an area, until you do the thing you&rsquo;re supposed to do. Which is a good thing for what the game wants to be, in my opinion at least.</p>
<h3 id="the-room"><a href="https://www.metacritic.com/game/the-room/">The Room</a></h3>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/8/july-2024-recap/the-room.png" class="lightbox">
		<img src="/blog/2024/8/july-2024-recap/the-room_hu_4ef5675bfa9291d6.png" class="center " loading="lazy" alt="The Room">
	</a>
	
</figure></p>
<p><em>FINISHED</em></p>
<p>Wanted to play some more games that didn&rsquo;t take up a lot of time, that I could pick up and set down again. The Room neatly fell into that category. I&rsquo;m sure I&rsquo;ve played the original on Android where it first released. But didn&rsquo;t play any of the others. Great concept, great execution. I guess the only slightly frustrating thing is that it&rsquo;s not always obvious which hidden switch needs to be found in order to progress the puzzle. Didn&rsquo;t have any issues with that in the first game, but definitely got stumped in the second one.</p>
<h3 id="the-room-two"><a href="https://www.metacritic.com/game/the-room-two/">The Room Two</a></h3>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/8/july-2024-recap/the-room-two.png" class="lightbox">
		<img src="/blog/2024/8/july-2024-recap/the-room-two_hu_698f3f8b9c8c1b03.png" class="center " loading="lazy" alt="The Room Two">
	</a>
	
</figure></p>
<p><em>FINISHED</em></p>
<p>See above.</p>
<h3 id="the-room-three"><a href="https://www.metacritic.com/game/the-room-three/">The Room Three</a></h3>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/8/july-2024-recap/the-room-three.png" class="lightbox">
		<img src="/blog/2024/8/july-2024-recap/the-room-three_hu_8f8406138b343cd7.png" class="center " loading="lazy" alt="The Room Three">
	</a>
	
</figure></p>
<p><em>PLAYING</em></p>
<p>Not gotten very far yet. But enjoying my time with it.</p>
<h2 id="interesting-links">Interesting links</h2>
<h3 id="text-to-color"><a href="https://text2color.com/">Text to color</a></h3>
<p>provide it with a description of the colour you want, and voilà, there&rsquo;s your hex code!</p>
<h3 id="old-maps-online"><a href="https://www.oldmapsonline.org/">Old Maps Online</a></h3>
<p>I have literally lost hours browsing through this site. It just gets better the deeper you go! At first you&rsquo;re just amazed at the borders shifting from one place to the next. Both in Europe and other continents, the sources for this site are very exhaustive. But then! Oh then you find out you can switch between regions, rulers, people and battles on the map. I&rsquo;ve learned so much about historical figures that are local to my area, such an amazing resource to have in your back pocket!</p>
<h2 id="podcasts">Podcasts</h2>
<h3 id="red-valley"><a href="https://podcastindex.org/podcast/116614">Red Valley</a></h3>
<p>Popping my cherry for fictional podcasts. The added sound effects really make these stand in their own right as a media format. I always wondered why these were a thing and how to differ from audiobooks. Now I know. The story is well thought out and I would definitely recommend it to anyone. The only thing with this one, is the amount of trailers played before and after an episode sometimes taking up to 2-3 minutes.</p>
<h3 id="sherlock--co"><a href="https://podcastindex.org/podcast/6637069">Sherlock &amp; Co</a></h3>
<p>More Sherlock, yay! Can&rsquo;t recommend this one enough. It&rsquo;s a play on the original Arthur Conan Doyle stories, but retold in a modern setting. Not only does it feature John Watson as a podcaster, it really nails the personalities and brings a more modern Mrs. Hudson. John&rsquo;s humour and ranting and fumbling through his intro&rsquo;s are especially hilarious.</p>
<h3 id="programming-throwdown"><a href="https://podcastindex.org/podcast/771847">Programming Throwdown</a></h3>
<p>This podcast got recommended to me by a good friend of mine. Each episode has a central topic, but the hosts only talk about it halfway through the episode. Before the actual episode, the hosts first talk about some random happenings they find mention-worthy. After that they have 2 fixed sections: Book of the show and Tool of the show. The book of the show isn&rsquo;t necessarily anything programming related, but might just be a (graphic) novel one of them is reading. The tool of the show (for the few episodes I&rsquo;ve listened to) has been always been a game. One that stood out to me, and hadn&rsquo;t heard of before is <a href="https://store.steampowered.com/app/1444480/Turing_Complete/">Turing Complete</a>.</p>
<h3 id="transmission-season-2"><a href="https://podcastindex.org/podcast/6625786">Transmission Season 2</a></h3>
<p>A podcast by the Tropical Institution of Tropical Diseases, based in Antwerp. This season talks about the supply chain that is necessary for a well-functioning health care system. One topic that is somewhat a central point throughout the season, is the death of mothers during childbirth. It&rsquo;s an especially interesting listen to get a better insight into the necessary infrastructure.</p>
<h2 id="private-life">Private life</h2>
<p>I got the keys to my new house, so I could start working on painting the rooms. Of course, first they drywalls needed to be sanded. I was lucky enough to loan a professional sanding machine with vacuum cleaner. This really helped to not make a mess of it and go through it more quickly than doing it by hand (which I really had no interest in doing).</p>
<p>Hence why I&rsquo;ve had more time to listen to content, than time for reading or gaming. Next steps is some more plastering to cover up some dents in the drywalls, lightly sanding those touch-ups. Afterwards I can get everything sealed off for actually painting the rooms. Hopefully I&rsquo;ll be able to get this all done in August and move my stuff in the new house.</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to July%202024%20recap">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Discovery Tests</title><link>https://pensiveibex.com/blog/2024/7/discovery-tests/</link><pubDate>Sun, 28 Jul 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/7/discovery-tests/</guid><description>
<![CDATA[<p>I recently started a new job and found myself in the Go ecosystem. To be honest, it has been a bit of a shock. I&rsquo;ve written .NET code for the past 15 years and know its ins and outs pretty well. As a language, I don&rsquo;t mind writing Go code. About the only thing that still bothers me is the <code>if err != nil { return err }</code> boilerplate code ad nauseam. But that&rsquo;s a topic for a whole different blog post (maybe in the future if I find the time?).</p>
<p>What I wanted to discuss is Go&rsquo;s ecosystem. The libraries that are (being) built for it, and their uses. The Go ecosystem is moving fast, with <a href="https://github.com/avelino/awesome-go?tab=readme-ov-file">many available libraries</a>. Some are actively maintained, some run behind the current Go version but are still in use in various projects. This might not be a problem at the time, but dependencies might break. Implementations may change over time.</p>
<p>Let&rsquo;s go back a few years. In a previous project we used <a href="https://github.com/nhibernate/nhibernate-core">NHibernate</a> as our ORM of choice. But instead of just using NHibernate, previous engineers made subtle changes to the source code of NHibernate in order to &ldquo;better support&rdquo; the underlying legacy database schema. This wouldn&rsquo;t have been much of a problem if the changes were documented. However&hellip; Those same engineers copied the source code <strong>with their changes</strong> over to a local git repo, and in the process removing all historic information about which changes were made and why they were made.</p>
<p>At some point during my time at the company, we identified NHibernate as a point of frustration for developers, since the version we were using (v3.x if I remember correctly) was missing a lot of new features that would make are future lives easier. Obviously we didn&rsquo;t want to make the same mistakes of the past and did our best to <em>fork</em> the existing NHibernate Github repo and only make changes to the source code if no other option was available.</p>
<p>The result was an effort of three to four months, of painstakingly identifying bugs and going through the source code, comparing it with the undocumented fork we had in our repo and making adjustments and tweaks along the way, until we had an implementation that had feature parity with the previous version.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup></p>
<p>Along the way, for every bug I discovered I wrote a <strong>discovery test</strong> in the source code of our application.<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> The purpose for this was mainly to make further upgrades easier. Pull the main branch of the official Github repo into our fork, pull that into the existing application, run the tests and if everything remains green you&rsquo;re good to go.</p>
<p>These discovery tests serve many needs:</p>
<ul>
<li>Document the <strong>expected behaviour</strong> of the external library for your application</li>
<li>Learning the possibilities of the external library in a sandboxed environment</li>
<li>Sharing your knowledge with other developers in the team</li>
</ul>
<p>This takes me back to the Go ecosystem and my current project. Incidentally, the library we wrote discovery tests for is also an ORM, namely <a href="https://github.com/go-gorm/gorm">GORM</a>. We were struggling with saving our associations. Let&rsquo;s say you have a Person, who speaks several Languages. And you have a PUT API call that wants to <em>delete</em> the existing languages and instead <em>insert</em> the new languages. Pretty straightforward right?</p>
<p>Well&hellip; By default GORM will only <em>add</em> associations in the database. Take the following code for example</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#a6e22e">person</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">Person</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">Name</span>: <span style="color:#e6db74">&#34;Spock&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">Languages</span> <span style="color:#f92672">:=</span> []<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">Language</span>{
</span></span><span style="display:flex;"><span>        {<span style="color:#a6e22e">Name</span>: <span style="color:#e6db74">&#34;Vulcan&#34;</span>},
</span></span><span style="display:flex;"><span>        {<span style="color:#a6e22e">Name</span>: <span style="color:#e6db74">&#34;English&#34;</span>},
</span></span><span style="display:flex;"><span>    },
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Save</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">person</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Result: 1 person Spock, with 2 spoken languages (Vulcan and English) in the database</span></span></span></code></pre></div><p>If we were to make a change to Spock and wanted to add Klingon as a language, we could do something like this</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#a6e22e">languages</span> <span style="color:#f92672">:=</span> []<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">Language</span>{
</span></span><span style="display:flex;"><span>        {<span style="color:#a6e22e">Name</span>: <span style="color:#e6db74">&#34;Vulcan&#34;</span>},
</span></span><span style="display:flex;"><span>        {<span style="color:#a6e22e">Name</span>: <span style="color:#e6db74">&#34;English&#34;</span>},
</span></span><span style="display:flex;"><span>        {<span style="color:#a6e22e">Name</span>: <span style="color:#e6db74">&#34;Klingon&#34;</span>},
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">person</span> <span style="color:#a6e22e">Person</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Where</span>(<span style="color:#e6db74">&#34;name = ?&#34;</span>, <span style="color:#e6db74">&#34;Spock&#34;</span>).<span style="color:#a6e22e">First</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">person</span>)
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">person</span>.<span style="color:#a6e22e">Languages</span> = <span style="color:#a6e22e">languages</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Save</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">person</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Result: 1 person Spock, with 5 spoken languages (2x Vulcan, 2x English and Klingon) in the database</span></span></span></code></pre></div><p>Not exactly what we wanted right?</p>
<p>Luckily, GORM does provide an API for replacing Associations, aptly called <code>.Replace()</code>. So we changed our code to use that</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Model</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">person</span>).<span style="color:#a6e22e">Association</span>(<span style="color:#e6db74">&#34;Languages&#34;</span>).<span style="color:#a6e22e">Replace</span>(<span style="color:#a6e22e">languages</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Result: 1 person Spock, with 3 spoken Languages (Vulcan, English and Klingon) in the database</span></span></span></code></pre></div><p>Awesome! That&rsquo;s what we wanted. Except&hellip; There are still two floating Language records in the database. Their link with the Person Spock (through a PersonID column) has just been emptied. Not exactly what we wanted to achieve in our case. Okay, so then, what&rsquo;s next? GORM supports deletes through the use of the <code>.Unscoped()</code> method. Not exactly a meaningful name, but hey we&rsquo;ll settle with what we have.</p>
<p>This Unscoped method can be called on the <code>db</code> instance as well as the <code>Assocations</code> instance. So we have four different variations of use and dependning on what we want with our application code, one of these might be the implementation we&rsquo;re looking for.</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-go" data-lang="go"><span style="display:flex;"><span><span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Model</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">person</span>).<span style="color:#a6e22e">Association</span>(<span style="color:#e6db74">&#34;Languages&#34;</span>).<span style="color:#a6e22e">Replace</span>(<span style="color:#a6e22e">languages</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// No deletes of languages, just remove the link between the language and the person</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Unscoped</span>().<span style="color:#a6e22e">Model</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">person</span>).<span style="color:#a6e22e">Association</span>(<span style="color:#e6db74">&#34;Languages&#34;</span>).<span style="color:#a6e22e">Replace</span>(<span style="color:#a6e22e">languages</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// No deletes of languages, just remove the link between the language and the person</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Model</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">person</span>).<span style="color:#a6e22e">Association</span>(<span style="color:#e6db74">&#34;Languages&#34;</span>).<span style="color:#a6e22e">Unscoped</span>().<span style="color:#a6e22e">Replace</span>(<span style="color:#a6e22e">languages</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Does not remove the link between language and person, but performs soft delete</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">db</span>.<span style="color:#a6e22e">Unscoped</span>().<span style="color:#a6e22e">Model</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">person</span>).<span style="color:#a6e22e">Association</span>(<span style="color:#e6db74">&#34;Languages&#34;</span>).<span style="color:#a6e22e">Unscoped</span>().<span style="color:#a6e22e">Replace</span>(<span style="color:#a6e22e">languages</span>)
</span></span><span style="display:flex;"><span><span style="color:#75715e">// Performs hard delete of the languages</span></span></span></code></pre></div><p>We documented these cases in our code as <strong>discovery tests</strong>, because their usage is so obscure and because we depend on an expected behaviour of one of these implementations. Should the maintainers behind GORM ever want to change the implementation or behaviour behind one of these calls, we have a simple unit test that will immediately pinpoint the issue after an upgrade. Which might save valuable debugging time in the future.</p>
<p>And any other developer in the team can check these examples and know exactly what the end result of the call will be.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>You can still find my changes <a href="https://github.com/pratoservices/nhibernate-core">here</a>, although I don&rsquo;t encourage making the same changes. It was a necessary evil that couldn&rsquo;t be avoided.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Unfortunately I can&rsquo;t link to these, as said application is closed source.&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Discovery%20Tests">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Edutainment games of my childhood</title><link>https://pensiveibex.com/blog/2024/7/edutainment-games/</link><pubDate>Sat, 06 Jul 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/7/edutainment-games/</guid><description>
<![CDATA[<p>I grew up surrounded by computers. My father is an unbelievable Amiga fanboy. We must have owned over 5 or 6 Amiga&rsquo;s, The Amiga 1200 being my very own home computer and my beast of choice when it came to gaming at a young age. Everyone talks about DOS gaming in their childhood. I had this gem whenever I booted my machine, with its accompaning clicking sounds.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/7/edutainment-games/kickstart.png" class="lightbox">
		<img src="/blog/2024/7/edutainment-games/kickstart_hu_7b318cb56dab6711.png" class="center " loading="lazy" alt="Kickstart">
	</a>
	
</figure></p>
<p>I had cases full of floppy disks that my dad bought me off eBay, full of games released for the Amiga. As a kid, I had a plethora of games to choose from and just picked whatever had my fancy. Many of the games I played were not per se designed for kids, especially non native English speaking kids. I remember fumbling through games like Monkey Island 1 &amp; 2 and Hook, without fully understanding the intricacies of the language. The insult swordfighting for example, was just a prompt/reply matching algorithm I noted down in order to quickly get past the bits I didn&rsquo;t actually understand.</p>
<p>However, that&rsquo;s not what I wanted to touch upon. I wanted to take the time going through the games of my childhood that were actually targetted at children and educational. This was very slim pickings indeed. You had some bare bones DOS games back in primary school, like hangman and other classics that were just <em>meh</em>. But I do still have some very fond memories of certain games.</p>
<h2 id="where-in-the-world-is-carmen-sandiego">Where in the World is Carmen Sandiego?</h2>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/7/edutainment-games/where-in-the-world-is-carmen-sandiego.png" class="lightbox">
		<img src="/blog/2024/7/edutainment-games/where-in-the-world-is-carmen-sandiego_hu_aef3f691db137d49.png" class="center " loading="lazy" alt="Where in the world is Carmen Sandiego">
	</a>
	
</figure></p>
<p><a href="https://www.mobygames.com/game/4848/where-in-the-world-is-carmen-sandiego-enhanced/">Moby games</a></p>
<p>Upon researching this, I didn&rsquo;t even realize the franchise had <em>so many</em> games in its repertoire, let alone that it was still going! I&rsquo;ll have to do some more digging and see if there are any noteworthy entries that are worth playing which I&rsquo;ve missed.</p>
<p>In any case, Carmen Sandiego is a criminal mastermind and has a small army of henchmen that travel around the world, steal an item and it&rsquo;s your job as an Interpol agent to track the culprit down and apprehend them. The gameplay is fairly easy, you have 3 locations to visit per city, you get clues about the culprit and clues about their destination.</p>
<p>Some of these clues might be the colors of the flag, the currency of the country or something about its history. As a kid, in the nineties, internet wasn&rsquo;t a thing yet. So I played this game next to the large encyclopedias my dad owned. Every single city has 3-4 linking connections to choose from. The world map doesn&rsquo;t show countries to visit, oh no, just cities. I must&rsquo;ve been 8 or 10 years old and knowing Montreal is a city in Canada or that Port Moresby lies in Papua New Guinea isn&rsquo;t common knowledge. So every little bit of info I got from the game, I had to look up in actual paper encyclopedia. They were usually divided in several books, some editions (including the one we owned) had over 20 volumes. So whenever I set out to play this game, I was surrounded by several books flipped open on different pages with the necessary info in order to solve the clues the game gave.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/7/edutainment-games/carmen-sandiego-interrogating-witnesses.png" class="lightbox">
		<img src="/blog/2024/7/edutainment-games/carmen-sandiego-interrogating-witnesses_hu_62bf43e1bf0feb9e.png" class="center " loading="lazy" alt="Interrogating witnesses in Carmen Sandiego" title="The gulf of what now?">
	</a>
	
		<figcaption>The gulf of what now?</figcaption>
	
</figure></p>
<p>The game is now marked as abandonware and can be <a href="https://www.myabandonware.com/game/where-in-the-world-is-carmen-sandiego-enhanced-1ax">freely played online</a>.</p>
<h2 id="rayman-junior">Rayman Junior</h2>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/7/edutainment-games/rayman-junior.png" class="lightbox">
		<img src="/blog/2024/7/edutainment-games/rayman-junior_hu_12223992655ba4c0.png" class="center " loading="lazy" alt="Rayman Junior">
	</a>
	
</figure></p>
<p><a href="https://www.mobygames.com/game/56490/amazing-learning-games-with-rayman/">Moby games</a></p>
<p>I didn&rsquo;t own this game. I know it by the title Rayman Junior, but the most common release title seems to be <strong>Amazing learning games with Rayman</strong>. A friend of mine owned this, when he booted the game up, I was immediately enthralled by it. It had platforming, one of my favourite genres as a child, and maths?</p>
<p>This was such a blast to play, levels were themed to a certain topic, some would be vocabulary or grammar-based, others might include mathematical equations. Whatever it was, I was just the right age for it to be somewhat challenging but not too hard or too easy to breeze through.</p>
<p>Not only that, but the platforming in the game wasn&rsquo;t that easy either, as I recall. There were parts where you would sit on a sliding platform, and as the platforming kept moving in the same direction, you were forced to pick the correct branching path based on the correct spelling of a spoken word.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/7/edutainment-games/rayman-junior-maths.png" class="lightbox">
		<img src="/blog/2024/7/edutainment-games/rayman-junior-maths_hu_c52a9fced3551854.png" class="center " loading="lazy" alt="Rayman Junior maths">
	</a>
	
</figure></p>
<p>My sister owns a medium-sized retro collection of games of the Playstation era, and I&rsquo;m interested in finding out if this game is one of them. Replaying it and finding out if I ever made it to the end, would be fun!</p>
<h2 id="spy-fox-in-dry-cereal">Spy Fox in &ldquo;Dry Cereal&rdquo;</h2>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/7/edutainment-games/spy-fox-in-dry-cereal.png" class="lightbox">
		<img src="/blog/2024/7/edutainment-games/spy-fox-in-dry-cereal_hu_d895e6bca04c7977.png" class="center " loading="lazy" alt="Spy Fox in &ldquo;Dry Cereal&rdquo;">
	</a>
	
</figure></p>
<p><a href="https://www.mobygames.com/game/21014/spy-fox-in-dry-cereal/">Moby games</a></p>
<p>By this time, we owned a <strong>Personal Computer</strong> with one of the most atrocious OS releases Microsoft ever cooked up, Windows Me. This was the only computer that was hooked up to the internet at the time. So it was a shared computer for the whole family. My sister and I would regularly get into scrapes about who had access to the computer.</p>
<p>If I remeber correctly we got this game on a CD as a free giveaway. I can&rsquo;t recall the specifics very clearly, but I&rsquo;m sure it doesn&rsquo;t really matter. I think it was the first time I was exposed to a point-and-click adventure game that was actually meant for children, instead of adults or young-adults. Before, I just played LucasArts point-and-click games and later moved on to Myst, Riven, and Zork in play sessions with my dad.</p>
<p>The game is set in a world where no humans exist and is populated by sentient, talking animals. You&rsquo;re a fox and a spy, you are helped by Mon<em>k</em>eypenny and professor <em>Q</em>uack, clever James Bond references that as a kid went over my head, but as an adult had me chuckling. And I guess, it&rsquo;s that kind of vision Ron Gilbert put into his line of games that were meant for kids. He realized the games would be played be children mainly, but their parents would be there along side them. Putting in the work to add in these kinds of puns (in naming as well as in-game jokes) means adults would be having a good time as well!</p>
<p>I have only played the first game as a child, and am interested in revisting this and giving the other 2 games a try as well. Filling up my backlog of games even more. Once I&rsquo;m retired in some thirty odd years, I&rsquo;ll finally have the time to complete all of those games.</p>
<h2 id="the-incredible-machine-2">The Incredible Machine 2</h2>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/7/edutainment-games/the-incredible-machine-2.png" class="lightbox">
		<img src="/blog/2024/7/edutainment-games/the-incredible-machine-2_hu_508bdb2c492bcc9b.png" class="center " loading="lazy" alt="The Incredible Machine 2">
	</a>
	
</figure></p>
<p><a href="https://www.mobygames.com/game/1605/the-incredible-machine-2/">Moby games</a></p>
<p>Once again a game I didn&rsquo;t own and knew under a different title. Every sunday I would stay over at friends of my dad as they went out to play tennis. They had two children as well about my age and were a French-speaking family. So naturally, the game was also in French, titled <strong>Les Incroyables Machines du Professeur Tim</strong>. My French was okay at the time, I knew enough to communicate on a basic level, understand the prompts of the game and solve the puzzles.</p>
<p>The premise is seemingly simple, you get a level setup with different immovable objects, a goal and a toolbox with moveable parts. This can be anything from scissors, to lasers and anything in between. It&rsquo;s your task to achieve that goal, with some or all of the parts provided.</p>
<p>Every time I solved a level, I felt like a genius, finding the right solution with all of the chaos going on. At times you get the solution by accident, or when handling basketballs, you get a lucky bounce because of the placement of a certain part and end up solving a level without actually planning for it. Those moments are what I remember most fondly about this game.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/7/edutainment-games/the-incredible-machine-2-hard-puzzle.png" class="lightbox">
		<img src="/blog/2024/7/edutainment-games/the-incredible-machine-2-hard-puzzle_hu_bb0080f652c87c4e.png" class="center " loading="lazy" alt="A slightly harder puzzle">
	</a>
	
</figure></p>
<p>As a child, building Rube Goldberg machines are a hard thing to do, you&rsquo;re usually limited to certain objects you&rsquo;re &ldquo;allowed&rdquo; to use (I know what I&rsquo;m doing, mom!) and playing this really scratched that itch. Complex mechanics working together to achieve a desired result. I&rsquo;m interested if there are any modern games with the same feel as this that are worth trying&hellip;</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Edutainment%20games%20of%20my%20childhood">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>June 2024 recap</title><link>https://pensiveibex.com/blog/2024/7/june-2024-recap/</link><pubDate>Mon, 01 Jul 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/7/june-2024-recap/</guid><description>
<![CDATA[<h2 id="series">Series</h2>
<ul>
<li><a href="https://www.rottentomatoes.com/tv/the_gentlemen">The Gentlemen</a> - <em>FINISHED</em> - My girlfriend recommended this to me. When I saw it was directed by Guy Ritchie I knew I was on board.  It&rsquo;s an entertaining show with a good premise.</li>
<li><a href="https://www.rottentomatoes.com/tv/eric/s01">Eric</a> - <em>FINISHED</em> - About a couple that loses their child. The main focus is on the father (played by Benedict Cumberbatch) who has some mental health issues. It&rsquo;s a mini-series and very well put together.</li>
<li><a href="https://www.rottentomatoes.com/tv/sherlock">Sherlock</a> - <em>ONGOING</em> - This is a rewatch for me. After watching Eric, we got talking about Benedict Cumberbatch and I was utterly amazed she hadn&rsquo;t seen Sherlock yet. So, that had to happen.</li>
</ul>
<h2 id="movies">Movies</h2>
<ul>
<li><a href="https://www.rottentomatoes.com/m/sheryl">Sheryl</a> - A documentary about Sheryl Crow. I was looking for something to watch, and this was recommended through a podcast I listen to. It sheds some light on the history of Sheryl and why she became an icon for so many people.</li>
</ul>
<h2 id="youtube">Youtube</h2>
<ul>
<li><a href="https://www.youtube.com/watch?v=fmaP8R0D9sQ">Speedrunning in Conquest of the Longbow</a> - I never heard of speedrunning in Adventure Games before watching this video. It&rsquo;s amazing, the lengths people go through to achieve these times and the amount of work and effort they put into it. It&rsquo;s fascinating. Not my cup of tea, mind; but I&rsquo;m honestly impressed by anyone who puts great effort into anything.</li>
</ul>
<h2 id="books">Books</h2>
<ul>
<li><a href="https://app.thestorygraph.com/books/3f7639dc-f2ca-437d-b4e8-071d66a77a7b">The Go Programming Language</a> - <em>FINISHED</em> - A book on loan by a friend. I&rsquo;m starting a new job soon and Go is the programming language of choice, so any leg up I can get before starting is nice.</li>
<li><a href="https://app.thestorygraph.com/books/88cb2a50-335b-466c-80ee-a9f2c7f44c15">Before They Are Hanged</a> - <em>FINISHED</em> - The second book in Joe Abercrombie&rsquo;s The First Law trilogy. I greatly enjoyed the first book and really like this one as well. Looking forward to where the series is going to go!</li>
<li>Code Rood - <em>FINISHED</em> - The title translates to Code Red. It&rsquo;s a non-fiction book in Dutch that goes through some recurring world-changing events, such as solar storms, volcanic eruptions, pandemics and  meteorite impacts. Especially solar storms is a personal worry of mine&hellip;</li>
<li><a href="https://app.thestorygraph.com/books/6e953625-ee91-4f6c-8d7b-4425ab33f4d4">Last Argument of Kings</a> - <em>READING</em> - The third book in the above-mentioned trilogy. I read quite a bit in the early hours at GMM (A Belgian Metal music festival).</li>
<li><a href="https://app.thestorygraph.com/books/bceb1031-61d4-4de3-80b9-fb72b5d1c0cb">Waarom niemand kwantum begrijpt</a> - <em>READING</em> - Another Dutch book I picked up at (like Code Rood) at the Nerdland festival. This one explains the history of quantum physics, starting from the 17th century and working its way up to the current theories. For the very first time, I believe I have somewhat of a basic graps on quantum mechanics. Very interested in finishing this one shortly!</li>
</ul>
<h2 id="games">Games</h2>
<ul>
<li><a href="https://www.metacritic.com/game/dave-the-diver/">Dave the Diver</a> - <em>FINISHED</em> - A game that should be a chill pick up and play game. For some reason I couldn&rsquo;t get myself to do any other real life tasks before finishing the whole thing. It&rsquo;s not a high-flying narrative game, but the gameplay is fenomenal. Every day you set out to catch fish, to then sell in your restaurant. And the game just absolutely delivers by blending several different genres. Every other day some sort of event happens and everytime a new polished minigame appears that usually feels easy enough but still okay to get a dopamine fix and play on.</li>
<li><a href="https://www.metacritic.com/game/dexter-stardust-adventures-in-outer-space/">Dexter Stardust</a> - <em>FINISHED</em> - This got recommended to me by a friend of mine. The puzzles weren&rsquo;t that hard and the gameplay was a bit too tongue-in-cheek at times for me (the references to Monkey Island were many). I liked it and finished it, and clearly a lot of love was put into the game. But in the end, I think I&rsquo;d pass for a possible sequel.</li>
</ul>
<h2 id="music">Music</h2>
<ul>
<li><a href="https://www.graspop.be/nl/">GMM</a> - Four days of Metal music, hell yeah! Personal favourites of mine included <a href="https://open.spotify.com/artist/7m63GptZSke3jGqCxR4rom?si=Hi2rVks2RxGCe73UMfLH1">Brutus</a>, <a href="https://open.spotify.com/artist/2yEwvVSSSUkcLeSTNyHKh8?si=5c6f3bfabc0e49ca">TOOL</a> and <a href="https://open.spotify.com/artist/3LkSiHbjqOHCKCqBfEZOTv?si=d742bfef4b5545f0">Atreyu</a>. <a href="https://open.spotify.com/artist/165ZgPlLkK7bf5bDoFc6Sb?si=2bfb95a7bd07415c">Limp Bizkit</a> was okay, but they just surfed on that nostalgia wave and stretched out 5 songs to last an hour. Not saying it wasn&rsquo;t good, it just wasn&rsquo;t special.</li>
<li><a href="https://open.spotify.com/album/4L5X7BuHWnNBMNG51aJe3P?si=fZHfts8CQna4rAyGRraNlw">Nell&rsquo; ora blu</a> by Uncle Acid and the Deadbeats has been playing in the background for most of my reading sessions. Really enjoyable album and excited to see them live!</li>
</ul>
<h2 id="private-life">Private life</h2>
<p>I moved out of my house. New house isn&rsquo;t ready yet, so I&rsquo;m currently in-between houses. I&rsquo;m hoping the new house will be done by August, so I can do a proper move-in before leaving on holiday for Canada in September.
My sports habits have taken a bit of a tumble during this period. I&rsquo;m hoping to start things back up in the coming weeks. I&rsquo;ve been going 1-2 times a week for the past month, hoping to ramp this back up to 4-5 times during the coming weeks.
I also started my career as a freelance developer. I am the proud owner and single employee of Pensive Ibex. It&rsquo;s been hectic the past month, but I hope things will settle down somewhat in the coming weeks. Though, I still have to paint the new house before moving in. So that will take some doing as well.</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to June%202024%20recap">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>On finishing Monkey Island</title><link>https://pensiveibex.com/blog/2024/6/on-finishing-monkey-island/</link><pubDate>Fri, 21 Jun 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/6/on-finishing-monkey-island/</guid><description>
<![CDATA[<p>I told myself I wanted to replay the Monkey Island games, so that I could then finish Return to Monkey Island, the 6th instalment in the series. Written by the original creator Ron Gilbert.</p>
<p>I have played the first two games multiple times and know them by heart. All the others I have only played once.</p>
<p>Curse of Monkey Island, the third game in the series. was actually better than I remembered. The cartoony art style gave it that timeless look that is still enjoyable today. I still remembered how to solve most of the puzzles and didn&rsquo;t really get stuck that often.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/6/on-finishing-monkey-island/curse-of-monkey-island.png" class="lightbox">
		<img src="/blog/2024/6/on-finishing-monkey-island/curse-of-monkey-island_hu_ce806618e6b899e4.png" class="center " loading="lazy" alt="Curse of Monkey Island" title="The introduction of Murray the demonic skull!">
	</a>
	
		<figcaption>The introduction of Murray the demonic skull!</figcaption>
	
</figure></p>
<p>I think the only issue I&rsquo;ve had with Curse is that it tried to follow in its predecessors shoes a little too much. The whole get ship, get crew thing is a returning trope in the series. It makes for a great setup for puzzles and narrative elements, but it still is just the same old concept rehashed.</p>
<p>Escape from Monkey Island is a whole different beast, though. I&rsquo;m glad I played it on the Steam Deck, even if the controls were frustrating, at least I could rebind some of them to make sense for me. Moving around is a hassle. Left and right makes you turn around in circles, instead of going left or right. And up and down are just for going forwards or backwards. Basically, tank controls.</p>
<p>Fixed camera angles and tank controls in a 3D game do not mix well. I found myself going back and forth through different screens because of sudden camera changes. I had trouble crossing certain places with limited space, like the bridge in the sushi restaurant. Which is doubly frustrating as this is a timed event, you have to cross the bridge and get in the kitchen before the chef does.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/6/on-finishing-monkey-island/escape-from-monkey-island.png" class="lightbox">
		<img src="/blog/2024/6/on-finishing-monkey-island/escape-from-monkey-island_hu_a0b6630bc42ff8e5.png" class="center " loading="lazy" alt="Escape from Monkey Island" title="The bridge of ill timings">
	</a>
	
		<figcaption>The bridge of ill timings</figcaption>
	
</figure></p>
<p>And the story&hellip; Well&hellip; It never made any sense to me. The introduction of an Australian land developer, seeing LeChuck in the role of a lackey to Ozzie Mandrill (said Australian land developer), and just the overall silliness of the story that just goes from one direction to another. At the end <span class="inline-spoiler">the giant monkey combat might have been topical at the time,</span> but now it&rsquo;s just silly.</p>
<p>Tales of Monkey Island is a nice palette cleanser after Escape. It follows the classic Telltale formula of an episodic adventure that has a bigger focus on narrative elements than gameplay or puzzle elements. The game features puzzles, but it is more of an on-rails experience than other Monkey Island instalments. Rob Gilbert&rsquo;s tenet of giving the player several goals in a game segment is dropped in this game in lieu of easier and more compact puzzles. However this never really bothered me. I think Dave Grossman did a great job of finding a middle ground between classic point-and-click adventure games and the Telltale vision of delivering a graphical adventure.</p>
<p>Finally came the time to boot up Return to Monkey Island. The long awaited Ron Gilbert version of what happens after Monkey Island 2. If you remember, that game ends with <span class="inline-spoiler">Guybrush and LeChuck (or rather your brother Chuckie) as children in a theme park.</span> I remember it being one the most controversial endings of its time. When I first played it, I had no clue what it meant or didn&rsquo;t fully grasp what was implied. After replaying the games now, I get why people are so divided by it.</p>
<p>Return to Monkey Island picks up right where Monkey Island 2 left us. I like the spin it takes on the ending, and I&rsquo;m sure it&rsquo;s not what people might have imagined. That in itself is already a great feat. The rest of the game is pretty much divided in two parts, the first part of the game has you going around Melee Island and reminiscing about Guybrush&rsquo;s old adventures of Monkey Island 1 &amp; 2. I have to say this had me twisted for a while. It didn&rsquo;t add a lot of value for me, but I for people that haven&rsquo;t played the originals in 18 years this might be a welcome wave of nostalgia.</p>
<p>Another thing I should probably mention at this time is the Trivia Book. Scattered around the world are Trivia Cards. Questions about any Monkey Island game, which might be a question about the Monkey Island universe, or a question about when Ron Gilbert started working at Lucasfilm Games. It&rsquo;s a nice little bit of extra for fans of the game. But what I didn&rsquo;t like about it, was the unintentional spoilers that filled the Trivia Book. Suddenly there&rsquo;s a question about a part of the game that I wasn&rsquo;t in yet. But the question did reveal something of what might happen. In my case it was <span class="inline-spoiler">the existence of Terror Island, even though I hadn't left Melee Island yet!</span></p>
<p>The second part of the game gives the player a lot more freedom. The whole map opens up and you get 5 items you have to collect, so 5 different tasks to complete where you can easily switch from one to the other, should you get stuck. The classic Ron Gilbert setup to avoid players from feeling frustrated. This is the meat of the game, the nostalgic vibes are left behind on Melee Island and you get a whole heap of new content. Ahhhh, how good it feels to be back in the Monkey Island universe.</p>
<p>The puzzles aren&rsquo;t that hard and I would say that any seasoned adventure gamer will have no trouble getting through the game. I don&rsquo;t think I ever got stuck on anything, all puzzles felt logical and I didn&rsquo;t have to guess at solutions (or furiously combine all items with each other in my inventory). Another change from previous Monkey Island titles, is when hovering over items in the game, you get a glimpse into the mind of Guybrush. It no longer just says <strong>Look at maggots</strong> but instead provides <strong>Ew, maggots</strong>. Other examples include knowing what Guybrush will say to another character in advance, which I really found helpful. It just makes it clearer to the user where the story is supposed to go. Instead of having to talk to a character again to know which open dialogues are left that might impact the story in some way, you now get options that tell you exactly what Guybrush will act. It&rsquo;s just a quicker and clearer way to help keep the player on track.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/6/on-finishing-monkey-island/return-to-monkey-island.png" class="lightbox">
		<img src="/blog/2024/6/on-finishing-monkey-island/return-to-monkey-island_hu_725709051b2d1913.png" class="center " loading="lazy" alt="Return to Monkey Island" title="Telegraphing dialogue prompts for the player">
	</a>
	
		<figcaption>Telegraphing dialogue prompts for the player</figcaption>
	
</figure></p>
<p>The ending of Return to Monkey Island is somewhat of a throwback to the ending of Monkey Island 2. And all along, multiple characters of the supporting cast are already warning Guybrush that the payoff might not be worth it. That Guybrush expects more from the reveal of the Secret than it might actually be. And that is exactly one of the possible endings. There are several others, which I won&rsquo;t spoil here. A couple of variations on the default ending and a couple more unique ones.</p>
<p>This alone is what makes Return to Monkey Island so great for me. It never promised to deliver a huge reveal. It&rsquo;s the journey and the fun you have along the way that is the reward. I enjoyed every step of the way, and the game ultimately tells us that it&rsquo;s hard to reach peoples&rsquo; expectations. Ron Gilbert chose to go with his vision and his story. He managed the player&rsquo;s expectations and delivered on that promise. Not trying to be anything that it shouldn&rsquo;t be. Not trying to exaggerate or reimagine an ending that didn&rsquo;t fit the scene.</p>
<p>Endings are hard, especially ones that have been talked and fantasized about by fans for 31 years. It&rsquo;s usually best to stick to your own vision and create what you wanted to create, instead of catering to others. The same can be said about music, you&rsquo;re creating music because you feel the need to create music, and if others enjoy what you created so much the better for it. But it gets created nonetheless.</p>
<p>Thanks Ron, for creating another Monkey Island game.</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to On%20finishing%20Monkey%20Island">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>goto Amsterdam</title><link>https://pensiveibex.com/blog/2024/6/goto-amsterdam/</link><pubDate>Wed, 12 Jun 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/6/goto-amsterdam/</guid><description>
<![CDATA[<p>I like the goto conference. Talks are more on an architectural level, and less about the new silver bullet out there. Companies also come talk about the pitfalls and talk about the mistakes they made along the way. Above all, I love Amsterdam. It&rsquo;s a city that shouldn&rsquo;t be able to exist. When you look around, many of the houses are just barely holding on. Floors of buildings just zigzag there way up and somehow that&rsquo;s okay.</p>
<h2 id="day-1">Day 1</h2>
<h3 id="is-it-time-to-version-observability-signs-point-to-yes">Is It Time To Version Observability? (Signs Point To Yes)</h3>
<h4 id="charity-majors">Charity Majors</h4>
<p>The first session of the day was a keynote session by <a href="https://charity.wtf">Charity Majors</a> on Observability. She made the case that we should evolve towards a new version of Observability. Think more in terms of <a href="https://isburmistrov.substack.com/p/all-you-need-is-wide-events-not-metrics">wide events</a> and <a href="https://opentelemetry.io/">OpenTelemetry</a> and less about just throwing logs into a system and hoping you&rsquo;ll find what you need when you need it most. One way to implement these wide events, might be by using <a href="https://stripe.com/blog/canonical-log-lines">canonical logs</a>, as discussed by <a href="https://brandur.org/">Brandur Leach</a> (back when he was still employed by Stripe).</p>
<p>In Belgium, we have this saying <strong>&ldquo;meten is weten&rdquo;</strong>, it&rsquo;s a very simple idiom which translates to &ldquo;measuring is knowing&rdquo;. It&rsquo;s mostly used in construction (by physically measuring distances in order to be sure you don&rsquo;t cut anything too short), but I think it holds for software development too. I&rsquo;m a big believer in observability and creating a comprehensive trace of what your application did. A good observability stack creates so much value when you finally get to the hard part, when greenfield is done and you release your product into the wild.</p>
<p>Some other random thoughts I picked up on during this talk:</p>
<ul>
<li><strong>Testing in production</strong>, Charity believes that your job is a Software Engineer is only done when you have verified that your changes work in production. I agree. In a world of <strong>true</strong> Continuous Deployment, I would urge every developer to do this. In my current setting, we still have fixed releases and a feature might not hit production for a month or more.</li>
<li><strong>The smallest unit of software delivery and ownership is a team</strong>, this resonates very well with my own beliefs. No single individual should be responsible for a piece of software. A sense of shared responsibility should be prevalent, and it&rsquo;s a tech leader&rsquo;s job to facilitate and encourage the feeling of shared responsibility among all members of the team.</li>
<li><strong>It&rsquo;s a tech leaders job to build and monitor feedback loops</strong>, I think this statement was meant to make a case for Continuous Deployment. But I feel it also holds for creating feedback loops with people. A tech leader should know what&rsquo;s going on in their team. They should build a rapport with other members of the team, in order to know where frustrations, troubles and pitfalls lie.</li>
</ul>
<h3 id="the-c4-model---misconceptions-misuses-and-mistakes">The C4 model - misconceptions, misuses and mistakes</h3>
<h4 id="simon-brown">Simon Brown</h4>
<p><a href="https://simonbrown.je/">Simon Brown</a> talked about his <a href="https://c4model.com/">C4 model</a>. He started off by explaining what his C4 model is and why he conceptualized it, all of that can be read on the C4 model website, his slides were basically the images on the website. It&rsquo;s followed by the comments and remarks Simon has read or heard about his C4 model, and why they&rsquo;re false. The key takeaways are listed below:</p>
<ul>
<li>Difference between a <strong>container</strong> and <strong>component</strong> is whether or not it is a deployable unit. If so, then it&rsquo;s a <strong>container</strong>!</li>
<li>Event Driven Architecture can be represented by the C4 model, just don&rsquo;t put your Message Broker in the middle for a hub and spoke diagram. Instead, use topics to describe how (micro)services communicate with one another.</li>
<li>C4 is notation independent and visualisation is open for interpretation. You might want to use <a href="https://d3js.org/">D3.js</a> or <a href="https://www.ilograph.com/">Ilograph</a></li>
<li>Micro frontends can be mapped with C4, usual mistakes come from not understanding how to use micro frontends. <a href="https://martinfowler.com/articles/micro-frontends.html">This article by Cam Jackson</a> does a great job of explaining how to implement them.</li>
</ul>
<h3 id="bottom-up-architecture---bridging-the-architecture-code-gap">Bottom-up Architecture - Bridging the Architecture Code Gap</h3>
<h4 id="oliver-drotbohm">Oliver Drotbohm</h4>
<p>The talk started off with a couple of book recommendations, some of them that have already been recommended to me by friends, so I&rsquo;ll have to bump them up my to-read list.</p>
<ul>
<li><a href="https://app.thestorygraph.com/books/84f82468-5179-4ebe-88ee-7d4c608ce5db">The Programmer&rsquo;s Brain</a>, by Felienne Hermans</li>
<li><a href="https://app.thestorygraph.com/books/8faf387b-090e-4f36-a36b-f39b15999c3d">Sustainable Software Architecture</a>, by Carola Lilienthal</li>
<li><a href="https://app.thestorygraph.com/books/dc21c3c0-5c73-4ec1-b008-adb9af3e6924">Just Enough Software Architecture</a>, by George Fairbanks</li>
</ul>
<p>The whole point of this talk was to introduce ways for your code to enforce DDD rules. The typical example that was given, was that an Aggregate Root is not allowed to directly reference another Aggregate Root, except by Id. Oliver has a heavy java background, so some of the tools he mentioned are leaning towards Java, but alternatives will be available in other languages.</p>
<p>Tools exist to enforce this behaviour, like <a href="https://github.com/jqassistant">jQAssistant</a> and <a href="https://www.archunit.org/">ArchUnit</a>. But these check the code after the fact. Instead, Oliver devised xMolecules (supporting Java, dotnet and php, although support for the last two aren&rsquo;t on par with Java) which uses the type system to enforce DDD rules at compile time.</p>
<h3 id="a-break-that-took-longer-than-expected">A break that took longer than expected</h3>
<p>At this point we visited a partner booth by <a href="https://navara.nl/">Navara</a>, we didn&rsquo;t really talk a lot about what they do, but they had me hooked when they asked if I liked puzzling. We were presented with <a href="https://www.idventure-shop.de/Cluebox-Escape-Room-in-a-Box-The-Trial-of-Camelot">a puzzle box</a> that needs to be solved and my colleagues and I immediately went to work. We got two parts open pretty quickly, only to struggle for a while on the next step. Once we get it rolling again, the final puzzle showed itself. We took a break from the puzzle at this point, to attend the next talk on OpenTelemetry.</p>
<h3 id="what-is-this-opentelemetry-thing">What is this OpenTelemetry thing?</h3>
<h4 id="martin-thwaites">Martin Thwaites</h4>
<p>There&rsquo;s not much to be said here. It was an introduction into what OpenTelemetry is, where it started and where it stands now. A quick collection of my notes:</p>
<ul>
<li>Logs are for people, traces are for machines</li>
<li>Structure your logs</li>
<li>Auto-instrumentation seems neat, but won&rsquo;t fit your needs in the long run</li>
<li>The OpenTelemetry Collector is a centralized tool that allows you to config what gets sent to who</li>
<li><a href="https://github.com/w3c/baggage">Baggage</a> is a w3c specification that is implemented by OpenTelemetry, but is not part of the open standard of OpenTelemetry</li>
</ul>
<h3 id="another-short-break-and-trip-to-waterstones">Another short break and trip to Waterstones</h3>
<p>Back to the puzzle box and the break we took did us well, less than 10 minutes after arriving at the stand the final puzzle was solved. We even put the whole thing back, fun little puzzle that saved me from spending €40 to get my own copy, ha!</p>
<p>Now, I like reading books preferably in English, we don&rsquo;t have a lot of choice when it comes to English books in my home town or nearest city. So whenever I go to Amsterdam I would be remiss not to visit Waterstones. The selection is immense and I always find something of note to take home with me. No big surprises this time, just some books that have been on my radar for a while.</p>
<ul>
<li><a href="https://app.thestorygraph.com/books/d7ccd765-59e1-4b64-84e6-c1c4ddf67f56">From Hell</a>, a graphic novel by Alan Moore, drawn by Eddie Campbell</li>
<li><a href="https://app.thestorygraph.com/books/e4cedf44-5cff-4ddf-816c-00ef488fc58b">The Bullet That Missed</a>, by Richard Osman</li>
<li><a href="https://app.thestorygraph.com/books/ec858c60-cbc3-493c-8efd-d4e1374881f1">The Last Devil To Die</a>, by Richard Osman</li>
<li><a href="https://app.thestorygraph.com/books/14bf9567-51dc-42e1-8b52-bab0faa62585">Humble Pi</a>, by Matt Parker</li>
<li><a href="https://app.thestorygraph.com/books/5b8b1886-79e2-4904-bc87-34f902e9570b">Soldiers: Great Stories of War and Peace</a>, by Max Hastings</li>
</ul>
<p>I&rsquo;ve read a couple of graphic novels by Alan Moore already but From Hell was still missing from my collection. I&rsquo;ve heard some great things about it, so I hope it will be just as good as I&rsquo;ve heard. The topic of the book and the mystery of Jack the Ripper is a personal fascination of mine. Even though the events itself are horrendous and gruesome, there&rsquo;s this thing about a mystery that just attracts my attention (much like the afore mentioned puzzle box).</p>
<p>Picking up the last books I haven&rsquo;t yet read from the Thursday Murder Club by Richard Osman, and finding out The Last Devil To Die is a Waterstones edition book with bonus content. Which is fun for me, because more content, but unsettling in its own right.</p>
<p>Humble Pi is a collection of stories where humanity made math errors and what happened because of them. One of the most well known stories is the <a href="https://everydayastronaut.com/mars-climate-orbiter/">1999 Mars Climate Observer mission error</a> where the probe sent measurements in Newton seconds, but the ground station was reading these numbers as pound seconds. I&rsquo;m stoked to read more of these and learning about maths along the way.</p>
<p>Soldiers is a gamble, it was a deal book, but the blurb sounded interesting and military tactics are something I wanted to read more about.</p>
<h3 id="theres-no-ai-in-human-navigating-the-intersection-of-technology-and-humanity">There&rsquo;s no AI in human: Navigating The Intersection of Technology and Humanity</h3>
<h4 id="imran-rashid">Imran Rashid</h4>
<p>I didn&rsquo;t make a lot of notes during this talk. But it was a great eye-opening talk about the use of mental space by using phones, but especially apps by big corporations like Instagram, TikTok, Facebook, etc&hellip; His point came across well, he used Daniel Kahneman&rsquo;s framework of Thinking Fast and Slow (System 1 and 2) to to explain the 0.4s initial emotional response to an input, and the 1s thought response if the initial emotional response didn&rsquo;t yield the desired result.</p>
<p>The talk then continued about the effects of this behaviour on children and how clear statistical evidence is available that since the introduction of smartphones in our everyday life, signs of mental health and suicides in children have increased. He ended the talk with a killer line that really resonated with me:</p>
<blockquote>
<p>Algorithms are raising children more than us.</p>
</blockquote>
<h2 id="day-2">Day 2</h2>
<h3 id="lessons-from-the-pitlane">Lessons From The Pitlane</h3>
<h4 id="marc-priestly">Marc Priestly</h4>
<p>Marc told us his story of how he started as a pit crew member with McLaren. The extraordinary circumstances in which he worked, and the drive for improvement facilitated by Ron Dennis, then owner and CEO of McLaren. It was a very entertaining story that I won&rsquo;t recount in full here, but the key takeaway elements were that you deliver a certain product (in his case a F1 car) and behind the scenes hundreds if not thousands of people are making that happen. Excellence comes from trusting each and every person around you as experts in their field, and together driving the process forward. Innovating, questioning and continuously driving forward.</p>
<h3 id="the-best-programmer-i-know">The best programmer I know</h3>
<h4 id="dan-north">Dan North</h4>
<p>Wow. This talk just had it all, each and every point Dan North pointed out is exactly how I feel what a programmer should be doing. It even highlights several points I&rsquo;m trying to change at my current employer. You should really watch the full talk once it&rsquo;s uploaded to goto&rsquo;s channel.</p>
<p><strong>Just start</strong>. Stop procrastinating. If you know that you don&rsquo;t know what you&rsquo;re doing (yet), then just start with what you know and iterate on the results. Try, fail, learn, repeat.</p>
<p><strong>Build a product</strong>. Code is just the means to deliver the product. If you could deliver the product without code, then that would be preferable. Study the domain, learn how it works and represent it in the code. Watch your users, what frustrates them? Like. Literally watch your users. Go sit next to them, wait for that sigh of frustration and ask about it. These internalized behaviours of users will never make it to a feature list, and yet they lose hours of time on a monthly or yearly basis by doing things the way they are used to.</p>
<p><strong>Solve for now</strong>. This isn&rsquo;t a universal truth. Solving for now, works better in business applications where you iterate and deliver fast. For designing programming languages this won&rsquo;t work. The time to delivery is too high and you have to put in more thought about how you build the solutions that your users are going to use.
Learn to see what is really there. Solve the problem that you really have to solve, not what you think is the problem. Strive for simplicity. Be mindful when bringing in a library into your code, you open yourself up to a potentially wider security risk. If you bring in a full-featured library that you will be using in two or three places, then you might question whether you really need a library for it, can you solve it yourself? Or better yet, is there a whole different approach that might be more suited to the few cases you have?</p>
<p><strong>Choosing the right tool</strong> for the <em>product</em>, not the <em>team</em>. Don&rsquo;t just default your solutions based on what the team members know and can implement quickly. Think about what the product needs to do and which tools are best suited for the task at hand. Programming languages are learnable. Teams can learn and will evolve around the choices that have been made. Do the simplest thing, not the easiest, as presented in a <a href="https://www.youtube.com/watch?v=SxdOUGdseq4">great talk by Rich Hickey</a>. System 1 tells us what the easiest things are, System 2 helps us picking out the right things. The right tool might change over time. <strong>Make the change easy, then make the easy change</strong></p>
<p><strong>Make the change easy</strong>. Minimise the blast radius. Self-contained parts, this might be a microservices architecture, but more options exist. Dan talked about Replaceable Component Architecture, where your applications have a hard shell and a soft center. The hard shell is the API or the outward facing aspects of the application and the soft shell is the internal business logic. Use spikes when implementing features. Spike an idea and stabilize over time. When do you stabilize? When you revisit that code. Dan has a work ethic where he writes <strong>TODO</strong> statements in his spiked code, clearly explaining why certain shortcuts are used and how it should be written. Don&rsquo;t overinvest, do what&rsquo;s necessary for now. If the spike is no longer used or needed, then just delete it and leave it behind, since you haven&rsquo;t overinvested the time lost is minimal. Reduce, reuse, recycle. If you have big things, turn into smaller pieces. If you have several small pieces and tomorrow brings a better way to solve a certain issue, just delete the old code and write the new code. When talking about architectural choices, also think about the <strong>reversible cost</strong>. If change is easy, iteration is easy.</p>
<p><strong>Be a polyglot</strong>. Explore different languages, tools, paradigms. Your mileage may vary but the <a href="https://adventofcode.com/">Advent of Code</a> is a great time to learn a new language! Be <strong>full-stack</strong>. Even if you&rsquo;re only coding backend calls at the moment, think about the frontend. Think about how you would implement the frontend. If you&rsquo;re stuck writing backend code, you&rsquo;re not a backend dev, you&rsquo;re a full-stack dev who just happens to be writing frontend code. Don&rsquo;t stop at software, be interested in the hardware as well.</p>
<p><strong>Care about the team</strong>. Find joy in helping others. Send the team home at the end of the day. Be kind. Assume everyone is doing their best. Build psychological safety. In a psychologically safe zone the following mean:</p>
<ul>
<li>I need help = COLLABORATION</li>
<li>I have a question = I WANT TO LEARN</li>
<li>I disagree = I WANT TO IMPROVE THINGS</li>
</ul>
<p><strong>Staying current</strong>. Join communities, don&rsquo;t be afraid of joining communities that think differently to yourself, you might learn from it! Try new things (but remain sceptical). Practise, practise, practise. Try new things and know that you will be rubbish when you start.</p>
<p><strong>Care about yourself</strong>. Have interests outside of programming. Go home on time. Be kind to yourself.</p>
<h3 id="developer-productivity">Developer productivity</h3>
<h4 id="james-lewis-dan-north-michaela-greiler-birgitta-böckeler-charity-majors">James Lewis, Dan North, Michaela Greiler, Birgitta Böckeler, Charity Majors</h4>
<p>Three topics were touched upon by the panel.</p>
<ol>
<li>Why do we care about developer productivity and how do we measure it?
<em>We don&rsquo;t know how to measure productivity effectively.</em> Management needs to know why they have to pour money towards a certain tool. In order to know that a certain tool is delivering, productivity needs to be measured. Are the costs worth the benefits?</li>
</ol>
<p>Productivity is a bogus statistic for employee evaluation. Some team members&rsquo; sole job might be lifting up other team members. Without that employee the whole team might crash and burn, no hard statistic or point of data will point to this person filling that particular role.</p>
<p>Technical debt can be easily identified by asking the question &ldquo;How confident are you making a change in this code?&rdquo; or any other variation on this question. If there is no confidence making a change effectively, this is a smell for tech debt.</p>
<ol start="2">
<li>
<p>Will AI make programmers&rsquo; jobs obsolete?
<em>We don&rsquo;t know how AI will shape the feature.</em> If you compare AI to calculators, it&rsquo;s just a tool that makes life easier and keeps you from making mistakes. It&rsquo;s an addition to your tool belt and not a replacement for your abilities.</p>
</li>
<li>
<p>Is it harder to onboard junior devs in a remote environment?
Physical environments are key for junior devs to pick up on cues on how other programmers are pair programming, overhear discussions, etc&hellip; In a fully remote world onboarding is still possible, but might be harder or take a longer time.</p>
</li>
</ol>
<h3 id="you-keep-using-that-word">You keep using that word</h3>
<h4 id="sam-newman">Sam Newman</h4>
<p>Basically Sam talked about trying to define the term <strong>asynchronous</strong>. In the end no clear definition could be given, because more than one definition might be right, depending on context. Words and language are ambiguous, be mindful of asking what someone means when they use certain words. Your understanding might not match with their meaning.</p>
<h3 id="a-field-guide-to-reliability-engineering-at-zalando">A Field Guide to Reliability Engineering at Zalando</h3>
<h4 id="heinrich-hartmann">Heinrich Hartmann</h4>
<p>Heinrich talked about several processes they put in place to monitor incidents and measure on-call health (the number of times an individual or team was on-call for a production issue). Monitoring your systems by implementing Traces and spans throughout your system allows yourself to reduce the Time to Detect issues. Metrics should be viewed through the lens of the User. User Experience is key, if your servers are buckling, but User Experience isn&rsquo;t impacted, then you have an issue, but it isn&rsquo;t as important.</p>
<p>An automatic incident alert should be as explicit as possible. Zalando uses the following template: <code>&lt;feature&gt;_&lt;platform&gt;_&lt;error rate over benchmark rechead&gt;_in the past &lt;timeframe&gt;</code>. For example: <code>Checkout_Mobile_Error rate &gt;0.82% in the past 6 hours</code>.</p>
<p>When certain teams or individuals have higher incident rates than others accountability is demanded by managers and propagated upwards.</p>
<p>Use distributed traces to have a full view of how your microservice environment is performing. Break through the &ldquo;My service is healthy, it must be another team that&rsquo;s causing the issue&rdquo; shrug-off mentality.</p>
<p>When incidents occur, use the Google template to perform post-mortems and log them formally. They should be searchable, readable and have action items that are SMART and can be verified by anyone that they have been put into action.</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to goto%20Amsterdam">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Us vs. Them</title><link>https://pensiveibex.com/blog/2024/6/us-vs-them/</link><pubDate>Thu, 06 Jun 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/6/us-vs-them/</guid><description>
<![CDATA[<p>I listened to the latest episode of <a href="https://www.globalplayer.com/podcasts/episodes/7DriXdV/">We Can Be Weirdos</a> where Rob Auton mentions how nice it would be when sitting on the train if you could just talk to the person next to you, get a load off your chest and just carry on with your day.</p>
<p>It reminded me of how many times I was in public and someone random started talking to me and I just wasn&rsquo;t open to the experience. It&rsquo;s something I grew up with. &ldquo;Don&rsquo;t talk to strangers&rdquo;, &ldquo;Come straight home&rdquo;.</p>
<p>I came to the realization that I divided my world view in two categories. People I know and other people. It&rsquo;s something I tried to work on for a while now. Usually when I pass someone on the street when I&rsquo;m walking my dog, I would give them a half-hearted smile. Any Belgians reading this know <em>exactly</em> what kind of smile I&rsquo;m referring to.</p>
<p>Now I try to actually smile to someone I&rsquo;m passing. Or not at all, if I don&rsquo;t feel like smiling. But no more in between. For me, this is already a big step. Going one further and actually being open to talk to people I haven&rsquo;t met yet. I&rsquo;m sure it would be worthwhile. But my mind is always set on the idea.</p>
<p>When I&rsquo;m out doing something, my mind is set on my goal, any interruption along the way causes me to feel like I&rsquo;m not progressing towards my goal. It&rsquo;s a silly, but persistent thought. There&rsquo;s nothing bad going to happen if I don&rsquo;t achieve that goal in the optimal time. I think it stems from the prejudice that I would be wasting my time, being dragged into a conversation I didn&rsquo;t ask for. Whereas it might be hugely rewarding.</p>
<p>If the We Can Be Weirdos podcast has taught me anything it&rsquo;s that different people have different beliefs, but it doesn&rsquo;t make them any less interesting, or funny, or engaging. It&rsquo;s opened my mind to the idea that everyone has something to tell. And if you let yourself be open to the experience, it might be worth your while.</p>
<p>They say &ldquo;a stranger is a friend you haven&rsquo;t met yet&rdquo;. It&rsquo;s a statement that was too cut and dry for me, I think if I changed it to &ldquo;every stranger has a story to tell&rdquo;, it vibes a little better with me.</p>
<p>I won&rsquo;t be chatting up strangers just yet, but I&rsquo;m more open to being chatted to. Come at me, world.</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Us%20vs.%20Them">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Birthday gift gone wrong</title><link>https://pensiveibex.com/blog/2024/4/birthday-gift-gone-wrong/</link><pubDate>Sun, 28 Apr 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/4/birthday-gift-gone-wrong/</guid><description>
<![CDATA[<p>A friend of mine was celebrating his birthday the other day. And in preparation for it, I designed this little puzzle challenge. Basically, it&rsquo;s just a closed box with a numeric lock holding its contents hidden. On the bottom of the box I printed a QR code, leading to a <a href="https://janisjarighoera.be/">website</a> where I edited the logos of boardgames (in his collection) to just show the first letter. Behind every logo sits another image, giving the final clue to opening the box.</p>
<p>Anyway, I arrived at the party, gave the little treasure chest. He visited the site and immediately recognized one of the boardgames. He entered the name of the game, but nothing happened. To my utter dread, I just stood there. I had tested this. Locally, after deployment, desktop mode, mobile mode. Why didn&rsquo;t it work?</p>
<p>The day after the party I woke up early to try and debug what might have happened. I opened the website on my laptop, entered one of the correct answers, and as I expected, it just worked. I then opened the site on my mobile device, entered the same answer, but no dice. It just didn&rsquo;t do anything.</p>
<p>I started furiously scouring Google, hungry for answers. What might happen that Javascript worked on mobile but not on desktop? I did find some things about mobile browsers not always supporting the latest EcmaScript standards, so I transpiled my code to ES5 in the hopes that that might be the case. It seemed plausible, whenever I worked with javascript in production environments (or even for this blog) there&rsquo;s always a <a href="https://babeljs.io/">Babel</a> step transpiling my code.</p>
<p>Click, deploy. No luck.</p>
<p>Hold on. My device is probably showing a cached version of the webpage. I just have to open an incognito window and try again. <strong>Still no luck</strong>. I tried some other things that didn&rsquo;t seem to make any sense to me, but I might as well try just in case. But nothing worked.</p>
<p>At this point I became desperate. I was doubting if my Javascript code even loaded. But instead of just putting a simple <code>alert</code> message to assuage any doubts, I decided to find a way to debug my code. Turns out this just isn&rsquo;t that easy on a mobile device. You have to enable Developer Options and then <a href="https://developer.chrome.com/docs/devtools/remote-debugging">enable Remote Debugging with Chrome Dev Tools</a> on Android.</p>
<p>Now this might just have been my lucky ticket, were it not for my extremely finicky USB-C port on my phone. It&rsquo;s horrible. There&rsquo;s only one cable in existence that still provides power to my phone (it&rsquo;s been chewed up by my dog and somehow is the only one that still fits). So whenever I plug my phone in, I fiddle, jiggle and twiddle for about 5 minutes before I hear the tune of a phone charging and thank all heavens that it survives another charge cycle.</p>
<p>But now when I had to plug it into my PC, it just didn&rsquo;t recognize it, and I couldn&rsquo;t enable USB debugging. So I had to go and find another option. And here&rsquo;s the interesting part, at least for me it was, I learned of <a href="https://eruda.liriliri.io/">Eruda</a>. A project to provide Dev Tools built into your webpage. It&rsquo;s awesome and mindblowing. You get a full-blown Console window, with all Error and console logging (and lots of other features as well, go check it out). I added the following script tags to my webpage and hit deploy:</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#f92672">script</span> <span style="color:#a6e22e">src</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;https://cdn.jsdelivr.net/npm/eruda&#34;</span>&gt;&lt;/<span style="color:#f92672">script</span>&gt;
</span></span><span style="display:flex;"><span>&lt;<span style="color:#f92672">script</span>&gt;<span style="color:#a6e22e">eruda</span>.<span style="color:#a6e22e">init</span>();&lt;/<span style="color:#f92672">script</span>&gt;</span></span></code></pre></div><p>Nothing happened. There&rsquo;s no gear icon in the lower right corner. It took me a while, but that&rsquo;s when I found my first stupid mistake. I added all <code>script</code> tags in the <code>head</code> of the HTML document. After I placed them just before closing the <code>html</code> tag (which is a best practice anyway and I&rsquo;m not sure why I didn&rsquo;t do this from the start), it did work! Finally, I had a console window. I could start debugging and I was <em>sure</em> that my Javascript code loaded in correctly.</p>
<p>I entered one of the correct answers and got a console error. Guess what? Mobile keyboards auto-capitalize. Whenever an answer is exactly correct, I do an <code>#id</code> search over the HTML document with the user input. Of course that didn&rsquo;t return any results for the wrong capitalization and of course my code couldn&rsquo;t handle an <code>undefined</code> error.</p>
<p>It was a horribly stupid mistake, and if I had taken the time to write tests I would have definitely found the bug and fixed it. But I just wanted to box something together quickly and didn&rsquo;t think I needed tests to get the puzzle to work properly.</p>
<p><strong>For all code, be they big or small, write test cases for every method call!</strong></p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Birthday%20gift%20gone%20wrong">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Installing a new PC</title><link>https://pensiveibex.com/blog/2024/4/installing-a-new-pc/</link><pubDate>Thu, 25 Apr 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/4/installing-a-new-pc/</guid><description>
<![CDATA[<p>I received a new laptop at work the other day. So begins the cycle again of having to tweak every little thing to the way I like it. I&rsquo;m a tinkerer and I love to play around in settings and customization screens. Heck, I&rsquo;ll even hop in regedit willingly to get the specific behaviour I want.</p>
<p>But I never properly document all the steps I take to get there. I do a lot of tweaking in my IDE&rsquo;s and I thank all heavens that in recent years these settings can be saved to your account, so that I don&rsquo;t have to painstakingly redo every little thing.</p>
<p>Installing programs is easier. I always fall back to <a href="https://ninite.com/">Ninite</a> to install the stuff I need. But lately, I have a lot more tools than Ninite provides. Sure, it&rsquo;s still a great tool, and it provides an easy and quick way to get you up and started. But what about <a href="https://brave.com/">Brave</a>, my browser of choice? It&rsquo;s not even an option. What about <a href="https://app.prntscr.com/en/index.html">Lightshot</a>, <a href="https://github.com/sabrogden/Ditto">Ditto</a>, <a href="https://obsidian.md/">Obsidian</a> or any of the other custom tools?</p>
<p>So this time around, I tried installing everything with <a href="https://community.chocolatey.org/">Chocolatey</a><sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. It&rsquo;s a public repository, with packages provided by the community, which has its own risks, but on the whole community-driven tools haven&rsquo;t led me astray so far (you can tell I wasn&rsquo;t hit by the XZ backdoor).</p>
<p>I found everything I needed and installed everything through Chocolatey. So now when I need to set up a new PC, I just have to run this handy little command:</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>choco list -lo -r -y | % { <span style="color:#e6db74">&#34;choco install </span>$($_.SubString(<span style="color:#ae81ff">0</span>, $_.IndexOf(<span style="color:#e6db74">&#34;|&#34;</span>)))<span style="color:#e6db74"> -y&#34;</span> }</span></span></code></pre></div><p>And I get a list of install commands to run on my new machine. Finally free of all the manual hassle!</p>
<p>Cool, now I just want to get rid of all the Windows bloatware crap. I used the <a href="https://github.com/LeDragoX/Win-Debloat-Tools">Win Debloat Tools</a> by Plínio Larrubia. Highly effective, highly recommend. With just one click of a button all the useless crap like Weather apps and MSN News are gone. Just barebones OS, thank you.</p>
<p>There&rsquo;s a couple of things I still had to do manually, like installing the <a href="https://www.jetbrains.com/lp/mono/">Jetbrains Mono</a> font, setting up Ditto, Lightshot and Cmder with the settings I like.</p>
<p>Overall I think this experience is still better than what I did before. I&rsquo;m curious to hearing how any of you tackle this problem. Get in touch!</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>I could have also tried <a href="https://github.com/microsoft/winget-cli">Winget</a> but decided to go for Chocolatey which has been around for a while longer, hoping all tools I use can be found there.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Installing%20a%20new%20PC">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>There's an AI for that</title><link>https://pensiveibex.com/blog/2024/4/theres-an-ai-for-that/</link><pubDate>Thu, 11 Apr 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/4/theres-an-ai-for-that/</guid><description>
<![CDATA[<p>About a year and a half ago ChatGPT 3.5 was let loose, and it took the world by storm. Since then we&rsquo;ve seen tremendous improvements in performance and reliability with ChatGPT 4. Not only that, but all other Generative AI tools have made major leaps. I remember way back when Dall-E 2 was released, I tried to create some images, some worked but others flopped. You really had to know what language to speak to the AI in order for it to do what you wanted. That&rsquo;s about the time that <strong>&ldquo;Prompt Engineering&rdquo;</strong> suddenly became a skill you should have. I never understood that trend. To me, it always just meant that GenAI just wasn&rsquo;t there yet.</p>
<p>And sure enough, look at Dall-E 3 now. I barely have to edit my prompts, I just regenerate the same prompt until I&rsquo;m satisfied with my creation. Prompt Engineering might still be a thing, but it is no longer needed to create the content you want.</p>
<p>The other trend, that&rsquo;s still going on, is the use of AI for anything and everything. Everybody suddenly wants to integrate AI in everything they&rsquo;re doing. And demand, in this case, has created supply. Much like the <strong>dot-com bubble</strong> of the late-90&rsquo;s, we have now entered the <strong>AI bubble</strong>. Just about every day a new AI tool pops out of the ground, dare I say even faster than development of new Javascript frameworks.</p>
<p>I&rsquo;m sure many of these tools (and companies/startups behind them) will go belly-up in the coming years. However, right now, it&rsquo;s an exciting time to live in. I love watching how the landscape evolves. The possibilities are tremendous, but the ethical implications are equally significant. When ChatGPT first became mainstream, it meant a great deal of hurt to institutions like universities and schools. Suddenly being confronted with this tool, that seemingly could generate all the homework of students.</p>
<p>As a teacher, myself, I experienced this first-hand. Students only took half the time to complete the exercises I had set up, using AI to generate the answers for them. While I&rsquo;m not completely against using AI as a <strong>tutor</strong> (in a sense it is no different to Googling if source citation is enabled), using it as a monkey to do your work for you is not instructive.</p>
<p>As a tutor, AI can provide reasoning and explanation in a different tone, or from a different viewpoint to help you better understand something. With the obvious caveat that GenAI is extremely bad at admitting it doesn&rsquo;t know something, and will convincingly provide false answers to any question. So always check your sources. Use AI as a springboard to find connections and start your search for knowledge. It&rsquo;s good at summarizing, it&rsquo;s good at providing many different resources. Know its strengths and its weaknesses and use it accordingly.</p>
<p>Even though I&rsquo;m excited for the future of AI, I&rsquo;m also horrified. There are definite ethical points that need addressing. There are implications and implementations that the world just isn&rsquo;t ready for. <em>Suppose</em>, that a leap in robotics is made similar to the leap in AI of the last couple of years. If you could combine the two, manual labour could be reliably replaced with robots. That might spell the start of economic collapse. Workers get replaced by robots, because they&rsquo;re cheaper. So if companies purchase robots to do manual labour, and workers get laid off and fall on unemployment, then how will they be able to pay for the services that those companies provide? And if those companies no longer receive income, how can they still purchase the raw resources for the products they fabricate?</p>
<p>There&rsquo;s a famous saying that comes to mind, first uttered (or should I say encoded?) as the first message telegraphed in Morse. <strong>&ldquo;What Hath God Wrought?&rdquo;</strong> Since then, the message has been repeated time and again, whenever mankind has made another leap in information communication. It seems awfully apt describing the current state of affairs of GenAI and its future if the ethical aspect keeps getting swept under the rug.</p>
<p>However I&rsquo;m no expert. These are no more than musings of how a world could look. I&rsquo;m sure that people are looking into this. But should a robotics market push for a rush-to-market strategy as OpenAI has done with ChatGPT (and the consequences be damned), then I&rsquo;m not sure we&rsquo;re working towards a better world.</p>
<p>I didn&rsquo;t mean for this post to take such a turn. So, in order to end on a more positive note, I curated a list of AI tools that I either use frequently or found interesting. All of them are free to use (although some require registration in order to use).</p>
<ul>
<li><a href="https://www.phind.com/">Phind</a> is a tool for programmers. I generally use it for the same thing that&rsquo;s promoted as the bots placeholder text, <em>&ldquo;Ask anything. What are you stuck on?&rdquo;</em></li>
<li><a href="https://www.perplexity.ai/">Perplexity</a> a great tool for fact-based questions. For any and all questions that require an answer you don&rsquo;t know, such as <em>&ldquo;Why does my nose tingle when I eat wasabi?&rdquo;</em>. The bot provides links to sources (both text and video).</li>
<li><a href="https://consensus.app/">Consensus</a> I used to browse through <a href="https://scholar.google.com/">Google Scholar</a> when I needed answers based on scientific papers, now I just ask the same question to Consensus. Like the above tools it&rsquo;s the same kind of RAG (Retrieval-Augmented Generation) implementation, but this time trained for scientific papers.</li>
<li><a href="https://pi.ai/">Pi</a> I&rsquo;m genuinely impressed with this one. It&rsquo;s an AI bot that is emotionally intelligent. I talked to it about my day and it gave some good advice. It&rsquo;s no replacement for a mental health professional, but it is an easy remedy to create perspective when you&rsquo;re stuck.</li>
<li><a href="https://replicate.com/meta/musicgen">MusicGen</a> I don&rsquo;t use this one frequently. I&rsquo;m just interested at what it can do. I like experimenting with it and mixing different genres and listening to the output.</li>
<li><a href="https://www.chatpdf.com/">ChatPDF</a> Got a manual lying around in PDF form and can&rsquo;t find what you&rsquo;re looking for? Upload it and just start chatting to get the info you need. Haven&rsquo;t tried this one extensively. But it looks promising.</li>
<li><a href="https://podcast.adobe.com/enhance">Adobe Podcast AI</a> Clean up background noise from your input audio. It&rsquo;s impressive what it can do. I haven&rsquo;t had the need to use this one yet, but I have heard others speak fondly of it.</li>
<li><a href="https://www.roomgpt.io/">RoomGPT</a> Provide it with an image of your room and it can transform it in different styles. I&rsquo;m moving house soon, and will definitely use this to help me design my new home.</li>
<li><a href="https://www.gnod.com/">GNOD</a> At first sight, this doesn&rsquo;t really provide anything new. A music/literature/movie-map to discover similar content to the one you have entered (last.fm already did this 20 years ago, based on user content). What did impress me was GNOD Products. Filtering through several products based on several different inputs is a great way to view the product landscape (although it boggles the mind what this has to do with AI).</li>
</ul>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to There%27s%20an%20AI%20for%20that">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>The Dark Eye on Steam Deck</title><link>https://pensiveibex.com/blog/2024/4/the-dark-eye-on-steam-deck/</link><pubDate>Mon, 08 Apr 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/4/the-dark-eye-on-steam-deck/</guid><description>
<![CDATA[<p>So I joined the <a href="https://dosgame.club/@adventure">Adventure Game Club</a> last month and decided to join in for the month of April. The game of the month? <a href="https://www.mobygames.com/game/1782/the-dark-eye/">The Dark Eye</a>. It&rsquo;s a game which I hadn&rsquo;t heard of and would never have played if it weren&rsquo;t for this club of enthusiastic gamers with an immense knowledge of the scene. Which is exactly what I was looking for, those gems of the genre that didn&rsquo;t get the credit they deserved at the time of release.</p>
<p>I also recently purchased a Steam Deck, so I wanted to play the games on my Steam Deck. And that&rsquo;s exactly where things started to get a little more difficult. At first I thought things wouldn&rsquo;t be that hard, the game was abandonware, so it was freely available for download. I googled it and immediately found a link on <a href="https://www.myabandonware.com/game/the-dark-eye-3ij">MyAbandonware</a>. But just unpacking the ISO file and loading this in ScummVM didn&rsquo;t give me a recognized game.</p>
<p>Okay, sure thing, I can fix this. After some googling I found the <a href="https://wiki.scummvm.org/index.php?title=The_Dark_Eye">ScummVM Wiki page for The Dark Eye</a>. This has some Install Notes which are quite important:</p>
<blockquote>
<p>The Dark Eye has key files stored in an installer archive. You will need to run &ldquo;SETUP/DKYINSTL.EXE&rdquo; in a Windows VM, then copy the full contents of the CD into the folder that gets created (usually &ldquo;C:\DARKEYE&rdquo;). ScummVM should then recognise the game.</p>
</blockquote>
<p>Not only that, but a little further down the following message is added:</p>
<blockquote>
<p>As of this writing, testing has been done with the Expert Software release of this game. Other releases, such as ones marked as version 1.0.3 have not been fully tested.</p>
</blockquote>
<p>The initial download I found was, of course, version 1.0.3 and not the version I needed. I them remembered that <a href="archive.org">archive.org</a> has turned into so much more than just a website archiver, any books that have come into public domain, any abandoned software or basically anything that is worth saving is hosted on it. I searched for The Dark Eye and found <a href="https://archive.org/details/the-dark-eye_202110">a version that is compatible</a> with ScummVM (though this was only visible after downloading the file and not mentioned on the page itself).</p>
<p>Success! Now I just needed to run the installer on my Windows laptop and get the necessary extra files.</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/4/the-dark-eye-on-steam-deck/this-app-cant-run-on-your-pc.png" class="lightbox">
		<img src="/blog/2024/4/the-dark-eye-on-steam-deck/this-app-cant-run-on-your-pc_hu_5f7c83b5df859be.png" class="center " loading="lazy" alt="&ldquo;Blue error message from Windows telling me the app can&rsquo;t be run on my PC&rdquo;" title="Figures it wouldn&#39;t work">
	</a>
	
		<figcaption>Figures it wouldn&#39;t work</figcaption>
	
</figure></p>
<p>Okay, sure&hellip; I just need a Win95 VM to install the files and I&rsquo;m good to go. Again, <a href="https://archive.org/details/windows_95_vdi">archive.org to the rescue</a>! You&rsquo;ll need <a href="https://www.virtualbox.org/">VirtualBox</a> for this to work. You can add a new VM with the following steps:</p>
<ol>
<li>New</li>
<li>Name your VM (if you name it <strong>Win95</strong> Virtual Box will autodetect the OS version you&rsquo;re trying to install)</li>
<li>Next</li>
<li>Make sure you give the device no more than <strong>480MB</strong> of memory. I used 256MB.</li>
<li>Keep the default of 1 CPU.</li>
<li>Next</li>
<li>Use an Existing VHD file</li>
<li>Browse to the location of the VDI file you downloaded from archive.org</li>
<li>Finish</li>
</ol>
<p>After starting the VM, I was presented with another error message:</p>





<pre tabindex="0"><code>While Initializing device IOS: Windows Protection Error. 
You need to restart your computer.</code></pre><p>Modern CPU&rsquo;s are too fast for poor old Windows 95 (any CPU that&rsquo;s faster than 350MHz, really) . So a fix is needed to patch the CPU firmware. This can also be downloaded form <a href="https://archive.org/details/fix-95-cpu-v3-final">archive.org</a>. Just follow these steps to patch your VM:</p>
<ol>
<li>Settings -&gt; Storage</li>
<li>Select your CD drive</li>
<li>Click the CD icon on the right hand side</li>
<li>Select the ISO file you downloaded from archive.org</li>
<li>Boot the VM</li>
<li>You&rsquo;ll get some red on black text. This is the installer, complete the process.</li>
<li>Power off your machine</li>
<li>Remove the ISO file from your CD Drive</li>
</ol>
<p>Just one more step if you want to reuse your VM without any additional installed software at this point. If you don&rsquo;t care about this, then go ahead and skip to the next paragraph.</p>
<ol>
<li>Click the context menu next to your VM, and select Snapshots</li>
<li>Take a new Snapshot, this is your clean install bootable Win95 machine</li>
</ol>
<p>Good to go! Alright, so now Win95 finally boots up. Now we just need to install The Dark Eye and we can finally get on with the good stuff. So, go ahead and load the ISO file for The Dark Eye in your VM&rsquo;s CD drive. Boot up the machine, and use explorer to install the game (you don&rsquo;t need Quicktime, we&rsquo;re only interested in the extra files). After installation they can be found in <code>C:\DARKEYE</code>.</p>
<p>The only issue that remains is how to get these from the VM to your host machine? Win95 doesn&rsquo;t provide an easy way to copy paste files from the VM to your host. Luckily, there&rsquo;s a neat little workaround. Go ahead and power down your machine.</p>
<ol>
<li>Click the context menu next to your VM, and select Snapshots</li>
<li>Select the Current state row</li>
<li>Clone the machine (the little sheep icon on top)</li>
<li>You don&rsquo;t need to change any of the default settings (should they ever change, the important was is that you create a full clone and not a linked clone)</li>
</ol>
<p>Now navigate to the folder of your newly cloned VM. Locate the VDI file and open it with 7zip. There you go, this is the C: drive of your machine and you can extract the DARKEYE folder from it, add it to the contents of The Dark Eye ISO and send this to your Steam Deck. Add the game through ScummVM like you would any other game and you&rsquo;re set.</p>
<p>You don&rsquo;t need the cloned VM anymore after this point. The main reason for doing it this way, is that the VDI is saved as the initial state of a VM, any changes you make after initial creation are stored in a different VDI file which is patched on top of the main VDI file. But these are not stored as browsable files and folders, they&rsquo;re some kind of scratch file containing changes I didn&rsquo;t bother to dig into.</p>
<p>A little more effort than I bargained for, but I&rsquo;m looking forward to starting it. And hey, I have a Win95 VM ready to go in case I ever need it.</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to The%20Dark%20Eye%20on%20Steam%20Deck">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Colour me interested</title><link>https://pensiveibex.com/blog/2024/4/colour-me-interested/</link><pubDate>Fri, 05 Apr 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/4/colour-me-interested/</guid><description>
<![CDATA[<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/4/colour-me-interested/colour-me-interested.svg" class="lightbox">
		<img src="/blog/2024/4/colour-me-interested/colour-me-interested.svg" class="center " loading="lazy" alt="Colour me interested" title="Colour me interested">
	</a>
	
		<figcaption>Colour me interested</figcaption>
	
</figure></p>
<p>That&rsquo;s it. That&rsquo;s all you get.</p>
<p>If you think you&rsquo;ve found the solution. You can mail it to me by following the link at the bottom of the page.</p>
<p>Good luck!</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Colour%20me%20interested">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Risks of GenAI</title><link>https://pensiveibex.com/blog/2024/3/risks-of-genai/</link><pubDate>Sun, 31 Mar 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/3/risks-of-genai/</guid><description>
<![CDATA[<p>I&rsquo;ve been using <a href="https://github.com/features/copilot">Github Copilot</a> for a couple of months now. It was an experiment in our company to test its use and see what benefits it might provide to developers. I have to say I was blown away when I saw what it could do. I was happily writing some tests in our code base, calling Builder objects to create the necessary setup data. Out of nowhere I get this suggestion of Copilot for the rest of the code for the Builder call. Sure it wasn&rsquo;t exactly what I needed, I still had to make a few changes and tweaks, but it blew my socks off. At one press of a button I get several lines of code which approximately is what I need at that time. Oh, did I also mention that our codebase is written in <strong>Dutch</strong>?</p>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/3/risks-of-genai/unlimited-power.jpg" class="lightbox">
		<img src="/blog/2024/3/risks-of-genai/unlimited-power_hu_79030f401b8fca07.jpg" class="center " loading="lazy" alt="Unlimited power" title="Unlimited power">
	</a>
	
		<figcaption>Unlimited power</figcaption>
	
</figure></p>
<p>I was washed over by this feeling of unbelief, of bewilderment and amazement. What would this allow me to do? What else could it do? Could I just get it to write any code for me and be done with it?</p>
<p>Maybe, kinda? Every time I wrote a new method, Copilot would come up with its suggestion of what the method should do. It was never a case of just accepting its suggestion and moving on. It was more along the lines of, review the suggestion, make necessary changes, accept and move on.</p>
<p>So suddenly I was <strong>reviewing</strong> code, while I actually should be writing code. This isn&rsquo;t bad in itself, but I do find both tasks require a slightly different mindset. You could argue that this isn&rsquo;t any different from copy pasting code from Stack Overflow, or any other part of the codebase, and you&rsquo;re right. It isn&rsquo;t. The difference is that the suggestions are given regularly and profusely. Copy pasting code was a deliberate act when you got stuck on solving a certain issue. Now, you just get suggestions flung at your face and you can either choose to implement them or ignore them.</p>
<p>However, what&rsquo;s even worse is that Copilot will suggest a certain implementation. If its suggestion is good enough for your needs (just needing a couple of tweaks), you&rsquo;ll accept it and move on. We&rsquo;ve just created a new function that does what we need. We haven&rsquo;t checked if there&rsquo;s another function that could meet our needs and reuse it.</p>
<p>GitClear have studied the trend of GenAI in the past 18 months and published a <a href="https://www.gitclear.com/coding_on_copilot_data_shows_ais_downward_pressure_on_code_quality">whitepaper</a> on the subject<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. They&rsquo;ve identified a couple of different metrics they tracked across several years. The ones that sprung out to me are the &ldquo;Moved&rdquo; and &ldquo;Churn&rdquo; categories.</p>
<h3 id="moved-code">Moved code</h3>
<blockquote>
<p>A line of code that is cut and pasted to a new file, or a new function within the same file. By definition, the content of a &ldquo;Moved&rdquo; operation doesn&rsquo;t change within a commit, except for (potentially) the white space that precedes the content.</p>
</blockquote>
<p>The amount of moved code since GenAI has come into our lives, has dropped by 5 to an estimated 10% over the past two years<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>. This fits with my own experience, if you&rsquo;re given a gift-wrapped piece of code, why check if you could have reused something else?</p>
<h3 id="churned-code">Churned code</h3>
<blockquote>
<p>For a line to qualify as &ldquo;churned,&rdquo; it must have been authored, pushed to the git repo, and then reverted or substantially revised within the subsequent two weeks. Churn is best understood as &ldquo;changes that were either incomplete or erroneous when the author initially wrote, committed, and pushed them to the company’s git repo.&rdquo;</p>
</blockquote>
<p>Within two weeks of committing certain lines of code, they have been <strong>reverted or revised</strong> completely. That&rsquo;s a worrying thought if I ever read one. And yet, since GenAI this has gone up, by 1.5% in 2023 to an estimated 3% in 2024.</p>
<p>As developers, it&rsquo;s in our nature to be lazy. This used to be described as a good thing. Why should I write code if I can reuse an existing one with minor changes? Since the emergence of GenAI, this inherent laziness is suddenly turned into a flaw. Why should I write code if GenAI can write it for me?</p>
<p>I think it&rsquo;s this trait that is at the root of the code churn increase. As with any tool, mastery comes with knowing how to use it. In my opinion, GenAI (at the time of writing) is really good in solving two problems.</p>
<p>The first is getting rid of <strong>blank page syndrome</strong>. Many devs don&rsquo;t know where to start if asked to write a certain feature from scratch. Many even admit to not knowing how to setup a new solution or project. Preferring to start from an existing project and adapting along the way. Both approaches have their merits, but if you want that flying start, GenAI can provide that.</p>
<p>The second is helping with <strong>menial tasks</strong>. Calling a Factory with a lot of parameters, calling a Builder class to get the object you want and any other boring tasks that GenAI could write for you with the press of a button. This just helps you do other stuff faster and keeps you in a flow state.</p>
<p>I&rsquo;m still planning on using Copilot, mainly for helping with menial tasks. I&rsquo;ll also be looking to turn off automatic suggestions by Copilot, instead opting for suggestions when <strong>I</strong> ask for them.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>You have to provide a mail address and name, if you want to protect your privacy there are plenty of <a href="https://temp-mail.org/">tools</a> to help you do that.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Raw data is available in the Whitepaper. The only caveat is that for every year of the analysis more repos have been analysed than the previous year, which is way percentages is the only thing that makes sense to talk about. But I wonder if the population size is large enough to make certain conclusions (2020 has less than half the amount of repos analysed in comparison to 2023)&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Risks%20of%20GenAI">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Keleşce</title><link>https://pensiveibex.com/blog/2024/3/kelesce/</link><pubDate>Mon, 25 Mar 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/3/kelesce/</guid><description>
<![CDATA[<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/3/kelesce/kelesce.jpg" class="lightbox">
		<img src="/blog/2024/3/kelesce/kelesce_hu_f1e8a660b59d30fa.jpg" class="center " loading="lazy" alt="The first ten words of Kelesce" title="The first ten words of Kelesce">
	</a>
	
		<figcaption>The first ten words of Kelesce</figcaption>
	
</figure></p>
<p>Last week I was tipped off to a puzzle hosted by <a href="https://www.alperenkeles.com/">Alperen Keles</a>. I opened the link and was immediately intrigued. Any puzzle with visual elements where you aren&rsquo;t given any information except for the simple task of deciphering what you see is a delight.</p>
<p>If you want to give it a go for yourself, <a href="https://puzzle.alperenkeles.com/">the puzzle</a> is still up and accepting answers. In this post I&rsquo;ll be explaining my solving process for the puzzle, so stop reading here if you want to avoid any spoilers.</p>
<p>The obvious thing to see is that any given square consists of one or more lines. None of the squares had an obvious repeating pattern, so that ruled out that the space character was encoded. Some squares are fairly simple (2 and 4 in the image above), others are quite complex (squares 9 and 10). That led me to believe that every square had to represent a single word.</p>
<p>Given that a square is a word, then focussing on the squares with only 1 line is the next logical step. The English language only knows two single-letter words, being <strong>a</strong> and <strong>I</strong>. This seemed to make sense, I then started looking for squares consisting of three lines, that looked similar. I was searching for <strong>the</strong>. A couple of matches sprung out to me, and confirmed I was on the right path.</p>
<p>However, I couldn&rsquo;t find a complete match. There seemed to always be slight variations. At this point I was really invested in solving the mystery. I had no idea how many people the puzzle might attract and really wanted to be the first to solve it. Since the first two clues were up and available to anyone, it seemed only fair to also look at the information. I think future puzzles could benefit from opting out from hints and thus increasing the challenge, if this also could be reflected in the submissions. I think the puzzle could also be solved without the first hint, but it greatly sped up the decryption process.</p>
<p>So I now had a <a href="https://puzzle.alperenkeles.com/clue1">plain text and the Keleşce equivalent</a>. This immediately confirmed my earlier suspicions, a word is encoded to a single square, and every letter is encoded to a line within that square. The next things of note, is the pattern. Keleşce always starts it first letter going from North to East, followed by East to South, South to West and finally West to North. If a word is longer than 5 letters, the pattern just repeats.</p>
<p>So next I focused on the first two words in the clue. <em>&ldquo;It is&rdquo;</em>. The letter <em>i</em> was encoded differently in both squares. That annoyed me. At first I thought Keleşce might be case sensitive. That uppercase I and lowercase i had two different encodings (much like different entries in the ASCII table). However, when I double-checked this assumption with another word, the letter <em>i</em> had yet another different line paired with it.</p>
<p>So, clearly the start and end position of a line had no relation to the letter being encoded. What was left? The area of the rectangle! I downloaded the image, opened my favourite image processor (paint.NET represent!) and traced the rectangle. But the letters <em>i</em> didn&rsquo;t match. Well, there goes that idea.</p>
<p>I took another look at the letter <em>a</em> standing all by itself in its square. This wasn&rsquo;t just a rectangle. This was a square! Sure enough, every time the letter a was encoded in Keleşce the resulting line formed a square. Sizes varied, but was always a square. That&rsquo;s when it hit me, its based on ratios.</p>
<p>A has a ratio of 1, the length of both lines is exactly the same. Once I had checked my assumption by running the theory against several different occurrences of the same letter, it was just a matter of mapping every different ratio and then solving the original text.</p>
<p>Although the Alperen seemed to be under the assumption that the puzzle could only be solved by programmers (and even though I am programmer) I didn&rsquo;t write a single line of code, just using an image processing tool to calculate the different line lengths. I&rsquo;m sure I could have written a tool for it, but I would have spent more time figuring out how to implement the interpretation of the different lines, then solving the first few words manually and hoping the text would be excerpt I could google.</p>
<p>And lo and behold, the text was indeed the first 4 sentences of the book <a href="https://app.thestorygraph.com/books/8607788e-b40e-4db5-8ba1-5e7f0691f3ea">&ldquo;The Ones Who Walk Away from Omelas&rdquo;</a>. I entered my answer in the submission box and pressed send.</p>
<p><strong>The answer is incorrect.</strong></p>
<p>I was dumbstruck. How? I was so sure. Everything had been explained, there were no loose threads. I pushed it again, expecting a different result.</p>
<p><strong>The answer is incorrect.</strong></p>
<p>I cleaned up my text by deleting any punctuation.</p>
<p><strong>The answer is incorrect.</strong></p>
<p>Of course! Keleşce does not do capitals, I lowercased the whole text.</p>
<p><strong>The answer is incorrect.</strong></p>
<p>I wasn&rsquo;t going to leave it at that, I got into contact with Alperen, gave my answer and asked if I was missing anything in the puzzle. Turned out that either my submission or Alperen&rsquo;s submission checker had an error that some spaces were left out of the submission. He fixed my entry, and there you go. First, and at the time of writing, only solver of Keleşce.</p>
<p>I had a lot of fun solving this one. As I mentioned previously I think it could have been more long-lasting by opting out of the hints. I&rsquo;m sure it could have been solved then as well. I asked Alperen if Keleşce was idempotent, ie. would the same input result in the exact same output? He confirmed my suspicions that this wasn&rsquo;t the case. The lengths of every line are chosen randomly, the only constant that had to be present was the ratio.</p>
<p>That&rsquo;s okay, it didn&rsquo;t get in the way of solving the puzzle, but I wonder if it could be improved by implementing idempotency. For example, giving every letter a certain base length for one side (and applying the ratio for the other), then whenever the letter repeats in the plaintext, its base length is incremented as well.</p>
<p>But these are really just minor remarks on an otherwise well thought-out puzzle. Great work, Alperen and thanks for the fun!</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Kele%c5%9fce">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>There is no such thing as Clean Code</title><link>https://pensiveibex.com/blog/2024/3/there-is-no-such-thing-as-clean-code/</link><pubDate>Wed, 20 Mar 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/3/there-is-no-such-thing-as-clean-code/</guid><description>
<![CDATA[<p>Bear with me.</p>
<p>I am under the impression that I write Clean Code. You might be too. And you&rsquo;re right. But you&rsquo;re also wrong.</p>
<p>I had a discussion at work the other week about a design decision in our codebase. I&rsquo;ll try to sketch the situation as simply as possible. Basically we have temporal objects called <code>Snapshots</code>. To give an example, imagine a <code>Person</code> that looks something like this:</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-csharp" data-lang="csharp"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Person</span> 
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Guid Id { <span style="color:#66d9ef">get</span>; <span style="color:#66d9ef">set</span>; }    
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">string</span> Name { <span style="color:#66d9ef">get</span>; <span style="color:#66d9ef">set</span>; }
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">string</span> MaritalState { <span style="color:#66d9ef">get</span>; <span style="color:#66d9ef">set</span>; }
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div><p>We know the name of a person, and usually this doesn&rsquo;t change. And even if it does their new name is the new truth. This doesn&rsquo;t need to be kept temporally. However, in the case of <code>MaritalState</code>, we do need the correct info at a certain point in time in order to make calculations in the past. So that&rsquo;s why we have a <code>PersonSnapshot</code> class. It looks something like this:</p>





<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-csharp" data-lang="csharp"><span style="display:flex;"><span><span style="color:#66d9ef">public</span> <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">PersonSnapshot</span>
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> Guid Id { <span style="color:#66d9ef">get</span>; <span style="color:#66d9ef">set</span>; }   
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">string</span> Name { <span style="color:#66d9ef">get</span>; <span style="color:#66d9ef">set</span>; }
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">string</span> MaritalState { <span style="color:#66d9ef">get</span>; <span style="color:#66d9ef">set</span>; }
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> DateTime StartDate { <span style="color:#66d9ef">get</span>; <span style="color:#66d9ef">set</span>; }
</span></span><span style="display:flex;"><span>}</span></span></code></pre></div><p>One <code>Person</code> could be identified as three different <code>PersonSnapshots</code>. Depending on which point in time you need this info, you&rsquo;d need a different snapshot to give the correct info. I&rsquo;ve given a simplified version of this principle, there are a couple more parameters that govern temporal data that I&rsquo;ve left out for brevity&rsquo;s sake.</p>
<p>In order for other developers to use the correct object we&rsquo;ve devised a <code>PersonFactory</code> class. This takes care of all the nitty gritty of how to get the correct <code>PersonSnapshot</code> in time and transforms it into a <code>Person</code> object.</p>
<p>On the other hand there&rsquo;s also a <code>PersonSnapshotRepository</code> class that handles the DB access for getting and saving <code>PersonSnapshots</code>. The whole picture looks something like this:</p>
<pre class="mermaid">classDiagram
    PersonFactory ..> PersonSnapshotRepository : uses
    PersonFactory ..> Person : creates
    PersonSnapshotRepository ..> PersonSnapshot : retrieves
    class PersonFactory{
      +Create()
    }
    class Person{
      +Guid Id
      +string Name
      +string MaritalState
    }
    class PersonSnapshotRepository {
      +GetById()
    }
    class PersonSnapshot{
      +Guid Id
      +string Name
      +string MaritalState
      +DateTime StartDate
    }
</pre>
<p>Any service that needed a <code>Person</code> object should pass through the <code>PersonFactory</code> and retrieve the object through it. However, newer devs recreated the implementation by calling the <code>PersonSnapshotRepository</code> and reimplementing (sometimes with bugs) the same logic as already written in the <code>PersonFactory</code>.</p>
<p>We discussed the reasoning behind it. And it came down to people finding it confusing going through a <em>Factory</em> to <em>fetch data</em>. They didn&rsquo;t want to create a <code>Person</code> object out of thin air, they wanted to <em>fetch</em> it. What fetches data? A <em>Repository</em>. By using  this method they bypass the creation of a <code>Person</code> object and use a <code>PersonSnapshot</code> directly.</p>
<p>One could also make an argument that the role of a Factory concerns the way an object is created. If, in that process, data is required in order to create said object, it does not violate the use of the Design Pattern.</p>
<p>Either way you look at it, the point I&rsquo;m trying to make is that all perception is relative. There are nuances that have merit for both sides of the argument. In my eyes, the design made perfect sense, but to others it didn&rsquo;t.</p>
<p>The <strong>key giveaway</strong> is that Clean Code is not an individual trait in a codebase. It&rsquo;s a pillar that is maintained by every member of the team. If one person has an objection or a misconception about the code, it should be addressed and discussed. What might make sense for me, might be utter gibberish to the next guy.</p>
<p><strong>Be susceptible to critique</strong>. If someone disagrees with you, find common ground and build on it. The code will be better for it, your working relation with your colleagues will be better for it and the willingness to maintain the code will increase.</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to There%20is%20no%20such%20thing%20as%20Clean%20Code">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Unbound Creativity</title><link>https://pensiveibex.com/blog/2024/3/unbound-creativity/</link><pubDate>Mon, 18 Mar 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/3/unbound-creativity/</guid><description>
<![CDATA[<div class="quote">
    <blockquote>
        Be the best, stay small, and don&#39;t lose any money.
    </blockquote>
    <p class="author">
        <strong>-George Lucas</strong>
    </p>
</div>
<p>
<figure>
	
		
	

	
	
	
	
	<a href="https://pensiveibex.com/blog/2024/3/unbound-creativity/the-mysteries-of-monkey-island.jpg" class="lightbox">
		<img src="/blog/2024/3/unbound-creativity/the-mysteries-of-monkey-island_hu_bc91fe27f52a384e.jpg" class="center floatright" loading="lazy" alt="Pirates Ahoy!">
	</a>
	
</figure>
I recently finished reading The Mysteries of Monkey Island by <a href="https://twitter.com/Nicozilla_FR">Nicolas Deneschau</a>. The Monkey Island game series remains with me after all these years. It&rsquo;s one of those games that has earned a cult following over the years, that has baffled the original creators (<a href="https://grumpygamer.com/">Ron Gilbert</a>, <a href="http://www.phrenopolis.com/">Dave Grossman</a> and <a href="https://www.doublefine.com/">Tim Schafer</a>).</p>
<p>In the book Nicolas tries to give some possible explanations why the game is such a staple in many top Adventure Games lists. His final conclusion, which is shared by <a href="https://en.wikipedia.org/wiki/Dominic_Armato">Dominic Armato</a> is that it&rsquo;s the characters that are developed in the game. I hadn&rsquo;t really realized it yet, but that hit the nail on the head.</p>
<p>I see myself in <strong>Guybrush</strong>. He starts off as a doofus with a dream. Becoming a pirate, a simple dream. But his rags to riches story of actually doing it, stumbling through the trials. I&rsquo;ve always been susceptible to <em>&ldquo;zero to hero&rdquo;</em> stories. Although in his case I think we can all agree that he remained a doofus. I still remember all the lines to the <em>&ldquo;How much wood would a woodchuck chuck&rdquo;</em> conversation between Guybrush and the carpenter at the start of MI2.</p>
<p>But what maybe struck me most when reading the book is the freedom that the people in LucasArts were given. At least during the first few years of the company. I, also, firmly believe that if you put passionate people together and you let them do their thing, you will get results. Now mind, it isn&rsquo;t a recipe for success, it&rsquo;s a recipe for getting work done. When not bogged down by administrative tasks<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup> and <strong>trusting</strong>, you will eventually get a return on that investment. A big caveat to this theory is the <strong>passionate</strong> bit. You can&rsquo;t just put random people from the street in a room, ask them to design a car and expect excellent results.</p>
<p>Many startup companies go through this phase. At first, anything goes. You go over to your boss and ask for <em>xyz</em> and &rsquo;lo and behold the very next day <em>xyz</em> has been taken care of. At that stage, <strong>trust</strong> is given almost implicitly. Either management is someone who takes up the job of being a manager on top of their regular job and knows exactly what you&rsquo;re asking for and sees why that&rsquo;s important or how it improves the company. Or they trust you, because they hired you. You&rsquo;ve proven your potential and you get some slack to make requests.</p>
<p>Then, the company starts growing. More people get hired and units start forming. Suddenly, in order to get <em>xyz</em> you no longer go through your boss but you have to make a request to another department. People who don&rsquo;t know you (well) are making the decision. These people might not even know what it&rsquo;s like doing your job. No longer is it a given that you know what you&rsquo;re doing. You now also have to provide a rationale as to why <em>xyz</em> is something you need. There has to be a cost-analysis before any purchase is approved.</p>
<p>I wonder if this change in companies is either due to people no longer working in close spaces together, or if it really is an inherent trait of a startup company that more freedom is given freely.</p>
<p>I <strong>abhor</strong> nepotism. I&rsquo;d much prefer if people were to be judged on merit. But it does seem that nepotism opens doors. And merit, requires work. I can&rsquo;t speak for everyone, but I would like to be remembered one day for what I did, and not for who I&rsquo;ve known.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Like filling in timesheets. I&rsquo;m looking at you, IT industry.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Unbound%20Creativity">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item><item><title>Hello world</title><link>https://pensiveibex.com/blog/2024/3/hello-world/</link><pubDate>Sat, 16 Mar 2024 00:00:00 +0000</pubDate><author>luk@pensiveibex.com (Luk Weyens)</author><guid>https://pensiveibex.com/blog/2024/3/hello-world/</guid><description>
<![CDATA[<h3 id="why-start-this-blog">Why start this blog?</h3>
<p>When the idea was first brought to me, I was a young developer working for a consulting company. We were asked to write blog posts about technical topics. At the time I read blogs by <a href="https://www.hanselman.com/">Scott Hanselmann</a>, <a href="https://haacked.com/">Phil Haack</a> and <a href="https://weblogs.asp.net/scottgu">Scott Guthrie</a> (aka the red shirt guy). Now some of you that are familiar with the .NET environment might know these names, they&rsquo;re big league. The kind of keynote speakers that would attract people to a conference.</p>
<p>Compared to those guys, what did I have to bring to the table? Who would take time out of their day to read about what I did? Moreover, while these guys are discussing design decisions in ASP.NET, the only vaguely interesting thing I had to write about was a bug I solved by crafting a well-composed Google search. Surely any self-respecting developer could do the same?</p>
<p>Years passed and I got to know a certain <a href="https://brainbaking.com/">Brain Baker</a>, he even interviewed me for the company I now am still working for. What started out as a professional relationship quickly evolved into a friendship. One that kept flourishing even after he left the company. One of his tenets was to write. On several occasions he would urge me to start a blog, or start journaling. I still felt the same reluctancy as before, who would want to read what I had to say? But I did start journaling.</p>
<p>Although I didn&rsquo;t keep it up. I&rsquo;ve filled about 3 or 4 notebooks before giving it up. I still journal on occasion, but it has become less train of thought and more regular note-taking. I&rsquo;m moving house soon, and had to pack up old stuff, including my notebooks. Before packing it up, I flicked through the pages, and I liked that. A lot. Revisiting old ideas, seeing what I was thinking at the time, how I&rsquo;ve grown since. It&rsquo;s a static collection of dreams, ideas, thoughts, drawings and memories that brought a smile to my face.</p>
<p>That triggered me to rethink the idea of creating a blog. Of writing <strong>publicly</strong>. Over the years, I&rsquo;ve come to realize that people started to trust my judgement. Some even look up to me. I&rsquo;m not the snot-nosed kid anymore that I was. I&rsquo;ve developed an instinct, an intuition for programming that only develops by years of repetition and learning from past mistakes.</p>
<p>Things haven&rsquo;t only changed on a professional level, but on a personal level too. I used to have few friends, again by a certain conviction that I didn&rsquo;t really have anything interesting to say, having such niche interests. But now I&rsquo;m happy to be surrounded by good friends who care as much for me, as I do for them. It might seem commonplace, but to be entrusted with someone else&rsquo;s troubles and to be able to provide advice is something very precious. It gives a sense of <strong>self-worth</strong>.</p>
<p>So that&rsquo;s why I&rsquo;m writing now, publicly. Because I do believe I have something interesting to say. It might not always pique your interest, but it might pique someone&rsquo;s interest. It gives me a place to capture and collect my thoughts, so I might revisit them in the future.</p>

        <p>
          <em>
            <a href="mailto:luk@pensiveibex.com?subject=Reply to Hello%20world">Reply to this post by email</a><br />
            Did you spot a mistake? You can help me fix it by opening a <a href="https://github.com/WeyensLuk/pensive-ibex" target="_blank">Pull Request</a>.
          </em>
        </p>
        ]]></description></item></channel></rss>