MoreRSS

site iconThe Practical DeveloperModify

A constructive and inclusive social network for software developers.
Please copy the RSS to your reader, or quickly subscribe to:

Inoreader Feedly Follow Feedbin Local Reader

Rss preview of Blog of The Practical Developer

Software should serve the Business, not the other way around.

2026-03-01 09:00:00

I’ve seen it happen too many times:
A brilliant dev team spends 3 months building a perfect scalable architecture for a problem the business hasn't even validated yet.

The result? A technical masterpiece that nobody uses.

In the startup world, code is a liability until it’s solving a business problem. Here’s why your software should follow your business - not the other way around.

Code is a Tool, Not the Product

Your customers don't care if you're using Clean Architecture or a messy monolith. They care if the button works and solves their pain. If the business pivots (which it will), your code needs to be flexible enough to follow - not so rigid that it blocks the move.

The "Over-Engineering" Trap

We often build for 1 million users when we only have 10. That’s "Software leading the Business." Instead, build for the business reality of today.

It’s better to have a successful business with "messy" code than a failed startup with "perfect" code.

Communication > Syntax

A Senior Developer’s job isn't just writing functions; it’s understanding the Business Model. If you don't know how your company makes money, you can't write effective software for it.

Conclusion

Stop asking 'How can we build this?' and start asking 'Should we build this?' Let the business goals drive the git commits.

Originally shared in a more casual, local context (Malay) on my blog: Read the original here. I'm curious — have you ever worked at a place where the tech dictated the business? Let's discuss below!

Goodbye Cloud: Building a Privacy-First Medical AI on Your MacBook with MLX and Llama-3

2026-03-01 09:00:00

Privacy is not just a feature; it’s a human right—especially when it comes to your health data. In the era of Local AI and Edge Computing, sending sensitive Electronic Health Records (EHR) to a cloud provider is becoming a gamble many aren't willing to take. If you are a developer looking to leverage the power of Llama-3 while ensuring 100% data sovereignty, you've come to the right place. 🚀

In this tutorial, we are going to build a Local-First Health AI using the MLX framework on Apple Silicon. We’ll transform raw, messy medical notes into structured data and concise summaries without a single byte leaving your MacBook. By the end of this guide, you’ll understand how to optimize Llama-3 for Mac hardware to achieve lightning-fast inference for Privacy-first healthcare applications.

Why MLX for Local Health AI?

Apple's MLX is a NumPy-like array framework designed specifically for machine learning on Apple Silicon. Unlike generic frameworks, MLX utilizes the Unified Memory Architecture of M1/M2/M3 chips, allowing the GPU and CPU to share data seamlessly. This is a game-changer for processing large language models (LLMs) locally.

The Architecture: Local Data Flow

Here is how we handle sensitive medical data without ever touching the internet:

graph TD
    A[Raw Medical Record / PDF] -->|Local Script| B(Python Pre-processing)
    B --> C{MLX Engine}
    C -->|Unified Memory| D[Llama-3-8B-Instruct]
    D --> E[Summarization & Entity Extraction]
    E -->|JSON Output| F[Local Health Dashboard]
    subgraph Privacy Boundary (Your MacBook)
    B
    C
    D
    E
    end

Prerequisites

To follow along, you’ll need:

  • A MacBook with Apple Silicon (M1, M2, or M3 series).
  • Python 3.10+
  • mlx-lm library (the high-level API for running LLMs on MLX).
pip install mlx-lm huggingface_hub

Step 1: Loading Llama-3 via MLX

Instead of using the heavy raw weights, we will use a 4-bit quantized version of Llama-3. This reduces memory pressure significantly while maintaining impressive medical reasoning capabilities.

from mlx_lm import load, generate

# Load the Llama-3 8B model optimized for MLX
model_path = "mlx-community/Meta-Llama-3-8B-Instruct-4bit"
model, tokenizer = load(model_path)

print("✅ Model loaded successfully on Apple Silicon!")

Step 2: Crafting the Medical Prompt

Medical records are often unstructured. We need a robust prompt to extract "Symptoms," "Diagnoses," and "Medications."

