<?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>Forem: Bashar Hasan</title>
    <description>The latest articles on Forem by Bashar Hasan (@abstract-333).</description>
    <link>https://forem.com/abstract-333</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%2F1251017%2Fa99a5efb-c18d-4453-aa87-23e018dd9bee.png</url>
      <title>Forem: Bashar Hasan</title>
      <link>https://forem.com/abstract-333</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/abstract-333"/>
    <language>en</language>
    <item>
      <title>Vibe Coding: ″Feel pain. Accept pain.‶</title>
      <dc:creator>Bashar Hasan</dc:creator>
      <pubDate>Sat, 31 May 2025 13:28:00 +0000</pubDate>
      <link>https://forem.com/abstract-333/vibe-coding-feel-pain-accept-pain-19hp</link>
      <guid>https://forem.com/abstract-333/vibe-coding-feel-pain-accept-pain-19hp</guid>
      <description>&lt;h2&gt;
  
  
  Background:
&lt;/h2&gt;

&lt;p&gt;Honestly, I was skeptical about vibe coding. I only used LLMs to help with a small portion of the code — around 10%.&lt;/p&gt;

&lt;p&gt;Why?&lt;br&gt;
Because it doesn’t know the context.&lt;br&gt;
It’s great at building standard apps like calculators, e-commerce templates, or to-do lists… but that’s not what I needed.&lt;/p&gt;

&lt;p&gt;That’s not to say I didn’t use it. I did.&lt;br&gt;
I leaned on it to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;    Fix bugs&lt;/li&gt;
&lt;li&gt;    Write code for domains I haven’t faced before&lt;/li&gt;
&lt;li&gt;    Answer questions I was too lazy to Google&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But everything changed when I started building a &lt;strong&gt;Phoenician transliteration tool&lt;/strong&gt; — a website that converts Arabic and English text into the ancient Phoenician script.&lt;/p&gt;

&lt;p&gt;And I was doing this in &lt;strong&gt;ReactJS&lt;/strong&gt;... without ever really learning ReactJS.&lt;/p&gt;

&lt;p&gt;Sure, I had some experience with Flutter. But building a web app in Flutter felt off. React was calling.&lt;/p&gt;

&lt;h2&gt;
  
  
  It Worked at First Sight!
&lt;/h2&gt;

&lt;p&gt;I tested the idea using ChatGPT.&lt;br&gt;
First, I asked Gemini to help me craft a good prompt. I tweaked it a bit, then passed it to ChatGPT.&lt;/p&gt;

&lt;p&gt;To my surprise, within about two hours, I had a working, &lt;strong&gt;decent-looking website.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sure, I had to adjust some of the mapping logic — the GPT-generated code wasn’t perfect there — but still, it worked.&lt;br&gt;
The LLMs handled everything else surprisingly well, from code generation to debugging.&lt;br&gt;
Except for the core logic — as I mentioned earlier, that part still needed human intuition and &lt;strong&gt;correction&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the Problems Started
&lt;/h2&gt;

&lt;p&gt;Then came the part where I had to &lt;strong&gt;actually deploy the website&lt;/strong&gt; — and that’s when the real problems began.&lt;/p&gt;

&lt;p&gt;ChatGPT couldn’t even provide a full list of the libraries it used. I thought, “Okay, maybe Cursor can help me solve this.”&lt;br&gt;
But even Cursor couldn’t install all the necessary libraries correctly.&lt;/p&gt;

&lt;p&gt;Worse, I couldn’t even get the app to &lt;strong&gt;run locally&lt;/strong&gt; — only inside ChatGPT’s code canvas.&lt;br&gt;
Both Cursor and ChatGPT were using &lt;strong&gt;outdated methods&lt;/strong&gt; for starting React projects.&lt;/p&gt;

&lt;p&gt;After some digging, a few hallucinated commands from ChatGPT, and multiple retries, I finally got partial answers.&lt;br&gt;
Some libraries were revealed, but I had to manually go through component websites to figure out what was missing.&lt;/p&gt;

&lt;p&gt;For example, ChatGPT used &lt;strong&gt;shadcn/ui&lt;/strong&gt; components but never referenced or installed the package.&lt;/p&gt;

