<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Toluwanimi Alfred</title>
    <description>The latest articles on DEV Community by Toluwanimi Alfred (@alfredoeinsteino2024).</description>
    <link>https://dev.to/alfredoeinsteino2024</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3990902%2Fbd4fe494-8036-4ad6-adeb-868c89da5300.jpg</url>
      <title>DEV Community: Toluwanimi Alfred</title>
      <link>https://dev.to/alfredoeinsteino2024</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alfredoeinsteino2024"/>
    <language>en</language>
    <item>
      <title>How I Built a Windows Security Monitor That Records Intruders Automatically Using PowerShell</title>
      <dc:creator>Toluwanimi Alfred</dc:creator>
      <pubDate>Tue, 29 Sep 2026 11:05:59 +0000</pubDate>
      <link>https://dev.to/alfredoeinsteino2024/how-i-built-a-windows-security-monitor-that-records-intruders-automatically-using-powershell-11ff</link>
      <guid>https://dev.to/alfredoeinsteino2024/how-i-built-a-windows-security-monitor-that-records-intruders-automatically-using-powershell-11ff</guid>
      <description>&lt;h2&gt;
  
  
  The Story That Started It All
&lt;/h2&gt;

&lt;p&gt;Years ago, I watched a video that stuck with me.&lt;/p&gt;

&lt;p&gt;An engineer had spent hours building an entire software from scratch. The moment he stepped away from his PC, someone who had been observing his pattern walked over, plugged in a flash drive, and copied the entire work.&lt;/p&gt;

&lt;p&gt;The painful part was not just the theft. It was how it happened. The spy had been watching. He knew the pattern. He tried the security details a few times before he got in.&lt;/p&gt;

&lt;p&gt;That video made me ask a question I could not stop thinking about:&lt;/p&gt;

&lt;p&gt;How do you secure a PC in an environment where it cannot be stolen but can still be accessed without your permission?&lt;/p&gt;

&lt;p&gt;That question sent me down a rabbit hole of research. A few weeks ago, curiosity turned into code.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;A Windows security monitoring tool built entirely in PowerShell with no third party security software.&lt;/p&gt;

&lt;p&gt;Here is what it does:&lt;/p&gt;

&lt;p&gt;After 3 failed login attempts on your Windows PC, two things happen automatically:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An email alert fires instantly to two configured addresses&lt;/li&gt;
&lt;li&gt;The webcam starts recording silently
The person trying to get in cannot stop the recording unless they have access to the code configured for manual stop or the keyboard shortcut built into the system.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A few days ago I confirmed it worked. I watched recorded footage of an actual attempt to enter my system.&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1 — Monitoring Failed Logins
&lt;/h3&gt;

&lt;p&gt;Windows logs every failed login attempt as Event ID 4625 in the Security Event Log. PowerShell can read this in real time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$events&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Get-WinEvent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-FilterHashtable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;LogName&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Security"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;Id&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4625&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;StartTime&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Date&lt;/span&gt;&lt;span class="err"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;AddSeconds&lt;/span&gt;&lt;span class="err"&gt;(-&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ErrorAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SilentlyContinue&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nv"&gt;$count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="nv"&gt;$events&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Count&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key fix here was using a sliding 30 second window instead of counting from script start. Counting from script start causes the number to grow forever and trigger duplicate recordings. The sliding window resets naturally every poll cycle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 — Email Alert via Gmail SMTP
&lt;/h3&gt;

&lt;p&gt;The moment the threshold is hit, an email fires to two addresses using Gmail SMTP through PowerShell's built in System.Net.Mail.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$smtp&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;New-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;System.Net.Mail.SmtpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"smtp.gmail.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;587&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$smtp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnableSsl&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$smtp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Credentials&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;New-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;System.Net.NetworkCredential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$gmailFrom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$gmailPass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No external libraries. No API keys to pay for. Just a Gmail App Password and two lines of configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3 — Webcam Recording via FFmpeg
&lt;/h3&gt;

