<?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: Hossam Assadallah</title>
    <description>The latest articles on DEV Community by Hossam Assadallah (@hossam_assadallah_842151a).</description>
    <link>https://dev.to/hossam_assadallah_842151a</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4122391%2Fc124246e-8782-4686-9e5a-f06143cca7f7.jpeg</url>
      <title>DEV Community: Hossam Assadallah</title>
      <link>https://dev.to/hossam_assadallah_842151a</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hossam_assadallah_842151a"/>
    <language>en</language>
    <item>
      <title>MAX()+1: The Invoice Number That Showed Up Twice</title>
      <dc:creator>Hossam Assadallah</dc:creator>
      <pubDate>Sat, 03 Oct 2026 12:48:22 +0000</pubDate>
      <link>https://dev.to/hossam_assadallah_842151a/max1-the-invoice-number-that-showed-up-twice-3lb1</link>
      <guid>https://dev.to/hossam_assadallah_842151a/max1-the-invoice-number-that-showed-up-twice-3lb1</guid>
      <description>&lt;p&gt;3 Oct 2026 · &lt;a class="mentioned-user" href="https://dev.to/hossam"&gt;@hossam&lt;/a&gt; Assadallah&lt;br&gt;
Two invoices, one number&lt;br&gt;
Friday, 2 PM, and the restaurant is packed. Two cashiers hit "Save" at almost the same moment. Both get invoice number 10452.&lt;br&gt;
At month end, the accountant finds the duplicate. One of the two invoices drops out of the report; the other stays. The money gets counted once instead of twice.&lt;br&gt;
The system had run for years without a problem. The bug wasn't new. It was one line written on day one.&lt;br&gt;
The suspect&lt;br&gt;
Most of us have written this, or inherited it in someone else's code:&lt;br&gt;
SELECT NVL(MAX(invoice_no), 0) + 1&lt;br&gt;
  INTO v_new_no&lt;br&gt;
  FROM invoices;&lt;/p&gt;

&lt;p&gt;INSERT INTO invoices (invoice_no, ...)&lt;br&gt;
VALUES (v_new_no, ...);&lt;br&gt;
It looks perfectly reasonable: take the highest number and add one. With one user on one machine, it will work forever. It only breaks when several people write at once, which is exactly when the system matters most.&lt;br&gt;
What actually happened&lt;br&gt;
Oracle gives every session a consistent view of the data (read consistency). A session can't see rows another session inserted but hasn't committed yet.&lt;br&gt;
Time&lt;br&gt;
Cashier 1&lt;br&gt;
Cashier 2&lt;br&gt;
14:00:00.100&lt;br&gt;
MAX = 10451 → computes 10452&lt;/p&gt;

&lt;p&gt;14:00:00.120&lt;/p&gt;

&lt;p&gt;MAX = 10451 → computes 10452&lt;br&gt;
14:00:00.150&lt;br&gt;
INSERT 10452&lt;/p&gt;

&lt;p&gt;14:00:00.170&lt;/p&gt;

&lt;p&gt;INSERT 10452&lt;br&gt;
14:00:00.200&lt;br&gt;
COMMIT&lt;br&gt;
COMMIT&lt;br&gt;
Both sessions read the same truth at the same moment, and both were right from where they stood. The flaw is that "read, then write" is two separate steps, and anything can happen in the gap between them.&lt;br&gt;
The more users you add, the more often that gap gets hit.&lt;br&gt;
The usual patches&lt;br&gt;
When the bug surfaces, the first reaction is usually one of these:&lt;br&gt;
• A unique constraint on the column. It stops the duplicate, but the second cashier gets ORA-00001 in front of the customer. You turned a silent bug into a loud one; you didn't fix it.&lt;br&gt;
• Retry on error. It can work, but under load you get sessions looping and colliding again.&lt;br&gt;
• LOCK TABLE, or SELECT ... FOR UPDATE on a counter row. This does prevent duplicates, by making every session wait in line. The whole system now issues one invoice at a time, and the lock is held until the entire transaction finishes, not just until the number is computed.&lt;br&gt;
On top of that, MAX on a table with millions of rows costs an index read on every invoice, and sometimes a full scan if you filter by branch or year.&lt;br&gt;
Sequences: a counter that waits for no one&lt;br&gt;
CREATE SEQUENCE invoice_seq&lt;br&gt;
  START WITH 10453&lt;br&gt;
  CACHE 50;&lt;/p&gt;

