<?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[TheGreenCodes]]></title><description><![CDATA[Engineering decisions explained - why they’re made and what they cost. Distributed systems, infrastructure, and real-world constraints beyond the docs.]]></description><link>https://thegreencodes.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1665573443352/MXr-0UdEa.png</url><title>TheGreenCodes</title><link>https://thegreencodes.com</link></image><generator>RSS for Node</generator><lastBuildDate>Fri, 15 May 2026 11:13:08 GMT</lastBuildDate><atom:link href="https://thegreencodes.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[One Bucket, Three Jobs]]></title><description><![CDATA[The last piece ended with an image leaving my hands and landing somewhere I cannot see. I described shipping NavEngine as pushing a container image to a registry and trusting that a process on a custo]]></description><link>https://thegreencodes.com/one-bucket-three-jobs</link><guid isPermaLink="true">https://thegreencodes.com/one-bucket-three-jobs</guid><category><![CDATA[distributed system]]></category><category><![CDATA[S3]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Infrastructure as code]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Wed, 06 May 2026 07:22:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5ce908d55332dd2471262e1b/ae9e8d6f-cb8e-4606-a326-a5ac4b0ea853.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The <a href="https://www.marvinkweyu.net/indulge/continuous-integration-for-licensed-software">last piece</a> ended with an image leaving my hands and landing somewhere I cannot see. I described shipping NavEngine as pushing a container image to a registry and trusting that a process on a customer's server will eventually notice.</p>
<p>That is accurate. It is also incomplete.</p>
<p>So far, there are two states for NavEngine; the hosted version - whose database I am responsible for whether it fails at three in the afternoon or three in the morning and the one a customer installs.</p>
<p>For this read, I share the story of what I built to hold it all together and why it ended up being more than a place to put files.</p>
<h2>The Decision I Didn't Know I Was Making</h2>
<p>I had a lot of questions at the start of the project.</p>
<ul>
<li><p>How would the customers download the product?</p>
</li>
<li><p>Where would it be stored?</p>
</li>
<li><p>How do companies like Canonical handle distribution?</p>
</li>
<li><p>What does <a href="https://www.marvinkweyu.net/indulge/business-minded-development">distribution</a> actually imply?</p>
</li>
</ul>
<p>I had set out to solve a storage problem. I needed a place that was reliable, versioned, and reachable from anywhere I needed to reach it from. S3 was the obvious answer. Most things are obvious in retrospect. I did not think much about the decision at the time.</p>
<p>What I did not anticipate was that a storage decision is also an architecture decision, and an architecture decision at the distribution layer has a way of spreading.</p>
<h2>Job One: The Product Suite</h2>
<p>NavEngine started as an ISO. Before a customer would run anything on their infrastructure, they needed to have an existing artifact . They needed somewhere they could fetch it from, with integrity guarantees, across whatever network conditions exist on their end.</p>
<blockquote>
<p><strong>Indulge</strong> This raised a different constraint: multiple products would need the same guarantees.</p>
</blockquote>
<p>I needed a place to store iterations as I built towards UAT - User Acceptance Testing. The registry handled images. The bucket handled everything else.</p>
<p>The decision to version the artifacts explicitly - not overwrite, not float - came from the same reasoning behind the floating tag in the update pipeline: I need to know exactly what was shipped.</p>
<img src="https://cdn.hashnode.com/uploads/covers/5ce908d55332dd2471262e1b/aa152afa-875c-4aa9-842f-997b4522d8ec.jpg" alt="Versioning, but without guarantees..." style="display:block;margin:0 auto" />

<p><em>Versioning, but without guarantees...</em></p>
<p>If <code>v4.5.0</code> ever needed to be reproduced or rolled back to, it should already exist. Not rebuilt. Not reconstructed. Present.</p>
<blockquote>
<p><strong>Indulge</strong> <em>The hardest part of distributing software you do not host is preserving the integrity of what you shipped. Tags drift. References move. The artifact you think you gave a customer can diverge from what they actually received. Versioned, immutable storage is the only reliable paper trail when something breaks on a system you cannot access.</em></p>
</blockquote>
<h2>Job Two: The Backup</h2>
<p>We initially served backups of NavEngine by running weekly and monthly VM snapshots. It was tedious, human-dependent and error-prone.</p>
<blockquote>
<p><strong>Example:</strong> If an engineer needed to manually update a database record, they would have to manually create a backup for that before that individual operation. This backup would then live on the same machine.</p>
<p>This meant that while the backup was present, if anything were to hit the fan, it was game over.</p>
<p><em>I have been here. The only grace I had was that it was on the staging environment. The story of how I got back is for another day.</em></p>
</blockquote>
<p>The issue wasn’t that we lacked backups. It was that restoring them required the same precision that introduced the risk.</p>
<p>A backup that lives in a different system than your product artifacts is a backup that gets forgotten about during an incident, when you are moving fast and your attention is already split. Having everything in one place means one set of access credentials, one retention policy to reason about, one place to look when something is wrong.</p>
<p>It was anything but elegant. It was reliable.</p>
<blockquote>
<p><strong>Indulge</strong> Backup strategies fail at the moment of failure, not at the moment of setup. The question to ask is not "do I have backups" but "can I restore from them at two in the morning, under pressure, with the right people asking questions?"</p>
<p>If the answer is uncertain, the backup strategy is incomplete regardless of how often the job runs.</p>
</blockquote>
<h2>Job Three: The Agnostic Product Registry</h2>
<p>This is the job I had not planned for.</p>
<blockquote>
<p><em>What if we had other products to ship that had the same constraints?</em></p>
</blockquote>
<p>Beyond hosting the versioned images of NavEngine, the storage option needed to be agnostic enough to store other images while retaining the ability to version those products too.</p>
<p>Somewhere in the process of building the first two jobs, I noticed that the structure I was laying down did not have to be NavEngine-specific. The bucket had opinions - a versioning scheme, an artifact layout, a naming convention - but those opinions were not tied to NavEngine. They were tied to the idea of a distributable product. Any product that needed the same things NavEngine needs - versioned artifacts, clean separation between releases, a retrievable history - could sit in the same bucket structure without the structure caring what the product was.</p>
<p>I did not set out to build a product registry. I set out to store some files. The registry emerged from the constraints.</p>
<p>As the team builds BusinessAI, the need to account for portability became obvious. Different pricing. Different licensing. Same distribution problem.</p>
<p>This matters because distribution surfaces compound. When the second or third product needed the same infrastructure, the cost should be near-zero. The structure would already exist, the access policies already reasoned about and the retention logic existing.</p>
<p>I wanted to reuse the shape I had already committed to without building new infrastructure for a new product.</p>
<p>I am building around invariants, not specifics. This isn’t storage for NavEngine. It’s storage for products that require versioning, integrity and retrievability from unknown environments.</p>
<h2>The Bucket That Became Infrastructure</h2>
<p>At some point the bucket stopped being a storage decision and became infrastructure.</p>
<p>Storage holds data. Infrastructure carries consequences.</p>
<p>For this use, I went for Garage - a self-hostable and distributed S3 store. Migrations, such as our port from v2 to v3 no longer required moving 60GB+ of assets. The problem reduced to managing references - ASCII text pointing to stable objects.</p>
<blockquote>
<p><strong>Indulge:</strong> In the case of migration, moving from v2 to v3 meant that while the database rows were ported, pointing the assets for each organisation including white-labelled data was a manual process. It relied on knowing the file system storage path and identifying what asset belonged to what organisation.</p>
<p>This meant moving large files over a network from server A to server B - a process I would not like to do again.</p>
</blockquote>
<p>Three jobs, one system - not because it was the cleanest architecture, but because the jobs turned out to share more than I initially gave them credit for -versioning, integrity, global access, and durability beyond any single system.</p>
<p>What I built was, inadvertently, the distribution layer for the company's technical output.</p>
<p>It holds what we ship, what we back up and what we might ship next.</p>
<p>That is more than I planned for when I sat down to store some files.</p>
<hr />
<p>I later ported the same S3 infrastructure to my <a href="https://www.marvinkweyu.net/indulge/series/infrastructure">Homelabbing series</a>, extending it with POSIX-compliant storage via <a href="https://github.com/versity/versitygw">versity</a>.</p>
<p>This means that even as I develop software for <a href="https://www.marvinkweyu.net/indulge/owing-your-infrastructure">my own use case</a>, I can safely extend anything pre-existing to use the volumes I already have. That's it. No config. No workaround. And most importantly, no downtime.</p>
<hr />
<h2>What This Changes</h2>
<p>As I dive deeper into product agnostic infrastructure and look back at what this quarter has meant, my thinking about distribution has shifted.</p>
<p>Uptime isn’t just about keeping systems running. It’s about designing for the moment you lose control of them - backups, extensibility, storage.</p>
<p>The CI/CD piece ended with designing for absence - for the reality that once the software leaves your hands, you have no control over what happens to it. The S3 structure is the complementary question: what must never leave your control?</p>
<p>Artifacts. Backups. Release history - the source of truth.</p>
<p>What the customer runs is a copy. If the copy breaks, you come back to the source. If the source is solid, the copy is recoverable.</p>
<p>That is the job the bucket is actually doing.</p>
<p>Not storage. Infrastructure.</p>
]]></content:encoded></item><item><title><![CDATA[CI/CD for Licensed Software You Don't Host]]></title><description><![CDATA[We are three weeks away from shipping NavEngine v4, an echo from the previous piece on Business Driven development.
I say "shipping" loosely. There is no deployment script I run, no SSH session I open]]></description><link>https://thegreencodes.com/ci-cd-for-licensed-software-you-don-t-host</link><guid isPermaLink="true">https://thegreencodes.com/ci-cd-for-licensed-software-you-don-t-host</guid><category><![CDATA[distributed system]]></category><category><![CDATA[licensing]]></category><category><![CDATA[Devops]]></category><category><![CDATA[self-hosted]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Tue, 07 Apr 2026 06:33:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5ce908d55332dd2471262e1b/8eefa882-3ca5-484d-981b-251d90c7d557.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We are three weeks away from shipping <a href="https://navengine.encha.cloud/"><strong>NavEngine v4</strong></a>, an echo from the previous piece on <a href="https://www.marvinkweyu.net/indulge/business-minded-development"><strong>Business Driven development</strong></a>.</p>
<p>I say "<em>shipping</em>" loosely. There is no deployment script I run, no SSH session I open and no Kubernetes rollout I watch. The software lives on infrastructure I have never seen, behind firewalls I cannot reach, on machines whose specs I do not know. Shipping, in this context, means pushing an image to a registry and trusting that a process running inside a container on a customer's server will eventually notice and do something about it.</p>
<p>That gap - between what I push and what the customer runs - is what this piece is about.</p>
<hr />
<h3>The Assumption Collapse</h3>
<p>Every CI/CD tool I have ever used was built on a premise so foundational that nobody thought to state it: you control the deployment target. You own the server. You have the keys. Deployment, in the conventional sense, is just automation wrapped around access you already have.</p>
<p>NavEngine is quite the opposite. It exists as a custom image - qcow2 - shipped onto the customer's infrastructure. The customer owns the machine. I do not have SSH access unless I go through DWService and even then, that is a support channel, not a deployment one. Yet somehow, we need to continuously deliver updates to machines we cannot reach, across connections we cannot guarantee, without breaking software that is actively in use.</p>
<p>So the question became: if you cannot push, how do you deliver?</p>
<hr />
<blockquote>
<p><em><strong>Indulge</strong></em> <em>The moment you decide to ship software you don't host, you have made a decision with consequences that will follow you for the life of the product. Not just operationally. Architecturally. Every assumption your codebase makes about the environment it runs in now belongs to someone else's infrastructure. That is not a deployment problem. It is a design problem that shows up at deployment time.</em></p>
</blockquote>
<hr />
<h3>The Answer is Pull</h3>
<p>Watchtower. It runs as a container alongside the rest of the stack, polls the Docker registry on a configured interval, and when it detects a new image digest on the tag it is watching, it pulls and restarts the relevant containers. No webhook, no push, no SSH. The installation phones home for updates and takes what it finds.</p>
<p>The key design decision here was the floating tag. Every customer's Butane config ships with <code>core:stable</code>. Not <code>core:v3.0.39</code>. Not a digest pin. <code>stable</code>. When Watchtower polls the registry and sees that <code>stable</code> now resolves to a different digest than what is currently running, it pulls. What "stable" points to is entirely under my control, from the registry side, without touching anything on the customer's machine.</p>
<p>This sounds obvious once you say it. It took longer than I would like to admit to get there.</p>
<hr />
<h3>Two Registries, Two floating tags, One gate</h3>
<p>Here is the full pipeline as it actually runs.</p>
<p>Every push to <code>main</code> triggers a build on the dev registry. The image gets tagged with a version identifier and a floating tag - <code>staging</code>. A staging environment - running the same Compose stack, same Butane configuration, same structure as a customer installation - pulls from <code>staging</code>. This is where the image lives until I am satisfied it works.</p>
<p>When staging looks good, I create a release. The production registry builds from that release, tags the image with the version (<code>v3.0.40</code>) and overwrites the floating <code>stable</code> tag. Customer installations, on their next Watchtower poll interval, see a new digest on <code>stable</code> and update.</p>
<p>The critical detail: <code>stable</code> is never overwritten by a push to <code>main</code>. Only by a release. The staging gate is the only thing standing between a broken image and a customer's running installation. There is no automated rollout percentage, no canary fleet, no gradual traffic shift. The gate is a human decision, made after watching staging run and deciding it is ready.</p>
<p>For a solo-operated product at this stage, that is the right call. Complexity in release infrastructure that you do not need is just surface area for things to go wrong.</p>
<hr />
<blockquote>
<p><em><strong>Indulge</strong></em> <em>A staging environment that does not accurately reflect production is a very expensive placebo. It gives you confidence without giving you information. The hardest thing about shipping self-hosted software is that your staging environment runs on infrastructure you understand, with data you created, on a network you control. Your customer's environment is none of those things. No pipeline fully closes that gap. The best you can do is know exactly where your confidence ends.</em></p>
</blockquote>
<hr />
<h3>What Happens When stable is broken</h3>
<img src="http://localhost:3000/_ipx/_/continuous-integration/backups.png" alt="backups (monkeyuser.com)" style="display:block;margin:0 auto" />

<p><em>Backups(</em><a href="http://monkeyuser.com"><em>monkeyuser.com</em></a><em>).</em></p>
<p>It will happen. An image that passes staging will break in a customer environment for a reason that staging did not surface - a schema migration that assumed a clean database, a dependency that behaves differently on older hardware, a configuration value that was present in staging and absent in the field.</p>
<p>The recovery flow is: fix on <code>main</code>, watch it pass staging, cut a new release. <code>v3.0.41</code> overwrites <code>stable</code>. Watchtower picks it up on the next poll interval. The customer, who may or may not have noticed anything, is now running the fixed image.</p>
<p>The window between the broken image landing and the fix arriving is real. Depending on how fast the hotfix moves through staging and how long the Watchtower poll interval is, a customer could be running broken software for anywhere from minutes to hours. There is no remote kill switch. There is no way to reach in and restart a service. There is DWService if the situation is bad enough to warrant it, but that is a support escalation, not a deployment tool.</p>
<p>This is the honest cost of not controlling the deployment target. You accept a recovery latency that you cannot compress below a certain floor. The mitigation is not a cleverer pipeline. It is investing deeply in staging fidelity and in making sure the image fails loudly rather than silently - health checks that surface problems immediately, startup validation that refuses to run on bad configuration rather than running badly.</p>
<p>A system that fails loudly is a system that can be fixed. A system that degrades quietly is a system that erodes trust before anyone knows there is a problem.</p>
<hr />
<h3>Enterprise and Standard Licenses: different cadences, same pattern</h3>
<p><em>How do we manage customers that diverge from the main product line with an enterprise license?</em></p>
<p>NavEngine has two license tiers. Enterprise customers are on a separate release cadence from standard customers. The mechanism is straightforward: separate floating tags on the production registry. <code>core-enterprise:stable</code> and <code>core-standard:stable</code>. The Butane config shipped to each customer points at the appropriate tag. Enterprise releases can go out on a different schedule, carry different feature sets, and move more cautiously than standard releases.</p>
<p>What prevents a standard customer from pointing Watchtower at the enterprise tag? Mostly friction. The Compose file is baked into the Butane config at provisioning time. There is no SSH access to change it. A customer would need console access and the motivation to go looking - unlikely for most, impossible to rule out for all.</p>
<p>The proper answer is registry-level access control: pull tokens scoped to the tags each customer is entitled to, issued at license activation and revoked at expiry. This means the registry enforces entitlement, not just the application. An expired license means an expired pull token means no updates, enforced at the point of delivery rather than after the fact.</p>
<p>This is on the roadmap. For v4, the answer is friction and trust.</p>
<hr />
<blockquote>
<p><em><strong>Indulge</strong></em> <em>License enforcement in self-hosted software is a negotiation between what you can technically control and what you have to trust. You cannot fully control what runs on a machine you do not own. At some point, a sufficiently motivated customer can circumvent almost any enforcement mechanism you build. The goal is not to make circumvention impossible. It is to make compliance easier than circumvention, and to make the value proposition strong enough that the question rarely comes up.</em></p>
</blockquote>
<hr />
<h3>The license server is not in the update path</h3>
<p>One decision I am glad we made early: the licensing server and the Docker registry are separate infrastructure. They do not share a failure domain.</p>
<p>Watchtower polls the registry. The license server is called from within one of the running containers as part of normal application operation. If the registry is unreachable, the software keeps running. If the license server is unreachable, the backend falls back to its last known state - persisted to disk, not held in memory, so it survives a container restart. The check runs periodically. The grace window is generous enough that a license server outage does not immediately affect customers, but not so generous that expired licenses can run indefinitely.</p>
<p>This matters because the failure modes compound. A product update that requires a license check to proceed has just made the license server a dependency of your deployment pipeline. Any outage that hits your license infrastructure also hits your ability to ship updates to paying customers. Keeping these paths separate means they fail independently, and independent failures are recoverable in ways that cascading ones are not.</p>
<hr />
<p><strong>What the pipeline actually looks like</strong></p>
<img src="https://cdn.hashnode.com/uploads/covers/5ce908d55332dd2471262e1b/558e468f-a5c6-43b3-96f5-8a183271c5b5.png" alt="" style="display:block;margin:0 auto" />

