<?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: Yunus Emre Altanay</title>
    <description>The latest articles on DEV Community by Yunus Emre Altanay (@yemrealtanay).</description>
    <link>https://dev.to/yemrealtanay</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F659658%2Fc2259f0f-2b42-47e1-b097-b737dabc330c.png</url>
      <title>DEV Community: Yunus Emre Altanay</title>
      <link>https://dev.to/yemrealtanay</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yemrealtanay"/>
    <language>en</language>
    <item>
      <title>How I Built a PII Tokenization Middleware to Keep Sensitive Data Out of LLM APIs</title>
      <dc:creator>Yunus Emre Altanay</dc:creator>
      <pubDate>Mon, 06 Apr 2026 09:25:18 +0000</pubDate>
      <link>https://dev.to/yemrealtanay/how-i-built-a-pii-tokenization-middleware-to-keep-sensitive-data-out-of-llm-apis-18po</link>
      <guid>https://dev.to/yemrealtanay/how-i-built-a-pii-tokenization-middleware-to-keep-sensitive-data-out-of-llm-apis-18po</guid>
      <description>&lt;h2&gt;
  
  
  The Problem I Kept Ignoring
&lt;/h2&gt;

&lt;p&gt;Every time we sent a customer transcript to an LLM API, we were sending real data — credit card numbers, home addresses, full names, national IDs — in plaintext to a third-party server.&lt;/p&gt;

&lt;p&gt;Most teams I've talked to handle this in one of two ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Ignore it&lt;/strong&gt; and hope the provider's data processing agreement covers them&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt engineer around it&lt;/strong&gt; — "don't repeat personal information in your response" — which does nothing about what's already been transmitted&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Neither is acceptable in a production system handling real user data. So I built &lt;a href="https://github.com/yemrealtanay/llm-hasher" rel="noopener noreferrer"&gt;llm-hasher&lt;/a&gt; — a PII tokenization middleware that sits between your application and any LLM API.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Core Idea
&lt;/h2&gt;

&lt;p&gt;The LLM doesn't need to see the actual credit card number to summarize a support transcript. It just needs to know &lt;em&gt;a credit card number was mentioned&lt;/em&gt;. So instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Hi, my card is 4111-1111-1111-1111 and email is john@example.com"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The LLM receives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Hi, my card is CREDIT_CARD_john12_4f8a2b and email is EMAIL_john12_9c3d1a"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It can still reason about the context. It just never touches the real values. When the response comes back, you detokenize it and restore the originals.&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;Your App ──► POST /v1/tokenize ──► llm-hasher ──► tokenized text
                                       │
                              detects PII locally
                              (Ollama, no cloud)
                              stores in encrypted vault

Your App ──► [your LLM call with tokenized text]

Your App ──► POST /v1/detokenize ──► llm-hasher ──► original text restored
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three moving parts: a &lt;strong&gt;detector&lt;/strong&gt;, a &lt;strong&gt;vault&lt;/strong&gt;, and an &lt;strong&gt;HTTP service&lt;/strong&gt; wrapping both.&lt;/p&gt;




&lt;h2&gt;
  
  
  Detection: Hybrid Regex + LLM
&lt;/h2&gt;

&lt;p&gt;PII falls into two categories that require different detection strategies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Structured PII&lt;/strong&gt; — credit cards, emails, IBANs, IPv4 addresses — has well-defined patterns. Regex handles these with sub-millisecond latency and 100% recall on valid formats. No need to involve a language model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contextual PII&lt;/strong&gt; — names, addresses, national IDs, passports — is where regex breaks down completely. "John Smith" looks identical to "Smith &amp;amp; Wesson" to a pattern matcher. You need semantic understanding.&lt;/p&gt;

&lt;p&gt;For contextual PII, llm-hasher sends the text to a locally running Ollama instance. The model (default: &lt;code&gt;llama3.2:3b&lt;/code&gt;) extracts entities and returns structured JSON. Because Ollama runs on your own server, this detection step never touches an external API — your raw data stays on your infra.&lt;/p&gt;

&lt;p&gt;The hybrid approach gives you the best of both: speed and precision for structured types, semantic understanding for contextual ones.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chunking for Long Texts
&lt;/h3&gt;

&lt;p&gt;Sending a 5,000-word transcript to Ollama in one shot causes problems — context window limits, degraded accuracy on long inputs, serial latency.&lt;/p&gt;

&lt;p&gt;llm-hasher chunks large texts (configurable, default 800 words) and processes chunks in parallel goroutines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Simplified — actual implementation handles overlap and deduplication&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Detector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;detectParallel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChunkSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;detectWithOllama&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;entities&lt;/span&gt;
        &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A 5,000-word document with 6 chunks processes in roughly the same time as a single chunk — latency scales with the slowest chunk, not the total count.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Vault: AES-256-GCM Encrypted SQLite
&lt;/h2&gt;

&lt;p&gt;Token-to-value mappings are stored in a local SQLite database. Each value is encrypted with AES-256-GCM before being written.&lt;/p&gt;