&lt;p&gt;INSERT INTO invoices (invoice_no, ...)&lt;br&gt;
VALUES (invoice_seq.NEXTVAL, ...);&lt;br&gt;
The key difference: a sequence lives outside the transaction. NEXTVAL hands you a number and moves on immediately. It doesn't read the table and doesn't wait for anyone's commit.&lt;br&gt;
• No duplicates: every session gets a number no one has taken, regardless of how many sessions there are.&lt;br&gt;
• No queue: a thousand cashiers can pull numbers at the same instant.&lt;br&gt;
• No table reads: with CACHE, numbers are reserved in memory, so most calls never touch disk.&lt;br&gt;
One expression instead of a SELECT, a MAX and a lock, and it's faster and safer than both.&lt;br&gt;
"But sequences leave gaps"&lt;br&gt;
True. A ROLLBACK, or an instance restart that drops the cache, and you'll see missing numbers: 10452, then 10455.&lt;br&gt;
That isn't a defect. It's the price of having no queue. A number once handed out never comes back, because taking it back would mean one session waiting on another to decide.&lt;br&gt;
The real question is whether gaps actually matter to you:&lt;br&gt;
• If the number is an internal key (an ID), nobody cares about gaps. Use a sequence and move on.&lt;br&gt;
• If there's a legal or accounting requirement for gapless numbering, separate the two. Keep the ID from a sequence, and generate the customer-facing serial number only at final posting, from a counter table with FOR UPDATE. The queue now sits on one small step at the end, not on the whole sale.&lt;br&gt;
From 12c on: let the table handle it&lt;br&gt;
On Oracle 12c or later, you don't need to wire up a sequence and a trigger yourself:&lt;br&gt;
CREATE TABLE invoices (&lt;br&gt;
  invoice_id NUMBER GENERATED ALWAYS AS IDENTITY,&lt;br&gt;
  ...&lt;br&gt;
);&lt;br&gt;
Under the hood it's a regular sequence, but bound to the column, so no one can insert a manual value by mistake. If you need to supply values during a migration, use BY DEFAULT ON NULL instead of ALWAYS.&lt;br&gt;
The takeaway&lt;br&gt;
MAX()+1 assumes you're alone in the database. A system that makes money is never alone.&lt;br&gt;
A sequence isn't "another way" to do the same thing. It's a tool built for exactly this problem: unique numbers, no queue, no table reads. The gaps it leaves cost far less than two invoices with the same number.&lt;br&gt;
Have you found MAX()+1 in code you inherited? Did it bite you, or is it still waiting?&lt;/p&gt;

&lt;h1&gt;
  
  
  Oracle #PLSQL #Database #SQL
&lt;/h1&gt;

</description>
      <category>backend</category>
      <category>database</category>
      <category>programming</category>
      <category>sql</category>
    </item>
    <item>
      <title># The Suspiciously Round Number That Stopped Me Cold</title>
      <dc:creator>Hossam Assadallah</dc:creator>
      <pubDate>Sun, 13 Sep 2026 23:25:05 +0000</pubDate>
      <link>https://dev.to/hossam_assadallah_842151a/-the-suspiciously-round-number-that-stopped-me-cold-2n6e</link>
      <guid>https://dev.to/hossam_assadallah_842151a/-the-suspiciously-round-number-that-stopped-me-cold-2n6e</guid>
      <description>&lt;p&gt;I was pulling data from SAP through an OData API — every Internal Order from 2020 to today. The response came back with exactly 1000 rows. Not 987, not 1214. A clean, round 1000.&lt;/p&gt;

&lt;p&gt;Was I happy? No. I got suspicious.&lt;/p&gt;

&lt;p&gt;In data work, a number that "too perfect" is usually a lie. Real data comes back messy — fractions, odd totals, nothing that lines up so neatly. That 1000 wasn't telling me "here's your data." It was telling me "this is a ceiling."&lt;/p&gt;

&lt;p&gt;I tried the standard fix: paginate using OData's own &lt;code&gt;$skip&lt;/code&gt; and &lt;code&gt;$top&lt;/code&gt; parameters. SAP's gateway ignored both completely and kept returning the exact same first 1000 rows, as if the parameters didn't exist. There was no &lt;code&gt;__next&lt;/code&gt; link in the response either — nothing pointing to a next page.&lt;/p&gt;

&lt;p&gt;So I tried a different check. I ran &lt;code&gt;$count&lt;/code&gt; (a request that returns just the row count, no data) over the same date range — and got 1000 again. Even the count itself was capped by the same limit. I split the range in half and ran &lt;code&gt;$count&lt;/code&gt; on each half separately: 938 on the first half, 651 on the second. Real total: 1589. Not 1000.&lt;/p&gt;