&lt;p&gt;FFmpeg captures the webcam using DirectShow, Windows built in camera interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ffmpegArgs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"-rtbufsize 100M -f dshow -i video=&lt;/span&gt;&lt;span class="se"&gt;`"&lt;/span&gt;&lt;span class="s2"&gt;Integrated Webcam&lt;/span&gt;&lt;span class="se"&gt;`"&lt;/span&gt;&lt;span class="s2"&gt; -vcodec libx264 -preset ultrafast &lt;/span&gt;&lt;span class="se"&gt;`"&lt;/span&gt;&lt;span class="nv"&gt;$outputFile&lt;/span&gt;&lt;span class="se"&gt;`"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The biggest bug I hit here was that combining -NoNewWindow and -WindowStyle Hidden when launching FFmpeg from a script caused DirectShow to fail silently. The webcam light never turned on and no error was written. The fix was switching to ProcessStartInfo with the window set to Minimized instead of Hidden, which gives DirectShow the process context it needs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4 — Hotkey Stop via Win32 API
&lt;/h3&gt;

&lt;p&gt;A separate script uses embedded C# inside PowerShell to register a global hotkey through the Win32 RegisterHotKey function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OnHandleCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EventArgs&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OnHandleCreated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;RegisterHotKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HOTKEY_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MOD_CONTROL&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;MOD_ALT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;VK_S&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The original version called RegisterHotKey inside the constructor, which meant the window handle did not exist yet and the hotkey silently never registered. Moving it to OnHandleCreated fixed it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Problems I Hit Along the Way
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Event count kept inflating
&lt;/h3&gt;

&lt;p&gt;Original code used StartTime set to script start time, so events accumulated forever. Fixed with a rolling 30 second window.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. FFmpeg crashed silently with no error log
&lt;/h3&gt;

&lt;p&gt;The combination of -NoNewWindow and -WindowStyle Hidden on Start-Process blocked DirectShow from accessing the webcam. No error. No log. Just a silent crash. Fixed by using ProcessStartInfo directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Two scripts running at the same time
&lt;/h3&gt;

&lt;p&gt;During testing, an old version of the script was still running in the background while the new one started. Both tried to grab the webcam simultaneously and both failed. Always kill old PowerShell instances before starting fresh.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Parser errors from special characters
&lt;/h3&gt;

&lt;p&gt;Em dashes and curly quotes copied into the script from documentation caused PowerShell parser errors that looked completely unrelated to the actual problem. Always write PowerShell in plain ASCII.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Honest Limitation
&lt;/h2&gt;

&lt;p&gt;Windows architecture locks webcam access to active user sessions. This means recording can only start after someone logs in, not before.&lt;/p&gt;

&lt;p&gt;On Linux, PAM (Pluggable Authentication Modules) and V4L2 (Video4Linux2) make it possible to hook into the login process itself and trigger recording before anyone gets past the login screen.&lt;/p&gt;

&lt;p&gt;A Linux port is something to explore in the future.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Windows Event Log is more accessible than most people realize. PowerShell can query it natively with no extra tools.&lt;/li&gt;
&lt;li&gt;DirectShow is sensitive to process context. How you launch a process matters as much as what you put in the command line.&lt;/li&gt;
&lt;li&gt;Silent failures are the hardest bugs. FFmpeg crashing with no output taught me to always check HasExited after launch and always redirect stderr somewhere readable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  - OS architecture decisions have real consequences. The Windows session model is a security feature. It is also the reason this tool has a fundamental ceiling.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The Full Code
&lt;/h2&gt;

&lt;p&gt;Everything is documented and available on GitHub:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/alfredoeinsteino2024/SecurityMonitor-PowerShell" rel="noopener noreferrer"&gt;https://github.com/alfredoeinsteino2024/SecurityMonitor-PowerShell&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The repo includes monitor.ps1, hotkey.ps1, stop.ps1, and a full README with setup instructions.&lt;/p&gt;




&lt;p&gt;There are still bugs to fix and more to learn.&lt;/p&gt;

&lt;p&gt;But curiosity got something working and that is enough to keep going.&lt;/p&gt;