&lt;p&gt;Eventually, after several trial-and-error commands, I was able to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;    Start the app locally&lt;/li&gt;
&lt;li&gt;    Fix the missing pieces&lt;/li&gt;
&lt;li&gt;    And finally, deploy it on &lt;strong&gt;GitHub Pages&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  It’s Live… But Was It Worth It?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5zx5nb8qddeh3cgjb210.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5zx5nb8qddeh3cgjb210.png" alt="The Final Result" width="800" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the end, I managed to upload the site and get a fully working version online.&lt;br&gt;
Yes — I even added it to Google Search and made final tweaks without using any LLMs 😅.&lt;/p&gt;

&lt;p&gt;But here's the catch:&lt;br&gt;
The code was… &lt;strong&gt;messy&lt;/strong&gt;.&lt;br&gt;
Everything was mostly thrown into a single file, with different pieces mixed together. No structure, no maintainability.&lt;/p&gt;

&lt;p&gt;It took me around &lt;strong&gt;6–8 hours&lt;/strong&gt; to fully debug and deploy it.&lt;/p&gt;

&lt;p&gt;Can you imagine? The app was generated in &lt;strong&gt;2 hours&lt;/strong&gt;, but I spent &lt;strong&gt;4 times&lt;/strong&gt; that just trying to make it actually work.&lt;/p&gt;

&lt;p&gt;That’s when I realized something important:&lt;br&gt;
If I had invested just &lt;strong&gt;20 hours&lt;/strong&gt; learning React properly, I probably could’ve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;    Avoided a ton of debugging&lt;/li&gt;
&lt;li&gt;    Known which library versions to use&lt;/li&gt;
&lt;li&gt;    Used LLMs more like a &lt;strong&gt;Lego kit&lt;/strong&gt; — asking for small, focused pieces of code&lt;/li&gt;
&lt;li&gt;    And focused my energy on the &lt;strong&gt;core logic&lt;/strong&gt;, not fixing broken scaffolding&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;As many people say, &lt;strong&gt;AI and LLMs are skill multipliers&lt;/strong&gt;.&lt;br&gt;
If you bring nothing to the table — you’ll get nearly nothing back. (Just like me struggling with React 😅.)&lt;/p&gt;