&lt;p&gt;Key design decisions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context scoping with your own IDs.&lt;/strong&gt; Instead of generating opaque foreign UUIDs that you'd need to track on your side, you pass a &lt;code&gt;context_id&lt;/code&gt; from your domain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hi, my card is 4111-1111-1111-1111"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"context_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"zoom_call_789"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means your Zoom call processor can detokenize with &lt;code&gt;zoom_call_789&lt;/code&gt; without needing to store a mapping between your ID and a vault-generated UUID.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deduplication within a context.&lt;/strong&gt; The same PII value within a context always maps to the same token. If a name appears five times in a transcript, the LLM sees the same token each time — so it can reason about the entity consistently across the full text.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TTL support.&lt;/strong&gt; Tokens can have an expiry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"context_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"session_abc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ttl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"24h"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For compliance scenarios (GDPR right to erasure), there's a hard-delete endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;DELETE /v1/contexts/{context_id}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This removes all mappings for that context from the vault. Once deleted, detokenization is impossible — by design.&lt;/p&gt;




&lt;h2&gt;
  
  
  Detokenization: Single-Pass Multi-String Replace
&lt;/h2&gt;

&lt;p&gt;Naive detokenization would loop through each token and do a string replace — O(n×m) where n is text length and m is token count. For a transcript with 40 entities, that's 40 passes over the text.&lt;/p&gt;

&lt;p&gt;llm-hasher builds an Aho-Corasick automaton from the token set and does a single linear pass:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Vault&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Detokenize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mappings&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;replacer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewReplacer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mappings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;replacer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&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;Detokenization latency is effectively constant regardless of token count — typically under 5ms even for large documents.&lt;/p&gt;




&lt;h2&gt;
  
  
  Real-World Integration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Python — LLM Proxy Pattern
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;

&lt;span class="c1"&gt;# 1. Tokenize before sending to LLM
&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:8080/v1/tokenize&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;transcript&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;context_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;zoom_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;call_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;tokenized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Send tokenized text to your LLM
&lt;/span&gt;&lt;span class="n"&gt;llm_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;system&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Summarize this call transcript.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tokenized&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tokenized_text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 3. Detokenize the LLM response
&lt;/span&gt;&lt;span class="n"&gt;final&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:8080/v1/detokenize&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;llm_response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;context_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;zoom_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;call_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;final&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;original_text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Go — Library Mode
&lt;/h3&gt;

&lt;p&gt;If you don't want to run a separate HTTP service, import the hasher package directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"github.com/yemrealtanay/llm-hasher/pkg/hasher"&lt;/span&gt;

&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;hasher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;hasher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithOllama&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://localhost:11434"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"llama3.2:3b"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;hasher&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithVault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"data/vault.db"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tokenize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transcript&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"zoom_call_789"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// result.Text contains tokenized transcript&lt;/span&gt;

&lt;span class="n"&gt;original&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Detokenize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;llmResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"zoom_call_789"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Performance Characteristics
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Typical Latency&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Short text, regex PII only&lt;/td&gt;
&lt;td&gt;&amp;lt; 5ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Short text with LLM detection&lt;/td&gt;
&lt;td&gt;2–8s (model dependent)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Long text (5,000 words), 6 parallel chunks&lt;/td&gt;
&lt;td&gt;3–10s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Detokenize (any size)&lt;/td&gt;
&lt;td&gt;&amp;lt; 5ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The dominant cost is Ollama inference. On a modern laptop with &lt;code&gt;llama3.2:3b&lt;/code&gt;, expect 2–4 seconds per chunk. A GPU or a larger/faster model changes this significantly. If your use case is async (batch processing, background jobs), the latency is generally acceptable without hardware changes.&lt;/p&gt;

&lt;p&gt;For latency-sensitive paths, run tokenization asynchronously before the user-facing LLM call — most pipelines have a natural point to do this.&lt;/p&gt;




&lt;h2&gt;
  
  
  What It Doesn't Do (Yet)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;It's not a firewall.&lt;/strong&gt; If someone deliberately encodes PII to evade detection (e.g., spelling out digits), llm-hasher won't catch it. It handles the common case, not adversarial inputs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ollama recall isn't 100%.&lt;/strong&gt; The LLM detector misses things, especially in noisy or multilingual text. Tuning &lt;code&gt;confidence_threshold&lt;/code&gt; and chunk size helps, but there's no guarantee of perfect recall without human review.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No streaming support yet.&lt;/strong&gt; Tokenization requires the full text — SSE/streaming tokenization is on the v2 roadmap.&lt;/p&gt;




&lt;h2&gt;
  
  
  Running It
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/yemrealtanay/llm-hasher
&lt;span class="nb"&gt;cd &lt;/span&gt;llm-hasher
make docker-up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Docker Compose starts Ollama, pulls &lt;code&gt;llama3.2:3b&lt;/code&gt; (~2GB), and starts the service on port 8080. Check it's running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8080/healthz
&lt;span class="c"&gt;# {"status":"ok"}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For production, set an explicit vault encryption key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Generate&lt;/span&gt;
openssl rand &lt;span class="nt"&gt;-hex&lt;/span&gt; 32