&lt;p&gt;We trust God in the process.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxjvplrs92h3q0wx6ztem.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxjvplrs92h3q0wx6ztem.jpeg" alt=" " width="572" height="1279"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>powershell</category>
      <category>security</category>
      <category>windows</category>
    </item>
    <item>
      <title>RescueHacks Alert: Building a Silent Emergency Dial Code That Actually Works</title>
      <dc:creator>Toluwanimi Alfred</dc:creator>
      <pubDate>Thu, 10 Sep 2026 15:17:36 +0000</pubDate>
      <link>https://dev.to/alfredoeinsteino2024/rescuehacks-alert-building-a-silent-emergency-dial-code-that-actually-works-35j0</link>
      <guid>https://dev.to/alfredoeinsteino2024/rescuehacks-alert-building-a-silent-emergency-dial-code-that-actually-works-35j0</guid>
      <description>&lt;h2&gt;
  
  
  The problem I wanted to solve
&lt;/h2&gt;

&lt;p&gt;Most emergency-alert apps make the same bad assumption: the person in danger has time, privacy, and a working data connection to open an app, unlock their phone, and tap through a UI.&lt;/p&gt;

&lt;p&gt;If someone is being followed, robbed, or is in a situation where their phone is visible to a threat, none of that holds. What they &lt;em&gt;do&lt;/em&gt; usually have is a phone that can dial a number, even on 2G and with zero data.&lt;/p&gt;

&lt;p&gt;That's the idea behind &lt;strong&gt;RescueHacks Alert&lt;/strong&gt;: dial a short USSD code, and an emergency contact gets notified on WhatsApp in real time. No app. No internet requirement on the victim's side. No visible menu that gives away what's happening.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core design decision: no menu
&lt;/h2&gt;

&lt;p&gt;My first instinct was to build an interactive USSD menu. Dial the code, see a list ("1. Medical, 2. Security, 3. Fire..."), and pick one. Standard USSD UX.&lt;/p&gt;

&lt;p&gt;Then I thought about who's actually dialing this. If someone is being confronted, pulling out their phone and having a menu appear on screen is a giveaway. USSD sessions stay visible while they're active.&lt;/p&gt;

&lt;p&gt;So I dropped the menu entirely. The emergency type is encoded directly in the digits the person dials with a single, silent action.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*384*23492*1#   → Medical
*384*23492*2#   → Safety threat
*384*23492*3#   → Accident
*384*23492*4#   → Disaster
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dial it, and the session ends immediately with no visible confirmation screen. To anyone watching, it looks like a dropped call attempt. Behind the scenes, the backend fires an emergency alert.&lt;/p&gt;

&lt;p&gt;For the demo video, I narrated it with a shorter, more realistic-looking code like &lt;code&gt;*911*[1-3]#&lt;/code&gt;. A real deployment would use a telecom-issued short code rather than a shared sandbox number. The working prototype runs on Africa's Talking's longer sandbox code above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Victim's phone
   │  dials USSD code
   ▼
Africa's Talking USSD Gateway
   │  HTTP callback
   ▼
AWS Lambda (USSD handler)
   │  parses emergency type from dialed digits
   ▼
Meta WhatsApp Cloud API
   │
   ▼
Emergency contact receives alert on WhatsApp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything runs on AWS SAM. API Gateway sits in front of a Lambda function that parses the incoming USSD session and triggers the WhatsApp send.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it got interesting: three bugs that taught me more than the happy path
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. The Lambda that "sent" messages that never arrived
&lt;/h3&gt;

&lt;p&gt;Early on, the WhatsApp send was fire-and-forget. I called the send function but didn't wait for it before returning the USSD response. It worked sometimes.&lt;/p&gt;

&lt;p&gt;The reason was simple: AWS Lambda freezes the execution environment as soon as it returns a response. If your background async call hasn't finished, it stops. No error. No completion.&lt;/p&gt;

&lt;p&gt;The fix was straightforward once I understood it. &lt;code&gt;await&lt;/code&gt; the WhatsApp send before returning the USSD response.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. A WhatsApp template that Meta quietly reclassified
&lt;/h3&gt;

&lt;p&gt;I submitted a message template under the Utility category, which is required for sending outside WhatsApp's 24-hour messaging window.&lt;/p&gt;

&lt;p&gt;Meta approved it, then quietly reclassified it as Marketing. Marketing templates require recipient opt-in, which my test number didn't have. The API returned a success status with a valid message ID, but nothing arrived.&lt;/p&gt;