<p>The immutable version tags are not just for auditing. They are the rollback reference. If <code>v3.0.40</code> breaks everything, <code>v3.0.39</code> still exists in the registry. I can retag it as <code>stable</code> manually and customers will roll back on the next poll. This has not been needed yet. It is there for the day it is.</p>
<hr />
<blockquote>
<p><em><strong>Indulge</strong></em> <em>Most CI/CD writing treats deployment as the end of the story. Ship it, watch the metrics, move on. Self-hosted software inverts this. Deployment is the beginning of a period during which software you cannot reach is running in an environment you cannot see, on behalf of a customer whose experience you will only hear about if something goes wrong. The pipeline is not a delivery mechanism. It is a trust mechanism. Every decision in it is a decision about how much you trust the image before it leaves your hands.</em></p>
</blockquote>
<hr />
<h3>Three Weeks Out</h3>
<p>NavEngine v4 is three weeks away. The pipeline is running. Staging has held. The tags are in place.</p>
<p>None of that answers the only question that matters: <em>what happens when the software leaves you?</em></p>
<p>It will run on machines you have never touched, against data you have never seen, in environments that do not care about your assumptions. By the time it fails, if it fails, it will already be someone else’s problem - and still entirely yours. The customer notices before you do. That is the thing. I am shit scared.</p>
<p>I suppose that this is the essence of <a href="https://www.marvinkweyu.net/indulge/why-distributed-systems-field-notes"><strong>these notes</strong></a> - to document real systems in real time. This is the inversion self-hosted systems force on you: treating deployment not as the end of control but as the beginning of its absence.</p>
<p>So you design for that absence.</p>
<p>You design for recovery over prevention.</p>
<p>For visibility over certainty and trust over control.</p>
<p>Everything else is just what it takes to make that possible.</p>
]]></content:encoded></item><item><title><![CDATA[Business-driven Development]]></title><description><![CDATA[What if your multi-tenant application could be shipped as a distributed SaaS? What if you could have a licensed version of your product as an installable on some corner of the internet? What if we cou]]></description><link>https://thegreencodes.com/business-driven-development</link><guid isPermaLink="true">https://thegreencodes.com/business-driven-development</guid><category><![CDATA[distributed system]]></category><category><![CDATA[Business growth ]]></category><category><![CDATA[SaaS]]></category><category><![CDATA[Infrastructure as code]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Fri, 06 Mar 2026 12:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/5ce908d55332dd2471262e1b/93eaac10-2e8d-4b38-91ab-cc989af4ec40.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>What if your multi-tenant application could be shipped as a distributed SaaS? What if you could have a licensed version of your product as an installable on some corner of the internet? What if we could break the barrier of what it meant to be a revenue generating company? Let's begin.</p>
<p>Software is the means by which businesses achieve mass distribution. Beyond technical acumen and efficiency, software is the bus through which businesses achieve scale.</p>
<p>Over the quarter, I have been working on software distribution. Specifically: licensing. Think of it in terms of introducing a new avenue of revenue. We dare ask: Do the businesses that <em>value this solution want control over where their data lives? Are they willing to pay a premium over this control?</em></p>
<p>The answer, in both cases, was yes and that opened a door I had not thought to knock on before.</p>
<p>I had to stop thinking about features and lean towards markets and distribution surfaces. Distribution, in this sense, is not about deployments and pipelines. It is about understanding that different buyers have fundamentally different relationships with trust, compliance, and infrastructure ownership. Your architecture either accommodates those differences or silently forecloses them.</p>
<p>Being technical helped me deploy features product needed. Being business-minded led me to more questions. <em>What would it take to ship this as a product someone else operates? What are we assuming about shared infrastructure that a regulated industry, a government agency, or a security-conscious enterprise would never accept?</em></p>
<p>The answers to those questions are not found in a ticket or a sprint. They surface when you sit long enough with the business model to let it ask questions back at you.</p>
<h3>Licensing as a pricing model</h3>
<p>For Navengine, the questions came back as licensing. Once you accept that a buyer might want to run your software in their own environment - air-gapped, on-premise, inside a VPS they control - you need a mechanism that lets the software know it is legitimate without phoning home in ways that violate their security posture. You need entitlements, activation flows, machine-bound licenses and expiry.</p>
<img src="https://www.marvinkweyu.net/_vercel/image?url=%2Fbusiness-dev%2Fforbidden-problems.webp&amp;w=1536&amp;q=100" alt="It turns out the problem I was solving was not purely technical." style="display:block;margin:0 auto" />

<p><em>It turns out the problem I was solving was not purely technical.</em></p>
<p>Somewhere in the middle of designing the activation flow, I realised the license schema was not a technical artifact. It was a pricing model. The fields I was choosing - seats, features, expiry dates, activation limits - were decisions about how we intended to capture value, just expressed as database columns. It was literally us deciding how we wanted to make money, written in schema form. And no product manager or founder had handed me a neat spec sheet. I was the one typing those business decisions into code.</p>
<p>That kind of realisation doesn’t land with a dramatic “aha!” moment and applause. It creeps in quietly. You’re just fiddling with fields one afternoon… and then, almost without noticing, the way you look at your own codebase has already changed. You start reading the same migrations and models like they’re business strategy documents instead of “just” backend plumbing.</p>
<h3>The second-order effects arrive</h3>
<p>When you decide to support self-hosted deployment, you are not making a DevOps decision. You are ratifying a set of architectural choices that were either made deliberately or inherited by accident. Configuration that was hardcoded because "we only have one environment" now needs to be externalized. Database assumptions that worked fine in a shared-infrastructure model now need isolation boundaries. Upgrade paths that were previously your problem - a migration you ran on a schedule you controlled - become your customer's problem, which means they become your support problem, which means they were always your design problem.</p>
<p>The business-minded engineer understands this before the contract is signed. They look at a feature and ask not just "how do we build this" but "how does this behave when someone else is operating it?" That is a different question and it produces different code. It produces code that fails loudly with actionable errors instead of silently with corrupted state. It produces configuration schema that are documented because they have to be, not because someone found time. It produces container images that carry their dependencies rather than assuming a shared environment that may not exist on the other side of a firewall.</p>
<p>Containerizing Navengine using Flatcar images was not primarily a reliability choice - it was a distribution choice. The image had to be self-contained because I could not know what the environment on the other side looked like. Keygen had to be reachable at activation but not required at runtime, because an installation behind a firewall cannot tolerate a dependency on an external service it may never reach. None of that came from an architecture review. It came from thinking hard about the buyer and working backwards from their constraints.</p>
<p>That backward motion - from buyer to architecture - is the discipline that business-minded engineers practice. It is less intuitive than building forward from requirements, and it is rarely taught, because most engineering education treats the business as a context for the technical problem rather than as a force that shapes the technical solution. But the shape of a system tells you exactly what assumptions its builders made about how it would be used, and by whom, and under what conditions.</p>
<p>If Navengine could only really be operated, understood, or debugged by the people who built it… it would cease to be a product. It would be a service that’s been dressed up in product clothing.</p>
<p>The distinction matters because services and products scale differently. A service scales with people - support engineers, customer success managers, implementation specialists. A product scales with copies. When you ship a licensed, self-hosted deployment, you are betting that the copy can stand on its own. That bet is won or lost in the architecture, long before the first installation.</p>
<h3>None of this is free.</h3>
<p>I will not pretend this is clean. Supporting two distribution surfaces - a managed SaaS and a self-hosted licensed product - means every feature has to answer for itself in both worlds. Every abstraction either holds across deployment models or eventually creates a seam you will debug at the worst possible time. The surface area grows and so does the discipline required to keep it coherent.</p>
<p>This is why most teams never do it. Not because it is technically beyond them, but because it requires a kind of thinking that does not come naturally when you are moving fast and the backlog is full. It requires you to slow down and ask what you are actually building - not in terms of features, but in terms of the thing a customer would take ownership of, operate independently, and stake their own reputation on. That is a different standard than passing your test suite. It is a harder one.</p>
<p>But it is also where engineering becomes interesting in a way that pure technical depth rarely matches. When you understand the business well enough to make architectural decisions that preserve future revenue options, you are no longer just implementing someone else's vision. You are shaping the product's possible futures. That is leverage of a different kind - not the leverage of writing faster code or designing more elegant abstractions, but the leverage of making choices today that compound into distribution tomorrow.</p>
<p>John Carmack once said the most important thing an engineer can do is <a href="https://x.com/ID_AA_Carmack/status/1637087219591659520"><strong>build full product skills</strong></a>. I used to read that as advice about career positioning. Working through this, I think it means something more specific: learn to see the economic system your technical system lives in. Features are temporary. Architectural commitments are long. A business model encoded in a data structure outlasts the engineer who designed it.</p>
<p>The business-minded engineer does not stop caring about the craft. If anything, they care more - because they understand what the craft is in service of. Every clean abstraction is a future operator's sanity. Every well-chosen failure mode is a support ticket that never gets filed. Every deployment boundary that was thought through carefully is a market that remains reachable.</p>
<p>Software is the means by which businesses achieve mass distribution. You already knew that. The question is whether the software you are writing is ready to be distributed - not just deployed, not just maintained, but handed to someone else, in a corner of the internet you will never see, running a business you will never fully understand, solving a problem you helped make solvable.</p>
<p>Becoming a business-minded engineer doesn't mean every engineer should be writing pricing decks. It means understanding that every architectural choice is also a business choice - and that some of the most impactful technical work you'll do is quietly expanding the distribution surface of the thing you're building.</p>
<p>That is the bar. Build to it.</p>
]]></content:encoded></item><item><title><![CDATA[Owning Your Infrastructure]]></title><description><![CDATA[I have self-hosted a number of things so far , including photos, office, docker registry and chat applications for mine and my own use. This piece is a reflection on that journey, partly inspired by a recent incident where a user was banned from GitH...]]></description><link>https://thegreencodes.com/owning-your-infrastructure</link><guid isPermaLink="true">https://thegreencodes.com/owning-your-infrastructure</guid><category><![CDATA[Homelab]]></category><category><![CDATA[self-hosted]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Fri, 31 Oct 2025 10:05:33 GMT</pubDate><content:encoded><![CDATA[<p>I have self-hosted a number of things so far , including photos, office, docker registry and chat applications for mine and my own use. This piece is a reflection on that journey, partly inspired by a recent incident where a user was banned from GitHub.</p>
<p><img src="https://res.cloudinary.com/dlxhllkxl/image/upload/v1761325142/Indulge/celeste_ban_xnxqkz.png" alt="Celeste gets banned" class="image--center mx-auto" /></p>
<p>I started self-hosting because I was bored and wanted to do hard things. Not just any hard thing but hard things that I understood ins and outs of. I kicked off with the usual simple applications, went of to projects I actually built and use and started getting dirty with writing programs for my own router - go figure. Be as it may, I have always been a tinkerer and labbing as well as my recent work with DevOps has given me the freedom to do so. What a glorious adventure.</p>
<p>Everything works other than my password manager. Why? Because we all know that if the server that manages your passwords goes down then the world is truly ending.</p>
<blockquote>
<p><strong>Indulge:</strong> You cannot claim rights to what you do not actually own. Or as FUTO put it: 'If you can’t review the source code, it’s not your software. If you can’t host the service yourself, it’s not really yours.'</p>
</blockquote>
<p>While Celeste, tweet above, was rightly banned because of his <a target="_blank" href="https://github.com/torvalds/linux/pull/1355">spam pr</a> (<a target="_blank" href="https://x.com/karthihegde/status/1978316798090006532/photo/1">original title</a>), it brings a number of things to question.</p>
<p>What does it mean for our convenient single signons? What happens , as with the case of <a target="_blank" href="https://www.nytimes.com/2022/08/21/technology/google-surveillance-toddler-photo.html">Mark</a>, if your Google account or any other SSO account is banned either temporarily or permanently? What happens to the ecosystems we so willingly give all our information to? For context, Mark's Google account was flagged when he took photos of his naked toddler for the doctor and Google mistakenly identified him as a criminal. He never recovered that account.</p>
<blockquote>
<p><strong>Thought:</strong></p>
<p>What percentage of your life is dependent on your online account?</p>
</blockquote>
<p>We place ourselves in bubbles of 'I cannot get banned' until it finally happens. One compromise to your online account , be it LinkedIn (as is so common these days), or any other and a cascading train of events follows.</p>
<blockquote>
<p><strong>Indulge:</strong></p>
<p>Maybe some of your online accounts should be your backup instead of your primary source.</p>
</blockquote>
<p>I will clone my most important work to my Gitea instance over the weekend and possibly hook it to Authentik. I leave this piece here, until our next conversation - UNRAID.</p>
<p><strong>Reference notes</strong></p>
<p>To sign off on owning, not renting, your software:</p>
<p>- <a target="_blank" href="https://www.youtube.com/watch?v=u_Lxkt50xOg">PwediePie starts self-hosting</a> to cut on subscriptions</p>
<p>- <a target="_blank" href="https://www.youtube.com/watch?v=zBnDWSvaQ1I">Our microphones</a> and our privacy.</p>
<p>Originally published: <a target="_blank" href="https://www.marvinkweyu.net/indulge/owing-your-infrastructure">Indulge</a></p>
]]></content:encoded></item><item><title><![CDATA[Keeping the Homelab Alive]]></title><description><![CDATA[One of the challenges that comes from getting yourself an enterprise minicomputer is the configuration set by the selling company. For my case, it was the BIOS lock - a toggle that inhibited my ability to have continuous uptime.
For this specific ser...]]></description><link>https://thegreencodes.com/keeping-the-homelab-alive</link><guid isPermaLink="true">https://thegreencodes.com/keeping-the-homelab-alive</guid><category><![CDATA[Homelab]]></category><category><![CDATA[networking]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Mon, 30 Jun 2025 06:00:39 GMT</pubDate><content:encoded><![CDATA[<p>One of the challenges that comes from getting yourself an enterprise minicomputer is the configuration set by the selling company. For my case, it was the BIOS lock - a toggle that inhibited my ability to have continuous uptime.</p>
<p>For this specific series, I had the following options to reset this:</p>
<ol>
<li><p>Unplug and plug back in the CMOS battery, effectively resetting the BIOS lock.</p>
</li>
<li><p>Removing the PCMOS plug, holding the reset option and placing it back in.</p>
</li>
<li><p>Flushing the BIOS and installing a new one.</p>
</li>
</ol>
<p>With option 1 and 2 not working for my particular use case and option 3 being out of my reach at that said time, I chose a fourth option. The workaround that came to mind was using wake on LAN. I figured, even if I lost power and it came back up, I should be able to power up the computer using another device on the same network.</p>
<p><strong>Considerations</strong></p>
<ol>
<li><p>What happens should I restart my homelab? Would it remember my configuration to wake up on LAN on command?</p>
</li>
<li><p>How would I connect to it within my home network?</p>
</li>
</ol>
<h4 id="heading-approach">Approach</h4>
<p><strong>Create a daemon to autostart wake on LAN for the homelab</strong></p>
<p>I connected my setup to my router via ethernet as I would always be assured that that was on. Figuring the interface with which it connected to the home network was as simple as using <code>ip</code>:</p>
<pre><code class="lang-bash">ip link
</code></pre>
<p>From this, I would then pick the connection with <code>&lt;BROADCAST,MULTICAST&gt;</code> to check its support. In my case, <code>eno1</code>.</p>
<pre><code class="lang-bash">sudo ethtool eno1

<span class="hljs-comment"># output contained</span>
Supports Wake-on: pumbg  
Wake-on: g
</code></pre>
<p>Great, wake on LAN is supported (<code>wake-on: g</code>) and it can support multiple triggers(<code>Wake-on: pumbg</code>). Should it have been (<code>Wake-on: d</code>) for not supported, I would have enabled it with:</p>
<pre><code class="lang-bash">sudo ethtool -s eno1 wol g
</code></pre>
<p>Because the NIC of the system will be reset to (<code>d</code> - disabled) on each restart, I needed to enable this on reboot. I created an internal service for this as:</p>
<pre><code class="lang-bash">nano /etc/systemd/system/wol.service
</code></pre>
<pre><code class="lang-plaintext">[Unit]  
Description=Enable Wake-on-LAN  
After=network.target  

[Service]  
Type=oneshot  
ExecStart=/sbin/ethtool -s eno1 wol g  

[Install]  
WantedBy=multi-user.target
</code></pre>
<p>Then I recognize and enable it with:</p>
<pre><code class="lang-bash">sudo systemctl daemon-reload
sudo systemctl <span class="hljs-built_in">enable</span> wol.service
systemct start wol.service
</code></pre>
<p><strong>Pinging the homelab from other devices in the same home network:</strong></p>
<p>Since the system is already on the home network with ethernet and always plugged in, I can call wake on lan using its MAC address. I would just need to install wake on LAN on my laptop or other device. On Arch:</p>
<pre><code class="lang-bash">yay wakeonlan
</code></pre>
<p>On my android devices, I chose to install a ready made solution. I was not going to start building again <a target="_blank" href="https://play.google.com/store/apps/details?id=co.uk.mrwebb.wakeonlan">Wake On Lan</a></p>
<p>I then retrieved the MAC address using the same <code>ip</code> command from earlier.</p>
<p>Now, waking my computer from a power outage should work as simple as:</p>
<pre><code class="lang-bash">wakeonlan &lt;mac-address&gt;
</code></pre>
<h4 id="heading-a-step-further">A step further</h4>
<p>I took it a step further and updated my aliases. In this case, creating a bash script that would ping my home server when called and only stop after 30 minutes of failure or when it got its first successful response. For reference:</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash  </span>
<span class="hljs-comment"># wake-on-lan-script</span>

MAC_ADDRESS=<span class="hljs-string">"mac-address"</span>  
HOSTNAME=<span class="hljs-string">"homelab-hostname"</span>  
SERVER_IP=<span class="hljs-string">"homelab-ip"</span>  

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Waking up <span class="hljs-variable">$HOSTNAME</span> (<span class="hljs-variable">$MAC_ADDRESS</span>)..."</span>  
wakeonlan <span class="hljs-string">"<span class="hljs-variable">$MAC_ADDRESS</span>"</span>  


sleep 45  

<span class="hljs-built_in">echo</span> <span class="hljs-string">"Checking if <span class="hljs-variable">$HOSTNAME</span> is up (will timeout after 30 minutes)..."</span>  

START_TIME=$(date +%s)  
TIMEOUT=$((<span class="hljs-number">30</span> * <span class="hljs-number">60</span>))  <span class="hljs-comment"># 30 minutes in seconds  </span>

<span class="hljs-keyword">while</span> <span class="hljs-literal">true</span>; <span class="hljs-keyword">do</span>  
   <span class="hljs-keyword">if</span> ping -c 1 -W 1 <span class="hljs-string">"<span class="hljs-variable">$SERVER_IP</span>"</span> &amp;&gt; /dev/null; <span class="hljs-keyword">then</span>  
       <span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">$HOSTNAME</span> is now online."</span>  
       <span class="hljs-built_in">break</span>  
   <span class="hljs-keyword">fi</span>  

   NOW=$(date +%s)  
   ELAPSED=$((NOW - START_TIME))  

   <span class="hljs-keyword">if</span> [ <span class="hljs-string">"<span class="hljs-variable">$ELAPSED</span>"</span> -ge <span class="hljs-string">"<span class="hljs-variable">$TIMEOUT</span>"</span> ]; <span class="hljs-keyword">then</span>  
       <span class="hljs-built_in">echo</span> <span class="hljs-string">"Timeout reached. <span class="hljs-variable">$HOSTNAME</span> did not come online within 30 minutes."</span>  
       <span class="hljs-built_in">break</span>  
   <span class="hljs-keyword">fi</span>  

   sleep 5  