&lt;span class="c"&gt;# Set in .env&lt;/span&gt;
&lt;span class="nv"&gt;VAULT_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your_64_char_hex_key&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;VAULT_KEY&lt;/code&gt; is not set, a key is auto-generated and saved to &lt;code&gt;data/vault.key&lt;/code&gt;. Fine for development, not for production — you need the key to survive restarts.&lt;/p&gt;




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

&lt;p&gt;The v2 roadmap includes built-in LLM proxy endpoints (OpenAI-compatible and Anthropic), so instead of calling llm-hasher then your LLM separately, you point your existing OpenAI client at llm-hasher and it handles tokenization transparently in the middle. This would make adoption essentially zero-config for teams already using the OpenAI SDK.&lt;/p&gt;

&lt;p&gt;Contributions are welcome, especially for &lt;strong&gt;v2 LLM provider adapters&lt;/strong&gt; — each provider is a well-defined, self-contained implementation.&lt;/p&gt;




&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/yemrealtanay/llm-hasher" rel="noopener noreferrer"&gt;github.com/yemrealtanay/llm-hasher&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;License: MIT&lt;/li&gt;
&lt;li&gt;Issues / PRs welcome&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>llm</category>
      <category>privacy</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Learning to Learn: The Real Skill of a Developer</title>
      <dc:creator>Yunus Emre Altanay</dc:creator>
      <pubDate>Sun, 02 Nov 2025 15:06:46 +0000</pubDate>
      <link>https://dev.to/yemrealtanay/learning-to-learn-the-real-skill-of-a-developer-1m8m</link>
      <guid>https://dev.to/yemrealtanay/learning-to-learn-the-real-skill-of-a-developer-1m8m</guid>
      <description>&lt;p&gt;Learning Go is easy.&lt;br&gt;
Five videos, two blogs, a bit of coding, and a few right questions to ChatGPT — and you’ll have your “hello world.”&lt;br&gt;
But the point isn’t learning Go.It’s learning how to learn any technology quickly.&lt;br&gt;
Because tomorrow it’ll be Rust, and the next day, AI will turn it all into some meta-language anyway.&lt;/p&gt;

&lt;p&gt;Technology no longer expects humans to be knowledgeable it expects them to be adaptable. Mastering one framework isn’t a skill; being able to understand the logic behind any framework is.The difference now isn’t how much you know, but how fast you can learn.&lt;/p&gt;

&lt;p&gt;Knowledge expires. But your way of learning stays. It’s no longer about writing code — it’s about debugging your own learning algorithm.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Traditional Learning Fails&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because technology moves at warp speed while we still study like it’s a classroom. We start with articles, videos, notes, repetition and before we know it, we’ve consumed the same information three times from different sources, yet still haven’t built anything.&lt;/p&gt;

&lt;p&gt;Traditional learning was made for static worlds. You’d read a book once and the information stayed valid for years. Now the documentation changes between page refreshes. Your handwritten notes are already outdated.&lt;/p&gt;

&lt;p&gt;Modern learning isn’t linear it’s cyclical:&lt;br&gt;
Try → Fail → Fix → Try again.&lt;br&gt;
The shorter that loop, the faster you evolve. Traditional methods simply can’t keep up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Mistakes We Make While Learning&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The most common one: we try to feel like we’re learning, instead of actually learning. We watch videos, take notes, and say “I get it now,” yet we never produce anything. The brain isn’t learning it’s just getting a dopamine hit.&lt;/p&gt;

&lt;p&gt;Then comes the obsession with understanding everything before acting. But understanding isn’t the cause of learning it’s the byproduct. Try first, then comprehension comes later. Run the code. Break it. Fix it. The brain extracts meaning from the scars left by failure.&lt;/p&gt;

&lt;p&gt;And of course, the speed obsession. Everyone’s shouting, “I learned Rust in a week!” No they learned the syntax, not the thinking model. Speed is being confused with depth. Real learning is still slow but continuous.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Information Is Everywhere, Understanding Is Not&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Thanks to AI, it’s now impossible not to access information. But understanding? Still a personal journey. AI gives you answers but if you don’t figure out why those answers work, you’ve learned nothing.&lt;/p&gt;

&lt;p&gt;The problem today isn’t ignorance it’s shallowness. Everything is within reach, yet nothing sinks in. We copy a command, it works, and we never ask why. But meaning is born inside that “why.”&lt;/p&gt;

&lt;p&gt;Unlimited access to understanding is possible only in one way: by keeping your curiosity muscle alive. Don’t move on the moment you get an answer.&lt;br&gt;
Stop and ask, “Why does this work?” That’s the moment learning actually happens not when you get the answer, but when you question it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learning Methods and Mental Endurance&lt;/strong&gt;&lt;br&gt;
Active Recall&lt;/p&gt;

&lt;p&gt;Passive learning is the brain’s enemy. Watching videos, reading articles, taking notes they feed information in but skip the processing part. Active recall means forcing your brain to work. Ask yourself:&lt;/p&gt;