&lt;p&gt;The dashboard never made the real reason obvious. I only found the actual category by querying the Meta API directly. For the hackathon deadline, I switched to plain-text messages inside the 24-hour window and documented the template fix for later.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. A token that worked in testing and silently failed in production
&lt;/h3&gt;

&lt;p&gt;My quick-test access token worked perfectly. The permanent system-user token used by the deployed app returned success but delivered nothing.&lt;/p&gt;

&lt;p&gt;Same phone number ID. Same WhatsApp Business Account. Same recipient.&lt;/p&gt;

&lt;p&gt;That pointed to a permissions issue rather than a code bug. The system user needed full control of the WhatsApp Business Account, along with the &lt;code&gt;whatsapp_business_messaging&lt;/code&gt; permission, before the permanent token worked.&lt;/p&gt;

&lt;p&gt;None of these problems were obvious from reading the documentation. They only showed up after building, deploying, and comparing "API says success" with "nothing arrived."&lt;/p&gt;

&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;

&lt;p&gt;End to end, dialing &lt;code&gt;*384*23492*2#&lt;/code&gt; in the Africa's Talking sandbox simulator triggers a WhatsApp emergency alert on the registered contact's phone in real time. No app. No menu. No visible trace on the victim's screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;RescueHacks Alert started as a hackathon weekend build. I look forward to&lt;/p&gt;

&lt;p&gt;turning it into my final-year Mechatronics Engineering project by adding a physical SOS tracker (ESP32 + GPS + cellular), live location tracking, a responder dashboard, and AI-assisted emergency classification with confidence-scored outputs rather than overclaimed certainty.&lt;/p&gt;

&lt;p&gt;That's a much bigger build with real hardware and power-budget constraints, and I'll be documenting the process as it develops.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built for the RescueHacks hackathon on Devpost. Code, demo video, and submission details: &lt;a href="https://devpost.com/software/rescuehacks-alert" rel="noopener noreferrer"&gt;https://devpost.com/software/rescuehacks-alert&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>iot</category>
      <category>security</category>
    </item>
    <item>
      <title>Building a Serverless Agriculture Platform with AWS</title>
      <dc:creator>Toluwanimi Alfred</dc:creator>
      <pubDate>Wed, 02 Sep 2026 03:21:05 +0000</pubDate>
      <link>https://dev.to/alfredoeinsteino2024/building-a-serverless-agriculture-platform-with-aws-2ao3</link>
      <guid>https://dev.to/alfredoeinsteino2024/building-a-serverless-agriculture-platform-with-aws-2ao3</guid>
      <description>&lt;p&gt;While building &lt;strong&gt;HarvestIQ&lt;/strong&gt;, I started paying much more attention to how backend architecture affects the way a product can be built, deployed, and scaled.&lt;/p&gt;

&lt;p&gt;HarvestIQ is an agriculture platform designed to help smallholder farmers access post-harvest intelligence, including market prices and buyer opportunities.&lt;/p&gt;

&lt;p&gt;One of the interesting parts of the project is that a farmer can interact with the system through &lt;strong&gt;USSD&lt;/strong&gt;, without requiring a smartphone or an internet connection.&lt;/p&gt;

&lt;p&gt;The backend is built around a serverless architecture using AWS services.&lt;/p&gt;

&lt;p&gt;This article breaks down how that architecture works and what I have learned from building it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does "serverless" actually mean?
&lt;/h2&gt;

&lt;p&gt;The name can be misleading.&lt;/p&gt;

&lt;p&gt;Serverless does &lt;strong&gt;not&lt;/strong&gt; mean that there are no servers.&lt;/p&gt;

&lt;p&gt;The servers still exist. AWS manages the underlying infrastructure, while I focus on writing and deploying the application code.&lt;/p&gt;

&lt;p&gt;Instead of maintaining an always-running backend server, different parts of the application can run when they are needed.&lt;/p&gt;

&lt;p&gt;For HarvestIQ, this works particularly well because many operations are event-driven.&lt;/p&gt;

&lt;p&gt;A farmer makes a request.&lt;/p&gt;

&lt;p&gt;A function executes.&lt;/p&gt;

&lt;p&gt;Data is retrieved or updated.&lt;/p&gt;

&lt;p&gt;The function finishes.&lt;/p&gt;