def process_health_record(raw_text):
    prompt = f"""
    <|begin_of_text|><|start_header_id|>system<|end_header_id|>
    You are a professional medical assistant. Analyze the following medical record. 
    Extract the key information in JSON format:
    - Summary (1 sentence)
    - Primary Diagnosis
    - Prescribed Medications
    - Follow-up actions
    Do not include any cloud-based references.
    <|eot_id|><|start_header_id|>user<|end_header_id|>
    Record: {raw_text}
    <|eot_id|><|start_header_id|>assistant<|end_header_id|>
    """

    response = generate(model, tokenizer, prompt=prompt, verbose=False, max_tokens=500)
    return response

# Example Usage
raw_ehr = "Patient presents with persistent cough for 2 weeks. BP 140/90. Prescribed Amoxicillin 500mg. Return in 7 days."
result = process_health_record(raw_ehr)
print(result)

Step 3: Benchmarking and Performance 💻

Running Llama-3 locally on an M3 Max can yield upwards of 50-70 tokens per second. Even on a base M1 MacBook Air, you can expect a very usable 15-20 tokens per second. Because MLX uses the Metal Performance Shaders (MPS), the energy efficiency is significantly better than running it via traditional CPU-bound methods.

The "Official" Way to Scale Local AI

While running a script on your laptop is great for personal use, scaling local AI for healthcare organizations requires more robust patterns—including encrypted storage, HIPAA-compliant local pipelines, and advanced quantization techniques.

For more production-ready examples and advanced patterns on deploying privacy-centric models, I highly recommend checking out the WellAlly Technical Blog. They provide deep dives into how modern AI can be reconciled with strict data privacy laws.

Conclusion: The Future is Local 🥑

We just turned a standard MacBook into a powerful, private medical assistant. By leveraging MLX and Llama-3, we’ve proved that you don't need a massive server farm (or a massive privacy risk) to process complex health data.

Key Takeaways:

  1. Zero Latency/Zero Cost: No API fees and no waiting for network requests.
  2. Privacy by Design: The data never leaves the hardware.
  3. Efficiency: MLX makes local LLMs viable for everyday development.

What are you building locally? Let me know in the comments below! If you found this helpful, don't forget to ❤️ and 🦄.

I Built an AI-Powered Website Monitor — Here's How It Works

2026-03-01 08:41:25

Hey folks! 👋

I've been working on PulseWatch — an AI-powered website monitoring tool that tracks changes on any webpage and sends instant notifications. I wanted to share how I built it and what makes it different from existing solutions.

The Problem

We all need to track changes on websites sometimes — price drops on Amazon, new job postings, API documentation updates, stock availability, or news articles. The existing tools either require complex CSS selectors or are too expensive for what they offer.

The Solution: AI-Powered Selection

PulseWatch uses GPT-4o to analyze web pages and suggest what to monitor. Instead of writing CSS selectors manually, you can:

  1. Point and click — Take a screenshot, click on the element you want to track
  2. Drag to select — Draw a box around a region on the page
  3. AI suggestions — Let GPT-4o analyze the page and recommend what to monitor
  4. 40+ templates — Pre-built selectors for popular sites like Amazon, eBay, GitHub, and more

Tech Stack

Here's what powers PulseWatch under the hood:

  • Backend: .NET 8, PostgreSQL, deployed on Railway
  • Frontend: Flutter Web + Mobile (iOS & Android), deployed on Vercel
  • AI: OpenAI GPT-4o for element detection, GPT-4o mini for change summaries
  • Screenshots: thum.io API for capturing page screenshots
  • Notifications: Brevo (email), Firebase Cloud Messaging (push), plus Slack, Discord, and webhook integrations
  • Error Tracking: Sentry for real-time error monitoring
  • Landing Page: Next.js with i18n support for 9 languages

How Change Detection Works

The monitoring flow is straightforward:

  1. User adds a URL and selects an element (via AI, visual selector, or template)
  2. PulseWatch captures a screenshot and extracts the element content on a schedule
  3. When content changes, it generates an AI summary of what changed
  4. Notifications fire across all configured channels