&lt;p&gt;Sure, tools like &lt;strong&gt;&lt;em&gt;context7&lt;/em&gt;&lt;/strong&gt; promise to make LLMs (e.g., in Cursor) use the latest documentation versions.&lt;br&gt;
But I’ll write about that later. &lt;em&gt;(Spoiler: it doesn’t work as well as you'd hope.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Trying to build anything beyond a small tool using pure "vibe coding" — no architecture, no planning, just prompts — is &lt;strong&gt;painful&lt;/strong&gt;.&lt;br&gt;
The code complexity scales faster than exponential, and debugging becomes a nightmare.&lt;/p&gt;

&lt;p&gt;But if you treat LLMs like a Lego toolkit, everything changes.&lt;/p&gt;

&lt;p&gt;Take the time to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;    Design a solid architecture (yes, this might take hours!)&lt;/li&gt;
&lt;li&gt;    Write a few key functions yourself&lt;/li&gt;
&lt;li&gt;    Then use the LLM to generate small, self-contained parts that fit into your structure&lt;/li&gt;
&lt;li&gt;Handle the hard logic manually — around &lt;strong&gt;20–30%&lt;/strong&gt; of the code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't ask it to write large functions across multiple files — that’s where hallucinations begin.&lt;/p&gt;

&lt;p&gt;And yeah, stay tuned for my next article — where I’ll show a &lt;strong&gt;successful vibe coding case in FastAPI&lt;/strong&gt; (where I actually know what I’m doing 😄).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Hit the reaction that match how you feel — and follow me to explore more!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://abstract-333.github.io/phoenician-transliterator/" rel="noopener noreferrer"&gt;Phoenician Transliteration Tool&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/abstract-333/phoenician-transliterator" rel="noopener noreferrer"&gt;Source Code&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  You can also find me there :)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://github.com/abstract-333" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://medium.com/@abstract-333" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

</description>
      <category>vibecoding</category>
      <category>react</category>
      <category>cursor</category>
      <category>chatgpt</category>
    </item>
    <item>
      <title>How Does print() Work in Python?</title>
      <dc:creator>Bashar Hasan</dc:creator>
      <pubDate>Tue, 01 Apr 2025 21:30:12 +0000</pubDate>
      <link>https://forem.com/abstract-333/how-does-print-work-in-python-390m</link>
      <guid>https://forem.com/abstract-333/how-does-print-work-in-python-390m</guid>
      <description>&lt;h2&gt;
  
  
  Overview:
&lt;/h2&gt;

&lt;p&gt;Have you ever asked yourself how Python's print() function works?&lt;/p&gt;

&lt;p&gt;Yes, yes, how to use it. Everyone knows how, but figuring out the core elements will be interesting.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀Short Description:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🐍Python interpreter starts.&lt;/li&gt;
&lt;li&gt;Create buffer of type FileIO or BufferedWriter, &lt;em&gt;we will see later&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Create sys.stdout object:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sys.stdout = TextIOWrapper(buffer, encoding)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;TextIOWrapper works as a cover for FileIO or BufferedWriter and also includes encoding as an option ('utf-8', 'ASCII', etc).&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The print() calls sys.stdout.write.&lt;/li&gt;
&lt;li&gt;sys.stdout.write is calling its internal function written in C.&lt;/li&gt;
&lt;li&gt;C code call Syscall.&lt;/li&gt;
&lt;li&gt;Execution go down to the Kernel.&lt;/li&gt;
&lt;li&gt;Finally, drivers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🖨️Let's check out the print() definition:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwqjx3wdfl0i9jhakidjn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwqjx3wdfl0i9jhakidjn.png" alt="print_overloads" width="800" height="708"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The print() function has two overloads, which accept any number of values and only four named parameters: &lt;strong&gt;separator&lt;/strong&gt;, &lt;strong&gt;end&lt;/strong&gt;, &lt;strong&gt;file&lt;/strong&gt;, and &lt;strong&gt;flush&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;sep&lt;/strong&gt; parameter specifies how to join objects together.&lt;/p&gt;

&lt;p&gt;🔚&lt;strong&gt;end&lt;/strong&gt; controls what will be at the end of the print; by default, it is &lt;strong&gt;"\n"&lt;/strong&gt; (next line). &lt;/p&gt;

&lt;p&gt;📁&lt;strong&gt;file&lt;/strong&gt; prints the values to a stream, file, or to &lt;em&gt;sys.stdout&lt;/em&gt; by default, but as we mentioned above, the first overload accepts the parameter of type &lt;strong&gt;&lt;em&gt;SupportsWrite&lt;/em&gt;&lt;/strong&gt; only, and in the second overload, file has a type that supports both writing and flushing (&lt;em&gt;It supports writing and flushing with the write() and flush() methods&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Thus, flush cannot be true in the &lt;strong&gt;first overload&lt;/strong&gt;, in case that file may not have the method &lt;strong&gt;flush()&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are &lt;strong&gt;&lt;em&gt;sys.stdout&lt;/em&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;em&gt;sys.stderr&lt;/em&gt;&lt;/strong&gt;?:
&lt;/h2&gt;

&lt;p&gt;⚜️&lt;strong&gt;&lt;em&gt;sys.stdout&lt;/em&gt;&lt;/strong&gt;: standard output stream.&lt;/p&gt;

&lt;p&gt;❌&lt;strong&gt;&lt;em&gt;sys.stderr&lt;/em&gt;&lt;/strong&gt;: the standard error output stream.&lt;/p&gt;

&lt;p&gt;They are special Python objects of type &lt;strong&gt;TextIOWrapper&lt;/strong&gt;, and we can use them to print information directly through an alternative method instead of the built-in &lt;em&gt;print()&lt;/em&gt; function.&lt;/p&gt;

&lt;h2&gt;
  
  
  📃TextIOWrapper—First Layer:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F74yehhcgz1acbjxlegew.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F74yehhcgz1acbjxlegew.png" alt="PYTHONUNBUFFERED=0" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This class is the upper class of print levels, as we mention above, sys.stoud and sys.stderr are objects of TextIOWrapper class.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TextIOWrapper&lt;/strong&gt; can have either unbuffered(FileIO) or buffered IO (BufferedWriter) object, and it depends on the variable &lt;strong&gt;&lt;em&gt;PYTHONUNBUFFERED&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;hmm&lt;/em&gt;‼️, you've seen this variable before; it's used in Docker images, where it is set like  &lt;strong&gt;&lt;em&gt;PYTHONUNBUFFERED 1&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This instructs Python to run in UNBUFFERED mode, which is recommended when using Python inside a Docker container. The reason for this is that it does not allow Python to buffer outputs; instead, it prints output directly, avoiding some complications in the Docker image when running your Python application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbni33faf1crsous4br5p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbni33faf1crsous4br5p.png" alt="PYTHONUNBUFFERED=1" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Okay, when &lt;strong&gt;&lt;em&gt;PYTHONUNBUFFERED=0&lt;/em&gt;&lt;/strong&gt; the class &lt;strong&gt;&lt;em&gt;BufferedWriter&lt;/em&gt;&lt;/strong&gt; will be utilized, and when &lt;strong&gt;&lt;em&gt;PYTHONUNBUFFERED=1&lt;/em&gt;&lt;/strong&gt;, we will use &lt;strong&gt;&lt;em&gt;FileIO&lt;/em&gt;&lt;/strong&gt; directly without any buffers, which is unbuffered I/O.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Take in mind🚨: in most cases python uses buffered output as default, &lt;em&gt;PYTHONUNBUFFERED=0&lt;/em&gt; 😊&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Buffered Writer—Second Layer:
&lt;/h2&gt;

&lt;p&gt;This class stores many values until they reach the maximum value of the buffer, and then prints the output.&lt;br&gt;
&lt;em&gt;We use buffers because physical output inside OS is not a cheap operation.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It uses FileIO as inner layer, so BufferedWriter works as additional layer that let us store data and output them in chunks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsw49d94wxikz3g8as4rc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsw49d94wxikz3g8as4rc.png" alt="Buffered Writer Code" width="800" height="971"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🏗️Constructor:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;self.buffer_size&lt;/strong&gt;: If the buffer_size is not given, it defaults to &lt;em&gt;DEFAUTL_BUFFER_SIZE = 8 * 1024&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;_write_buff&lt;/strong&gt;: Store data in order to print it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;_write_lock&lt;/strong&gt;: We use Lock() in order to print the data in safe thread mode.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;raw&lt;/strong&gt;: is a write stream, type of FileIO. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ✍️write() method:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Using safe lock thread, we check whether our buffer is already full, in this case we flush the output (write to the output stream).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add output data to _write_buff and flush the _write_buff if it gets full.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Return length of added data (printed data or which will be printed).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⚡Flush methods:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;flush()&lt;/strong&gt;: just execute _flush_unlocked() method with thread lock.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;_flush_unlocked()&lt;/strong&gt;: while loop puts the _write_buff on the write stream, and delete the first n written bytes until the write buffer get empty.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FileIO—Last Layer:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv68bv1xucjn4itvjiksb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv68bv1xucjn4itvjiksb.png" alt="FileIO Code" width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🏗️Constructor:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File Descriptor&lt;/strong&gt;: named as &lt;em&gt;fd.&lt;br&gt;
_File descriptors in Python are identifiers that represents the open files in the os kernel and are kept in a table of files. Typically, they have non-negative values. Negative results denote an error or a "no value" condition. They support a variety of file-related operations. In general, descriptors are a special approach Python uses to maintain attributes.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ✍️write() method:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Write bytes b to file, return number written.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Only makes one system call, so not all of the data may be written. The number of bytes actually written is returned. In non-blocking mode, returns None if the write would block.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ⚡Flush method:
&lt;/h3&gt;

&lt;p&gt;Simply returns &lt;strong&gt;None&lt;/strong&gt;, because FileIO don't have buffer, and it writes inside the system directly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Hit the reaction that match how you feel — and follow me to explore more!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  References:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/sobolevn/the-best-python-course" rel="noopener noreferrer"&gt;Source&lt;/a&gt;&lt;br&gt;
&lt;a href="https://stackoverflow.com/questions/59812009/what-is-the-use-of-pythonunbuffered-in-docker-file" rel="noopener noreferrer"&gt;PYTHONUNBUFFERED&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.python.org/3/library/io.html#io.BufferedWriter" rel="noopener noreferrer"&gt;Buffered Writer&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.tutorialspoint.com/What-is-a-file-descriptor-used-in-Python" rel="noopener noreferrer"&gt;File Descriptor&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  You can also find me there :)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://github.com/abstract-333" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://medium.com/@abstract-333" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>computerscience</category>
      <category>software</category>
    </item>
    <item>
      <title>Best Practices for Storing and Securing Passwords: A Developer's Guide</title>
      <dc:creator>Bashar Hasan</dc:creator>
      <pubDate>Fri, 28 Feb 2025 18:59:57 +0000</pubDate>
      <link>https://forem.com/abstract-333/best-practices-for-storing-and-securing-passwords-a-developers-guide-ocm</link>
      <guid>https://forem.com/abstract-333/best-practices-for-storing-and-securing-passwords-a-developers-guide-ocm</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the digital age, safeguarding user passwords is crucial for protecting sensitive data. With the rise in data breaches, where passwords are exposed as plain text, attackers can exploit reused passwords to access multiple user accounts across different platforms. This compromises both user security and organizational integrity.&lt;/p&gt;

&lt;p&gt;One of the most effective ways to prevent such vulnerabilities is through hashing. However, it's not just about hashing passwords—it's about implementing a robust, secure hashing strategy. In this guide, we’ll dive deep into the best practices for password hashing, ensuring that even if your password database is compromised, user data remains secure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Obvious First Step: Hashing Passwords
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flu5rttn830s248igr8kh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flu5rttn830s248igr8kh.png" alt="hash" width="611" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hashing is the foundational security technique used to protect passwords. When done correctly, it ensures that even if hackers gain access to your hashed password database, they cannot easily reverse-engineer the hashes to recover the original passwords.&lt;/p&gt;

&lt;p&gt;While developers often consider simple hashing algorithms like MD5 or SHA-1, these are now considered outdated and insecure. Their vulnerabilities make them susceptible to modern attacks. Let’s dive into why simple hashing techniques aren’t enough and explore more secure alternatives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Problems with Simple Hashing Techniques
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Collision Vulnerability&lt;/strong&gt;&lt;br&gt;
Cryptographic hashing algorithms are designed to map variable-length inputs (like a password) into a fixed-length output. However, a collision occurs when two distinct inputs produce the same hash output. This vulnerability can be exploited by attackers to reverse-engineer passwords, particularly when using weak hashing functions. This scenario is analogous to the birthday paradox, where the likelihood of collisions increases as the input size grows in relation to the hash output length.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Brute-Force Attacks&lt;/strong&gt;&lt;br&gt;
While hashing improves security over plain text passwords, attackers can still use brute-force methods to guess the original password by attempting every possible combination. If the attacker has significant computational power, brute-force attacks become feasible, making it critical to slow down the hashing process to mitigate such threats.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Hash Tables&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmj1w7ejqnex8wqu7mqbe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmj1w7ejqnex8wqu7mqbe.png" alt="hash_tables" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hash tables are precomputed tables containing hashes of common passwords or strings. These allow attackers to bypass the time-consuming hashing process, quickly identifying matching hashes and dramatically reducing the time required to crack a password.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Rainbow Tables&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F14jlosugsqm1y3zqttaf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F14jlosugsqm1y3zqttaf.png" alt="rainbow_tables" width="536" height="303"&gt;&lt;/a&gt;&lt;br&gt;
Rainbow tables are advanced versions of hash tables, using precomputed chains of hashed values designed to reverse-engineer a hash back to its original string. Although static salts can reduce the effectiveness of rainbow table attacks, improper password storage practices can still leave your system vulnerable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solutions to Enhance Password Security
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Salt: The First Line of Defense&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F07lofojugi2g3agzia0c.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F07lofojugi2g3agzia0c.jpg" alt="salt" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To protect against hash tables and rainbow table attacks, salting is indispensable. A salt is a random string added to the password before it’s hashed. By doing so, even if two users have the same password, their resulting hashes will be different, as each password is combined with a unique salt. This process makes hash tables and rainbow tables ineffective since attackers would need to generate unique tables for each salt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Static Salts:&lt;/strong&gt; A static salt is a single random value generated once and used across all passwords. While it effectively prevents rainbow table attacks, a compromised salt could put all passwords at risk.&lt;br&gt;
&lt;strong&gt;Dynamic Salts:&lt;/strong&gt; Dynamic salts are unique for each password, created at the time of password generation. This adds another layer of security by ensuring that even if an attacker compromises one salt, they cannot use it to crack other passwords.&lt;br&gt;
"Salting is your best defense against rainbow tables."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Adjusting Computational Cost: Making Brute-Force Attacks Harder&lt;/strong&gt;&lt;br&gt;
Modern cryptographic hashing algorithms are intentionally designed to be slow to counter brute-force attacks. By adjusting the computational cost—which refers to the time required to compute the hash—you can increase the difficulty of brute-force attacks. The longer it takes to hash a password, the more computationally expensive and time-consuming it becomes for attackers to try multiple combinations.&lt;/p&gt;

&lt;p&gt;The optimal hashing time is around &lt;strong&gt;&lt;em&gt;50 milliseconds&lt;/em&gt;&lt;/strong&gt; per password. This ensures a balance between security and performance, making brute-force attacks impractical while keeping application responsiveness intact.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Using Cryptographically Secure Hash Functions&lt;/strong&gt;&lt;br&gt;
For optimal password security, you need to use cryptographically secure hash functions specifically designed for password storage. Algorithms like SHA-512 are fast and suitable for general hashing tasks, but they are not ideal for password hashing because their speed makes them vulnerable to brute-force attacks.&lt;/p&gt;

&lt;p&gt;Here, the specific needs of your system come into play: if your server resources are limited, you can still implement cryptographic hash algorithms with both dynamic and static salts, alongside performance standards that ensure the hash algorithm runs within the 50-millisecond range. This approach strikes an optimal balance between performance and security.&lt;/p&gt;

&lt;p&gt;However, if you have more resources at your disposal, consider using more advanced, pre-configured, and robust hashing algorithms like Argon2. These algorithms are designed to be both secure and scalable, making them ideal for larger projects with more computational capacity.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bcrypt: Includes a salt and is adaptive to hardware improvements, meaning the computational cost can be increased over time.&lt;/li&gt;
&lt;li&gt;scrypt: A memory-hard function that requires substantial memory and CPU resources, making it more difficult to crack with brute-force methods.&lt;/li&gt;
&lt;li&gt;Argon2: The winner of the Password Hashing Competition, Argon2 offers exceptional security and flexibility, allowing you to adjust time, memory, and parallelism parameters, providing strong resistance to modern attack techniques.
&lt;em&gt;Argon2 is widely regarded as the most secure option due to its flexibility and superior features, making it the best choice for most applications.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Implementing Strong Password Policies&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy2resgm5qa5mw21h6eq0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy2resgm5qa5mw21h6eq0.png" alt="password_policy" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Strong password policies are crucial for ensuring password hashes are resistant to brute-force attacks. The more complex and lengthy a password is, the more difficult it becomes for attackers to crack.&lt;/p&gt;

&lt;p&gt;For example, let’s assume an attacker can perform one trillion operations per second. If the password uses 72 symbols and is 8 characters long, the total number of combinations would be approximately:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;728≈722,204,136,308,736 combinations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the attacker can perform one trillion operations per second, the time to crack this password would be around &lt;em&gt;12 minutes&lt;/em&gt;. Increasing the password length to 9 characters increases the attack time to &lt;strong&gt;&lt;em&gt;14.44 hours&lt;/em&gt;&lt;/strong&gt;, and with 10 characters, it would take an impractical &lt;strong&gt;&lt;em&gt;1,039 hours&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This exponential increase in time makes it far more difficult for attackers to succeed, especially with long and complex passwords.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Regularly Updating Hashing Parameters&lt;/strong&gt;&lt;br&gt;
As computational power grows, it's important to regularly update hashing parameters—such as the number of iterations and memory usage—to stay ahead of improvements in computing power. Regular updates ensure that your password hashing techniques remain effective against increasingly sophisticated hardware and attack methods.&lt;/p&gt;

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

&lt;p&gt;Proper password security hinges on robust hashing, salting, and careful adjustments to computational costs. By using secure algorithms like Argon2, implementing dynamic salts, enforcing strong password policies, and regularly updating your hashing parameters, you can significantly improve your system’s resistance to attacks.&lt;/p&gt;

&lt;p&gt;No system is immune to threats, but by adopting these best practices, you can fortify your application against hash table attacks, brute-force attempts, and rainbow table exploits. In doing so, you ensure that your users’ data remains secure well into the future.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Hit the reaction that match how you feel — and follow me to explore more!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://github.com/abstract-333" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;&lt;a href="https://medium.com/@abstract-333" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;&lt;/strong&gt;
&lt;/h3&gt;

</description>
      <category>security</category>
      <category>database</category>
      <category>backend</category>
      <category>password</category>
    </item>
  </channel>
</rss>