<span class="hljs-keyword">done</span>
</code></pre>
<p>I would then update my <code>~/.zshrc</code> with my alias call. I just called it <code>home</code></p>
<pre><code class="lang-bash"><span class="hljs-built_in">alias</span> home=<span class="hljs-string">"path-to-wake-on-lan-script"</span>
</code></pre>
<p>That was pretty much it.</p>
<h4 id="heading-the-future">The Future</h4>
<p>My current setup works as I expect. I do, however, foresee a scenario where I would like to wake the system when not connected to my home network. I could either use wireguard with a rasberry pi or setup an ESP32 that would always try to ping it when plugged in.</p>
]]></content:encoded></item><item><title><![CDATA[Home labbing - The start of an adventure]]></title><description><![CDATA[My recent work on Scale Computing and Opennebula has piqued my interest in home lab environments. I decided to take a peek and got myself a HP G2 800 minicomputer for play.This , along with a number of smart devices to really push the limits of what ...]]></description><link>https://thegreencodes.com/home-labbing-the-start-of-an-adventure</link><guid isPermaLink="true">https://thegreencodes.com/home-labbing-the-start-of-an-adventure</guid><category><![CDATA[Homelab]]></category><category><![CDATA[Home Assistant]]></category><category><![CDATA[self-hosted]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Mon, 09 Jun 2025 06:00:44 GMT</pubDate><content:encoded><![CDATA[<p>My recent work on Scale Computing and Opennebula has piqued my interest in home lab environments. I decided to take a peek and got myself a HP G2 800 minicomputer for play.This , along with a number of smart devices to really push the limits of what is possible.</p>
<h5 id="heading-so-what-is-a-home-lab"><strong>So, what is a home lab?</strong></h5>
<h5 id="heading-a-home-lab-serves-as-a-safe-space-for-tech-enthusiasts-to-experiment-on-ideas">A home lab serves as a safe space for tech enthusiasts to experiment on ideas.</h5>
<p>So far, I have been able to create and manage virtual machines including the assignment of public IP address and management of mikrotik routers. All this has been in a globally distributed environment with data centers all over. While this is exciting in and of itself, I always wondered; what doors could I possibly unlock if I ran my own set up within a space I could control? I built this space for exactly this reason.</p>
<p>The <a target="_blank" href="https://www.marvinkweyu.net/indulge/the-start-of-an-adventure">#homelabbing</a> series serves as a documentation of the experiments I perform on this handy resource I currently have. It will encompass everything from setting up , power consumption, projects I am working on to the paths I take in the foreseeable future.</p>
<p>It is my hope that on this wire of the internet, someone finds a spark — the same curiosity that led me down this rabbit hole. Whether you're just getting started or are years into your own home lab journey, may this series serve as a source of insight, inspiration, and maybe even a few lessons from my inevitable missteps. The adventure has just begun, and I look forward to sharing each step along the way.</p>
<p><strong>PS:</strong></p>
<p>While I’ve been away from TheGreenCodes space for a while, that doesn’t mean I’ve been idle. Instead, I’ve been building an environment that goes beyond guides and tutorials — one that mules deeper than code, creating value not just through syntax but through systems, insight and experimentation.</p>
]]></content:encoded></item><item><title><![CDATA[The 20% that makes all the difference]]></title><description><![CDATA[“And I took the road less travelled. And that made all the difference.”

Time management is something I find myself working through every once in a while whether it involves writing down weekly items to check off and crossing 2 of the twenty, crossin...]]></description><link>https://thegreencodes.com/the-20-that-makes-all-the-difference</link><guid isPermaLink="true">https://thegreencodes.com/the-20-that-makes-all-the-difference</guid><category><![CDATA[Entrepreneurship]]></category><category><![CDATA[software development]]></category><category><![CDATA[Startups]]></category><category><![CDATA[business]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[side project]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Sun, 25 Aug 2024 21:00:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724581260180/d7ca32f7-cfaf-41df-840b-2722452021d9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>“And I took the road less travelled. And that made all the difference.”</p>
</blockquote>
<p>Time management is something I find myself working through every once in a while whether it involves writing down weekly items to check off and crossing 2 of the twenty, crossing a 3/4 percentage or throwing it all together.</p>
<p>My read on effective engineering dubbed, <a target="_blank" href="https://www.goodreads.com/book/show/25238425-the-effective-engineer?ac=1&amp;from_search=true&amp;qid=V59d6Adpga&amp;rank=1">The Effective Enginee</a>r by Edmond Lau, has been as inspirational as it has been eye-opening. From this, a few thought processes came up that would be worth noting, specifically regarding impact, sustainability and effectiveness.</p>
<p>To quote:</p>
<blockquote>
<p>I worked the long hours because I wanted to make a meaningful impact, but I couldn’t help but wonder: Was putting in 70-80 hour weeks really the most effective way of ensuring our startup’s success? Our intentions were sound, but could we have worked smarter? - Edmond Lau</p>
</blockquote>
<p>With this piece, and in a builder’s pursuit of mastery, I will interweave a few ideas, thoughts and research points to challenge convention and support the contrarian or vice versa. It is a leap out of the <a target="_blank" href="https://www.marvinkweyu.net/indulge/work_and_life">day-to-day routine</a> of the builder and into the vastness unknown.</p>
<h3 id="heading-the-always-be-shipping-mantra">The Always Be Shipping mantra</h3>
<p>The most captivating moment from the book, at least for me, was the mention and talk of experimentation. The goal is building, not with having a specific audience or market in mind but for the sake of it. I call it flow.</p>
<blockquote>
<p>I can’t tell you why you need a home computer right now. I mean, people ask me, “Why should I buy a computer in my home?” And I say, “Well, to learn about it, to run some fun simulations. If you’ve got some kids, they should probably know about it in terms of literacy. They can probably get some good educational software, especially if they’re younger. “You can hook up to the source and, you know, do whatever you’re going to do. Meet women, I don’t know. But other than that, there’s no good reason to buy one for your house right now. But there will be. There will be.” - Steve Jobs (Speech at the International Design Conference in Aspen, June 1983)</p>
</blockquote>
<p>In the early 2000s, Google pioneered what was called “The 20% time” - a chip of time within which engineers in its domain would be free to leverage Google’s technology to build their own products unhindered. Suffice it to say, this led to the development of products such as Google News, Google Maps and Gmail.</p>
<p>Consequently, this fostered a culture of innovation and creativity which contributed to its relish within the engineering community as the ‘go-to’ company to work with. <a target="_blank" href="https://www.wired.com/2012/12/llinkedin-20-percent-time/">LinkedIn, Atlassian and Adobe</a> followed suit with hopes of catching up.</p>
<p><img src="https://res.cloudinary.com/dlxhllkxl/image/upload/v1687601656/Indulge/how-instagram-started_xnrhsa.png" alt="Instagram" /></p>
<blockquote>
<p>I don't know what the future will bring, but if you stop investing in basic research today, you won't have a future. - <strong>Neil deGrasse Tyson</strong></p>
</blockquote>
<p>From my experience, it is always the builders that do more than is within their scope that end up being the great men and women in their domain; <a target="_blank" href="https://www.marvinkweyu.net/indulge/a_call_to_dream">the innovators of the future</a>. To mention a few of these; ProductHunt, Slack, Twitter, Pinterest (hello Elle), Shopify, AppSumo and GitHub. For the founders, it was the little something on the side that made all the difference.</p>
<p>Remarkably, by the time the aforementioned companies were either acquired, went public or reached a certain user-base marking, their ratio of engineer to user was in the scale of one to thousands or even millions. In other words, they had built successful enterprises not with an abundance of human resources but with a vision for a product that <a target="_blank" href="https://www.marvinkweyu.net/indulge/necessity_versus_opportunity">addressed their immediate need</a>.</p>
<blockquote>
<p>The reason we[Woz and I] built a computer was that we wanted one, and we couldn’t afford to buy one… We were just two teenagers. We started trying to build them and scrounging parts around Silicon Valley where we could…All our friends wanted them too. It was taking up all of our spare time because our friends were not that skilled at building them, so Woz and I were building them for them. - Steve Jobs, 1996, Apple 20th anniversary.</p>
</blockquote>
<p><strong>Thought:</strong> If someone does not think you are insane for how relentlessly you work to achieve your dreams, you might want to re-evaluate your choices. Being called crazy and being rejected is not such a bad thing.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In the end, <a target="_blank" href="https://youtu.be/pqQrL1K0Z5g?t=184">you might never know when or where your project might be of use</a> to the rest of the populous. The least you can do, however, is to take a chunk of time within your day to build, innovate and imagine the possibilities.</p>
<h3 id="heading-reference-notes">Reference notes</h3>
<p>For some notes on how some of the products above came to be, I leave some starter resources here.</p>
<ul>
<li><p><a target="_blank" href="https://nira.com/github-history/">How GitHub Democratized Coding, Built a $2 Billion Business, and Found a New Home at Microsoft</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=2rqwi63Q1Gs">Steve Jobs Speech at the International Design Conference 1983</a></p>
</li>
<li><p><a target="_blank" href="https://medium.com/lets-make-things/the-origin-of-product-hunt-7acb09e2593a">The origin of ProductHunt</a></p>
</li>
<li><p><a target="_blank" href="https://www.goodreads.com/book/show/128533513-make-something-wonderful">Make Something Wonderful - Steve Jobs</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Necessity versus Opportunity]]></title><description><![CDATA[Over the past few weeks, I have been exploring the world of entrepreneurship, attending various events where accelerators gather, joining breakfasts for entrepreneurial-minded individuals, and participating in debates on the subject. Throughout this ...]]></description><link>https://thegreencodes.com/necessity-versus-opportunity</link><guid isPermaLink="true">https://thegreencodes.com/necessity-versus-opportunity</guid><category><![CDATA[Entrepreneurship]]></category><category><![CDATA[Africa]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Tue, 11 Apr 2023 04:58:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/oqStl2L5oxI/upload/1f89b73e16644e92c5626691a6972700.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Over the past few weeks, I have been exploring the world of entrepreneurship, attending various events where accelerators gather, joining breakfasts for entrepreneurial-minded individuals, and participating in debates on the subject. Throughout this journey, I have been focusing on funding opportunities, education, and mindset shifts that ultimately lead to the creation of successful businesses.</p>
<p>An opinion piece that caught my attention was one by Adam Molai entitled "<a target="_blank" href="https://www.businesslive.co.za/bd/opinion/2022-06-25-adam-molai-africa-has-entrepreneurs-just-not-the-right-kind/">Africa lacks the right kind of entrepreneurs</a>," along with the paper "<a target="_blank" href="https://www.afdb.org/en/documents/working-paper-336-jobs-economic-growth-and-capacity-development-youth-africa">Jobs, Economic Growth and Capacity Development for Youth in Africa</a>," both of which form the basis of my thoughts today.</p>
<h3 id="heading-indulge">Indulge</h3>
<p>With the world at 8 billion persons as of <a target="_blank" href="https://www.un.org/en/dayof8billion">15th November 2022</a>, Africa remains one of the poorest continents on the globe, despite the fact that it will account for 2 out of 5 working-age individuals by the end of the 21st century. The peculiar part of this statement is the quality and purposes with which we build our ventures within the African economic zones.</p>
<p>The crux? Was this business built out of a pure innovative spirit - to create what once was not - or was it a means to an end?</p>
<p>Returning to the population question, with a 245.0% increase in population within the working age group, we expect a rise in the number of graduates and professionals alike. All this while, the market is not primed to absorb this number of individuals. If anything, the <a target="_blank" href="https://layoffs.fyi/">tech lay-offs</a> that have happened over the last couple of months have been a testament to what happens when projects fail and companies are bloated.</p>
<blockquote>
<p>Was this business built out of a pure innovative spirit - to create what once was not - or was it a means to an end?</p>
</blockquote>
<p>This raises the question, what does this mean for education?</p>
<p>In a culture where entrepreneurship is often viewed as a 'side-hustle' for those unable to secure traditional jobs, we risk neglecting the creation of strong foundations for the future.</p>
<blockquote>
<p>The next Bill Gates will not build an operating system. The next Larry Page or Sergey Brin won’t make a search engine. And the next Mark Zuckerberg won’t create a social network. If you are copying these guys, you aren’t learning from them. - Peter Thiel (Zero To One)</p>
</blockquote>
<p>It is high time we create sustainable solutions that navigate from bringing in the everyday meal to those that impart beyond sustenance. To leave you something to nibble and ponder, here is an article from TechCabal about <a target="_blank" href="https://techcabal.com/2022/11/08/african-tech-talent-emigration-jobs/">tech talent navigating its way back to Africa</a>.</p>
<p><strong>Thought:</strong></p>
<p>Perhaps the danger of Artificial Intelligence is not in it taking away employment ( unless you champion for <a target="_blank" href="https://www.youtube.com/watch?v=uK3OBAxCi6k">bullshit jobs</a>) but that with the increased use of the same technology, AI relearns from itself and other old content rather than what is made a-new. The limit remains; Artificial Intelligence will only learn from what already exists.</p>
]]></content:encoded></item><item><title><![CDATA[Recommendation systems on the web]]></title><description><![CDATA[Introduction
I have a confession to make; I am a huge fan of sci-fi.
Whether it is another episode of The Minority Report, Upload or Travelers, I am all for it. Perhaps the underlying cause is my fascination with how these societies use technology in...]]></description><link>https://thegreencodes.com/recommendation-systems-on-the-web</link><guid isPermaLink="true">https://thegreencodes.com/recommendation-systems-on-the-web</guid><category><![CDATA[recommender-systems]]></category><category><![CDATA[Entrepreneurship]]></category><category><![CDATA[user experience]]></category><category><![CDATA[logging]]></category><category><![CDATA[scalability]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Tue, 28 Mar 2023 07:03:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1679947226540/ff8e5a23-c5f9-4a46-9ddc-d018eb142c18.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>I have a confession to make; I am a huge fan of sci-fi.</p>
<p>Whether it is another episode of The Minority Report, Upload or Travelers, I am all for it. Perhaps the underlying cause is my fascination with how these societies use technology in their everyday lives. Moreso, perhaps it is in the chance to witness something that is on the brink of discovery in our modern-day information era.</p>
<p>One of the common theme that appears across these films is the ability of machines to predict what we want.</p>
<p>An observer need only take one look at how, say the show, The Minority Report, uses its predictive algorithm Hawk-Eye, to predict the occurrence of crime and compare it to Essex University’s <a target="_blank" href="https://www.essex.ac.uk/research/showcase/imagine-being-able-to-predict-a-crime-in-the-future">KeyCrime</a>, to see a <a target="_blank" href="https://www.marvinkweyu.net/indulge/the_effect_of_daydreaming_and_fiction_in_the_evolution_of_science">closeness between fiction and reality</a>.</p>
<p>What if we could predict what would happen before it does? What if a machine could tell what you would buy before you actually get to it?</p>
<hr />
<h2 id="heading-what-is-a-recommendation-system">What is a Recommendation System?</h2>
<p>A recommendation system is an information filtering technique that predicts what a user might prefer based on their historical interactions or preferences.</p>
<p>As an example, and coming back from our high on KeyCrime, if a user frequently watches romantic comedies on a streaming service, a recommendation system may suggest similar movies or TV shows. These systems are based on machine learning algorithms that analyze user behaviour to generate other details that they might be interested in.</p>
<p>They have become commonplace in industries such as e-commerce, social media platforms, security and healthcare. Let’s talk about this and the different aspects that come to play around recommendation engines.</p>
<h2 id="heading-types-of-recommendation-systems">Types of Recommendation Systems</h2>
<p>For brevity, there are different types of recommendation systems, including content-based, collaborative-based, hybrid, and demographic-based recommendations.</p>
<h3 id="heading-content-based-recommendation">Content-based Recommendation</h3>
<p>Say, for instance, you are called Ian, and you have a thing for apple products. You log into Instagram and double-tap on two or three images around apple products or advertisements. What happens in the background?</p>
<p>Content-based recommendation systems make recommendations based on the similarity of items and are attached to the particular user. the more interaction you have with a system, the more accurate the data gets. In essence, a content-based recommendation engine needs a base item(s) around which a user’s actions(reviews, likes etc…) can be pegged.</p>
<p>“We see you liked an image that has wheat. Here are other wheat-based products you might relish.”</p>
<h3 id="heading-collaborative-based-recommendation">Collaborative-based Recommendation</h3>
<p>What if we have a whole community of foodies? Could they ping each other based on what they enjoyed preparing?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679945896788/9e93cb3b-9997-490d-8884-a648674659f2.png" alt class="image--center mx-auto" /></p>
<p>Collaborative-based recommendation systems generate recommendations based on the behaviour of similar users. If two users have similar preferences, the system will recommend items that one user has liked to the other.</p>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Netflix_Prize">The Netflix Prize</a> was one such event where builders across the board were invited to a collaborative filtering algorithm challenge to improve upon its own algorithm, Cinematch. A grand prize of $1000 000 for any team that came through with the solution.</p>
<p>Broadly speaking, collaborative-based recommendation systems are grouped into memory and model-based. For purposes of this guide, we shall focus on memory-based collaborative filtering within which we can further break into Item and user-based collaborative filtering.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679945926676/b2c46030-5dc5-4842-b139-1bc3ddff6aba.png" alt class="image--center mx-auto" /></p>
<p><strong>User-based collaborative filtering</strong></p>
<p>At its core, user-based collaborative filtering is based on similar consumption patterns.</p>
<p><strong><em>Example:</em></strong> Let’s say Rita finally set up her restaurant. We pay a visit, and you give it a 5-star rating. Now, your friend, Peter, does the same. Already, we have two users with a similar rating on the same location. It is very likely that because Rita and Peter have a 5-star rating on a specific item, they will have other items in common. Thus, we look for people with a rating of between 5 and 3.5 for the restaurant and suggest other restaurants they like to you.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1679945951780/82d04d9c-657b-4a0b-8f43-09a754f80e23.png" alt class="image--center mx-auto" /></p>
<p>This ‘envelope’ we just created in our example is called a threshold. So, a user with a rating of 1 on the said restaurant will not be a source of suggestions for our next restaurant hopping experience.</p>
<p><strong>Item-based collaborative filtering</strong></p>
<p><em>Example:</em> Most users that buy bread also buy butter. therefore, these items must be similar. Or if user X likes films with ‘Iron man’ then they will like those with ‘Spiderman’. You get the gist.</p>
<p><a target="_blank" href="https://patents.google.com/patent/US6266649">Introduced by Amazon in 1998</a>, item-based filtering bases recommendations on similarities between items. This decision will affect our ‘pre-sales’ option during checkout. The suggestion is to get this customer to buy one more item, that is, spend more. This is the reason why everything in retail stores is where it is. Nothing by chance, nothing random.</p>
<p>Are there challenges to collaborative filtering? Well, certainly. Depending on which of the aforementioned you use you might encounter the following:</p>
<ol>
<li>The early rater problem</li>
</ol>
<p>So, you successfully have a user log in to your platform with 20 000 books. They rate 1 / 20 000. We literally have nothing to recommend.</p>
<ol>
<li>Sparsity</li>
</ol>
<p>You have a number of users all of whom have rated a significant count of products. However, these items are too far spread apart. Say, for instance, back to books, only two have rated the same books. All the others have rated items with no duplication.</p>
<ol>
<li>A gray sheep</li>
</ol>
<p>You know yourself. You like to remain unpredictable, you open browsers in incognito all the time, like random things every time and leave the platforms you visit. Just like Elle(laughs like Mojo Jojo).</p>
<ol>
<li>The shilling attack</li>
</ol>
<p>This happens when a single user or group of people create multiple accounts on the same platform and rate , say a product in a certain way in order to sway other users’ interest to the items they are rating highly. It can also happen to sway users away from a product by giving it bad ratings.</p>
<h3 id="heading-hybrid-recommendation">Hybrid Recommendation</h3>
<p>Certainly, we must have come up with a workaround content and collaborative-based recommendation engines. In comes Hybrid recommendations.</p>
<p>Hybrid engines combine both content-based and collaborative-based approaches to generate recommendations.</p>
<h3 id="heading-demographic-based-recommendation">Demographic-based Recommendation</h3>
<p>Do you remember the piece, <a target="_blank" href="https://thegreencodes.com/going-enterprise-and-its-aftermath">Up and Away with Scalability</a> - specifically on caching and content delivery servers?</p>
<p>Demographic-based recommendation systems make recommendations based on demographic information such as age, gender, or location.</p>
<p>For one, we could have a location that is known for a type of music. Thus, instead of having our data centre closest to them caching everything and all other genres, why not cache what people actually listen to?</p>
<p><strong>Pro tip:</strong> Bongo, a music genre, is popular in the coastal regions of Kenya and Tanzania. My music service would therefore hold a cache for this genre on servers closest to these regions as opposed to , say Alaska.</p>
<p>Demographic-based recommendation systems are often used for marketing purposes and can be particularly useful for identifying and targeting specific groups of users.</p>
<h2 id="heading-applications-of-recommendation-systems">Applications of Recommendation Systems</h2>
<p>A favourite example I like to reference when it comes to recommendation engines is one highlighted in the book, <a target="_blank" href="https://charlesduhigg.com/the-power-of-habit/">The Power of Habit</a>, by Charles Duhigg, of the American retail store, Target.</p>
<p>Target’s data analytics team got so good at building these systems, it got into the public limelight when it <a target="_blank" href="https://www.nytimes.com/2012/02/19/magazine/shopping-habits.html?pagewanted=1&amp;_r=1&amp;hp">suggested diapers in one of its marketing campaigns to a father</a> who was sure his daughter was not. It recommended products users might want to purchase based on their patterns and on the data of other people they collected using their gift cards.</p>
<p>Other examples you might find interesting include how, for instance, LinkedIn uses the “You may also know” or “You may also like” for companies or profiles to follow.</p>
<blockquote>
<p><strong>Thought:</strong> Did you know , Netflix has gone through phases in its <a target="_blank" href="https://gibsonbiddle.medium.com/a-brief-history-of-netflix-personalization-1f2debf010a1">Personalization using recommendation systems</a>?</p>
</blockquote>
<h2 id="heading-what-does-this-mean-for-the-products-in-the-build-process">What does this mean for the products in the build process?</h2>
<p>For a preview, you can take a sneak peek into <a target="_blank" href="https://github.com/marvinkweyu/marastore">marvinkweyu/marastore</a> - an e-commerce platform for travellers and backpackers. It includes within it, an item-based collaborative filtering engine. We dare answer;</p>
<p>Does user A need product Y given user B bought X and Y?</p>
<p><strong>Back to you, the reader</strong>: <em>How would you rank the aforementioned results?</em></p>
<p>Another example of a similar implementation is the library project, "<a target="_blank" href="https://urbanlibrary.marvinkweyu.net/">Urbanlibrary</a>" - the Afrocentric literature bookshelf. Within it, I implemented a mix-and-match if you may of recommendation algorithms. Is it based on history? Is it based on rating? You’ll never know unless you find out.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Recommendation systems have evolved to suit different needs and algorithms have been built on top of each other to meet this demand. You can combine, break away from, build your own or adopt an existing solution. Either way, it offers a path to understanding your customers and business. Take advantage. Personalize this experience.</p>
<blockquote>
<p><a target="_blank" href="https://www.marvinkweyu.net/indulge">Indulge</a>: Perhaps all you need to be a mind reader is your browser history.</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Docker image optimization: Tips and Tricks for Faster Builds and Smaller Sizes]]></title><description><![CDATA[I have been making a couple of changes in the build and deployment process of The Urbanlibrary. Notably, I opted to switch to docker altogether because going to the /etc directory to change some configurations was getting tedious.
I needed a central ...]]></description><link>https://thegreencodes.com/docker-image-optimization-tips-and-tricks-for-faster-builds-and-smaller-sizes</link><guid isPermaLink="true">https://thegreencodes.com/docker-image-optimization-tips-and-tricks-for-faster-builds-and-smaller-sizes</guid><category><![CDATA[Docker]]></category><category><![CDATA[Devops]]></category><category><![CDATA[Continuous Integration]]></category><category><![CDATA[optimization]]></category><category><![CDATA[Docker compose]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Tue, 07 Mar 2023 09:00:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/HjBOmBPbi9k/upload/4ff521b145b0f30c3eb3564d063da3e0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I have been making a couple of changes in the build and deployment process of <a target="_blank" href="https://thegreencodes.com/the-era-of-the-builder">The Urbanlibrary</a>. Notably, I opted to switch to docker altogether because going to the <code>/etc</code> directory to change some configurations was getting tedious.</p>
<p>I needed a central place for all this. I needed a localized address where I could get all my code and the requirements to, well, ‘just work’.</p>
<p><strong>Scenario:</strong></p>
<p>I deploy projects A and B to the same server. We might have two domain names, or each might use a different subdomain. To be sure, or if I wanted to change them, I would have to modify the nginx file(s) on the server.</p>
<p><em>Would it not be easier to look at these locally such that I deployed with confidence each time?</em></p>
<h2 id="heading-come-ye-docker">Come Ye Docker</h2>
<p>Consequently, I packaged my projects into their respective images and deployed them. All the while, I was keen on performance and memory consumption.</p>
<p><em>Questions:</em></p>
<p>How long does it take to build?</p>
<p>How big are the respective images?</p>
<p>What does CPU usage look like?</p>
<p>Are they truly that much safer than bare metal?</p>
<hr />
<p>In this journey of discovery, I built upon the following recommended practices of containerization - modifying each to suit what it needed to accomplish.</p>
<h3 id="heading-minimizing-the-number-of-layers">Minimizing the number of layers</h3>
<p>At its core, docker sits on the premise of layers. Case in point; creating a software engineering project will require an operating system, the core components that will let your programming library/language work, the programming language itself and the files that you write.</p>
<p>Similarly, when you go the docker way, you create a system where you are in control of these layers. Do you need library X or would Y work better? What about cron tasks? Does my system require cron or curl to be installed somewhere within?</p>
<p>Across the commands that we have in docker files, the following modify the image size:</p>
<p>COPY</p>
<p>RUN</p>
<p>ADD</p>
<p>What is common amongst the above is that they involve the movement of files either from the internet (RUN or ADD) or within your directory(COPY).</p>
<p><strong>Example:</strong></p>
<p>Take the following docker file.</p>
<pre><code class="lang-plaintext"># many layers
FROM python:3