The AI summary is a game-changer — instead of just saying "something changed," PulseWatch tells you what changed in plain language.

Multi-Channel Notifications

One of the most requested features was flexible notifications. PulseWatch supports:

  • Push notifications — iOS (APNs) and Web (FCM)
  • Email — Detailed change reports via Brevo
  • Slack — Channel-based alerts
  • Discord — Webhook integration
  • Custom Webhooks — POST requests to any endpoint
  • Quiet hours — Don't disturb during sleep

REST API for Developers

As a developer, I wanted PulseWatch to be API-first. The REST API lets you:

GET    /api/watches          — List all monitors
POST   /api/watches          — Create a new monitor
GET    /api/watches/:id      — Get monitor details
DELETE /api/watches/:id      — Delete a monitor
GET    /api/history/:id      — Get change history

Authenticate with an API key (X-API-Key header) and build your own integrations. Full docs at pulsewatch.watch/docs/api.

Chrome Extension

I also built a Chrome extension that lets you add any website to PulseWatch directly from your browser. Right-click on any page → "Monitor with PulseWatch" → done.

Available on the Chrome Web Store.

Internationalization

PulseWatch supports 9 languages: English, Turkish, German, Spanish, French, Arabic, Japanese, Korean, and Chinese. The landing page, app, and even AI-generated change summaries are all localized.

What's Next

I'm currently working on:

  • Public status pages for monitored sites
  • Weekly digest emails
  • Webhook retry mechanism
  • Onboarding flow improvements

Try It Out

PulseWatch has a free tier (2 monitors, daily checks) so you can try it without commitment. Paid plans start at $8.99/month for more monitors, faster checks, and API access.

🔗 Website: pulsewatch.watch
📱 Chrome Extension: Chrome Web Store
📖 API Docs: pulsewatch.watch/docs/api

I'd love to hear your feedback! What features would you find most useful? Drop a comment below 👇

Construct Note: A Local-First, Privacy-Focused Kanban Desktop App

2026-03-01 08:41:12

This is a submission for the Built with Google Gemini: Writing Challenge

What I Built with Google Gemini

I built Construct Note, a fast, local-first Kanban and task management desktop application.

Construct Note Demo

Many modern productivity apps rely heavily on cloud syncing and subscriptions, which can be a privacy concern for users who want complete control over their own data. I wanted to build a Trello-like application that lives entirely on the user's machine, offering the same rich drag-and-drop experience without the data leaving the local file system.

The Tech Stack:

  • Frontend: React, Vite, Tailwind/Vanilla CSS, and @hello-pangea/dnd for fluid drag-and-drop mechanics.
  • Backend / Desktop wrapper: Electron, Express (running locally inside the Electron main process), and better-sqlite3 for high-performance, synchronous database operations.
  • Distribution: Packaged as a standalone Linux AppImage.

Key Features:

  • Unlimited Boards, Lists, and Cards.
  • Full Markdown support for card descriptions (react-markdown).
  • Checklists, Card Notes, and the ability to link/relate cards to one another.
  • Card templates for standardizing repetitive task creation.
  • Offline-by-default architecture: Everything is saved to a local SQLite database (constructnote.db) operating in WAL (Write-Ahead Log) mode for speed.

Adding a card

What role did Google Gemini play?
I used Google Gemini as my AI pair-programmer throughout the majority of the development lifecycle. Gemini helped me:

  1. Architect the Application: I am very bad at planning, which is why I wanted my own little planning helper. Gemini helped me stay in scope and stick to a plan. I put my ideas into simple words and after a few prompts I was able to have a good folder structure to go by and an idea of the general layout with some good suggestions for imports.
  2. Database Design & Migrations: Gemini wrote the SQLite schema and helped incrementally add new features (like milestones and accent colors).
  3. Complex UI Interactions: It assisted in wiring up the React drag-and-drop logic for reordering both lists and cards, ensuring optimistic UI updates matched the backend database state when I encountered some bugs.
  4. Packaging and Compilation: When I ran into native Node module compilation errors trying to bundle better-sqlite3 for Linux, Gemini helped debug the build process and correctly configure the asarUnpack bindings.

