<?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: Georgios Moustakas</title>
    <description>The latest articles on DEV Community by Georgios Moustakas (@gmoustakas).</description>
    <link>https://dev.to/gmoustakas</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%2F92253%2F6887267d-0547-4884-920b-256ced03a00b.png</url>
      <title>DEV Community: Georgios Moustakas</title>
      <link>https://dev.to/gmoustakas</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gmoustakas"/>
    <language>en</language>
    <item>
      <title>The networking problem behind every "random" backend outage.</title>
      <dc:creator>Georgios Moustakas</dc:creator>
      <pubDate>Sat, 13 Jun 2026 13:21:07 +0000</pubDate>
      <link>https://dev.to/gmoustakas/the-networking-problem-behind-every-random-backend-outage-ei3</link>
      <guid>https://dev.to/gmoustakas/the-networking-problem-behind-every-random-backend-outage-ei3</guid>
      <description>&lt;p&gt;You get paged at 2am. The service is down. You check the app — no deploys, no config changes, nothing. You restart the container and it comes back. You go to sleep. It happens again Thursday.&lt;/p&gt;

&lt;p&gt;It was never the app.&lt;/p&gt;

&lt;p&gt;I spent three years doing satellite internet support before I moved into backend engineering. That job taught me one thing: most "application" problems are network problems wearing a disguise. I see the same patterns now in backend systems that I saw then in rural broadband infrastructure.&lt;/p&gt;

&lt;p&gt;Here are the ones that get teams every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The timeout that isn't a timeout
&lt;/h2&gt;

&lt;p&gt;Your service calls a third-party API. It times out. You log it, you retry, life goes on. But the retries pile up. Each retry holds a connection open. Your connection pool fills. New requests start queuing. The queue backs up. Now your service looks down — but the third-party API recovered ten seconds ago.&lt;/p&gt;

&lt;p&gt;The fix is not a shorter timeout. The fix is a circuit breaker. Don't retry into a wall. Detect the wall and stop knocking.&lt;/p&gt;

&lt;h2&gt;
  
  
  DNS TTL lying to you in production
&lt;/h2&gt;

&lt;p&gt;You rotate a database host. You update the DNS record. You wait for TTL to expire — 300 seconds, fine. But your app has been running for six hours and the old IP is baked into the JVM DNS cache, or your connection pool, or a library that ignores TTL entirely.&lt;/p&gt;

&lt;p&gt;The new host is up. The app is still talking to the old one. The old one is gone. Outage.&lt;/p&gt;

&lt;p&gt;Always set TTL aggressively low before a planned DNS change. And test your app's actual DNS resolution behaviour, not just the record.&lt;/p&gt;

&lt;h2&gt;
  
  
  The packet that never comes back
&lt;/h2&gt;

&lt;p&gt;TCP connections are stateful. A NAT device, a load balancer, a firewall — they all keep track of active connections. Leave a connection idle long enough and that state entry gets evicted. The next packet on that connection goes nowhere. Your app is still waiting for a response that will never arrive.&lt;/p&gt;

&lt;p&gt;This is the silent killer of database connection pools. The DB is fine. The network path is fine. But the connection your pool thinks is open has been silently dropped by a load balancer that forgot it existed.&lt;/p&gt;

&lt;p&gt;Keepalives exist for this reason. Use them. Set &lt;code&gt;tcp_keepalive_time&lt;/code&gt; lower than your NAT timeout. Most default settings are wrong for production.&lt;/p&gt;

&lt;h2&gt;
  
  
  MTU mismatch on the path nobody checks
&lt;/h2&gt;