RUN python -m pip install --upgrade pip
RUN python -m pip install --upgrade setuptools
RUN pip install -r requirements.txt
</code></pre>
<p>To optimize this, we can merge multiple RUN commands and or use ADD instead</p>
<p>Image 2:</p>
<pre><code class="lang-plaintext">FROM python:3
# notice the merge of RUN commands TO update the system and install any packages needed
RUN python -m pip install --upgrade pip \\
&amp;&amp; python -m pip install --upgrade setuptools \\
&amp;&amp; pip install -r requirements.txt
</code></pre>
<p>You notice that every time we run either of the commands highlighted above, the image size changes. The same does not apply to other docker file commands (CMD, ENTRYPOINT)as they are limited to creating intermediate layers (0 bytes).</p>
<h3 id="heading-choosing-the-right-image">Choosing the right image</h3>
<p>When it comes to choosing a base image for your containers, it is advised to use an image that matches your environment as closely as possible.</p>
<p><strong>Example:</strong></p>
<p>If deploying a java-based application, you would use the JDK image upfront rather than using an ubuntu-based image and installing the JDK on top of it. In this case, your Dockerfile would look as below:</p>
<p><code>FROM ubuntu:latest</code> vs <code>FROM openjdk:latest</code></p>
<p>This way, you free the image from having to install some apt dependency <strong>W</strong> all because it was needed by some background task that is recommended.</p>
<h3 id="heading-using-the-exact-image-tag-rather-than-choosing-the-latest-tag-for-the-image-base">Using the exact image tag rather than choosing the latest tag for the image base</h3>
<p>Correct. The previous Docker image file is wildly flawed.</p>
<p><strong>Example:</strong></p>
<p>Consider for a moment, that we are running a Django 1.17 project. However, our Dockerfile insists that it wants to build based on the latest version of python out there, so we add the following image.</p>
<pre><code class="lang-plaintext">FROM python:latest
</code></pre>
<p>What are the project dependencies that were deprecated? What module was moved or merged? What package had to change because the libraries of the latest python version no longer behave the same?</p>
<p>Instead, you could run, your product with a specified version:</p>
<pre><code class="lang-plaintext">FROM rustc:1.64.0
</code></pre>
<p>(<em>The above snippet assumes you are a rustacean, but the same principle applies to any code base you might have).</em></p>
<h3 id="heading-using-a-minimal-sized-base-image">Using a minimal-sized base image</h3>
<p>Getting back to layers, an image can be built based on another. To this end, your stack of choice, say python3 might come as is, that is python 3 or be based on the Debian or alpine images. These image versions can appear as below:</p>
<p>python:<a target="_blank" href="https://hub.docker.com/layers/library/python/3.9.16/images/sha256-18a98a1b5772864baf5f7cef5df1adb085669a0e1867d5634c4831ba8700d139?context=explore">3.9.16</a></p>
<p>python:3.9.16-slim</p>
<p>python:3.9.16-alpine</p>
<p>python: 3.9.6-slim-bullseye</p>
<p>To identify the base of your images, you observe the tags that follow. In the above case, images tagged with the keywords alpine are based on a<a target="_blank" href="https://alpinelinux.org/">lpine-linux</a> while those with the tags Jessie, stretch, buster and bullseye rely on Debian 8, 9, 10 and 11 respectively. The tag, <code>slim</code>*, is the trimmed version of the default image, that is, python:3.9.16 and may be included in either tag, Debian or just python default tags.</p>
<blockquote>
<p><strong>Note:</strong> The names jessie, stretch, buster and bullseye are not random but rather the actual names of the Debian Linux versions released at that time. Thus, if we had a new Debian linux version named, strange-happenings, we would consequently get a python image tagged: python3.9.16-strange-happenings.</p>
</blockquote>
<p>Of the mentioned, the safest bet is on using the default image. In this case, python:3.9.16. We use alpine when we want to have the bare minimum setup and are willing to install only the required packages manually.</p>
<p>Remember, however, that alpine-based images will have challenges in terms of <code>libc</code> dependencies ( musl-based vs not glibc). For reference, these are common C libraries that you might find in data science packages like pandas, scipy and so forth.</p>
<p>Let’s take a look at how these images might compare by pulling and doing an image size comparison.</p>
<p>From your terminal, pull the images, replacing the tags where needed.</p>
<pre><code class="lang-bash">docker pull python:3.9.16
docker pull python:3.9.16-slim
docker pull python:3.9.16-alpine
<span class="hljs-comment"># add --quiet flag to keep the logs out of your screen or at a minimal</span>
docker pull --quiet python: 3.9.6-slim-bullseye
</code></pre>
<p>To compare their sizes:</p>
<pre><code class="lang-bash">docker images
</code></pre>
<p>A great thread that you might be interested in is this: <a target="_blank" href="https://news.ycombinator.com/item?id=10782897">Super small images based on alpine linux</a>. To cap a comment that stood out for me:</p>
<blockquote>
<p>As another example, a co-worker recently was working with some (out-of-tree) gstreamer plugins, and the most convenient way to do so was with a docker image in which all the major gstreamer dependencies, the latest version of gstreamer, and the out-of-tree plugins were built from source. The offered image was over 10GB and 30 layers, took quite a while to download, and a surprising number of seconds to run. With just a few tweaks it was reduced to 1.1GB and a handful of layers which runs in less than a second. It was just a total lack of care for efficiency that made it 10x less efficient in every way, enough to actually reduce developer productivity … <a target="_blank" href="https://news.ycombinator.com/user?id=ploxiln">ploxiln</a> <a target="_blank" href="https://news.ycombinator.com/item?id=10785602">on Dec 23, 2015</a></p>
</blockquote>
<p>Remember; choose the right image based on your needs.</p>
<h3 id="heading-use-multi-stage-docker-files">Use multi-stage docker files</h3>
<p>The concept of multi-stage docker files entails breaking your project build process into more than one. In this case, if building a project with say golang, the build files and the dependencies needed for them would be on one image while the compiled file would be on another, ready to be run.</p>
<p>Likewise, if building a python project, the installation of the dependencies would be on one image while the actual production-ready application would be on another. The result would look something like <a target="_blank" href="https://github.com/MarvinKweyu/tambua-shamba/blob/main/tambuashamba_server/Dockerfile.prod">this</a>.</p>
<p>You can read more about this in the piece: <a target="_blank" href="https://thegreencodes.com/multi-stage-docker-files-vs-builder-patterns-tipping-the-scales">Multi-stage docker files vs builder patterns</a></p>
<blockquote>
<p><strong>Thought Digest:</strong> Did you know that when a Docker image is first built or used, Docker retains components that haven't changed, so it doesn't have to rebuild everything from scratch again? That’s called caching.</p>
</blockquote>
<h3 id="heading-only-install-the-required-dependencies">Only install the required dependencies</h3>
<p>Alluding to installing the image that closely resembles the stack you are using, having only the required dependencies is key. For instance, using an alpine-based image and installing git, node js, and java jdk to a program that needs none of them is baggage brought forward.</p>
<h3 id="heading-have-a-dockerignore-file">Have a .dockerignore file</h3>
<p>Your gitignore file knows to keep <code>node_modules</code> out of version control. Your docker image, however, does not. We keep any items that the image might add during installation later on or items that are not needed for the docker image to function.</p>
<h3 id="heading-running-your-docker-container-commands-as-a-non-root-user">Running your docker container commands as a non-root user</h3>
<p>Every time we create a Dockerfile and build its image, the base-image file places you in the place of the root user. That is, you know what you are doing. This leaves you vulnerable to attackers(users/processes) that can gain access to your host system. They can, consequently access the project files, copy or add more scripts and so forth.</p>
<p>In the same way, you are not expected to use a VPS as root nor do I expect to see the almighty <strong>#</strong> on your terminal(<em>an indication that you are navigating as root</em>).</p>
<p>To avert this, you create a non-root user in your docker image by adding a USER directive to your Dockerfile.</p>
<p>For example, to create a non-root user called <code>appuser101</code>:</p>
<pre><code class="lang-plaintext">FROM python:3.9.16
# Create user
RUN useradd -m appuser101
# Set user as default
USER appuser101
</code></pre>
<p>To run commands in the container as this new user, you can use the <code>docker exec</code> command as below:</p>
<pre><code class="lang-bash">docker <span class="hljs-built_in">exec</span> -u appuser101 -it &lt;container_name&gt; &lt;<span class="hljs-built_in">command</span>&gt;
</code></pre>
<h2 id="heading-where-we-stand">Where we stand</h2>
<p>So far, I have significantly reduced the sizes of my images and their build times as well as improved their maintainability. My billing has also changed. I get the room to have one or more projects for the price of one.</p>
<p>Is there more? I think so. I am pushing this to see how it goes but I will come back with more along this trail.</p>
<p><strong><em>A word to the wise:</em></strong></p>
<p><em>Caching is your friend. Caching is here to stay.</em></p>
]]></content:encoded></item><item><title><![CDATA[Multi-stage docker files Vs Builder patterns - tipping the scales]]></title><description><![CDATA[When it comes to containerization and packaging, docker has proven itself capable of shortening the development time and ensuring consistency across multiple environments. In this way, cross-team communication and collaboration have been made more ef...]]></description><link>https://thegreencodes.com/multi-stage-docker-files-vs-builder-patterns-tipping-the-scales</link><guid isPermaLink="true">https://thegreencodes.com/multi-stage-docker-files-vs-builder-patterns-tipping-the-scales</guid><category><![CDATA[Docker]]></category><category><![CDATA[docker images]]></category><category><![CDATA[containers]]></category><category><![CDATA[optimization]]></category><category><![CDATA[Devops]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Tue, 14 Feb 2023 05:24:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/FHLGDs4CkY8/upload/5b729869ef735bb903f416f1788db812.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When it comes to containerization and packaging, docker has proven itself capable of shortening the development time and ensuring consistency across multiple environments. In this way, cross-team communication and collaboration have been made more efficient, with decreased set-up time while management of issues that arise have ceased to be #ItIsYourMachine.</p>
<hr />
<p>Consider, for one moment, that you were building a project that required shipping to a different platform from the one we were using. Better yet, we want it to act exactly the same way as it does locally.</p>
<blockquote>
<p><strong>Sidenote:</strong> I have had my fair share of deployments during which some library was perfectly fine in development only to discover ubuntu 22.0 or some other version did not support it anymore.</p>
</blockquote>
<p>For this illustration, we shall take the program, <a target="_blank" href="https://github.com/MarvinKweyu/minigrep">marvinkweyu/minigrep</a>, a command-line tool that lets you search via text files; a mimic of the popular UNIX grep command-line utility.</p>
<p><em>How would you containerize this?</em></p>
<p><em>What method would be the most efficient given the resources?</em></p>
<p>Let us understand this.</p>
<p><strong>(Clone the minigrep command-line program to your local file system if you have not done so already)</strong></p>
<h2 id="heading-a-single-dockerfile">A single dockerfile</h2>
<p>Create a dockerfile at the root of the project directory that looks like below:</p>
<pre><code class="lang-plaintext">FROM rust:latest
WORKDIR /myawesomeapp
# copy the source file onto the /app directory
COPY . .
# compile into executable
RUN cargo build
# run the project
ENTRYPOINT ["./target/debug/minigrep", "to" , "poem.txt"]
</code></pre>
<p>Above, we tell minigrep to look for characters that match the consecutive <code>to</code>.</p>
<p>Finally, build your image as the first of its kind by running this in the same root directory:</p>
<pre><code class="lang-bash">docker image build -t minigrep:v1 .
</code></pre>
<p>What is the possible size of this build?</p>
<pre><code class="lang-bash">docker images minigrep
</code></pre>
<pre><code class="lang-bash">REPOSITORY                                TAG                   IMAGE ID       CREATED              SIZE
minigrep                                  v1                    c4c56d10c4b2   About a minute ago   1.41GB
</code></pre>
<p>You can play around with a container of the image to see what minigrep finds:</p>
<pre><code class="lang-bash">docker container run minigrep:v1
</code></pre>
<p>Observe: <a target="_blank" href="https://github.com/MarvinKweyu/minigrep/tree/v1.0.1">minigrep:v1</a></p>
<h2 id="heading-using-the-builder-pattern">Using the builder pattern</h2>
<p><em>The v2 to reproducible code</em></p>
<p>Earlier, we build our image using a single dockerfile. Along with the executable, it had non-essential build files. That is, files it did not need at run-time to actually work.</p>
<p>We could change this by creating two images instead. the first would contain all the necessary files we needed before the build and act as the image build. The second would contain only what was needed for the package to run.</p>
<p>The builder image would look similar to the normal build:</p>
<pre><code class="lang-plaintext">FROM rust:latest
WORKDIR /myawesomeapp
# copy the source file onto the /app directory
COPY . .
# compile into executable
RUN cargo build
# run the project
ENTRYPOINT ["./target/debug/minigrep", "to" , "poem.txt"]
</code></pre>
<p>In comes the runtime image:</p>
<pre><code class="lang-plaintext">FROM rust:latest
WORKDIR /myawesomeapp
# copy the source file onto the /app directory
COPY . .
# compile into executable
RUN cargo build
# run the project
ENTRYPOINT ["./target/debug/minigrep", "to" , "poem.txt"]
</code></pre>
<p>We minimize our image even further by using an alpine image, 5MB in size, rather than the 800MB default rust image.</p>
<blockquote>
<p>Remember, we have already compiled our code and all that it requires.</p>
</blockquote>
<p>To manage assets from one image to the other, we need to copy the compiled code onto the runtime image. A transfer of files between two images if you may.</p>
<p>To achieve this, we would navigate into a container of the <strong>build</strong> image, copy the compiled code onto the current working directory and let the <strong>runtime</strong> image dockerfile copy the required file(s) into itself as it creates the final image.</p>
<p>The command would look something like this:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># notice the path of the main built app. It is the same as where we copied our file in our working directory</span>
docker container cp minigrepv:/myawesomeapp/main .
</code></pre>
<p>Once this is done, we would then delete the initial build image as it is no longer required, giving us that one single docker image for spawning containers.</p>
<p>To shorten this and the cycle of commands you would have to run, create a <a target="_blank" href="http://develop.sh"><strong>develop.sh</strong></a> file with the following contents: (This assumes you have <code>bash</code> on your system)</p>
<pre><code class="lang-bash"><span class="hljs-comment"># !/bin/bash</span>
docker image build -t minigrep-build-image -f Dockerfile.build .
<span class="hljs-comment"># Create container from the build Docker image</span>
docker container create --name minigrepv2-build-container minigrep-build-image