&lt;p&gt;589 rows would have quietly disappeared, and nobody would have known — if I hadn't been suspicious of a number that looked too clean.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The lesson:&lt;/strong&gt; any time an API can return a lot of data, assume it's silently capped until you prove otherwise. A round number isn't a sign of success — it's the first flag that something needs verification. And trusting the standard protocol alone isn't enough: here, SAP's own gateway simply didn't honor OData's standard pagination mechanism. The fix is building independent verification — like splitting time windows and cross-checking partial counts — before you trust any number an API hands you.&lt;/p&gt;

&lt;p&gt;Have you run into this? An API silently truncating your data without telling you?&lt;/p&gt;

&lt;h1&gt;
  
  
  SAP #OData #DataEngineering #NodeJS #OracleAPEX #SoftwareEngineering #API
&lt;/h1&gt;

</description>
      <category>hossamassadallah</category>
      <category>oracle</category>
      <category>node</category>
      <category>fastapi</category>
    </item>
    <item>
      <title>"Boredom Isn't the Enemy of Creativity — Knowing When to Stop Is the Skill</title>
      <dc:creator>Hossam Assadallah</dc:creator>
      <pubDate>Sun, 13 Sep 2026 03:26:46 +0000</pubDate>
      <link>https://dev.to/hossam_assadallah_842151a/boredom-isnt-the-enemy-of-creativity-knowing-when-to-stop-is-the-skill-5co</link>
      <guid>https://dev.to/hossam_assadallah_842151a/boredom-isnt-the-enemy-of-creativity-knowing-when-to-stop-is-the-skill-5co</guid>
      <description>&lt;p&gt;The second English piece from "Psychology of the Keyboard," a series I write about the mental side of being a programmer — the part nobody puts in the documentation.&lt;br&gt;
I was standing at the sink, mid-wudu — not in front of a laptop, no editor open, not a single line of code in front of me — and the solution just jumped into my head. I'd been stuck on a bug for two days: an integration issue between FastAPI and Oracle. I'd tried everything — changed the query, dug through the documentation, asked everyone I could think of. Nothing. Then, while washing my hands, with zero warning, I suddenly understood: the problem wasn't in the code at all. The connection pool wasn't closing properly before it reopened. Something embarrassingly simple — but my mind couldn't see it while I was sitting there forcing focus.&lt;br&gt;
That's not a coincidence. In cognitive psychology it's called the Default Mode Network — the part of your brain that activates when you're not demanding conscious focus from it: washing dishes, walking, showering. In those moments, your brain isn't off. It keeps working quietly in the background, connecting pieces of information that were scattered while you were focused, which is exactly what produces that "sudden" solution.&lt;br&gt;
The problem is that we're trained, as programmers, to believe the answer comes from pressure — the harder you focus, the faster you'll find it. That's true, up to a point. Past that point, it works in reverse. When your brain sits on the same problem for two hours straight, it drops into a narrow tunnel of focus that shuts out every other possibility, and just keeps circling the same idea that already failed.&lt;br&gt;
Boredom isn't the enemy of creativity. Boredom is the door that opens that space — when you let yourself get distracted for a bit, without a phone, without a screen, not to be lazy, but to give your brain the chance to work in a completely different mode than the one you're used to at your desk.&lt;br&gt;
Take this as a rule, not a luxury: when you're stuck in front of a problem and can't move a single step forward, step away. Not just to rest your body — to give the other half of your mind room to work.&lt;br&gt;
Has a coding solution ever come to you while you were nowhere near a computer? Tell me where, and when.&lt;/p&gt;

</description>
      <category>hossamassadallah</category>
      <category>oracle</category>
      <category>career</category>
      <category>mentalhealth</category>
    </item>
    <item>
      <title>The 3 A.M. Moment Every Programmer Lies to Themselves About</title>
      <dc:creator>Hossam Assadallah</dc:creator>
      <pubDate>Sat, 12 Sep 2026 20:27:28 +0000</pubDate>
      <link>https://dev.to/hossam_assadallah_842151a/the-3-am-moment-every-programmer-lies-to-themselves-about-2e3f</link>
      <guid>https://dev.to/hossam_assadallah_842151a/the-3-am-moment-every-programmer-lies-to-themselves-about-2e3f</guid>
      <description>&lt;p&gt;The second English piece from "Psychology of the Keyboard," a series I write about the mental side of being a programmer — the part nobody puts in the documentation.&lt;/p&gt;

&lt;p&gt;It was around three in the morning. I'd been in front of the screen since nine at night, staring at the same line of code for what felt like the hundredth time. The function looked perfect on paper — no visible issue — but the result kept coming out wrong. I tried everything I could think of: changed the condition, dug through Stack Overflow, asked an AI. Nothing changed.&lt;/p&gt;