Drag and drop demo

What I Learned

  • Native Node Modules: I gained a better understanding of how native C++ Node modules behave when packaged into an .asar archive, and how to configure electron-builder to correctly rebuild them for specific target platforms.
  • AI Pair Programming: Developing with Gemini changed how I approach roadblocks. Instead of spending hours scouring StackOverflow for edge cases (like React state mismatches during fast drag-and-drop reordering), I could bounce ideas off Gemini and implement robust solutions in minutes.

Google Gemini Feedback

What worked well?
Gemini was surprisingly good at holding context of my project. I did not have to repeat myself too many times and I was able to actually progress much quicker in certain areas by having something to bounce ideas off rather than spending hours reading documentation and trying to figure out edge cases.

How I built an AI-powered Git context menu for Windows using Tauri and Rust

2026-03-01 08:36:41

As developers, we commit code constantly. The annoying part is that quick commits tend to force a slow workflow:

  • Open a heavy IDE (often just to stage files and write a message), or
  • Run git add . && git commit -m "fix" in a terminal and hope you remember what changed.

I wanted the best parts of both worlds: visual staging like a GUI, but the speed of a terminal.

So I built GitPop: a lightweight Windows File Explorer extension that adds a modern Git commit UI to your right-click menu, with an optional local AI commit generator.

GitPop on GitHub

GitPop banner

What GitPop does

From File Explorer, you can right-click inside any repo folder and choose GitPop Here to open a small popup that lets you:

  • See changed files instantly
  • Stage and unstage with a clean UI
  • Review diffs (without switching to a separate app) - Coming soon.
  • Generate commit messages from staged diffs using local models via Ollama (or your preferred API)

The core goal is simple: make the “small commit” workflow as fast as a shell command, but less blind.

Tech stack and why Tauri

For a context menu popup, the most important metric is startup time. If right-clicking a folder and selecting GitPop Here takes a noticeable moment, it feels broken.

GitPop uses:

  • Frontend: React + TypeScript + vanilla CSS (glassmorphism-style dark UI)
  • Backend: Rust
  • Framework: Tauri v2

I ruled out Electron because it ships a full Chromium runtime and commonly incurs large binary sizes and heavier memory overhead compared to a native-webview approach. Tauri uses the system webview (WebView2 on Windows) with a Rust backend, which fits the “open instantly” requirement much better.

The engineering challenges

Windows integration looks simple from the outside, but there are a few spicy corners. These were the big three.

1. Registering a File Explorer context menu entry (from Rust)

To show GitPop Here in the right-click menu, GitPop needs to register a command in the Windows Registry.

Instead of asking users to run a .reg file (which feels sketchy even when it is not), GitPop can do this via a Rust command in a “Setup Mode”.

This uses the winreg crate and registers under:

  • HKCU\Software\Classes\Directory\Background\shell\GitPop

That keeps the install per-user (no admin required) and binds the command to the app executable path:

use winreg::enums::*;
use winreg::RegKey;

#[tauri::command]
fn install_context_menu() -> Result<(), String> {
    let hkcu = RegKey::predef(HKEY_CURRENT_USER);

    let exe_path = std::env::current_exe()
        .map_err(|e| e.to_string())?
        .to_string_lossy()
        .into_owned();

    let bg_path = r#"Software\Classes\Directory\Background\shell\GitPop"#;
    let (bg_key, _) = hkcu
        .create_subkey(bg_path)
        .map_err(|e| e.to_string())?;

    bg_key.set_value("", &"GitPop Here").map_err(|e| e.to_string())?;
    bg_key
        .set_value("Icon", &format!("\"{}\"", exe_path))
        .map_err(|e| e.to_string())?;

    let (bg_cmd, _) = bg_key
        .create_subkey("command")
        .map_err(|e| e.to_string())?;

    // %V resolves to the clicked folder path for Directory\Background handlers.
    bg_cmd
        .set_value("", &format!("\"{}\" \"%V\"", exe_path))
        .map_err(|e| e.to_string())?;

    Ok(())
}