<span class="hljs-comment"># Copy build items from build container to the local filesystem </span>
docker container cp minigrepv2-build-container:/myawesomeapp/target/debug/minigrep .
docker container cp minigrepv2-build-container:/myawesomeapp/poem.txt .
<span class="hljs-comment"># Build the runtime Docker image </span>
docker image build -t minigrep-runtime-image . 
<span class="hljs-comment"># Remove the build Docker container</span>
docker container rm -f minigrepv2-build-container 

rm minigrep
</code></pre>
<p>Our directory would look as below:</p>
<pre><code class="lang-bash">src
target
.gitignore
poem.txt
Cargo.lock
Cargo.toml
README.md
Dockerfile.build
Dockerfile
develop.sh
</code></pre>
<p>Run the <a target="_blank" href="http://develop.sh">develop.sh</a> file to build the images:</p>
<pre><code class="lang-bash">./develop.sh
</code></pre>
<p>This will build the two images, copy the compiled code from one container to the other and delete the build container.</p>
<p>Let’s see how our images differ: <code>docker images ls</code></p>
<pre><code class="lang-bash">REPOSITORY       TAG                  IMAGE ID       CREATED              SIZE
minigrep-runtime-image                    latest                0ef6f1b87748   14 seconds ago       11.8MB
minigrep-build-image                      latest                66d4a2a395c3   16 seconds ago       1.41GB
</code></pre>
<p>Walah! A whopping difference of over 1000MB!</p>
<hr />
<p>In our use of the builder pattern, we have managed to save up to 1GB of file storage in our final image size. The trade-off was that we had to create two docker files, build the first, copy the final file to the local directory, and only the n move this t the final image. Perhaps there is a shorter way.</p>
<p>To observe: <a target="_blank" href="https://github.com/MarvinKweyu/minigrep/tree/v1.0.2">minigrep: v2</a></p>
<h2 id="heading-multi-stage-dockerfiles">Multi-stage dockerfiles</h2>
<p>Much like the builder pattern, a multi-stage dockerfile will create intermediate images and have our final image of equivalent size. The pro to this methodology, however, is the use of a single Dockerfile. Behold, say goodbye to the bash script and the need to have files copied to the local filesystem before transferring to the final image.</p>
<pre><code class="lang-plaintext"># give the initial image a name
FROM rust:latest as build-image
# Set the working directory 
WORKDIR /myawesomeapp
# Copy source file from current directory to container 
COPY . .
# Build the application
RUN cargo build
#* build the final image 
# give this a name
FROM alpine:latest as runtime-image
# Set the working directory 
WORKDIR /myawesomeapp
# copy the compiled code from the initial image onto the runtime image
COPY --from=build-image /myawesomeapp/target/debug/minigrep .
COPY --from=build-image /myawesomeapp/poem.txt .
# Run the application 
ENTRYPOINT ["./minigrep", "to" , "poem.txt"]
</code></pre>
<p>Go ahead and inspect your image.</p>
<pre><code class="lang-bash">REPOSITORY                                TAG                   IMAGE ID       CREATED              SIZE
minigrep                                  v3                    2c4927420843   19 seconds ago       11.8MB
</code></pre>
<p>What a difference.</p>
<p>What does this look like in other projects? Can we build dependencies separately from the final image in interpreted languages?</p>
<blockquote>
<p>Hint: <a target="_blank" href="https://github.com/MarvinKweyu/tambua-shamba/blob/main/tambuashamba_server/Dockerfile.prod">TambuaShamba</a></p>
</blockquote>
<h2 id="heading-conclusion">Conclusion</h2>
<p>We could create a simple dockerfile for smaller products and applications, or go ahead and use multi-stage docker files. The choice remains to the engineer that <em>#builds</em>. Along the way, what you intend to #create , your capacity, your development experience and what you are willing to take differently all sum up to your ideal. Iterate.</p>
]]></content:encoded></item><item><title><![CDATA[Tambua Shamba - Highlighting soil organic carbon content across Kenyan farms]]></title><description><![CDATA[Introduction
The Covid-19 epidemic revealed the large gaps in our social systems, infrastructure, and outlook on life. We lost jobs, we lost loved ones, and we had to prioritize basic needs over impulse purchases; understanding that that extra brocco...]]></description><link>https://thegreencodes.com/tambua-shamba-highlighting-soil-organic-carbon-content-across-kenyan-farms</link><guid isPermaLink="true">https://thegreencodes.com/tambua-shamba-highlighting-soil-organic-carbon-content-across-kenyan-farms</guid><category><![CDATA[agriculture]]></category><category><![CDATA[side project]]></category><category><![CDATA[Geospatial]]></category><category><![CDATA[Entrepreneurship]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Wed, 08 Feb 2023 07:40:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1675841695138/d58dc367-bac3-48b3-8297-808983d7d8af.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<hr />
<h3 id="heading-introduction">Introduction</h3>
<p>The Covid-19 epidemic revealed the large gaps in our social systems, infrastructure, and outlook on life. We lost jobs, we lost loved ones, and we had to prioritize basic needs over impulse purchases; understanding that that extra broccoli is not so bad after all.</p>
<hr />
<p>Soil organic carbon is the measure of carbon stored in soil organic matter. It plays an essential role in determining the quality of soil and the productivity of a farm. Poor soil organic content can lead to soil erosion, reduced crop yields, and decreased water infiltration. Therefore, it is important for farmers to track the soil organic content of their farms and identify areas for improvement.</p>
<p>What if there was a way to map this data out? What if you could get a glimpse of which farms were performing better based on their soil organic carbon content?</p>
<p><img src="https://cdn-images-1.medium.com/max/1600/1*1cFFEMCtyZg7znJHUC-h1A.png" alt /></p>
<h3 id="heading-tambua-shamba">Tambua Shamba</h3>
<p>I developed Tambua Shamba, an analytical dashboard view of farms based on their soil organic content. This dashboard will enable users to view the best and worst farms based on their content measures, as well as to identify trends in soil measurements over time.</p>
<h4 id="heading-the-build">The Build</h4>
<p>I had to decide which tools to use to build this project. I could have used Phoenix LiveView, an elixir framework whose concurrency would have been beneficial if the project had multiple users at once. On the other hand, I could have gone with a REST API approach and opened the product up to different clients around the globe. I chose the former.</p>
<p>To maintain this project, I needed to answer a few questions:</p>
<p>1. How would farms be added?</p>
<p>2. Who would this product speak to?</p>
<p>3. Would it be as easy for a farmer to understand as it would be for a soil analyst?</p>
<p>4. How would anyone across the project trace their steps?</p>
<p>5. How would the data be rendered?</p>
<p>From a system design perspective, I wanted to record the actual files of the sources of data. I also needed a mechanism to track which farms belonged to which instance of a data update, as well as which farms existed in that specific update. Additionally, I needed to know who did the update and when it was done. All this would eventually need to be rendered on a map, plotted as a multi-polygon.</p>
<h4 id="heading-its-never-what-it-seems-the-challenges">It’s never what it seems — The Challenges</h4>
<p>The main challenge I encountered was ensuring data integrity. We could not have random file formats uploaded. For example, a video file recording should not be treated as a source of truth for a quantifiable entity. Additionally, if there are specific identifiers the farms require, then all farms must meet this spec.</p>
<p>Moreover, since data can be collected in multiple formats, we need to account for when a scientist uses polygons to demarcate farms on one occasion and a multipolygon on the next.</p>
<p>To render this information, we need to consider what happens when we have two farms to record data on. Would we get the same result if we queried for the best and worst farms? What would happen if we had two files with the exact same farms? What if we forgot to add a field on one of them?</p>
<h4 id="heading-hitting-the-nail-on-the-wall-navigating-product-edge-cases">Hitting the nail on the wall — Navigating product edge-cases</h4>
<p>To address these challenges, I overwrote the <code>ModelViewSet</code> <code>create</code> method to read and check the file before saving. I let the API accept CSV files as a data source as they are much easier to work with when inputting data into a database table. To ensure I did not get a duplicate list of best and worst farms, I filtered through the already returned list of best farms; <em>Warning: By no means is this scalable.</em></p>
<p>I also color-coded the farms to show what kind of farms we had and added popups to give more detail about specific farms. Conventionally, the project is split into modules and lazy loaded to reduce the bundle size and increase its speed.</p>
<h4 id="heading-the-horizon">The Horizon</h4>
<p>For the next release, I plan to add features such as asynchronous file management and a standard user management system to the dashboard. Additionally, I will look into providing more user-friendly features such as searching for farms by name and pinpointing their location on the map and updating information on farms.</p>
<p>This should let users have a comprehensive understanding of the soil organic content in their farms, as well as allow them to compare their farms to others in the same region.</p>
<p><strong>Indulge:</strong> <em>Can we include a data analytics engine that will enable users to track trends in their soil measurements over time?</em></p>
<p>For reference, the project can be found on <a target="_blank" href="https://github.com/MarvinKweyu/tambua-shamba/">marvinkweyu/tambua-shamba</a></p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>As I continue to build Tambua Shamba and explore the relationship between soil and food security, I invite you to join in the conversation. <strong>#build</strong></p>
<p><em>Originally published on</em> <a target="_blank" href="https://www.marvinkweyu.net/projects/tambua_shamba"><em>marvinkweyu/projects/tambua-shamba</em></a></p>
]]></content:encoded></item><item><title><![CDATA[Semantic Versioning vs Git commit hashing]]></title><description><![CDATA[As with all great software, we build our products and releases in the spirit of continuous delivery. It is akin to creating a picture memory of where your product was at that point in time - the SDLC snapshot.
In the packaging of one of my projects, ...]]></description><link>https://thegreencodes.com/semantic-versioning-vs-git-commit-hashing</link><guid isPermaLink="true">https://thegreencodes.com/semantic-versioning-vs-git-commit-hashing</guid><category><![CDATA[versioning]]></category><category><![CDATA[deployment automation]]></category><category><![CDATA[shipping]]></category><category><![CDATA[project management]]></category><category><![CDATA[Entrepreneurship]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Mon, 30 Jan 2023 05:05:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1674890047632/4811adfb-0ce6-4776-8d68-435064427c64.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As with all great software, we build our products and releases in the spirit of continuous delivery. It is akin to creating a picture memory of where your product was at <a target="_blank" href="https://thegreencodes.com/software-engineering-architectural-patterns">that point in time</a> - the SDLC snapshot.</p>
<p>In the packaging of one of my projects, I came across a scenario that caught me off guard: versioning. Specifically, my challenge came with the choice of what versioning system I would use or how I would combine multiple versioning techniques if the need arose.</p>
<p>Working with multiple teams and in different demographics, packaging has always been different. For one, we have the SemVer evangelists, the CalVer antagonists(e.g Ubuntu packaging), the build version engineers and my just discovered git commit hashing brooders. Lo! How The choices go on.</p>
<p>I want to share with you the two that have piqued my interest so far and what options I use to curate experiences for the web.</p>
<h3 id="heading-a-case-for-semantic-versioning">A Case for Semantic Versioning</h3>
<p>Semantic Versioning or simply <a target="_blank" href="https://semver.org/">SemVer</a>, is a system of packaging software in which major, minor and bug fixes or enhancements are noted.</p>
<p>MAJOR**.<strong>MINOR</strong>.**FIXES</p>
<p><strong>Examples:</strong></p>
<p><a target="_blank" href="https://github.com/django/django/releases/tag/4.1.5">Django 4.1.5</a></p>
<p><a target="_blank" href="https://github.com/marvinkweyu/ColorDetect">ColorDetect v1.6.0</a></p>
<p><a target="_blank" href="https://github.com/diogocavilha/fancy-git">fancy-git v7.1.9</a></p>
<p>Here, we would bump each version according to what purpose it serves. With this in mind, one of the major advantages that comes with SemVer is human readability. Engineers and users alike can clearly tell what came after the other. User A, will see that your product, <strong>‘Legendary Lemons’</strong> has a version, v3.0.0 while they have v1.2.0. Subsequently, they can tell that what is on your site is of a higher value if we were counting from 1 to 10. The same goes for your team members, albeit with a little more technicality.</p>
<h3 id="heading-git-commit-hashing-strikes-back">Git commit Hashing strikes back</h3>
<p>When it comes to using git commit hashing for software versioning, Fred Simon’s <a target="_blank" href="https://liquidsoftware.com/blog/the-7-deadly-sins-of-versioning-part-2/">7 Deadly sins of Versioning</a> comes to mind.</p>
<p><strong>Scenario</strong></p>
<p>What if I needed to consider a component that had no impact on either functionality, performance or quality? Would I release v1.4.<strong>5</strong> due to a spelling mistake in the README? Clearly, this is a developer-centred update in which a config file on the main branch needs to be updated for the project to run on the local environment. Should this be transferred to the user? What is the extent of items that should be? Ahh... the conundrum. Release management can be messy.</p>
<p>However, the challenge comes with interpretation. Surely <code>5517829933722</code> should mean something more than an array of digits. Is it higher than the others? Is it lower than the package I have?</p>
<blockquote>
<p>Release management can be messy.</p>
</blockquote>
<h3 id="heading-the-pill">The pill</h3>
<p>I packaged The Urbanlibrary as a docker container. We have dev-centered versioning and what is made known to the public. A mix and match if you may. Taking what works, modifying what I needed and sharing the much-needed value.</p>
<p><strong>Example:</strong></p>
<p>Consider the Windows operating system packaging. We have Windows 11, Windows 10 and so forth. In between these, we constantly have updates for the software. Patch upon patch each modifying the previous build.</p>
<p>I might as well merge these two schemas. Ultimately, what matters is that:</p>
<ol>
<li><p>The product has <a target="_blank" href="https://twitter.com/marvinus_j/status/1616175397137428480?cxt=HHwWgMDRkb-95-0sAAAA">clear documentation</a></p>
</li>
<li><p>I can see what happens across multiple builds</p>
</li>
<li><p>Automation sits at the center of deployment and changelogs happen on the fly as much as they can (I am not going to do an SSH every single time ).</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1674889040598/e9ea0cdd-1ce8-49ce-b42d-d8ca1f90d638.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>What I have come to understand is that just because something is well-known, does not always mean it is the right way to do it. There is a plethora of choices on the table and I welcome thoughts and conversations on the same. I am keen to discover what your team or you personally use or would use to version your project. Reach out, touch base and let’s <strong>#build</strong>.</p>
<p><strong>PS:</strong> For some anecdote, I stumbled on Julie’s <a target="_blank" href="https://youtu.be/q3qE2nJRuYM?t=147">video</a> on how she chose to version her projects in general.</p>
<p><strong>Image credits:</strong></p>
<p><a target="_blank" href="https://storyset.com/people"><strong>People illustrations by Storyset</strong></a><br /><a target="_blank" href="http://monkeyuser.com">Monkeyuser</a></p>
]]></content:encoded></item><item><title><![CDATA[The Value Chain Factory hackathon]]></title><description><![CDATA[Built by Africans and for Africans
It’s been a week since we had our first hackathon here at Value Chain Factory. A week since we had a buzz of activity with young engineers teeming with ideas on how to create the next solution that would address Afr...]]></description><link>https://thegreencodes.com/the-value-chain-factory-hackathon</link><guid isPermaLink="true">https://thegreencodes.com/the-value-chain-factory-hackathon</guid><category><![CDATA[Entrepreneurship]]></category><category><![CDATA[hackathon]]></category><category><![CDATA[Africa]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Fri, 18 Nov 2022 04:27:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1668716475197/qC5Y3Z5LM.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-built-by-africans-and-for-africans">Built by Africans and for Africans</h3>
<p>It’s been a week since we had our first hackathon here at Value Chain Factory. A week since we had a buzz of activity with young engineers teeming with ideas on how to create the next solution that would address Africa’s most daunting challenges.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668712343904/0qWwEXtlJ.jpg" alt="team_innovation.jpg" /></p>
<p>Over the weekend, my team had the pleasure of hosting one of the most exciting hackathons we have had this quarter. Our aim was to call upon innovators in the technical space to share and build upon their ideas on agriculture, health and transport; matters that are paramount in a mineral and nutrient-rich continent.</p>
<p>Of the possible startups brought forth, I thought I would mention a few notable ones. That is, that in conjunction with my team and the participants, would provide more value and be impactful in their own right.</p>
<h3 id="heading-lifeline-medicare">Lifeline medicare</h3>
<p>To assist emergency responders, team #lifelinemedicare created a solution that stores key details of their patients. Succinctly, the determining whether a particular treatment would be viable for an incapacitated patient.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668713033637/wYfqiWlYK.jpg" alt="team_nfc.jpg" /></p>
<h3 id="heading-smartbins">SmartBins</h3>
<p>With an ever-growing population, currently, at 8 billion, our primary approach to waste disposal and management has been to bury it. Practically equivalent to burying our heads in the sand and letting the tides of time do its thing. To address this, the smartbins startup would provide waste management services. Taking up this role from collection, recycling and selling of compost manure back to the local farmer.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668712752746/jUk9Ey3ir.jpg" alt="IMG_1857.jpg" /></p>
<h3 id="heading-the-farmer-market-bridge">The Farmer-market bridge</h3>
<p>To complete the cycle, the market bridge team would open up the marketplace to expose farmers to their immediate sellers. In a way, making the farmer aware of their produce’s movement through to the consumer.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668713224620/94UD718Ru.jpg" alt="market_bridge.jpg" /></p>
<p>What stood out was how these builders were willing to take a leap in validating their enterprises. An emerging trend amongst this lot of African engineers, was their embrace of new technology. From the use of NFC tags in medicine, the leverage of blockchain technology for transparent transactions to the use of geo-sensors in garbage collection. They took a step beyond ideation to provide the next possible solution.</p>
<p><strong>Remember:</strong></p>
<p>More important than starting a particular startup, is getting to meet a number of potential cofounders. From there, instead of working on what you intend to make and then finding the audience, work in the reverse by thinking of the public. Ideate.</p>
<blockquote>
<p>You should only start a startup if you feel compelled by a certain problem and you think starting a startup is the only way to solve it. The passion should come first, and the startup comes second. - Sam Altman</p>
</blockquote>
<p>Thus, to you the reader: <em>If you knew success was a certainty, what would you do?</em></p>
<p><strong>PS:</strong> Yes. My team came second. Because winning is what we do. Hi Wachira.</p>
]]></content:encoded></item><item><title><![CDATA[TechStartup weekend: The place of technology in Africa]]></title><description><![CDATA[I had the opportunity to participate in The #TechStartUpWeekend - a 3-day event aimed at bringing innovators from all fields and ages to participate in a challenge that would build solutions for Africa.

During this time, I got to interact with the b...]]></description><link>https://thegreencodes.com/techstartup-weekend-the-place-of-technology-in-africa</link><guid isPermaLink="true">https://thegreencodes.com/techstartup-weekend-the-place-of-technology-in-africa</guid><category><![CDATA[Entrepreneurship]]></category><category><![CDATA[technology]]></category><category><![CDATA[Africa]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Sat, 12 Nov 2022 17:34:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1668274390938/xVy8lgR8_.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I had the opportunity to participate in <a target="_blank" href="https://www.techstars.com/">The #TechStartUpWeekend</a> - a 3-day event aimed at bringing innovators from all fields and ages to participate in a challenge that would build solutions for Africa.</p>
<p><img src="https://res.cloudinary.com/dlxhllkxl/image/upload/v1668197057/Indulge/startupweekend_jrk63h.jpg" alt="StartupWeekend" /></p>
<p>During this time, I got to interact with the best in their fields; lawyers, psychologists, mechanical engineers , security analysts, fellow startup founders and so forth. Each of us was brought together to spark sustainable solutions that would impact our communities in one way or another.</p>
<p>Truth be told, it was a nerve-wracking 54-hour brain-storming session.</p>
<p><img src="https://res.cloudinary.com/dlxhllkxl/image/upload/v1668195812/Indulge/brainstorming_cn0hzu.jpg" alt="Brainstorming" /></p>
<p>Suffice it to say, from this, we brought to life a number of products:</p>
<ol>
<li><a target="_blank" href="https://twitter.com/startupwkndNBI/status/1510628698793336841">ABCs of mental Health</a> (A place to get mental to the corporate workforce)</li>
<li><a target="_blank" href="https://twitter.com/Knockknockke/status/1561970483372986368">Knock knock</a>(Accessible emergency services to those with hearing disabilities.)</li>
<li>Iko Network (A solution that provides easy registration to visitors within a premises)</li>
<li><a target="_blank" href="https://twitter.com/startupwkndNBI/status/1510621873285087240">Vamva</a> (A #fintech solution solving the barrier-to-growth problems faced by ride-hailing drivers and other mobility )</li>
<li>Caes International (An organisation that gives the local boda-boda rider rechargeable batteries.)</li>
<li>Instruct Kenya - An easy-to-access legal advisory platform</li>
<li>ShopOkoa - money management services to university students</li>
</ol>
<p>One point that resonated with me, however, was the fact that technology should not be the #1 go-to to solving the that Africa faces.</p>
<blockquote>
<p>Technology should not be the <strong>#1 go-to</strong> to solving the challenges that Africa faces.</p>
</blockquote>
<p>Rather than shoving technology down the throat of our future product users, our question should bring us back to one single question:</p>
<p><em>How will this product affect the local citizen(</em>mama mboga<em>)?</em></p>
<p>Along with the network built and the products created, I got #first-hand information as to the success points and pitfalls of pushing a successful product through the African market. How do you identify the different types of users, and tell whether that specific cluster needs what you have to offer?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1668166819366/YB4K4jEXY.jpg" alt="market_vaibility.jpg" /></p>
<p>Do the people want this? Talk with the people. Who are your users? How are they different? What are their needs?</p>
<blockquote>
<p>The best feedback you're going to get on your product is in the 3 seconds after you tell them the price.</p>
</blockquote>
<p>Ultimately, the baseline sits with where you intend to take your product and what solution it intends to tackle. Removing the technical jargon and complexity, we ask:</p>
<p><em>'Is this the most suitable way to solve this problem?'</em></p>
<p><em>Originally published at: https://www.marvinkweyu.net/indulge/the_place_of_technology_in_africa</em></p>
]]></content:encoded></item><item><title><![CDATA[Binary vs Interpolation Search]]></title><description><![CDATA[This guide acts as a follow-up to the talk Binary vs Interpolation Search.

Time complexity and search algorithms. A walk through their definition, purpose, use cases and constraints. A search algorithm is a technique used to locate an item in a cert...]]></description><link>https://thegreencodes.com/binary-vs-interpolation-search</link><guid isPermaLink="true">https://thegreencodes.com/binary-vs-interpolation-search</guid><category><![CDATA[algorithms]]></category><category><![CDATA[Binary Search Algorithm]]></category><category><![CDATA[Interpolation search]]></category><category><![CDATA[Time Complexity]]></category><category><![CDATA[#big o notation]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Tue, 11 Oct 2022 03:55:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1665460486022/QoBXANoch.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>This guide acts as a follow-up to the talk <a target="_blank" href="https://gdsc.community.dev/events/details/developer-student-clubs-taita-taveta-university-presents-data-structuresinterpolation-search-vs-binary-search/">Binary vs Interpolation Search</a>.</p>
</blockquote>
<p>Time complexity and search algorithms. A walk through their definition, purpose, use cases and constraints. A search algorithm is a technique used to locate an item in a certain data structure. </p>
<h3 id="heading-introduction">Introduction</h3>
<p>A search algorithm is a technique used to locate an item in a certain data structure. </p>
<p>Before we begin, you should have an understanding of the below:</p>
<ul>
<li>Arrays</li>
<li>Iteration and recursion</li>
</ul>