&lt;p&gt;Another event can trigger another function later.&lt;/p&gt;

&lt;h2&gt;
  
  
  HarvestIQ's Serverless Architecture
&lt;/h2&gt;

&lt;p&gt;The simplified architecture looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Farmer
                      |
                     USSD
                      |
                      v
              Africa's Talking
                      |
                      v
                AWS Lambda
                 /       \
                /         \
               v           v
          DynamoDB       Response


          EventBridge
               |
               v
          AWS Lambda
               |
               v
          Price / Alert
            Logic
               |
               v
             SNS
               |
               v
              SMS
               |
               v
             Farmer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each AWS service has a specific responsibility.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS Lambda&lt;/strong&gt; handles application logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DynamoDB&lt;/strong&gt; stores application data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EventBridge&lt;/strong&gt; triggers scheduled operations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SNS&lt;/strong&gt; handles notifications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Africa's Talking&lt;/strong&gt; provides the USSD and SMS connectivity layer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's look at each part.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. USSD as the Entry Point
&lt;/h2&gt;

&lt;p&gt;One of the design goals of HarvestIQ is accessibility.&lt;/p&gt;

&lt;p&gt;A farmer should not necessarily need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A smartphone&lt;/li&gt;
&lt;li&gt;A mobile application&lt;/li&gt;
&lt;li&gt;Mobile data&lt;/li&gt;
&lt;li&gt;A web browser&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A basic mobile phone with cellular connectivity can be enough.&lt;/p&gt;

&lt;p&gt;The farmer interacts with HarvestIQ through a USSD menu.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HarvestIQ

1. Check Market Price
2. List Produce
3. View Buyer Demand
4. Set Price Alert
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The USSD request is handled through the Africa's Talking USSD gateway and passed to the backend.&lt;/p&gt;

&lt;p&gt;This is where AWS Lambda comes in.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. AWS Lambda
&lt;/h2&gt;

&lt;p&gt;AWS Lambda is the compute layer of the application.&lt;/p&gt;

&lt;p&gt;Instead of maintaining a traditional server that is continuously running, I can deploy functions that execute in response to events.&lt;/p&gt;

&lt;p&gt;The basic idea is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Event
  |
  v
Lambda Function
  |
  v
Execute Code
  |
  v
Return Result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, when a farmer sends a USSD request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Farmer
   |
   v
USSD Request
   |
   v
AWS Lambda
   |
   v
Process Request
   |
   v
Return USSD Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Lambda function can also communicate with other AWS services.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Lambda
   |
   +----&amp;gt; DynamoDB
   |
   +----&amp;gt; SNS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means the application logic does not have to live on one large traditional backend server.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. DynamoDB
&lt;/h2&gt;

&lt;p&gt;HarvestIQ uses &lt;strong&gt;Amazon DynamoDB&lt;/strong&gt; as its database.&lt;/p&gt;

&lt;p&gt;This is where application data can be stored and retrieved by Lambda functions.&lt;/p&gt;

&lt;p&gt;For example, the system can store information related to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Farmers&lt;/li&gt;
&lt;li&gt;Produce listings&lt;/li&gt;
&lt;li&gt;Market prices&lt;/li&gt;
&lt;li&gt;Buyer demands&lt;/li&gt;
&lt;li&gt;Price alerts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A simplified interaction might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;USSD Request
     |
     v
Lambda
     |
     v
DynamoDB
     |
     v
Retrieve Data
     |
     v
Lambda
     |
     v
USSD Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, when a farmer requests the current price of maize, Lambda can query DynamoDB and return the relevant information through the USSD session.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. EventBridge for Scheduled Jobs
&lt;/h2&gt;

&lt;p&gt;Not everything in HarvestIQ starts with a farmer.&lt;/p&gt;

&lt;p&gt;Some operations need to happen automatically.&lt;/p&gt;

&lt;p&gt;For example, market prices may need to be updated periodically.&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;Amazon EventBridge&lt;/strong&gt; becomes useful.&lt;/p&gt;

&lt;p&gt;Instead of keeping a server running and writing a program that constantly waits for the next scheduled operation, EventBridge can trigger a Lambda function according to a schedule.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EventBridge
     |
     | Scheduled Event
     v
Lambda
     |
     v