&lt;p&gt;“Can I actually explain this topic?”&lt;/p&gt;

&lt;p&gt;Close your sources, open a blank page, and explain in your own words. If you can’t form sentences, you haven’t learned it. Learning isn’t about taking in information it’s about reproducing it. That tiny moment of mental friction is where real learning begins.&lt;/p&gt;

&lt;p&gt;Spaced Repetition&lt;/p&gt;

&lt;p&gt;The brain is built to forget. Trying to memorize everything at once is like writing to RAM it disappears when you power off.&lt;/p&gt;

&lt;p&gt;Spaced repetition means planning to forget. Revisit a topic after 1 day, 3 days, 7 days, 14 days. Each time you recall it, your brain re-discovers it, and the connection gets stronger.&lt;/p&gt;

&lt;p&gt;Simple rule:&lt;/p&gt;

&lt;p&gt;“Review not when you’ve forgotten, but right before you forget.”&lt;/p&gt;

&lt;p&gt;That’s when your brain upgrades short-term data into long-term memory.&lt;br&gt;
Learning isn’t a single event it’s a series of well-timed mental workouts.&lt;/p&gt;

&lt;p&gt;Zettelkasten (Linked Notes)&lt;/p&gt;

&lt;p&gt;Most people treat note-taking like hoarding. But archiving isn’t learning.&lt;br&gt;
Zettelkasten is a way to organize notes by connections, not hierarchy.&lt;/p&gt;

&lt;p&gt;Each note links to another ideas form a web. &lt;/p&gt;

&lt;p&gt;For example, a note on “learning psychology” connects to “active recall,” which connects to “memory systems.” One day you realize you’ve built a second brain.&lt;/p&gt;

&lt;p&gt;In this system, knowledge isn’t static it grows. Each new idea touches an old one, keeping the whole system alive. For developers, this is gold.&lt;br&gt;
It’s not a library; it’s a mental map.&lt;/p&gt;

&lt;p&gt;Feedback Loop&lt;/p&gt;

&lt;p&gt;Teaching something is the fastest way to learn it. Explaining tests your own reasoning process. Writing documentation, mentoring, or just explaining your code out loud — all of these force your brain to organize knowledge. If you get stuck while explaining, that’s where your gap is.&lt;/p&gt;

&lt;p&gt;Learning becomes a cycle:&lt;/p&gt;

&lt;p&gt;Try → Teach → Spot the gap → Fix it.&lt;/p&gt;

&lt;p&gt;Even explaining to yourself works. Turn on the camera, talk it out, record a voice note. The moment you pretend to be observed, your brain starts cleaning up the mess.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A 5-Step Framework to Learn How to Learn&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Knowing the methods isn’t enough you have to systematize them. Here’s a simple model that turns theory into habit.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Map It&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Before learning anything, ask:&lt;/p&gt;

&lt;p&gt;“What does the map of this topic look like?”&lt;br&gt;
The goal of day one isn’t understanding it’s seeing the outline. What are the subtopics, the key ideas, the dependencies? Draw a map. Give your brain a sense of direction.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build Small Loops&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The fastest way to understand something is to use it immediately. Not in big projects in tiny experiments. New framework? Don’t build a full app make a one-endpoint test. New language? Rebuild a small function.&lt;/p&gt;

&lt;p&gt;The goal isn’t perfection; it’s to wire the reflex of try → break → fix → repeat.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Explain to Retain&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you don’t teach it, you’ll forget it. Write, talk, draw, explain even to yourself.&lt;/p&gt;

&lt;p&gt;“Explaining is the brain’s compile step.”&lt;/p&gt;

&lt;p&gt;That’s when knowledge becomes structured and permanent.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reflect &amp;amp; Refactor&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every few days, review your process.&lt;/p&gt;

&lt;p&gt;“What did I actually understand?”&lt;br&gt;
“What didn’t stick?”&lt;br&gt;
Learning to learn is really refactoring your learning system. Simplify it, optimize it, make it sustainable.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Link Everything&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Connect new ideas to old ones. A technology, a concept, a pattern each becomes durable when it links to something you already know. This is why Zettelkasten works: linked memory stays alive. Your brain remembers through relationships, not isolation.&lt;/p&gt;

&lt;p&gt;Short Formula&lt;/p&gt;

&lt;p&gt;Map → Build → Explain → Refactor → Link&lt;/p&gt;

&lt;p&gt;Once this loop becomes a habit, you’ve learned how to learn. Because you no longer ask how to learn one thing you know how to learn anything.&lt;/p&gt;

&lt;p&gt;Conclusion&lt;/p&gt;

&lt;p&gt;Access to information is no longer a problem. The real challenge is transforming that information into understanding. Languages, frameworks, technologies they’ll keep changing. But those who build their learning system will never fall behind.&lt;br&gt;
Code, architecture, even programming paradigms will shift.&lt;br&gt;
But one truth remains:&lt;/p&gt;