<p>Let's give an overview of time complexity and what it entails.
<br /></p>
<h3 id="heading-time-complexity">Time Complexity</h3>
<p>A way to show how the runtime of a function increases.</p>
<p>Broadly speaking, the time complexity of a program is grouped into three:</p>
<ul>
<li>Linear time</li>
<li>Constant time</li>
<li>Quadratic time</li>
</ul>
<p><strong>Linear Time O(n)</strong></p>
<p>The processing time of a program will increase as the size of the input increases. </p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665136435585/PcPZNmIT3.png" alt="linear-time.png" /></p>
<p><strong>Example</strong>
We can create a program that processes a list of items stored in an array. A case example can be a program to <a target="_blank" href="https://thegreencodes.com/command-line-arguments-part-2-argparse">process locally stored files</a>. </p>
<p><strong>Constant Time O(1)</strong></p>
<p>Here, no matter what input we parse to our program, we get the results in the same time frame. Hence, a process taking 10_000_000 items returns in the same time as the one taking in 7 items.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665136382730/moPmDSQSv.png" alt="constant-time.png" /></p>
<p><strong>Quadratic time O(n2)</strong></p>
<p>Where <em>n2</em> is n squared.
As the name suggests, a program will return results in a time period that resembles a quadratic curve. 
This time is common with multi-dimensional arrays/lists of lists, since:</p>
<ul>
<li>We loop over the list(say <em>A</em>) to get individual lists</li>
<li>We loop over a specific list(say <em>B</em>) in this list to get the item and perform an operation on it.</li>
</ul>
<p>For reference, the equation: </p>
<p><strong>a + bx + c</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665136484695/IuAkb3NKX.png" alt="quadratic-time.png" /></p>
<p><strong>Example:</strong> 
A program to calculate the product of integers in an array.</p>
<pre><code class="lang-java"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">array_products</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] a)</span></span>{
    <span class="hljs-keyword">int</span> product = <span class="hljs-number">0</span>; <span class="hljs-comment">// O(1)</span>
    <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> number: a){
       product = product * number; <span class="hljs-comment">// O(1)</span>
   }
<span class="hljs-keyword">return</span> product; <span class="hljs-comment">// O(1)</span>
}
</code></pre>
<p>We can get an overview of how long a function will take, based on how large of an array we have in this particular function/ method.</p>
<p>In our case, since we can get the time complexity of this function as below:</p>
<p><code>O(1) + n * O(1) + O(1)</code></p>
<p>Since we are adding a value to the summation <em>x</em> number of times, we have O(1) happening for each of those occurrences. Thus <em>n </em> O(1)*.</p>
<p>Since a constant +  another constant is still a constant.</p>
<p><code>O(1) + n * O(1)</code></p>
<p>Get the fastest-growing term from the equation, i.e:</p>
<p> <code>n * O(1)</code></p>
<p> Then remove the coefficient to get <code>O(n)</code> (linear time i.e, the function takes longer to complete the larger the array)</p>
<h2 id="heading-binary-search">Binary Search</h2>
<p>Given a <em>sorted</em> array, binary search locates an item in question, using the 'divide and conquor'</p>
<p><strong>Time complexity: 
O(log n)</strong></p>
<p><strong>Binary Search pseudocode</strong></p>
<ol>
<li>Get the first and last item of the sorted array.</li>
<li>Add the first and last item indexes and divide by 2</li>
<li>Get the element in the middle from the step above i.e middle</li>
<li>If the value at the middle index is equal to the searched item, return the index</li>
<li>If the value at the index is greater than the searched item, set the middle item to be the new high and discard the right</li>
<li>If the value at the index is less than searched item, make the item the new low and discard the left side</li>
<li>Repeat the process until the index is obtained</li>
<li>Return -1 if the item is absent</li>
</ol>
<p><strong>Visual representation</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665133315613/3pgwxJ_mp.gif" alt="binary_sequential_search.gif" /></p>
<p><strong>Implementation of binary search</strong></p>
<pre><code class="lang-java">
<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">search</span><span class="hljs-params">( <span class="hljs-keyword">int</span>[] a, target)</span></span>{
    <span class="hljs-keyword">int</span> arrayLength = a.length;
    <span class="hljs-keyword">int</span> left = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">int</span> right = a.length;

    <span class="hljs-keyword">while</span>(left &lt;= right){ 
       <span class="hljs-keyword">int</span> middle = (left + right) / <span class="hljs-number">2</span>;

       <span class="hljs-keyword">if</span>(a[middle] == target){ 
          <span class="hljs-keyword">return</span> middle;
        }

       <span class="hljs-keyword">if</span>(target &lt; a[middle]){
             right = middle - <span class="hljs-number">1</span>;
        }<span class="hljs-keyword">else</span>{
         left = middle + <span class="hljs-number">1</span>;
    }

  <span class="hljs-keyword">return</span> -<span class="hljs-number">1</span>;
}
</code></pre>
<p><strong>Applications of Binary Search</strong></p>
<ol>
<li>Database indexing</li>
</ol>
<p>Within your database of choice, a binary tree will be used where it will precompute the middle point on each step, until reaching the single item. More details of database indexing can be found <a target="_blank" href="https://medium.com/@vaibhavnamburi/database-indexing-making-your-database-fast-73b4b0615275">here</a></p>
<ol>
<li>3D games and applications. </li>
</ol>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Binary_space_partitioning">Binary space partitioning</a> occurs as space is divided into a tree structure and a binary search is used to retrieve which subdivisions to display according to a 3D position and camera.</p>
<ol>
<li><p>Git debugging with <a target="_blank" href="https://git-scm.com/book/en/v2/Git-Tools-Debugging-with-Git#Binary-Search">git bisect</a></p>
</li>
<li><p>Autocomplete search</p>
</li>
</ol>
<p>Consider a user typing in a URL on a browser. Given a history of searches, instead of going through each one and comparing, a binary search is used to perform a faster lookup across the history.</p>
<ol>
<li>Searching for prefixes</li>
</ol>
<p>Instead of an array of integers, you can have an array of strings where you intend to search for an item that starts with a certain string or character sequence.</p>
<ol>
<li><p>Going through a dictionary to find a word</p>
</li>
<li><p>Git cherry picking</p>
</li>
</ol>
<p><em>A clever example of where this is used is by <a target="_blank" href="https://www.quora.com/profile/Sarv-Shakti-Singh">Sarv Shakti</a>, who used it to identify <a target="_blank" href="https://qr.ae/pvZffW">what commit broke the application</a></em></p>
<blockquote>
<p><strong>Example:</strong> Consider a scenario where you have a list of maps storing student records in your classroom. Given a name, or phone number, which algorithm would you use to search through this? What if the records got to 10_000 or more? How would this <a class="post-section-overview" href="#resources-and-questions">grow</a>?</p>
</blockquote>
<hr />
<h2 id="heading-interpolation-search">Interpolation Search</h2>
<p>This is an improvement over binary search.
Gets an element from where it is more likely to exist.</p>
<p><strong>Time complexity: O(log log N)</strong></p>
<p><strong>Constraints of interpolation search</strong></p>
<ol>
<li>The array should be sorted</li>
<li>The array should be uniformly distributed.</li>
</ol>
<p><strong>Note:</strong>
Uniform distribution in an array implies that the difference between subsequent elements should be relatively equal. In this case, an array [10, 30, 300000, 23_000_000] would fail to meet this condition.</p>
<p><strong>Example:</strong> Searching for the word 'zelda' in a dictionary of words from letters 'a' to 'z'.</p>
<p>Instead of starting from the middle item in the array, we go closer to the end of the array.</p>
<p><strong>Time complexity and its relation to interpolation search</strong></p>
<p>A walk through the equations </p>
<p><code>y = m*x + c</code></p>
<p><code>arr[index] = m*index + c</code></p>
<p>where:
index: the position of the element in the array
arr[index]: the value at this index in the array</p>
<p><code>arr[low] = m*low + c —– (1)</code></p>
<p><code>arr[high] = m*high + c —– (2)</code></p>
<p>Subtract equation (1) from (2), and we get</p>
<p><code>arr[high] – arr[low] = m * (high – low)</code></p>
<p><code>m = (arr[high] – arr[low])  /  (high – low)  —– (3)</code></p>
<p>Say we are searching for an element, K in this array.</p>
<p><code>arr[index] = m*index + c</code></p>
<p>Then replacing target in the above equation, we get</p>
<p><code>target = m*index + c —– (4)</code></p>
<p><code>target – arr[low] = m * (index – low)</code></p>
<p><code>index – low = (target – arr[low]) / m</code></p>
<p><code>index = low + (target – arr[low]) / m</code></p>
<pre><code class="lang-python">index = low + (target - arr[low])*(high - low) / (arr[high] - arr[low])
</code></pre>
<p><strong>Example</strong></p>
<p>Array to search through:</p>
<p><code>[32, 35, 37, 39, 42, 44, 46, 48]</code></p>
<p>We will search for <code>target = 42</code> in the above array. </p>
<p>The size of the array is <code>8</code>.</p>
<p><code>low = 0</code>, </p>
<p><code>high = 7</code>, </p>
<p><code>arr[low] = 32</code>, </p>
<p><code>arr[high] = 48</code></p>
<pre><code class="lang-python">index = <span class="hljs-number">0</span> + (<span class="hljs-number">42</span> - <span class="hljs-number">32</span>) * (<span class="hljs-number">7</span> - <span class="hljs-number">0</span>) / (<span class="hljs-number">48</span> - <span class="hljs-number">22</span>) = <span class="hljs-number">2.6923</span> ~ <span class="hljs-number">2</span>