Run Price Update
     |
     v
DynamoDB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;8:00 AM  -&amp;gt; Lambda runs
10:00 AM -&amp;gt; Lambda runs
12:00 PM -&amp;gt; Lambda runs
2:00 PM  -&amp;gt; Lambda runs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact schedule depends on the application requirements.&lt;/p&gt;

&lt;p&gt;This is one of the things I found interesting about event-driven architecture: the system does not need to continuously run code just to wait for something to happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Understanding Amazon SNS
&lt;/h2&gt;

&lt;p&gt;This was one of the concepts I found particularly interesting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Amazon SNS (Simple Notification Service)&lt;/strong&gt; is a publish/subscribe messaging service.&lt;/p&gt;

&lt;p&gt;A simple way to think about SNS is as a notification or broadcast layer.&lt;/p&gt;

&lt;p&gt;Instead of having every part of the application know exactly how to deliver a notification, an application can publish a message to an SNS topic.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application
     |
     v
SNS Topic
   /   \
  /     \
SMS     Other Subscribers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In HarvestIQ, this can be useful for price alerts.&lt;/p&gt;

&lt;p&gt;Suppose a farmer sets a target price:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Produce: Maize
Target Price: ₦85,000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Later, the system checks the current market price.&lt;/p&gt;

&lt;p&gt;If the target condition is satisfied, the application can publish a notification through SNS.&lt;/p&gt;

&lt;p&gt;The flow becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EventBridge
     |
     v
Price-check Lambda
     |
     v
DynamoDB
     |
     v
Target condition reached
     |
     v
Lambda publishes notification
     |
     v
SNS
     |
     v
SMS notification
     |
     v
Farmer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important distinction is that &lt;strong&gt;SNS is not the component deciding whether the target price has been reached&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The application logic does that.&lt;/p&gt;

&lt;p&gt;Lambda determines that the condition has been satisfied, then publishes the notification to SNS.&lt;/p&gt;

&lt;p&gt;SNS handles the notification delivery to its configured subscriber.&lt;/p&gt;

&lt;p&gt;That separation of responsibilities makes the architecture easier to reason about.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Complete Example
&lt;/h2&gt;

&lt;p&gt;Let's put everything together.&lt;/p&gt;

&lt;p&gt;Imagine a farmer wants to know the current price of maize.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: The farmer sends a USSD request
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Farmer
   |
   v
USSD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: The request reaches the backend
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;USSD
   |
   v
Africa's Talking
   |
   v
AWS Lambda
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Lambda retrieves the data
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Lambda
   |
   v
DynamoDB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DynamoDB returns the relevant market information.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Lambda generates the response
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DynamoDB
   |
   v
Lambda
   |
   v
USSD Response
   |
   v
Farmer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The entire interaction can happen without the farmer installing an application or using mobile data.&lt;/p&gt;

&lt;p&gt;Now consider a different scenario: a scheduled price update.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EventBridge
     |
     v
Lambda
     |
     v
Fetch / Process Price Data
     |
     v
DynamoDB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if a price alert condition is reached:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Price-check Lambda
       |
       v
Target reached
       |
       v
SNS
       |
       v
SMS
       |
       v
Farmer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the part of the architecture that makes the system event-driven.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use Serverless?
&lt;/h2&gt;

&lt;p&gt;There are several reasons this architecture made sense for HarvestIQ.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Less infrastructure management
&lt;/h3&gt;

&lt;p&gt;I don't have to maintain an always-running application server myself.&lt;/p&gt;

&lt;p&gt;AWS manages much of the underlying infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Event-driven execution
&lt;/h3&gt;

&lt;p&gt;Different parts of the application can execute in response to specific events.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;USSD request
     ↓
Lambda
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Scheduled event
     ↓
Lambda
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Business condition
     ↓
Notification
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Automatic scaling
&lt;/h3&gt;

&lt;p&gt;Lambda can handle multiple invocations without me manually provisioning individual servers for each request.&lt;/p&gt;

&lt;p&gt;The underlying infrastructure is managed by AWS.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Efficient use of compute
&lt;/h3&gt;

&lt;p&gt;For workloads that are intermittent or event-driven, there is less reason to maintain an application server that is continuously running just waiting for requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serverless Is Not Perfect
&lt;/h2&gt;