&lt;p&gt;A packet leaves your server at 1500 bytes. Somewhere between you and the destination, a link has an MTU of 1400. The packet needs to be fragmented. If the DF (don't fragment) bit is set and ICMP is blocked — which it often is — the packet is silently dropped. The connection hangs. Nothing in your application logs explains why.&lt;/p&gt;

&lt;p&gt;I saw this constantly in satellite networks where overhead compression changed effective MTU. I still see it in cloud environments where overlay networks, VPNs, and tunnel encapsulation all shave bytes off the path.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;tracepath&lt;/code&gt; instead of &lt;code&gt;traceroute&lt;/code&gt;. Check PMTUD. If you're running on Kubernetes with Flannel or Calico, know what your overlay MTU actually is.&lt;/p&gt;

&lt;h2&gt;
  
  
  The retry storm
&lt;/h2&gt;

&lt;p&gt;Your upstream is slow. Your service retries. Every service instance retries at the same time because they all hit the same timeout window. Your upstream — which was recovering — now gets hit with 10x normal traffic. It goes down again.&lt;/p&gt;

&lt;p&gt;Add jitter to your retries. Exponential backoff without jitter is a coordinated attack on your own infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters more now
&lt;/h2&gt;

&lt;p&gt;More surface area means more network paths. Microservices, managed databases, external APIs, LLM providers — each hop is a place for the network to betray you. The app is often the last thing to blame.&lt;/p&gt;

&lt;p&gt;When something breaks randomly and the restart fixes it, start at the network. Check connection pool state, check DNS, check keepalive settings. The answer is usually there.&lt;/p&gt;

&lt;p&gt;The app was fine the whole time.&lt;/p&gt;

</description>
      <category>networking</category>
      <category>backend</category>
      <category>python</category>
      <category>devops</category>
    </item>
    <item>
      <title>Stop vibe coding. Start using AI with intent.</title>
      <dc:creator>Georgios Moustakas</dc:creator>
      <pubDate>Sat, 13 Jun 2026 11:27:01 +0000</pubDate>
      <link>https://dev.to/gmoustakas/stop-vibe-coding-start-using-ai-with-intent-3km3</link>
      <guid>https://dev.to/gmoustakas/stop-vibe-coding-start-using-ai-with-intent-3km3</guid>
      <description>&lt;p&gt;Everyone is vibe coding. Prompting an AI, accepting whatever comes out, shipping it. It works until it doesn't, and when it doesn't, nobody knows why.&lt;/p&gt;

&lt;p&gt;I use Claude Code every day. Across planning, implementation, and review. But the way I use it looks nothing like what gets posted on Twitter.&lt;/p&gt;

&lt;h2&gt;
  
  
  The vibe coding trap
&lt;/h2&gt;

&lt;p&gt;Vibe coding assumes the model knows what you want. It doesn't. It knows what you typed. If you type vague things, you get vague code that passes a surface-level read and breaks on the third edge case.&lt;/p&gt;

&lt;p&gt;The output is only as good as the intent behind the prompt. That's not a model problem. That's a thinking problem.&lt;/p&gt;

&lt;p&gt;I have watched engineers prompt their way into a working demo in 20 minutes and spend two days debugging production because the model made a reasonable-looking decision that was wrong for their specific data shape. The model was not wrong in any general sense. It was wrong for that context, and nobody checked.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "with intent" actually means
&lt;/h2&gt;

&lt;p&gt;Before I write a single prompt, I know three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What this piece of code is supposed to do&lt;/li&gt;
&lt;li&gt;What it must not do&lt;/li&gt;
&lt;li&gt;How I will verify it works&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That sounds obvious. Most people skip steps two and three entirely.&lt;/p&gt;

&lt;p&gt;Step two is where security holes live. It is where the off-by-one errors live. It is where "handle the error case" gets interpreted as "swallow the exception and return None." The model will do something reasonable. Reasonable is not always correct.&lt;/p&gt;

&lt;p&gt;Step three is where you find out if you actually understood the problem before you started prompting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I hand it the wheel and where I don't
&lt;/h2&gt;

&lt;p&gt;I use Claude Code to move fast on the parts where speed is the point: boilerplate, repetitive transforms, first drafts of tests, scaffolding a new route that follows an existing pattern. These are low-risk, high-repetition tasks. The model is faster than I am and the output is easy to verify.&lt;/p&gt;

&lt;p&gt;I slow down and take over on the parts where judgment matters: data modeling, failure modes, anything that touches auth or external APIs, anything where "plausible" and "correct" are different things.&lt;/p&gt;

&lt;p&gt;The model is a force multiplier. Force multipliers amplify what you bring. If you bring nothing, you get nothing, faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  The review step nobody does
&lt;/h2&gt;

&lt;p&gt;After Claude Code writes something, I read it. Not skim it. Read it line by line. I treat it like code from a junior engineer who is very confident and occasionally wrong in ways that are hard to spot.&lt;/p&gt;

&lt;p&gt;I evaluate AI models professionally at Datawise. We run structured benchmarks across dozens of tasks. One thing I have learned from that work: these models are very good at producing output that looks right. Looking right and being right are not the same thing. The gap between them is where bugs live.&lt;/p&gt;

&lt;p&gt;Reading the output is not optional. It is the job.&lt;/p&gt;

&lt;h2&gt;
  
  
  The prompting discipline that actually matters
&lt;/h2&gt;

&lt;p&gt;Vague prompt: "write a function that processes user input"&lt;/p&gt;

&lt;p&gt;Specific prompt: "write a Python function that validates and sanitizes a username: ASCII only, 3 to 30 characters, no spaces, raise ValueError with a clear message on failure, no dependencies outside the standard library"&lt;/p&gt;

&lt;p&gt;The second prompt gets you something you can ship. The first gets you something you have to rewrite.&lt;/p&gt;

&lt;p&gt;The more specific your prompt, the less reviewing you have to do. That is the actual skill. Not knowing which AI tool to use. Not having the right subscription. Writing prompts that leave no room for interpretation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The actual workflow
&lt;/h2&gt;

&lt;p&gt;Plan in plain language first. Write out what you want and what you do not want before you open Claude Code. Let it draft. Read what comes back. Push back on anything clever. Verify against the original intent. Ship.&lt;/p&gt;

&lt;p&gt;That's it. No magic. Just using a powerful tool with the same discipline you'd bring to any other part of the stack.&lt;/p&gt;

&lt;p&gt;Vibe coding is a fine way to prototype. It is a bad way to build things that need to keep working.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>programming</category>
      <category>claudecode</category>
    </item>
    <item>
      <title>LLM API Tokens burning your Bank even on testing ? Not anymore, cuesheet is here to help with that.</title>
      <dc:creator>Georgios Moustakas</dc:creator>
      <pubDate>Wed, 27 May 2026 08:01:26 +0000</pubDate>
      <link>https://dev.to/gmoustakas/llm-api-tokens-burning-your-bank-even-on-testing-not-anymore-cuesheet-is-here-to-help-with-that-4pgc</link>
      <guid>https://dev.to/gmoustakas/llm-api-tokens-burning-your-bank-even-on-testing-not-anymore-cuesheet-is-here-to-help-with-that-4pgc</guid>
      <description>&lt;p&gt;Tests that called &lt;strong&gt;#Claude&lt;/strong&gt; in CI were quietly burning tokens and breaking on every other run.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;cuesheet&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One decorator around your test. The first run hits the real API and saves the response to a YAML file you commit to your repo. Every run &lt;br&gt;
after that replays from the file. Byte-identical, no network, no cost.&lt;/p&gt;

&lt;p&gt;It works with any Python SDK that sits on httpx, which is most of them in 2026. #Anthropic, #OpenAI, #Google Gemini, #Mistral AI, #DeepSeek AI, and more, Together. &lt;/p&gt;

&lt;p&gt;The pytest plugin auto-discovers cassettes in tests/cassettes/. Streaming responses get recorded as raw SSE chunks and replayed in order. API keys, JWTs, and emails are scrubbed before write so cassettes are safe to commit.&lt;/p&gt;

&lt;p&gt;There is a local web UI too. Dark + ochre, watches the filesystem, refreshes live as your tests record new conversations. Useful for code review and for the "what did the model actually say" moment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;v0.2.0 is out today.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/gmoustakas/cuesheet" rel="noopener noreferrer"&gt;https://github.com/gmoustakas/cuesheet&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Project Details:&lt;/strong&gt; &lt;a href="https://www.georgemou.gr/projects/cuesheet" rel="noopener noreferrer"&gt;https://www.georgemou.gr/projects/cuesheet&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Open source, MIT. If you have been writing LLM tests and quietly hating it, this might give you a few hours back.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>claude</category>
      <category>discuss</category>
    </item>
    <item>
      <title>🚀 Why Every Developer Should Think Like a Product Builder (Not Just a Coder)</title>
      <dc:creator>Georgios Moustakas</dc:creator>
      <pubDate>Thu, 21 Aug 2025 19:36:19 +0000</pubDate>
      <link>https://dev.to/gmoustakas/why-every-developer-should-think-like-a-product-builder-not-just-a-coder-17pl</link>
      <guid>https://dev.to/gmoustakas/why-every-developer-should-think-like-a-product-builder-not-just-a-coder-17pl</guid>
      <description>&lt;p&gt;Software development isn’t just about writing lines of code. It’s about solving real problems, making things that people actually use, and shaping the web in ways that impact millions. Too often, we focus only on frameworks, languages, and tools—but forget the bigger picture: &lt;strong&gt;we’re builders.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Trap: Chasing Tech Trends
&lt;/h2&gt;

&lt;p&gt;Every week, Twitter (sorry, X) lights up with debates:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;“Is React dead?”&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;“Is Rust the new C++?”&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;“Will AI replace developers?”&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Chasing every new technology can feel like running on a treadmill—you’re moving fast but going nowhere.  &lt;/p&gt;




&lt;h2&gt;
  
  
  The Shift: From Coder to Creator
&lt;/h2&gt;

&lt;p&gt;The best developers I’ve worked with didn’t just know syntax—they thought like product people. They asked:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Who is this feature for?&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Does this design make sense?&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Is this solving the actual problem?&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This mindset shift transforms your work from “just code” into something meaningful.  &lt;/p&gt;




&lt;h2&gt;
  
  
  Web Development Today: Building With Superpowers
&lt;/h2&gt;

&lt;p&gt;We’re living in a golden age of web development. With tools like &lt;strong&gt;Next.js&lt;/strong&gt;, &lt;strong&gt;Vite&lt;/strong&gt;, and &lt;strong&gt;TailwindCSS&lt;/strong&gt;, spinning up a slick, production-ready app is faster than ever.  &lt;/p&gt;

&lt;p&gt;But with great tools comes a responsibility: &lt;strong&gt;don’t just build cool stuff—build useful stuff.&lt;/strong&gt;  &lt;/p&gt;




&lt;h2&gt;
  
  
  The Human Side of Development
&lt;/h2&gt;

&lt;p&gt;At the end of the day, code is for people. Whether it’s an e-commerce checkout flow or a developer CLI, real users will interact with what you create. Thinking about their experience is what separates a “good developer” from a “great one.”  &lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Being a developer isn’t about being a “code monkey.” It’s about being a problem solver, a builder, a creator. If you approach every project with the mindset of &lt;em&gt;“how will this actually help someone?”&lt;/em&gt;—you’ll not only stand out as a developer, you’ll make work that matters.&lt;/p&gt;




&lt;p&gt;✍️ &lt;em&gt;If you liked this article, follow me for more thoughts on web development, software, and building products that matter.&lt;/em&gt;  &lt;/p&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>product</category>
    </item>
    <item>
      <title>Update on my PDF file manipulation Script</title>
      <dc:creator>Georgios Moustakas</dc:creator>
      <pubDate>Mon, 24 Feb 2020 13:43:58 +0000</pubDate>
      <link>https://dev.to/gmoustakas/update-on-my-pdf-file-manipulation-script-44el</link>
      <guid>https://dev.to/gmoustakas/update-on-my-pdf-file-manipulation-script-44el</guid>
      <description>&lt;p&gt;Hi again, in my previous post i had a problem on how to search a large PDF file for a keyword which can be found in multiple pages of the file and in some cases more than once in single page!&lt;/p&gt;

&lt;p&gt;I've used &lt;strong&gt;PyPDF2&lt;/strong&gt; to open a given PDF file, then extract the text page by page, search that text for the given keyword and then check in what page the keyword was found and how many times per page and finally split those pages from the original file and merge them all together to create my final file so it can be printed with the useful data and not with other non-useful data from the original file.&lt;/p&gt;

&lt;p&gt;All works fine with test/dummy data in &lt;strong&gt;English&lt;/strong&gt; Characters but the original file is in &lt;strong&gt;Greek&lt;/strong&gt; and the&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;PdfPageObj.extractText()&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
 function of &lt;strong&gt;PyPDF2&lt;/strong&gt; returns an empty string.&lt;/p&gt;

&lt;p&gt;So how would you approach this problem?&lt;br&gt;
Any Suggestions?&lt;/p&gt;

</description>
      <category>python</category>
      <category>help</category>
      <category>problem</category>
      <category>solution</category>
    </item>
    <item>
      <title>PDF file manipulation with python 3 (Problem)</title>
      <dc:creator>Georgios Moustakas</dc:creator>
      <pubDate>Sun, 23 Feb 2020 10:16:19 +0000</pubDate>
      <link>https://dev.to/gmoustakas/pdf-file-manipulation-with-python-3-problem-14l1</link>
      <guid>https://dev.to/gmoustakas/pdf-file-manipulation-with-python-3-problem-14l1</guid>
      <description>&lt;p&gt;Hi, I have a problem I would like help with, i'm working on a project/script with python 3 where I want to manipulate a large PDF file (50-60 plus pages long) where I would like to find a specific keyword in that file, this keyword is repeated multiple times in the file and each time this keyword is referring to a different data set, then save how many times the keyword was found, in what pages was found and then split those pages from the original file and then merge those pages together in a single file.&lt;/p&gt;

&lt;p&gt;I will use multithreading of course, because this script will run alongside other's in a small in-house server and it's already running quite a lot, other scripts.&lt;/p&gt;

&lt;p&gt;I found some things online but no luck in what my problem is, except some python libraries that is possible to do what i'm looking for, but i have no idea how i will found this keyword in the file, because the keyword isn't in the same page order in the files, it's different in every file!! &lt;/p&gt;

</description>
      <category>python</category>
      <category>help</category>
      <category>question</category>
    </item>
  </channel>
</rss>