&lt;p&gt;Those who learn how to learn never start from zero.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>ai</category>
      <category>productivity</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The Art of Asking Questions in the Age of AI</title>
      <dc:creator>Yunus Emre Altanay</dc:creator>
      <pubDate>Tue, 23 Sep 2025 10:44:10 +0000</pubDate>
      <link>https://dev.to/yemrealtanay/the-art-of-asking-questions-in-the-age-of-ai-1gp5</link>
      <guid>https://dev.to/yemrealtanay/the-art-of-asking-questions-in-the-age-of-ai-1gp5</guid>
      <description>&lt;p&gt;In one of my older writings, I argued that &lt;em&gt;“asking the right question”&lt;/em&gt; was the golden key to getting quick and useful answers from people. Back then, developer communities, forums, and Telegram groups were the holy grounds where our questions lived. Everyone had Google, but the real magic was asking the right people in the right way. Ask poorly, and you’d either get mocked or dismissed with: &lt;em&gt;“Dude, do your own research first.”&lt;/em&gt;  &lt;/p&gt;

&lt;p&gt;Today, things are different. Instead of &lt;em&gt;bad-tempered humans&lt;/em&gt;, we now face an &lt;em&gt;always-eager, sometimes confused&lt;/em&gt; AI. Large Language Models (LLMs) like ChatGPT have rewritten the rules of the game.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Superpowers and Weaknesses of AI
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Thrives on raw input&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feed AI code snippets, error logs, and outputs—it digests them instantly. A human would need to parse, think, and simulate first.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Infinite patience&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Humans get tired or annoyed. AI doesn’t. Throw a 3-page prompt at it; it won’t ask for a coffee break.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Wrong context = plausible nonsense&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The danger zone. Wrong or incomplete context yields answers that &lt;em&gt;look&lt;/em&gt; right but waste hours. Context is everything.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Core Principles for AI-Era Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Research First, Then Ask AI
&lt;/h3&gt;

&lt;p&gt;“Google it first” is still true. Now it means:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Search docs, forums, or GitHub issues.
&lt;/li&gt;
&lt;li&gt;Use AI to simplify, expand, or validate what you found.
&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  2. Provide Maximum Context
&lt;/h3&gt;

&lt;p&gt;Details matter:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Language, version, framework
&lt;/li&gt;
&lt;li&gt;Error messages, code snippets
&lt;/li&gt;
&lt;li&gt;Expected output
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without this, AI can’t guess your intent.  &lt;/p&gt;




&lt;h3&gt;
  
  
  3. Be Explicit, Define the Output Format
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Weak ask: &lt;em&gt;“Explain this.”&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Strong ask: &lt;em&gt;“Explain this in 3 bullet points, each with a code block and inline comments.”&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The clearer your request, the more useful the answer.  &lt;/p&gt;




&lt;h3&gt;
  
  
  4. Ask Step by Step
&lt;/h3&gt;

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

&lt;blockquote&gt;
&lt;p&gt;“Build me a login system.”  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Try:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Draft the flow
&lt;/li&gt;
&lt;li&gt;Add details
&lt;/li&gt;
&lt;li&gt;Suggest test cases
&lt;/li&gt;
&lt;li&gt;Refine the code
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Small steps prevent irrelevant dumps.  &lt;/p&gt;




&lt;h3&gt;
  
  
  5. Request Version and Source Info
&lt;/h3&gt;

&lt;p&gt;Ask directly:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;“Which PHP version does this work for?”&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;“What documentation does this come from?”&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This stops you from applying outdated or mismatched advice.  &lt;/p&gt;




&lt;h3&gt;
  
  
  6. Add Safety Nets
&lt;/h3&gt;

&lt;p&gt;AI isn’t flawless. For production code:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always ask for test scenarios
&lt;/li&gt;
&lt;li&gt;Run everything in staging first
&lt;/li&gt;
&lt;li&gt;Don’t skip validation
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Practical Prompt Templates
&lt;/h2&gt;

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

&lt;p&gt;My goal: &lt;br&gt;&lt;br&gt;
Environment: &lt;br&gt;&lt;br&gt;
Code: &lt;br&gt;&lt;br&gt;
Error / Expected:   &lt;/p&gt;

&lt;p&gt;Expected output:&lt;br&gt;&lt;br&gt;
1) Explain the root cause&lt;br&gt;&lt;br&gt;
2) Suggest a 3-step fix&lt;br&gt;&lt;br&gt;
3) Add test instructions for each step&lt;/p&gt;

&lt;h3&gt;
  
  
  Design / Architecture
&lt;/h3&gt;

&lt;p&gt;Context: &lt;br&gt;&lt;br&gt;
Constraints: &lt;br&gt;&lt;br&gt;
Problem:   &lt;/p&gt;

&lt;p&gt;Expected output:&lt;br&gt;&lt;br&gt;
1) 3 alternative solutions with pros/cons&lt;br&gt;&lt;br&gt;
2) Best option + 6-step plan&lt;br&gt;&lt;br&gt;
3) Risks and mitigation strategies&lt;/p&gt;

