<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[CodeChem Blog]]></title><description><![CDATA[Diligent coding, creative thinking, transparent working. We’ve mastered the custom software development.]]></description><link>https://blog.codechem.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1630681313575/4VrLlp_3N.png</url><title>CodeChem Blog</title><link>https://blog.codechem.com</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 16 May 2026 21:06:26 GMT</lastBuildDate><atom:link href="https://blog.codechem.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Reading matters...]]></title><description><![CDATA[Reading matters, now more than ever before. As I have expressed this exact opinion with a couple of mates lately, we don't live in the era of information, we live in the era of noise. We lie to oursel]]></description><link>https://blog.codechem.com/reading-matters</link><guid isPermaLink="true">https://blog.codechem.com/reading-matters</guid><category><![CDATA[debugging]]></category><category><![CDATA[AI in programming]]></category><category><![CDATA[Developer Workflow]]></category><category><![CDATA[nextjs middleware]]></category><dc:creator><![CDATA[Vasilaki Totsili]]></dc:creator><pubDate>Thu, 26 Mar 2026 11:36:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/9f5abc62-20dc-465f-8d46-450146f4a536.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Reading matters</strong>, now more than ever before. As I have expressed this exact opinion with a couple of mates lately, <strong>we don't live in the era of information, we live in the era of noise</strong>. We lie to ourselves that the needed information is in front of our eyes daily, because there <strong>IS</strong> a lot of information, <em>more than any king before had in his entire life</em>, but fundamentaly, most of that information is not at all important, it is in fact misleading you in the wrong direction or in the worst case lying and shaping your mindset wrongfully.</p>
<p>Now, yes, you can find the needed information and knowledge on the internet, but more in form of <strong>books, articles, documentation, forums, comment sections, and direct messages</strong> with knowledgeable people, all having one thing in common-<strong>reading</strong>. <em>(Podcasts and videos can also be helpful, but for sustained long-term knowledge, I think that reading and spending time on the topic is king)</em> Still, you have to be very selective and filter on what you read, but that comes with experience, which is essentially just <strong>patience</strong>, one of the things our generation is missing the most.</p>
<p><strong>I am going to share a story on how reading saved me precious time.</strong></p>
<p>Currently, I am building a web app for personal finance management-<strong>FEiN(</strong><a href="https://fein.finance/"><strong>https://fein.finance/</strong></a><strong>)</strong>, tailored to my needs. Doing the management in Google Sheets, I saw that it comes with challenges, one of them being that the whole system is dependent on strings, and if the format of the strings is missed, there will be errors and data missing, so I decided to make a UX-friendly app that will minimize my mistakes and please my love for unique design.</p>
<p>Consequently, I started <strong>upskilling myself</strong> by renewing my knowledge of NextJS.</p>
<p>I have previously used older versions of it to build apps (<a href="https://python.mk/">https://python.mk/</a>, <a href="https://summer23.best.org.mk/">https://summer23.best.org.mk/</a>), which used the Pages Router. I wanted to learn the "new" App Router, so I completed the NextJS' Foundations course on App Router, ending up with a <a href="https://nextjs.org/learn/certificate?course=dashboard-app&amp;user=127057&amp;certId=dashboard-app-127057-1768949362573">certificate</a> and a scaffolding for a financial app. Upon starting the course, I needed to generate the template using the <strong>CLI command</strong>:</p>
<pre><code class="language-bash">npx create-next-app@latest nextjs-dashboard --example "https://github.com/vercel/next-learn/tree/main/dashboard/starter-example" --use-pnpm
</code></pre>
<p>and this is an <strong>important step</strong>, will get to it later on why. (hint: <code>@latest</code>)</p>
<p>I did this before the <strong>infamous CVEs</strong> that React and Next had, so when they got vocal I did what everyone else did, <strong>changed the version of the Next</strong> to an <strong>explicit one</strong> that <strong>had the CVEs fixed</strong> and continued developing it.</p>
<p>I had already made a Figma design prototype for the app and started implementing it in my app after the course ended. The first things served on my menu were accounts, authentication, and security, and I implemented them with great care, paying attention to every minutia.</p>
<p>I am <strong>keen on</strong> writing <strong>organic code</strong>, but am not opposed to getting your code from AI if you go over it thoroughly, rigorously, and exhaustively, and <strong>understand it deeply</strong>, so you <strong>can modify it and maintain it in the future</strong>, as an essential rule of software engineering. So, less vibe in vibe coding, and more <strong>scrupulousness</strong>(<em>doing things right because it is right</em>) and <strong>punctiliousness</strong>(<em>implying an extreme/rigid focus on the smallest details</em>).</p>
<p>Turned to AI for one of the things I didn't know how to do, <strong>authentication middleware</strong> or <strong>authorization logic</strong> that runs checks on user sessions or tokens before allowing access to certain routes. This ensures a seamless user experience by not requiring a user to log in again or view the login form when they already have an active, valid session.</p>
<p>It did its job, giving me an extension to my middleware file(<code>proxy.ts</code>)-matching what to redirect to <code>/dashboard</code> route if the user is logged in and requests <code>/login</code> or <code>/register</code> route, also hardening other non-authenticating routes the same way.</p>
<p>But, it didn't work...</p>
<p>I rechecked it twice: to see if something was wrong in the code or if I had other files overwriting this one, as such a bug can materialize, but it wasn't that. And the AI of my choice kept repeating the same code when asked to fix it because it wasn't working...</p>
<p>Thereupon, I <strong>fell back</strong> to what I do when something is not working-digging deep for every single detail about it by either <strong>reading documentation, forums, or articles</strong> about it, <strong>not skipping a single word</strong>.</p>
<p>I opened the documentation for NextJS and was met with the UI on left that had two drop-down menus: one for usage of App Router/Pages Router and the other one for the version of NextJS, put it in my brain's RAM and proceeded to search the documentation for "middleware", pressed enter and was redirected to the documentation's page for "Proxy", exactly what I had, right?</p>
<p>I read it whole, I saw that the AI gave me the correct file and content, but came back to the very top that said:</p>
<blockquote>
<p><strong>Good to know</strong>: Starting with Next.js 16, Middleware is now called Proxy to better reflect its purpose. The functionality remains the same.</p>
</blockquote>
<p>I immediately thought back to the explicitly changed version of the scaffolding because of the CVEs and remembered that I don't use the <code>@latest</code> one(<em>v16.1.6</em>) anymore, but rather a slightly older one, <em>v15.5.9</em>.</p>
<p>Then I switched the version of the documentation to <em>v15</em> and again wrote "middleware" in the search, pressed enter, and there it was, the file name called <code>middleware.ts</code> instead of <code>proxy.ts</code>. Then I went to the <em>v16</em> documentation and searched for <code>proxy.ts</code>, and on my screen popped this note:</p>
<blockquote>
<p><strong>Note</strong>: The <code>middleware</code> file convention is deprecated and has been renamed to <code>proxy</code>. See Migration to Proxy for more details.</p>
</blockquote>
<p>Rushed to my IDE, renamed <code>proxy.ts</code> to <code>middleware.ts</code> without changing the content and...</p>
<p>It worked!</p>
<p>I thought to myself that this is a big win for me, having solved this thing so fast instead of falling into debugging hell, and credited my reading skills, instead of using AI or trying a hundred things in practice, for the quickness of the fix.</p>
<p>I was unsure whether to write such a blog post since I am an embedded software engineer; this is not my expertise, and the audience would be waaay more experienced in these technologies.</p>
<p>Doubted if this would seem like a small thing to you, but then I asked colleagues who work on the web daily, and they said it's totally a scenario of their daily work. That gave me enthusiasm to do it, so thanks to Teo, you are <strong>reading</strong> this, and that <strong>matters</strong>...</p>
]]></content:encoded></item><item><title><![CDATA[What's Behind All Those Masks? ]]></title><description><![CDATA[Since we traditionally gather and take part in Game Jams, skipping this year was never really on the table, especially now that we have our own game division, Isotope Games. So one year later, we show]]></description><link>https://blog.codechem.com/what-s-behind-all-those-masks-game-jam</link><guid isPermaLink="true">https://blog.codechem.com/what-s-behind-all-those-masks-game-jam</guid><category><![CDATA[Game Jam]]></category><category><![CDATA[gaming industry]]></category><category><![CDATA[Game Development]]></category><dc:creator><![CDATA[Jasna Mishevska]]></dc:creator><pubDate>Thu, 26 Feb 2026 08:57:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/862cb1c6-9c7a-4c54-b7fc-62fb7d5d510b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Since we traditionally gather and take part in Game Jams, skipping this year was never really on the table, especially now that we have our own game division, Isotope Games. So one year later, we showed up again at Global Game Jam with more teams and bigger expectations.</p>
<p>The jam started on January 30th and ran for 48 hours straight. That is two days of building from scratch, running on coffee, stubbornness, and real willpower. The kind of weekend where we run mainly on coffee, and every quick fix slowly becomes a two-hour setback. There were noticeably more participants this time, but Base42 came prepared. The space was bigger, the setup was better, and the overall atmosphere felt more focused. People were obviously not there to kill time. Most teams got straight to work and stayed locked in.</p>
<p>As you can probably guess from the title, this year's theme was "masks." Compared to last year's "bubbles," it felt heavier and more layered, pushing everyone to think twice before jumping into their first idea. Once the brainstorming started rolling, though, it was full steam ahead. MGI's posts also made it clear that this year's Global Game Jam was massive. One of the biggest in the world, with an absurd number of prototypes made in just 48 hours.</p>
<h2>Masquerade Exorcist - Vasilaki Totsili</h2>
<p><strong>Maybe</strong> the boldest move this year came from going solo.</p>
<p>Vasilaki, our embedded software engineer, switched to solo mode and built a game called  <a href="https://globalgamejam.org/games/2026/masquerade-exorcist-7">Masquerade Exorcist.</a> At one point, he worked nearly 18 hours straight without stopping, fully immersed in development.</p>
<p>Masquerade Exorcist drops you into a cursed mannequin masquerade where demons blend in, and one wrong move ends the run. Using a rapid-fire MaskBow, you must read micro-twitch tells, correctly tag enemies, and avoid killing innocents before they hit the stage. Miss a demon or grief an ally, and the screen bleeds to black: game over, show's dead.</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/278f415d-b83e-4fc9-b9f3-cfffb0043efb.png" alt="" style="display:block;margin:0 auto" />

<p>Check out the game:</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/98dda656-8134-4c15-b806-b83afae55059.png" alt="" style="display:block;margin:0 auto" />

<p>Over the 48 hours, the game was built almost entirely in Unreal Engine C++. Vasilaki handled everything: enemy logic, combat mechanics, level events, audiovisual feedback, difficulty balancing, and a final cinematic, delivering a polished game by Sunday.</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/69b0a839-8c1d-49f4-b2cc-cb16c0131ad1.jpg" alt="" style="display:block;margin:0 auto" />

<h2>Best Game at the Global Game Jam 2026 - Tomislav Ingjatov &amp; CBT</h2>
<p><strong>Across</strong> the space, another team was building something much louder.</p>
<p>Tomislav Ignjatov and his team CBT, consisting of three developers, two artists, and one game designer, won Best Game at Global Game Jam 2026 in Skopje with S.A.M. Spirit, Animal, Machine. Built completely during the jam, the game stood out for its tight combat design, clear mechanics, and multiplayer execution. The award came with a 300-euro prize, enough for one proper kafana night for the whole team.</p>
<p>Some pics from the winning team:</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/c1e692c9-dcbb-4df5-b8b8-44d8e8abef84.jpg" alt="" style="display:block;margin:0 auto" />

<p>Another one with the prize and the art itself:</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/98abe337-22d6-4acc-bfa5-6f7285df87ea.jpg" alt="" style="display:block;margin:0 auto" />

<p>S.A.M. is a server-based online arena battler for Windows and macOS where masks define your abilities. Players choose between Animal, Spirit, and Machine masks, each following a rock-paper-scissors logic. Animals counter Spirits, Spirits counter Machines, and Machines counter Animals. Combat revolves around throwing your mask to strip or damage opponents, creating fast-paced matches that reward timing and positioning.</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/d57721c3-9967-4acf-953a-7d22b15a18e5.jpg" alt="" style="display:block;margin:0 auto" />

<p>Developed in Godot, with assets created in Aseprite and Blender, the game delivers short but competitive sessions built around skill and smart decision-making. You can learn more and play the game here: <a href="https://lorddeathunter.itch.io/sam"><strong>https://lorddeathunter.itch.io/sam</strong></a></p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/99e69ff5-0bc9-45ad-afb4-3e0623ae8ebc.jpg" alt="" style="display:block;margin:0 auto" />

<h2><strong>Rising Star Award to our team Lab Rats</strong></h2>
<p><strong>Some</strong> teams were stepping into their first Game Jam, while others treated it like a tradition.<br />Dimitrij Krstev, Teodor Angeleski, and Aleksandar Filipovski from Team Lab Rats won the Rising Star Award at Global Game Jam 2026.</p>
<p>More pics, screenshots and details follow:</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/4e5deb6d-bc54-4267-b116-8797c5520377.jpg" alt="" style="display:block;margin:0 auto" />

<p>For everyone except Teodor, this was their first game jam, making the recognition an important milestone for the team. They built their game Masked Descent using Godot and Aseprite, learning and solving technical challenges live during the event.</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/2785f2bb-7ea5-4f7f-8e17-9616b2308275.png" alt="" style="display:block;margin:0 auto" />

<p><em>Masked Descent</em> is a roguelike dungeon crawler featuring procedurally generated levels and a mask-swapping combat system, melee combos, ranged attacks, and stealth-based mobility. Boss fights appear every five floors, with powerups shaping each run and encouraging different playstyles. The game blends fast decision-making with classic dungeon progression and pixel-art visuals.</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/89ae509a-9be3-4a3b-81f8-60df7205196f.png" alt="" style="display:block;margin:0 auto" />

<h2>Gjorgji Dimeski - Multiple Projects, Won Audience's Hearts</h2>
<p>Gjorgji Dimeski participated in Global Game Jam 2026 with two projects.</p>
<p>His solo project, <a href="https://bits.dimeski.net/">Bits</a>, or "Wordle for Hackers," was built in just three hours using SvelteKit with Discord integration. It's a logic puzzle based on binary operations, where players manipulate inputs to match the Goal Pattern shown at the bottom.</p>
<p>The game is available here:<br /><a href="https://bits.dimeski.net/">https://bits.dimeski.net/</a></p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/ac12e6f1-a9eb-4109-a3db-d8f95fc3f643.png" alt="" style="display:block;margin:0 auto" />

<p>The game has been gaining popularity among tech enthusiasts, and many are playing it on Discord. Gjorgji continues to improve the game and regularly shares updates and new iterations on his LinkedIn.</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/b12942e9-8f12-41c1-a1c9-cf6730a89208.jpg" alt="" style="display:block;margin:0 auto" />

<h2>MikroShpajz - Gjorgji Dimeski again with the team</h2>
<p>At the same time, he collaborated with the team Mikro Shpajz (7 members) on “Maskakar,” developed in Godot. You can see the game here:<br /><a href="https://www.youtube.com/watch?v=ZzRXUK2YT-4">https://www.youtube.com/watch?v=ZzRXUK2YT-4</a></p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/fe297a10-31aa-4111-b232-0e651cee42c9.png" alt="" style="display:block;margin:0 auto" />

<p>Once again, Gjorgji won the audience's hearts, as he has consistently done. This marks his fourth consecutive year participating in Global Game Jam.</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/2879401d-721b-41ca-8caa-2f2012adc1c8.png" alt="" style="display:block;margin:0 auto" />

<h2>Team Elon Mask,  Not That Elon!</h2>
<h3>Pixel Perfect for Best Art</h3>
<p>No, not that Elon. Just Elon Mask, and honestly, the name already sets expectations.</p>
<p>Andrej Slavejkov, Andrej Mickov, Nikola Dinevski, Martin Dinev, Ilija Boshkov, all software engineers from CodeChem, featuring Goran Petrushevski, an embedded software engineer also from CodeChem, and their team member Gagi (Viktor), teamed up under this slightly suspiciously familiar name and built Mask of Life using Unity, while Gagi handled the art on a tablet. Six developers coding, one artist carrying, and they won Pixel Perfect for Best Art. They openly admitted it: the award wasn’t just about the programmers.</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/2ddd2312-9603-484a-8c43-961da5727ab2.png" alt="" style="display:block;margin:0 auto" />

<p>They went all in. Full 48-hour focus (realistically 30 effective hours, but who's counting). Everyone treated it like work, not just a jam.</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/740e848a-43e2-45d1-ab00-174951e2135a.png" alt="" style="display:block;margin:0 auto" />

<p>Mask of Life is a 2D storytelling platformer set in a shattered monochrome world. You play as the Colorless One, restoring color and meaning by collecting powerful masks. The more masks you reclaim, the more the world comes alive. Clean mechanics, strong atmosphere, and apparently, some great music, as multiple people pointed out.</p>
<p>Play it here: <a href="https://maskoflife.codechem.dev/">https://maskoflife.codechem.dev/</a></p>
<p>Gameplay: <a href="https://www.youtube.com/watch?v=kxePk7Rc6GQ">https://www.youtube.com/watch?v=kxePk7Rc6GQ</a></p>
<p>Soundtrack highlight: <a href="https://www.youtube.com/watch?v=jWYrm_XZSOM">https://www.youtube.com/watch?v=jWYrm_XZSOM</a></p>
<p>Now some visuals, which are ridiculously good, considering the fact that they were drawn on a tablet in what looks like a paint app:</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/89159aa5-9f78-4092-893d-94caba53d6a1.png" alt="" style="display:block;margin:0 auto" />

<p>Also included: A snapshot from the jam, when a colleague from CBT went to see what the team Elon Musk was building, or the other way around...</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/7faeb59d-1a9b-4cd8-87a1-1c2d3d71ad5e.jpg" alt="" style="display:block;margin:0 auto" />

<h2><strong>Sarmakedonci – Isotope Games</strong></h2>
<p>They didn't just participate in the Global Game Jam, but also sponsored it. In a gaming industry like ours, that kind of support genuinely means everything, and so does it to Isotope Games.</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/25739f23-db7a-4c0c-8785-46f5e68317e2.jpg" alt="" style="display:block;margin:0 auto" />

<p>The name Sarmakedonci wasn't random. It comes from the main character of their game, <a href="https://onelink.to/downloadastralmatch">Astral Match</a>, so the team name was actually very on-brand.</p>
<p>Matej, Martin, Filip, Manuel, Boris, Ekaterina, and Nikola created a rhythm-based theatre game built around masks and emotions. You perform on stage, matching masks to target emotions, keeping musical notes in tune, and managing the audience's happiness. If the crowd turns on you, tomatoes start flying, and you get one last chaotic mini game to save the show.</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/913bb4f1-cb12-4f24-9b74-8535d8b6a2cf.jpg" alt="" style="display:block;margin:0 auto" />

<p>It's hypercasual, fun, and one of the most conceptual and finished games at the jam. Everything was built during the event in Unity, with all visuals originally drawn by Nikola and animations handled by Martin Stoilov.</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/8274631f-46a9-4040-830c-c2308e45568e.jpg" alt="" style="display:block;margin:0 auto" />

<p>Compared to last year, this one simply felt more complete and more enjoyable.</p>
<h2>Stefan Ivanovski, part of The Unfortunate 7" - Dalewood's Masquerade</h2>
<h3>Epic Coding Award  🏆</h3>
<p>We were called “The Unfortunate 7.” There were six of us. We don't talk about the seventh.</p>
<p>We built a VR horror-puzzle game for the Meta Quest 3 using Unity and C#. The 3D modelling was done in Blender and Maya, music production with FL Studio, and UI/story mockups with Figma. You play as an invited guest to a masquerade party, and quickly find out that not all is as it seems. The goal is to escape this cursed mansion with powers gained through pieces of a cursed mask.</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/25028919-de7d-4957-970e-6c2ccb33de29.jpg" alt="" style="display:block;margin:0 auto" />

<p>It was our first time working together, but we clicked fast. Strong 3D work, quick iteration, solid level design, and original music came together naturally. As a programmer, it’s always impressive to see the unbounded creativity of artists and how they turn rough ideas into something fun, quickly.</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/55b4bdc5-f1dc-46ca-a0ea-48fc12ac07d1.jpg" alt="" style="display:block;margin:0 auto" />

<p>The vibe at the Skopje Game Jam was great as always. The organization was amazing, we had constant support, and developed our game in a welcoming atmosphere.  It was especially nice to see more kid and teen teams this year.</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/d50b27d6-63c5-4816-b7a9-f157728eb644.jpg" alt="" style="display:block;margin:0 auto" />

<p>We started Friday night, pushed through Saturday, and finished Sunday at the ceremony. I had to sit out the final day because I was sick, but I had full faith in the team to carry it through.</p>
<img src="https://cdn.hashnode.com/uploads/covers/63c138c72d657e1f29d7dcf8/59cfbe69-d4f1-409f-aa79-d813095473cb.jpg" alt="" style="display:block;margin:0 auto" />

<h2><strong>Final Thoughts</strong></h2>
<p>Forty-eight hours is short until you try building a game inside it. This year felt bigger and more serious, with more teams, more young participants. <strong>Knowing</strong> that everything you see was built from scratch in those two days changes how you look at these games.</p>
<p>The theme was “Masks,” but by Sunday night, nobody was hiding much. You could see the lack of sleep, the stress before submission, the relief when something finally worked. Across all the games, there was real effort. Different engines, different styles, different ideas, but everything was built from scratch in those two days.</p>
<p>Some teams took home awards, some won the audience, and some simply proved they could finish, but that counts too. We say every year that next time we will rest more.</p>
<p>We won't!</p>
<p>See you at the next jam.</p>
]]></content:encoded></item><item><title><![CDATA[Why I Made Jack (of All Trades)]]></title><description><![CDATA[We all do it. Maybe you just started using curl instead of those GUI HTTP clients like Postman or Insomnia, and you had to copy the response body and paste it into a browser-based JSON formatter to ma]]></description><link>https://blog.codechem.com/why-i-made-jack-of-all-trades</link><guid isPermaLink="true">https://blog.codechem.com/why-i-made-jack-of-all-trades</guid><dc:creator><![CDATA[Gjorgji Dimeski]]></dc:creator><pubDate>Mon, 26 Jan 2026 13:34:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769434351752/721c1ce3-2d48-4357-80f9-0a3acf35773a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We all do it. Maybe you <em>just</em> started using curl instead of those GUI HTTP clients like Postman or Insomnia, and you had to copy the response body and paste it into a browser-based JSON formatter to make sense of it. Perhaps you wanted to inspect a JWT, so you go to jwt.io, and although the site says it doesn’t transmit tokens, pasting credentials into any webpage is a habit worth avoiding. Or you needed some IDs for those tests, so you googled “UUID generator“. Maybe you also wanted to generate a QR code - same story. Not to mention the ads you usually see on the websites.</p>
<p>Of course, there are various solutions for this - right in your terminal:</p>
<ul>
<li><p><code>jq</code> for JSON formatting and processing</p>
</li>
<li><p><code>qrencode</code> for generating QR codes</p>
</li>
<li><p><code>uuidgen</code>(Unix) and <code>New-Guid</code> (Windows) for all your UUID needs</p>
</li>
</ul>
<p>And you can always just google what you need and use some web app instead. I did that too, who am I to judge? But this is all too fractured and inconsistent.</p>
<p>I personally use some of these tools myself. And I’ve noticed a common trend among my colleagues: many default to web-based tools, even though terminal apps are often faster and easier once you get the hang of them. I sometimes recommend some specific CLI tool, but it rarely sticks. And with CLI tools there’s also the issue of compatibility across platforms, you can use one tool on your Linux system, but when you switch to Windows you need to suppress that muscle memory and write another command in PowerShell instead. It’s just too frustrating and fragmented.</p>
<p>Wouldn’t it just be easier to have a single tool, that you could install once on your system, would work across different platforms? No need to remember and install different tools, or search for alternatives for your Windows machine. Imagine it all centralized: <code>jack json</code>, <code>jack qr</code>, <code>jack uuid generate</code>, <code>jack jwt</code> - all just working, in a single package, across platforms.</p>
<p>That’s why I decided to make a sort of Swiss Army Knife tool for developers that’s portable and accessible. Initially, I actually named it factotum - a word for a general handyman. Then, my friend <a href="https://hashnode.com/@ndinevski" class="user-mention" data-type="mention" title="Nikola Dinevski">Nikola Dinevski</a> came over and suggested <strong>jack</strong> - as in, jack of all trades. I thought that it was perfect! It’s exactly what it is, a multi-tool for all trades - but a master of none. What’s often omitted from that saying though, is that it’s oftentimes better than a master of one! Besides, jack is a pretty memorable name and easy to type in your terminal.</p>
<p>Jack removes the friction from remembering all those different tools, you just type in <code>jack</code> and find the tool you need, on all your systems! No need to install multiple tools, or lookup something online. It’s easy and intuitive to use, with no fancy and complicated options that you may find in more specific tools which, let’s be honest, you’ll only ever need a fraction of the time. It’s composable, simple, and helps with most of your day-to-day tools needs.</p>
<p>The intention is not to replace all the other tools I mentioned, of course they’ll have their use-cases. I don’t expect jack to have feature parity with dedicated tools. No, the aim is to have jack as the easy default tool you go to when you need something so you don’t have to juggle multiple tools.</p>
<p>Jack is made with Kotlin. <em>Why?</em> Because I want to be unique! No, but really - I wanted to try out the language for something else than backend services. It’s cross-platform, and is overall very nice to work with. Additionally, I had recently read about <a href="https://ajalt.github.io/clikt/">clikt</a>, a CLI library for Kotlin, and I wanted to take it for a spin.</p>
<p>I’d love for you to contribute! If you have a feature in mind you can always submit a PR or open an issue if you want me to put it on the to-do list. You can find the repository at <a href="https://github.com/dimeskigj/jack-cli">https://github.com/dimeskigj/jack-cli</a>.</p>
<p>Jack has a lot more features, and you can try them out for yourself!</p>
<p>On Linux/MacOS, you can install jack with:</p>
<pre><code class="language-bash">curl -fsSL https://raw.githubusercontent.com/dimeskigj/jack-cli/main/scripts/install.sh | bash
</code></pre>
<p>If you’re on Windows, use PowerShell instead:</p>
<pre><code class="language-powershell">iwr https://raw.githubusercontent.com/dimeskigj/jack-cli/main/scripts/install.ps1 -useb | iex
</code></pre>
<p>Let me know what you think! I would be glad if you find jack useful.</p>
]]></content:encoded></item><item><title><![CDATA[Memory Specialists & Retrospective Experts]]></title><description><![CDATA[The Theory of Everything
While science accurately argues that humans are among the most complex forms in the universe, given that the universe and its vast system are even more complex, we tend to find joy in very simple things. The human brain conta...]]></description><link>https://blog.codechem.com/memory-specialists-and-retrospective-experts</link><guid isPermaLink="true">https://blog.codechem.com/memory-specialists-and-retrospective-experts</guid><category><![CDATA[teambuilding]]></category><category><![CDATA[team building activities]]></category><category><![CDATA[Retrospective]]></category><dc:creator><![CDATA[Jasna Mishevska]]></dc:creator><pubDate>Tue, 09 Dec 2025 15:18:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1765293478827/ce1491e7-99bd-45ca-b793-f9b209631715.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-the-theory-of-everything"><strong>The Theory of Everything</strong></h2>
<p>While science accurately argues that humans are among the most complex forms in the universe, given that the universe and its vast system are even more complex, we tend to find joy in very simple things. The human brain contains more than <a target="_blank" href="https://theconversation.com/the-brain-is-the-most-complicated-object-in-the-universe-this-is-the-story-of-scientists-quest-to-decode-it-and-read-peoples-minds-222458#:~:text=It%20contains%20more%20than%2089%20billion%20neurons%2C%20each%20connected%20to%20around%207%2C000%20other%20neurons%20that%20send%20between%20ten%20and%20100%20signals%20every%20second.">89 billion neurons</a>, each connected to around 7,000 other neurons, sending between 10 and 100 signals every second. Yet, we humans are mostly stuck, searching for the meaning of everything. So all those signals might be tangled somewhere along the way. 🙃</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764923576339/0b338394-479f-442a-a700-2e9592a755b5.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-interstellar"><strong>Interstellar</strong></h2>
<p>The meaning of everything, and life in general, is not something that we'll answer here, but the thought does visit us often. Maybe the best thing in life is waiting. The anticipation behind it, the quiet hope it carries, and the time leading up to this blog post being written might be an example of that.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764929526091/ca978f82-1d3e-4734-9c58-e34798a7baad.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-pursuit-of-happyness"><strong>The Pursuit of Happyness</strong></h2>
<p>You experience different feelings and situations with the people you spend most of your time with. Family is one part of it, but another grows quietly at work. It's often the people with whom you share your routines, the morning coffee, the balcony talk, the wins, the frustrations, the silent glances that say <em>I know something’s wrong with you</em>, and the moments of laughter that make your long days a bit lighter.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764923599614/012a0e8e-e3fc-4858-b7e1-0ae6fa036954.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-usual-suspects"><strong>The Usual Suspects</strong></h2>
<p>Now look around…yup, those are the people you spend most of your waking hours with. The ones who’ve seen you celebrate a bug fix like it's a world record, survive another sprint, and stare at your screen in quiet confusion before the third coffee kicks in, wondering how something that worked yesterday suddenly doesn't today. They've heard your “just one more thing to finish” speech more times than you'd like to admit, and they’re probably the reason you laugh at least once a day, even when a deadline refuses to play nice.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764924571922/fecaaef1-d4a1-44a7-8bf8-8312ba710173.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-about-time"><strong>About Time</strong></h2>
<p>After 9 months of calls, commits, and quick lunch breaks this year that never lasted long enough, it was time to hit pause. We decided to replace Discord messages for honest conversations and code reviews with something else, and that’s how our team building began.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764924016960/0c3052dc-ef57-43c4-aebf-d6707e5e1df7.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-cloudy-with-a-chance-of-meatballs"><strong>Cloudy With a Chance of Meatballs</strong></h2>
<p>Skopje sat under heavy clouds that morning. Two buses stood outside our office, surrounded by suitcases, backpacks, and people still negotiating with their eyelids to stay open. 😴 For a moment, it looked like a big group heading off on a vacation. In a way, we were not to rest, but to reconnect. It marked the start of our team building.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764928648747/faac1561-75c3-4fc1-be58-7b8bdc6e0d2e.jpeg" alt class="image--center mx-auto" /></p>
<p>These are the moments to remind us to slow down, listen, <strong>care</strong> more, <strong>share</strong> a little deeper, and to <strong>dare</strong> a little more too, because somewhere between the bus ride and the beach, we kept coming back to those values. They were the quiet thread running through everything.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764924038930/e367ad88-0b29-4673-8946-19f0da00af56.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-road"><strong>The Road</strong></h2>
<p>This year, our team had doubled, but “surprisingly,” somehow our chaos hadn’t. 😆 There were fewer forgotten passports, fewer “wait, did I take my charger?” moments, and everything moved smoothly than expected. We were headed to Olympic Beach in Greece, and despite the terribly cloudy weather, it seemed nothing could get in our way!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764924482190/4bbe18fb-94f9-4828-89df-6719d91cb1ed.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-grand-budapest-hotel"><strong>The Grand Budapest Hotel</strong></h2>
<p>The three-hour trip went by in a blink of an eye because there were games like <em>Guess the Song</em> and <em>Two Truths and a Lie</em>, along with some casual music, all accompanied by Nikolaj's dancing like he was warming up for a world tour. No one complained, as we couldn't, it was too funny.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764929589662/da8c1c54-5881-490a-9eb0-4e10f60bd927.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-arrival"><strong>The Arrival</strong></h2>
<p>Once you enter Greece, the first thing your eyes land on is the sea. It stretches out like it owns the whole horizon. When we arrived, we checked into the hotel and instantly switched into our special mode. We inspected everything: the dining area, the pool, the rooms… even the most minor details that normal people would never bother with.😆🙈</p>
<p>After the official opening, where Costa (Zelenskyy's doppelganger) said a few words, and the Simbiotika crew handed out the bracelets, that’s where our team building officially began, with us going straight to the beach.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764924536196/540f9b7e-280c-4293-b833-2d0570fecf5d.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764924500981/fce221d7-2a3b-4eda-9ea0-65cc7d6d032f.jpeg" alt class="image--center mx-auto" /></p>
<p>You’ll probably ask why Zelenskyy, well, check this out:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764928743224/61fcf756-077e-435f-a8a1-2b4adf8f70e5.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-opening-act"><strong>The Opening Act</strong></h2>
<p>Not sure who thought of the name, but it completely resonates with us, so congrats, you did it once again… now let's go through the festival activities!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764928823798/5b59e3d0-f829-4e81-861c-97445e6fccb8.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-lord-of-the-rings-the-two-towers"><strong>The Lord of the Rings: The Two Towers</strong></h2>
<p>We were divided into teams, and our task was to build sandcastles using specific elements and following the rules <strong>Simbiotika</strong> gave us. For instance, some of the castles should have included gates, decorations, bridges, and so on. It was great to see how the teams are divided, how competitive everyone is (not that we don't know this), and how we understood the assignment from our team leads by getting specific roles.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764928945646/156a549f-ac6b-42fe-aa89-7c2064f9c8a3.jpeg" alt class="image--center mx-auto" /></p>
<p>The end of the game was great, seeing all those medieval castles made from sand, a few sticks, stones, and other materials that looked like they were built straight from <a target="_blank" href="https://blog.nationalmuseum.ch/en/2024/12/a-visionary-of-medieval-architecture-james-of-st-george/">James of Saint George</a>. The first three, including the winning team, really stood out. Their castles seemed so impressive, you'd think they were hiding an architect somewhere. 👀 The second thing that stood out was the names of the teams: Komunalci, Barbie and Ken, The Pyrates from Gevgelija, A Yellow Van, Loto 7, and so on…</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764928981014/e95981e4-f51f-4ea3-9a0d-2dc15901c48e.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764929012332/51f74aea-a56f-4bcd-8930-132fd322d787.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-pirates-of-the-caribbean"><strong>Pirates of the Caribbean</strong></h2>
<p>As the day faded and the night stepped in, it continued with a pirate party at the bar near the swimming pool. Everyone was supposed to dress like a pirate, and we had some pirate games, some sips here and there, and a lot of fun. To be honest, there were some pretty awesome costumes! Not sure how, but <em>"rrrrrrrrrr!"</em> came out as a pirate voice from the night, and it stayed longer than expected! Once again, all participants in these games were very competitive!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764929036340/84b9fb03-1c6d-4fcf-91ed-2b7b2fb9a32e.jpeg" alt class="image--center mx-auto" /></p>
<p>When the pirate things ended, the music kept playing, and the dance floor got really crowded. As usual, the bar closed, and the party continued at the beach under the wide, dark sky.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764929082239/35631f50-6a06-4f60-92ba-45250b17ac8c.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-edge-of-tomorrow"><strong>Edge of Tomorrow</strong></h2>
<p>The second day of our team building started right after the tasty breakfast we had at the hotel. We are still trying to figure out if the food was actually that good or if we were just very hungry. After that, the games began, and the whole afternoon was busy from the start.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764929210666/a862de4a-7acb-4fbd-8c0f-d8485bb7ba08.jpeg" alt class="image--center mx-auto" /></p>
<p>The first game was connected to memory and running, which is a cruel combination before the coffee fully kicks in. Again, we really nailed the team names, like “Kravari”, “Perfex”, “Mamurni”, and so on. Only we would choose names that sound like they came from a late-night group chat.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764930042232/afa367ed-d9c3-4a09-b691-995fb5189ff1.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764930471435/ae5ed73f-8b20-469c-96c2-c68a48a53dbb.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764930523254/1c8630f6-f56b-4e2c-ae44-4e0046c17419.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-bird-box"><strong>Bird Box</strong></h2>
<p>Then we had some games with our eyes closed, like Blind Train, an activity with a rope stretcher, some associations, a world scramble, and slowly we reached the final and most challenging game. Blind Train deserves a special mention because it was so funny. Half of us were walking in the wrong direction, the other half were also confused about what to do, and the rest of the teams were laughing so hard they forgot they were supposed to play too.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764930642456/428d0175-959e-4b6a-809e-4c884b1266eb.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764939492804/10c97fe7-95da-42a8-804c-245b3954866b.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-warrior"><strong>Warrior</strong></h2>
<p><a target="_blank" href="https://thegeniusofplay.org/tgop/genius/play-ideas-tips/play-ideas/catch-the-dragons-tail.aspx">Catch the Dragon’s Tail</a> is a game that teaches teamwork, communication, coordination, and peaceful conflict resolution. At least, that is what the description promises. In reality, we turned the hotel’s backyard into something that looked suspiciously like a battlefield where nobody remembered the “peaceful” part.</p>
<p>Players form a line, with the first player as the head and the last as the tail. The head must chase the tail while the rest of the line tries to stay connected. The players who act as tails wear a scarf that they must protect, and the heads try to steal it. It sounds simple until the competitiveness shows up and everyone suddenly moves like the scarf contains ancient treasure.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764930697207/dc5cf967-87ed-4ea9-bddc-c3ba342c418b.jpeg" alt class="image--center mx-auto" /></p>
<p>Sometimes we forget how competitive we can get, and it becomes a little scary. After a long session of cautious running, suspicious strategies, dramatic slides, and at least one move nobody has been able to explain since, one of the teams finally declared their win.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764930726645/eee1e03d-efeb-40ca-b6e9-b9a3d1e67efe.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764938042944/a5fc67a8-5f5d-4919-b274-ae589bb660d9.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764938074210/7f322441-a64b-4e0e-b3af-4fdd5d23177d.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764939462642/209e7d4e-c2f0-4ba8-bc30-710ac3c83faa.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-secret-life-of-walter-mitty"><strong>The Secret Life of Walter Mitty</strong></h2>
<p>After lunch and an hour of free time, we continued with a set of workshops organized by our colleagues and by Simbiotika. It felt like the moment in a movie when everyone suddenly discovers their secret superpower.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764939532701/8a2c45f1-4980-41c2-91d0-c082a78ec41c.jpeg" alt class="image--center mx-auto" /></p>
<p>We had a color fabrics workshop by Bojana Arizankovska, where half of us realized we barely know the difference between some colors. A caricature drawing workshop by Nikola Kostovski, where some faces were stretched, some were exaggerated, and some of us wondered if that is really how we look.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764939560426/d39fec9c-d5c5-49b6-aebe-bba957740e8b.jpeg" alt class="image--center mx-auto" /></p>
<p>An origami workshop by Teodora Stoilovska and Todor Jovanovski, which proved that folding paper is much harder than our childhood made it seem. Salsa Cubana by Aleksandar Mirchovski, where hips tried their best and coordination politely stepped aside.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764940218135/873bbde4-42bc-45a3-a967-301032397e3a.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764940242395/51940a8a-29a1-4ed3-8759-092b7b2eed6b.jpeg" alt class="image--center mx-auto" /></p>
<p>Then came Vandalism 101 by Mario Stojchevski, the basics of lettering in graffiti, types of graffiti, and history. It was the only time we were legally encouraged to learn how to make things look like vandalism.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764940269234/b360bd59-bcd5-470f-b3aa-5d1f444a1bff.jpeg" alt class="image--center mx-auto" /></p>
<p>And last but not least, Basics of Photography by Luka Krstikj. This one happened right after the team building at Base42 because it got dark, and we ran out of time. The irony of doing a photography workshop without light was not lost on anyone.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764940430360/e50684b3-3d1b-4398-b495-71427209fa4e.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-oceans-eleven"><strong>Ocean’s Eleven</strong></h2>
<p>Simbiotika also added their own workshops: Sip and Paint, Stress Management and Mindfulness, Communication and Active Listening, and Bushcraft Survival Skills. Truly something for every version of us, from artistic to stressed to secretly preparing for a life in the woods.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764940485517/6ea41a87-ad51-4cd2-901d-37c889967d3e.jpeg" alt class="image--center mx-auto" /></p>
<p>After all of these activities, we realized that we have a lot of knowledge to share, and that there is always something extra besides our everyday job that makes us feel good. We also saw how rarely we give ourselves time to learn something different.</p>
<p>Most importantly, we discovered that our colleagues are great at what they do, sometimes in ways we never expected.</p>
<h2 id="heading-saturday-night-fever"><strong>Saturday Night Fever</strong></h2>
<p>If you thought that the workshops were where the night ended, you are totally wrong. We all had disco outfits, and suddenly the bar and the floor became like a <a target="_blank" href="https://youtu.be/WSLMN6g_Od4?si=BVHcDP5mpLRNRbcx&amp;t=86">Pulp Fiction dance scene</a>. There were sparkles everywhere, some new dance moves where Nikolaj again took the spot, and Sheva made the night even better by being the DJ and adding some character to the party.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764940864730/249d4f34-aa19-4157-9637-658b5748b88b.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764940764802/5c9b0a6f-d82a-4377-a271-da67490a6d34.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764940747220/ebff5e20-ff00-4f7c-bd03-50aba97b6f69.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-morning-after"><strong>The Morning After</strong></h2>
<p>Even though our eyes were fighting a battle that morning, we packed everything, went downstairs, and checked out. Then we closed the team-building by reflecting on the good and the things we need to improve. Yes, we are very self-aware of that.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764940727152/0f0b2985-e277-4b3f-a687-bb4187d43cf6.jpeg" alt class="image--center mx-auto" /></p>
<p>First, we shared some personal opinions and aspects of our approach to caring in this company, and although we shine in this value, there’s always room to improve ourselves. Then someone said that we definitely need initiative to share and dare, so we can intensify these values.</p>
<h2 id="heading-the-kings-speech"><strong>The King’s Speech</strong></h2>
<p>After some time and reflection on all these values, we shared certificates among ourselves and with our team, who had practically organized the whole team building “For the People,” which was applauded by everyone. It was time to say goodbye and to get back to our country, so we did.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764940650259/500804b0-fbf6-49bb-9e1a-6917973e5add.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-inside-out"><strong>Inside Out</strong></h2>
<p>You’ve probably been reading for 7 -10 minutes right now, but here’s the conclusion and what we learned from this team building…</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764941999797/bfcf9e44-459c-46ae-9d55-94881bcfa245.jpeg" alt class="image--center mx-auto" /></p>
<p>Listen to your colleagues, listen to them to the very end, try to be patient, do not jump to conclusions about some reaction. Don’t be impulsive; our moods shift like the skies above us. A serene morning can become a stormy night, and vice versa. Remember that our thoughts aren’t just thoughts. They are sometimes shaped by hunger, by grief, by sleep deprivation, by hormones, by something totally random, like losing in Dragon’s Tail or realizing breakfast is over.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764941502565/aead1ad7-0484-4b83-9c75-cd97a726628f.jpeg" alt class="image--center mx-auto" /></p>
<p>Try to understand and value someone else's opinion. You don’t have to be right sometimes, and even if you do, if you see how someone is passionate about something and they have spent their time doing it, support them, be with them. This is sharing, not sharing a burger or a coffee, although that’s also nice. Whether it is for career growth, a game in a team building, or something more personal, take the initiative and be there for the people.</p>
<h2 id="heading-the-little-things"><strong>The Little Things</strong></h2>
<p>We tend to forget these moments and how fragile we, the human beings, are. We forget so much that things become unforgettable. Again, as at the very beginning of this blog post, joy can be simple, and we may all need less than we imagine.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764941553971/c5f2edbc-4538-4270-aa82-cdff876103fc.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-social-network"><strong>The Social Network</strong></h2>
<p>In a way, that’s the whole point for us at CodeChem. Not just writing good code and delivering projects, but making sure the people behind all of that stay connected, grounded, and actually enjoy working together. Team building made it obvious, and now the job is to keep that same energy once we get back at our desks.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764942017476/9011d72e-79ca-43a0-b329-e1ef50f198f9.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-maybe-i-do"><strong>Maybe I Do</strong></h2>
<p>Maybe that’s all we really need going forward: a little more awareness, a little more patience, and the reminder that good work always starts with good people.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764942024596/9ef3430e-ebb2-4dba-a2e7-87da11d15829.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-a-beautiful-day-in-the-neighborhood"><strong>A Beautiful Day in the Neighborhood</strong></h2>
<p>Special thanks to <a target="_blank" href="https://simbiotika.mk/">Simbiotika</a>, who organized our team building for the second year in a row and knows how to handle us, even though we are a lot.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764942047450/6f6aa539-3785-4810-82dd-5c0bf47725a7.jpeg" alt class="image--center mx-auto" /></p>
<p>Also, special thanks to Krume, our photographer, for making these amazing photos, for his charisma, and for his positive attitude. If you need photos like these, you can always contact him here: <a target="_blank" href="https://krumetakesphotos.com/">https://krumetakesphotos.com/</a>. Plus, he is a great human and brings the fun!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1764942085208/91292255-d3ab-4b03-8f6c-bd567971e2b5.jpeg" alt class="image--center mx-auto" /></p>
<p>Now that we come to the end of this blog post, I hope you all noticed:</p>
<h2 id="heading-post-credits-hint"><strong>Post-Credits Hint 🎥</strong></h2>
<h3 id="heading-if-you-recognized-the-section-titles">If you recognized the section titles:</h3>
<p><strong>Yes, they’re all real movies. I</strong>f you haven’t watched some of them yet, well… you just got a pretty solid watchlist. 😄🍿</p>
<h1 id="heading-rolling-credits-codechem-edition"><strong>🎬 ROLLING CREDITS: CODECHEM EDITION</strong></h1>
<p><strong>CAST</strong></p>
<p>Gen Z Engineers ....................... Agents of Chaos &amp; Memes</p>
<p>Millennial Engineers .................. Masters of “One More Commit”</p>
<p>Gen X Engineers ....................... The Actual “Responsible Adults”</p>
<p>Designers ............................. Pixel Sorcerers &amp; Color Psychics</p>
<p>QA Specialists ........................ Certified Breakers of Everything</p>
<p>Project Managers ...................... Professional Crisis Containment</p>
<p>DevOps ................................ Cloud Whisperers &amp; Deployment Wizards</p>
<p>Marketing &amp; Recruitment &amp; Finance............The Only Reason We Function</p>
<p><strong>SPECIAL CAMEOS</strong></p>
<p>Nikolaj ................................ Chief Dance Officer</p>
<p>Sheva .................................. DJ &amp; Energy Distributor</p>
<p>Costa “Zelenskyy”...................... Ceremony Opener</p>
<p>Simbiotika Crew ........................ Bracelet Keepers / Team Building Organizers</p>
<p>Hotel Staff ............................ Witnesses of Our Collective Behavior</p>
<p>Blind Train Participants ............... Temporarily Disoriented Adventurers</p>
<p>Dragon’s Tail Survivors ................ Unofficial Stunt Performers</p>
<p><strong>LOCATIONS</strong></p>
<p>Skopje Office .......................... Where Deadlines Are Born</p>
<p>Two Buses .............................. Where Bonding Became Mandatory</p>
<p>Olympic Beach, Greece .................. Where We Rebooted Ourselves</p>
<p>Hotel Backyard ......................... Battlefield #1 (RIP to the grass)</p>
<p>Pool Bar ............................... Battlefield #2 (RIP to our dignity)</p>
<p>Beach at Midnight ...................... Battlefield #3 (RIP to everyone’s shoes)</p>
<p>Base42 ................................ Photography Class with Luka</p>
<p>Till our next one,</p>
<p>&lt;3, CodeChem</p>
]]></content:encoded></item><item><title><![CDATA[Why What You Learn in Class Matters: Handpicked Real-World Problems]]></title><description><![CDATA[Introduction
In this blog post, I’m highlighting three problems I’ve had the opportunity to work on. I found their solutions both endearing and instructive, especially for a wider audience such as Computer Science or Software Engineering students. Fe...]]></description><link>https://blog.codechem.com/why-what-you-learn-in-class-matters-handpicked-real-world-problems</link><guid isPermaLink="true">https://blog.codechem.com/why-what-you-learn-in-class-matters-handpicked-real-world-problems</guid><category><![CDATA[DFS]]></category><category><![CDATA[sql migration]]></category><category><![CDATA[#softwareengineering]]></category><category><![CDATA[problem solving skills]]></category><dc:creator><![CDATA[Gjorgi Krenkov]]></dc:creator><pubDate>Fri, 07 Nov 2025 11:44:36 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1762514591920/1341c07d-2bfb-45eb-a6fc-be707132dba7.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>In this blog post, I’m highlighting three problems I’ve had the opportunity to work on. I found their solutions both endearing and instructive, especially for a wider audience such as Computer Science or Software Engineering students. Feel free to try solving them if you haven’t already. The first one is a great warm-up for Advent of Code (and Open Day 😉).</p>
<h2 id="heading-1-groups-in-groups"><strong>1. Groups in Groups</strong></h2>
<h3 id="heading-problem-statement"><strong>Problem Statement:</strong></h3>
<p>One system allows a specific user group to be part of another group. If Group A is a subgroup of Group B, then Group B cannot be a subgroup of Group A—not even indirectly (e.g., A → B, B → C, C → A). The task is to display the parent relationship of a selected group.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762352300164/0bc6a690-2814-42b2-8db9-8198d06760a9.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-solution"><strong>Solution:</strong></h3>
<p>You may have seen similar structures in a filesystem GUI or encountered recursion in OS lab exercises involving file system entries. This problem, like many others, can be solved using one of the most versatile algorithms: <strong>Depth First Search (DFS)</strong>.</p>
<p>How do we apply DFS here? One key observation is that there must be at least one group that isn’t a subgroup. Why? Let’s use an intuitive explanation (powered by GPT) alongside formal proofs:</p>
<h3 id="heading-no-two-boxes-can-contain-each-other-at-the-same-time"><strong>No Two Boxes Can Contain Each Other at the Same Time</strong></h3>
<p>Think of a <strong>group as a box</strong>. Some boxes can contain other boxes.</p>
<p><strong>Rule:</strong> No two boxes can contain each other at the same time.</p>
<p>Now ask yourself: Is it possible that <strong>every box is inside another box</strong>?</p>
<ul>
<li><p>Pick any box.</p>
</li>
<li><p>That box is inside another box. That box is inside yet another. Keep going.</p>
</li>
<li><p>You can’t ever return to the first box you picked (the rule forbids two boxes containing each other).</p>
</li>
<li><p>But there are only <strong>finitely many boxes</strong>.</p>
</li>
</ul>
<p>So eventually, you <strong>must reach a box that is not inside any other box</strong>.</p>
<p>That box is the “top-level box”—the one that belongs to nothing.</p>
<p>Starting from these top-level groups, we run the DFS and track which nodes are being visited. Suppose we have paths like:</p>
<p><code>[[1, 2, 3], [1, 2, 4], [1, 3], [5, 3]]</code></p>
<p>Filter out all paths that don’t include the selected group. Sort by ID and then by length:</p>
<p><code>[[1, 3], [1, 2, 3], [5, 3]]</code></p>
<p>Print the first path. For the second path, remove the matching prefix and print from there. Repeat until the end. Boom! We’ve solved it (and documented the solution 😄).</p>
<h2 id="heading-2-big-endian-to-double-sql-migration"><strong>2. Big-Endian to Double SQL Migration</strong></h2>
<h3 id="heading-scenario"><strong>Scenario:</strong></h3>
<p>Imagine you have a relational table named <code>vector</code> containing arrays of N positive double numbers stored as big-endian hexadecimal representations, along with a column type (e.g. <code>position</code>). For your favorite 3D position vectors, you need to store additional data beyond (x, y, z), and the dependencies require creating a separate entity. The constraint: solve it using SQL* (MySQL in my case). Any SQL nerds?</p>
<h3 id="heading-example"><strong>Example:</strong></h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Value (Decoded)</strong></td><td><strong>Value (in SQL)</strong></td><td><strong>Type</strong></td></tr>
</thead>
<tbody>
<tr>
<td>[23.19191, 35.132, 380.77]</td><td>40374c8f5c28f5c34041b851eb851eb840877b3333333333</td><td>‘position’</td></tr>
<tr>
<td>[0, 11, 450]</td><td>00000000000000004026000000000000408c400000000000</td><td>‘position’</td></tr>
</tbody>
</table>
</div><h3 id="heading-solution-1"><strong>Solution:</strong></h3>
<p>This might not be the cleanest solution, but I chose this challenge because IEEE 754 representations are essential knowledge for computer architecture classes, SQL, and data migration stress. Hopefully, this blog sheds light on the question many engineers ask: “Where would I need this knowledge?”</p>
<p>Start by selecting all rows where <code>type = 'position'</code>:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SELECT</span> <span class="hljs-keyword">value</span> <span class="hljs-keyword">FROM</span> vector <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">type</span> = <span class="hljs-string">'position'</span>;
</code></pre>
<p>Next, split the concatenated value (each double is 8 bytes = 64 bits):</p>
<pre><code class="lang-sql">SUBSTRING(value, 1, 8)
SUBSTRING(value, 9, 8)
SUBSTRING(value, 17, 8)
</code></pre>
<p>Create a function to convert each CHAR(16) hex value (16 hex digits = 64 bits):</p>
<pre><code class="lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">FUNCTION</span> convert_big_endian_to_double(big_endian_hex <span class="hljs-built_in">CHAR</span>(<span class="hljs-number">16</span>)) <span class="hljs-keyword">RETURNS</span> <span class="hljs-keyword">DOUBLE</span>
</code></pre>
<p>Convert the hex to binary:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">SET</span> binary_representation = <span class="hljs-keyword">LPAD</span>(<span class="hljs-keyword">CONV</span>(big_endian_hex, <span class="hljs-number">16</span>, <span class="hljs-number">2</span>), <span class="hljs-number">64</span>, <span class="hljs-string">'0'</span>);
</code></pre>
<p>Then decode using IEEE 754:</p>
<p>How do we convert? <a target="_blank" href="https://en.wikipedia.org/wiki/Double-precision_floating-point_format">https://en.wikipedia.org/wiki/Double-precision_floating-point_format</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762036583062/817d9a41-d34f-41b0-a72c-68b45fff2dad.png" alt class="image--center mx-auto" /></p>
<pre><code class="lang-sql"><span class="hljs-keyword">DECLARE</span> <span class="hljs-keyword">result</span> <span class="hljs-keyword">DOUBLE</span>;  
<span class="hljs-keyword">SELECT</span> 
    <span class="hljs-keyword">POW</span>(<span class="hljs-number">-1</span>, <span class="hljs-keyword">CONV</span>(<span class="hljs-keyword">SUBSTRING</span>(binary_representation, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>), <span class="hljs-number">2</span>, <span class="hljs-number">10</span>))  <span class="hljs-comment">-- sign bit </span>
    <span class="hljs-keyword">POW</span>(<span class="hljs-number">2</span>, <span class="hljs-keyword">CONV</span>(<span class="hljs-keyword">SUBSTRING</span>(binary_representation, <span class="hljs-number">2</span>, <span class="hljs-number">11</span>), <span class="hljs-number">2</span>, <span class="hljs-number">10</span>) - <span class="hljs-number">1023</span>)  <span class="hljs-comment">-- exponent </span>
    (<span class="hljs-number">1</span> + <span class="hljs-keyword">CONV</span>(<span class="hljs-keyword">SUBSTRING</span>(binary_representation, <span class="hljs-number">13</span>, <span class="hljs-number">52</span>), <span class="hljs-number">2</span>, <span class="hljs-number">10</span>) / <span class="hljs-keyword">POW</span>(<span class="hljs-number">2</span>, <span class="hljs-number">52</span>)) <span class="hljs-comment">-- significand </span>