arr[<span class="hljs-number">2</span>] = <span class="hljs-number">37</span> &lt; <span class="hljs-number">42</span>
</code></pre>
<p>Remember to floor the value of the index</p>
<p><strong>Interpolation search pseudocode</strong></p>
<ol>
<li>Calculate the Index using the interpolation index formula.</li>
<li>If the target is smaller than the item at that index, search in the lower sub-list. Calculate the index for the left sub-array. Let low = index - 1</li>
<li>If the target is greater than the item at that index, search in higher sub-list. Calculate the position of the right sub-array by assigning low = index + 1.</li>
<li>If the target is a match, return the index of the item from the array and exit.</li>
<li>If it is not a match, probe position.</li>
<li>Repeat until the match or array is eventually 0</li>
</ol>
<p><strong>Implementation of Interpolation search</strong></p>
<pre><code class="lang-java"><span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">search</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] array, <span class="hljs-keyword">int</span> target)</span> </span>{
    <span class="hljs-keyword">int</span> n = array.length;
    <span class="hljs-keyword">int</span> low = <span class="hljs-number">0</span>;
    <span class="hljs-keyword">int</span> high = n - <span class="hljs-number">1</span>;

    <span class="hljs-keyword">while</span> (low &lt;= high) {

        <span class="hljs-keyword">int</span> index = low + ((target - array[low]) * (high - low)) / (array[high] - array[low]);

        <span class="hljs-keyword">if</span> (array[index] &lt; target) {
            low = index + <span class="hljs-number">1</span>;
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (array[index] &gt; target) {
            high = index - <span class="hljs-number">1</span>;
        } <span class="hljs-keyword">else</span> {

            <span class="hljs-keyword">return</span> index;
        }
    }

    <span class="hljs-keyword">return</span> -<span class="hljs-number">1</span>;
}
</code></pre>
<h3 id="heading-applications-of-interpolation-search">Applications of interpolation search</h3>
<p>Interpolation search can be used in the same areas where binary search is used. The only caveat is that this data must be uniformly distributed. A failure to meet this condition will give you a <a class="post-section-overview" href="#time-complexity">time complexity</a> of O(n).</p>
<h3 id="heading-benchmark">Benchmark</h3>
<p>Comparatively, given uniformly distributed data, this difference might occur as <a class="post-section-overview" href="#references">below</a>:</p>
<p><img src="https://res.cloudinary.com/dlxhllkxl/image/upload/v1665307817/Talks/search-benchmark_vs1uvz.jpg" alt="comparison graph" /></p>
<h2 id="heading-resources-and-questions">Resources and questions</h2>
<p>These are locations to practice your data structures along with links to various challenges that may hold the above mentioned concepts or pivot them accordingly.</p>
<ul>
<li><a target="_blank" href="https://leetcode.com/">Leetcode</a></li>
<li><a target="_blank" href="https://exercism.org">Exercism</a></li>
<li><a target="_blank" href="https://www.hackerrank.com">Hackerrank</a></li>
<li><a target="_blank" href="https://www.algoexpert.io/">Algoexpert</a></li>
</ul>
<ul>
<li><a target="_blank" href="https://leetcode.com/problems/two-sum/">The two sum problem</a></li>
<li><a target="_blank" href="https://leetcode.com/problems/how-many-numbers-are-smaller-than-the-current-number/">How many numbers are smaller than the current number</a></li>
<li><a target="_blank" href="https://leetcode.com/problems/middle-of-the-linked-list/">Middle of a linked list</a></li>
<li><a target="_blank" href="https://leetcode.com/problems/container-with-most-water/">Container with most water</a></li>
<li><a target="_blank" href="https://github.com/MarvinKweyu/TheAlgorithmCore">OpenSource collection - TheAlgorithmCore</a></li>
</ul>
<h3 id="heading-other-types-of-search-algorithms">Other types of search algorithms</h3>
<ul>
<li>Linear search / sequential search</li>
<li>Breadth-first search</li>
<li>Depth-first search</li>
<li>Jump search</li>
<li>Exponential search</li>
<li>Fibonacci Search</li>
</ul>
<h3 id="heading-conclusion">Conclusion</h3>
<p>There are more search algorithms out there. This is by no means a comprehensive list, and by no means are you expected to know all of them. A single algorithm can be used as the basis for other searches. With that said, there is no silver bullet. You choose what works based on the constraints at hand.</p>
<h2 id="heading-references">References:</h2>
<p>Mohammed, A. S., Amrahov, Ş. E., &amp; Çelebi, F. V. (2021). Interpolated binary search: An efficient hybrid search algorithm on ordered datasets. Engineering Science and Technology, an International Journal, 24(5), 1072–1079. https://doi.org/10.1016/j.jestch.2021.02.009</p>
<p>Manolopoulos, Y., Theodoridis, Y., &amp; Tsotras, V. (2012). Advanced Database Indexing. In Google Books. Springer Science &amp; Business Media. https://books.google.com/books?hl=en&amp;lr=&amp;id=pD3tBwAAQBAJ&amp;oi=fnd&amp;pg=PP13&amp;dq=+database+indexing+using+binary+search+&amp;ots=HecPStLWUK&amp;sig=9A5wLiIHxg1ygaiZ-UxiSob7-Qs</p>
<p><em>Originally published at https://www.marvinkweyu.net/talks/binary_vs_interpolation_search</em></p>
]]></content:encoded></item><item><title><![CDATA[Going Enterprise and its Aftermath]]></title><description><![CDATA[I thought I knew what scalability was. Just the same way most of us thought we knew what distributed systems were.

I realized I had to completely relearn these systems because of the cloud.        ~Satya Nadella

There are a number of considerations...]]></description><link>https://thegreencodes.com/going-enterprise-and-its-aftermath</link><guid isPermaLink="true">https://thegreencodes.com/going-enterprise-and-its-aftermath</guid><category><![CDATA[Entrepreneurship]]></category><category><![CDATA[scalability]]></category><category><![CDATA[project management]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[System Design]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Mon, 18 Jul 2022 13:08:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1655898753232/64UuP_9W-.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I thought I knew what scalability was. Just the same way most of us thought we knew what distributed systems were.</p>
<blockquote>
<p>I realized I had to completely relearn these systems because of the cloud.<br />        ~Satya Nadella</p>
</blockquote>
<p>There are a number of considerations that you as a developer, architect or engineering team have to make as your user base grows. Going from products with 10 to say 30 or a million and so forth has its considerations. This, of course, depends on the user base we are talking about. </p>
<p><em>Remember astute reader, a customer can be an organisation with a plethora of other members inside it, or just as well be a single user called Jack</em>. </p>
<p><strong><em>Explore with me</em></strong></p>
<p>Imagine thousands, half a million and so forth people performing a search query against a server. If those queries land on your end, would it break? Would it be able to hold?</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1655896705329/_btWC0KtA.png" alt="datacenter_scale_2x.png" /></p>
<p>We should be able to handle more data, more concurrent connections and higher interaction rates.</p>
<p><strong>A note on interaction rate:</strong></p>
<p>  How often a user changes the interface on a blog application vs a game.</p>
<hr />
<p>Before we begin, it is important to note that setting up our product for scalability should be as easy and cheap to grow 10x as it should at 0.2x as is common with startups whose needs change rapidly over a short period of time.</p>
<p>Foremost, there are two types of scaling we need to observe.</p>
<p>a) Vertical scalability</p>
<p>b) Horizontal scalability</p>
<p>Both of the aforementioned have their pros and cons - each with a use case which would be deemed fit. Let's narrow this down.</p>
<p><em>Example</em> :</p>
<p>For solo and relatively small ventures, you might opt for a VPS(virtual private server) which is essentially a physical machine holding multiple 'servers', yours included, each with its own OS and so forth. Once at a certain cap, you might see the need to increase resources and hence, the incremental hunt; more RAM, more storage, more CPU and so forth. almost everything gets more. </p>
<p>The example above, is one implementing vertical scaling, where, we upgrade the hardware and or the network throughput. In short, you do not need to modify your application architecture.</p>
<h2 id="heading-vertical-scalability">Vertical Scalability</h2>
<p>Broken to bits, we resolve to a number of techniques.</p>
<ul>
<li>Adding more drives in RAID arrays and thus distributing our reads and writes during database interaction.</li>
<li>Switching to solid-state drives from hard drives</li>
<li>Increasing the RAM</li>
<li>Adding more cores to the server to reduce the context switching.</li>
<li>Upgrading network adapters, especially for systems reliant on media file processing.</li>
</ul>
<p>There are a number of drawbacks, however. For instance, the change to a solid-state drive might not show a significant difference if working with MySQL which uses its own data structures for sequential disk operations or Cassandra. At a certain point, <a target="_blank" href="https://en.wikipedia.org/wiki/Lock_(computer_science)">lock contention</a> is bound to catch up and here, more CPU does little to any good. Vertical scaling also comes with a steep financial cost as you add more and more given the cash input doubles or triples as a unit of resource is added.</p>
<p><em>Example:</em></p>
<p>A RAM chip will double in cost as it grows in size. That is, x GB is $z , 2x GB is $2z and so forth. A reality check hits us once we get to a stage, say 128GB where the rules are not quite the same.</p>
<h2 id="heading-horizontal-scalability">Horizontal Scalability</h2>
<p>The alternative and preferred method - horizontal scaling. While it may come at a steep cost initially, it does get significantly cheaper as your enterprise grows to reach more users. Let's see how.</p>
<h3 id="heading-caching">Caching</h3>
<h4 id="heading-use-of-content-delivery-networks-cdn">Use of content delivery networks (CDN)</h4>
<p>To manage our assets, we save the hassle of having to perform the read and write operations on our own servers. Ever wondered why we have CDNs for most packages(Bootstrap, Material etc)?</p>
<p><em>Example:</em></p>
<p>We have our servers for, say <a target="_blank" href="https://thegreencodes.com/the-era-of-the-builder">UrbanDesk</a> in South Africa. For access, an audacious Sergei (hint - thy knowest thyself) an enthusiastic early adopter from Germany, will hit the CDN(which are just data centres on their own). The CDN, acknowledging it lacks this data - images in our case, will hit our server for the resources it needs (CSS, images, javascript) and serve it to him while storing the same data and resources for further calls to the site. In this way, the next time, the call does not have to go a whole continent away.</p>
<p><img src="https://imgs.xkcd.com/comics/the_cloud.png" alt="The Cloud" /></p>
<p>Services like Cloudflare, Cloudinary or GoogleCloud CDN should ring a bell.</p>
<p>We have our static assets sorted out, but what about our data?</p>
<h4 id="heading-edge-cache-servers">Edge Cache Servers</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1656524966263/fOEvH6oNE.png" alt="CacheScaling.png" /></p>
<p>I've expounded on the data server to include <strong>functional partitioning</strong>, yet , another enhancement to our scaling needs. The concept behind it is that our project should be decomposed into individual actions those components need to perform - to group components of our application based on what they do. </p>
<p>For instance, we have sections that address this page you are currently reading (thegreencodes.com), then others that speak to different types of users, say, those interested in merch (merch.thegreencodes.com), or the admin (admin.thegreencodes.com). Each of these sections has been compartmentalized. </p>
<p>We might also move the database to its own server and update our configs to point to it, hence to each its own, that is, the server the application runs and the server the database runs are different but still communicating.</p>
<p>You will notice that I also added the GeoDNS. It works very similarly to an ordinary DNS, the only difference being that it is ' geo-tagged '.</p>
<p><em>The DNS</em></p>
<p><em>A Domain Name Server(DNS) is a way to identify your server's IP address on the web. In this way, if your server has an IP of say 127.0.0.1, it is displayed as example.com, to whoever else is looking at it.</em></p>
<p><em>Back to GeoDNS</em></p>
<p>Essentially, when you attempt to connect to thegreencodes.com, the server IP will be resolved to the data centre closest to you. </p>
<p>Elaborately, once your product has a certain cap of users , serving all across the globe, having a single server in a single location might degrade the experience these very users get. </p>
<p><strong>Example</strong></p>
<p><em>Google has multiple servers. While you might connect to its root domain from Australia and person B from Germany, these might not be served from the same server. The GeoDNS works to resolve the IP addresses of these servers/ data centers based on the location of the end user.</em></p>
<p>You will access the same data, only without knowledge of what IP the domain you are visiting is currently resolving to.</p>
<p>What makes horizontal scaling stand out is the basis on which it stands. At its core, horizontal scaling lets you deploy and maintain your project on several medium or small servers. A single server does not necessarily have to be extensive with vast amounts of resources - we split the load between different servers.</p>
<p>Of note, is that we need to consider whether our project is <code>stateful</code> or <code>stateless</code>. What this means is to identify whether the split needs data and whether that data needs to be synchronised. </p>
<h4 id="heading-managing-data-in-stateful-horizontally-scaled-products">Managing data in stateful horizontally scaled products</h4>
<p>Behold, the <a target="_blank" href="https://twitter.com/marvinus_j/status/1549016362475028481?s=20&amp;t=dKqkup_XXxEnNNTwfZ-hSg">CAP theorem</a> and the ability to identify whether we need more reading or more writing of our database.</p>
<p>If we indeed have data that needs management, we might opt for three techniques.</p>
<p><strong>a)</strong>  Sharding by data
<strong>b)</strong>  Sharding by hash
<strong>c)</strong>  Data replication</p>
<p>On the one hand, we have sharding by data. In a case example similar to the one shown, we can have a database that holds data from those in Europe and another that holds data from those in America. </p>
<p>On the other hand, we can opt to use a consistent technique of hashing specific keys on our model and use those hashes to store data in different databases. For instance, hashing the <em>profile_id</em> and stating that data for users with the hash algorithm ABC will sit on this server and not the other. </p>
<p>The above are optimizations meant to prevent hitting the same database for all requests.</p>
<p>While not in-depth, I do intend to come back to this in future. So keep an eye up for this.</p>
<hr />
<p>More than the type of scaling, we have to consider a number of techniques and practices to maintain.</p>
<p>As these platforms grow, the following have to be considered.</p>
<h3 id="heading-testing">Testing</h3>
<p>There is more to testing than <a target="_blank" href="https://thegreencodes.com/series/vue-unit-testing">unit tests</a>. Larger systems eventually comprise of larger subsystems. How these systems work together (integration testing), whether the application is behaving according to the specification(functional testing), whether it can handle different loads (performance testing) and so forth.</p>
<h3 id="heading-logging">Logging</h3>
<p>The more the components, the more integration is needed and the more the system is prone to fail. The more servers we have, the higher the chances. We hope for the best, but prepare for the worst. Your team needs to know when a module went down, whether the data maintained its integrity, which modules are still up and so on. </p>
<p>Choose to go for the <a target="_blank" href="https://dslab.epfl.ch/pubs/crashonly.pdf">Crash-only</a> approach; let the system always be ready for a crash and whenever it reboots, it should be able to continue without human interaction. An example of such a system is Netflix's <strong>Chaos Monkey</strong> which runs to kill random components of the system within working hours to test its reliability.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>The practices above are intertwined. Functional partitioning would lead to the decomposition of the project, decomposition would lead to a '<a target="_blank" href="https://www.youtube.com/watch?v=GBTdnfD6s5Q">maybe</a>' use of microservices, this would bring a restructure of your team to smaller domain-driven teams, a change in how data is cached and managed and so forth. Build upon this. Go agile and iterate. This path is not linear, nor should it be treated as such.</p>
<p>Treat these principles as your northern star, but feel free to morph them based on the value they create for your business.</p>
<h4 id="heading-understand">Understand</h4>
<p>In the creation of sustainable software applications, we place the business logic at the centre. The inverse, you'll find, will get you great code, rather than solving the need to be addressed. </p>
<blockquote>
<p>By placing technology first, we may get a great rails application, but it may not be a great pharmaceutical application ~ Robert C. Martin</p>
</blockquote>
<p>Onto <a target="_blank" href="https://thegreencodes.com/series/architectural-patterns">Architecture</a> - the stuff we wish we'd gotten right at the start of our project. </p>
]]></content:encoded></item><item><title><![CDATA[Vue Unit Testing: The Breakdown]]></title><description><![CDATA[So far so good. We have our application boilerplate and have successfully written our first test for the home page of our todo application.
Next, we have to get through fetching, displaying this information and manipulating it.
Let's use beloved axio...]]></description><link>https://thegreencodes.com/vue-unit-testing-the-breakdown</link><guid isPermaLink="true">https://thegreencodes.com/vue-unit-testing-the-breakdown</guid><category><![CDATA[Vue.js]]></category><category><![CDATA[TDD (Test-driven development)]]></category><category><![CDATA[Testing]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[project management]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Thu, 26 May 2022 17:13:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1653584307355/jc3DUGCoI.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>So far so good. We have our application boilerplate and have successfully written our first test for the home page of our todo application.</p>
<p>Next, we have to get through fetching, displaying this information and manipulating it.</p>
<p>Let's use beloved <code>axios</code> to grab and interact with our API.</p>
<pre><code class="lang-bash">npm install --save axios
</code></pre>
<p>For our application, we'll use an already created database - <a target="_blank" href="https://my-json-server.typicode.com/TheGreenCodes/awesome-todo-database/">TheGreenCodes data source</a>.
In the same manner of thinking as before, we create tests for the non-existent feature; listing to-do items.</p>
<p>We shall display uncategorised items on one page, all the incomplete items on another, and then follow and display those that have actually been completed on the last page.</p>
<p>As we are starting off, we ensure, just like before, that since we have nothing in our database, yet, we display an appropriate message. Among others, here are the questions we need to ask:</p>
<ul>
<li>Does it show an appropriate message if no item exists in the database yet?</li>
<li>Does our application fetch to-do items if any?</li>
<li>Does the app show any error message in case it cannot get to the server?</li>
<li>Can I even create a task?</li>
</ul>
<p>Bear with me on this one. In the spirit of TDD, we are going to write our application based on our tests. So from here on out, no UI until we have something complete. That is, after all, the whole point of testing; pushing code with the confidence it is not going to break. </p>
<p>Modify the test suit to watch for changes in our test files. That way, we do not have to run <code>npm run test: unit</code> after every modification. </p>
<p>Load your <code>package.json</code> and add the below:</p>
<pre><code class="lang-json">...
<span class="hljs-string">"test:unit"</span>: <span class="hljs-string">"vue-cli-service test:unit"</span>,
<span class="hljs-string">"test:unit:watch"</span>: <span class="hljs-string">"vue-cli-service test:unit --watchAll"</span>, <span class="hljs-comment">// line to add</span>
...
</code></pre>
<p>From here, we open our console and run:</p>
<pre><code class="lang-bash">npm run <span class="hljs-built_in">test</span>:unit:watch
</code></pre>
<p>Leave it open for now. You can always open it to see any changes that may occur.
Let's fulfil our queries as we go.</p>
<p>We want our home page to display the 'empty database' message for an empty database. Let's test that.</p>
<p>To start, we do some modifications to our test suite, making it easier to work with as it grows.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { BootstrapVue, BootstrapVueIcons } <span class="hljs-keyword">from</span> <span class="hljs-string">'bootstrap-vue'</span>
<span class="hljs-keyword">import</span> Vue <span class="hljs-keyword">from</span> <span class="hljs-string">'vue'</span>


describe(<span class="hljs-string">'Home.vue'</span>, <span class="hljs-function">() =&gt;</span> {
<span class="hljs-comment">// before any test case in this test suite, import and use bootstrap UI components </span>
  beforeEach(<span class="hljs-function">() =&gt;</span> {
    Vue.use(BootstrapVue)
    Vue.use(BootstrapVueIcons)
  })
  it(<span class="hljs-string">'Displays welcome message'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> wrapper = shallowMount(Home)
    <span class="hljs-keyword">const</span> welcomeMessage = <span class="hljs-string">'Welcome to TheGreenCodes awesome to-do list'</span>
    expect(wrapper.text()).toMatch(welcomeMessage)
  })
)}
</code></pre>
<p>Along with the other previous imports, we import bootstrap UI components. </p>
<p><strong>Remember:</strong> </p>
<blockquote>
<p>Our test case is assuming a black box. We are testing this specific component. Nothing outside. So it does not know what we have. Without the use of the UI import, the test would surely work but will show a warning as to what <code>b-container</code> or <code>b-card</code> means. It doesn't know.</p>
</blockquote>
<p>Let's test for a message in case there are no to-do items. We expect this <em>to fail</em> at the first instance as we have not implemented any feature to display to-do items.</p>
<p> Append the below code snippet to your suite:</p>
<pre><code class="lang-javascript">
  it(<span class="hljs-string">'Displays a message when there are no todo items'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> wrapper = shallowMount(Home, {
      data () {
        <span class="hljs-keyword">return</span> {
          <span class="hljs-attr">todoItems</span>: <span class="hljs-literal">null</span>
        }
      }
    })

    <span class="hljs-keyword">const</span> titleFound = wrapper.find(<span class="hljs-string">'h4'</span>)
    <span class="hljs-keyword">const</span> emptyTodoListMessage = <span class="hljs-string">'You have no existing todo!'</span>
    expect(titleFound.text()).toMatch(emptyTodoListMessage)
  })
</code></pre>
<p><span><em>Reasoning</em></span></p>
<p>We mount the Home component and set a data property to hold the data from the API. We also grab the <code>h4</code> tag, an element we expect to hold the message when there are no items on the to-do list. </p>
<p>We should also check that this 'You have no existing todo!' message does not display if there are indeed items on our to-do list.</p>
<pre><code class="lang-javascript">
  it(<span class="hljs-string">'Does not display message when there are todo items'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> wrapper = shallowMount(Home, {
      data () {
        <span class="hljs-keyword">return</span> {
          <span class="hljs-attr">todoItems</span>: [{ <span class="hljs-attr">id</span>: <span class="hljs-string">'1'</span>, <span class="hljs-attr">title</span>: <span class="hljs-string">'new item'</span>, <span class="hljs-attr">content</span>: <span class="hljs-string">'make awesome content'</span> }]
        }
      }
    })
    expect(wrapper.find(<span class="hljs-string">'h4'</span>).exists()).toBe(<span class="hljs-literal">false</span>)
  })
</code></pre>
<p>Run the tests, in case you have not done so yet,  and take a look at the spectacular failure. </p>
<p><strong>PS to self:</strong></p>
<blockquote>
<p>Stop logging 'madness' on Sentry servers.</p>
</blockquote>
<p>Let's fix this.</p>
<pre><code class="lang-js">&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"home"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Welcome to TheGreenCodes awesome to-do list<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">b-card</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list-container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h4</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"!todoItems"</span>&gt;</span>You have no existing todo!<span class="hljs-tag">&lt;/<span class="hljs-name">h4</span>&gt;</span>

      <span class="hljs-tag">&lt;/<span class="hljs-name">b-card</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
&lt;/template&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">'axios'</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">name</span>: <span class="hljs-string">'Home'</span>,
  data () {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">todoItems</span>: <span class="hljs-literal">null</span>
    }
  }
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">scoped</span>&gt;</span><span class="css">
<span class="hljs-selector-class">.list-container</span>{
    <span class="hljs-attribute">max-width</span>: <span class="hljs-number">170%</span>;
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>As you may have noticed, we have redundant code. We create a new <code>wrapper</code> each time we have a test. We can have this centralized. Modify your test to look as below. We explain, as always what each means.</p>
<p>For brevity, we ignore other components of the test file.</p>
<pre><code class="lang-js">...

describe(<span class="hljs-string">"Home"</span>, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> build = <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> wrapper = shallowMount(Home, {});
    <span class="hljs-keyword">return</span> { wrapper };
  };
  beforeEach(<span class="hljs-function">() =&gt;</span> {
    Vue.use(BootstrapVue);
    Vue.use(BootstrapVueIcons);

  });

...
</code></pre>
<p>At the very top of the description statement of the test, we <code>shallowMount</code> the <code>Home</code> component. That said, further tests can be used as below:</p>
<pre><code class="lang-js">
 it(<span class="hljs-string">"Displays application title"</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { wrapper } = build();

    <span class="hljs-keyword">const</span> welcomeMessage = <span class="hljs-string">"Welcome to TheGreenCodes awesome to-do list"</span>;
    expect(wrapper.text()).toMatch(welcomeMessage);
  });

  it(<span class="hljs-string">"Displays a message when there are no todo items"</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { wrapper } = build({});

    wrapper.setData({
      <span class="hljs-attr">todoItems</span>: []
    });

    <span class="hljs-keyword">const</span> titleFound = wrapper.find(<span class="hljs-string">"h4"</span>);
    <span class="hljs-keyword">const</span> emptyTodoListMessage = <span class="hljs-string">"You have no existing todo!"</span>;
    expect(titleFound.text()).toMatch(emptyTodoListMessage);
  });
</code></pre>
<p>With this refactor, we declare at the very start that it is the <code>Home</code> component in testing mode. We make the code cleaner and reduce having to remember that every time since we know that only the component's properties would be changing every time.</p>
<p>To set these individual properties, we can call the methods: <code>setData</code>, <code>setMethods</code>, <code>setProps</code> and so forth directly.</p>
<p>Because our component has no children, we navigated to <code>shallowMount</code>. However, if it did and we wanted to show whatever these children have in them as well, we could as well call <code>mount</code> and import it from the same path we got <code>shallowMount</code>.</p>
<p><strong>What about the listing of all items?</strong></p>
<pre><code class="lang-js">
<span class="hljs-comment">// add imports</span>
...
import axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> flushPromises <span class="hljs-keyword">from</span> <span class="hljs-string">"flush-promises"</span>;