&lt;h3&gt;
  
  
  Concept Learning
&lt;/h3&gt;

&lt;p&gt;Topic: &lt;br&gt;&lt;br&gt;
Level:   &lt;/p&gt;

&lt;p&gt;Expected output:&lt;br&gt;&lt;br&gt;
1) 3-sentence summary&lt;br&gt;&lt;br&gt;
2) Key concepts listed&lt;br&gt;&lt;br&gt;
3) Simple example&lt;br&gt;&lt;br&gt;
4) 2–3 reliable resources&lt;/p&gt;

&lt;h3&gt;
  
  
  From Human Question to AI Prompt
&lt;/h3&gt;

&lt;p&gt;Original Human Question:&lt;/p&gt;

&lt;p&gt;“X data isn’t being posted, and Y function doesn’t work. What do I do?”&lt;/p&gt;

&lt;p&gt;AI-Optimized Prompt:&lt;/p&gt;

&lt;p&gt;Goal: Send form data via POST to &lt;a href="https://api.example.com/forward" rel="noopener noreferrer"&gt;https://api.example.com/forward&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Code: &lt;br&gt;&lt;br&gt;
Problem: Request goes out but service returns 500. Log shows ‘Undefined index: body’.&lt;br&gt;&lt;br&gt;
Expectation: Data should be sent, service should return 200.  &lt;/p&gt;

&lt;p&gt;Expected output:&lt;br&gt;&lt;br&gt;
1) List 5 possible causes&lt;br&gt;&lt;br&gt;
2) Steps to check each cause&lt;br&gt;&lt;br&gt;
3) Example fix in code&lt;/p&gt;

&lt;p&gt;No guessing. AI now has the full picture.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common Mistakes (and Fixes)
&lt;/h2&gt;

&lt;p&gt;No: “It doesn’t work.”&lt;br&gt;
Include logs, environment, and code.&lt;/p&gt;

&lt;p&gt;No: Huge, vague asks&lt;br&gt;
Break problems into smaller parts.&lt;/p&gt;

&lt;p&gt;No: No format instructions&lt;br&gt;
Say “step by step + code block.”&lt;/p&gt;

&lt;p&gt;No: Blind trust&lt;br&gt;
Always test before deploying.&lt;/p&gt;




&lt;h2&gt;
  
  
  Questions Still Matter
&lt;/h2&gt;

&lt;p&gt;Once, asking well earned you respect in forums. Now, it earns you better AI answers.&lt;/p&gt;

&lt;p&gt;Good prompts = good results.&lt;br&gt;
AI doesn’t “know”—it reflects the quality of your input.&lt;/p&gt;

&lt;p&gt;So treat AI like your soldier: arm it with context, precision, and clear goals. Technology changes, but the art of asking remains timeless.&lt;/p&gt;

&lt;p&gt;Questions still matter—only the address has changed.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>developers</category>
      <category>learning</category>
    </item>
    <item>
      <title>Artificial Intelligence, Devin and Farewell to Software Developers(!)</title>
      <dc:creator>Yunus Emre Altanay</dc:creator>
      <pubDate>Sun, 17 Mar 2024 17:12:30 +0000</pubDate>
      <link>https://dev.to/yemrealtanay/artificial-intelligence-devin-and-farewell-to-software-developers-5e7j</link>
      <guid>https://dev.to/yemrealtanay/artificial-intelligence-devin-and-farewell-to-software-developers-5e7j</guid>
      <description>&lt;p&gt;OpenAI has undoubtedly revolutionized our lives. Yes, it has revolutionized the lives of every person, regardless of their profession and their distance from the computer, but we would not be unfair if we say that it touched the lives of software developers the most. CoPilot, developed by Github and OpenAI, was perhaps one of the first footsteps of this revolution. It enabled us to write code faster and easier, and it was improving and improving itself every day. Chatgpt, which was later made available to everyone, Gemini, which has just started to enter our lives, many other artificial intelligence tools, and finally Devin, which is claimed to be the world's first artificial intelligence software engineer.&lt;/p&gt;

&lt;p&gt;The revolutions that have come one after another in this short time have undoubtedly created a change in the lives of us software developers. Some people are afraid of losing their profession, while others are about to be convinced that this profession is an unreasonable profession to choose and has no future. Some have found ways to use these technologies to their advantage. Learning faster, writing code faster, delegating simpler tasks to artificial intelligence and finding time to deal with more complex tasks. Some companies seem to have found ways to employ fewer developers. Or everyone thinks that technology companies, which have recently made serious layoffs, are able to work with fewer software developers thanks to Artificial Intelligence.&lt;/p&gt;

&lt;p&gt;The revolutions we mentioned above are not the first revolutions of software. This is not the first time that software developers have made such a shocking progress and have to keep up with it.&lt;/p&gt;

&lt;p&gt;As humanity, we have created 9000 different programming languages since the emergence of the first computer. Some of these languages became very popular in their time and were used by everyone. Experts in these languages emerged and continued to develop better software as if they would never be shaken.&lt;/p&gt;