&lt;p&gt;Serverless is not automatically the best architecture for every application.&lt;/p&gt;

&lt;p&gt;There are trade-offs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cold Starts
&lt;/h3&gt;

&lt;p&gt;A function that has not been invoked recently may experience additional startup latency depending on the runtime and configuration.&lt;/p&gt;

&lt;p&gt;For some applications, that latency matters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Execution Limits
&lt;/h3&gt;

&lt;p&gt;Lambda functions are designed for bounded workloads rather than indefinitely running processes.&lt;/p&gt;

&lt;p&gt;That means some workloads are better suited to other architectures.&lt;/p&gt;

&lt;h3&gt;
  
  
  Distributed Debugging
&lt;/h3&gt;

&lt;p&gt;A traditional application might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client
  |
  v
Backend
  |
  v
Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A serverless application can involve many managed services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;USSD
  |
  v
Gateway
  |
  v
Lambda
  |
  +----&amp;gt; DynamoDB
  |
  +----&amp;gt; SNS
  |
  +----&amp;gt; Other Services

EventBridge
  |
  v
Lambda
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When something fails, understanding exactly where the failure occurred can require proper logging, monitoring, and tracing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vendor Lock-in
&lt;/h3&gt;

&lt;p&gt;Using managed services deeply can also make an application more dependent on a particular cloud provider.&lt;/p&gt;

&lt;p&gt;That is an architectural decision worth considering before building at scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;Building HarvestIQ changed how I think about backend architecture.&lt;/p&gt;

&lt;p&gt;The biggest lesson for me is that &lt;strong&gt;serverless is less about "not having servers" and more about changing who manages the infrastructure and how application components are executed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I also learned to think in terms of events.&lt;/p&gt;

&lt;p&gt;Instead of asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What server should always be running?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I started asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What event should cause this piece of code to run?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For HarvestIQ, those events can be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Farmer makes a USSD request
              ↓
        Lambda executes

Scheduled update occurs
              ↓
        Lambda executes

Price condition is reached
              ↓
      Notification is published
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That shift in thinking is probably the most valuable thing I have taken from building the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;HarvestIQ started as an attempt to solve a real agricultural problem, but building it has also become an opportunity for me to learn more about cloud architecture and distributed systems.&lt;/p&gt;

&lt;p&gt;The combination of &lt;strong&gt;Lambda, DynamoDB, EventBridge, and SNS&lt;/strong&gt; gives the platform a relatively lightweight event-driven backend while allowing me to focus more on the application itself rather than server management.&lt;/p&gt;

&lt;p&gt;I'm still learning, and there are several areas I want to explore further, particularly observability, security, cost optimization, and designing more robust distributed systems.&lt;/p&gt;

&lt;p&gt;For me, this is one of the interesting parts of building software: the project solves one problem while teaching you how to solve the next one better.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Why the Power-of-Two Trick Works for Binary Fractions (And Why It Breaks for Everything Else)</title>
      <dc:creator>Toluwanimi Alfred</dc:creator>
      <pubDate>Thu, 18 Jun 2026 12:25:50 +0000</pubDate>
      <link>https://dev.to/alfredoeinsteino2024/why-the-power-of-two-trick-works-for-binary-fractions-and-why-it-breaks-for-everything-else-3iga</link>
      <guid>https://dev.to/alfredoeinsteino2024/why-the-power-of-two-trick-works-for-binary-fractions-and-why-it-breaks-for-everything-else-3iga</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftbac0j78g6wk6lcglfs5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftbac0j78g6wk6lcglfs5.png" alt=" " width="680" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've taken any course that covers number systems, you've probably learned the "repeated multiplication" method for converting a decimal fraction to binary. Multiply by 2, record the digit before the decimal point, keep the remainder, repeat. It works. You can pass an exam with it. But it also feels a little like a magic trick — you follow the steps, you get the right answer, and you have no real intuition for &lt;em&gt;why&lt;/em&gt; it works or &lt;em&gt;why&lt;/em&gt; it sometimes never ends.&lt;/p&gt;

&lt;p&gt;Here's the thought process that gave me that intuition, and where it eventually breaks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The starting point: 0.25
&lt;/h2&gt;