<span class="hljs-comment">// more tests go here</span>
...

it(<span class="hljs-string">"Gets all todo items regardless of status"</span>, <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">const</span> { wrapper } = build();

    <span class="hljs-keyword">const</span> expectedItems = {
      <span class="hljs-comment">// ToDo: our items contain articles to read</span>
      <span class="hljs-attr">data</span>: [
        {
          <span class="hljs-attr">id</span>: <span class="hljs-string">"1"</span>,
          <span class="hljs-attr">title</span>: <span class="hljs-string">"TheGreenCodes: Unit testing in Vue"</span>,
          <span class="hljs-attr">content</span>: <span class="hljs-string">"A guide to better predictable code."</span>,
          <span class="hljs-attr">complete</span>: <span class="hljs-literal">true</span>
        },
        {
          <span class="hljs-attr">id</span>: <span class="hljs-string">"2"</span>,
          <span class="hljs-attr">title</span>: <span class="hljs-string">"TheGreenCodes: Tests must fail"</span>,
          <span class="hljs-attr">content</span>: <span class="hljs-string">"Building blocks to test driven development"</span>,
          <span class="hljs-attr">complete</span>: <span class="hljs-literal">false</span>
        },
        {
          <span class="hljs-attr">id</span>: <span class="hljs-string">"3"</span>,
          <span class="hljs-attr">title</span>: <span class="hljs-string">"TheGreenCodes: Tests must also pass"</span>,
          <span class="hljs-attr">content</span>: <span class="hljs-string">"This share"</span>,
          <span class="hljs-attr">complete</span>: <span class="hljs-literal">false</span>
        }
      ]
    };
    <span class="hljs-comment">// on axios call, use expectedItems object</span>
    jest.spyOn(axios, <span class="hljs-string">"get"</span>).mockResolvedValue(expectedItems);

    <span class="hljs-keyword">await</span> wrapper.vm.getToDoItems();
    <span class="hljs-comment">// make sure API request promises are complete before looking for articles to read</span>
    <span class="hljs-keyword">await</span> flushPromises();

    expect(axios.get).toHaveBeenCalledTimes(<span class="hljs-number">1</span>);
    expect(axios.get).toHaveBeenCalledWith(<span class="hljs-string">"todos/"</span>);

    expect(wrapper.vm.todoItems).toEqual(expectedItems.data);

    <span class="hljs-comment">// Finally, we make sure we've rendered the content from the API.</span>
    <span class="hljs-keyword">const</span> todos = wrapper.findAll(<span class="hljs-string">'[data-test="todo"]'</span>);
    expect(todos).toHaveLength(<span class="hljs-number">3</span>);


    <span class="hljs-comment">// we have articles now</span>
    expect(wrapper.html().includes(<span class="hljs-string">"You have no existing todo!"</span>)).toBe(<span class="hljs-literal">false</span>);
    expect(wrapper.html().includes(<span class="hljs-string">"TheGreenCodes: Unit testing in Vue"</span>)).toBe(
      <span class="hljs-literal">true</span>
    );
  expect(
      wrapper.html().includes(<span class="hljs-string">"Building blocks to test driven development"</span>)
    ).toBe(<span class="hljs-literal">true</span>);
  });
</code></pre>
<p>Through this case, we build an object we expect to get as a response. It returns a list of the series you are reading right now.</p>
<p>We say, <em>' Whenever you call on <code>axios</code> with a <code>get</code> request, return data that looks similar to this - '</em></p>
<p>Since our component calls the <code>getToDoItems</code> method, we can call it directly by using <code>await wrapper.vm.getToDoItems()</code>. This is almost similar to how we edited or set our data before.</p>
<p>Because the call is asynchronous, i.e, a request is made to the server and data sent back, we have to ensure our data replicates a wait time as well. For this, we call to <code>flushPromises</code> after adding it to the list of imports.</p>
<p>We are also ascertain that the get request is made only once and to the specific URL we need it to.</p>
<p>As axios will return the information wrapped in an inner <code>data</code> object, we want our data to get out of that to be compared directly to an array we intend to store. Thus the line:</p>
<pre><code class="lang-js">expect(wrapper.vm.todoItems).toEqual(expectedItems.data);
</code></pre>
<p>For the last part, this should come out clearly.</p>
<p>If you have seen the light at the end, you might have seen the errors all snarly and already changed your <code>Home</code> component. For reference:</p>
<pre><code class="lang-js">&lt;template&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"home"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Welcome to TheGreenCodes awesome to-do list<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">b-card</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"list-container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">h4</span> <span class="hljs-attr">v-if</span>=<span class="hljs-string">"todoItems.length &lt; 1"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"empty-list"</span>&gt;</span>
          You have no existing todo!
        <span class="hljs-tag">&lt;/<span class="hljs-name">h4</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">v-else</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">b-list-group</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">b-list-group-item</span>
              <span class="hljs-attr">v-for</span>=<span class="hljs-string">"(item, index) in todoItems"</span>
              <span class="hljs-attr">:key</span>=<span class="hljs-string">"index"</span>
              <span class="hljs-attr">data-test</span>=<span class="hljs-string">"todo"</span>
            &gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"d-flex justify-start"</span>&gt;</span>
                {{ item.title }}
              <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>

              <span class="hljs-tag">&lt;<span class="hljs-name">article</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"d-flex justify-start"</span>&gt;</span>
                {{ item.content }}
              <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">b-list-group-item</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">b-list-group</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">b-card</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
&lt;/template&gt;

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">name</span>: <span class="hljs-string">"Home"</span>,
  data() {
    <span class="hljs-keyword">return</span> {
      <span class="hljs-attr">todoItems</span>: [],
      <span class="hljs-attr">errorFound</span>: <span class="hljs-literal">null</span>,
    };
  },
  created() {
    <span class="hljs-built_in">this</span>.getToDoItems();
  },
  <span class="hljs-attr">methods</span>: {
    getToDoItems() {
      axios
        .get(<span class="hljs-string">"todos/"</span>)
        .then(<span class="hljs-function">(<span class="hljs-params">res</span>) =&gt;</span> {
          <span class="hljs-built_in">this</span>.todoItems = res.data;
        })
        .catch(<span class="hljs-function">(<span class="hljs-params">error</span>) =&gt;</span> {
          <span class="hljs-built_in">this</span>.errorFound = error;
        });
    },
  },
};
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">style</span> <span class="hljs-attr">scoped</span>&gt;</span><span class="css">
<span class="hljs-selector-class">.list-container</span> {
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">170%</span>;
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span></span>
</code></pre>
<p>This change should make our current tests pass. </p>
<p>Zoom in on this line:</p>
<pre><code class="lang-js">...
&lt;b-list-group-item
              v-<span class="hljs-keyword">for</span>=<span class="hljs-string">"(item, index) in todoItems"</span>
              :key=<span class="hljs-string">"index"</span>
              data-test=<span class="hljs-string">"todo"</span> 
            &gt;
...
</code></pre>
<p>To be specific <code>data-test="todo"</code>.</p>
<p>This is a property added to the list of items for the articles yet to be read. This helps us call: </p>
<pre><code class="lang-js"> <span class="hljs-keyword">const</span> todos = wrapper.findAll(<span class="hljs-string">'[data-test="todo"]'</span>);
</code></pre>
<p>You can equate this to a CSS <code>class</code> that is relevant to writing unit tests. We all the items in one swoop and check their length.</p>
<p>We can go on with the tests and features but this is the baseline; </p>
<ul>
<li>Write your failing tests</li>
<li>Make the tests pass</li>
<li>Refactor the code.</li>
</ul>
<p>Working iteratively through this , enables not just error-free code, but also prevents us from writing extra redundant code.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1653583402566/kGbZhQ8QJ.png" alt="FeatureComplete.png" /></p>
<p>Over the lifetime of the repository,<a target="_blank" href="https://github.com/TheGreenCodes/awesome-todo">awesome-to-do</a>, we shall iterate through this process and come up with a complete application. I invite both you and your counterpart in crime, to join in and build better software together. </p>
<p>Alas! Let the OpenSource contributions begin.</p>
<p>Regards,</p>
<p>Marvin K.</p>
<p><strong>PS:</strong> <em>Picture creds: monkeyuser.com</em></p>
]]></content:encoded></item><item><title><![CDATA[The era of the builder]]></title><description><![CDATA[I start this piece at the big bang of it all; TheGreenCodes and all it entails.

This here goes out to all those who have reached out or are yet to, with regards to articles shared, both new and old.
To you, the reader that you are and builder that k...]]></description><link>https://thegreencodes.com/the-era-of-the-builder</link><guid isPermaLink="true">https://thegreencodes.com/the-era-of-the-builder</guid><category><![CDATA[project management]]></category><category><![CDATA[software development]]></category><category><![CDATA[Entrepreneurship]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[Open Source]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Mon, 31 Jan 2022 13:43:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1643633791631/7UVsvEnwI.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I start this piece at the big bang of it all; <a target="_blank" href="https://thegreencodes.com/">TheGreenCodes</a> and all it entails.</p>
<blockquote>
<p><em>This here goes out to all those who have reached out or are yet to, with regards to articles shared, both new and old.</em></p>
<p><em>To you, the reader that you are and builder that keeps at it.</em></p>
</blockquote>
<p>I took a moment, a beat, to reflect on why I got started. The reason as to why the wheels turned to this particular alley, consequently bringing with it an array of an audience.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1643630363893/IZD8ueQey.png" alt="Bricklayer-bro.png" /></p>
<p>This here outlines an engineer's path to a targetted mastery. A nudge towards paths, journeys and challenges he encounters on his quest; a story by all means.</p>
<p>For the frequents, '<em>welcome back</em> ' and to the visitors '<em>we are glad you made it</em>'.</p>
<p>Over the last three years or so, I have journeyed with engineers across the board towards writing pages, useful to both us and those around us. It has been a tremendous journey, down to its hours of reading and research to beckon what I thought best for the audience at the time. Three years in, and here we are.</p>
<p>Series that have sparked <a target="_blank" href="https://thegreencodes.com/series">conversation or passionate debates</a> and those once-in-a-while articles that open up doors to collaboration and open source contribution. Hurrah!</p>
<p>A heads up to all those unexpecting eyes and ears, and in the words of those before me:</p>
<blockquote>
<p><strong>I refuse to be nothing but a full-time blogger.</strong></p>
</blockquote>
<p>As I take the time to pass this along, I open up the box of what is to come through this next phase; the builder's era.</p>
<p>With this, comes a voyage through which I shall not only share the nuggets of my findings but build around those same <a target="_blank" href="https://thegreencodes.com/software-engineering-principles-to-live-by">principles</a> and <a target="_blank" href="https://thegreencodes.com/software-engineering-architectural-patterns">guidelines</a>.</p>
<p>For the start of this, however, I share with you <a target="_blank" href="https://urbanlibrary.marvinkweyu.net/">Project Urbanlibrary</a> to lead you into the world of content aggregation.</p>
<p>Along the way, I share routines and practices that have helped and still help to keep me sane in both mind and body. Keep healthy at all times and make time for your wellness, lest you are forced to make time for your illness - <a target="_blank" href="https://thegreencodes.com/a-developers-mental-day">balanced, as all things should be</a>.</p>
<p>Note to a future self and anyone else reading this:</p>
<blockquote>
<p>Good work isn't created in a vacuum and the experience of art is a two-way street; incomplete without feedback. - Kleon Austin</p>
</blockquote>
<p>I keep it short. I keep it sweet. Just like Thanksgiving.</p>
<p>So who are we? We are TheGreenCodes and at its heart, is a drive to build and talk about what we have built and continue to build. I urge both you and the friend you share this with, <a target="_blank" href="https://twitter.com/marvinus_j">to join us</a> and discover a place that could be.</p>
<p>Regards,</p>
<p><a target="_blank" href="https://www.marvinkweyu.net/">Marvin Kweyu</a></p>
]]></content:encoded></item><item><title><![CDATA[The Age of Monolithic systems]]></title><description><![CDATA[Coming in first in the series; the monoliths of web applications - monolithic architectural patterns. 
Broken down, a monolithic system is one that is deployed as a single unit of interconnected components.
Let's give an example.
We are creating a ho...]]></description><link>https://thegreencodes.com/the-age-of-monolithic-systems</link><guid isPermaLink="true">https://thegreencodes.com/the-age-of-monolithic-systems</guid><category><![CDATA[software architecture]]></category><category><![CDATA[software development]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[project management]]></category><category><![CDATA[2Articles1Week]]></category><dc:creator><![CDATA[Marvin Kweyu]]></dc:creator><pubDate>Mon, 10 Jan 2022 12:43:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1641195274699/LnGU5IgVS.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Coming in first in <a target="_blank" href="https://thegreencodes.com/series/architectural-patterns">the series</a>; the monoliths of web applications - monolithic architectural patterns. </p>
<p>Broken down, a monolithic system is one that is deployed as a single unit of interconnected components.</p>
<p>Let's give an example.</p>
<p>We are creating a hotel management system for our local favourite spot in <a target="_blank" href="https://thegreencodes.com/preparing-django-for-deployment">Django</a>. Our application will hold, amongst other things, account management , rooms, rating and so forth. Break it into as many modular applications as you might come up with.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641238805893/NH9OndSNt.png" alt="LocalHotel.png" /></p>
<p>Essentially, a monolithic system is one in which multiple smaller applications live within the same server, share a file system and same database. Sound familiar? To easily identify if a project is monolithic, ask, can you scale an individual modular part of the application (memory or CPU) while leaving other apps unattended? If not, then this is a monolithic application.</p>
<p>Projects built like this are known to be simple in terms of development, easy to scale up to a certain cap, easy to deploy and be fast during the development phase. Fast, because all its components are together hence easy to collect and it would be written majorly in one language hence no need to learn another language/framework.</p>
<p>Have in mind , for instance, a java application using a jar file that contains all the apps logic for deployment.</p>
<p>A common architectural pattern , one we aim to discuss , that follows this , is the layered architectural pattern.</p>
<h2 id="heading-the-layered-architectural-pattern-n-tier-architecture">The  Layered Architectural Pattern (n-tier architecture)</h2>
<p>Governed by the <a target="_blank" href="https://thegreencodes.com/software-engineering-principles-to-live-by">Single responsibility Principle</a> -  a class or module has one and only one function - the layered approach leverages the separation of concerns. Broadly speaking, it splits software products into the presentation layer, business logic layer , persistence layer and the database layer.</p>
<p>These are modular sections of the application.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641290511377/KTmxg9MBI.png" alt="LayeredArchitecture.png" /></p>
<p>Each section/layer outlined has a specific function without needing to know what the other layer entails. </p>
<p>The presentation layer, for instance, deals with the display of information to the user. The business layer gets data from the persistence layer and processes it against application logic (say merge with another table or filter against a third party ) without the need to know anything about the user interface. Hence, you might as well change the presentation without changing the logic of what your project aims to do or change from an SQLite database to MySQL without your business logic requiring to know.</p>
<p>On a number of smaller applications, the business and persistent layer may be merged into one business layer. As observed, we get to have 3 layers in one case, four in another and so forth, hence the name n-tier, where <em>n</em> is the number of layers.</p>
<p>Requests flow from one layer to the next, say business logic to the persistence layer. This is a classic example of a closed layered system. That is, one in which, a lower-level layer cannot be accessed directly. </p>
<p><strong>Example:</strong> </p>
<p><em>Not letting the user access the database without walking through the business logic. 
What is handled in this 'logic' you might ask?</em></p>
<p><em>For one, authentication and authorization. No one should just access our local hotel database. at the same time, an ordinary user should not be able to perform managerial actions within our platform. That is left to the manager and only the manager.</em></p>
<p> In its basic form, a layered architectural system works in a closed circle.</p>
<p>We may, however, need to have access to lower-level layers without the intermediaries - an open layered system.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1641297973198/EqIEZOQkP.png" alt="LayeredOpenArchitecture.png" /></p>
<p><strong>Example:</strong></p>
<p><em>Given the premise of the <strong>n-tier</strong> architecture, we have an extra layer, <strong>the services layer</strong> . Our project is now a <strong>5-tier</strong> system. Despite having this layer, we might not use it as often. Hence, it does not serve our purpose for every request to go through it and have no change or mutation. What this layer would be adding to this specific request, is time; and time is of the essence. We have it, yes, but only use it when needed. </em></p>
<p>We bypass all that, and keep this layer open. This allows our request to access the level lower to it without having to go through it.</p>
<p><strong>Note: </strong></p>
<blockquote>
<p>Within your project, aim to have at most one open layer. Having more will create
    interdependencies between these layers, and you lose the whole point of having the layered system in the first place.</p>
</blockquote>
<p>Another variation of the n-tier architecture is the use of cached layers. Here, requests may be cached in between layers so that concurrent requests do not have to go all the way down. Plainly put, not every request made must hit the database (save the user some time). </p>
<p><strong>Let's take our app idea from the top</strong></p>
<p>A guest wants to make a reservation. They log onto our page and see that we have , on top of rooms, fun activities and games for our guests (<strong>the presentation layer</strong>). They go ahead to make a reservation. Our screen gets their request and sends it to our module within the <strong>business logic layer</strong>. Here, we want all available rooms and as a bonus, the activities available within the time frame of booking (notice the filtering of time, price and so forth). Now, call the <em>room</em> and <em>activities</em> data access object (dao) within the <strong>persistence layer</strong>, our ORM. These will, in turn, execute the queries necessary from the <em>room</em> and <em>activity</em> database table. Push this data back to the user and let them know they can have sushi on the house!</p>
<h3 id="heading-a-little-perspective">A little perspective</h3>
<p>So, we've given a primer on monolith architectures using the n-tier approach. We have seen a case application that uses the monolith system and used it to get our new client a room. Our system works and our local hotel pays in kind. What happens when they get new outlets? More activities and more traffic? Will it scale?</p>
<p>Monoliths are good, and monoliths are great. How you use them depends on your needs. Use a monolith when you want simplicity in development, deployment and scaling , work in a relatively small team or are creating a prototype. That works 100%.</p>
<p>A monolith will, however, bite you as the system gets larger due to a number of reasons.</p>
<p><strong>Framework /Language lock</strong></p>
<p>The whole codebase is in one framework that might not be suited for future feature additions. For example: we wrote our application in one language that is good for speed but we now need a section of it to use image processing libraries. How suited is it for image processing?</p>
<p><strong>Inefficient resource allocation</strong></p>
<p>If one endpoint needs more time either due to IO operations or processing, other functions may be locked.</p>
<p><strong>Scaling becomes difficult</strong></p>
<p>1000 or so requests to the search functionality have been made. In monolithic architecture, a new instance of the running application might be created during load balancing to handle multiple accesses. Here, we have a whole new instance of the same application created, when all we needed was the search to grow .</p>
<p><strong>Slowed development</strong></p>
<p>Take it that we now have a chain of hotels across the town. Heck, across the country. We have added feature 1 and gotten to feature 300. We now want to change a variable name within an application in our project. We have not touched anywhere else but that section. The whole codebase, including the untouched , has to be compiled once more. We are still developing, remember that! That's 10 minutes for build and compilation that could have been better served elsewhere not to mention an IDE load time that puts us all to sleep.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>So far, we have a birds-eye view of what we have been creating. A capture of what monoliths involve and what they do not -  layer upon layer. Great start. Is there more? Stick around a while longer. </p>
]]></content:encoded></item></channel></rss>