&lt;p&gt;But revolution was always at the door. Programming languages that are closer to human language, easier to learn and write, and developed for specific tasks have emerged and started to replace popular languages. Slogans that everyone can now learn software were already being shouted in the mid-1990s. In the early 2000s, it was said that software would be taught in primary schools, everyone would be a software developer, and we would continue our daily work, needs and communication with software languages. It was discussed whether programming languages could also be used for human communication.&lt;/p&gt;

&lt;p&gt;As programming languages became easy to learn and fun to write, a thesis was put forward every day about which profession was finished and which type of person was no longer needed. Software had become an enemy to people who did not know it.&lt;/p&gt;

&lt;p&gt;However, new technologies and languages were also the enemy of software developers. Software developers who did not improve themselves and did not follow innovations that specialized in only one language were lost on the dusty shelves of history. Good software developers produced better software and made the work of both people and themselves easier. This has led to the development of better software developers and the elimination of worse software developers, and has continued to this day.&lt;/p&gt;

&lt;p&gt;When software developers developed Google Translate in 2006, it was thought that the translation profession was coming to an end. However, today, Google Translate continues to pave the way for better translators to be trained, for foreign language learners to learn more languages, and for those who do not know the language to benefit, rather than ending the profession of translators.&lt;/p&gt;

&lt;p&gt;Technology develops, everyone has to keep up with it. Those who cannot keep up will perish. Programming, which is done with small holes and protrusions drilled into copper plates, has become full of artificial intelligence tools that show us all classes starting with that letter when we press a letter, enable us to update and correct the entire code with a single click, and produce examples when we tell us the code we want to write.&lt;/p&gt;

&lt;p&gt;These developments will not destroy software developers, but they will definitely contribute to the development of better software and software developers.&lt;/p&gt;

&lt;p&gt;We are now in Devin's era. He can design and code a certain level of software tasks on his own. So what does this mean? This now means a great opportunity for us, software developers, to do much more complex and bigger jobs. According to some, it is a farewell to software developers.&lt;/p&gt;

&lt;p&gt;I can understand why the good news that every new artificial intelligence tool will bring the end of software developers is spreading so much on social media. For the last 20 years, software developers have threatened the professions of many people with their innovations and inventions. Of course, imagining that it is their turn may feed our sense of pleasant fantasy and revenge.&lt;/p&gt;

&lt;p&gt;However, this new era is nothing more than a light that progresses much faster and indicates that many more software developers can do much bigger things.&lt;/p&gt;

&lt;p&gt;Nvidia CEO made a statement in the past weeks implying that learning software is no longer necessary and that we are teaching software to our children in vain. But isn't that all big companies want anyway? Don't bother, we will do it on your behalf and you just pay us.&lt;/p&gt;

&lt;p&gt;No. Software is growing like never before and will continue to grow. Maybe it is not a very distant possibility for the dreams made in the late 90s to come true. However, in order to achieve this, we need an artificial intelligence that helps us, rather than an artificial intelligence that controls us. Otherwise, it will be impossible for us to distinguish whether the thing to which we are entrusting our vital decisions is an artificial intelligence or a giant company.&lt;/p&gt;

&lt;p&gt;In order to realize this, instead of saying goodbye to software developers, we should know that we need them more...&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Art of Asking Questions</title>
      <dc:creator>Yunus Emre Altanay</dc:creator>
      <pubDate>Fri, 16 Jun 2023 14:27:43 +0000</pubDate>
      <link>https://dev.to/yemrealtanay/the-art-of-asking-questions-4ajo</link>
      <guid>https://dev.to/yemrealtanay/the-art-of-asking-questions-4ajo</guid>
      <description>&lt;p&gt;Especially if you have just started software and I can clearly say that even if you haven't started yet, you have asked or wanted to ask hundreds of questions to people working in the software industry. Although I guess what your questions are, in this article, instead of answering these questions, I will try to explain how you can ask effective questions and increase your chances of getting an answer. In addition, although you may not realize it in the article, "asking a question" is a much more important and serious issue than you might imagine. That's why I recommend that you read this article and the "question guide" that I will share at the end, very seriously and carefully.&lt;/p&gt;

&lt;p&gt;I said increasing your odds of getting an answer because asking the right question can really increase your odds of getting an answer. Also, this is a possibility because there is no rule that you will get answers to all your questions. People may want to spare their precious time to help you, or they may easily choose not to help you for hundreds of reasons, such as a small word mistake in your question, your reactions to previous answers, your contribution to the community, or even for no reason.&lt;/p&gt;

&lt;p&gt;No matter what level of knowledge you have, you will ask questions of others. As your experience in software increases, you will witness a serious change in two things.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The depth and quality of the questions you ask will increase.&lt;/li&gt;
&lt;li&gt;You will ask fewer questions and have the ability to find answers yourself faster.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The questions of someone who has not yet started the software are usually as follows;&lt;/p&gt;

&lt;p&gt;Where should I start? Which language should I learn? Can I find a job? I went to school, can I find a job? Which language can I find a job faster if I learn? Which language should I start with? I learned X language, what should I do now? Can I learn by myself? Which course should I go to?&lt;/p&gt;