&lt;p&gt;Take 0.25. The standard method says: multiply by 2 repeatedly, record the integer parts.&lt;/p&gt;

&lt;p&gt;0.25 × 2 = 0.50 → record 0&lt;br&gt;
0.50 × 2 = 1.00 → record 1&lt;/p&gt;

&lt;p&gt;Read top to bottom: 0.25 = 0.01 in binary. Correct, but mechanical.&lt;/p&gt;

&lt;p&gt;Here's the alternative way I started thinking about it instead. 0.25 is just 1/4. And 4 is 2². So instead of multiplying repeatedly, what if I convert the numerator and denominator to binary separately, and treat the division as what it actually is — a division by a power of the base?&lt;/p&gt;

&lt;p&gt;1 in binary is 1.&lt;br&gt;
4 in binary is 100.&lt;/p&gt;

&lt;p&gt;So 1/4 is 1 / 100 in binary. And dividing by 100 (in any base) doesn't require long division if 100 is a power of that base — it just shifts the point. In decimal, dividing by 100 shifts a decimal point two places left because 100 is 10². In binary, dividing by 100₂ (which is 4 in decimal) shifts the binary point two places left for exactly the same reason: 100₂ is 2².&lt;/p&gt;

&lt;p&gt;Shift the point in "1." two places left: 0.01₂.&lt;/p&gt;

&lt;p&gt;Same answer, but now you can see &lt;em&gt;why&lt;/em&gt; it's the answer instead of just trusting the algorithm.&lt;/p&gt;

&lt;h2&gt;
  
  
  This isn't a coincidence — it's how place-value systems work
&lt;/h2&gt;

&lt;p&gt;This generalizes. Any fraction a/2ⁿ can be converted by writing 'a' in binary and shifting the point n places. 1/2 → shift 1 place → 0.1₂. 1/8 → shift 3 places → 0.001₂. 3/16 → 3 is 11 in binary, shift 4 places → 0.0011₂.&lt;/p&gt;

&lt;p&gt;It's the same logic as why dividing by 1000 in decimal is "free" (just move the point three places) — except in binary, the powers that are "free" are powers of 2, not powers of 10. This is also, not coincidentally, the entire basis of fixed-point arithmetic in embedded systems: when a microcontroller needs to represent a fraction without the overhead of a floating-point unit, it represents the value as an integer with an implicit binary point at a fixed position, and operations that would otherwise need division become bit-shifts. The "trick" above is a small, hand-worked version of that same idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it breaks
&lt;/h2&gt;

&lt;p&gt;The shortcut depends entirely on the denominator being a power of 2. Try it on 0.2, which as a fraction is 1/5.&lt;/p&gt;

&lt;p&gt;5 in binary is 101. 101 is not a power of 2 (it's 4 + 1, not a single power), so there's no clean shift available. To get 1/101₂ you actually have to do binary long division, and unlike 1/4, this one doesn't terminate. It repeats forever: 0.0011001100110011...&lt;/p&gt;

&lt;p&gt;This is the same underlying reason 0.1 + 0.2 doesn't exactly equal 0.3 in most programming languages — 0.1 and 0.2 are not exactly representable in binary floating point, because their denominators (10 and 5) aren't powers of 2. It's not a bug in your code; it's a structural consequence of representing base-10 fractions in a base-2 system.&lt;/p&gt;

&lt;p&gt;So the boundary is sharp: this shortcut is fast and exact for denominators of 2, 4, 8, 16, 32, and so on (equivalently, decimals like 0.5, 0.25, 0.125, 0.0625, 0.375). For anything else, you're back to repeated multiplication, and the result may never terminate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;None of this is a new method — it's a restatement of how positional number systems and fixed-point representation work, just arrived at by asking "what is this algorithm actually doing" instead of memorizing the steps. But that's worth writing down, because most people learn the multiplication method as a rote procedure and never connect it to the much more general (and much more useful) fact: in any base, dividing by a power of that base is just a point shift, and that single fact is also why certain "simple" decimal fractions can never be represented exactly in binary — a fact that quietly underlies one of the most common gotchas in floating-point programming.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>computerscience</category>
      <category>programming</category>
      <category>binary</category>
    </item>
  </channel>
</rss>