&lt;p&gt;I still remember exactly what I felt in that moment. It wasn't physical tiredness. It was something else entirely — a feeling that I wasn't good enough, that maybe the problem was in my own head, not in the code. That if my colleagues saw me stuck like this, they'd assume I was a beginner, not someone running a company that builds systems handling real data.&lt;/p&gt;

&lt;p&gt;That's the thing almost nobody talks about in programming. We talk about algorithms, best practices, the newest framework — but nobody tells you this profession takes as much from your mental health as it does from your time.&lt;/p&gt;

&lt;p&gt;In that moment of being stuck, something happens in your brain called tunnel vision. Your mind locks onto the same path you already tried and failed on, and keeps pulling you back to it — not because the answer is there, but because a tired brain finds it easier to repeat the same move than to open a new path. The dangerous part of that moment isn't failing. It's staying seated, convinced that continuing in the same direction is the answer — which is exactly what turns one exhausting hour into two or three wasted ones.&lt;/p&gt;

&lt;p&gt;The fix isn't to be "strong" and push through. The fix is giving yourself real space away from the screen — even five minutes. Walk. Drink water. Look at something completely different. The mind isn't a machine; it needs to reorganize itself. And when you come back, you'll often find your eyes suddenly see something that had been sitting in front of you for two hours, unseen.&lt;/p&gt;

&lt;p&gt;One more thing worth saying clearly: your value as a programmer isn't in solving everything fast. It's in continuing even when a lot of things don't get solved on the first try. Every professional programmer has been through the exact moment I just described. The difference is learning when to stop and when to keep going — not that they stopped getting lost altogether.&lt;/p&gt;

&lt;p&gt;Have you had a moment like this? What actually helps you find your focus again?&lt;/p&gt;

</description>
      <category>hossamassadallah</category>
      <category>oracle</category>
      <category>programming</category>
      <category>gooshylx</category>
    </item>
    <item>
      <title>What Training an AI Agent Taught Me About Letting Go of Control</title>
      <dc:creator>Hossam Assadallah</dc:creator>
      <pubDate>Sat, 12 Sep 2026 18:25:21 +0000</pubDate>
      <link>https://dev.to/hossam_assadallah_842151a/what-training-an-ai-agent-taught-me-about-letting-go-of-control-40an</link>
      <guid>https://dev.to/hossam_assadallah_842151a/what-training-an-ai-agent-taught-me-about-letting-go-of-control-40an</guid>
      <description>&lt;p&gt;his is the first English piece from "Psychology of the Keyboard," a series I write about the mental side of being a programmer — the part nobody puts in the documentation.&lt;/p&gt;

&lt;p&gt;I was training the AI agent behind Amin, the product I've been building, and I had the exact reply mapped out in my head for every question it should get. I wrote the prompt, reviewed it, tuned it, ran the test. The reply came back — not wrong, exactly, just not phrased the way I'd already decided it should be. I went back, adjusted, tried again. A third reply came out, different from the first two. And I felt something strange. Not frustration at the model's performance — a feeling that I was losing control over something I had built from scratch.&lt;/p&gt;

&lt;p&gt;I paused the training. Not because the model was wrong, but because I couldn't tolerate a system I'd built with my own hands producing responses I didn't control 100%. That made me think — this wasn't the first time I'd felt this. It shows up in everything I build, from the database layer to the UI: I want every detail under my control, completely.&lt;/p&gt;

&lt;p&gt;And that instinct makes perfect sense in our profession. We're trained to believe that one point outside our control can break the whole system, so we've been conditioned to treat total control as the only real safety. The problem is that mindset doesn't stay inside the code. It follows you out. You catch yourself wanting to control an employee's reaction, a client's decision, even your own kid's mood mid-conversation — because your brain has learned that "no full control means danger."&lt;/p&gt;

&lt;p&gt;But an agent, like any AI system, is built on probability, not fixed rules. It's not supposed to give you the exact same wording every time — that's not a flaw, that's its nature. The real lesson wasn't figuring out how to make the output 100% consistent. The lesson was learning to separate "controlling the general direction" from "controlling every word." I needed to tune the framework and the rules, not micromanage every small detail inside it.&lt;/p&gt;

&lt;p&gt;Once I let the agent take up more space inside the framework I'd set, the responses got more natural and closer to each customer's actual tone — not because I'd gotten less precise, but because I'd gotten confident that the framework itself was enough.&lt;/p&gt;

&lt;p&gt;Have you ever caught yourself trying to control something that was never meant to be fully controlled, at work or outside it? How did you know it was time to let go?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