&lt;p&gt;The most important skill you need to acquire and develop before asking questions is the ability to research. All of these questions you see above have been asked millions of times and answered millions of times. Before you wait for someone to take the time to answer your question, don't stop, take time for yourself and see if your question really has an answer. Especially if you are planning to enter the sector or if you have just learned the software, that bright question that comes to your mind is very big, but most likely, thousands of people have thought of it before and I am sure it has been answered. So use Google and search.&lt;/p&gt;

&lt;p&gt;If you start to develop your research skills from the very first levels, you will find that you are very comfortable as an experienced software developer. Use the internet and rip the information out of her heart!&lt;/p&gt;

&lt;p&gt;After showing some professional progress, your questions focus more on technical issues. Most of the technical questions are also probably already answered. However, you may not be able to find the answer because it does not fit with your current scenario. As time progresses, you will easily find how a similar technical question has been answered regardless of your scenario, but it may be difficult to achieve at first. Because you don't have the experience to visualize how many different scenarios a technical application or piece of code can work in yet.&lt;/p&gt;

&lt;p&gt;Then you will ask questions, but where? How? to who?&lt;/p&gt;

&lt;p&gt;There are software groups on social media, whatsapp or telegram groups, discord channels, and many channels where you can get help with software. Search, find and join these groups related to your language or technology.&lt;/p&gt;

&lt;p&gt;You've joined these groups, but don't see the people here as people who dedicate all their time to helping you and others like you, eagerly waiting in line to answer your questions. Everyone is there to help each other and get help when needed someday. Having to learn new things all the time is a must for software and we software developers love to be wherever we can learn new things.&lt;/p&gt;

&lt;p&gt;So I want to remind you again, SEARCH before asking a question. Read the documents, see other answers, go through local and foreign sources. I'll recommend a very simple pattern so you can ask your question when you're sure you won't be able to find it through research.&lt;/p&gt;

&lt;p&gt;But first, let me convince you why you need this pattern. Before asking a question, you should try to foresee the size of the area covered by that question. For example;&lt;/p&gt;

&lt;p&gt;“I want to design a user login system, how do I do it? Can you help me?"&lt;/p&gt;

&lt;p&gt;If this question is not a job offer, that is, I want to have a user login system in my project, I am open to your offers, bravo, you asked your first bad question. The scope of your question is so great at first glance; What language, what kind of architecture? Are you designing an API? Is this a service? What do you mean by login? Token? what? Lots and lots of questions. So you askedThe long question gave rise to huge questions. Answering these questions is not something that will happen right away. People will either make fun of you, say a few annoying things, or post an instructional video as broad as the question you ask.&lt;/p&gt;

&lt;p&gt;The question you will ask should not be one that you can find the answer to with your education and research. No one can give you a huge education there. It cannot discover what the structure you want to build is and design an answer accordingly. So first make sure your question has a small scope and can be answered right there.&lt;/p&gt;

&lt;p&gt;You have determined the scope of your question, but you are still far from asking it correctly.&lt;/p&gt;

&lt;p&gt;“I want to post X information, but my Y function is not working, what can I do?”&lt;/p&gt;

&lt;p&gt;I don't know? X information Y function, what does it do, what did you write, what is this program? I don't know what you intend to do...&lt;/p&gt;

&lt;p&gt;While people are asking questions, they may fall into the misconception that they know the content of the code, so others can understand it. No matter how experienced he is, no one can give an answer to a structure whose contents he does not know.&lt;/p&gt;

&lt;p&gt;Here, I will share a simple pattern with you to avoid this mistake. This pattern is the first thing I teach my students when they ask me questions. If you ask your questions through this pattern, your probability of getting an answer increases.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;What Do You Want To Do?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What did you do?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What happened?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What did you expect to happen?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's the perfect template for you to place your question in and divide it into. Before you ask your question, if you answer these questions, fill them in, and paste examples from the codes you have written, there is almost no chance that you will not get an answer to that question. Now let's fit the above question into this pattern.&lt;/p&gt;

&lt;p&gt;What I want to do: I want to send the X information from the form filled by the user to another service via Post.&lt;br&gt;
What I did: I wrote a method called Y for this and as you can see below, I think it looks right.&lt;br&gt;
What happened: the information does not go, I guess the method does not work… XX error appears on the console.&lt;br&gt;
What did you expect to happen: The information from the X form should have been sent to the service I wanted via this method when the submit button was pressed.&lt;br&gt;
The question has become much clearer. In fact, the answer to this imaginary question has started to form in my head, I think you wrote a method, but it seems like you forgot to trigger it somewhere.&lt;/p&gt;

&lt;p&gt;What inexperience! While I pride myself on answering the question you asked in my own fantasy world, I say you should read the following guide.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.catb.org/~esr/faqs/smart-questions.html"&gt;http://www.catb.org/~esr/faqs/smart-questions.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Asking the right question is the key to getting the right answer…&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>programming</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