<span class="hljs-keyword">INTO</span> <span class="hljs-keyword">result</span>;
</code></pre>
<p>And that’s it! You can return the result from the function; however, keep in mind edge cases such as zero, infinity, etc.</p>
<h2 id="heading-3-finding-mac-addresses-of-disabled-network-adapters-on-windows-7"><strong>3. Finding MAC Addresses of Disabled Network Adapters on Windows 7</strong></h2>
<h3 id="heading-problem"><strong>Problem:</strong></h3>
<p>This is a bug fix, not a feature request. Not strictly tied to uni classes, but I chose it because it’s an unusual, non-trivial problem that requires deep troubleshooting across shells, WMI, and the registry.</p>
<p>How do you figure out the MAC addresses of all (including <strong>disabled</strong>) physical network adapters on Windows 7?</p>
<h3 id="heading-solution-2"><strong>Solution:</strong></h3>
<p>It sounds trivial, but it’s not. Disabled physical adapters don’t expose their MAC addresses via standard WMI queries, and Get-NetAdapter isn’t available on Windows 7. If you’ve used WMI queries before, and the user has a disabled network interface, you won’t get the MAC address.</p>
<p>You might be able to resolve this with some Windows 7 <a target="_blank" href="https://www.reddit.com/r/PowerShell/comments/ctjtj5/comment/exlx1u9/">upgrades</a> (if you have hardware control). Otherwise, the only solution I could propose is to ask the customer to enable the interfaces or upgrade. ¯\<em>(ツ)</em>/¯</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762175967683/f6f49e2c-dcb5-4cb0-a038-0d4df9a871aa.png" alt class="image--center mx-auto" /></p>
<p>(My Ethernet 2 was intentionally disabled)</p>
<h2 id="heading-final-words">Final words</h2>
<p>Knowledge-sharing is one of the foundations of community progress and personal growth for those who share it. I’m grateful to CodeChem and its clients for fostering a culture of knowledge sharing and accessibility. I hope this blog post serves as my contribution to that spirit. If you find this blog post useful, certainly do let me know, and I will share more!</p>
]]></content:encoded></item><item><title><![CDATA[Building Software by Drawing State Diagrams in XState]]></title><description><![CDATA[Motivation
I have always wondered what is the most crucial thing for creating effective, endurable, and scalable software systems, following the stories of how some companies have core software written in languages ​​that were “popular” in the 70s of...]]></description><link>https://blog.codechem.com/building-software-by-drawing-state-diagrams-in-xstate</link><guid isPermaLink="true">https://blog.codechem.com/building-software-by-drawing-state-diagrams-in-xstate</guid><dc:creator><![CDATA[Gjorgi Krenkov]]></dc:creator><pubDate>Tue, 20 May 2025 10:00:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747392854919/27e0f69a-2ca9-45c0-9dae-e863767960b9.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-motivation">Motivation</h2>
<p>I have always wondered what is the most crucial thing for creating effective, endurable, and scalable software systems, following the stories of how some companies have core software written in languages ​​that were “popular” in the 70s of the last century or experiences such as rewriting WinForms 90s Desktop software to adapt to the modern Cloud/Web/Mobile world.</p>
<p>A few months ago, I attended a tech conference in Skopje, <a target="_blank" href="https://wts.sh/">WhatTheStack</a>. One of the presentations reminded me of an interesting concept in computer science: State Machines.</p>
<p>At this event, it was presented how UI components can be modeled using Finite State Machines and the selling point for me to try the <a target="_blank" href="https://xstate.js.org/">XState</a> library was the visual editor and my belief that such CASE (Computer Aided Software Engineering) tools can significantly simplify the definition of certain business and system processes in the form of a diagram drawing/wiring that is quite understandable even for non-IT people.</p>
<p>So I decided to try to develop my ATM system to describe all its UI interactions and states using XState! #LearnByDoing</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737625620654/e6259889-61de-48c8-90ac-9fafba90d73c.png" alt="A small snippet from the state chart of some of the functionalities of my ATM machine " /></p>
<h2 id="heading-what-is-a-state-chart">What is a state chart?</h2>
<p>State diagrams (or charts) provide an abstract description of a system's behavior. The content described in a state chart is a deterministic finite state machine (FSM), a conceptual model that is defined by the state in which the system currently is, and the events that cause a transition from the current state to another (or the same) known state from the finite number of states.</p>
<h2 id="heading-atm-system-breakdown">ATM: System breakdown</h2>
<blockquote>
<p>Note: To maintain the conciseness of the presentation and the reader's concentration, I highly recommend cloning and starting the project by yourself, available at the <a target="_blank" href="https://github.com/gjorgi-krenkov/atm-fsm">link</a> provided at the very end of this post. The project is a React web application and a Node Express (server.js) application.</p>
</blockquote>
<h3 id="heading-creating-an-initial-state">Creating an initial state</h3>
<p>Every ATM will ask you to insert your credit/debit/crypto card, so the initial state of my ATM state machine is: <code>Insert Card</code>. After successfully “inserting” a card, we are presented with a menu where we need to authenticate. This is how the definition of the initial state looks in code:</p>
<pre><code class="lang-javascript"><span class="hljs-string">"Insert Card"</span>: {
    <span class="hljs-attr">on</span>: {
        <span class="hljs-attr">CardInserted</span>: <span class="hljs-string">"Unauthorized Menu"</span>
    }
} <span class="hljs-comment">// creating a new state with the visual editor is even simpler</span>
</code></pre>
<blockquote>
<p>In the interest of my time, while developing the application, I didn’t go into some details (such as whether the correct card was inserted).</p>
</blockquote>
<h3 id="heading-interaction-with-the-main-application">Interaction with the main application</h3>
<p>During the lifecycle of an actor (in this case, an ATM FSM instance), the outside World (in this case, the frontend application itself) can find out the current state of the instance or send an event message with the send function.</p>
<pre><code class="lang-javascript"> {state.matches(<span class="hljs-string">'Insert Card'</span>) &amp;&amp; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">InsertCard</span> <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> send({ type: "CardInserted" })} /&gt;</span>}
</code></pre>
<blockquote>
<p>Therefore, while we are on the InsertCard screen, some external actor (in this case, onClick) will send an event of type “CardInserted” and will “trigger” the machine to make a transition to the Unauthorized Menu. As simple as that!</p>
</blockquote>
<h3 id="heading-what-about-data">What about data?</h3>
<p>Each instance also has its global memory, defined as <strong>Context</strong>, where we can store data needed during the machine’s lifecycle.</p>
<p>In my case, the PIN is stored as <code>userId</code> in the Context of the ATM. Although this is unnecessary, my goal was to create an <code>updateUserId</code> event that triggers a transition within the same state when updating the PIN, which will, at some point, be used as input when calling another type of actor to authorize ourselves – <strong>Promise actor</strong>.</p>
<h3 id="heading-the-promise-actor">The Promise actor</h3>
<p>Using <code>fromPromise</code> we’ve defined our authorization actor, which essentially makes a POST request to the server and validates the user (the PIN/userId). What is interesting about Promise actors is that they have exactly two outcomes, done and error, which would direct the user to the Authorized Menu or Incorrect Pin (simplification) screen, respectively.</p>
<h3 id="heading-reusability">Reusability</h3>
<p>What enhances the reusability is using another machine as a child actor in our machine. For example, the ATM uses a countdown machine to transition out from some screens where the user receives an informational message (Thank you for using our services).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737626823347/9d96d373-4117-4f29-bf0f-67968b0f85bc.png" alt /></p>
<blockquote>
<p>In this machine, we have a countdown event that after 1 second transitions to the same state and that event has a <strong>guard</strong> (it can be executed if the <code>remaining count seconds != 0</code>). A similar guard is <code>countingFinished</code> – we can’t finish if the <code>remaining count seconds != 0</code>. XState allows us to call an action upon each entrance of a specific state, and <code>notifyParent</code> is such an example, upon each entrance in the counting state, notify the parent (ATM instance) about how many seconds are left!</p>
</blockquote>
<h2 id="heading-atm-visualised">ATM: Visualised</h2>
<p>To better visualise how all this would look to the outside world, that is, from the point of view of the ATM user, my colleague <a class="user-mention" href="https://hashnode.com/@andrej-d">Andrej Dojchinovski</a> stepped in and helped design the user interface of our imaginary ATM. In the following section, he’ll share the thoughts and reasoning behind the designs in a few words.</p>
<h3 id="heading-guides-and-constraints">Guides and Constraints</h3>
<p>Let’s start by clarifying that the goal was never to invent a new type of ATM, but rather to create a smooth, familiar user flow, guided by UX and UI best practices, with the main objective of simulating the functionalities provided by the state machines working in the background. We decided that our fictional ATM would include a touchscreen, a physical numeric keypad, a card slot, and a cash slot.</p>
<h3 id="heading-ui-design">UI Design</h3>
<p>Since the ATM is purely fictional and unaffiliated with any existing bank, I had the creative freedom over its branding and visuals. Assuming it might be used outdoors in daylight, I gave the interface a bright, neutral background to allow for better contrast and text readability. I used a semantic approach for the colour palette, organising it into three groups:</p>
<ul>
<li><p><strong>Teal and mint green</strong> for primary, desired actions and success messages</p>
</li>
<li><p><strong>Dark desaturated teal</strong> for secondary actions and neutral text</p>
</li>
<li><p><strong>Raspberry pink</strong> for cancelling actions and error states</p>
</li>
</ul>
<p>To ensure visual consistency and harmony, I applied shades from these same color groups to all graphic elements and illustrations throughout the designs.</p>
<h3 id="heading-content-layout-actions">Content, Layout, Actions</h3>
<p>The overall digital interface includes two distinct types of screens:</p>
<ol>
<li><p><strong>Screens that prompt physical interaction</strong> with the ATM (e.g., inserting or removing a card, entering a PIN, or depositing/collecting cash)</p>
</li>
<li><p><strong>Screens that require touchscreen interaction</strong>, where the user selects from multiple on-screen options</p>
</li>
</ol>
<p>In addition to differing in expected user input, these two types also vary in content and layout.</p>
<p>The first type is characterised by a clear written instruction accompanied by an image as a visual cue indicating the expected physical action.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747036451392/4ccce3ee-b5ba-4e48-97dd-fd962c74a32a.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>Here we see the initial state screen prompting the user to insert their card to start using the ATM, followed by the second screen requiring authentication with a PIN.</p>
</blockquote>
<p>The second type presents the user with a set of choices, prompting them to proceed by tapping one of the displayed options. Users can end the session at any point (except during background processes such as checking a balance or counting cash).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747036259727/4264f578-4ecd-42ec-af3c-823624a0d12e.png" alt class="image--center mx-auto" /></p>
<blockquote>
<p>After a successful authentication, the user is presented with the main menu, with the option to withdraw cash, deposit cash, and check the card balance. If they choose to withdraw cash, they are given several pre-filled amounts based on commonly requested values, and the option to input a different amount.</p>
</blockquote>
<p>To prevent system errors and avoid unnecessary background processes, some actions are disabled until additional steps are completed. Animated screens provide real-time feedback during background operations, reassuring the user that the system is working. When errors occur, users are shown an explanatory message along with suggested steps to resolve the issue.</p>
<p>All of these use cases can be seen in the example below.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1747044251932/a83d9515-bd06-4906-a108-92ae08c31bce.png" alt class="image--center mx-auto" /></p>
<p>Once the user has performed all desired actions and necessary steps, the final screen displays an informational message confirming that the session has ended successfully. This screen is implemented with a countdown timer and automatically transitions back to the ATM's initial state after a short delay.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1746802744992/d3313121-9585-4295-b731-613d5071e1ab.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-prototype">Prototype</h3>
<p>To see all of this in action, check out the full prototype via the following link:</p>
<p><a target="_blank" href="https://www.figma.com/proto/38UFZDL7GEmXwBaP6uqz8J/ATM-Design?page-id=0%3A1&amp;node-id=83-917&amp;viewport=-2740%2C-3096%2C0.2&amp;t=CdonHG5dU83XXOkD-1&amp;scaling=min-zoom&amp;content-scaling=fixed&amp;starting-point-node-id=83%3A917">Figma Prototype</a></p>
<p>[Hint: Whenever an external action is required (such as inserting a card), simply click anywhere on the screen to proceed in the prototype.]</p>
<h2 id="heading-final-words">Final Words</h2>
<p>Of course, many other functionalities weren’t even mentioned in this blog post, so I encourage you to try modeling the behavior of some system that comes to your mind.</p>
<p>I believe developing software as a state machine will guarantee its longevity, easier integration into different media, reliable system upgrades, and easier testing/observance of the possible state paths within the system (btw, writing tests for FSM is also fun!).</p>
<p>Finally, thank you for making it this far! Below you can find the GitHub link to the project itself, and if you have any comments and/or suggestions, I encourage you to contact me at <a target="_blank" href="mailto:gjorgi.krenkov@codechem.com">gjorgi.krenkov@codechem.com</a></p>
<p>Till my next blog post,</p>
<p>Best,</p>
<p>Gjorgi Krenkov</p>
<p>Project: <a target="_blank" href="https://github.com/gjorgi-krenkov/atm-fsm">https://github.com/gjorgi-krenkov/atm-fsm</a></p>
]]></content:encoded></item><item><title><![CDATA[A Game Jam Story: Debugging Bubbles at 3AM]]></title><description><![CDATA[The world was quiet. Too quiet. Then, out of nowhere… POP! A new challenge appeared. Armed with nothing but keyboards, creativity, and a questionable amount of caffeine, our engineers accepted the quest. The timer was set. The game jam had begun. The...]]></description><link>https://blog.codechem.com/a-game-jam-story-debugging-bubbles-at-3am</link><guid isPermaLink="true">https://blog.codechem.com/a-game-jam-story-debugging-bubbles-at-3am</guid><dc:creator><![CDATA[Jasna Mishevska]]></dc:creator><pubDate>Thu, 20 Feb 2025 11:03:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1739955863437/1c033065-2eb1-4499-893f-b2f5049d6f5c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The world was quiet. Too quiet. Then, out of nowhere… <em>POP!</em> A new challenge appeared. Armed with nothing but keyboards, creativity, and a questionable amount of caffeine, our engineers accepted the quest. The timer was set. The game jam had begun. The battlefield? Mystical hackerspace, Base42, where ideas clashed, code was forged, and physics engines were pushed to their absolute limits. Would they emerge victorious, crafting a bubble-powered masterpiece? Or would they fall into the abyss of infinite debugging?</p>
<p>There’s only one way to find out…</p>
<p>Read on to see who built what, who popped under pressure, and who walked away with the title of Best Game and some other awards. 🎮🫧</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739543741756/257e02ea-112c-40c2-a5e4-f2fb82443f39.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-jammin-i-want-to-game-jam-it-with-you">Jammin’, I Want to Game Jam It With You</h2>
<p>Game jams are the ultimate playground for game developers—an opportunity to test skills, experiment with absurd ideas, and consume alarming amounts of energy drinks. This year, the event was once again hosted by <a target="_blank" href="https://mgi.mk/"><strong>MGI</strong></a> <strong>at</strong> <a target="_blank" href="https://base42.mk/"><strong>Base42</strong></a><strong>,</strong> the second year in a row on this location, where engineers, artists, and just game enthusiasts gathered to embrace <strong>48 hours of creative madness</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739543771432/6d32a2ce-a2db-452a-9ec3-531230b884b4.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-codechem-representation-5-teams-2-major-awards">CodeChem Representation: 5 Teams, 2 Major Awards!</h2>
<p>This year, <strong>CodeChem had engineers and a game designer in 5 different teams</strong> battling against time, sleep deprivation, and their own ambitions. And guess what? <strong>Two of those teams took home top awards!</strong> Now, let’s take a closer look at what our colleagues built and <strong>who walked away victorious!</strong></p>
<h2 id="heading-best-game-award-hydroplane">🏆 Best Game Award: "Hydroplane"</h2>
<p>Not sure If I’m supposed to say meet Tomislav, because I said this in the previous blog post for Game Jam, but let’s structure it this way:  We’re gonna start with <strong>Tomislav</strong> Ignjatov, an ML engineer at CodeChem, our colleague and a Game Jam veteran who has <strong>never skipped a year</strong> (we stopped counting). Together with his crew, he created <strong>Hydroplane</strong>, a multiplayer game that <strong>protects the ocean floor from toxic and explosive barrels.</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739543984833/7c0ceb97-6499-4aa8-85b0-a9c47a228b3c.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-the-fish-fueled-cleanup-that-won-best-game">The Fish-Fueled Cleanup That Won Best Game 🎮</h3>
<p>One player controls a geyser that shoots bubbles to trap fish, while the other takes command of a yellow submarine that collects the fish and catapults them at barrels to destroy them; because what better way to clean up the ocean than with fish-powered demolition? Built using Godot Engine and Aseprite, the game earned them the Best Game Award, and they hope to launch it on Steam soon. The only thing Tomislav would change? The food. Also, despite constant interruptions from Nikola Dinevski of another team, he still came out on top. Or, as he puts it: <em>"I came, I saw, I conquered."</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739796056469/b1aed438-741c-4ab7-bbda-0141225cdd3e.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739543996824/571e14e4-7404-4be5-9654-93989c498357.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-best-hybrid-casual-game-overboiled-brainstormed-at-the-codechem-balcony">🔥 Best Hybrid-Casual Game: "Overboiled"  Brainstormed at the CodeChem Balcony</h2>
<p>Now, moving on to the next team…yes, we have a <strong>team</strong> now: <strong>Nikola Dinevski, Matey Cardula, Petar Atanasovski, Nikola Kostovski, and Gjorgji Nechovski.</strong> All of them are our engineers, except for <strong>Nikola Kostovski,</strong> the creative hero and our game designer. And oh, do we have a story to tell about this one?</p>
<p>If you’ve been around CodeChem long enough, you already know that a lot of ideas are born on our balcony, usually accompanied by a cup of coffee, some deep tech debates, and at least one person zoning out completely. This time, while sipping his coffee, Nikola Kostovski had a moment of pure inspiration. He stared into his cup and thought, <em>What if we made a game about overboiled milk?</em> Yes, really. Based on the Macedonian idiomatic phrase <strong><em>"Изгоре лончето, претече млекото,"</em></strong> which translates to <strong><em>"A watched pot never boils, but an unwatched one overflows,"</em></strong> Nikola figured, <em>why not turn a common kitchen disaster into a fast-paced game?</em> And thus**, Overboiled** was born.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739544632348/d8071846-b44a-4146-8f46-23df96bd0c37.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-brainstorming-banter-and-enough-caffeine">💡 Brainstorming, Banter, and Enough Caffeine</h3>
<p>While having a meet about this blog post, Nikola was on his philosophical game development journey, and the other Nikola (<strong>Dinevski from Bitola</strong>) was passionately explaining the difference between hybrid and hyper-casual games. The rest of us? We were just nodding along while internally wondering how much caffeine he had consumed at that point.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739544090056/f7f4717f-a4b7-4abb-97a1-fb0840d58256.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-so-what-is-overboiled">So, What is Overboiled?</h3>
<p>To answer your question, it is a fast-paced, strategic bubble-popping game where players must prevent a boiling container of milk, coffee, or beer from overflowing. Simple enough, right?</p>
<p>Well, there’s a twist. You can’t just tap bubbles when they reach the surface. Instead, you have to wait for three or more of the same color to match up before they burst automatically, giving you combo bonuses and gold. And, because chaos is mandatory in a game jam, the heat keeps increasing, sending bubbles flying up faster and faster until you feel like your screen is personally judging your reflexes.</p>
<h3 id="heading-power-ups-customization-and-pure-bubble-panic">🛠️ Power-Ups, Customization, and Pure Bubble Panic</h3>
<p>Thankfully, players aren’t left completely helpless. Power-ups like Cool-Off, Pop All, and Lid let you regain some control (at least for a few precious seconds before panic sets in again). And, as if boiling virtual coffee wasn’t fun enough, you can customize your container, switch up the liquids, and unlock new power-ups, all while trying to stay sane in the chaos.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739544185090/d91acf57-46e3-4022-adbc-848a8d3f93e8.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-art-sound-and-the-wild-methods-of-game-jammers">🎨 Art, Sound, and The Wild Methods of Game Jammers</h3>
<p>Now, let’s talk about the art. Nikola Kostovski’s work was so good that some people thought it was AI-generated. Nope, just raw talent and a ridiculous amount of attention to detail. Then there’s the music, which deserves a special mention because Nikola Dinevski literally woke up, grabbed random household objects, and started recording sound effects himself. That’s the level of dedication (or desperation?) we’re dealing with here.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739544226483/f2b10d75-8e44-4030-a2d8-537d062397ec.jpeg" alt class="image--center mx-auto" /></p>
<p>While Nikola Kostovski was on the creative front, the rest of the team Nikola Dinevski, Gjorgji Nechovski, Matey, and Petar went full Unity mode, tackling all the development, gameplay logic, and physics madness. They started by setting things up on one computer, but once tasks were divided, they switched to two machines and went full-speed ahead. And yes, some additional video editing skills were needed along the way, but somehow, in the middle of the jam-fueled insanity, they pulled it all together with slick transitions and audio.</p>
<h3 id="heading-the-aftermath-award-winning-amp-caffeine-induced-regrets">🏆 The Aftermath: Award-Winning &amp; Caffeine-Induced Regrets</h3>
<p>48 hours later, Overboied took home the Best Hybrid-Casual Game Award. And it was totally deserved. Will they be back next year? Absolutely. Are they still recovering from dangerous amounts of caffeine and energy drinks? Also yes. But hey, that’s just part of the Game Jam experience. 🔥🫧</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739544217831/e3f9b2bf-ea3d-4f8f-bd8a-d1514f8de906.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-a-multiplayer-web-game-bubble-pop">🌍 A Multiplayer Web Game: "Bubble Pop"</h2>
<h3 id="heading-solo-mode-activated">🕹️ Solo Mode Activated!</h3>
<p>Next on our list is Gjorgji Dimeski, who decided to go fully solo this year. As he boldly declared during our meeting, <em>"I might not win any awards this year, but I definitely won everyone’s hearts instead."</em> And honestly? He wasn’t wrong.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739544250115/b6147153-7d5b-4de9-8ac0-b8bad7c39623.jpeg" alt class="image--center mx-auto" /></p>
<p>Taking the lone wolf approach, Gjorgji developed Bubble Pop, a multiplayer bubble-popping game that can be played by anyone, anytime. No teammates, no distractions, just him, his code, and a mission. The game runs entirely on web technologies, built with Angular, and can be played online at <a target="_blank" href="https://bubbles.dimeski.net/"><strong>Bubble Pop</strong></a>.</p>
<h3 id="heading-sleep-deprived-not">Sleep-deprived, Not</h3>
<p>Unlike the caffeine-fueled chaos happening around him, Gjorgji actually went home to sleep instead of pulling a 48-hour all-nighter like the rest of the Game Jam warriors (<em>legend</em>). But despite his well-rested approach, he still had an amazing time, especially appreciating the fact that Base42 had heating—something past Game Jams seriously lacked.</p>
<p>His only complaint? The fast food situation could use an upgrade next year. Fair enough, Gjorgji. Fair enough. 🍕😂</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739544283597/566b411f-8e60-4f77-8a4f-c1869acb477f.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-bubble-blaster-a-kitchen-cleaning-fps-yes-really">💥 Bubble Blaster: A Kitchen Cleaning FPS (Yes, Really)</h2>
<h3 id="heading-clean-the-kitchen-with-a-bubble-gun">🦠 Clean the Kitchen… With a Bubble Gun?</h3>
<p>Next up, we have Teodor Angeleski and his crew, who took a wild approach to the Game Jam theme and turned kitchen cleaning into a full-blown FPS.</p>
<p>Yes, you read that right. In Bubble Blaster, players take on the role of a sentient cleaning detergent whose life mission is to eliminate bacteria and flies using—what else?—a bubble blaster. But that’s not all. Because, apparently, kitchen appliances are way too far out of reach for an average bottle of dish soap, players also get a grappling hook to swing to higher places (<em>which, for normal humans, would be waist height</em>).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739544317653/4ca1a895-fd36-4823-8528-9248672a9eda.png" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739544375135/3a6acec0-ea13-43bd-a734-ed220fadbc3d.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-a-crash-course-in-3d-game-development">👨‍💻 A Crash Course in 3D Game Development</h3>
<p>To bring this soapy warfare to life, the team used Godot Engine &amp; Blender, diving headfirst into 3D game development for the first time and somehow pulling it off in just 48 hours. If that’s not dedication, I don’t know what is.</p>
<h3 id="heading-teodors-secret-superpower-tallness-amp-humility">🦒 Teodor’s Secret Superpower: Tallness &amp; Humility</h3>
<p>Now, if you don’t know Teodor, let me paint you a picture. Imagine a guy who’s tall enough to reach the top shelf without a ladder yet humble enough to never mention it. Meanwhile, his game characters are out here grappling-hooking their way around a kitchen like it's a Marvel movie.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739548324059/298ac2e6-ca8c-4575-b9bf-28cda93b5e39.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-achievement-unlocked-fps-bubbles-amp-brilliance">🏆 Achievement Unlocked: FPS, Bubbles &amp; Brilliance</h3>
<p>Despite sleep deprivation, Blender struggles, and a very intense battle against bacteria, the team successfully created a 3D multiplayer shooter from scratch in just two days. Not bad for a weekend project, huh?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739548355240/41225c6e-14df-479b-b3ff-a46060fd1d89.jpeg" alt class="image--center mx-auto" /></p>
<p>Would they do it again? Absolutely. Would they sleep next time? Probably not. But hey, that’s Game Jam life. 💥🫧🎮</p>
<p>We’ve slowly come to an end… just kidding, there’s mooooooore.</p>
<h2 id="heading-bubbles-adventure-the-couch-kings">🎮 Bubbles’ Adventure: The Couch Kings</h2>
<p>Last but not least, we have Vasilaki Tocili, the only one from our embedded engineers in the jam, teaming up with his sister to create Bubbles’ Adventure, a hybrid-casual mini-game collection inspired by Bubbles from The Powerpuff Girls. And if there’s one thing we learned from their journey, it’s that a fancy setup alone doesn’t make a great game, but pairing it with strong determination definitely helps.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739544470415/0523d548-0032-4463-9c56-e301aa030a5e.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-the-setup-the-ultimate-couch-command-center">🛋️ The Setup: The Ultimate Couch Command Center</h3>
<p>From the moment the jam started, Vasilaki and his sister claimed the best couch at Base42—and never left it. Seriously, they built an entire PC + laptop fortress right there. For 38 out of 48 hours, they coded, designed, brainstormed, and probably questioned their life choices, all while refusing to move from their carefully chosen spot.</p>
<h3 id="heading-whats-bubbles-adventure-all-about">🎮 What’s Bubbles’ Adventure All About?</h3>
<p>The game is a collection of mini-games, each an adventure on its own. Before every game, players enter a lobby with unskippable ads, except you’re not locked in place. You can walk around, interact, and goof off while waiting for the next challenge to begin. Suspense, chaos, and monetization are all in one place.</p>
<p>Once the game starts, players take control of Bubbles, but with a twist…all characters are Bubbles, just stylized in their own way with custom outfits and accessories. And, of course, power-ups are available to spice things up.</p>
<p>One mini-game involves quick reflexes as bombs disguised in a similar color as the bubbles try to trick you. Another challenge features slippery and bouncy platforms-bubbles, where falling means getting yeeted into the void and sent back to the lobby.</p>
<h3 id="heading-the-tech-amp-the-grind">🛠️ The Tech &amp; The Grind</h3>
<p>Vasilaki handled all the programming and setup using Unity Engine, while his sister took care of the art, inventory, character designs, and the in-game shop. Aside from Unity, they also used Roblox Studio for inventory and shop mechanics. Did he work hard? Oh yes. Did he sleep? Not really. Did he eat? Probably, but only within arm’s reach of the couch. He was also the last person to submit a game—just like last year. But hey, <em>traditions are traditions</em>.</p>
<h3 id="heading-the-ultimate-couch-potatoes">The Ultimate Couch Potatoes</h3>
<p>At the end of the jam, Vasilaki and his sister didn’t walk away with an award, but they did leave with the undisputed title of Ultimate Couch Champions. While others paced, stressed, and powered through their games in questionable ergonomic positions, these two secured the comfiest spot in Base42 and refused to move for nearly two days.</p>
<p>It was his sister’s first Game Jam, and what better way to experience it than by coding, designing, and strategizing, all from the couch fortress they built? They had a blast and are already planning to return next year, hopefully with an even more optimized couch-to-coding ratio. What’s next? More caffeine, more coding, and, of course, claiming the best couch again. 🛋️🎮🔥</p>
<h2 id="heading-final-thoughts-would-we-do-it-again-absolutely">Final Thoughts: Would We Do It Again? ABSOLUTELY.</h2>
<p>48 hours. Too much caffeine. Questionable life choices. But was it worth it? 100%. From balcony brainstorms to 3 AM debugging chaos, this Game Jam was nothing short of legendary, wrapped up with four judges from four different companies, one of whom was our colleague Filip. While he may be locked in an endless rivalry with gravity, if there’s one thing he loves, it’s being involved in game-related events.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739796087155/5ab31851-e63d-4f93-86b3-bca6474dafae.jpeg" alt class="image--center mx-auto" /></p>
<p>Hopefully, next year, we’ll be back with better food, fewer energy-drink-induced hallucinations, and even crazier game ideas. Until then, keep coding, keep dreaming, and never underestimate the power of bubbles! 🫧🎮🔥</p>
]]></content:encoded></item><item><title><![CDATA[Parallel Documents Rendering: A Performance Comparison of VM, Kubernetes and FaaS in AWS]]></title><description><![CDATA[TL;DR
This blog post summarizes the comparison of the performance of parallel PDF document rendering across three AWS architectures: Virtual Machine (EC2) with Docker and Nginx, Kubernetes (EKS), and Function-as-a-Service (FaaS) using AWS Lambda. The...]]></description><link>https://blog.codechem.com/parallel-documents-rendering-a-performance-comparison-of-vm-kubernetes-and-faas-in-aws</link><guid isPermaLink="true">https://blog.codechem.com/parallel-documents-rendering-a-performance-comparison-of-vm-kubernetes-and-faas-in-aws</guid><category><![CDATA[ #DocumentRendering]]></category><category><![CDATA[aws lambda]]></category><category><![CDATA[Kubernetes]]></category><category><![CDATA[ec2]]></category><category><![CDATA[Cloud Computing]]></category><category><![CDATA[#EngineeringExcellence]]></category><category><![CDATA[TechInsights]]></category><category><![CDATA[vm]]></category><dc:creator><![CDATA[Nikola Dinevski]]></dc:creator><pubDate>Thu, 30 Jan 2025 11:45:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737985367432/e7f954e4-5436-479d-aca0-8eb12010dca3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-tldr"><strong>TL;DR</strong></h2>
<p>This blog post summarizes the comparison of the performance of parallel PDF document rendering across three AWS architectures: Virtual Machine (EC2) with Docker and Nginx, Kubernetes (EKS), and Function-as-a-Service (FaaS) using AWS Lambda. The goal is to evaluate scalability, cost-effectiveness, and complexity when rendering PDFs with Puppeteer under different cloud-based setups. I’ve written more details on the subject, which you can check out <a target="_blank" href="https://github.com/ndinevski/puppeteer-renderer-performance-comparison/blob/master/A_Performance_Comparison_of_Parallel_Documents_Rendering__VM___Kubernetes__and_FaaS_in_AWS.pdf">here</a>.</p>
<h2 id="heading-introduction">Introduction</h2>
<p>Cloud computing has dramatically transformed application development and deployment, particularly compute-intensive workloads. Document generation, a common task across industries like finance and reporting, is an ideal scenario for evaluating the performance of different cloud architectures.</p>
<p>In this comparison, I evaluate the performance of rendering PDFs using Puppeteer across three different AWS services:</p>
<ul>
<li><p><strong>EC2 (Docker and Nginx)</strong></p>
</li>
<li><p><strong>EKS (Kubernetes)</strong></p>
</li>
<li><p><strong>Lambda (FaaS)</strong></p>
</li>
</ul>
<p>Performance is measured in terms of request time, render time and total processing time for request batches of various sizes. The insights from this comparison can help developers choose the right cloud architecture for their specific use case.</p>
<h2 id="heading-architecture">Architecture</h2>
<h3 id="heading-local-container-docker">Local Container (Docker)</h3>
<p>For this setup, I developed a Node.js application with an Express endpoint to handle PDF rendering. The application was containerized using Docker and tested on a local machine, serving as a baseline for standalone deployments.</p>
<h3 id="heading-ec2-docker-and-nginx">EC2 (Docker and Nginx)</h3>
<p>In the EC2 setup, I provisioned an EC2 instance, installed Docker and Nginx, and deployed the application container. Nginx served as a reverse proxy, handling HTTP requests and forwarding them to the Docker container, ensuring efficient resource usage for parallel processing.</p>
<h3 id="heading-eks-kubernetes">EKS (Kubernetes)</h3>
<p>For Kubernetes, I used Amazon Elastic Kubernetes Service (EKS) with a 3-node cluster. The Docker container was pushed to Amazon Elastic Container Registry (ECR) and deployed through Kubernetes. A NodePort service exposed the application to external traffic, allowing for testing under different load conditions.</p>
<h3 id="heading-lambda-faas">Lambda (FaaS)</h3>
<p>The serverless approach utilized AWS Lambda to handle PDF rendering as a function. The Lambda function was triggered through an API Gateway, enabling dynamic scaling without the need to manage the underlying infrastructure.</p>
<h3 id="heading-testing-code-structure">Testing Code Structure</h3>
<p>I implemented a Node.js script that sent parallel HTTP POST requests to each service, passing EJS templates and JSON data as payloads. The testing was conducted for batch sizes of 1, 10, 30, 50, and 100 documents. Each service was evaluated based on average response time, render time, and total processing time.</p>
<h2 id="heading-performance-and-results-analysis">Performance and Results Analysis</h2>
<h3 id="heading-average-times-per-document">Average Times Per Document</h3>
<p>The table below summarizes the average response and generation times in seconds per document for 100 parallel requests.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Service</strong></td><td><strong>Avg Response Time (s)</strong></td><td><strong>Avg Generation Time (s)</strong></td></tr>
</thead>
<tbody>
<tr>
<td>Local Container</td><td>0.79</td><td>0.11</td></tr>
<tr>
<td>Lambda</td><td>0.7</td><td>0.22</td></tr>
<tr>
<td>EC2</td><td>0.89</td><td>0.27</td></tr>
<tr>
<td>EKS</td><td>0.91</td><td>0.28</td></tr>
</tbody>
</table>
</div><h3 id="heading-total-processing-times-for-batches">Total Processing Times for Batches</h3>
<p>The following table shows the total processing times in seconds for varying batch sizes across the different architectures, with a graph representing the data.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Num. Documents</strong></td><td><strong>Lambda</strong></td><td><strong>Local</strong></td><td><strong>EC2</strong></td><td><strong>EKS</strong></td></tr>
</thead>
<tbody>
<tr>
<td>1</td><td>1.9</td><td>0.96</td><td>1.17</td><td>1.28</td></tr>
<tr>
<td>10</td><td>2.82</td><td>5.42</td><td>6.12</td><td>3.05</td></tr>
<tr>
<td>30</td><td>7.51</td><td>15.54</td><td>17.51</td><td>9.64</td></tr>
<tr>
<td>50</td><td>9.3</td><td>30.43</td><td>33.22</td><td>17.56</td></tr>
<tr>
<td>100</td><td>14.06</td><td>63.41</td><td>68.23</td><td>35.93</td></tr>
</tbody>
</table>
</div><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1737721310272/c5ae0cb6-054e-4989-9da1-2393bd4da336.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-cost-analysis-of-document-rendering-services">Cost Analysis of Document Rendering Services</h3>
<p>When comparing the costs of document rendering across different AWS services, it’s crucial to understand execution times and the associated charges. Based on the results of rendering 100 documents (as detailed in Table II), here’s a breakdown of cost estimates for each service:</p>
<h4 id="heading-1-aws-lambda">1. <strong>AWS Lambda</strong></h4>
<p>Lambda functions charge based on execution time and allocated memory. With 2048 MB memory, the cost is $0.0000000333 per millisecond. For 100 documents, with an average of <strong>14.06 seconds</strong> (14,060 ms), the cost comes to approximately <strong>$0.00047</strong>. While this may seem highly cost-effective, Lambda’s pricing is best suited for short, on-demand tasks rather than long-running or high-frequency jobs.</p>
<h4 id="heading-2-amazon-ec2">2. <strong>Amazon EC2</strong></h4>
<p>Using a <code>t4g.small</code> EC2 instance costs <strong>$0.0168 per hour</strong>, and the execution time for processing 100 documents was <strong>68.23 seconds</strong> (0.01896 hours). This results in a cost of approximately <strong>$0.00032</strong> for rendering 100 documents. However, it’s important to note that EC2 instances remain active and incur costs even when not processing documents, making the actual cost much higher for continuous or low-usage workloads.</p>
<h4 id="heading-3-amazon-eks-kubernetes">3. <strong>Amazon EKS (Kubernetes)</strong></h4>
<p>The EKS setup used <code>c6g.large</code> nodes, which cost <strong>$0.02628 per hour per node</strong>. With a 3-node cluster and an execution time of <strong>35.93 seconds</strong> (0.00998 hours), the cost for rendering 100 documents was approximately <strong>$0.00026</strong>. However, additional costs for EKS must be considered, including <strong>control plane charges</strong> ($0.10 per hour) and potential load balancer usage. Like EC2, EKS clusters also incur costs for all running nodes, even when not actively processing tasks, which significantly increases the true cost for workloads requiring persistent resources.</p>
<h4 id="heading-4-local-container-on-dedicated-server">4. <strong>Local Container on Dedicated Server</strong></h4>
<p>For this simulation, running the Local Container on a dedicated server was assumed to be free. In a real-world scenario, however, a dedicated server typically costs between <strong>$0.05 and $0.10 per hour</strong>. With an average processing time of <strong>63.41 seconds</strong> (0.01761 hours), the estimated cost for rendering 100 documents would be approximately <strong>$0.001 to $0.002</strong>, depending on server pricing. While this approach offers predictable costs, it requires maintaining dedicated infrastructure, which could become inefficient for variable workloads.</p>
<h2 id="heading-discussion">Discussion</h2>
<p>The results clearly highlight the strengths and weaknesses of each architecture:</p>
<ul>
<li><p><strong>Local Container</strong>:</p>
<ul>
<li><p>Benefits: Suitable for isolated or small-scale deployments.</p>
</li>
<li><p>Limitations: Fully self-managed, with a lot of overhead and constant costs.</p>
</li>
</ul>
</li>
<li><p><strong>EC2</strong>:</p>
<ul>
<li><p>Benefits: Full control over the environment, flexibility, and resource allocation.</p>
</li>
<li><p>Limitations: Requires manual scaling and management of resources.</p>
</li>
</ul>
</li>
<li><p><strong>Kubernetes (EKS)</strong>:</p>
<ul>
<li><p>Benefits: Automated scaling, resource management, large workload handling.</p>
</li>
<li><p>Limitations: Complexity in setup and management, higher cost due to infrastructure overhead.</p>
</li>
</ul>
</li>
<li><p><strong>Lambda (FaaS)</strong>:</p>
<ul>
<li><p>Benefits: Fully serverless, automatic scaling with no infrastructure management.</p>
</li>
<li><p>Limitations: Cold start latency and limitations on execution time and resource allocation.</p>
</li>
</ul>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Choosing the right infrastructure for your workload depends on several factors, including cost, scalability, and performance. AWS Lambda offers serverless scalability for small-scale, cost-effective solutions but may struggle with high concurrency. EC2, while providing higher resource limits and simplicity, comes with continuous infrastructure costs. EKS shines for large-scale, continuous workloads, harnessing Kubernetes’ power for orchestration, but its complexity and cost can hinder low-utilization tasks. A Local Container setup is ideal for development or small deployments but lacks the scalability for more demanding applications.</p>
<p>Ultimately, assessing the specific needs of your workload—whether it’s predictable or variable, small or large-scale—along with budget considerations will help you make the most informed choice. A hybrid approach combining these options often provides the optimal balance of cost, performance, and flexibility.</p>
<h2 id="heading-recommendations">Recommendations</h2>
<p>My personal take on choosing the right infrastructure for this specific use case, rendering PDF documents, is:</p>
<ul>
<li><p><strong>Online solution</strong> -If our goal is to generate documents, whether for sale or personal use, I would go for Lambda (FaaS). The pay-as-you-go pricing model is ideal because you only pay when documents are generated. If we are selling them, the cost of document generation essentially “pays for itself.” There are no costs for personal use, and when documents aren’t being processed, no infrastructure is running in the background.</p>
</li>
<li><p><strong>Offline solution</strong> - Usually, this use case means that a mid-to-large company generates documents on-premise. If this is for personal use, I would suggest just using Docker and starting a container locally. But, if this is for a large company where we need to handle big workloads and offer scalability, reliability, and elasticity, I would go for a local Kubernetes orchestration.</p>
</li>
</ul>
<hr />
<p>Check out the full paper <a target="_blank" href="https://github.com/ndinevski/puppeteer-renderer-performance-comparison/blob/master/A_Performance_Comparison_of_Parallel_Documents_Rendering__VM___Kubernetes__and_FaaS_in_AWS.pdf">here</a> for more detailed information on cloud architecture choices and performance comparisons.</p>
]]></content:encoded></item><item><title><![CDATA[Automating the Repetitive with Source Generators]]></title><description><![CDATA[Overview
We often write repetitive code when starting a new Web API project, whether using the modern, minimal API style or using classical .NET Controllers.
The most common cases are:

Rewriting pagination and sorting filters across projects;

Handl...]]></description><link>https://blog.codechem.com/automating-the-repetitive-with-source-generators</link><guid isPermaLink="true">https://blog.codechem.com/automating-the-repetitive-with-source-generators</guid><category><![CDATA[.NET]]></category><category><![CDATA[sourcegenerators]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Dule Pop-Andov]]></dc:creator><pubDate>Tue, 28 Jan 2025 09:48:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1738049068832/1d1fa967-93e4-434d-8dfb-8b4f64954cb4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-overview">Overview</h2>
<p>We often write repetitive code when starting a new Web API project, whether using the modern, minimal API style or using classical .NET Controllers.</p>
<p><strong>The most common cases are:</strong></p>
<ul>
<li><p>Rewriting pagination and sorting filters across projects;</p>
</li>
<li><p>Handling navigation properties and managing joins manually;</p>
</li>
<li><p>Creating controllers and database queries from scratch.</p>
</li>
</ul>
<p>What I will go through within this article won’t be a replacement, but rather a package to quickly build and test an API, whether in minutes or hours… it depends on many things. All you have to do is think <strong>about the models and their relations beforehand</strong>. The rest can be built by using proper annotations.</p>
<p><strong>Disclaimer:</strong> This is not a full implementation, or maybe it could be in the near future. For now, its peak potential will likely serve as a prototype for testing your ideas or perhaps for a personal project that doesn’t require heavy “configuration.” I mean, it is possible to do that, but it’s just not the intent— at least for now, though maybe in the future.</p>
<h2 id="heading-meet-dappi">Meet <strong>dappi</strong></h2>
<p>The name stands for dotnet application pre-programming interface; it’s all lowercase because it’s small, if that makes sense at all <em>(the truth is, dapi was taken, and I had to settle for dappi, which I’m equally happy with).</em></p>
<p>Now, I will introduce you to the annotation <strong>[CCController]</strong>. While the name may not seem directly related to dappi, I chose it because of my strong affection for the company where I work (<a target="_blank" href="http://codechem.com">CodeChem</a>), hence the initials as a prefix. As for the name Controller, well, it speaks for itself.</p>
<pre><code class="lang-csharp"> [<span class="hljs-meta">CCController</span>]
</code></pre>
<p>This can be used on top of any class representing an entity in <strong>your</strong> db, something we want to expose to the world in a REST API manner.</p>
<p>Let’s imagine we’re building a simple API to list our books and <strong>their</strong> author. We probably, almost always, would start by creating the class, right?<br />Yes, so let’s start with a book class.</p>
<pre><code class="lang-csharp">[<span class="hljs-meta">CCController</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Book</span>
{
    [<span class="hljs-meta">Key</span>]
    [<span class="hljs-meta">DatabaseGenerated(DatabaseGeneratedOption.Identity)</span>]
    <span class="hljs-keyword">public</span> Guid Id { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Title { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> YearPublished { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    <span class="hljs-comment">// Foreign key to reference the Author</span>
    [<span class="hljs-meta">Required</span>]
    [<span class="hljs-meta">ForeignKey(<span class="hljs-meta-string">"Author"</span>)</span>]
    <span class="hljs-keyword">public</span> Guid AuthorId { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    <span class="hljs-comment">// Navigation property: Each book has one author</span>
    <span class="hljs-keyword">public</span> Author? Author { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
</code></pre>
<p>Yep, it looks like every other class represents a table in the database. The attributes mentioned here are part of Entity Framework or .NET's <strong>System.ComponentModel.DataAnnotations</strong> namespace. These attributes help Entity Framework understand how to map our class properties to database schema columns and create relationships. While we’re not discussing Fluent API or EF in detail right now, we are simply referencing the tools we use.</p>
<p>Since we have finished the Book class and mentioned the Author there, let’s also create the Author class.</p>
<pre><code class="lang-csharp">[<span class="hljs-meta">CCController</span>]
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Author</span>
{
    [<span class="hljs-meta">Key</span>]
    [<span class="hljs-meta">DatabaseGenerated(DatabaseGeneratedOption.Identity)</span>]
    <span class="hljs-keyword">public</span> Guid Id { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    [<span class="hljs-meta">Required</span>]
    [<span class="hljs-meta">MaxLength(100)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    [<span class="hljs-meta">Required</span>]
    [<span class="hljs-meta">Range(0, 120)</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> Age { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    <span class="hljs-comment">// Navigation property: One author can have many books</span>
    <span class="hljs-keyword">public</span> ICollection&lt;Book&gt;? Books { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
}
</code></pre>
<p>Yes, that's it, folks! Believe it or not, we now have e a "fully” functional API ready to serve our needs. It includes all the CRUD operations that we would typically write manually and it is ready for testing. Simply just run <code>dotnet run &lt;your api-project&gt;</code> and open swagger in the browser… if you have it configured, of course. :)</p>
<p>Something like this should pop up:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733919968527/3f0e741f-a04a-47c2-8de3-09e0fc8f3f2e.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-filtering-sorting-and-pagination">Filtering, Sorting, and Pagination</h2>
<p>Now only that, but our read operation come along with features for filtering, sorting, pagination, and database manipulation. And yes, they all work!<br />Here’s an example of what a GET request for books looks like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733920548394/8b8c15eb-2c84-42c5-a630-a8f06001ed1c.png" alt class="image--center mx-auto" /></p>
<p>The result:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733920214461/6a716635-d6d6-44bf-84ce-0245cb72c12a.png" alt class="image--center mx-auto" /></p>
<p>In the query, we have a limit of 3, sorted by YearPublished in ascending order.  </p>
<p>Here is an example for filtering, can be done for any property:<br />We are asking for books that are published in 2019.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738067076216/ba049c29-be38-4bbe-8857-35ac303a4cbe.png" alt class="image--center mx-auto" /></p>
<p><strong>The result</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738067124061/1f6a57e8-add8-4fed-826a-abbcb99205e4.png" alt class="image--center mx-auto" /></p>
<p>We have retrieved the books that have been published 2019, this query can also be combined with sorting, we can limit our picks and we can add pagination.</p>
<h2 id="heading-what-is-this-magic-where-can-i-find-the-controllers-code">What is this magic? Where can I find the controllers’ code?</h2>
<p>This will definitely make it onto the FAQ list, so here it is: It’s located in the /obj folder generated at <strong>compile time</strong>, specifically during the <strong>C# build process.</strong> As for any other IDEs, it’s typically found under Dependencies/Source Generators/.</p>
<p>For VS Code, you can load it from the/Generated folder under /obj, but previously, you had to modify your .csproj like this:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">PropertyGroup</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- This for setting the path to find your source generated files --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">EmitCompilerGeneratedFiles</span>&gt;</span>true<span class="hljs-tag">&lt;/<span class="hljs-name">EmitCompilerGeneratedFiles</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">CompilerGeneratedFilesOutputPath</span>&gt;</span>$(BaseIntermediateOutputPath)\Generated<span class="hljs-tag">&lt;/<span class="hljs-name">CompilerGeneratedFilesOutputPath</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">PropertyGroup</span>&gt;</span>
</code></pre>
<h2 id="heading-can-i-debug-the-code">Can I debug the code?</h2>
<p>Yes, fully; just locate the files from the section above and place breakpoints.</p>
<h2 id="heading-can-i-change-the-implementation">Can I change the implementation?</h2>
<p>No, unfortunately, you cannot change the implementation, but you can definitely extend your controller by adding code to your implementation. For instance, if we had a system to rent books, we would want to incorporate that functionality. Just <strong>ensure you declare it as a partial class,</strong> something like this:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">CCApi.WebApiExample.Controllers</span>;

<span class="hljs-keyword">public</span> <span class="hljs-keyword">partial</span> <span class="hljs-keyword">class</span> <span class="hljs-title">BookController</span>
{
    [<span class="hljs-meta">HttpGet(<span class="hljs-meta-string">"rent/{id}"</span>)</span>]
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;IActionResult&gt; <span class="hljs-title">RentBook</span>(<span class="hljs-params">Guid id</span>)</span>
    {
        <span class="hljs-keyword">var</span> book = <span class="hljs-keyword">await</span> dbContext.Books.FirstOrDefaultAsync(book =&gt; book.Id == id);
        <span class="hljs-comment">// rent the book.</span>
        <span class="hljs-keyword">return</span> Ok(book);
    }
}
</code></pre>
<p>This will register it under the same BookController, and swagger will recognize it and display it in the same section.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733932886400/aa268979-ea5c-48a8-bd17-28c3a505ef69.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-what-happened-how-did-this-code-end-up-here">What happened? How did this code end up here?</h2>
<p>Simply put, this package utilizes the <strong>C# Source Generators,</strong> which is how it’s building our API in the background.</p>
<h2 id="heading-how-to-install">How to Install</h2>
<p>It’s fairly easy! Just add the NuGet package by running the command below, and happy coding! No real dependencies, just a dotnet-api project with <code>&lt;TargetFramework&gt;8.0&lt;/TargetFramework&gt;</code>.</p>
<pre><code class="lang-bash">dotnet add package Codechem.Dappi.Generator --version 1.0.0
</code></pre>
<p><strong><mark>Note: The package is not yet deployed, will be within the next couple of days</mark></strong></p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>Yes, I plan to develop this further and make it production-friendly. I hope to help many developers and save their time, potentially even creating a GUI. It’s not a replacement for custom solutions but a big leap forward in saving time and reducing boilerplate.</p>
<p>Until then, I hope some of you will try this package and build something good with it. I am open to feedback, suggestions, and contributions, so please reach out to me at dule@codechem.com.</p>
<p>Until next time, stay curious and keep exploring!</p>
<p>Dule Pop-Andov</p>
]]></content:encoded></item><item><title><![CDATA[A Deep Dive into OpenVAS: Enhancing Network Security Through Vulnerability Scanning]]></title><description><![CDATA[Heads up: Some of the vulnerabilities found in the reports were created for the explicit purpose of testing the accuracy and reliability of OpenVAS as a tool and platform.
TL;DR:This blog post explores the implementation of OpenVAS (Open Vulnerabilit...]]></description><link>https://blog.codechem.com/a-deep-dive-into-openvas-enhancing-network-security-through-vulnerability-scanning</link><guid isPermaLink="true">https://blog.codechem.com/a-deep-dive-into-openvas-enhancing-network-security-through-vulnerability-scanning</guid><category><![CDATA[#openvas]]></category><category><![CDATA[#cybersecurity]]></category><category><![CDATA[networksecurity]]></category><category><![CDATA[vulnerability scanning ]]></category><dc:creator><![CDATA[Nikola Dinevski]]></dc:creator><pubDate>Tue, 10 Dec 2024 11:43:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1733497613523/4bf1dbe2-94b1-4646-abdc-9706eaa0df91.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>Heads up:</strong> Some of the vulnerabilities found in the reports were created for the explicit purpose of testing the accuracy and reliability of OpenVAS as a tool and platform.</p>
<p><strong>TL;DR:</strong><br />This blog post explores the implementation of <strong>OpenVAS</strong> (Open Vulnerability Assessment System) to enhance our company's network security. If you’re interested in a deeper dive into the process, I’ve written a <a target="_blank" href="https://github.com/ndinevski/openvas-research-paper/blob/master/A_Deep_Dive_into_OpenVAS__Enhancing_Your_Network_s_Security_Through_Effective_Vulnerability_Scanning_and_Risk_Mitigation.pdf">detailed paper</a> on the subject, which you can refer to for more in-depth insights.</p>
<p>Initially, OpenVAS was set up on a Linux VM. Several scan types were configured, including <strong>host discovery</strong>, <strong>full/fast scans</strong>, <strong>authenticated scans</strong>, and <strong>CVE scans</strong>, which helped identify critical and minor vulnerabilities. The tool's detailed reports prioritized remediation efforts.</p>
<p>After testing, the setup was moved to a <strong>dedicated on-premise server</strong> for better reliability and performance. As things progress, automation and integration with other security tools are planned to streamline vulnerability management. OpenVAS proved to be a valuable, cost-effective solution for identifying and mitigating security risks in corporate networks.</p>
<p>While the tests also show potential false positives, having automated security scanning can prove invaluable with a proper process in place for scanning and triage.</p>
<h3 id="heading-introduction">Introduction</h3>
<p>In today’s interconnected world, cybersecurity is more critical than ever. You might never think your company will be the target of a cyber attack, but you can never rely on beliefs.</p>
<p>Organizations face constant cyberattack threats, making a robust vulnerability management system essential for safeguarding sensitive information. <strong>OpenVAS (Open Vulnerability Assessment System)</strong>, a powerful open-source vulnerability scanner, can be a pivotal tool in securing your network.</p>
<p>In this blog post, I will walk you through implementing OpenVAS in a corporate network environment, discussing its setup, findings, challenges, and benefits.</p>
<h3 id="heading-what-is-openvas"><strong>What is OpenVAS?</strong></h3>
<p>OpenVAS is a comprehensive vulnerability scanning tool designed to identify potential security risks in a network. It performs detailed assessments by scanning various devices, ports, and applications for vulnerabilities. It also provides valuable insights through generated reports, allowing security teams to prioritize remediation based on the severity of the risks.</p>
<p>The flexibility of OpenVAS makes it a strong candidate for organizations looking for a cost-effective, open-source solution to monitor their network's security posture continuously.</p>
<h3 id="heading-getting-started-with-openvas-setup-and-configuration"><strong>Getting Started With OpenVAS: Setup and Configuration</strong></h3>
<p>The first step in implementing OpenVAS was setting up the tool on a <strong>macOS machine</strong>. However, due to networking restrictions with Docker on macOS, I faced challenges giving OpenVAS access to the network from the container. After several attempts using custom bridges and VLANs, I decided to set up a <strong>Linux VM</strong> running Ubuntu, which worked seamlessly with Docker, enabling me to deploy OpenVAS without any issues. The docker-compose.yml I was using can be found <a target="_blank" href="https://greenbone.github.io/docs/latest/_static/docker-compose-22.4.yml">here</a>.</p>
<p>An important thing to note is that to each container, <code>network_mode: "host"</code> should be added to allow all the containers to be treated as separate machines in the network. The point is that they get a private IP Address from the local network, allowing them to ping all devices inside this network.</p>
<p><img src="https://cdn.discordapp.com/attachments/1270409675422302228/1309909319738724424/Screenshot_2024-11-23_at_16.51.54.png?ex=67590c5e&amp;is=6757bade&amp;hm=b9df1356196ffbb12fe45f8dbee1452d5038047e088567164e1610fba8e54efe&amp;=" alt /></p>
<p>With OpenVAS running on the Linux VM, I could begin scanning CodeChem’s network to identify vulnerabilities. I configured OpenVAS to scan two subnets within the network (192.168.0.100/24 and 192.168.0.101/24), ensuring that it covered the entire range of addresses managed by the router. This initial scan uncovered valuable information, such as operating systems, ports, applications, CVEs, and certificates, which were ranked based on their severity.</p>
<p><img src="https://cdn.discordapp.com/attachments/1270409675422302228/1309909787215003741/Screenshot_2024-11-23_at_16.53.45.png?ex=67590cce&amp;is=6757bb4e&amp;hm=c7bcb326b7deb7a4496b636d6391075ab4a15c04ab0bd4e4d57083a17dc47f3d&amp;=" alt /></p>
<h3 id="heading-scans-types-setup-and-results"><strong>Scans: Types, Setup, and Results</strong></h3>
<p>One of the most important features of OpenVAS is its <strong>scan types</strong> and how they can be configured to meet specific needs for vulnerability assessments. I configured several types of scans for our network to ensure thorough vulnerability detection.</p>
<h4 id="heading-defining-targets-and-network-segmentation"><strong>Defining Targets and Network Segmentation</strong></h4>
<p>I began by selecting two subnets (<code>192.168.0.100/24</code> and <code>192.168.0.101/24</code>) to scan, covering all devices connected to our network, including servers, workstations, and networked devices. It ensured that every device would be included in the vulnerability scanning process.</p>
<p><img src="https://cdn.discordapp.com/attachments/1270409675422302228/1310294508453363813/Screenshot_2024-11-24_at_18.22.30.png?ex=6759219a&amp;is=6757d01a&amp;hm=360e592ef8771dde093867aa8df440d8ffbc13c7180625a90ff2d4d9c25cec6f&amp;=" alt /></p>
<h4 id="heading-host-discovery"><strong>Host Discovery</strong></h4>
<p>The first task was a <strong>Host Discovery</strong> scan to identify all active devices on the network. This scan helped create a comprehensive inventory of devices essential for targeting future vulnerability scans.</p>
<h4 id="heading-full-and-fast-scans"><strong>Full and Fast Scans</strong></h4>
<p>Next, I performed <strong>Full and Fast Scans</strong> across the network. The <strong>Full Scan</strong> checked for vulnerabilities like missing patches, open ports, and configuration errors, while the <strong>Fast Scan</strong> focused on critical issues. These scans uncovered important findings, including a <strong>brute-force attack</strong> on a VNC Remote Control service. OpenVAS identified the weak password, allowing us to act quickly and secure the device.</p>
<p><img src="https://cdn.discordapp.com/attachments/1306321115173359686/1314594542279983256/image1_blur.png?ex=6758f452&amp;is=6757a2d2&amp;hm=7e63be40451d0bf73d73d5f144ee54ff0fd5d87b51513a0742dbe50e1a80fd65&amp;=" alt /></p>
<h4 id="heading-authenticated-scans"><strong>Authenticated Scans</strong></h4>
<p>I set up <strong>Authenticated Scans</strong> on critical systems like web servers and databases for deeper insights. These scans required valid credentials, enabling OpenVAS to detect vulnerabilities not visible from the outside, such as misconfigurations and outdated software.</p>
<h4 id="heading-cve-scan-tasks"><strong>CVE Scan Tasks</strong></h4>
<p>To ensure no known vulnerabilities were missed, I created <strong>CVE Scan Tasks</strong>, which specifically checked for critical vulnerabilities cataloged in the <strong>CVE</strong> database. These scans were vital for systems exposed to the internet, like public-facing web servers.</p>
<h4 id="heading-fine-tuning-the-scan-process"><strong>Fine-Tuning the Scan Process</strong></h4>
<p>After initial scans, I refined the process by scheduling daily scans at 7:00 AM and configuring email alerts for critical vulnerabilities. This automation ensured continuous monitoring without manual intervention.</p>
<p><img src="https://cdn.discordapp.com/attachments/1270409675422302228/1310305135502688327/Screenshot_2024-11-24_at_19.04.44.png?ex=67592b80&amp;is=6757da00&amp;hm=7f40fde71c887acd984b04b4d7c633d172e7d8387ee68b3c5e2c149eda782ea6&amp;=" alt /></p>
<h4 id="heading-generated-reports"><strong>Generated Reports</strong></h4>
<p>Each scan generated detailed <strong>PDF reports</strong> that listed vulnerabilities, categorized by severity, and offered actionable remediation steps. These reports helped our security team prioritize fixes and strengthen the network's security posture.</p>
<p>The results from these scans were detailed and comprehensive, with OpenVAS identifying both <strong>critical vulnerabilities</strong> that required immediate attention and <strong>minor issues</strong> that could be addressed over time. For example, some critical findings included outdated software versions with known exploits, while minor findings were related to less severe configuration issues.</p>
<p>Here’s an example of one of the generated reports, which visually breaks down the scan results:</p>
<p><img src="https://cdn.discordapp.com/attachments/1306321115173359686/1314594541340463104/image2_blur.png?ex=67599d12&amp;is=67584b92&amp;hm=7bc0d746a082adf1a37c5c4fe48a64f3c09af5640ae392687f6f6f6b48d71e2b&amp;=" alt /></p>
<p>These detailed reports helped prioritize remediation efforts based on severity, allowing the security team to address the most pressing vulnerabilities first.</p>
<p><img src="https://cdn.discordapp.com/attachments/1306321115173359686/1314594540887474239/image3_blur.png?ex=67599d12&amp;is=67584b92&amp;hm=1c9611f3e7d12165a8f1149dedac7ecda5d136899a8aba43458c22e56aa69d3c&amp;=" alt /></p>
<p><img src="https://cdn.discordapp.com/attachments/1306321115173359686/1314594540887474239/image3_blur.png?ex=67545712&amp;is=67530592&amp;hm=9cdbab9c8fa284937d07ddb89340537c8a4bbcdc028b429aede1e9b676a43812&amp;=" alt /></p>
<h3 id="heading-transitioning-to-an-on-premise-setup"><strong>Transitioning to an On-Premise Setup</strong></h3>
<p>While the initial configuration on the VM was successful, I realized that for OpenVAS to perform daily scans and provide continuous monitoring, it needed to be moved to a <strong>dedicated on-premise server</strong>. Running OpenVAS on a VM can be unstable, especially if the virtual environment encounters resource limitations. Moving to an on-premise machine offered the following benefits:</p>
<ol>
<li><p><strong>Reliability</strong>: The server would always be available, ensuring scans ran without interruptions.</p>
</li>
<li><p><strong>Performance</strong>: On-premise hardware offered more control over resources, allowing OpenVAS to handle larger networks and more complex scan tasks.</p>
</li>
<li><p><strong>Scalability</strong>: As the network grows, the on-premise setup can be upgraded to meet increasing demands.</p>
</li>
</ol>
<p>Once the transition was made to the dedicated server, OpenVAS was successfully set up and configured to run daily scheduled scans. This setup will ensure that our network remains continuously monitored, providing regular reports and timely alerts whenever vulnerabilities are detected.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733443534520/59132cd0-8982-4fbe-b44a-5faa972ece65.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-the-next-steps-automating-and-integrating-openvas"><strong>The Next Steps: Automating and Integrating OpenVAS</strong></h3>
<p>With OpenVAS now running on an on-premise server, the next steps involve <strong>automating</strong> the vulnerability management process. These include:</p>
<ul>
<li><p><strong>Automated Remediation Workflows</strong>: Implementing automated processes to address vulnerabilities once identified, reducing the need for manual intervention.</p>
</li>
<li><p><strong>Integration with Other Security Tools</strong>: Enhancing OpenVAS's capabilities by integrating it with other security tools used in the company, creating a more cohesive security strategy.</p>
</li>
</ul>
<p>These additional features will help streamline the vulnerability management process, improve response times, and strengthen the organization’s security infrastructure.</p>
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>In summary, implementing OpenVAS within a company’s network environment has been a rewarding and educational experience. The tool's ability to perform <strong>thorough vulnerability scans</strong>, generate detailed, <strong>actionable reports</strong>, and offer <strong>customized scanning options</strong> makes it an indispensable asset for any organization's cybersecurity framework.</p>
<p>While OpenVAS is a cost-effective and open-source solution, it’s important to note that it does come with some challenges. These include occasional <strong>performance limitations</strong> when scanning larger networks and the need for manual intervention to handle <strong>false positives</strong>. However, its <strong>flexibility</strong>, <strong>scalability</strong>, and <strong>robust reporting features</strong> make it an essential part of a comprehensive vulnerability management system.</p>
<p>The transition to an on-premise setup ensures that OpenVAS can continue to monitor the network reliably and efficiently. As the next step, I plan to focus on <strong>automating remediation workflows</strong>, integrating OpenVAS with other security tools, and fine-tuning the system to adapt to evolving threats.</p>
<p>By adopting OpenVAS as part of a broader security strategy, organizations can enhance their defenses, <strong>mitigate risks</strong>, and reduce the potential impact of cyber threats.</p>
]]></content:encoded></item><item><title><![CDATA[Calling Strapi REST APIs Fluently]]></title><description><![CDATA[When working with Strapi, one of the most powerful and flexible headless CMS platforms out there, we often find ourselves interacting with the Strapi REST API to fetch data. While Strapi’s REST API is straightforward, building complex queries—especia...]]></description><link>https://blog.codechem.com/calling-strapi-rest-apis-fluently</link><guid isPermaLink="true">https://blog.codechem.com/calling-strapi-rest-apis-fluently</guid><dc:creator><![CDATA[Ilija Boshkov]]></dc:creator><pubDate>Tue, 03 Dec 2024 12:19:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1733216612106/64508be6-5785-436d-b6f7-f2de5f1b222c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When working with Strapi, one of the most powerful and flexible headless CMS platforms out there, we often find ourselves interacting with the Strapi REST API to fetch data. While Strapi’s REST API is straightforward, building complex queries—especially for filtering, sorting, pagination, and population of relations—can become cumbersome and error-prone as the needs of your project grow.</p>
<h2 id="heading-the-old-way">The Old Way</h2>
<p>Strapi’s <a target="_blank" href="https://docs.strapi.io/dev-docs/api/rest/filters-locale-publication#deep-filtering">docs</a> on using the REST APIs, including its many features are quite extensive and well-explained, even for complex usecases. To sum it up, the way the REST API handles data querying is by mimicking a database query engine, which is very powerful and allows us to write queries like this:</p>
<pre><code class="lang-javascript">{
  <span class="hljs-attr">filters</span>: {
    <span class="hljs-attr">$or</span>: [
      {
        <span class="hljs-attr">date</span>: {
          <span class="hljs-attr">$eq</span>: <span class="hljs-string">'2020-01-01'</span>,
        },
      },
      {
        <span class="hljs-attr">date</span>: {
          <span class="hljs-attr">$eq</span>: <span class="hljs-string">'2020-01-02'</span>,
        },
      },
    ],
    <span class="hljs-attr">author</span>: {
      <span class="hljs-attr">name</span>: {
        <span class="hljs-attr">$eq</span>: <span class="hljs-string">'Kai doe'</span>,
      },
    },
  },
}
</code></pre>
<p>Then to make the call you make a GET request by using <code>qs</code> to stringify this into a URL-friendly query string, and you get:</p>
<p><code>filters[$or][0][date][$eq]=2020-01-01&amp;filters[$or][1][date][$eq]=2020-01-02&amp;filters[author][name][$eq]=Kai%20doe</code></p>
<p>Now it’s getting sticky.</p>
<p>This way of building queries is quite powerful, but can become very unwieldy when we want to express something in a more programmatic fashion; we have to spread a bunch of JSON objects on a bunch of different depths which can become very painful, very fast.</p>
<h2 id="heading-the-new-way-a-fluent-query-builder">The “new” way - a fluent query builder</h2>
<p>As is tradition in the JS ecosystem when you run into a problem - you build a library.</p>
<p>The goal behind developing this library was simple: <strong>to streamline the process of building dynamic, complex queries with a fluent, easy-to-understand API</strong>. Whether you’re querying content for a blog, managing a large product catalog, or building a custom CMS with intricate relationships, this library should make working with Strapi’s REST API significantly more efficient.</p>
<p>While <strong>Strapi Fluent Query Builder</strong> is designed with Strapi in mind (it’s in the name), it’s also meant to be <strong>agnostic</strong>—it should theoretically work with any RESTful API that adheres to similar conventions. (if you know of any, let me know :))</p>
<p>Let’s take the example we looked at in the previous section:</p>
<pre><code class="lang-javascript">{
      <span class="hljs-attr">filters</span>: {
        <span class="hljs-attr">$or</span>: [
          {
            <span class="hljs-attr">date</span>: {
              <span class="hljs-attr">$eq</span>: <span class="hljs-string">"2020-01-01"</span>,
            },
          },
          {
            <span class="hljs-attr">date</span>: {
              <span class="hljs-attr">$eq</span>: <span class="hljs-string">"2020-01-02"</span>,
            },
          },
        ],
        <span class="hljs-attr">author</span>: {
          <span class="hljs-attr">name</span>: {
            <span class="hljs-attr">$eq</span>: <span class="hljs-string">"Kai doe"</span>,
          },
        },
      },
    };
</code></pre>
<p>The equivalent of this code with the query builder would be:</p>
<pre><code class="lang-javascript">query(<span class="hljs-string">"blogs"</span>)
  .where(<span class="hljs-string">"author.name.$eq"</span>, <span class="hljs-string">"Kai doe"</span>)
  .or({
    <span class="hljs-attr">date</span>: {
      <span class="hljs-attr">$eq</span>: <span class="hljs-string">"2020-01-01"</span>,
    },
  })
  .or({
    <span class="hljs-attr">date</span>: {
      <span class="hljs-attr">$eq</span>: <span class="hljs-string">"2020-01-02"</span>,
    },
  });
</code></pre>
<p>While it’s not a lot less code, it does provide us with a JS/TS API for interacting with the parameters we want to send to our API, this means we can chain calls and perform any other operations as we would with any other builder.</p>
<h2 id="heading-key-features">Key Features</h2>
<h3 id="heading-1-fluent-api-for-easy-query-building">1. <strong>Fluent API for Easy Query Building</strong></h3>
<p>One of the standout features of the <strong>Strapi Fluent Query Builder</strong> is its <strong>fluent API</strong>. This allows you to chain methods in a clean and readable way, making query building intuitive and reducing the need for boilerplate code. You can focus on what you're querying, not how to format the query.</p>
<p>Example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> result = query(<span class="hljs-string">'books'</span>)
    .where(<span class="hljs-string">'title.$contains'</span>, <span class="hljs-string">'example'</span>)
    .sort(<span class="hljs-string">'createdAt'</span>, <span class="hljs-string">'desc'</span>)
    .page(<span class="hljs-number">1</span>)
    .pageSize(<span class="hljs-number">10</span>)
    .get();
</code></pre>
<h3 id="heading-2-advanced-filtering-capabilities">2. <strong>Advanced Filtering Capabilities</strong></h3>
<p>The library offers a flexible filtering system that supports multiple filter types, such as <strong>equality</strong> (<code>$eq</code>), <strong>inclusion</strong> (<code>$in</code>), and <strong>string matching</strong> (<code>$contains</code>). You can easily apply <strong>logical operators</strong> (<code>$and</code>, <code>$or</code>, <code>$not</code>) to combine multiple conditions and create complex filtering logic.</p>
<p>Example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> result = query(<span class="hljs-string">'templates'</span>)
    .or({ title: { $eq: <span class="hljs-string">'test'</span> } })
    .or({ tags: { $in: [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>] } })
    .get();
</code></pre>
<p>This will match either the templates that have exactly the title ‘test’ or that contain the tags 1, 2 or 3.</p>
<h3 id="heading-3-sorting-and-pagination">3. <strong>Sorting and Pagination</strong></h3>
<p>With the library’s <strong>sorting</strong> and <strong>pagination</strong> features, you can precisely control how results are returned. Whether you're displaying a list of blog posts or product pages, you can easily sort by multiple fields and control pagination parameters (e.g., page size, start index).</p>
<p>Example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> result = query(<span class="hljs-string">'templates'</span>)
    .sort(<span class="hljs-string">'createdAt'</span>, <span class="hljs-string">'desc'</span>)
    .page(<span class="hljs-number">1</span>)
    .pageSize(<span class="hljs-number">10</span>)
    .get();
</code></pre>
<h3 id="heading-4-population-of-relations">4. <strong>Population of Relations</strong></h3>
<p>Strapi allows for complex relationships between content types (e.g., one-to-many or many-to-many). With the <strong>populate</strong> method, you can easily fetch related content along with the main resource in a single query. The library also supports <strong>nested relations</strong>, meaning you can populate relations within relations, with filtering options to optimize your queries.</p>
<p>Example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> result = query(<span class="hljs-string">'books'</span>)
    .populate(<span class="hljs-string">'author'</span>)
    .populate(<span class="hljs-string">'author.friends'</span>);
</code></pre>
<h3 id="heading-even-populating-with-sorting-and-filtering-is-supported">Even populating with sorting and filtering is supported</h3>
<p>Let’s take for example the more complex samples from the <a target="_blank" href="https://docs.strapi.io/dev-docs/api/rest/populate-select#populate-with-filtering">Strapi docs:</a></p>
<p>Here’s the QS generated query string:</p>
<pre><code class="lang-plaintext">GET /api/articles?populate[categories][sort][0]=name%3Aasc&amp;populate[categories][filters][name][$eq]=Cars
</code></pre>
<p>It was created using the following piece of code:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> qs = <span class="hljs-built_in">require</span>(<span class="hljs-string">'qs'</span>);
<span class="hljs-keyword">const</span> query = qs.stringify(
  {
    populate: {
      categories: {
        sort: [<span class="hljs-string">'name:asc'</span>],
        filters: {
          name: {
            $eq: <span class="hljs-string">'Cars'</span>,
          },
        },
      },
    },
  },
  {
    encodeValuesOnly: <span class="hljs-literal">true</span>, <span class="hljs-comment">// prettify URL</span>
  }
);
</code></pre>
<p>With our query builder it’s as simple as:</p>
<pre><code class="lang-typescript">query(<span class="hljs-string">"products"</span>)
  .populateQ(<span class="hljs-string">"categories"</span>, <span class="hljs-function">(<span class="hljs-params">q</span>) =&gt;</span>
    q.sort(<span class="hljs-string">"name"</span>, <span class="hljs-string">"asc"</span>)
     .where(<span class="hljs-string">"name.$eq"</span>, <span class="hljs-string">"Cars"</span>)
  );
</code></pre>
<h3 id="heading-5-content-status-amp-localization">5. <strong>Content Status &amp; Localization</strong></h3>
<p>The ability to filter content by its <strong>status</strong> (e.g., <code>published</code> or <code>draft</code>) is crucial for content management. The <strong>Strapi Fluent Query Builder</strong> makes this easy with dedicated methods to retrieve content based on its publication state. Additionally, it supports querying content in different <strong>locales</strong>, which is useful for building multilingual applications.</p>
<p>Example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> result = query(<span class="hljs-string">'templates'</span>).published();  <span class="hljs-comment">// Fetch only published content</span>
<span class="hljs-keyword">const</span> result = query(<span class="hljs-string">'templates'</span>).locale(<span class="hljs-string">'en'</span>); <span class="hljs-comment">// Query content in English</span>
</code></pre>
<h3 id="heading-6-field-selection">6. <strong>Field Selection</strong></h3>
<p>Another powerful feature is <strong>field selection</strong>. You can specify exactly which fields to retrieve from the API, reducing unnecessary data in the response and improving application performance. This is especially useful when working with large datasets.</p>
<p>Example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">const</span> result = query(<span class="hljs-string">'templates'</span>).fields(<span class="hljs-string">'id'</span>, <span class="hljs-string">'title'</span>, <span class="hljs-string">'description'</span>);
<span class="hljs-comment">// select is equivalent to fields, it just exists as a more descriptive name</span>
<span class="hljs-keyword">const</span> result = query(<span class="hljs-string">'templates'</span>).select(<span class="hljs-string">'id'</span>, <span class="hljs-string">'title'</span>, <span class="hljs-string">'description'</span>);
</code></pre>
<h3 id="heading-7-transform-your-built-query-into-anything-you-need">7. Transform your built query into anything you need</h3>
<p>You can get the output of the query builder into the following:</p>
<ul>
<li><p>To JSON by calling <code>.json()</code> when you’re done building, it will give you a stringified version of the query in JSON form.</p>
</li>
<li><p>As an object by calling <code>.get()</code>, this will return the fully built JavaScript object.</p>
</li>
<li><p>As a query string only by calling <code>.qs()</code>, this will only return the query string part of the URL.</p>
</li>
<li><p>As a full URL (path + query string) by calling <code>.full()</code>.</p>
</li>
</ul>
<h3 id="heading-8-type-safety-with-typescript">8. <strong>Type Safety with TypeScript</strong></h3>
<p>The library is built with <strong>TypeScript</strong> to ensure full type safety across all query operations. This not only helps with autocompletion and error checking during development but also ensures that you’re working with well-structured data when building queries, <strong>even when populating nested relations</strong>.</p>
<p>While far from perfect, it tries to provide you with as good a guess as possible on your structure without getting in your way.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1732827791488/7aa8dd2b-c35c-47e7-81a8-b92b98332417.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-why-you-should-use-it">Why You Should Use It</h2>
<p>Let’s go back and reiterate on what you would get by using the query builder instead of creating filters manually:</p>
<ul>
<li><p><strong>Cleaner Code</strong>: By chaining methods together, you can create complex queries with minimal boilerplate.</p>
</li>
<li><p><strong>Easier Maintenance</strong>: The fluent API makes it easier to read and maintain queries, especially when working with dynamic or variable conditions.</p>
</li>
<li><p><strong>Flexibility</strong>: Although optimized for Strapi, this library is agnostic and can be used with any RESTful API that follows similar conventions.</p>
</li>
<li><p><strong>Unopinionated:</strong> It helps you cobble together the requests, nothing more, nothing less, bring your own way to make requests and go to town.</p>
</li>
<li><p><strong>Very good coverage:</strong> I don’t have a percentage for you, but the vast majority of operations that are possible by creating a filter manually should be possible with this builder. Aiming at 100%, if you find an incompatibility, feel free to open an issue, or even better - a PR on the <a target="_blank" href="https://github.com/codechem/strapi-fluent-rest-api">GitHub repository</a>.</p>
</li>
</ul>
<h2 id="heading-how-to-get-started">How to Get Started</h2>
<p>Getting started with <strong>Strapi Fluent Query Builder</strong> is quick and easy. Simply install the package via npm or yarn:</p>
<pre><code class="lang-bash">npm install @codechem/strapi-fluent-rest-api
</code></pre>
<p>Or:</p>
<pre><code class="lang-bash">yarn add @codechem/strapi-fluent-rest-api
</code></pre>
<p>Once installed, you can start building queries like never before. Here’s a simple example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> { query } <span class="hljs-keyword">from</span> <span class="hljs-string">'@codechem/strapi-fluent-rest-api'</span>;

<span class="hljs-keyword">const</span> result = query(<span class="hljs-string">'books'</span>)
    .where(<span class="hljs-string">'title.$contains'</span>, <span class="hljs-string">'example'</span>)
    .sort(<span class="hljs-string">'createdAt'</span>, <span class="hljs-string">'desc'</span>)
    .page(<span class="hljs-number">1</span>)
    .pageSize(<span class="hljs-number">10</span>);

<span class="hljs-keyword">const</span> myData = <span class="hljs-keyword">await</span> request.get(result.full());
</code></pre>
<p>The library supports a wide range of features and can be customized to fit your needs.</p>
<p>You can find the repository on <a target="_blank" href="https://github.com/codechem/strapi-fluent-rest-api">GitHub</a> and the package itself on <a target="_blank" href="https://www.npmjs.com/package/@codechem/strapi-fluent-rest-api">NPM</a>.</p>
<h2 id="heading-playground-codesandbox">Playground / CodeSandbox</h2>
<p>You can play around with the query builder below and list some of the events on <a target="_blank" href="https://42.mk">42.mk</a> to get a feel of the API and its capabilities, 42.mk runs a version of Strapi 4.</p>
<p>If you want to chat about the library, feel free to find me on the Discord server of 42.mk.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codesandbox.io/embed/vjgx84?view=editor+%2B+preview&amp;module=%2Fsrc%2Fquery.ts&amp;hidenavigation=1">https://codesandbox.io/embed/vjgx84?view=editor+%2B+preview&amp;module=%2Fsrc%2Fquery.ts&amp;hidenavigation=1</a></div>
<p> </p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>I hope the Fluent Query Builder can help make working with the Strapi REST API easier, cleaner, and more efficient.</p>
<p>Feel free to explore the library, contribute to its development, and let me know how it improves your workflow!</p>
<p>I’m open to feedback, contributions and ideas, shoot me a message, comment, issue or whatever else comes to your mind. :)</p>
<p>Cheers,</p>
<p>Ilija</p>
]]></content:encoded></item><item><title><![CDATA[Ready, Set, Late: The Adventure Begins]]></title><description><![CDATA[Sun, Fun, and Teamwork Done: CC Team Building, Nikiti 2024
Gather around the heart, people! We’re about to take you on a journey through our amazing team-building trip to Nikiti, Greece! 🙌🏼 Let’s face it: team building can, quite frankly, be bland!...]]></description><link>https://blog.codechem.com/ready-set-late-the-adventure-begins</link><guid isPermaLink="true">https://blog.codechem.com/ready-set-late-the-adventure-begins</guid><dc:creator><![CDATA[Jasna Mishevska]]></dc:creator><pubDate>Thu, 31 Oct 2024 11:24:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729501504608/b0364ecf-d3b8-41bd-8b8a-4c336aa094c2.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Sun, Fun, and Teamwork Done: CC Team Building, Nikiti 2024</p>
<p>Gather around the heart, people! We’re about to take you on a journey through our amazing team-building trip to Nikiti, Greece! 🙌🏼 Let’s face it: team building can, quite frankly, be bland! To prove you wrong, we’ll go through these 200 passages! 📖 Joke aside, there are only a few, and it will take up to 10 minutes of your precious time!</p>
<p>Now, let’s go through it!</p>
<h2 id="heading-day-1-the-beginning">Day 1: The Beginning</h2>
<p>We gathered at the bus stop early Friday morning with our luggage in hand, ready to roll at 08:00 sharp. 🕗 Knowing it’s rocket science for us to be on time, we left at 08:30. 🤣 Only half an hour late, but a record when dealing with so many people! We all have our flaws, but 100+ people to be on time is a mission impossible. However, we made it possible, and with the fantastic team from <a target="_blank" href="https://simbiotika.mk/">Simbiotika</a>, we were officially ready to be “team-built.” 🎉</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729601412315/53144b12-ff42-4cd5-926f-0da290c90851.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-games-on-the-go">Games on the Go</h3>
<p>The bus ride wasn’t just any trip; it was more like a party on wheels. 🥳 During it, we played “<em>Who am I?</em>” where everyone tried to guess the mystery person, no matter if it was a colleague or a celebrity. Things escalated quickly into chaotic fun as we scrambled to guess when some celebrity photos popped up!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729601433767/4e2c43c6-363d-4008-bee9-316b2be06ff9.jpeg" alt class="image--center mx-auto" /></p>
<p>Next, we were thrown into a survival scenario, imagining ourselves stranded in the middle of the ocean in a boat. 🚨 Spoiler alert: If this had been real, we’d be long gone by now. Thank goodness it was just a game! 😆</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729601373463/0c13b3a5-8967-4489-b47f-330abafc2033.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-angels-among-us-the-secret-angel"><strong>Angels Among Us: The Secret Angel</strong></h3>
<p>Simbiotika also introduced us to the <em>“Secret Angel”</em> game, and it’s like they truly knew us because taking care of each other is what we do best at <a target="_blank" href="https://codechem.com/how-we-work">CodeChem</a>. Everyone had a secret angel looking out for them, doing little acts of kindness. 💞</p>
<p>It reflects how we support each other, whether grabbing a coffee ☕ for a colleague or offering a listening ear when someone’s down. And yes, even though “we’re a family” 🙄 sounds cringy, we spend so much time together at work that it feels spot on.</p>
<p>But let’s get back to the subject! ✍🏼</p>
<h3 id="heading-finally-there-first-beach-impressions"><strong>Finally There: First Beach Impressions</strong></h3>
<p>We arrived in Nikiti in the afternoon, checked into the hotel, and headed straight for the beach without missing a beat. Our initial reaction? The beach was fantastic, and the view was absolutely breathtaking. 🏖️ After a tiring journey, we decided to take it easy and plan activities everyone could enjoy.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729601604327/b04390f3-6d47-4742-a6b5-0a08fc87ae39.jpeg" alt class="image--center mx-auto" /></p>
<p>Whether it was volleyball, frisbee, archery, spike ball, swimming, or just lounging on the beach, 🏐 🏹 🥏 🪷 🪸it was amazing to see everyone getting involved in the fun. The sunset was spectacular, and thanks to the talented <a target="_blank" href="https://www.instagram.com/alek_cheski/">photographer</a>, we have some postcard-worthy photos to remember it by. 📸 🌆 ✨</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729601638086/c467b38b-9bb7-465e-8361-9c8998ba05de.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729601655079/f9c02abd-fc7c-4ce8-ac74-f024b4ef52c9.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729601674479/67ded469-9558-4b10-8f00-bbac7d00f341.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729601716581/bf4a9115-aed0-437a-ac8a-66157c0c9369.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729601748179/d71c1b27-387f-4c1f-a549-7582b1a1a105.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-hula-and-limbo-madness"><strong>Hula and Limbo Madness</strong> 🌺💮💃</h3>
<p>Did we go to Hawaii, or was it still Nikiti? Yup, we had a themed party, dressed in traditional <a target="_blank" href="https://www.thehalepauhana.com/blog/hawaiian-leis-guide-to-flowers-customs-and-respect">Hawaiian Leis</a> and <a target="_blank" href="https://hawaiiflowerlei.com/product-category/haku-leis-hair-clips/haku-leis/">haku leis</a>, and had a competition in <a target="_blank" href="https://www.halekulani.com/the-movement-of-hula/">Hula dance</a>. Turns out, our dance moves are out of this world. But that wasn’t all; we also had a Limbo contest.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729601780703/79ada659-523a-4394-b790-03f2b3979bb1.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729601824759/212b3f64-7778-4e0f-96ec-98937be8086b.jpeg" alt class="image--center mx-auto" /></p>
<p>Shoutout to Alek, the most flexible person on the planet, for dominating the <a target="_blank" href="https://wikihow.com/Limbo">Limbo!</a></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729601843398/ca75106e-7819-4ed5-a1dd-a229f71b6db3.jpeg" alt class="image--center mx-auto" /></p>
<p>The night wasn’t over after the dancing. Board games kept the energy alive, and it was amazing to see how conversations and laughter flowed even between people who had only known each other over a short period of time.</p>
<h2 id="heading-day-2-the-shipwrights"><strong>Day 2: The Shipwrights</strong></h2>
<p>Day two started with breakfast, salty coffee included because, you know, the tap water in Nikiti is a little bit salty. 😂 🚰 We tried to see the bright side, though, treating it as an extra dose of electrolytes to supercharge our bodies for the day ahead. With our energy levels high (thanks, salty coffee!), Simbiotika divided us into teams for the “Cardboard Boat Building Challenge” with a twist. 🤔</p>
<p>While each team received specialized equipment, tools, and detailed blueprints for crafting their boats, we also had to hunt for hidden objects on the beach to complete our creations. A little scavenger hunt never hurt anyone, right?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729601994538/819734eb-09b8-4ede-b2fb-ccb5ace1147d.jpeg" alt class="image--center mx-auto" /></p>
<p>One thing’s for sure: we get seriously competitive when it comes to any challenge. But despite the rivalry, we’re always fair and polite, and believe it or not, we still love each other! Of course, that doesn’t mean we didn’t pull out all the stops to win. 🌟💪🥇</p>
<p>When the boats were finally built, it was clear that teamwork truly made the dream work. Not only did every boat float, but the creativity in their design and execution was impressive. 🛶 🛠️ The flags waved proudly, and the team names? Hilarious! We had everything from the prehistoric "Nendertalci" to the not-so-optimistic "Titanic." ⚐</p>
<h3 id="heading-and-the-winner-is">And the Winner Is…</h3>
<p>Congrats to “<em>Brodolom”</em> who won the first place! 🥇 Milan definitely nailed the sweep rowing skills, 🚣 but let’s not forget that every team member played a crucial role; just like in our work, cooperation was vital because your boat is bound to sink without it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729605776967/a039356a-1ef7-4f75-9ede-15918478c7e3.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729602274041/4565a27d-2796-4cdc-92db-4b47a5ee8a9a.jpeg" alt class="image--center mx-auto" /></p>
<p>The fun didn’t end there! After the boat race, we dove into the Beach Olympics, with different teams battling for the top spots. Post-Olympics, we split into three groups to tackle the next set of challenges. 🎖️</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729602312733/3796e509-3f82-460f-a1df-13fa2f7969df.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-artistic-avant-garde"><strong>Artistic Avant-Garde</strong></h3>
<p>There was one cool corner near the pool bar where Simbiotika set up a whole place for “Paint &amp; Sip,” which also had a twist; everything about this team building was with a twist. 🎨🍷 It was hilarious and heartwarming to see how our colleagues interpreted us. Some arts were true masterpieces, while others… well, let’s just say they belong in a meme gallery! 🤭🥰🙈</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729603149176/3f9e183d-87c5-4ecc-b85d-9f1ab9ed9aa8.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-codechem-survival"><strong>CodeChem Survival</strong></h3>
<p>One group ventured off into the wilderness (well, not too far) to learn some essential survival skills. We learned how to orient ourselves if we got lost in the great outdoors and Bojan from Simbiotika taught us how to set up a tent, 🏕️ pack for backpacking, ⛰ and, best of all, try military food. It might not have been gourmet, but hey, at least we know how to set up a tent for the next music festival or survive a surprise adventure. 𓆝 𓆟 𓆞 𓆝 𓆟</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729603188305/25bbf96f-3020-48eb-9c13-69069d8a3e63.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729603296287/42d30b6e-bd55-4858-bf89-e6cf44f55815.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-exploring-emotional-intelligence"><strong>Exploring Emotional Intelligence</strong></h3>
<p>The opportunity to explore emotional intelligence in a truly engaging way was great. Lazar from Simbiotika led an interesting workshop where we learned that emotions can be powerful assets when understood and managed correctly. 🫶🏻 One key takeaway was that if you're struggling to identify an emotion, you should pause, close your eyes, reflect on your feelings, and then define what’s happening internally. 😌</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729603315617/820e7d21-d1b4-4d43-b4cd-0bcf5725c4dd.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-empathy-as-strength">Empathy as Strength</h3>
<p>We also discussed how empathy, far from being a weakness, allows us to better understand the motivations behind people’s actions. 💞 However, knowing your limits is important, as well as ensuring that empathy doesn’t lead you to repeat the same mistakes or situations.</p>
<p>Lazar emphasized the importance of balancing emotions in decision-making—knowing when to lead with your heart ❤️ when to rely on your head,🧠 and, more importantly, how to combine both effectively.</p>
<h3 id="heading-understanding-and-helping-others">Understanding and Helping Others</h3>
<p>Emotional intelligence, at its core, involves helping others by not dismissing their words but by truly stepping into their shoes, understanding their perspective, and then, if possible, offering support. 🤝 Sitting by the beach, we practiced active listening techniques and discussed how emotional intelligence enhances team dynamics.</p>
<p>Despite the workshop’s intensity, the open discussions made it a memorable experience. Afterward, we treated ourselves to a refreshing swim, soaking in the warmth of the Indian summer. 🌊 It was the kind of moment that made you pause and appreciate both the company and the calm, a perfect balance to all the heavy lifting we’d done with our emotions earlier.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729603342704/eb2563c1-8f68-4dcc-8bf0-871c665d9620.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-coachella-the-surprise-on-the-agenda"><strong>Coachella: The Surprise on the Agenda</strong></h3>
<p>When we saw "Coachella" on the agenda, questions buzzed—what could it mean? Soon enough, we got some festive outfits again from Simbiotika,  🎊 and the event started with a twist—a Kahoot quiz about how well you know your colleagues. It was a personal and, yes, fiercely competitive challenge that had everyone on edge, revealing just how much (or little!) we all knew about each other.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729603367733/65e2335d-a632-4493-859e-a587871cace9.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-balloons-amp-battles-let-the-games-begin"><strong>Balloons &amp; Battles: Let the Games Begin</strong></h3>
<p>The evening escalated with even more fun and games: cup stacking with balloons, a hilarious Head-Hoop Basketball challenge, and the ultimate showdown: a Dance Battle! 🎈💃🎈</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729603616793/27c52f42-da26-4803-a716-29b7e456730b.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729603638764/65390751-08aa-4ede-9700-a56afe0a78eb.jpeg" alt class="image--center mx-auto" /></p>
<p>In pairs, we had to keep a balloon between us while dancing to various music genres. The last couple that managed to keep the balloon intact the longest won the battle without it popping or falling. Of course, there were prizes, medals, and loads of laughter as the night progressed.🏅🏅🏆🏆</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729603508203/a52e7621-33f4-4e00-9593-d73f70d98419.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729603550149/a7bbd8dc-0dc2-4302-9520-876bca051889.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-bioluminescense-adolescence">Bioluminescense, Adolescence</h3>
<p>As the party continued under the stars, the vibe turned into a beachside jam session. 🏖️ Instruments came out, 🎸 songs were sung, ♫♫ and stories were shared. Midway through, someone noticed the algae glowing in the water and dropped the news like it was no big deal. 🌊✨✨🌱 ✨</p>
<p>Turns out, those glowing dinoflagellates are pretty important marine microbes. They light up when something strange happens in their environment, kind of like us after too much karaoke. 🎤 🎙 Luckily, only a few species are actually toxic, so we were safe.</p>
<p>Plus, did you know that 70% of marine animals produce bioluminescence, too? Some use it to attract prey, others to navigate the deep waters. Pretty cool stuff, and no, this wasn’t just the wine talking. For the science nerds among us, here’s a <a target="_blank" href="https://www.sciencedirect.com/science/article/abs/pii/S1568988320301293?via%3Dihub">research</a> to dive deeper!</p>
<h2 id="heading-day-3">Day 3</h2>
<h3 id="heading-the-return-reflecting-relaxing-and-heading-home">The Return: Reflecting, Relaxing and Heading Home</h3>
<p>We started the final morning with a peaceful yoga session, during which a few of our colleagues stretched out and embraced the tranquility of the early hours. 🤸‍♀️🧘‍♀️ You could tell how relaxed they were; some even showed up in their pajamas (because why not?) 🛏️</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729603582763/196e7a80-344b-4157-9d21-2892b2440b62.jpeg" alt class="image--center mx-auto" /></p>
<p>After breakfast, we gathered for a closing talk—sharing impressions, reflections, and lessons learned. It was heartening to see everyone fully engaged as we reinforced our commitment to supporting each other. This team-building experience will stay with us long into the future. 💫</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729603660797/1bc4124f-97e1-4c87-a30f-8348db222f1e.jpeg" alt class="image--center mx-auto" /></p>
<p>We began our journey back to Skopje with everything packed and checked out. The bus ride was filled with laughter and games, particularly a never-ending association game where "Is it Galichica?" became the running joke; 🤣🤣 someone would ask, another didn’t hear, so they’d ask again, keeping the fun going. Meanwhile, the other bus turned into a lively sing-along, making those five hours fly by in a flash. 🎤♫⋆｡♪ ₊˚♬ﾟ.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729603680436/1cb6932e-c0f9-4f0a-a612-98b089beb5c3.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-conclusion-a-journey-to-remember">Conclusion: A Journey to Remember</h3>
<p>As we wrapped up our adventure, it was clear this trip was more than just team-building. It was an unforgettable journey that brought us closer in unique and fun ways. From the competitive games and hilarious moments to the deep emotional discussions and early yoga sessions, we experienced it all, and we did it together.</p>
<p>Big thanks to Simbiotika for organizing such an unforgettable experience and for taking care of us every step of the way. You somehow managed to bring us even closer together while keeping up with our endless jokes, endless energy, and so many different personalities! But we could tell you were having just as much fun as we were… and that’s saying something!</p>
<p>Here’s to more adventures, unforgettable memories, and even stronger teamwork in the future!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1729605113285/33f8abe2-724a-4ef9-8ab2-d49c4fad3a20.jpeg" alt class="image--center mx-auto" /></p>
<p>And for those who missed the fun (or just want to relive it), here’s a video capturing all the best moments of the chaos. Trust us, it’s <em>definitely</em> worth the watch! 🎥 😂</p>
<p>❤️, CodeChem</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://twitter.com/code_chem/status/1848632638132691355">https://twitter.com/code_chem/status/1848632638132691355</a></div>
]]></content:encoded></item><item><title><![CDATA[Introduction to Bicep: Create Everything You Need to Deploy Your Full-Stack Application on Azure]]></title><description><![CDATA[Introduction
Hey there! Welcome back to our Infrastructure as Code series on the CodeChem blog! 👋
If you missed our last article on the topic of Managing Azure Services & Resources, definitely give it a read first. But don’t worry, you can dive into...]]></description><link>https://blog.codechem.com/introduction-to-bicep-create-everything-you-need-to-deploy-your-full-stack-application-on-azure</link><guid isPermaLink="true">https://blog.codechem.com/introduction-to-bicep-create-everything-you-need-to-deploy-your-full-stack-application-on-azure</guid><dc:creator><![CDATA[Marko Spasenovski]]></dc:creator><pubDate>Mon, 28 Oct 2024 13:18:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1729867837870/e86e66bf-9f4e-45cc-9b50-e15dcb008de4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>Hey there! Welcome back to our Infrastructure as Code series on the CodeChem blog! 👋</p>
<p>If you missed our last article on the topic of <a target="_blank" href="https://blog.codechem.com/managing-azure-services-resources"><strong>Managing Azure Services &amp; Resources</strong></a>, definitely give it a read first. But don’t worry, you can dive into this one right away because today we’re talking about something exciting—Microsoft’s new, declarative language: Bicep! 🦾</p>
<p>After a brief introduction, we’ll explore a practical example of how to create everything you need to deploy and host a full-stack application using Bicep!</p>
<p>Let’s get started!</p>
<h1 id="heading-whats-bicep">What’s Bicep?</h1>
<p>Bicep is a domain-specific language (DSL) created by Microsoft for deploying and managing Azure resources. Throughout the development lifecycle, you can utilize a Bicep file to define the infrastructure you want to deploy to Azure and then repeatedly and incrementally deploy it. This guarantees consistent deployment cycles of your resources.</p>
<p>What makes Bicep stand out is its code reuse assistance, dependable type safety, and clear syntax. Bicep provides top-notch authoring for your Azure infrastructure-as-code solutions and it offers a much better developer experience.</p>
<h1 id="heading-benefits-of-bicep">Benefits of Bicep</h1>
<p>Let’s talk about what makes Bicep awesome and why I’m a big fan:</p>
<ul>
<li><p><strong>Support for all resource types and API versions:</strong> If you didn’t know, every Azure resource is controlled through its respected API. When a resource provider introduces new resource types and API versions, you can use them in your Bicep file. No waiting around for updated tools, just jump in and go.</p>
</li>
<li><p><strong>Simpler Syntax, Happier Developer Life:</strong> If you’ve ever wrestled with JSON templates, you know the struggle is real. They’re long, clunky, and prone to errors. Bicep, though, feels like a breath of fresh air—simple, clear, and so much easier to work with. You don’t need to be a coding wizard to understand it; the syntax is clean and declarative, so you just describe what you want to deploy. Easy-peasy!</p>
</li>
<li><p><strong>Modularity: Keep Your Infrastructure Organized and Scalable:</strong> One of the cool things about Bicep is its modularity. You can easily break your resources into multiple Bicep files and manage them with modules, giving you the flexibility to keep everything neat and organized. I prefer keeping all of my infrastructure in a single <code>main.bicep</code> file. However, if you use a lot of resources and get to a point where the file gets too bulky, no problem, just split it up!</p>
</li>
<li><p><strong>Seamless integration with Azure services:</strong> I mean, of course, right? Bicep was born for Azure, so it’s no surprise that it plays perfectly with all Azure services. The language was created to deploy.</p>
</li>
<li><p><strong>Preview changes</strong>: You can use the <a target="_blank" href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deploy-what-if">what-if operation</a> to get a preview of changes before deploying the Bicep file, much like the <code>git diff</code> command.</p>
</li>
<li><p><strong>Repeatable results</strong>: Bicep files are idempotent. Repeatedly deploy your infrastructure throughout the development lifecycle and have confidence your resources are deployed in a consistent manner.</p>
</li>
<li><p><strong>Orchestration</strong>: You don't have to worry about the complexities of ordering operations. Resource Manager orchestrates the deployment of interdependent resources so they're created in the correct order.</p>
</li>
</ul>
<h1 id="heading-how-to-create-the-resources-needed-to-deploy-your-full-stack-application"><strong>How to Create the Resources Needed to Deploy Your Full-Stack Application?</strong></h1>
<p><strong>Note:</strong>  Before we dive into the details, here’s a quick note: The code formatter here doesn’t support Bicep syntax highlighting. For the best experience, I recommend installing the official <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep">Microsoft Bicep</a> extension and opening the file in VS Code. It’ll make everything much easier to read and work with!</p>
<p>Now, let’s get into how to set up all the resources you need for deploying and hosting your full-stack application using Bicep.</p>
<p><code>bicep</code></p>
<pre><code class="lang-plaintext">// Parameters
param location string = resourceGroup().location
param appServicePlanSku string = 'P1v2'
param sqlServerAdminLogin string = 'adminuser'
param sqlServerAdminPassword string = 'P@ssword123!'
param databaseName string = 'appdb'
param frontendAppName string = 'frontendstaticapp${uniqueString(resourceGroup().id)}'
param backendAppName string = 'backendapp${uniqueString(resourceGroup().id)}'
param sqlServerName string = 'sqlserver${uniqueString(resourceGroup().id)}'
param keyVaultName string = 'keyvault${uniqueString(resourceGroup().id)}'
param staticWebAppSkuName string = 'Free'
param staticWebAppSkuTier string = 'Free'

// Resource: Static Web App for our Frontend
resource staticWebApp 'Microsoft.Web/staticSites@2022-03-01' = {
  name: frontendAppName
  location: location
  sku: {
    name: staticWebAppSku
    tier: staticWebAppSkuTier
  }
  properties: {
    repositoryUrl: 'https://github.com/your-org/your-repo' // GitHub repo containing frontend code
    branch: 'main'
    buildProperties: {
      appLocation: 'app' // Directory containing the frontend app
      apiLocation: '' // Optional: leave empty if no API is required here
      outputLocation: 'build' // Output directory for the frontend app
    }
  }
}

// Resource: App Service Plan for our Backend
resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = {
  name: 'appServicePlan${uniqueString(resourceGroup().id)}'
  sku: {
    name: appServicePlanSku
  }
  kind: 'linux'
}

// Resource: Backend App Service
resource backendApp 'Microsoft.Web/sites@2022-03-01' = {
  name: backendAppName
  location: location
  serverFarmId: appServicePlan.id
  httpsOnly: true
  dependsOn: [appServicePlan]
  siteConfig: {
    appSettings: [
      {
        name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
        value: applicationInsights.properties.InstrumentationKey
      }
      {
        name: 'SQL_CONNECTION_STRING'
        value: sqlDbConnectionString
      }
      {
        name: 'KeyVaultUri'
        value: keyVault.properties.vaultUri
      }
    ]
  }
}

// Resource: SQL Database
resource sqlDatabase 'Microsoft.Sql/servers/databases@2022-02-01-preview' = {
  name: '${sqlServerName}/${databaseName}'
  location: location
  sku: {
    name: 'S1'
    tier: 'Standard'
  }
}

// Resource: SQL Server
resource sqlServer 'Microsoft.Sql/servers@2022-02-01-preview' = {
  name: sqlServerName
  location: location
  administratorLogin: sqlServerAdminLogin
  administratorLoginPassword: sqlServerAdminPassword
  version: '12.0'
}

// Resource: Key Vault
resource keyVault 'Microsoft.KeyVault/vaults@2021-06-01-preview' = {
  name: keyVaultName
  location: location
  properties: {
    sku: {
      family: 'A'
      name: 'standard'
    }
    tenantId: subscription().tenantId
    accessPolicies: [
      {
        tenantId: subscription().tenantId
        objectId: 'your-principal-object-id' // Replace this with your Object ID for access
        permissions: {
          secrets: [
            'get'
            'list'
            'set'
          ]
        }
      }
    ]
  }
}

// Resource: Application Insights
resource applicationInsights 'Microsoft.Insights/components@2021-04-01' = {
  name: 'appInsights${uniqueString(resourceGroup().id)}'
  location: location
  kind: 'web'
  properties: {
    Application_Type: 'web'
  }
}

// Output connection details
output sqlDbConnectionString string = 'Server=tcp:${sqlServerName}.database.windows.net,1433;Database=${databaseName};User ID=${sqlServerAdminLogin};Password=${sqlServerAdminPassword};'
output frontendAppUrl string = 'https://${staticWebApp.defaultHostname}'
output backendAppUrl string = backendApp.defaultHostName
output keyVaultUri string = keyVault.properties.vaultUri
</code></pre>
<h2 id="heading-quick-summary">Quick Summary</h2>
<p>The example <code>bicep</code> file will provision the following resources:</p>
<ul>
<li><p><strong>Static Web App:</strong> Hosting the frontend app;</p>
</li>
<li><p><strong>Backend App Service</strong>: Hosting the backend services;</p>
</li>
<li><p><strong>SQL Server &amp; Database</strong>: Hosting the SQL Server and the app's database;</p>
</li>
<li><p><strong>Key Vault</strong>: For securely storing secrets;</p>
</li>
<li><p><strong>Application Insights</strong>: For monitoring the frontend and backend services.</p>
</li>
</ul>
<p>This is the basic infrastructure for a full-stack application with essential resources. You can modify and extend this according to your specific requirements. The Static Web App, Backend App Service, and the SQL Server &amp; Database are all you need. The Key Vault and Application Insights are optional but nice to have.</p>
<p>At the end of the <code>bicep</code> file, we have some output values. You can return output variables valuable to you for subsequent scripts in the pipeline or the application itself, e.g. the sqlDbConnectionString or the backend API URL.</p>
<h2 id="heading-keynotes-to-keep-in-mind">Keynotes to Keep in Mind</h2>
<p>The order in which the resources are declared in the <code>bicep</code> file <strong>doesn’t matter</strong>. For example, notice how we declare the SQL Server <strong>after</strong> the SQL Database. Of course, we can’t create the SQL Database before provisioning the SQL Server. The Azure task that executes your compiled bicep code is smart enough to know the order in which it has to provision the resources. If you want to ensure your order is followed, there is an optional parameter called <code>dependsOn</code>, which takes an array of resources. You can see this in the <code>backendApp</code> resource, where we say, “this <code>backendApp</code> depends on the <code>appServicePlan</code> resource.”</p>
<p>For the sake of simplicity, you might’ve noticed some of the declared parameters really shouldn’t be hard coded. Or, at least, not be a part of the <code>bicep</code> file. That’s true, most if not all parameters should be <strong>input</strong> parameters from the pipeline. For example, they should be declared as Azure Pipeline variables and passed to the <code>bicep</code> file.</p>
<p><strong>Never expose sensitive information in your</strong> <code>bicep</code> <strong>file</strong>. Your <code>bicep</code> file is version-controlled and should be treated like any other file you keep in your remote repository.</p>
<p>Bicep also offers the <code>@secure()</code> annotation. When you set a parameter to a secure string or secure object, the parameter's value isn't saved to the deployment history and isn't logged. However, if you set that secure value to a property that isn't expecting a secure value, the value isn't protected.</p>
<h1 id="heading-deploying-your-resources">Deploying Your Resources</h1>
<p>After you have defined your bicep file and declared your necessary resources, it’s time to deploy! You’re going to need the <code>AzureResourceManagerTemplateDeployment@3</code> task in your Azure Pipeline.</p>
<p>Example:</p>
<pre><code class="lang-plaintext">- task: AzureResourceManagerTemplateDeployment@3
         inputs:    
           deploymentScope: 'Resource Group'
           azureSubscription: '${{ parameters.azureServiceConnection }}'
           action: 'Create Or Update Resource Group'
           resourceGroupName: 'exampleRG'
           location: '&lt;your-resource-group-location&gt;'
           templateLocation: 'Linked artifact'
           csmFile: './main.bicep'
           deploymentMode: 'Incremental'
           deploymentName: 'DeployPipelineTemplate'
           deploymentOutputs: deploymentOutputs
</code></pre>
<p>This task will deploy the resources declared in the <code>main.bicep</code> file in a Resource Group. The deployment mode is ‘incremental’ to update existing resources and provision new first-time ones. Also, all the output variables will be available in the <code>deploymentOutputs</code> object.</p>
<h1 id="heading-final-thoughts">Final Thoughts</h1>
<p>I hope the example bicep file and example deployment task were useful to you! This is just the tip of the iceberg if you want to use Bicep in your CI/CD pipelines! In this article we explored deploying with Azure Pipelines, but you can also use Bicep in GitHub Actions! I’ve provided some additional reading material. And remember—when working with Bicep, the official Microsoft documentation is your best go-to guide.</p>
<p>Happy deploying!</p>
<h1 id="heading-resources">Resources</h1>
<ul>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/">Bicep Documentation</a> (<a target="_blank" href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/">https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/</a>)</p>
</li>
<li><p>Deploy Bicep files by using GitHub Actions (<a target="_blank" href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deploy-github-actions?tabs=CLI%2Cuserlevel">https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/deploy-github-actions?tabs=CLI%2Cuserlevel</a>)</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[An April Fools’ Party or a Royal Gathering?]]></title><description><![CDATA[Step into the world of the most famous Wallachian hero, Vlad the Impaler, and his wife, who time-traveled to meet the Tudors. They were known for their strange antics, like Henry VIII, the king with an insatiable appetite who loved disguises.
At our ...]]></description><link>https://blog.codechem.com/an-april-fools-party-or-a-royal-gathering</link><guid isPermaLink="true">https://blog.codechem.com/an-april-fools-party-or-a-royal-gathering</guid><dc:creator><![CDATA[Jasna Mishevska]]></dc:creator><pubDate>Wed, 03 Apr 2024 13:10:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1712144099256/8e868c2f-79ed-4930-b8a6-3261c5bc693f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Step into the world of the most famous Wallachian hero, Vlad the Impaler, and his wife, who time-traveled to meet the Tudors. They were known for their strange antics, like Henry VIII, the king with an insatiable appetite who loved disguises.</p>
<p>At our recent party, our colleagues reflected this Tudor theme with a Romanian accent through their costumes, looking so convincing that they could have easily traveled back in time. Their hilarious costumes won the best group costume award for April Fools' Day.</p>
<p>Are you sure this isn't Elizabeth I in the pictures? :) Or her mother, hand in hand with her husband, accompanied by the striking beauty of Vlad’s wife and Vlad himself?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712144161888/c4e9e7bd-82ed-4372-b1f6-302bf0df502e.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712144171463/b01a5d4d-94ad-4cbd-9674-68dad8a687db.jpeg" alt class="image--center mx-auto" /></p>
<p>The party had this cool Western theme going on, with cowboys tossing their hats around. And can you believe it? We could still hear Mandark's laughter, Dexter's biggest rival, echoing throughout the place. Are we still in Dexter’s laboratory?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712144237363/f56f21a6-65dd-48bc-827f-d3b3c4f78b8a.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712144684114/96e9c51d-5650-4bd8-9e32-0edb7fb4692a.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712144887580/8a83e3b6-a253-402b-bc06-248546f9044a.jpeg" alt class="image--center mx-auto" /></p>
<p>There was also an Asian corner where we got to experience some traditional clothing. Oh, and not to forget the Lipton tea group mask that brought nature to us while we had to keep an eye out for the pirates, who are known for their bad behavior of stealing stuff.</p>
<p><strong><em>Kаде ми е HDMI кабелот? Кој го украде донглето од конференциска?</em></strong></p>
<p>Ahoy!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712144797909/b4c976c4-df8b-4ebf-9c1d-4c7064998169.jpeg" alt class="image--center mx-auto" /></p>
<p>We won't spill the beans about this year's best individual costume award, as we don't want to be kicked off social media, but let's talk about the awesome things these people did to make the event even more unforgettable!</p>
<h2 id="heading-a-mixology-station"><strong>A mixology station</strong></h2>
<p>Yup, the cocktails were out of this world! Our very own personal cocktail expert created a custom menu for us, and it was all just perfect. The music was on point, too - our famous DJ had us all dancing and singing along to his amazing playlists.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712144923672/9163fa05-8195-4dba-8bf7-66778bc20233.jpeg" alt class="image--center mx-auto" /></p>
<p>Let's not forget our show master and judoka—he definitely won the crowds with his hilarious jokes and incredible hosting skills. But then, out of nowhere, Hermione showed up and cast a spell, <strong><em>"*</em></strong>Evanesco!"* that made us all go home and disappear.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712145059290/c0768abe-9228-404e-8a8d-1efd72ddae0a.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1712145268525/72a1e8a7-b261-4647-b9ab-02fa20032dc0.png" alt class="image--center mx-auto" /></p>
<p>It's amazing, don't you think? CodeChem is hosting many important events, including Open Day, which will be held on May 11th this year at our offices. This is our biggest event and is an excellent opportunity for students in their 3rd or 4th year of study, especially those looking for internships and employment.</p>
<p>If this blog post made you want to be present on our April Fools' Day, or if you believe our culture and vibe match your skills and education, be sure not to miss the registration link for Open Day, which we will share very soon!</p>
]]></content:encoded></item><item><title><![CDATA[Global Game Jam 2024 Retrospective: Pushing the Boundaries of Creativity]]></title><description><![CDATA[A few weeks ago, our brave engineers set on a quest to unravel the mysteries of their creative abilities, and now their conclusions are something to reckon with. Well, this is their story!
January has finally passed, and besides being so long and a m...]]></description><link>https://blog.codechem.com/global-game-jam-2024-retrospective</link><guid isPermaLink="true">https://blog.codechem.com/global-game-jam-2024-retrospective</guid><category><![CDATA[Game Development]]></category><category><![CDATA[Game Jam]]></category><dc:creator><![CDATA[Jasna Mishevska]]></dc:creator><pubDate>Fri, 23 Feb 2024 15:17:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1708700600688/3a8642d9-5a86-40fb-991d-aab073cc712c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><strong>A few weeks ago, our brave engineers set on a quest to unravel the mysteries of their creative abilities, and now their conclusions are something to reckon with. Well, this is their story!</strong></p>
<p>January has finally passed, and besides being so long and a month of empty pockets, we still have some great news to share. The Global Game Jam happened during the last week of January in Base42 - a mystic hackerspace that seems to be the place everyone’s crazy about.</p>
<h2 id="heading-intro">Intro</h2>
<p>For everyone unfamiliar, Global Game Jam is a worldwide event where participants gather to create games for fun. Game development enthusiasts from various backgrounds gather to create games in 48 hours. Organized by the Macedonian Game Initiative, this year's event brought together many newcomers, but also participants who attend every year. A small group of CodeChem’s crew also participated in the event, making it even more eye candy.</p>
<p>Read on as we are going to unroll some exciting events. Did our engineers push their limits? What were their goals, and who won what? Nope, we won’t reveal it. Sorry, but you must read this till the very last line of this blog post. I bet you have five minutes to spare and read something spellbinding.</p>
<h2 id="heading-the-layer-underneath-the-jam">The Layer Underneath the Jam</h2>
<p>Let's dive deeper into the jam-packed action!</p>
<p>Picture Base42 buzzing with energy, the air thick with anticipation as participants eagerly awaited the announcement of making teams and an official start, setting the stage for what was to come. This time, the globally announced theme was revealed a week or so before the event:  “Make Me Laugh,” and we bet everyone did.</p>
<h2 id="heading-the-interviews">The Interviews</h2>
<p>When we interviewed the guys and asked them how they felt and what they thought of the event, we got one mutual answer: the atmosphere was crazy good, and this even came from Tomislav, who attended GGJ for the fifth time. They were all amazed by the event's success, but somehow, we managed to put all impressions in one place. As you continue to read, you'll have the opportunity to witness firsthand the incredible work they accomplished during the event.</p>
<h3 id="heading-team-lama-laughter-lord">Team Lama - Laughter Lord</h3>
<h4 id="heading-the-best-dev-gjorgji-dimeski">The Best Dev: Gjorgji Dimeski  🏆</h4>
<p>Gjorgji was surprised to find himself exceeding his expectations in so many areas of gameplay implementation. He was particularly happy that “Laughter Lord” perfectly embodied the "Make Me Laugh" theme with a certain amount of humor and wit. Although Team Lama was randomly chosen, this multiplayer browser game won an award, “The Best Dev,” in other words, team Lama used the best technologies for this Game, such as llama2, nest.js, angular, Tailwind CSS for animation, and so on.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708697016954/b1d225a1-e9e9-40e2-bb15-3f12abc3029d.jpeg" alt class="image--center mx-auto" /></p>
<p>The story revolves around a thrilling face-off between two players who battle it out by delivering humorous jokes that can make the powerful Laughter Lord chuckle. The game features a simple and user-friendly interface, where players can write their own jokes and unleash them on the Laughter Lord, each trying to top the other with their comedic skills.</p>
<p><img src="https://lh7-us.googleusercontent.com/6TYm7O85qspEIeTidlj0L6vbzebLqjFW3m0dduJH_rCPaMfQZfPPZ-nCneYATVUA-PHCU1jicu0v_h1ppnYNAOOmxO9pPtwXbsbPNWLZYSxRhcPjM7evn2WXwoc6hLppjbkdkqt78bb2WFcEbCk_OhA" alt /></p>
<h3 id="heading-team-toilet-skibidi-skibidi-toilet">Team Toilet Skibidi - Skibidi Toilet</h3>
<p>Vasilaki's journey into Game Jam was quite unique compared to that of the other participants. He hadn't even planned on joining the competition, but something about the excitement in the air drew him in. Sitting on the sofa at Base42, he couldn't help but notice the toilet across from him. That's when inspiration struck - he decided to base his game on a true story and an existing meme where you keep the toilet door shut with all your extremities up. We have to admit - an amazing start for someone who didn’t even know the theme before.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708696661284/b464b044-3301-4541-93dd-12c22199b09b.jpeg" alt class="image--center mx-auto" /></p>
<p>Despite feeling exhausted from a long work day, Vasilaki was determined to turn his idea into a reality. He used his knowledge of blender to create 3D models applicable to Unity and write scripts for them with C#. Unlike some other participants, he preferred to work independently, so he acted as a one-man band throughout the competition. The endgame was so good that Vasilaki still works on Toilet Skibidi at home together with his sister, a talented 3D artist.</p>
<p>Conversely, of being the last to submit the game, Vasilaki brought the best from the day. From lending a helping hand to volunteers to networking with new people, this GJ was a lifetime experience for him. The creative mindset and the way the game turned out led Skibidi Toilet to be a candidate for “The Best Game Award.” It was a challenging but rewarding experience that he will never forget.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708692141287/036d8172-fc4f-4810-8233-36f3ceaa6382.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-team-cbt-laughing-stock">Team CBT - Laughing Stock</h3>
<p>Next on this list is Tomislav Ignjatov, who attended Game Jam for the fifth time. Tomislav has a standard team for this event, so together with his gang,  they nurture this tradition and consider it very important. They even attend similar events to GGJ, and their main goal is always the creativity and the fun times during the event, but most importantly, the ideas that are a great start to be developed in the future.</p>
<p>As mentioned earlier, although attending for the 5th time, Tomislav has never seen such an atmosphere as this year. The place was crowded, but it was tremendous and cozy. Enough about the atmosphere; let’s talk about the game that CBT created.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708696793729/b605ebce-1d21-43ac-ace5-195f76d599fb.jpeg" alt class="image--center mx-auto" /></p>
<p>Laughing Stock is an auto-shooter-inspired game where the main character, an evil Demon Clown, converts the local villagers into minions by throwing balloons at them. In the left corner, you can see the health bar, which shows the status of the balloons, and also you can see the score in the other corner.</p>
<p>The CBT team used different technologies for this game, such as Wave Function Collapse, an algorithm that can generate procedural patterns from a sample image - in this case, a different map - and Godot - an open-source game engine and art by PixelArt. One key takeaway for Tomislav from this event was the importance of borrowing wisdom from other jammers, sharing experiences and techniques to overcome challenges more effectively, and elevating the quality of each game.</p>
<p><img src="https://lh7-us.googleusercontent.com/-g2ukqZFkoQuAZK4PKDSE-h2Hn5s6UEz83XePb5cSEmEOspDf6AjXyH3Em6UV5kGcylqWihBMWfL162h0p916DGM2qYiqZgKONcekUW7FN3OiFlb7rAa7lkVuwAyyYbXhN_cNvRb2J_wl1alHEB2SG8" alt /></p>
<h3 id="heading-team-clumsy-coders-the-last-laugh">Team Clumsy Coders - The Last Laugh</h3>
<p>The last team with the “Last Laugh” in this blog post is Clumsy Coders, where our engineers Angel Stojanov and Stefan Ivanovski created a 2D game together with other game designers and artists. Their team was also randomly chosen, but everyone had a specific role, and for them, the planning of the game and the idea were the driving force of this event.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708696494601/43a04304-3d5e-4e0a-b466-2df9513e4cec.jpeg" alt class="image--center mx-auto" /></p>
<p>The game interface perfectly pictures the story behind it. So, let’s get into this incredible narrative. To be fair, I really liked how Clumsy Coders put together this storyline, so I decided to borrow it! 😊 👇</p>
<p><strong><em>“In a medieval kingdom very far away, a king has been betrayed and murdered by his heir. The former king's ghost is back and attempts to possess the body of the court jester to spread malicious rumors about the new king and have him "canceled.”</em></strong></p>
<p>The Last Laugh is an exciting game where two players compete against each other. The game aims to see who will come out on top. One player is a jester trying to navigate away from a ghostly presence while keeping his head on his shoulders and controlling his bodily functions. The other player is the ghost trying to succeed in his evil plan. The jester must outmaneuver the ghost to win the game.</p>
<p>Stefan and Angel worked on a new game with other team members, including talented designers and artists. Collaborating with Angel, they utilized cutting-edge technologies in C# and Unity to create stunning animations, bringing their vision to life. Things got even more exciting when Stefan and Angel both worked on Unity simultaneously, something they had never done before. They both enjoyed the competitiveness and the freedom to experiment with new ideas during the 48-hour game development process.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708692590530/14b79c01-3740-4596-809c-bd58add64643.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-final-thoughts"><strong>Final Thoughts</strong></h2>
<p>Despite the challenges and constraints, the journey of participating in a Game Jam, as our engineers said, is incredibly rewarding. Whether a student, amateur, hobbyist, or professional, engaging in game jams fosters creativity skills and provides a platform for experimentation and innovation. As everyone mentioned in this blog post aptly puts it, jamming is one of the most worthwhile activities an engineer can undertake, regardless of their skill level.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1708699926209/1b5911cf-4c84-43a4-902c-302ede2729d3.jpeg" alt class="image--center mx-auto" /></p>
<p>In conclusion, the Global Game Jam 2024 was a testament to the power of collaboration, creativity, and community in game development. Participants walked away with awards, newfound skills, valuable connections, and a passion for doing more. Each year, as the event ends, innovation inspires game developers worldwide to take on new challenges and push the boundaries of what's possible in game development. It’s an icebreaker for everyone who feels joy in the gaming world.</p>
<p>As we look back on the incredible games developed by talented jammers behind them, we can't help but be amazed by the gaming community!</p>
]]></content:encoded></item><item><title><![CDATA[‘Tis the Season for Christmas Cooking, Hosting and Gathering]]></title><description><![CDATA[If there’s one thing CodeChem is known for, it’s definitely doing things differently.✨ So, instead of throwing a regular Christmas corporate boring party where employees' kids would have fun with Santa, we poured our hearts out with some Christmas co...]]></description><link>https://blog.codechem.com/cc-cooking-competition-and-secret-santa</link><guid isPermaLink="true">https://blog.codechem.com/cc-cooking-competition-and-secret-santa</guid><category><![CDATA[cooking techniques]]></category><category><![CDATA[Christmas gifts]]></category><dc:creator><![CDATA[Jasna Mishevska]]></dc:creator><pubDate>Wed, 27 Dec 2023 14:22:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1703677487587/df05eddc-d2cc-41ef-8c75-a1e40b5e7e36.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If there’s one thing CodeChem is known for, it’s definitely doing things differently.✨ So, instead of throwing a regular Christmas corporate boring party where employees' kids would have fun with Santa, we poured our hearts out with some Christmas cooking combined with a Secret Santa gift exchange. It was a competition to remember where all the bakers, decorators, video editors, shopping executives, and other team members competed by showing their cooking skills.</p>
<p>Read on, as we are going into full detail about Secret Santa and who won the cooking competition. 👇</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703671861990/29cf1805-cbfc-48f2-a20d-dc3e14e9761d.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703670866339/86acc3d7-0977-4134-9f0b-5391bc8c7a49.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703671511507/9ebee723-04a5-4d65-ba5a-40c51cd1e556.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703671534469/47df04be-410f-4098-a139-37e4b816a079.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-who-could-my-santa-be">Who Could My Santa Be?</h2>
<p>We decked the halls of Base42 with a beautiful light ambiance, presents, and a Christmas tree, creating a warm and inviting seasonal atmosphere. After our working hours, the whole crew went to Base42  and had the gift exchange. Everyone took this task very seriously, and you could feel the suspense and the excitement. Once the gift exchange was over, happy and surprised faces were everywhere, and the holiday joy filled the air. 💕</p>
<p>We decided to skip the public guessing part for Secret Santa 🎁 so that people could discover by themselves. Although some people weren’t thrilled with this decision, we hope you understand that guessing who bought a gift for 100 people would have lasted for hours, and you always have to take into account that there are other activities. After all, the season is about gathering, connecting with your colleagues and friends, and surrounding ourselves with joy and warmth. Plus, a little curiosity never kills anyone! 🤗</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703672338375/3f81137e-b37b-4a19-b436-7bd623c88ff2.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703672354872/e90adabc-9f21-440b-bfdd-e8af695694ad.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703672411563/37da5669-9dbc-423e-8a62-067c14510f35.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703672444063/a45c2d73-65f8-483c-bf78-68e97e7ef267.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703672510705/6cfa9cc5-21cf-465b-a32b-8b156004f2d2.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-the-teams-behind-the-cooking-competition">The Teams Behind the Cooking Competition</h3>
<p>After exchanging presents, we put on our aprons and chef hats. There were seven teams, each representing a different color: blue, orange, green, red, yellow, violet, and indigo. These colors were not chosen randomly, and we'll discuss their significance in some of our upcoming blog posts. Finally, all the teams presented their pre-made Christmas desserts on the table.</p>
<p>Suddenly, the atmosphere transformed into something resembling a scene from a popular cooking show, as if Gordon Ramsey himself would emerge from around the corner any moment.  It was the exact moment when you could feel the excitement and the competitiveness. The level of dedication, hard work, and teamwork required for this competition was truly surprising. The desserts looked impeccable, and when combined with the colorful aprons and chef hats, we resembled the crew of MasterChef.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703672862516/48b723ec-dcc8-46b1-a76a-ae627767759b.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703672977053/6d04ecf6-9270-4e07-a475-3953d1dbebbb.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-judge-mental-much">Judge-Mental Much?</h3>
<p>As we planned for this competition, we decided that the judges should be unbiased, honest, and willing to provide genuine feedback. Who is the most pure-hearted and honest person in this world? Children, of course. Thus, we came up with the idea of allowing our employees' children to become judges. Initially, we introduced them to the voting guidelines, and then they stepped onto the stage, officially introducing themselves to the teams as their judges.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703673120863/132949c5-1add-4143-9561-2b7f7d95b185.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703673165492/506db0c1-f63c-417f-bb30-acdc49737440.jpeg" alt class="image--center mx-auto" /></p>
<h3 id="heading-the-rule-of-three">The Rule of Three</h3>
<p>All the teams had one common goal: to create the most outstanding dessert within a specified budget, select a wine that complements the dessert, and strive to win the competition. The judges evaluated each team based on their teamwork, decoration, and taste and awarded points accordingly. The first and foremost rule of the competition was that every team member had to be actively involved in the dessert-making process, and each person had a specific role to play, ranging from purchasing the ingredients, finding the perfect recipe, decorating the dessert, and so on.</p>
<p>It was enjoyable to overhear people discussing their cooking plans, what they would make, and who would bake. It was heartening to witness the level of enthusiasm and dedication everyone had, to the extent that some teams even held meetings to plan their cooking strategies. The dessert was made one day before the event, and each team made videos of the cooking process, proving the teamwork and that the dessert wasn’t bought from a confectionery (because everything looked so good).</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703673362358/fce8f3fe-41a6-417a-a435-6d858bc89a73.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703673373165/9633810c-bc41-4bfd-8067-64dc677ce100.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703673406915/56df4922-7712-41b5-a661-cdc3aebad594.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703673445612/d315e4fe-6496-4a76-9114-8e44590619a0.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-special-thanks-to-the-video-editors">Special Thanks to the Video Editors</h2>
<p>Some videos were very professional, and some team members stood out from the crowd with their teamwork. Whoever made the video did a great job and left the judges impressed. After watching the videos of all the teams, the judges went around the table and carefully examined the decorations of each team. From gingerbread houses, winter wonderland brownies, Christmas cookies, Christmas tree muffins, chocolate snowmen, and pinecones, everything looked so magical that everyone enjoyed just watching it.</p>
<h2 id="heading-a-recipe-has-no-soul-your-team-has-to-bring-soul-to-the-recipe">A Recipe Has No Soul, Your Team Has to Bring Soul to the Recipe</h2>
<p>There is one popular quote among famous chefs: <em>“If you are a chef, no matter how good a chef you are, it's not good cooking for yourself; the joy is in cooking for others,”</em> and we somehow got stuck to it. 🌟❣️</p>
<p>The judges stepped away from the table and moved to another room to award points to the teams for their teamwork and decorations. Despite being young, they were very strict and made decisions quickly. Still, they got silly questions like, <em>“Why are your gingerbread cookies painted red? Is that blood?” “Why is my father not included in the cooking? Is it because he really doesn’t know how to cook anything?” “Why are you lying to us that you are covering your gingerbread house with snow? We are adult enough to know that it’s icing sugar?” “Are those ghosts? Isn’t this a theme for Halloween?”</em> which made the competition even funnier. 🤣</p>
<p>After a long day of judging, the judges became exhausted and hungry. They took a break to evaluate the final round based on taste. Each judge tasted every dessert before returning to the voting area to score them. It was a difficult decision, but eventually, they came to a conclusion.</p>
<p><img src="https://lh7-us.googleusercontent.com/Nc_wJGwxwxSt_QkyW96OooHhnkMdwDRNOavfR89QJc718TwzdJJINI0Qq79zzBcd40AF6HOgeOuvBBFcmAg8p5NVD-r2p6Fz-WDdXdnMCH0ydf1tMVzF9siVFIdoeCWAbLZ03fDwA9rBQWKY04maFzg" alt /></p>
<h3 id="heading-the-verdict-golden-silver-and-bronze-spoons">The Verdict: Golden, Silver and Bronze Spoons</h3>
<p>After making the decision, the judges ran back among the teams to claim the winner, the team with the best dessert in taste, decoration, and teamwork.</p>
<p><strong>1st Place:</strong> The blue team won, so they got the first prize in the cooking competition, wine degustation in one of our local wineries, + their golden spoon  (actually a wooden spoon with a golden ribbon, but let’s pretend it was a golden one 😀).</p>
<p><img src="https://lh7-us.googleusercontent.com/GPYG1E4Wke4h8sNfhBeMlsL3KHuwknXVaR54JporoFxLPc69hj92-thl6550QRG3iClZEu8f-fv2dAClIGUxk8sxFh81crlHDdligXNP6i0yyct8rn9nShW9FG-UGWg0SL5ODc6mLS0bb6PB5V603W8" alt /></p>
<p><strong>2nd Place:</strong> The indigo team came in second place, but the judges noted that although their decoration was excellent, their muffins were dry, which prevented them from winning the top prize. They received a free meal day and a silver spoon as a consolation.</p>
<p><img src="https://lh7-us.googleusercontent.com/_iv1UxR1dS72h0teUvKfmqMiRbad12RKzYh5jGARBOGo0fkoUMa4RDayzIAEoo_VJq8TbIDImKB_d7ESEzezsJsRkOAIsFSNEtzz2SNHYbFsrxmyWpEylpDRKChY4rO9KbJxbnnepY-9cE97bR1_kKw" alt /></p>
<p><strong>3rd Place:</strong> Finally, the announcement for the third-place winner was made. The orange team was awarded a recipe book and a bronze spoon for their impressive gingerbread house. Despite the elaborate design and delicious taste, the judges didn't award them a higher position because they felt deceived by the snow on the cake, which was clearly made of icing sugar.</p>
<p><img src="https://lh7-us.googleusercontent.com/qqzV8rtVf5j_BcQ7q4MgaNFal076PDWCvEyvYgczKd_64VaUwe6xDnnabPBsOetBc6poxX-46Fm8ggKF8TZkB_YFZjagVJJZX5WWcTc2K0FTlkAZFN1SGksGxoe-pijnLynyCZhOY1t3BGWkU88vuc8" alt /></p>
<p>The judges had a tough time choosing the winners because each team put in their best effort, but ultimately, they felt that the blue, indigo, and orange teams had won their hearts.</p>
<h3 id="heading-the-ultimate-battle-of-best-dessert"><strong>The Ultimate Battle of Best Dessert</strong></h3>
<p>After claiming the winners of the competition, we were all invited to try out the desserts and drink some wine that the teams bought with their desserts and some soft drinks and snacks for our young judges who got tired from the competition because it was exhaustive and hard to decide. While trying the desserts, everyone was invited to vote for the best dessert, excluding their own team.</p>
<p>After counting the votes, we declared the green team the Best Dessert Award winner and awarded them a Michelin Star. Their chocolate snowmen were incredibly delicious, and we couldn't resist having more of them in the following days.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703675243858/3beef262-464a-4a17-807e-8653fef197ff.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-catching-snowballs">Catching Snowballs</h3>
<p>The competition ended with a silly game where the participants had to gather cotton balls from a table using a spatula while their eyes were sealed. The winner was the one who gathered the most cotton balls. However, the interest in the game could have been higher, as people were more curious to find out who their Santa was and what gift they had received.</p>
<p>Nevertheless, the organizer forgave the lack of enthusiasm, as the event was already long enough without this part. After the game, some crew members stayed behind, and the night continued with karaoke and music.</p>
<p><img src="https://lh7-us.googleusercontent.com/OXeGcVM29hCTn_3jE9Nr1AW786Lpy9Dt_nCFZZ3-70GUGxh0G8IWDdblgQVHJpIHy0LINiMtg3SMxulNYbZem-fxS4X-4p5OxFFwSTq8tjUuwiP--nsYS4QyPBGWN_OS8P9f2biXM_0VY3r6FsOfutw" alt /></p>
<h2 id="heading-final-touch">Final Touch</h2>
<p>Long story short, regardless of who won, you proved again that you are all amazing. Creating a dessert as a team, with a limited budget, that is both impressive and visually appealing enough to capture a child's imagination is exceptionally challenging. So congratulations on your hard work and creativity and for showing respect and participating in this event. Keep nurturing these values; combined with your work, you will someday conquer the world! 💕👏🏻</p>
<p><img src="https://lh7-us.googleusercontent.com/mn0qshkXB4MnulyG8fg3ZuIPqUaW6ojOHAytptO91u1ebVaFX-qHvznmbQmnwdk467JEScJQ4Ik9edA456sYs_Fi7wQNBUmQJdrikmaEJeEvdt_VK0r28sxhd6DXY6PBdHVzRd_Lx-KmzjJJD4qxIIY" alt /></p>
<p><img src="https://lh7-us.googleusercontent.com/WsEPQ_xrt4Q6yfhM-szZ3JVzBVuRmZTlrlC8-fCXFy_zG8n4USATO6HxejV2jQkgGDtD3SfUKwkLApIRqG6iWBsj-qYcAdvsew9lFhHqQu46Y3Loh1s77PUxGpHmhW2hesh4bmLzo2nAt1Mh_H5H-ro" alt /></p>
<p><img src="https://lh7-us.googleusercontent.com/_TDrwfbe_6glGlXXba4h2ZhxKUGOaXTY3VbwGEZrOK8d3mC7A1J-Fc8LfQdnE1d5P9w7dy6QndT2hT3c7OMvgrakojyCnBdcjS1bqn4Sx7bDokdSrsuPzVI4oYB1DTFWbA7mNctRWJgftxo87TTKp1Q" alt /></p>
<p><img src="https://lh7-us.googleusercontent.com/g-YO31Q5I1YZqMjX1Lg6MTB_HfZOELV3U4B8WTR2oDfQGRkIuIJih31gtCkpsG9ZcXeM5n-Lj77iLXpS7XBKPuESvDSknYkPPP5creHJwLGiaD5c86kPXcTOyxOJIU53kEoolJnBDbQvJhCCxKmAG0A" alt /></p>
<p><img src="https://lh7-us.googleusercontent.com/OXouZZF3gGOFMHND27ZDJohsSqmvh9KTQNtYX5hFp6fZV2NSBkbd018fpfBQ_e-kb1tesJGp2JFH4EcxUoma-IgkYrgqbn1b_RAaq2CbDNueimqZ5GTOlDJfTlM1NMgrSe4EopGIXuJsiZKcWZP7CCE" alt /></p>
<p>As this is our final blog post for this year, we are extremely optimistic as we set our sights on 2024. ‘Tis the season to be jolly, and we are certainly spreading the joy! 🎄 We can't wait to see what the future holds! 🌟</p>
<p>See you next year!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703676969424/72678070-8313-487b-97f1-d3a565b8220e.jpeg" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[But it works on my machine?! ONNX 101]]></title><description><![CDATA[PyData Skopje Chapter
After a significant pause of this chapter, it's finally revived. So, if you are located in close geographic proximity or are interested in remotely following the events, join the official Meetup Group.
Reflecting on the exhilara...]]></description><link>https://blog.codechem.com/but-it-works-on-my-machine-onnx-101</link><guid isPermaLink="true">https://blog.codechem.com/but-it-works-on-my-machine-onnx-101</guid><category><![CDATA[Python]]></category><category><![CDATA[PyData]]></category><category><![CDATA[Machine Learning]]></category><dc:creator><![CDATA[Aleksandar Ivanovski]]></dc:creator><pubDate>Thu, 07 Dec 2023 13:18:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1701955150740/5a228907-d4e5-4613-90ab-25bac7d19a1a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-pydata-skopje-chapter">PyData Skopje Chapter</h2>
<p>After a significant pause of this chapter, it's finally revived. So, if you are located in close geographic proximity or are interested in remotely following the events, join the official Meetup Group.</p>
<p>Reflecting on the exhilarating experience of spearheading the community's revival during the first event post-hiatus! It was an honor to contribute to reigniting the community spirit. Our exploration into the realms of interoperability and operationalizing ML models with <a target="_blank" href="https://onnx.ai/">ONNX</a> was truly rewarding.</p>
<p>The added excitement of delving into the seamless deployment capabilities offered by <a target="_blank" href="https://onnxruntime.ai/">ONNX Runtime</a> made this journey unforgettable. A heartfelt thanks to everyone who joined the discussion, and let's look forward to many more insightful conversations on the horizon!</p>
<h2 id="heading-synopsis-of-my-talk">Synopsis of my talk</h2>
<h3 id="heading-challenges-taming-the-complexity"><strong>Challenges: Taming the Complexity</strong></h3>
<p>First off, let's acknowledge the challenges we face in the ever-expanding universe of deep learning. Multiple frameworks like TensorFlow and PyTorch, coupled with varied training accelerators (think T4 GPUs and VPUs), make the landscape intricate. This is where ONNX steps in, initiated by tech giants AWS, Microsoft, and Meta. It acts as a unifying force, providing an abstraction layer over frameworks and hardware, reducing the complexity of integrating these different components.</p>
<h3 id="heading-design-principles-flexibility-and-standardization"><strong>Design Principles: Flexibility and Standardization</strong></h3>
<p>ONNX isn't just another acronym; it's a set of design principles supporting both deep learning and traditional machine learning. These principles aim to be flexible enough to keep up with the rapid advances in AI while providing a standardized, cross-platform representation for serialization. Imagine it as the Common Language Runtime for programming languages, minimizing the number of moving parts in the deep learning landscape.</p>
<h3 id="heading-understanding-the-onnx-specification"><strong>Understanding the ONNX Specification</strong></h3>
<p>So, what's under the hood of ONNX? The ONNX specification reveals a structured format where each computational graph is a directed acyclic graph. Nodes represent inputs, outputs, and operators, with metadata documenting crucial details about the model and its production environment. Data types, including tensor types and non-tensor types in ONNX-ML, showcase the framework's versatility.</p>
<h3 id="heading-operators-the-essence-of-onnx"><strong>Operators: The Essence of ONNX</strong></h3>
<p>Now, let's talk about operators – the heart and soul of ONNX. These are defined by name, domain, and version, encapsulating the essence of various operations. Take, for instance, the Relu and Abs operators, which I'll be diving into during the presentation. These examples demonstrate input-output relationships and type constraints, showcasing the elegance and power of ONNX.</p>
<h3 id="heading-practical-demos-bridging-theory-and-application"><strong>Practical Demos: Bridging Theory and Application</strong></h3>
<p>Enough theory; let's get hands-on! In <a target="_blank" href="https://github.com/Aleksandar1932/onnx-101/blob/master/onnx_workshop/mnist.py">Demo 1</a>, we'll walk through defining a PyTorch model, training it, exporting it to ONNX, and visualizing the resulting graph. The practical application comes to life as we tackle a real-world problem – training a classifier for the MNIST dataset using a convolutional neural network in PyTorch.</p>
<h3 id="heading-onnx-runtime-bridging-the-gap"><strong>ONNX Runtime: Bridging the Gap</strong></h3>
<p>What about deployment? Enter ONNX Runtime, the bridge between the ONNX file format and deploying the graph on different hardware. Microsoft takes the lead here, maintaining ONNX Runtime as a distinct project from the ONNX specification governed by the Linux Foundation AI.</p>
<p><img src="https://lh7-us.googleusercontent.com/itmyqmU7sL1uzxaTcVQ1faj1gET1ZvsRPkflAtsTwia1c5XRcgtz7wZ2P-JCqmA1LftUw8hsS5hXbluyy6Z40Ams3bJfFaISWwS9g6DgS_jZlX9JR6zh9DUO8NKjGUmF9s0yA0jpyE7fEgrg_OrofpKHKw=s2048" alt class="image--center mx-auto" /></p>
<h3 id="heading-interoperability-onnx-in-action"><strong>Interoperability: ONNX in Action</strong></h3>
<p>But ONNX isn't limited to theoretical discussions. We'll explore interoperability, touching on the ONNX Model Zoo, Azure Cognitive Services, and methods to convert existing models or train from scratch. Practical tools like Netron and VisualDL will be your companions in understanding and visualizing ONNX models.</p>
<h3 id="heading-demo-2-onnx-in-the-real-world"><strong>Demo 2: ONNX in the Real World</strong></h3>
<p>The finale? <a target="_blank" href="https://github.com/Aleksandar1932/onnx-101/tree/master/ort-web-api">Demo 2</a>, where we take the model from Demo 1, integrate ONNX Runtime in JavaScript and build an inference REST API with Express.js. This real-world application underscores ONNX's cross-language applicability, bringing everything full circle from theory to practice.</p>
<h3 id="heading-join-the-onnx-adventure"><strong>Join the ONNX Adventure</strong></h3>
<p>I'm beyond excited to share this ONNX adventure with you. Whether you're a seasoned deep learning enthusiast or just dipping your toes into the data science world, this journey promises to offer insights, practical knowledge, and a newfound appreciation for the unifying force that ONNX brings to the table.</p>
]]></content:encoded></item><item><title><![CDATA[The Table Titans in CC 🏓 Tournament 2023]]></title><description><![CDATA[Did you know that the first version of ping-pong was played on a dinner table, with books serving as the net? Years later, J. Jaques & Son Ltd began selling it under the name "Ping-Pong” which means moving back and forth rapidly from one place to ano...]]></description><link>https://blog.codechem.com/the-table-titans-in-cc-pingpong-tournament</link><guid isPermaLink="true">https://blog.codechem.com/the-table-titans-in-cc-pingpong-tournament</guid><category><![CDATA[tournament]]></category><category><![CDATA[Pingpong]]></category><dc:creator><![CDATA[Jasna Mishevska]]></dc:creator><pubDate>Tue, 21 Nov 2023 13:48:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1700568106690/b8ffdec3-dd7b-487f-bc8b-207de4ffb447.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Did you know that the first version of ping-pong was played on a dinner table, with books serving as the net? Years later, J. Jaques &amp; Son Ltd began selling it under the name <strong>"Ping-Pong”</strong> which means moving back and forth rapidly from one place to another.</p>
<p>As we rapidly move at CodeChem, we encourage engaging in extracurricular activities that add some fun to our routines. In that matter, for the second year in a row, ping-pong has generated a surprising interest among our team members.</p>
<p>Join us in this blog post as we pull back the curtain, inviting you to step "behind the scenes" and enjoy the best moments of our latest ping-pong tournament.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700568229173/9142b47b-57fa-4ae4-a4d9-cb06fba9fe20.jpeg" alt="This image contains two players playing ping-pong on a table. There is one person standing behind them and two persons having a conversation. The area is filled with chairs and desks. " class="image--center mx-auto" /></p>
<h2 id="heading-the-very-beginning">The Very Beginning</h2>
<p>It all started a few years ago when everyone was working. Back then, you could often hear the sound of a bouncing ball echoing through the hallways, and even today, we can still hear it (it's pretty funny, actually). That was the first sign that we had a group of people who absolutely loved playing ping-pong.</p>
<p>As always, we had to do something about it, and that’s how the idea of our first CC tournament came. Our first official ping-pong tournament happened in 2022 in Hazard, an excellent pool billiard club in Skopje, but this year, the tournament occurred in Base42, which is way more private and a perfect fit for this event.</p>
<p><img src="https://lh7-us.googleusercontent.com/7xtNLpPtP_JpsOzI65WzJwcaxBpzjb0yQERnN2HUc2VYb18GK4oAXq8x4ynB6TxzqTtKApiTtdvCdLtspIhMdBEs-P5usdzxVF9p0Ddz_e2UPnNNIOdpCmQph1NfToyaKGaXlMrHqkwdfG5ohCKapK4" alt /></p>
<h2 id="heading-new-faces-new-places">New Faces, New Places</h2>
<p>We are constantly growing and learning from each other. While our main focus is software engineering, we always remember about knowledge-sharing, which often comes in different segments, including our hobbies. During 2023, many new faces joined CC, and thus, we welcomed fresh faces to our ping-pong crew, by whom our squad has significantly grown. That’s why we put an accent on our fun zone in CC, where one of the key elements is our ping-pong area.</p>
<p>Suppose you ask one of the players why they love playing ping-pong so much. In that case, you’ll probably get a variety of answers like it makes them feel relaxed, they measure their strength, they cannot wait to inspire other players, or compete with the most successful ones, but you’ll get one mutual answer for sure: ping-pong connects people, makes them laugh, makes them focus, and they all can compete, bond and have fun while cheering.</p>
<p>Whether you are a coach, a player, a colleague who came to watch the tournament, or even someone who came just for the beer and snacks, you all have the spirit of sportsmanship.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1700569268299/c2f25e82-b981-4e49-b755-fdb5af4a59cb.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-the-serve-ivors-and-winners">The Serve-ivors and Winners</h2>
<p>Everyone who participated in the tournament should be proud of themselves, even if they didn’t make it to the next match. We had 16 participants in total, and throughout the matches, we could all feel the excitement and competitiveness because of the unexpected and tight results. There were moments when we didn’t know what would happen till the very last second.</p>
<p>Although ping-pong appears to be a simple game, in reality, it requires great skill and focus, evident from the concentration and perspiration visible on the players' faces as they all strive for victory. We always value courage, honesty, fairness, and competitiveness at CC; according to that, the tournament ended with one trophy and three certificates.</p>
<p>Our colleagues Aleksandar Mirchovski and Kosta Halicea won third and second place, respectively. At the same time, Mino Todorov triumphed in the tournament and will keep the trophy of 1st place till our next CC ping-pong tournament. Everyone else who participated in the tournament was excellent, especially Aleksandra Gjurova, who won 4th place.</p>
<p><img src="https://lh7-us.googleusercontent.com/C7-EyF-mKHskL-swJuM_Zd3Mpj3mpEIYDX8r2-6HNxq7X5EPoLaCf0GMsJJ_-GJe8adxCbnFFiM_HasF_GepyooxtTTKYdHEwD06O35CCJ6tFZAm5ouw9UBd3QXdRYXNdKIWNL_9d6yq85_TIqJ9Xh4" alt /></p>
<p><img src="https://lh7-us.googleusercontent.com/awcxtQMg4LYVjZQcsGwyZbSTNwVOROS9c7tcxjLru5DiANcdMWyZxng4xB3tJ12vMJakuAtHMTB748X6rqb5tobNobv_wEI5aF_6XXuzq4rkcWH88q_obTbG6HYwzTl6sU0B-J5O_GMPGlpiOKRWB1E" alt /></p>
<p><img src="https://lh7-us.googleusercontent.com/grICFeybjFhnDry8FenUogo4KJ5VTyiXvoot5sCSVLsPKsTOZSzsigS1GR2oyQbj0OCZpyBYzSLUGttZue-70jIRFrL1iTEgP0ML1JmxBM_pfjeYkV-kzGt6ZMXobIa5a81Ji9ktLThpmjXjdkizCPU" alt /></p>
<h2 id="heading-judges-and-organization">Judges and Organization</h2>
<p>The tournament wouldn’t have gone smoothly without our professional judges, who kept the atmosphere funny but professional at the same time, keeping the scores and results up-to-date all the time and monitoring each step of the tournament. It was so good, as if Mills Bee Lane was speaking.</p>
<p><img src="https://lh7-us.googleusercontent.com/9sIQZR8inSC7G1uolcR1VOBL7ezyET95Vtj0-saMFzRJGy5BdEiQrf4_bq9zXyWIOVTDrIY6WY0_Oi2cQX8jKOWv940aIt7_zJ6K1C4HBFtKmYSSe9HS2RtqOLEQZBUFxuFetbT8CMm7dZxYGJy8NxM" alt /></p>
<p>Besides the judges, there was an excellent organization from Pale who delivered the certificates, food, snacks, and everything equipped for the tournament in Base42. You must love Base42, an awesome space for awesome people (ping-pong intended), but without Pale nothing would have been possible, so big thanks to her.</p>
<h2 id="heading-practice-what-you-preach">Practice What You Preach</h2>
<p>Our second official ping-pong tournament ended, but we won’t stop playing, practicing, and having fun. There’s no victory without training, getting new experiences, and adding a unique playing style to beat your opponent.</p>
<p><img src="https://lh7-us.googleusercontent.com/YeMyevEOHE_JZUauehR63zEDfHhhDzxSNuVwKfBmkZuFFb08aIw8SFDjMkiZ3CBLE0fgmntwq8mdO87w7skLY3sC4y7Lk98bihz5IRG-MSumID6z9NAJNqjWaNm8J7fX1pvpO6NC0cIeFBCWW2j8i50" alt /></p>
<p>Our ping-pong tournament is just another way to get to know your colleagues well and bond over something you both have a passion for, and we cannot wait till our next one.</p>
<h3 id="heading-winners-statement">Winner’s Statement</h3>
<p><img src="https://lh7-us.googleusercontent.com/p54DOCV3HCMmFwmgZudyQSQdktPVyPttQuGcGKyscD0pVng-GKfWxeHkEZrNZAPyUOq0OI3UNY3c3qpiJy2vQCoeWeegg4ULeudie5EDe-GgA2T1j881MVR8R3dFhPxn-17tLZkNakpEnRZ_UZsfhsc" alt /></p>
<p><em>Interviewer: What does playing ping-pong mean to you, and how do you feel after winning 1st place?</em></p>
<p><em>Mino: It's a fun way to take a break and use some trash talk</em> 😃. I really enjoy it, especially the long rallies ending with a full-power smash. And the sound of the ball is relaxing. Given my competitive nature and love for winning, it was satisfying and felt great 😊.</p>
<p>Stay tuned until the next serve and victory as CodeChem's ping-pong journey continues! 🏓🎉</p>
]]></content:encoded></item><item><title><![CDATA[Managing Azure Services & Resources]]></title><description><![CDATA[In this article, as part of our IT Infrastructure as Code series, we're going to explore the three fundamental building blocks for managing your resources on Azure:

Azure Resource Manager

Azure Resource Provider

ARM Templates


Note: ARM is an acr...]]></description><link>https://blog.codechem.com/managing-azure-services-resources</link><guid isPermaLink="true">https://blog.codechem.com/managing-azure-services-resources</guid><category><![CDATA[#azuremanagedservices]]></category><category><![CDATA[ARM]]></category><category><![CDATA[#IaC]]></category><category><![CDATA[#azuretemplates]]></category><category><![CDATA[#BicepDSL]]></category><dc:creator><![CDATA[Marko Spasenovski]]></dc:creator><pubDate>Tue, 24 Oct 2023 14:42:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1698159352730/a11491f1-6cfd-42fa-b1fd-ec89287b8cd6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, as part of our IT Infrastructure as Code series, we're going to explore the three fundamental building blocks for managing your resources on Azure:</p>
<ul>
<li><p>Azure Resource Manager</p>
</li>
<li><p>Azure Resource Provider</p>
</li>
<li><p>ARM Templates</p>
</li>
</ul>
<p><em>Note:</em> ARM is an acronym for Azure Resource Manager.</p>
<hr />
<h1 id="heading-azure-resource-manager">Azure Resource Manager</h1>
<p>The <strong>Azure Resource Manager</strong> is the official deployment and management service for Microsoft Azure. It provides a layer that enables you to manage (create, update, delete) different resources in your Azure account.</p>
<h2 id="heading-benefits">Benefits</h2>
<p>Let's take a look at some of the benefits that this service offers:</p>
<ul>
<li><p><strong>Declarative templates instead of scripts:</strong> Consistent state amongst deployed resources is guaranteed as your app infrastructure and dependencies are defined in a single declarative template</p>
</li>
<li><p><strong>Improved management and organization of resources</strong>: No more piece-by-piece deployments of your app and manually stitching them together. Resources with a common lifecycle are grouped in a <strong>resource group</strong> that can be deployed or deleted in a single action. You can see which resources are linked by a dependency and/or categorize resources by tags for management tasks (e.g., billing)</p>
</li>
<li><p><strong>Authorization</strong>: ARM offers control access to resources. You control who in your organization can perform actions on any resource. Permissions are managed by defining roles and adding users (or groups of users) to those roles. ARM logs all user actions so you can audit those actions</p>
</li>
</ul>
<h2 id="heading-basic-terminology">Basic Terminology</h2>
<p>In the previous section, I mentioned something called a resource group. Before we continue, let's explain some of the most basic terminology you'll need to understand when working with the ARM:</p>
<ul>
<li><p><strong>Resource</strong>: Manageable items such as virtual machines, storage accounts, web apps, databases, etc., are regarded as resources. As strange as it may seem, resource groups are also treated as resources.</p>
</li>
<li><p><strong>Resource group</strong>: As the name implies, a resource group is a container that holds related resources for an Azure solution. For example, you usually include all your resources related to a single application deployment in a resource group. This might include an app service, static web app, app service plan, SQL server &amp; database, etc.</p>
</li>
<li><p><strong>Declarative syntax:</strong> It defines "what" we want to happen; we don't care how it happens. ARM templates and Bicep files are examples of declarative syntax.</p>
</li>
<li><p><strong>Bicep file</strong>: A file for declaratively deploying Azure resources.</p>
</li>
</ul>
<h2 id="heading-management-layer">Management Layer</h2>
<p>ARM is the middleman between different access routes to Azure services and the actual resources.</p>
<p>Here's an image that better illustrates this:</p>
<p><img src="https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/media/overview/consistent-management-layer.png" alt="Diagram that shows the role of Azure Resource Manager in handling Azure requests." class="image--center mx-auto" /></p>
<p>No matter how you try to access Azure services &amp; resources, whether through the Azure web portal, the Azure API, CLI, or SDKs, the <strong>Resource Manager intercepts all requests</strong>. It authenticates and authorizes the request before forwarding it to the appropriate Azure service.</p>
<p>Because all requests are handled through the same API, you see consistent results in all the different tools.</p>
<h2 id="heading-scope">Scope</h2>
<p>Azure provides four levels of scope:</p>
<ul>
<li><p>Management groups</p>
</li>
<li><p>Subscriptions</p>
</li>
<li><p>Resource groups</p>
</li>
<li><p>Resources</p>
</li>
</ul>
<p>The most common scopes used are <strong>subscriptions</strong> and <strong>resource groups</strong>.</p>
<p>We can deploy templates to tenants, management groups, subscriptions, or resource groups.</p>
<p>It's the first time we mentioned tenants, so I'll quickly explain what tenants are:</p>
<ul>
<li><p>An Azure AD (Active Directory) tenant is a reserved Azure AD service instance that an organization receives and owns once it signs up for a Microsoft cloud service such as Azure or Microsoft 365.</p>
</li>
<li><p>Azure Active Directory, now known as Microsoft Entra ID, is a cloud-based identity and access management service. It provides single sign-on, multifactor authentication, and more.</p>
</li>
</ul>
<p>These concepts are out of the scope of this article, but we might hear them again in future articles, so I've linked some extra resources at the end so you can check them out.</p>
<hr />
<h1 id="heading-azure-resource-provider">Azure Resource Provider</h1>
<p>An <strong>Azure resource provider</strong> is a service that supplies Azure resources. It's a set of REST operations that enable functionality for a specific Azure service.</p>
<p><em>Example per the Microsoft documentation</em>:</p>
<blockquote>
<p>The Key Vault service consists of a resource provider named <strong>Microsoft.KeyVault</strong>. The resource provider defines <a target="_blank" href="https://learn.microsoft.com/en-us/rest/api/keyvault/">REST operations</a> for managing vaults, secrets, keys, and certificates.</p>
</blockquote>
<p>The resource provider defines the Azure resources you can deploy to your account.</p>
<p>The good thing is that <strong>a resource type's name is standardized and follows this format</strong>:</p>
<p><code>{resource-provider}/{resource-type}.</code></p>
<p>The resource type for a key vault is <strong>Microsoft.KeyVault/vaults</strong>.</p>
<p>Of course, you don't have to remember different resource types off the top of your head. Microsoft provides documentation for all types, and you can easily look them up!</p>
<h2 id="heading-why-are-they-important">Why are they important?</h2>
<p>Resource providers are important because <strong>we use the resource provider types to register our resources in our declarative language</strong> (ARM templates or Bicep). That's how we tell Azure what resources we want to deploy.</p>
<p>It's important to note that before we can use a resource provider, we must ensure our Azure subscription is registered for the one we want to use. Tip: register a resource provider only when you're ready to use it. Registering unnecessary resource providers may result in unrecognized apps appearing in your Microsoft Entra ID tenant.</p>
<p>Some resource providers are registered by default. Other resource providers are automatically registered when you take specific actions.</p>
<p>When you carry out specific actions, other resource providers are registered automatically. Usually, the resource provider is already registered for you when you create a resource using the Azure web portal. The resource providers specified in an ARM template or Bicep file are immediately registered when deployed.</p>
<p>There are situations when a templated resource needs supporting resources not included in the template. Resources for monitoring or security are frequent examples. Those resource providers must be manually registered.</p>
<hr />
<h1 id="heading-arm-templates">ARM Templates</h1>
<p>If you made it this far, give yourself a pat on the back! That was boring; now we're getting into the exciting stuff.</p>
<p>ARM templates are normal JSON files that define one or more resources to deploy to a resource group, subscription, management group, or tenant. These templates can deploy resources consistently and repeatedly without configuration drift. That's how we implement infrastructure as code for our Azure solutions!</p>
<h2 id="heading-how-does-an-arm-template-file-look-like">How does an ARM Template file look like?</h2>
<p>Within the template file, we can write additional template expressions that extend the capabilities of JSON. These expressions make use of the functions provided by the Resource Manager.</p>
<p>Each ARM template file has the following sections:</p>
<ul>
<li><p><strong>Parameters</strong>: Provide values during deployment that allow the same template to be used with different environments.</p>
</li>
<li><p><strong>Variables</strong>: Define values that are reused in your templates. They can be constructed from parameter values.</p>
</li>
<li><p><strong>User-defined Functions</strong>: Create customized functions that simplify your template.</p>
</li>
<li><p><strong>Resources</strong>: Specify the resources to deploy.</p>
</li>
<li><p><strong>Outputs</strong>: Return values from the deployed resources.</p>
</li>
</ul>
<p>Here's an example ARM template that tells Azure RM to create a Storage Account:</p>
<pre><code class="lang-json"><span class="hljs-string">"resources"</span>: [
  {
    <span class="hljs-attr">"type"</span>: <span class="hljs-string">"Microsoft.Storage/storageAccounts"</span>,
    <span class="hljs-attr">"apiVersion"</span>: <span class="hljs-string">"2022-09-01"</span>,
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"mystorageaccount"</span>,
    <span class="hljs-attr">"location"</span>: <span class="hljs-string">"centralus"</span>,
    <span class="hljs-attr">"sku"</span>: {
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Standard_LRS"</span>
    },
    <span class="hljs-attr">"kind"</span>: <span class="hljs-string">"StorageV2"</span>
  },
]
</code></pre>
<p>When a template is deployed, the Resource Manager intercepts the request and converts this template into REST API operations. The example above would translate to the following operations:</p>
<pre><code class="lang-json">PUT
https:<span class="hljs-comment">//management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Storage/storageAccounts/mystorageaccount?api-version=2022-09-01</span>
REQUEST BODY
{
  <span class="hljs-attr">"location"</span>: <span class="hljs-string">"centralus"</span>,
  <span class="hljs-attr">"sku"</span>: {
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Standard_LRS"</span>
  },
  <span class="hljs-attr">"kind"</span>: <span class="hljs-string">"StorageV2"</span>,
  <span class="hljs-attr">"properties"</span>: {}
}
</code></pre>
<p>This request is then sent to the appropriate <strong>resource provider</strong>. In this example, that's Microsoft.Storage provider.</p>
<h2 id="heading-why-should-you-use-arm-templates">Why should you use ARM Templates?</h2>
<p>Here are some benefits to convince you to use ARM templates:</p>
<ul>
<li><p>Declarative syntax</p>
</li>
<li><p>Repeatable results</p>
</li>
<li><p>Orchestration</p>
</li>
<li><p>Modularity</p>
</li>
<li><p>Extensibility</p>
</li>
<li><p>Testing</p>
</li>
<li><p>CI/CD integration</p>
</li>
</ul>
<h2 id="heading-why-you-shouldnt-write-arm-templates">Why you shouldn't write ARM Templates.</h2>
<p>Alright, you saw the benefits, but now I will convince you <strong>not</strong> to write ARM templates! Pretty ironic, but hear me out!</p>
<h2 id="heading-hello-bicep">Hello Bicep!</h2>
<p>Bicep is a <strong>new</strong> domain-specific language (DSL) that uses declarative syntax—created explicitly for deploying Azure resources.</p>
<p>It's the <strong>recommended</strong> way to deploy your Azure resources because it offers the same capabilities as ARM templates. However, the syntax is much easier to use, and the developer experience is way better!</p>
<p>I won't go any deeper; the next article in this series will be about Bicep💪😉.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>In this article, we explored the Azure Resource Manager, Resource Provider, and ARM Templates and scratched the surface of Microsoft's new DSL Bicep.</p>
<p>If you enjoyed reading this article, make sure to follow us for more on the same topic in the coming weeks!</p>
<h1 id="heading-resources">Resources</h1>
<ul>
<li><p><a target="_blank" href="https://azure.microsoft.com/en-us/get-started/azure-portal/resource-manager">https://azure.microsoft.com/en-us/get-started/azure-portal/resource-manager</a></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/overview">https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/overview</a></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-providers-and-types">https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-providers-and-types</a></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/overview">https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/overview</a></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/template-functions">https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/template-functions</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Infrastructure as Code: Transforming IT Infrastructure Management]]></title><description><![CDATA[In this short article, I'll explain what Infrastructure as Code is, why it exists and how it revolutionized IT infrastructure management.
Wait, what do you mean by “infrastructure”?
Before explaining Infrastructure as Code, we first need to define wh...]]></description><link>https://blog.codechem.com/infrastructure-as-code-transforming-it-infrastructure-management</link><guid isPermaLink="true">https://blog.codechem.com/infrastructure-as-code-transforming-it-infrastructure-management</guid><category><![CDATA[Devops]]></category><category><![CDATA[Devops articles]]></category><category><![CDATA[Infrastructure as code]]></category><category><![CDATA[infrastructure]]></category><category><![CDATA[Infrastructure management]]></category><dc:creator><![CDATA[Marko Spasenovski]]></dc:creator><pubDate>Wed, 20 Sep 2023 10:56:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1695130646489/df0019d3-26d1-441e-be5f-c5125a355020.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this short article, I'll explain what Infrastructure as Code is, why it exists and how it revolutionized IT infrastructure management.</p>
<h2 id="heading-wait-what-do-you-mean-by-infrastructure">Wait, what do you mean by “infrastructure”?</h2>
<p>Before explaining Infrastructure as Code, we first need to define what we mean by infrastructure. When we talk about IT infrastructure, we’re talking about interdependent elements categorized into two core groups: hardware and software infrastructure elements.</p>
<p>Hardware components include computers, servers, data centers, routers, switches, etc. Software components include operating systems, web servers, firewalls, resource management systems, databases, etc.</p>
<p>The two primary types of IT infrastructure are traditional and cloud infrastructure. I won’t continue into details, as it would escape the scope of this article. However, I’ve linked some resources if you wish to further read up on these concepts at the end of this article.</p>
<h2 id="heading-okay-cool-now-what-do-you-mean-by-infrastructure-as-code">Okay, cool, now what do you mean by “infrastructure as code”?</h2>
<p>As the name implies, Infrastructure as Code (IaC, a common abbreviation) is the practice of automating and managing IT infrastructure through code, leveraging DevOps and traditional software development principles (like code versioning). It involves using a descriptive coding language to define and provide infrastructure consistently, ensuring rapid development, cost control and reliability relative to treating infrastructure like standard application code.</p>
<p>I mentioned it uses a <strong>descriptive</strong> coding language. This isn't always the case, as <strong>imperative</strong> IaC exists and we’ll quickly discuss that at the end of this article.</p>
<h1 id="heading-history">History</h1>
<p>I'll take a very short detour to explain the history of deploying and maintaining software infrastructure and <em>why</em> the process of IaC was developed.</p>
<p>In the era before IaC, setting up and managing infrastructure typically involved several manual tasks and processes, including:</p>
<ul>
<li><p>Providing physical hardware: This means providing physical (often on-site) servers, switches, routers, storage devices, etc.</p>
</li>
<li><p>Operating system installation and configuration: After the hardware was set up, system administrators manually installed and configured operating systems on each server.</p>
</li>
<li><p>Deploying the software application: Each application had to be installed and configured individually and manually.</p>
</li>
<li><p>Network configuration: Manual setting up and managing network connections, firewalls, load balancers, and other networking components required manual configurations</p>
</li>
<li><p>Storage management: Managing storage resources involved creating partitions, configuring RAID arrays, and manually allocating storage space to different applications and servers.</p>
</li>
</ul>
<p>The main downside of manually setting up infrastructure was, well, obviously, that we’re doing all of this <strong>manually</strong>, but also:</p>
<ul>
<li><p>Slow deployment</p>
</li>
<li><p>Error-prone</p>
</li>
<li><p>Lack of scalability</p>
</li>
<li><p>Inconsistency</p>
</li>
<li><p>Difficulty in versioning</p>
</li>
</ul>
<p>Infrastructure as Code addresses these challenges by automating the provisioning and management of infrastructure using code, enabling rapid, consistent, and error-free deployments while facilitating versioning and scalability. It represents a significant advancement in the field of IT infrastructure management.</p>
<h1 id="heading-other-benefits">Other benefits</h1>
<p>Besides the things we highlighted in the previous section, IaC has other benefits:</p>
<ul>
<li><p>Allows a company to enter the cloud computing scene more easily</p>
</li>
<li><p>Cost reductions</p>
</li>
<li><p>Increased deployment speeds</p>
</li>
<li><p>Eliminates configuration drift</p>
</li>
</ul>
<p>You might be wondering what I mean by configuration drift so here’s a short definition:</p>
<p>Ad hoc configuration updates and changes can cause a discrepancy between the environments used for development, testing, and deployment, known as configuration drift. Designing apps and services that must adhere to stringent regulatory compliance standards might lead to problems during deployment, security vulnerabilities, and hazards. By consistently offering the same environment, IaC reduces drift.</p>
<p>IaC is also crucial for DevOps, as it streamlines the process and CI/CD by automating provisioning. It unifies teams and ensures consistent deployments. IaC's benefits span all environments, including production. It extends DevOps principles to infrastructure, enabling rigorous testing and version control.</p>
<h1 id="heading-declarative-vs-imperative-approach"><strong>Declarative vs. Imperative approach</strong></h1>
<p>Declarative usually defines “what” we want to happen, while imperative defines “how” we want the thing to happen.</p>
<p>In most cases, the declarative approach, also known as the functional approach, is preferred. It specifies the desired final infrastructure state with the IaC software handling tasks like VM setup, software installation, and version management. However, it may require skilled administrators to set up and manage.</p>
<p>On the other hand, the imperative or procedural approach involves creating automation scripts for each step of infrastructure provisioning. While this may be more manageable for existing staff, it can become complex and costly at scale.</p>
<p>I’m going to leave you with this fantastic analogy I read on IBM’s website:</p>
<blockquote>
<p>Choosing a declarative or imperative approach is analogous to using a GPS or following turn-by-turn instructions. With a GPS, you enter an address, and the GPS does the rest, plotting the fastest route and avoiding traffic for you, but you probably need an expert to tell you why it made the choices it made. The turn-by-turn instructions are based on personal experience; the provider knows the route and why he/she chose it, but if you encounter obstacles or want to optimize the route, you have to call for help or do the work yourself.</p>
</blockquote>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Hey, you made it to the end! Thanks for reading my article❤️🙏.</p>
<p>Infrastructure as Code is a big part of DevOps and the entire software development and maintenance process. It provides codification, versioning, ease of life, and, most importantly, consistency</p>
<p>If you enjoyed reading this article, make sure to follow us for more on the same topic in the coming weeks!</p>
<h1 id="heading-extra-resources">Extra resources</h1>
<ul>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=EtEb40LE5zQ">"Infrastructure as Code - Crash Course" by freecodecamp</a></p>
</li>
<li><p><a target="_blank" href="https://www.redhat.com/en/topics/automation/what-is-infrastructure-as-code-iac#:~:text=Infrastructure">Red Hat’s definition of Infrastructure as Code</a></p>
</li>
<li><p><a target="_blank" href="https://www.ibm.com/topics/infrastructure-as-code">IBM’s definition of Infrastructure as Code</a></p>
</li>
<li><p><a target="_blank" href="https://www.ibm.com/topics/infrastructure">"What is IT Infrastructure?" by IBM</a></p>
</li>
</ul>
]]></content:encoded></item></channel></rss>