Why this approach works well:

  • It is self-contained and reversible
  • It avoids “copy this registry text and trust me” instructions
  • It stays compatible with existing Git setups because GitPop does not try to reconfigure Git

2. The “flashing terminal” bug when spawning Git on Windows

GitPop does not use libgit2. Instead, the Rust backend spawns native Git CLI commands like:

  • git status --porcelain
  • git diff --cached
  • git commit -m ...

This is intentional: the Git CLI automatically respects the user’s existing SSH keys, credential helpers, hooks, and global configs.

On Windows, though, naïvely calling Command::new("git") can cause a CMD window to flash briefly. It is the kind of micro-annoyance that makes an app feel janky.

The fix is to set a Windows-specific process creation flag so child processes run hidden:

use std::process::Command;

#[cfg(target_os = "windows")]
use std::os::windows::process::CommandExt;

#[cfg(target_os = "windows")]
const CREATE_NO_WINDOW: u32 = 0x08000000;

fn build_hidden_cmd(program: &str) -> Command {
    let mut cmd = Command::new(program);

    #[cfg(target_os = "windows")]
    {
        cmd.creation_flags(CREATE_NO_WINDOW);
    }

    cmd
}

From there, all Git calls use build_hidden_cmd("git") instead of Command::new("git").

3. Tauri v2 capabilities, window transparency, and the invisible app trap

I wanted a transparent, glassy popup. That means:

  • "transparent": true
  • Start hidden to avoid a white flash while React loads: "visible": false
  • Show the window once the UI is ready (window.show())

The catch is that Tauri v2 locks down frontend APIs by default. Without the right capability permissions, the window did not crash, it just stayed invisible while the process happily ran in the background.

The fix is to explicitly allow the window operations your frontend performs in capabilities/default.json:

{
  "permissions": [
    "core:window:default",
    "core:window:allow-show",
    "core:window:allow-close",
    "process:allow-exit"
  ]
}

This is one of those “security first” defaults that is correct, but it will absolutely prank you the first time you try to do anything window-related.

The sparkle button: AI commit generation (locally, by default)

Writing commit messages is small, but it adds friction. GitPop’s ✨ Sparkle button reduces that friction:

  1. Stage files
  2. GitPop runs git diff --cached
  3. The staged diff is sent to an LLM to propose a commit message

Privacy matters. Shipping proprietary diffs to a cloud API is a non-starter for a lot of dev work. So GitPop defaults to Ollama, running locally. It detects installed models (for example llama3.2 or qwen2.5-coder) and generates commit messages without API keys, paid tokens, or network calls.

GitPop also supports OpenAI, Anthropic, Gemini, and custom endpoints for people who prefer hosted models. The model selection is an implementation detail. The UX goal is consistent: stage, sparkle, commit, done.

Try it out

If you are on Windows (Soon OSx) and this fits your workflow, grab the latest installer from the repository:

Feedback, issues, and PRs are welcome. I am also exploring what it would take to bring the same “right-click commit UI” to macOS Finder, where the integration constraints are different but the pain is identical.

Happy committing.

How I Redesigned My Portfolio with Google Gemini (and Where the AI Actually Let Me Down)

2026-03-01 08:36:32

This is a submission for the Built with Google Gemini: Writing Challenge

What I Built with Google Gemini

A few months ago I entered DEV's New Year, New You Portfolio Challenge and decided to rebuild my portfolio from scratch. The brief: use Google AI's tools, deploy to Cloud Run, make it yours.

The result is "Brutalist/Industrial" (original submission post). The aesthetic intentionally rejects the clean, white-space-heavy look that most developer portfolios default to. Exposed grids, heavy typography with the SCHABO typeface, cursor-reactive background cells, a mathematically generated DNA helix that assembles and deconstructs as you scroll. The whole thing runs on Astro with React islands, GSAP for animations, and OGL (a lightweight WebGL library) for a metaballs footer effect.

The most interesting part, at least for this challenge, was the Gemini integration I shipped as actual product features rather than just development tooling:

Pitch Generator: paste any job description into it, and it pulls from a structured knowledge base of my work to generate a tailored pitch explaining why I'm a fit. Not a boilerplate cover letter, a specific one.

Interactive Assistant: a terminal-style interface that answers questions about my stack and recommends relevant projects based on what the visitor is looking for. It uses RAG with my portfolio data as the knowledge base, served through Google Genkit with Zod-validated flows and server-side rendering via Astro's Node adapter.

Both features run on Gemini 2.5 Flash. I wanted to demonstrate that AI in a portfolio doesn't have to mean a chatbot that says "Hi! I'm Ore's assistant." It can be a tool that does something useful for the person looking at your work.

I also used Google Antigravity as my primary AI coding pair throughout the build, and Nano Banana Pro to generate and iterate on imagery to match the industrial art direction.

Demo

https://ore.codes

What I Learned

Google Antigravity handled things I would have spent hours on otherwise: refactoring the original Codegrid template (raw HTML/CSS/JS with a sci-fi theme) into Astro and React components, writing the sine wave math for the DNA helix, catching performance regressions in the WebGL loop.

On the engineering side, it was often genuinely good. Give it a clear, bounded problem ("make this GSAP ScrollTrigger reversible on scroll-up") and it would produce something workable on the first or second attempt.

The design side was a different story, and this was the biggest surprise.

What I didn't anticipate was how little the AI could help with actual creative direction. I had a clear concept (Industrial/Brutalist, raw, engineering-first) but when I tried to use it to develop the visual language, I kept getting suggestions that were technically fine and aesthetically inert. Gradient proposals that belonged on a SaaS landing page. Color palettes that were "safe." Layout ideas that could have come from any template.

The AI wasn't wrong. It just had no sense of what I was going for, and no amount of prompting about "brutalism" or "industrial aesthetic" closed that gap. I ended up doing all the design decision-making myself and using the AI to execute those decisions, not to arrive at them.

The real skill I walked away with is knowing which problems to hand off and which to hold. Bounded, well-specified engineering problems: hand off. Open-ended creative decisions that require taste: hold.

DNA section while scrolling

Google Gemini Feedback

My biggest gripe isn't dramatic. No hallucinated APIs, no rate limit crises. The problem was subtler: outputs were consistently competent and consistently generic until I provided so much direction that I might as well have specified the answer in the prompt.

For the Pitch Generator, early iterations produced pitches that were accurate but read like they were assembled from a template. "Ore is a skilled full-stack engineer with experience in X, Y, and Z..." Fine. Forgettable. I spent a lot of time refining the system prompt and knowledge base schema to push the outputs toward something that actually sounded like how I'd pitch myself in a real conversation.

What worked well was the Genkit integration. The type-safe flows with Zod schemas made it straightforward to build production-ready AI features without treating the model as a black box. Server-side rendering through Astro's Node adapter kept API keys secure without any awkward workarounds. That part of the experience was genuinely smooth.

The lesson on the friction side: Gemini rewards precision. Vague prompts produce vague results. When I described exactly what I wanted (the tone, the structure, specific things to emphasize) the quality went up meaningfully. But that precision requires you to already know what good looks like, which means the model can't substitute for taste, only for execution once the taste is established.

AI features

What's next

The portfolio is staying live and I plan to keep building on the AI features. The Pitch Generator currently takes a job description and outputs a pitch; I want to add a follow-up mode where the visitor can ask it to emphasize particular aspects of my background, making it more of a back-and-forth tool than a one-shot output.

The Interactive Assistant's knowledge base is static right now, a JSON structure I maintain manually. I want to connect it to a proper database so I can update it as I ship new projects without redeploying.

I'm also looking at adding project search using embeddings instead of keyword matching, so someone can describe what they're trying to build and get back relevant work from my portfolio rather than having to browse everything.

The DNA helix math, the Genkit integration, the Cloud Run deployment pipeline: all of it benefited from AI assistance. The decision to build an industrial portfolio that looks nothing like other portfolios? That one was mine.

Website's font in light mode