<?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: Fuad Husnan</title>
    <description>The latest articles on DEV Community by Fuad Husnan (@fuadhusnan_f44f3e13).</description>
    <link>https://dev.to/fuadhusnan_f44f3e13</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%2F3914266%2F094c796a-3db7-45ac-abff-19a1b85ff8a7.png</url>
      <title>DEV Community: Fuad Husnan</title>
      <link>https://dev.to/fuadhusnan_f44f3e13</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fuadhusnan_f44f3e13"/>
    <language>en</language>
    <item>
      <title>Next-Gen Synergy: How Blockchain and Decoupled Databases Secure Big Data Integrity</title>
      <dc:creator>Fuad Husnan</dc:creator>
      <pubDate>Wed, 14 Oct 2026 07:45:54 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/next-gen-synergy-how-blockchain-and-decoupled-databases-secure-big-data-integrity-2jmn</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/next-gen-synergy-how-blockchain-and-decoupled-databases-secure-big-data-integrity-2jmn</guid>
      <description>&lt;p&gt;Big data systems now move billions of records across services, pipelines, and regions every day. Each hop creates a chance for silent corruption, accidental overwrites, or deliberate tampering. Blockchain and decoupled database architectures offer a practical answer to that problem when they are combined thoughtfully. One stores data where it performs best, and the other proves that the data has not changed since it was written. This article explains how the two fit together, where the pairing works well, and where it does not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Big Data Integrity Is Hard to Guarantee
&lt;/h2&gt;

&lt;p&gt;Most data platforms were built for speed and scale, not for proof. A typical analytics stack might ingest events from a message queue, transform them in a batch engine, store them in a data lake, and serve them through a warehouse. At every stage, a bug, a misconfigured job, or a compromised credential can change values without leaving a clear trace.&lt;/p&gt;

&lt;p&gt;Traditional safeguards help but do not solve the whole problem. Database transaction logs record changes, yet the logs usually live inside the same administrative domain as the data. Anyone with sufficient privileges can alter both. Checksums catch accidental corruption during transfer, but they do not stop a motivated insider from recalculating them. Integrity in this context means more than "the bits arrived intact." It means that an organization can demonstrate, to itself or to an auditor, that a record is the same one that was originally committed.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Core Problem: Trust Is Concentrated
&lt;/h3&gt;

&lt;p&gt;The real weakness is concentration. When one team controls the database, the backups, the audit trail, and the access keys, the integrity guarantee is only as strong as that team's controls. Decentralized verification changes this by distributing the record of truth across independent parties, so that no single operator can rewrite history unnoticed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Blockchain Adds to the Picture
&lt;/h2&gt;

&lt;p&gt;A blockchain is, at its core, an append-only sequence of records in which each entry is cryptographically linked to the one before it. Changing any historical entry changes its hash, which breaks every link that follows. When many nodes maintain copies of the chain and agree on its state through a consensus protocol, tampering becomes expensive and easy to detect.&lt;/p&gt;

&lt;p&gt;It is important to be precise about what a blockchain does not do. It does not store large datasets efficiently. Putting terabytes of raw records on a public ledger would be slow, costly, and usually unnecessary. What a blockchain does well is anchor a small, verifiable fingerprint of data that lives elsewhere. That fingerprint, often a hash or the root of a Merkle tree, is enough to prove later that the underlying data has not been altered.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hashing as the Bridge
&lt;/h3&gt;

&lt;p&gt;Hash functions make this separation possible. A cryptographic hash such as SHA-256 converts any input into a fixed-length digest. Even a one-character change produces a completely different digest, and it is computationally infeasible to craft two different inputs with the same output. A system can hash a batch of records, publish that digest to a blockchain, and later recompute the hash to check whether anything has changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Decoupled Databases
&lt;/h2&gt;

&lt;p&gt;A decoupled database architecture separates the components that were once bundled together. Storage, compute, indexing, and access control may run on different systems, scale independently, and be replaced without rewriting the whole platform. Object storage holds raw files, a query engine reads them on demand, and a metadata service tracks what exists and where.&lt;/p&gt;

&lt;p&gt;This design brings clear benefits. Teams can choose the right tool for each job, control costs by scaling storage and compute separately, and avoid vendor lock-in at the storage layer. It also creates a natural seam where integrity checks can be inserted. Because data is written to and read from separate services, each boundary is an opportunity to verify that what moved across it is what was expected.&lt;/p&gt;

&lt;p&gt;The trade-off is complexity. More moving parts mean more places where things can drift out of sync. A decoupled system without strong verification can silently serve inconsistent results, which is exactly the failure that integrity mechanisms aim to prevent.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Two Architectures Work Together
&lt;/h2&gt;

&lt;p&gt;The most effective pattern separates responsibilities cleanly. The decoupled database handles storage, querying, and high-throughput writes. The blockchain layer receives periodic commitments, usually a Merkle root computed over each batch of new records, and records them immutably. Verification then becomes a routine operation rather than an emergency investigation.&lt;/p&gt;

&lt;p&gt;Consider a data pipeline that ingests financial transactions. Every hour, a job collects the new records, computes a Merkle root, and writes that root to a blockchain transaction. The raw records remain in object storage and in the query engine, where analysts can use them normally. If an auditor later questions a specific transaction, the team can retrieve the record, recompute its proof path, and compare the result against the anchored root. Any mismatch points directly to the batch that was changed.&lt;/p&gt;

&lt;p&gt;This approach keeps the performance characteristics of the decoupled system while adding a verifiable history. It also limits blockchain costs, since only compact commitments are published rather than every row.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Working Example: Hash-Chained Audit Log
&lt;/h3&gt;

&lt;p&gt;The following Python example illustrates the core idea of linking records through hashes. Each entry includes the hash of the previous entry, so any modification breaks verification from that point onward.&lt;br&gt;
&lt;/p&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;hashlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compute_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prev_hash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return a SHA-256 digest that binds a record to its predecessor.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&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;record&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prev&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prev_hash&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;sort_keys&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&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;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IntegrityChain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;GENESIS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;prev_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entries&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GENESIS&lt;/span&gt;
        &lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;entry_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;compute_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prev_hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&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;record&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prev&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prev_hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entry_hash&lt;/span&gt;&lt;span class="p"&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;entry_hash&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;prev_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GENESIS&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;compute_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;record&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;prev_hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prev&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;prev_hash&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
            &lt;span class="n"&gt;prev_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;head&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;The latest hash, suitable for publishing to an external ledger.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entries&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GENESIS&lt;/span&gt;


&lt;span class="n"&gt;chain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;IntegrityChain&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;account&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;A-1042&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;amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;250.00&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;account&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;B-2210&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;amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;75.50&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Chain valid:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;   &lt;span class="c1"&gt;# True
&lt;/span&gt;
&lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entries&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;record&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;amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;9999.00&lt;/span&gt;  &lt;span class="c1"&gt;# simulate tampering
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Chain valid:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;   &lt;span class="c1"&gt;# False
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In production, the &lt;code&gt;head()&lt;/code&gt; value would be written to a blockchain at regular intervals. Anyone holding the original records could then confirm that the local chain still matches the published head. The example uses an in-memory list for clarity, but the same logic applies when entries are stored in a decoupled database and verified by a scheduled job.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anchoring Batches with Merkle Trees
&lt;/h3&gt;

&lt;p&gt;A single hash chain works well for ordered logs, but large datasets are often better represented as a Merkle tree. In this structure, records are hashed in pairs, those hashes are hashed again, and the process continues until a single root remains. The root summarizes the entire batch. To prove that one record belongs to the batch, a verifier needs only the record, its sibling hashes along the path, and the published root. Proofs grow logarithmically with batch size, which keeps verification fast even for millions of records.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Considerations Before Adopting This Pattern
&lt;/h2&gt;

&lt;p&gt;The combination is powerful, but it is not free. Teams should weigh several factors before committing.&lt;/p&gt;

&lt;p&gt;Latency is the first. Anchoring happens in batches, so there is always a window between a write and its external commitment. For use cases where that window is unacceptable, the verification guarantee must be applied differently, perhaps through synchronous signing at the application layer.&lt;/p&gt;

&lt;p&gt;Key management is the second. The integrity proof is only as strong as the protection of the systems that publish commitments. Hardware security modules, separation of duties, and regular key rotation are essential. A compromised signing key can undermine everything the architecture is meant to provide.&lt;/p&gt;

&lt;p&gt;Privacy is the third. Even hashed values can leak information if the input space is small or predictable. Salting records before hashing and keeping sensitive fields out of the committed payload are standard safeguards. Regulations such as data protection laws may also restrict what can be written to a public ledger at all, so legal review belongs early in the design process.&lt;/p&gt;

&lt;p&gt;Cost and chain choice are the fourth. Public chains offer broad independent verification but charge fees and have variable throughput. Permissioned ledgers offer control and predictable performance but depend on the trust model of their members. The right choice depends on who needs to verify the data and who should be able to write to the ledger.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Pattern Delivers the Most Value
&lt;/h2&gt;

&lt;p&gt;Some domains benefit more than others. Financial reconciliation, supply chain provenance, regulatory reporting, and scientific data sharing all share a need for records that can be trusted across organizations. In these settings, the value of independent verification often outweighs the added complexity.&lt;/p&gt;

&lt;p&gt;Internal analytics teams may find lighter approaches sufficient. Strong access controls, immutable storage policies, and regular automated checksums can meet many governance requirements without a blockchain layer. The decision should follow the threat model, not the technology trend. Ask who might want to alter the data, how that alteration would be detected today, and what it would cost if it went unnoticed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Verifiable Data Practice
&lt;/h2&gt;

&lt;p&gt;Teams that want to start should begin small. Pick one high-value dataset, define the records that matter most, and implement hash-based fingerprinting at the batch level. Store the fingerprints in a location separate from the data itself. Automate verification so that discrepancies generate alerts. Once the process is reliable, consider publishing commitments to a blockchain and documenting the verification procedure for auditors.&lt;/p&gt;

&lt;p&gt;Clear documentation matters as much as code. Explain what is hashed, how batches are formed, when commitments are published, and how anyone can recompute and check them. A verification process that only the original engineers understand provides little assurance to outside parties.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Integrity as an Architectural Choice
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://repository.telkomuniversity.ac.id/pustaka/178222/big-data-and-blockchain-for-service-operations-management.html" rel="noopener noreferrer"&gt;Big data&lt;/a&gt; integrity cannot be bolted on after the fact. It has to be designed into how data is written, stored, and verified. Decoupled databases provide the flexibility and scale that modern workloads demand. Blockchains provide a way to publish compact, tamper-evident commitments that no single party controls. Used together, they let organizations keep their data where it performs best while proving that it has not been quietly changed.&lt;/p&gt;

&lt;p&gt;If your team manages critical datasets, start with a single pipeline and map its trust boundaries this week. Identify where data crosses a boundary without verification, and add a fingerprinting step there first. The improvement is measurable, the cost is modest, and the result is a data platform you can defend to anyone who asks.&lt;/p&gt;

</description>
      <category>bigdata</category>
      <category>blockchain</category>
    </item>
    <item>
      <title>The Deflation of the Hype: Managing Data and AI Infrastructure in 2026</title>
      <dc:creator>Fuad Husnan</dc:creator>
      <pubDate>Wed, 14 Oct 2026 07:43:36 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/the-deflation-of-the-hype-managing-data-and-ai-infrastructure-in-2026-17o1</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/the-deflation-of-the-hype-managing-data-and-ai-infrastructure-in-2026-17o1</guid>
      <description>&lt;p&gt;For the past few years, nearly every conversation about AI infrastructure started with ambition. Companies wanted large language models in every product, data platforms that could answer any question, and agents that would automate entire departments. Budgets grew quickly, and so did expectations. In 2026, that momentum has cooled into something more useful: a sober, practical look at what data and AI infrastructure actually costs, what it actually delivers, and how teams can run it without burning money or trust.&lt;/p&gt;

&lt;p&gt;This shift is not a retreat from AI. It is a maturing of the field. The organizations making real progress now are the ones asking narrower questions. Which workloads justify the expense of a large model? Where does our data come from, and can we trust it? How will we know if the system is working six months from now? This article walks through the forces behind the deflation of the hype and offers a grounded approach to managing data and AI infrastructure in the current environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Hype Is Deflating
&lt;/h2&gt;

&lt;p&gt;Hype cycles follow a familiar pattern. A new capability appears, demonstrations impress executives, and investment rushes in faster than the underlying practices can keep up. The gap between what a demo shows and what a production system delivers becomes the source of disappointment. Many teams discovered that a prototype built on clean sample data behaves very differently when it meets messy, real-world inputs, changing schemas, and users who ask questions nobody anticipated.&lt;/p&gt;

&lt;p&gt;Another factor is economics. Running inference at scale, storing vector embeddings, moving data between systems, and maintaining pipelines all carry recurring costs. When finance teams began reviewing these line items next to measurable business outcomes, many initiatives looked very different. Some were clearly valuable and deserved more investment. Others were novelties that solved problems no one had prioritized. The result is a healthier conversation about return on investment, even if it is less exciting than the earlier headlines.&lt;/p&gt;

&lt;p&gt;Trust has also become central. Regulators, customers, and internal stakeholders now ask how data was collected, how models were evaluated, and who is accountable when something goes wrong. These questions are not obstacles to innovation. They are the natural requirements of any infrastructure that people depend on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start With the Data, Not the Model
&lt;/h2&gt;

&lt;p&gt;The most common mistake in AI projects is treating the model as the centerpiece and the data as an afterthought. In practice, the model is often the most replaceable component. Data quality, lineage, and accessibility determine whether any model can produce reliable results.&lt;/p&gt;

&lt;p&gt;A practical starting point is to define what "good data" means for each use case. A customer support assistant needs current product documentation and accurate ticket histories. A forecasting system needs consistent timestamps and documented handling of missing values. Writing these expectations down turns vague aspirations into testable requirements.&lt;/p&gt;

&lt;p&gt;Validation should happen early and automatically, before data reaches training or retrieval pipelines. The following Python snippet shows a simple quality gate that checks for required columns and flags columns with excessive missing values. It is not a complete framework, but it illustrates the principle that bad inputs should fail loudly rather than silently degrade outputs.&lt;br&gt;
&lt;/p&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;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_batch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;required_columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;max_null_ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.02&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return a list of human-readable issues found in a data batch.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;issues&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="n"&gt;missing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;required_columns&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&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;Missing columns: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&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;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;)&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;required_columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;col&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;null_ratio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;isna&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;null_ratio&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;max_null_ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;col&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: null ratio &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;null_ratio&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; exceeds limit of &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;max_null_ratio&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;%&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;issues&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;sample&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DataFrame&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer_id&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;created_at&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;2026-01-01&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2026-01-04&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="n"&gt;problems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;validate_batch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sample&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;customer_id&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;created_at&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;plan_type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;problem&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;problems&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;problem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running a check like this in a scheduled job, and blocking downstream steps when it fails, is often more valuable than a sophisticated model upgrade. It prevents the quiet failures that are hardest to diagnose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Right-Size the Architecture
&lt;/h2&gt;

&lt;p&gt;Another consequence of the hype cycle was the tendency to build for maximum capability from day one. Teams deployed the largest available models, set up complex multi-agent workflows, and connected every data source they could find. Many of these systems are now being simplified.&lt;/p&gt;

&lt;p&gt;Right-sizing begins with honest questions about each workload. Does the task require a frontier model, or would a smaller, cheaper model handle it with acceptable quality? Can a deterministic rule or a traditional classifier solve part of the problem? Is retrieval-augmented generation needed, or does the system already have the context it requires? Every layer added to an architecture increases latency, cost, and the surface area for failure.&lt;/p&gt;

&lt;p&gt;Caching, batching, and routing requests to appropriate models are practical techniques that reduce spending without sacrificing the user experience for most tasks. Monitoring token usage per feature, rather than in aggregate, reveals which parts of a product are expensive and whether that expense is justified by the value delivered.&lt;/p&gt;

&lt;p&gt;It is worth acknowledging the trade-offs here. Smaller models can underperform on ambiguous or highly complex inputs. Caching can serve stale answers if invalidation is handled poorly. Routing logic adds its own maintenance burden. The goal is not to minimize every cost but to make these decisions deliberately and measure the results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Governance Without Paralysis
&lt;/h2&gt;

&lt;p&gt;Governance is often portrayed as the enemy of speed. In reality, clear governance is what allows teams to move quickly with confidence. The key is to make it proportional to risk.&lt;/p&gt;

&lt;p&gt;A low-stakes internal tool that summarizes meeting notes does not need the same review process as a system that makes lending decisions or handles medical information. Classifying use cases by impact and sensitivity helps teams focus their effort where it matters. Documentation should cover where data came from, what permissions govern its use, how models were evaluated, and what monitoring is in place.&lt;/p&gt;

&lt;p&gt;Access control deserves particular attention. Retrieval systems can inadvertently expose information to users who should not see it if document-level permissions are not enforced at query time. Treating retrieval as a security boundary, rather than a convenience feature, prevents a class of problems that can be expensive to fix after deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measure What Actually Matters
&lt;/h2&gt;

&lt;p&gt;Perhaps the most important discipline in 2026 is evaluation. Many AI systems were launched on the strength of impressive demonstrations, with little systematic testing afterward. Without measurement, it is impossible to know whether a change improved the system or made it worse.&lt;/p&gt;

&lt;p&gt;Effective evaluation combines several approaches. Offline test sets, built from representative real queries and reviewed by domain experts, provide a stable baseline for comparing versions. Online metrics, such as task completion rates, escalation frequency, and user corrections, reveal how the system performs in practice. Human review of a sample of outputs catches failure modes that automated metrics miss.&lt;/p&gt;

&lt;p&gt;Teams should also track drift. Data distributions change, user behavior evolves, and upstream systems are modified. A model that performed well at launch can degrade quietly over months. Scheduled re-evaluation and alerting on key indicators turn drift from a surprise into a manageable maintenance task.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Sustainable Approach Looks Like
&lt;/h2&gt;

&lt;p&gt;Taken together, these principles point toward a practical operating model. Data pipelines are validated and documented. Architecture is sized to the workload rather than to the marketing. Governance scales with risk. Evaluation is continuous, and costs are visible at the feature level.&lt;/p&gt;

&lt;p&gt;This model is less dramatic than the visions that dominated earlier discussions. It does not promise that &lt;a href="https://repository.telkomuniversity.ac.id/pustaka/177187/leading-with-ai-and-analytics-build-your-data-science-iq-to-drive-business-value.html" rel="noopener noreferrer"&gt;AI&lt;/a&gt; will transform every process overnight. It does offer something more valuable: a path where each investment can be justified, measured, and improved over time. Organizations that adopt this mindset tend to ship fewer experiments but more systems that last.&lt;/p&gt;

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

&lt;p&gt;The deflation of the hype is good news for teams willing to do the unglamorous work. Managing data and AI infrastructure in 2026 means starting with data quality, choosing architectures based on real requirements, governing systems in proportion to their risk, and measuring outcomes continuously. If your team is planning its next AI initiative, begin with a single workflow, define what success looks like in numbers, and build the validation and monitoring you will need before scaling. Share your current challenges in the comments or reach out to discuss how your infrastructure can move from experimentation to dependable production.&lt;/p&gt;

</description>
      <category>datascience</category>
      <category>ai</category>
    </item>
    <item>
      <title>Quantum Leap: Preparing Data Science Models for the Age of Quantum Computing</title>
      <dc:creator>Fuad Husnan</dc:creator>
      <pubDate>Wed, 14 Oct 2026 07:41:25 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/quantum-leap-preparing-data-science-models-for-the-age-of-quantum-computing-i35</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/quantum-leap-preparing-data-science-models-for-the-age-of-quantum-computing-i35</guid>
      <description>&lt;p&gt;Quantum computing has moved from physics laboratories into the conversations of data science teams. Many practitioners now ask a practical question: how should we prepare our data science models for quantum computing, even though large-scale fault-tolerant machines are not yet available? The honest answer is that preparation does not require a quantum computer on your desk. It requires understanding where quantum methods might help, building clean and portable data pipelines, and designing models so they can be tested against quantum approaches when the hardware matures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Quantum Computing Matters for Data Science
&lt;/h2&gt;

&lt;p&gt;Classical machine learning relies on bits that are either zero or one. Quantum computers use qubits, which can exist in superpositions of states and become entangled with one another. These properties allow a quantum system to represent and manipulate certain mathematical structures in ways that classical hardware struggles to reproduce efficiently. That does not mean quantum computers will make every model faster. It means a narrow class of problems, such as certain optimization tasks, sampling problems, and kernel-based similarity calculations, may benefit from quantum approaches.&lt;/p&gt;

&lt;p&gt;For data scientists, this distinction matters. Most everyday work, including cleaning tabular data, building dashboards, or training gradient-boosted trees on customer records, will remain firmly classical. The opportunity lies in identifying the specific bottlenecks in your workflow that could one day be reframed as quantum problems. Treating quantum computing as a universal upgrade leads to wasted effort and unrealistic expectations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Hybrid Model Approach
&lt;/h2&gt;

&lt;p&gt;Today, the most realistic path forward is hybrid computing. In a hybrid setup, a classical computer handles most of the pipeline, including data loading, preprocessing, evaluation, and orchestration, while a quantum processor or simulator handles a specific subroutine. A variational circuit, for example, can be tuned by a classical optimizer over many iterations. This pattern is already used in research prototypes across finance, chemistry, and logistics.&lt;/p&gt;

&lt;p&gt;Hybrid thinking also protects your investment. If you design your model with clear boundaries between the classical feature pipeline and the learning component, you can swap in a quantum kernel or a quantum feature map later without rewriting everything. Teams that keep their code modular now will find the transition far less painful than teams whose notebooks mix data loading, modeling, and plotting in a single tangled file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing Your Data for Quantum Encoding
&lt;/h2&gt;

&lt;p&gt;One of the first practical challenges is data encoding. Quantum circuits do not accept raw numbers in the way a scikit-learn estimator does. Features must be mapped into quantum states, and the mapping choice affects both accuracy and computational cost. A common approach is amplitude encoding, where a feature vector is normalized and placed into the amplitudes of a quantum state. This requires the vector length to be a power of two, so padding is often necessary.&lt;/p&gt;

&lt;p&gt;The following Python snippet demonstrates the classical preparation steps that sit in front of an amplitude encoding circuit. It normalizes a feature vector and pads it to the nearest power of two, which is a useful habit regardless of whether you ever run the quantum part.&lt;br&gt;
&lt;/p&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;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;prepare_amplitude_vector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;features&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ndarray&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ndarray&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Normalize a feature vector and pad it to a power of two length
    so it can be used as the amplitudes of a quantum state.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;features&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asarray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;features&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Pad to the next power of two
&lt;/span&gt;    &lt;span class="n"&gt;target_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;features&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
    &lt;span class="n"&gt;padded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zeros&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;padded&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;features&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;features&lt;/span&gt;

    &lt;span class="c1"&gt;# Normalize so the squared amplitudes sum to one
&lt;/span&gt;    &lt;span class="n"&gt;norm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linalg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;norm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;norm&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Feature vector must contain at least one non-zero value.&lt;/span&gt;&lt;span class="sh"&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;padded&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;norm&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;4.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;state_amplitudes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;prepare_amplitude_vector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Amplitudes:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state_amplitudes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sum of squares:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state_amplitudes&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running this script produces a vector of length eight whose squared values sum to one, which is the requirement for a valid quantum state. Notice that the function raises an error for an all-zero vector. Small validation checks like this prevent confusing failures later, when a quantum backend would otherwise reject the input with a less helpful message.&lt;/p&gt;

&lt;p&gt;Beyond encoding, consider how you scale and transform data. Quantum methods are sensitive to the range and distribution of inputs. Standardizing features, reducing dimensionality with techniques such as principal component analysis, and documenting every transformation step will make your experiments reproducible. Reproducibility becomes especially important when comparing a classical baseline with a quantum candidate, because small preprocessing differences can create misleading performance gaps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Strong Classical Baseline
&lt;/h2&gt;

&lt;p&gt;Every quantum experiment should be judged against a strong classical baseline. This is a discipline that many teams skip, often because the excitement around new hardware encourages comparisons against weak or untuned models. A rigorous approach trains well-understood classical methods, such as logistic regression, random forests, or support vector machines with a radial basis function kernel, using the same data splits and evaluation metrics you would use for the quantum version.&lt;/p&gt;

&lt;p&gt;The following example shows a classical baseline built with scikit-learn. It uses a proper train and test split, scales features inside a pipeline to avoid data leakage, and reports cross-validated performance. The structure is deliberately simple so it can later be adapted to compare against a quantum kernel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.datasets&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_breast_cancer&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.model_selection&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;train_test_split&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cross_val_score&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.pipeline&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;make_pipeline&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.preprocessing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StandardScaler&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.svm&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SVC&lt;/span&gt;

&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load_breast_cancer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;return_X_y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_test&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;train_test_split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;test_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;random_state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stratify&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# The scaler lives inside the pipeline so it is fit only on training folds
&lt;/span&gt;&lt;span class="n"&gt;baseline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;make_pipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;StandardScaler&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;SVC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rbf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;scores&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cross_val_score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;baseline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cv&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scoring&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accuracy&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cross-validated accuracy: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (+/- &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;std&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&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;baseline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_train&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_train&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Held-out test accuracy: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;baseline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X_test&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_test&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;f&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Placing the scaler inside the pipeline is a small detail with a large impact. Fitting a scaler on the full dataset before splitting leaks information from the test set into training, which inflates results. When a quantum kernel is eventually introduced, this same pipeline structure makes the comparison fair, because both approaches receive identical preprocessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing Problems Worth Watching
&lt;/h2&gt;

&lt;p&gt;Not every model deserves a quantum experiment. Research so far suggests that the most promising candidates tend to involve high-dimensional feature spaces with complex correlations, combinatorial optimization, or simulation of physical systems. Problems that are dominated by data volume rather than computational complexity, such as storing and querying billions of rows, are unlikely to benefit from quantum hardware in the near term.&lt;/p&gt;

&lt;p&gt;A useful habit is to maintain a short internal document that records which business problems have computational bottlenecks, how long those computations take today, and what accuracy or cost improvement would justify exploring alternatives. This document turns a vague fascination with quantum computing into a concrete research agenda. It also helps leadership understand why some experiments are worth funding while others are not.&lt;/p&gt;

&lt;p&gt;Be cautious about claims in vendor marketing and early research papers. Results on small, curated datasets do not always generalize, and simulators can behave differently from real hardware because of noise and error rates. Treat any reported advantage as a hypothesis to test on your own data, using your own evaluation criteria.&lt;/p&gt;

&lt;h2&gt;
  
  
  Skills and Habits for the Quantum-Ready Data Scientist
&lt;/h2&gt;

&lt;p&gt;Preparing for &lt;a href="https://bds-sby.telkomuniversity.ac.id/tag/quantum-computing/" rel="noopener noreferrer"&gt;quantum computing&lt;/a&gt; is less about learning a new framework overnight and more about strengthening foundations. Linear algebra is central, because state vectors, unitary transformations, and kernel matrices all rely on it. Probability and statistics remain essential for measuring noisy outputs, since quantum measurements are inherently probabilistic. Comfort with optimization helps when tuning variational circuits, and familiarity with modular software design makes hybrid experiments manageable.&lt;/p&gt;

&lt;p&gt;Practical experience matters too. Many quantum software development kits offer simulators that run on a laptop for small circuits. Working through tutorials, reproducing published experiments, and documenting differences between simulated and reported results builds intuition that no article can fully provide. Share what you learn with colleagues, since cross-functional discussion between data scientists, software engineers, and domain experts is where the most useful ideas tend to emerge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Organizational Readiness
&lt;/h2&gt;

&lt;p&gt;Organizations that want to prepare seriously should focus on three areas. The first is data infrastructure. Clean, versioned, well-documented datasets are valuable regardless of the computing paradigm. The second is experimentation culture. Teams need clear processes for comparing models fairly, logging parameters, and retiring experiments that do not deliver. The third is governance and security. Quantum computing also raises questions about cryptography, and organizations should review how sensitive data is protected over long time horizons, a concern widely discussed under the label of post-quantum cryptography.&lt;/p&gt;

&lt;p&gt;Leadership plays a role here. Rather than announcing a quantum transformation, leaders can fund small exploratory projects, set realistic expectations, and reward teams for honest findings, including negative results. This approach keeps the organization curious without encouraging hype.&lt;/p&gt;

&lt;h2&gt;
  
  
  Balancing Optimism and Realism
&lt;/h2&gt;

&lt;p&gt;The promise of quantum computing is real, but so are its constraints. Current devices have limited qubit counts, high error rates, and short coherence times. Many algorithms that look impressive on paper require error correction that is still under development. For data scientists, this means the immediate return on investment lies in learning, experimentation, and infrastructure, not in replacing production models.&lt;/p&gt;

&lt;p&gt;Maintaining this balance protects your credibility. When you present quantum-related work, explain what was tested, what was measured, and where the limitations lie. Readers and colleagues trust analysis that acknowledges trade-offs far more than analysis that promises revolutionary outcomes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Start Preparing Today
&lt;/h2&gt;

&lt;p&gt;Preparing data science models for the age of quantum computing does not require waiting for a perfect machine. It starts with clean and modular pipelines, honest classical baselines, thoughtful data encoding, and a clear sense of which problems might eventually benefit from quantum methods. Teams that build these foundations now will be ready to test quantum approaches rigorously as the technology matures, and they will avoid the costly mistakes that come from chasing hype.&lt;/p&gt;

&lt;p&gt;If your team is just beginning, pick one existing model, document its preprocessing and evaluation, and build a classical baseline you trust. Then explore a quantum simulator with the same data. Share the results with your colleagues, and let the findings guide your next step. Subscribe to our newsletter or leave a comment below with the quantum topic you most want to explore next.&lt;/p&gt;

</description>
      <category>datascience</category>
    </item>
    <item>
      <title>Beyond the Cloud: Why Edge Computing Is the Next Frontier for Real-Time Data Analytics</title>
      <dc:creator>Fuad Husnan</dc:creator>
      <pubDate>Wed, 14 Oct 2026 07:39:49 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/beyond-the-cloud-why-edge-computing-is-the-next-frontier-for-real-time-data-analytics-11n0</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/beyond-the-cloud-why-edge-computing-is-the-next-frontier-for-real-time-data-analytics-11n0</guid>
      <description>&lt;p&gt;For more than a decade, the default answer to almost every data question has been the same: send it to the cloud. Centralized data centers offered nearly unlimited storage, elastic compute, and a single place to build dashboards and train models. That model still works well for many workloads. But as sensors, cameras, vehicles, and industrial machines multiply, a growing number of teams are discovering that routing every byte to a distant data center is slow, expensive, and sometimes simply impractical. Edge computing, which processes data close to where it is generated, is quickly becoming the next frontier for real-time analytics.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Cloud Alone Is Not Enough
&lt;/h2&gt;

&lt;p&gt;The cloud's strengths are real. It centralizes storage, simplifies maintenance, and makes large-scale analysis possible. The trouble begins when the time between an event and a decision matters. A round trip to a regional data center can add tens or even hundreds of milliseconds of latency, depending on network conditions and distance. For a dashboard that refreshes every few minutes, that delay is invisible. For a robotic arm that must stop before colliding with a worker, or a power grid sensor that must detect a fault in milliseconds, it is unacceptable.&lt;/p&gt;

&lt;p&gt;Bandwidth creates a second problem. A single high-resolution camera can generate a steady stream of video, and a factory floor may contain hundreds of such devices along with vibration sensors, temperature probes, and programmable controllers. Uploading all of that raw data continuously consumes network capacity and generates substantial transfer and storage costs. Many organizations end up paying to move data they will never look at again. Edge processing addresses this by filtering, aggregating, and summarizing information on site, then forwarding only what matters.&lt;/p&gt;

&lt;p&gt;Reliability is the third consideration. Cloud-dependent systems stop being useful when the connection drops. A retail store that relies on a remote service to process point-of-sale analytics or detect inventory anomalies may find itself blind during an outage. An edge node that can continue operating locally offers a degree of resilience that a purely centralized architecture struggles to match.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Edge Computing Actually Means
&lt;/h2&gt;

&lt;p&gt;Edge computing is best understood as a spectrum rather than a single device. At one end sit tiny microcontrollers embedded in sensors. In the middle are gateways and industrial PCs that aggregate data from a cluster of machines. At the other end are small regional micro data centers that sit closer to users than the major cloud regions. Each layer trades raw computing power for proximity and speed.&lt;/p&gt;

&lt;p&gt;The most important shift is architectural. Instead of treating the cloud as the center of gravity, edge architectures distribute intelligence across the network. Data is analyzed where it originates, insights are shared upward when needed, and models are updated centrally and pushed back out to devices. This creates a continuous loop in which the cloud manages the long view while the edge handles immediate decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Pattern for Edge Analytics
&lt;/h2&gt;

&lt;p&gt;To make this concrete, consider a common pattern: an edge node receives sensor readings, computes rolling statistics over a short window, flags anomalies locally, and sends only compact summaries to the cloud. The following Python example illustrates the idea using a simple sliding window and a threshold based on standard deviation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;deque&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;statistics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stdev&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EdgeAnomalyDetector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window_size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;deque&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxlen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;window_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;threshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;is_anomaly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;mu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;sigma&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;stdev&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;sigma&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reading&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;threshold&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;sigma&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;is_anomaly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;is_anomaly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;reading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;anomaly&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;is_anomaly&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="n"&gt;detector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;EdgeAnomalyDetector&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;readings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;20.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;20.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;19.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;20.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;20.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;20.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;19.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;20.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;20.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;20.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;35.7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;20.2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;readings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;result&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="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;anomaly&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="c1"&gt;# Only the alert is forwarded upstream, not every raw reading.
&lt;/span&gt;        &lt;span class="nf"&gt;print&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;Anomaly detected at value &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this design, the edge node performs the time-sensitive work. It decides within the same device whether a reading is unusual and raises an alert immediately. The cloud receives the alert and can perform deeper analysis, such as correlating it with maintenance logs or historical trends. Excluding anomalous values from the rolling window also prevents a single spike from distorting the baseline, a small detail that matters in production systems.&lt;/p&gt;

&lt;p&gt;Real deployments add more layers: model compression so that machine learning inference fits on constrained hardware, secure device authentication, buffering for intermittent connectivity, and remote orchestration tools that update edge software safely. Frameworks in the containerized and lightweight runtime space have made these tasks more manageable, but they still require careful engineering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Edge Analytics Delivers the Most Value
&lt;/h2&gt;

&lt;p&gt;Certain industries have adopted edge computing faster than others because the economics and physics align. Manufacturing is a leading example. Predictive maintenance systems analyze vibration and acoustic signatures on the line, catching bearing wear or motor imbalance before failure. Acting on those signals locally avoids stopping production while waiting for a remote verdict.&lt;/p&gt;

&lt;p&gt;Transportation and logistics offer another compelling case. Vehicles equipped with cameras and radar must interpret their surroundings in real time, and while the cloud can improve models over time, the immediate decisions cannot wait for a network round trip. Fleet operators also use edge gateways to summarize telemetry from trucks that may travel through areas with limited coverage.&lt;/p&gt;

&lt;p&gt;Healthcare, energy, and smart cities present similar opportunities. A patient monitoring device can flag a dangerous heart rhythm locally, while a substation controller can isolate a fault faster than a centralized system could respond. Traffic management systems can adjust signal timing based on live camera data without shipping continuous video to a distant server.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Trade-offs to Consider
&lt;/h2&gt;

&lt;p&gt;Edge computing is not a universal replacement for the cloud, and treating it as one would be a mistake. Distributed systems are harder to manage than centralized ones. Updating thousands of devices, monitoring their health, and ensuring consistent behavior requires disciplined operations. Security also becomes more complex, since each edge node is a potential entry point that must be hardened, patched, and physically protected where appropriate.&lt;/p&gt;

&lt;p&gt;Hardware constraints impose limits as well. Edge devices typically have less memory, storage, and power than cloud servers, which means models and pipelines must be designed with efficiency in mind. Data governance requires attention too, because keeping information local can simplify some compliance concerns while complicating others, particularly when data must be aggregated across regions.&lt;/p&gt;

&lt;p&gt;The most sensible approach is usually hybrid. Edge nodes handle latency-sensitive decisions and reduce data volume, while the cloud remains responsible for long-term storage, large-scale training, and cross-site reporting. Teams that define clear responsibilities for each layer tend to avoid the pitfalls of either extreme.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started With Edge Analytics
&lt;/h2&gt;

&lt;p&gt;Organizations considering this shift can begin with a focused use case rather than an enterprise-wide redesign. Start by identifying a process where delays or bandwidth costs cause measurable problems. Measure current latency and data volume, then prototype a small edge component that performs one well-defined task, such as anomaly detection or local aggregation. Compare the results against the existing cloud-only baseline before expanding.&lt;/p&gt;

&lt;p&gt;It also helps to plan for lifecycle management from the beginning. Decide how models will be updated, how devices will report health, and how failures will be handled when a node goes offline. Teams that treat these operational questions as first-class concerns tend to scale edge deployments more smoothly.&lt;/p&gt;

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

&lt;p&gt;The cloud transformed how organizations store and analyze data, and it will remain central to that work. But real-time analytics increasingly demands decisions made at the point where data is created. Edge computing reduces latency, cuts bandwidth costs, and keeps systems running when connectivity falters. The organizations that succeed will not abandon the cloud but will design architectures that place each task where it performs best. If your team is evaluating real-time data needs, start with one high-impact workflow, measure what matters, and let the results guide your next step.uting, real-time analytics, IoT, &lt;a href="https://it.telkomuniversity.ac.id/en/a-complete-breakdown-of-public-private-and-hybrid-clouds/" rel="noopener noreferrer"&gt;cloud computing&lt;/a&gt;, data analytics, distributed systems, predictive maintenance, latency, edge AI, data processing&lt;/p&gt;

</description>
      <category>techtalks</category>
      <category>cloud</category>
    </item>
    <item>
      <title>The Symbiosis of Tomorrow: How Emerging Technologies Are Reshaping Data Science Pipeline Dynamics</title>
      <dc:creator>Fuad Husnan</dc:creator>
      <pubDate>Wed, 14 Oct 2026 07:36:56 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/the-symbiosis-of-tomorrow-how-emerging-technologies-are-reshaping-data-science-pipeline-dynamics-2ca3</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/the-symbiosis-of-tomorrow-how-emerging-technologies-are-reshaping-data-science-pipeline-dynamics-2ca3</guid>
      <description>&lt;p&gt;Data science pipelines were once a relay race. Engineers collected data, analysts cleaned it, scientists modeled it, and engineers deployed the result, often weeks later and with a lot of handoff friction. Emerging technologies are changing that sequence. Automated machine learning, generative AI, edge computing, and new data infrastructure are blurring the lines between stages, so the pipeline increasingly behaves like a connected system rather than a chain of separate jobs.&lt;/p&gt;

&lt;p&gt;This shift matters for anyone building data products. It changes which skills are valuable, how teams divide responsibilities, and where things break. This article examines the main forces at work, the trade-offs they introduce, and a practical example of how one stage of a modern pipeline can be automated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Traditional Pipeline Is Under Pressure
&lt;/h2&gt;

&lt;p&gt;The classic pipeline has five broad stages: ingestion, preparation, exploration, modeling, and deployment. Each stage historically relied on different tools and different people. That separation made sense when data volumes were smaller, and models changed slowly.&lt;/p&gt;

&lt;p&gt;Today the pressure comes from three directions. Data arrives faster and from more sources, including sensors, application logs, and third-party APIs. Business questions also change more quickly, so a model that took a quarter to build may need retraining in days. Finally, organizations want analytics close to where decisions happen, which pushes computation toward the edge of the network.&lt;/p&gt;

&lt;p&gt;These pressures expose a weakness in the relay model. Every handoff adds latency, and every handoff is a place where assumptions get lost. A feature engineered by one person may be computed differently in production by another. Modern pipeline design tries to remove those seams.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Role of Automation
&lt;/h3&gt;

&lt;p&gt;Automation is the first major force. AutoML tools can search across model families, hyperparameters, and feature transformations without a practitioner manually testing each combination. This does not eliminate the need for expertise, but it changes where that expertise is spent. Instead of running dozens of experiments by hand, a data scientist can define the search space, evaluate the results critically, and decide whether the chosen model is appropriate for the business context.&lt;/p&gt;

&lt;p&gt;Automation also reaches data preparation. Schema inference, anomaly detection on incoming data, and automated profiling reduce the time spent discovering problems that a pipeline could have flagged on its own. The benefit is speed and consistency. The risk is over-trust: an automated tool can produce a confident result on data it misunderstands, so human review remains essential.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generative AI as a Pipeline Participant
&lt;/h3&gt;

&lt;p&gt;Generative AI has moved beyond chat interfaces and into the workflow itself. Language models can draft SQL queries from natural-language questions, generate documentation for undocumented datasets, suggest feature ideas based on column names and descriptions, and write the boilerplate code that connects one stage to the next.&lt;/p&gt;

&lt;p&gt;These capabilities are useful, but they come with limitations worth stating plainly. Generated SQL can be syntactically valid and still answer the wrong question. Generated feature logic can leak information from the target variable into the training data, which inflates validation scores. A reasonable rule is that generative tools accelerate drafting, while validation remains a human and automated-testing responsibility. Teams that treat generated code as a starting point, not a finished product, tend to get the benefits without the surprises.&lt;/p&gt;

&lt;h3&gt;
  
  
  Edge Computing and Distributed Processing
&lt;/h3&gt;

&lt;p&gt;Edge computing introduces a different kind of change. When devices such as industrial sensors, vehicles, or retail kiosks generate data continuously, sending every raw record to a central cloud can be expensive and slow. Some processing moves to the device or a nearby gateway. Filtering, aggregation, and lightweight inference can happen locally, with only summaries or flagged events transmitted upstream.&lt;/p&gt;

&lt;p&gt;This creates a split pipeline. Part of the logic runs in constrained environments with limited memory and intermittent connectivity, and part runs in a central platform with more resources. Designing for both requires discipline. Feature definitions must be identical across environments, model versions must be tracked on every device, and monitoring must detect when local conditions drift away from what the central model expects.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Example: Automating Feature Selection
&lt;/h2&gt;

&lt;p&gt;To make these ideas concrete, consider one common task: reducing a wide feature set before training. Many datasets contain redundant or uninformative columns, and removing them can speed training and improve interpretability. The following example uses scikit-learn to drop near-constant features and then keep the most informative ones based on univariate scoring. It is a simple illustration, not a complete production system.&lt;br&gt;
&lt;/p&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;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklear.feature_selection&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;VarianceThreshold&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SelectKBest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f_classif&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.pipeline&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Pipeline&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.preprocessing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StandardScaler&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;build_selection_pipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Pipeline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return a pipeline that removes low-variance features,
    scales the rest, and keeps the k most informative columns.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Pipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;steps&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;variance&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;VarianceThreshold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;threshold&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.01&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;scale&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;StandardScaler&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;select&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;SelectKBest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;score_func&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;f_classif&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# Example usage with a labeled dataset
&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer_events.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columns&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;churned&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;churned&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;selector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;build_selection_pipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;X_selected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit_transform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Original features: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Selected features: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;X_selected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few points about this code deserve attention. The selection steps are fitted on training data only, which prevents leakage into validation. Wrapping the steps in a single &lt;code&gt;Pipeline&lt;/code&gt; object means the same transformations can be saved and reapplied in production without retyping them. The threshold and the value of &lt;code&gt;k&lt;/code&gt; are choices a team should justify against its own data rather than accept as defaults.&lt;/p&gt;

&lt;p&gt;Note also what the example does not do. It does not handle missing values, categorical encoding, or time-based splits, all of which matter in real projects. A production version would add those steps and would store the fitted pipeline alongside the model so that inference uses the same logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trade-Offs Worth Taking Seriously
&lt;/h2&gt;

&lt;p&gt;Enthusiasm for new tools can obscure real costs. Automated pipelines are harder to debug when they fail silently, and an AutoML run that selects a complex ensemble may be difficult to explain to stakeholders or regulators. Generative components introduce dependencies on external services, which raises questions about cost, latency, data privacy, and vendor lock-in.&lt;/p&gt;

&lt;p&gt;Edge deployments add operational burden. Updating models across thousands of devices is a different problem from updating one central endpoint, and failed updates can leave a fleet running inconsistent versions. Teams should plan for rollback and for monitoring at the device level, not just in aggregate.&lt;/p&gt;

&lt;p&gt;There is also a skills question. The most effective data teams in this environment are not simply those with the newest tools. They are teams that understand data quality, can evaluate automated output critically, and communicate clearly about uncertainty. Tooling makes some tasks faster, but it does not remove the need for judgment about what a result actually means.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Toward an Integrated Pipeline
&lt;/h2&gt;

&lt;p&gt;The most practical path forward is incremental. Start by identifying the handoff that causes the most delay or the most errors, and automate or integrate that seam first. For many teams, this is the transition from experimentation to production, where a notebook becomes a service. Shared feature definitions, versioned pipelines, and automated validation checks tend to deliver value quickly.&lt;/p&gt;

&lt;p&gt;From there, expand carefully. Add monitoring for data drift and model performance, and set thresholds that trigger human review rather than automatic retraining in high-stakes contexts. Where edge computing is relevant, test the local logic against the same validation suite used centrally before deploying it to devices.&lt;/p&gt;

&lt;p&gt;The symbiosis between these technologies is real, but it is not automatic. Emerging tools shorten the distance between an idea and a deployed model, and they make the pipeline more connected. Whether that connection produces reliable results depends on the discipline teams bring to it: clear definitions, honest evaluation, and a willingness to question automated answers.&lt;/p&gt;

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

&lt;p&gt;Emerging technologies are reshaping the &lt;a href="https://bds.telkomuniversity.ac.id/en/a_data_scientist_is/" rel="noopener noreferrer"&gt;data science&lt;/a&gt; pipeline from a sequence of handoffs into an integrated system. Automation accelerates modeling and preparation, generative AI speeds up drafting and documentation, and edge computing moves analysis closer to the data source. Each change brings genuine gains and genuine risks. Teams that adopt these tools thoughtfully, validate what they produce, and invest in the skills to interpret results will be best positioned for what comes next. If your team is planning its next pipeline upgrade, start by mapping where your handoffs slow you down, and begin there.&lt;/p&gt;

</description>
      <category>techtalks</category>
      <category>datascience</category>
    </item>
    <item>
      <title>The Journey Blueprint: Why Modern Programming Articles Should Focus on End-to-End Problem Solving</title>
      <dc:creator>Fuad Husnan</dc:creator>
      <pubDate>Tue, 13 Oct 2026 13:16:05 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/the-journey-blueprint-why-modern-programming-articles-should-focus-on-end-to-end-problem-solving-10o0</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/the-journey-blueprint-why-modern-programming-articles-should-focus-on-end-to-end-problem-solving-10o0</guid>
      <description>&lt;p&gt;Most programming articles teach one concept well and then stop. Real engineering work rarely looks like that. Developers need end-to-end problem solving, the ability to take a messy requirement from a first idea to software that runs, gets maintained, and keeps working after the launch party ends. This article argues that modern programming content should be built around that full journey rather than around isolated syntax.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Isolated Tutorials Fall Short
&lt;/h2&gt;

&lt;p&gt;A typical tutorial explains how a decorator works, how a hook manages state, or how a query joins two tables. Each explanation is accurate, and each one helps. The problem appears later, when the reader sits down with a real task and realizes that the tutorial never mentioned where the data comes from, how errors should be reported, or how the result gets delivered to a user. The missing pieces are often more important than the feature being taught.&lt;/p&gt;

&lt;p&gt;This gap is not the fault of the authors. Single-concept lessons are easy to structure, easy to test, and easy to rank for narrow search queries. They also fit neatly into a short video or a short article. However, readers searching for help usually have a bigger question in mind. They want to know how to build a reporting feature, automate a data cleanup, or ship an internal tool. A fragment of code does not answer that question, even when the fragment is correct.&lt;/p&gt;

&lt;p&gt;There is also a trust issue. When an article skips the messy parts, such as validation, edge cases, and deployment, readers assume the solution is simpler than it actually is. They then struggle on their own and often blame themselves. Honest content that shows the full path, including the awkward steps, builds more confidence than polished snippets that work only in a clean sandbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Journey Blueprint Looks Like
&lt;/h2&gt;

&lt;p&gt;A journey blueprint is a way to structure technical content around the stages that a real project passes through. The first stage is defining the problem in plain language. A good article starts by describing who is affected, what currently happens, and what success looks like. This step prevents the common mistake of building a clever solution to the wrong question.&lt;/p&gt;

&lt;p&gt;The second stage is choosing a minimal approach. Many developers reach for heavy frameworks before they understand the requirements. A strong article shows why a simple script or a small function may be enough for the first version, and it explains when the project would justify more infrastructure. Trade-offs belong in this section, because every choice has a cost in complexity, speed, or maintenance.&lt;/p&gt;

&lt;p&gt;The third stage is building the core logic, followed by testing it. The fourth stage is exposing the logic through an interface, whether that is a command-line tool, an API, or a web page. The fifth stage is deployment and observation, where the article covers configuration, logging, and what to check when something breaks. A blueprint does not need to cover every stage in depth, but it should make the reader aware of all of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Worked Example From Requirement to Endpoint
&lt;/h2&gt;

&lt;p&gt;Consider a small business that exports orders as a CSV file each night. The operations team wants a summary of paid orders and total revenue, available through a simple web endpoint. The problem sounds small, yet it touches parsing, validation, computation, and delivery. An end-to-end article can walk through all four in a few hundred lines of code.&lt;/p&gt;

&lt;p&gt;The first step is the data layer. The loader reads each row, converts types, and skips malformed records instead of crashing the whole process. Notice that the function reports skipped rows rather than hiding them. Silent failures are one of the most expensive problems in production software, and an article that demonstrates good habits like this teaches more than one that focuses only on the happy path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# orders.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_orders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newline&lt;/span&gt;&lt;span class="o"&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;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DictReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;order_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                    &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
                    &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="nf"&gt;except &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;KeyError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;err&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Skipping malformed row &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;err&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;summarize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;paid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total_orders&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid_orders&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paid&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;revenue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;paid&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;2&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;The second step is the logic layer, which is intentionally separate from the file reading. Keeping the summary function pure makes it easy to test without touching the disk. This separation is a design decision that deserves explanation in the article, because beginners often mix input, logic, and output into one large function that becomes hard to change later.&lt;/p&gt;

&lt;p&gt;The third step is the interface. A small Flask application can expose the summary as JSON, which any dashboard or script can consume.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jsonify&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_orders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;summarize&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;DATA_FILE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;orders.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@app.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/summary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;jsonify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;summarize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;load_orders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DATA_FILE&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final part of the journey is verification. A short test confirms that the business rule, counting only paid orders, behaves as expected. Tests are often treated as an afterthought in tutorials, but including them in the same article reinforces that the code is meant to be trusted, not just demonstrated.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# test_orders.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;summarize&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_summarize_counts_only_paid_orders&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;10.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nc"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pending&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="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;summarize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid_orders&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;revenue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mf"&gt;10.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the test with &lt;code&gt;pytest&lt;/code&gt; and then start the server with &lt;code&gt;python app.py&lt;/code&gt;. Requesting &lt;code&gt;http://localhost:5000/summary&lt;/code&gt; returns the computed values. The whole example is modest, but it contains every stage of the blueprint, and that is precisely the point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment, Observation, and the Parts Readers Forget
&lt;/h2&gt;

&lt;p&gt;Once the code works locally, the journey is not finished. A complete article should discuss how the script runs on a schedule, where the CSV file arrives, and who gets alerted if the file is missing. It should also mention that the debug flag is turned off in the example, since running a development server in production exposes risks. These details feel mundane, yet they decide whether the solution survives its first month.&lt;/p&gt;

&lt;p&gt;Observation matters just as much. Logging the number of skipped rows, for example, turns a silent data quality problem into a visible signal. A good article can show how to log the count instead of printing each row, and it can explain why that choice reduces noise in production. Readers who learn to think about what their software tells them after deployment are better prepared for real work.&lt;/p&gt;

&lt;p&gt;Deployment also introduces trade-offs that deserve honest treatment. A single-file CSV is fine for a small business, but it may fail under concurrent writes or very large volumes. An article that acknowledges these limits and points toward a database or a queue when the requirements grow earns more credibility than one that presents the first version as the final answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing Content That Follows the Journey
&lt;/h2&gt;

&lt;p&gt;Writers who want to produce this kind of content can start by mapping the stages before drafting any code. Ask what problem the reader is trying to solve, what the simplest working version looks like, which parts are likely to break, and how the result reaches the person who needs it. Then decide which stages deserve detailed code and which can be summarized in a paragraph.&lt;/p&gt;

&lt;p&gt;Editing matters too. Long technical articles often contain code that is correct but not explained, or explanations that never connect back to a working example. Each code block should have a clear purpose, and each paragraph should help the reader move to the next stage. Short paragraphs, descriptive subheadings, and a consistent naming convention make the article easier to scan, which also helps readers who arrive from search engines looking for one specific part of the process.&lt;/p&gt;

&lt;p&gt;Search visibility follows naturally from this approach. A journey-based article covers many related questions, such as how to parse CSV files in Python, how to build a small API, and how to test business logic. Each of those questions is a potential entry point for a reader who may then stay for the complete walkthrough. Rather than chasing narrow keywords, the article earns relevance by answering the full sequence of problems a developer actually faces.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion and Next Steps
&lt;/h2&gt;

&lt;p&gt;Programming articles become more useful when they show the whole road rather than a single turn in it. End-to-end problem solving connects definition, design, implementation, testing, deployment, and observation into one coherent story. Readers leave with working code and, more importantly, with a mental model they can apply to their own projects.&lt;/p&gt;

&lt;p&gt;If you are writing for developers, try building one article around a real problem from start to finish, including the parts that feel unglamorous. Share the draft with a colleague who has never seen the project and ask where they got stuck. Those gaps are the sections your next article should cover. If this approach fits the way you teach or build software, consider applying it to your next tutorial and sharing your results with your audience.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>73 Ways to Practice: Building Real-World Infrastructure Projects to Test Your Coding Limits</title>
      <dc:creator>Fuad Husnan</dc:creator>
      <pubDate>Tue, 13 Oct 2026 13:12:47 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/73-ways-to-practice-building-real-world-infrastructure-projects-to-test-your-coding-limits-n2c</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/73-ways-to-practice-building-real-world-infrastructure-projects-to-test-your-coding-limits-n2c</guid>
      <description>&lt;p&gt;Most developers learn to code by following tutorials. They build a to-do app, clone a weather dashboard, or work through a bootcamp capstone. These exercises are useful at the start, but they rarely reveal how a piece of software behaves when it has to run for months, serve real users, and recover from failures nobody planned for. Real-world infrastructure projects close that gap. They force you to think about networking, storage, deployment, monitoring, and security at the same time, which is exactly where your coding limits show up.&lt;/p&gt;

&lt;p&gt;This article explores why building infrastructure is one of the most effective ways to practice &lt;a href="https://repositori.telkomuniversity.ac.id/pustaka/207778/computational-thinking-a-beginner-s-guide-to-problem-solving-and-programming.html" rel="noopener noreferrer"&gt;programming&lt;/a&gt;, what kinds of projects are worth your time, and how to structure your practice so you actually improve instead of simply staying busy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Infrastructure Projects Teach More Than Feature Projects
&lt;/h2&gt;

&lt;p&gt;A feature project usually ends when the code works on your laptop. An infrastructure project begins at that point. A web scraper that runs once is a script. A scraper that runs every hour, retries on timeouts, stores results reliably, and alerts you when a target site changes its layout is a system. The second version demands skills that the first never touches.&lt;/p&gt;

&lt;p&gt;These skills include designing for failure, handling concurrency, writing idempotent operations, and understanding how components communicate. You also learn to read logs carefully, because when a system breaks in production, logs are often your only window into what happened. Each of these lessons transfers directly to professional work, whether you end up building internal tools, data pipelines, or customer-facing services.&lt;/p&gt;

&lt;p&gt;There is also a psychological benefit. Infrastructure projects are open-ended. Nobody hands you a test suite that tells you when you are finished. That ambiguity is uncomfortable, but it is also where judgment develops.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting Small With Practical Building Blocks
&lt;/h2&gt;

&lt;p&gt;The most common mistake is attempting an ambitious project before mastering its components. A distributed job queue is a worthy goal, but it sits on top of knowledge about processes, sockets, serialization, and error handling. Start with smaller pieces and combine them over time.&lt;/p&gt;

&lt;p&gt;A good first project is a service health checker. It polls a list of endpoints, records response times, and reports failures. The code is short, but it introduces timeouts, error classification, and scheduling. Here is a minimal version in Python:&lt;br&gt;
&lt;/p&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;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;ENDPOINTS&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;https://example.com/health&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;https://api.example.org/status&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_endpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;response&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;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;elapsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ok&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latency_ms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elapsed&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestException&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ok&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ENDPOINTS&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="nf"&gt;check_endpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once this script works, extend it. Add a loop with a sleep interval, write results to a CSV file, and send an alert when three consecutive checks fail. Each extension is small, yet together they resemble the monitoring agents used in production systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automating Deployment and Operations
&lt;/h2&gt;

&lt;p&gt;After you can build a service, the next challenge is getting it running reliably on a machine you do not sit in front of. Deployment automation is a rich area for practice. Shell scripting, container images, and continuous integration pipelines each deserve hands-on time.&lt;/p&gt;

&lt;p&gt;A simple backup script illustrates the kind of operational thinking involved. It compresses a directory, timestamps the archive, and removes old copies so disk space does not run out:&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;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;SOURCE_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/app/data"&lt;/span&gt;
&lt;span class="nv"&gt;BACKUP_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/backups/app"&lt;/span&gt;
&lt;span class="nv"&gt;KEEP_DAYS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;7

&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;STAMP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; +%Y%m%d-%H%M%S&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-czf&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_DIR&lt;/span&gt;&lt;span class="s2"&gt;/data-&lt;/span&gt;&lt;span class="nv"&gt;$STAMP&lt;/span&gt;&lt;span class="s2"&gt;.tar.gz"&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SOURCE_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;

find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$BACKUP_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"data-*.tar.gz"&lt;/span&gt; &lt;span class="nt"&gt;-mtime&lt;/span&gt; +&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$KEEP_DAYS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-delete&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Backup completed: data-&lt;/span&gt;&lt;span class="nv"&gt;$STAMP&lt;/span&gt;&lt;span class="s2"&gt;.tar.gz"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;set -euo pipefail&lt;/code&gt; line is worth special attention. It makes the script stop on the first error instead of quietly continuing with a broken state, a habit that prevents many real outages. Practicing this kind of defensive scripting builds the discipline infrastructure work demands.&lt;/p&gt;

&lt;p&gt;Once you have a few scripts, containerize one of your services. Writing a Dockerfile forces you to think about dependencies, build layers, and the difference between what your application needs at build time and what it needs at runtime. Then set up a pipeline that builds and tests the image on every commit. Even a basic workflow teaches you how code moves from your editor into an environment others depend on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practicing Storage, Caching, and Data Flow
&lt;/h2&gt;

&lt;p&gt;Data is where many infrastructure projects get interesting. A log aggregator, a URL shortener with analytics, or a small message broker each raises questions about durability and consistency. What happens if the process crashes halfway through writing? How do you avoid duplicate records when a request is retried?&lt;/p&gt;

&lt;p&gt;Consider a caching layer. Even a simple in-memory cache with expiration rules forces decisions about eviction and memory limits. You can implement the logic yourself before reaching for a tool like Redis, then compare your version to the established one. The comparison teaches more than either approach alone, because you start to see why production caches make the trade-offs they do.&lt;/p&gt;

&lt;p&gt;Database work deserves similar attention. Write a small ingestion pipeline that reads a CSV file, validates each row, and loads valid records into PostgreSQL inside a transaction. Then intentionally feed it bad data and observe what happens. Learning to design for malformed input is one of the fastest ways to grow as an engineer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Your Limits Deliberately
&lt;/h2&gt;

&lt;p&gt;Infrastructure practice works best when you introduce controlled stress. Once a service runs, try to break it. Send it more requests than it can handle. Kill its process while it is writing. Disconnect the network mid-transfer. Watch how your code responds and what your logs reveal.&lt;/p&gt;

&lt;p&gt;These experiments turn abstract concepts like backpressure, retries with exponential backoff, and graceful shutdown into things you have actually seen. A retry loop that hammers a failing service can make an outage worse, while a loop with jitter and a maximum attempt count gives the system room to recover. Reading about this is useful. Watching your own system overwhelm itself, then fixing it, is far more memorable.&lt;/p&gt;

&lt;p&gt;Document each experiment in a short notes file. Record what you expected, what happened, and what you changed. Over months, that file becomes a personal playbook that reflects your growth more accurately than any certificate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing Projects That Match Your Goals
&lt;/h2&gt;

&lt;p&gt;With so many possible projects, selecting the right ones matters. If you are preparing for backend roles, prioritize APIs, databases, authentication, and job scheduling. If you lean toward DevOps, focus on provisioning, configuration management, monitoring dashboards, and incident response drills. Data engineers might build streaming pipelines and data quality checks. Each path has its own set of rewarding projects.&lt;/p&gt;

&lt;p&gt;Be honest about trade-offs, too. Building a full distributed system from scratch can take months and may teach you more about frustration than about engineering. Sometimes the better choice is a smaller project executed carefully, with clear tests and documentation. Depth beats breadth when you are still developing the habits that make infrastructure reliable.&lt;/p&gt;

&lt;p&gt;Finally, share your work. Publishing a project write-up, opening a pull request on an open-source monitoring tool, or presenting a postmortem for one of your own experiments invites feedback that sharpens your thinking. Other practitioners will spot assumptions you missed, and explaining your design forces clarity you might otherwise skip.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning Practice Into a Lasting Habit
&lt;/h2&gt;

&lt;p&gt;The phrase "73 ways to practice" can sound overwhelming, as if you need dozens of projects before you are ready. You do not. A handful of well-chosen builds, revisited and extended over time, will teach more than a long checklist completed in a rush. Pick one project this week, define what success looks like, and commit to improving it for a month.&lt;/p&gt;

&lt;p&gt;Infrastructure work rewards patience. The systems you admire in production were rarely built in a single attempt. They grew through repeated failures, careful monitoring, and small improvements. Your practice projects can follow the same path. Start with a script that checks a website, add logging, add retries, add a schedule, and eventually you will have built something that genuinely runs.&lt;/p&gt;

&lt;p&gt;The coding limits you discover along the way are not walls. They are a map of what to learn next. Keep building, keep breaking things on purpose, and keep writing down what you learn. That combination turns ordinary practice into real engineering skill.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>coding</category>
    </item>
    <item>
      <title>Debugging the Brain: How Code-Tracing Exercises Enhance Algorithmic Problem-Solving Skills</title>
      <dc:creator>Fuad Husnan</dc:creator>
      <pubDate>Tue, 13 Oct 2026 13:05:10 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/debugging-the-brain-how-code-tracing-exercises-enhance-algorithmic-problem-solving-skills-58o4</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/debugging-the-brain-how-code-tracing-exercises-enhance-algorithmic-problem-solving-skills-58o4</guid>
      <description>&lt;p&gt;Many programmers learn algorithms by reading solutions, nodding along, and moving on. The code looks clear, the logic seems obvious, and yet the same programmer often freezes when faced with a blank editor. Code-tracing exercises close that gap. By following a program line by line and predicting its state at each step, you train the mental model that algorithmic problem-solving depends on. This article explains why tracing works, how to practice it, and where it falls short.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Reading Code Is Not the Same as Understanding It
&lt;/h2&gt;

&lt;p&gt;Reading code is a passive activity. Your eyes move across familiar syntax, and your brain fills in the gaps with assumptions. A loop that looks correct on the page may hide an off-by-one error, and a recursive call may seem to return the right answer simply because you expect it to.&lt;/p&gt;

&lt;p&gt;Tracing forces active reasoning. You must decide, for every line, what the variables hold and what the program will do next. This slows you down, but it exposes the places where your mental model and the actual behavior diverge. Those divergences are exactly where bugs and misunderstandings live.&lt;/p&gt;

&lt;p&gt;Cognitive scientists who study expertise often describe this kind of deliberate, step-by-step reasoning as a core feature of skilled performance. Experts build detailed internal representations of how &lt;a href="https://repository.telkomuniversity.ac.id/pustaka/158853/systems-programming-in-unix-linux.html" rel="noopener noreferrer"&gt;systems&lt;/a&gt; behave, and tracing is one of the most direct ways to build those representations yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Worked Example: Tracing Binary Search
&lt;/h2&gt;

&lt;p&gt;Consider a classic binary search function with a subtle boundary issue. Before running it, trace it by hand.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;binary_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;low&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;low&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;low&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;target&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;mid&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;low&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;high&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mid&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;binary_search&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;   &lt;span class="c1"&gt;# Expected: 3
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;binary_search&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;   &lt;span class="c1"&gt;# Expected: -1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now trace the first call on paper. Create a small table with columns for &lt;code&gt;low&lt;/code&gt;, &lt;code&gt;high&lt;/code&gt;, &lt;code&gt;mid&lt;/code&gt;, and &lt;code&gt;nums[mid]&lt;/code&gt;, then fill it in one iteration at a time.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Iteration&lt;/th&gt;
&lt;th&gt;low&lt;/th&gt;
&lt;th&gt;high&lt;/th&gt;
&lt;th&gt;mid&lt;/th&gt;
&lt;th&gt;nums[mid]&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;5 &amp;lt; 7, so low = 3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;9 &amp;gt; 7, so high = 4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Match, return 3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The trace confirms the expected output. Now run the second call, searching for 4, and watch what happens when &lt;code&gt;low&lt;/code&gt; and &lt;code&gt;high&lt;/code&gt; converge. The loop exits and returns &lt;code&gt;-1&lt;/code&gt;, which is the correct result.&lt;/p&gt;

&lt;p&gt;The value of this exercise is not the answer itself. It is the habit of asking, at each step, "What is the state now, and why does the program move to the next state?" If you cannot fill in a row of the table with confidence, you have found a gap in your understanding, and that gap is what you should study.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tracing Surfaces Off-by-One Errors
&lt;/h2&gt;

&lt;p&gt;Tracing becomes especially powerful when you change the code slightly and predict the consequences. Suppose someone writes &lt;code&gt;high = len(nums) - 1&lt;/code&gt; and then changes the loop condition to &lt;code&gt;low &amp;lt;= high&lt;/code&gt; while keeping &lt;code&gt;high = mid&lt;/code&gt; in the else branch. The code may still work for many inputs, but for certain array sizes it can loop forever, because &lt;code&gt;mid&lt;/code&gt; no longer shrinks the search range.&lt;/p&gt;

&lt;p&gt;You would not discover this by skimming. You would discover it only by tracing a two-element array and noticing that &lt;code&gt;low&lt;/code&gt; and &lt;code&gt;high&lt;/code&gt; stop changing. This is a critical skill for algorithm interviews and production code alike: reasoning about boundaries and termination conditions is where many candidates and engineers struggle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Habit: A Practical Routine
&lt;/h2&gt;

&lt;p&gt;Tracing is most effective when it becomes a routine rather than an occasional exercise. A simple approach works well in practice.&lt;/p&gt;

&lt;p&gt;Start by choosing a small input, ideally one with three to five elements. Small inputs keep the trace manageable and make patterns visible. Next, write down the initial state of every variable before running any code. Then step through the program, updating your table after each line or loop iteration. Finally, compare your prediction with the actual output, and when they differ, investigate the gap rather than simply fixing the code.&lt;/p&gt;

&lt;p&gt;That last step matters most. When your prediction is wrong, the question is not "How do I make the test pass?" but "Which assumption did I get wrong?" Recording these mistakes in a notebook creates a personal catalog of recurring errors, and reviewing that catalog is one of the fastest ways to improve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting Tracing to Algorithmic Thinking
&lt;/h2&gt;

&lt;p&gt;Algorithmic problem-solving involves more than memorizing standard solutions. It requires recognizing the structure of a problem, selecting an approach, and reasoning about correctness and efficiency. Tracing contributes to each of these abilities in different ways.&lt;/p&gt;

&lt;p&gt;For recognition, repeatedly tracing algorithms such as two-pointer techniques, sliding windows, and depth-first search teaches you the shape each pattern takes over time. For correctness, tracing forces you to test invariants, the conditions that should hold throughout execution. If you can state an invariant for binary search, such as "the target, if present, lies within &lt;code&gt;low&lt;/code&gt; and &lt;code&gt;high&lt;/code&gt;," you can check whether each step preserves it. For efficiency, tracing a loop shows how the work shrinks or grows with input size, which makes complexity analysis more concrete.&lt;/p&gt;

&lt;p&gt;Many developers also find that tracing reduces anxiety during interviews. When you have practiced following unfamiliar code step by step, you have a reliable method to fall back on when you encounter an unfamiliar problem. Instead of guessing, you can simulate the approach on a small example and let the trace reveal whether it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations and Honest Trade-offs
&lt;/h2&gt;

&lt;p&gt;Code tracing is not a complete substitute for other practices. Hand tracing is slow, and it becomes impractical for long programs or those with many interacting components. Trace only the parts that matter, and use a debugger, print statements, or unit tests to verify the rest.&lt;/p&gt;

&lt;p&gt;There is also a risk of tracing only the cases you already expect to work. Deliberately choose edge cases: empty inputs, single elements, duplicates, and values outside the range. A trace that only covers the happy path can give false confidence.&lt;/p&gt;

&lt;p&gt;Finally, tracing builds understanding, but understanding must be applied. Pair tracing exercises with writing solutions from scratch, explaining your reasoning aloud, and solving new problems. The goal is to make the reasoning process automatic enough that it works under pressure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start Practicing Today
&lt;/h2&gt;

&lt;p&gt;Choose one algorithm you use regularly but do not fully understand. Write a small input on paper, trace the code for five minutes, and record where your prediction failed. Repeat this with a different algorithm the next day. Within a few weeks, you will notice that you read unfamiliar code more carefully, catch boundary errors earlier, and approach new problems with a clearer plan.&lt;/p&gt;

&lt;p&gt;Debugging the brain is not a mysterious process. It is the disciplined habit of making your assumptions visible and testing them against reality, one line at a time. Begin with a single trace, and let the results guide your practice.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>The AI Co-Pilot Dilemma: Does Code Generation Stifle Authentic Programming Practice?</title>
      <dc:creator>Fuad Husnan</dc:creator>
      <pubDate>Fri, 09 Oct 2026 13:45:45 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/the-ai-co-pilot-dilemma-does-code-generation-stifle-authentic-programming-practice-3lmk</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/the-ai-co-pilot-dilemma-does-code-generation-stifle-authentic-programming-practice-3lmk</guid>
      <description>&lt;p&gt;AI coding assistants now write boilerplate, suggest entire functions, and explain error messages in seconds. For many developers, that speed feels like a gift. For others, it raises an uncomfortable question: does code generation stifle authentic &lt;a href="https://journals.telkomuniversity.ac.id/jasmed/article/view/11260" rel="noopener noreferrer"&gt;programming&lt;/a&gt; practice? The honest answer is that it depends on how the tool is used, and the difference between a shortcut and a crutch is worth understanding before it shapes your career.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Question Matters
&lt;/h2&gt;

&lt;p&gt;Programming has always been a skill built through friction. You struggle with a loop that never terminates, you read documentation until a method signature finally makes sense, and you trace a bug through five files before spotting the missing return statement. That struggle is not wasted time. It is how mental models form.&lt;/p&gt;

&lt;p&gt;When a tool removes that friction, the risk is not that developers suddenly forget how to code. The risk is quieter. Someone accepts a generated solution they do not fully understand, ships it, and later cannot reason about why it fails under load. The code works, but the developer's understanding does not grow.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Case for Code Generation
&lt;/h2&gt;

&lt;p&gt;It would be unfair to treat AI assistance as purely harmful. Experienced engineers often use these tools to skip the parts of their work that never required deep thought, such as writing test scaffolding, converting data formats, or remembering the exact syntax of a library they use twice a year.&lt;/p&gt;

&lt;p&gt;Used this way, the assistant functions like a fast reference manual that can also draft a first attempt. That frees attention for architecture, edge cases, and the decisions that actually matter. A developer who already understands the problem can evaluate a generated answer quickly, spot the flaw, and move on. In that setting, the tool amplifies existing skill rather than replacing it.&lt;/p&gt;

&lt;p&gt;Beginners can benefit too, but the benefit depends on what they do next. Reading a working example and then rewriting it from memory builds recall. Accepting the example and moving on builds dependence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Learning Breaks Down
&lt;/h2&gt;

&lt;p&gt;The problem appears when the generated output bypasses the thinking the task was meant to require. Consider a common scenario. A learner needs to find the first non-repeating character in a string. Instead of working through the logic, they request a complete solution and paste it in. The function passes the test case, and the lesson is lost.&lt;/p&gt;

&lt;p&gt;Here is the kind of code an assistant might produce for that task:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;first_unique_char&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="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Counter&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&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;index&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;


&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;first_unique_char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;leetcode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# 0
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;first_unique_char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;aabb&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;      &lt;span class="c1"&gt;# -1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This solution is correct and readable. The concern is not the code itself. The concern is what the learner did not do. They never decided to count occurrences first, never considered why a second pass over the string is necessary, and never tested an empty input.&lt;/p&gt;

&lt;p&gt;A more productive approach is to write the first version yourself, even if it is clumsy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;first_unique_char&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="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&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;appears_again&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;and&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;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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;j&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
                &lt;span class="n"&gt;appears_again&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
                &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;appears_again&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;i&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This version is slower, and its performance is worse on long inputs. But writing it forces you to confront the problem directly. Once it works, you can ask the assistant to propose an optimized version and compare the two. Now the tool is teaching you rather than thinking for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Healthy Workflow
&lt;/h2&gt;

&lt;p&gt;Developers who use AI assistance well tend to follow a few informal habits. None of them requires rejecting the tools entirely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Attempt First, Then Ask
&lt;/h3&gt;

&lt;p&gt;Before requesting generated code, spend a short, defined period working on the problem. Write pseudocode, sketch the data flow, or draft a failing test. This protects the moment of struggle where understanding forms. If you are still stuck after that effort, ask for a hint rather than a full solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Explain What You Accept
&lt;/h3&gt;

&lt;p&gt;Treat every suggestion as a claim that needs verification. Before keeping a generated function, be able to explain its time complexity, its failure cases, and why it chose one data structure over another. If you cannot explain it, you have not finished reviewing it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write Tests That Reflect Your Understanding
&lt;/h3&gt;

&lt;p&gt;Tests are a strong check on comprehension because they require you to specify expected behavior in your own terms. Writing tests before or alongside generated code makes it harder to accept something that quietly does the wrong thing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reproduce Without Assistance Regularly
&lt;/h3&gt;

&lt;p&gt;Schedule occasional sessions where you solve problems with no tools at all. Code katas, small algorithm exercises, or rebuilding a previous project from memory all keep fundamental skills active. Think of it the way a musician practices scales even after years of performing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Employers and Teams Should Consider
&lt;/h2&gt;

&lt;p&gt;The question is not only individual. Engineering teams shape how assistance is used. Code review that focuses only on whether code passes tests can miss whether the author understands it. Mentors can ask junior developers to walk through generated solutions line by line. Teams can also distinguish between tasks where generation is appropriate, such as repetitive configuration, and tasks where the design should remain human-led, such as security-sensitive authentication logic or core domain models.&lt;/p&gt;

&lt;p&gt;Organizations that measure productivity only by lines shipped may accidentally reward the behavior that weakens learning. Measuring review quality, incident understanding, and the ability of engineers to debug unfamiliar code offers a more accurate picture.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Trade-Off
&lt;/h2&gt;

&lt;p&gt;AI co-pilots change where effort goes. They reduce the cost of producing code and increase the importance of judging it. That shift is real, and it does reward a different set of skills: specification, critical reading, testing, and knowing when a generated answer is wrong.&lt;/p&gt;

&lt;p&gt;Still, judgment is not a substitute for foundations. A developer who has never struggled with recursion will have a harder time recognizing when a generated recursive function overflows the stack. The foundations are what make the judgment possible.&lt;/p&gt;

&lt;p&gt;So the dilemma is less about whether to use the tools and more about when. Use them to accelerate work you already understand, to explore alternatives after you have made an attempt, and to fill gaps you have chosen to fill. Be cautious when they replace the stage where you are supposed to be learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Keep the Struggle Worth Having
&lt;/h2&gt;

&lt;p&gt;AI coding assistants will not disappear, and refusing to learn them would be its own mistake. The question is whether you remain the author of your work. Start with an attempt, verify what you accept, test your understanding, and practice without assistance on purpose. Developers who do this will get the speed of generation without giving up the depth that makes them valuable.&lt;/p&gt;

&lt;p&gt;If you are building your own practice routine, pick one small problem this week and solve it without help. Then compare your version with the assistant's. The gap between the two is where your learning is.&lt;/p&gt;

</description>
      <category>vibecoding</category>
      <category>programming</category>
    </item>
    <item>
      <title>Why Reading Other People's Code Is the Most Underrated Programming Practice</title>
      <dc:creator>Fuad Husnan</dc:creator>
      <pubDate>Fri, 09 Oct 2026 13:43:28 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/why-reading-other-peoples-code-is-the-most-underrated-programming-practice-2177</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/why-reading-other-peoples-code-is-the-most-underrated-programming-practice-2177</guid>
      <description>&lt;p&gt;Reading other people's code is one of the most valuable habits a developer can build, yet it rarely gets the attention it deserves. Most &lt;a href="https://it.telkomuniversity.ac.id/category/blogs/coding-programming/" rel="noopener noreferrer"&gt;programming&lt;/a&gt; education focuses on writing: learning syntax, building projects, and solving problems from scratch. Reading code receives far less credit, even though professional developers spend a large share of their working hours inside existing codebases. This article explains why the skill matters, how to approach unfamiliar code without getting overwhelmed, and how to turn each reading session into lasting improvement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Reading Code Matters More Than Writing It
&lt;/h2&gt;

&lt;p&gt;Most software is not built from a blank page. It grows over years, passed between teams, patched under deadline pressure, and shaped by decisions that made sense at the time. A new developer joining a project inherits thousands or millions of lines written by people they may never meet. Their first useful contribution almost always depends on understanding what is already there.&lt;/p&gt;

&lt;p&gt;Reading code also trains judgment in a way that writing alone cannot. When you write a function, you see only your intent. When you read someone else's function, you see their intent filtered through their constraints, their knowledge at the time, and their tradeoffs. You start to notice why a loop was chosen over a recursive call, why a cache was added in one place and not another, or why a seemingly redundant check exists. Over time, that exposure builds a sense of what good structure feels like, which makes your own code clearer.&lt;/p&gt;

&lt;p&gt;There is also a debugging advantage. Many production problems live at the boundaries between components, where one author's assumptions meet another's. Developers who read widely tend to form mental models of how systems fit together, so they can trace a failure to its source faster. They know where to look because they have seen similar patterns before.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Obstacles and How to Work Through Them
&lt;/h2&gt;

&lt;p&gt;Unfamiliar code can feel intimidating. Variable names may be cryptic, documentation may be missing or outdated, and the project may use conventions you have never encountered. Many developers respond by giving up after a few minutes and asking a colleague, which is sometimes the right move but often skips the learning.&lt;/p&gt;

&lt;p&gt;A more productive approach starts with a clear question. Instead of trying to understand an entire repository, pick one behavior you need to know about. Perhaps you want to understand how user sessions expire, or where a particular configuration value gets read. A narrow question gives your reading direction and prevents the feeling of drowning in unrelated detail.&lt;/p&gt;

&lt;p&gt;Start from the outside in. Look at the entry point, whether that is a main function, a route handler, or a command-line interface. Follow the path a request or action takes through the system, noting each function it calls without yet worrying about every line inside them. Tools help here. A global search for a function name, a call-graph viewer, or your editor's "go to definition" feature can turn an hour of guessing into a few minutes of tracing.&lt;/p&gt;

&lt;p&gt;Keep a running note of what you learn, even if it is rough. Writing down a summary such as "this module validates input, then delegates to the payment service" forces you to check your understanding and gives future readers a starting point. If you find something confusing, record the question. Many confusing sections become clear once you know what they are supposed to do, and your notes will remind you where to return.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Example: Tracing an Unknown Function
&lt;/h2&gt;

&lt;p&gt;Consider a common situation. You are working on a web service and notice that some API responses are cached, but you cannot find where the cache is set. Rather than reading every file, you can use a short script to search for the cache key pattern and see where it appears.&lt;br&gt;
&lt;/p&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;re&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_usages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Print every line in the project that matches a regex pattern.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pattern&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;rglob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;splitlines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;UnicodeDecodeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;lineno&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;lineno&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;find_usages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./src&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache\.(set|get)\(&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;p&gt;Running this quickly reveals every place the cache is read or written. From there, you can open each file, read the surrounding logic, and build your understanding one connection at a time. The script itself is simple, but the habit it represents is important: let a small, specific question guide your exploration instead of wandering through the code without direction.&lt;/p&gt;

&lt;p&gt;Version control history offers another powerful lens. The commands below show who last changed a file and why, which often reveals the reasoning behind an odd design choice.&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;# Show the commit history for a specific file&lt;/span&gt;
git log &lt;span class="nt"&gt;--follow&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; src/services/cache.py

&lt;span class="c"&gt;# Show who last changed each line, with commit summaries&lt;/span&gt;
git blame &lt;span class="nt"&gt;-w&lt;/span&gt; src/services/cache.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Commit messages frequently explain constraints that the code itself does not. A line that looks unnecessary may have been added to fix a bug that appeared only under heavy load. Reading history turns a puzzling line into a story you can evaluate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading Code Makes You a Better Reviewer and Teammate
&lt;/h2&gt;

&lt;p&gt;Code review is one of the clearest places where reading skill pays off. A reviewer who understands how a system is structured can spot changes that break hidden assumptions, even when the modified code looks correct in isolation. A reviewer who reads carefully also asks better questions, which helps authors improve their work instead of simply approving or rejecting it.&lt;/p&gt;

&lt;p&gt;Reading widely also improves communication. When you have seen many approaches to the same problem, you can explain trade-offs with concrete references rather than abstract opinions. Teammates tend to trust developers who understand the broader codebase, and that trust makes collaboration smoother. Over time, you become someone others consult when they are stuck, which is one of the most respected roles on any engineering team.&lt;/p&gt;

&lt;p&gt;Open source projects offer a free and enormous library for this practice. Choose a well-maintained project in a language or domain you care about, read its tests before its implementation, and observe how the maintainers name things and organize modules. Tests in particular act as executable documentation, showing expected behavior with concrete examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Habit Over Time
&lt;/h2&gt;

&lt;p&gt;Like any skill, code reading improves with regular practice. A few focused sessions each week will teach you more than a single marathon weekend. Set aside time to read something outside your current work, such as a library you use or a tool you admire, and try to explain one piece of it to yourself in plain language.&lt;/p&gt;

&lt;p&gt;It also helps to read with a purpose beyond curiosity. Ask what you would have done differently, and why the original author might have chosen another path. Sometimes you will conclude that their approach was better. Other times you will find a legitimate tradeoff you had not considered. Both outcomes sharpen your judgment.&lt;/p&gt;

&lt;p&gt;Be patient with yourself. Experienced developers were once beginners who struggled to follow unfamiliar code. The difference is that they kept reading, kept asking questions, and kept building mental models until the patterns became familiar. Each codebase you read adds to that library of patterns, making the next one easier to understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Make Reading a Deliberate Part of Your Practice
&lt;/h2&gt;

&lt;p&gt;Writing code gets most of the attention in programming, but reading code is where much of the real learning happens. It builds judgment, speeds up debugging, improves code reviews, and makes you a stronger collaborator. You do not need a special tool or a large block of time to begin. Pick one open source project or one unfamiliar module in your current codebase this week, choose a narrow question, and trace the answer using search, history, and careful notes.&lt;/p&gt;

&lt;p&gt;If this approach helped you, try it on a project you have been meaning to understand and share what you discovered with a colleague. Teaching what you have read is one of the fastest ways to make it stick, and it often starts the kind of conversations that lead to better software for everyone.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>python</category>
    </item>
    <item>
      <title>The Feedback Loop: How Code Reviews Accelerate Your Programming Practice</title>
      <dc:creator>Fuad Husnan</dc:creator>
      <pubDate>Fri, 09 Oct 2026 13:40:22 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/the-feedback-loop-how-code-reviews-accelerate-your-programming-practice-4gd8</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/the-feedback-loop-how-code-reviews-accelerate-your-programming-practice-4gd8</guid>
      <description>&lt;p&gt;Code reviews are often treated as a gate, a hurdle between writing code and merging it. That view misses their real value. Done well, code reviews create a tight feedback loop that shortens the distance between a mistake and its correction, and that loop is one of the fastest ways to grow as a programmer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Feedback Speed Matters More Than Feedback Volume
&lt;/h2&gt;

&lt;p&gt;Most developers learn by doing, but doing alone can reinforce bad habits. If you write a function, test it against your own assumptions, and move on, you never discover the edge case you overlooked. Learning stalls because nobody points out the gap.&lt;/p&gt;

&lt;p&gt;A code review closes that gap quickly. A reviewer reads your change with fresh eyes, notices the unhandled null, questions the naming, or asks why a loop runs twice. The comment arrives while the logic is still fresh in your mind, which makes the lesson stick. Feedback given days later, or never, loses most of its teaching power.&lt;/p&gt;

&lt;p&gt;Speed matters more than the total number of comments. Ten precise comments on a single pull request teach more than fifty vague remarks spread across a month. The goal is a short cycle: write, get a specific response, adjust, and move on.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Healthy Review Loop Looks Like
&lt;/h2&gt;

&lt;p&gt;A healthy loop has three properties. The changes are small enough to understand in one sitting. The feedback is specific enough to act on. The author treats the comments as information rather than as a verdict on their ability.&lt;/p&gt;

&lt;p&gt;Small changes are the foundation. A pull request that touches forty files invites superficial approval, because no reviewer can hold that much context at once. A change of a few hundred lines, focused on one purpose, gets a careful read. Splitting work into smaller pieces is often the single most effective improvement a team can make to its review process.&lt;/p&gt;

&lt;p&gt;Specific feedback is the second pillar. "This could be cleaner" gives the author nothing to do. "This function mixes parsing and database writes, so splitting them would make the parser testable without a database" gives a clear next step. Authors should ask for that level of detail when a comment is unclear.&lt;/p&gt;

&lt;p&gt;The third property is psychological, and it is harder to engineer. Authors who feel defensive stop asking questions and start defending their code. Reviewers who feel their comments will be taken personally soften their feedback until it stops being useful. Both sides benefit when everyone assumes the goal is a better product and a better developer, not a win in an argument.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading Code Like a Reviewer
&lt;/h2&gt;

&lt;p&gt;Reviewing is a skill you can practice on purpose. Start by reading the description or ticket before the diff. Knowing the intent makes it easier to judge whether the code achieves it. Then review the change at the level of behavior first and style second. Ask whether the code does what it claims, then whether it handles failure, then whether it is readable.&lt;/p&gt;

&lt;p&gt;You can also use the command line to get your bearings before opening the review tool. The following commands show a compact summary of what changed on a feature branch compared with main:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch origin
git diff origin/main...feature/invoice-export &lt;span class="nt"&gt;--stat&lt;/span&gt;
git diff origin/main...feature/invoice-export &lt;span class="nt"&gt;--&lt;/span&gt; src/invoice/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first command lists the files touched and how many lines changed in each. The second narrows the diff to one directory, which helps you focus on the module that matters most. Reviewing in these slices keeps attention sharp.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning From a Concrete Comment
&lt;/h2&gt;

&lt;p&gt;Review comments become most valuable when you treat them as small lessons. Consider a common issue in Python: a mutable default argument. A reviewer might flag this function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt;
    &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;new&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tags&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The problem is subtle. Python evaluates the default list once, when the function is defined, so every call that omits &lt;code&gt;tags&lt;/code&gt; shares the same list. The first user's tags leak into the second user's record. A reviewer explaining this in one sentence turns a bug into a durable rule. The corrected version looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;new&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tags&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A good author then goes one step further and writes a test that locks the behavior in place. Here is a pytest case that confirms two calls never share state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;add_user&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_add_user_does_not_share_tags&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;add_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Ana&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;second&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;add_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Budi&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tags&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;second&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tags&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;p&gt;This small exchange contains the whole loop. A mistake appeared, a reviewer named it, the author fixed it, and a test now prevents its return. Repeat that cycle across hundreds of reviews, and the codebase improves, and so does the developer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing Code That Is Easy to Review
&lt;/h2&gt;

&lt;p&gt;Reviewing is a two-sided activity, and authors shape how easy their work is to evaluate. Clear commit messages explain why a change exists, not only what it does. A pull request description that states the problem, the approach, and the areas that need the most scrutiny saves reviewers considerable time.&lt;/p&gt;

&lt;p&gt;Authors can also run their own review before asking for anyone else's. Reading your diff from top to bottom, as if you had never seen it, often reveals leftover debug statements, unclear names, and commented-out code. This self-review takes minutes and frequently catches problems that would otherwise consume a full review round.&lt;/p&gt;

&lt;p&gt;Tests deserve special attention. A change that comes with tests shows the author's intent and gives the reviewer a way to verify behavior without running everything by hand. When a reviewer can read the test names and understand the expected behavior, the review becomes much faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Pitfalls and Trade-offs
&lt;/h2&gt;

&lt;p&gt;Code reviews are not free. They add waiting time, and a slow review queue can block progress as much as a bad release. Teams that treat review as a bottleneck often rush it, which defeats the purpose. The remedy is to set expectations for response time and to keep changes small so that reviews stay quick.&lt;/p&gt;

&lt;p&gt;Another pitfall is nitpicking. When reviewers spend their energy on formatting that a linter could enforce, they neglect the questions that matter, such as correctness and design. Automating style checks frees reviewers to focus on logic, and it reduces the friction that makes reviews feel personal.&lt;/p&gt;

&lt;p&gt;Finally, reviews can become a one-way street where senior developers critique juniors without learning anything themselves. The best review cultures encourage questions from everyone. A reviewer who asks, "Why did you choose this data structure?" may discover a better approach, and the author gains a chance to explain their reasoning. Both outcomes strengthen the team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turning Review Lessons Into Lasting Habits
&lt;/h2&gt;

&lt;p&gt;Improvement compounds when you capture what you learn. Keep a short personal log of recurring review comments. If the same issue appears three times, it deserves a habit, a checklist item, or a lint rule. Over several months, that log reveals your blind spots with precision.&lt;/p&gt;

&lt;p&gt;Share the patterns you notice with your team. A brief note in a retrospective, or a short document of common review findings, helps everyone avoid repeating the same mistakes. This turns individual feedback into collective knowledge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Make the Loop Work for You
&lt;/h2&gt;

&lt;p&gt;Code reviews accelerate &lt;a href="https://bif-sby.telkomuniversity.ac.id/pemrograman-fondasi-utama-dalam-dunia-informatika-modern/" rel="noopener noreferrer"&gt;programming&lt;/a&gt; practice because they shorten the feedback loop. A specific comment, delivered while the work is fresh, teaches more than hours of solitary trial and error. Small changes, precise feedback, and a respectful tone turn that loop into a reliable engine for growth.&lt;/p&gt;

&lt;p&gt;Start with your next pull request. Write a clear description, keep the change focused, and review your own diff before anyone else sees it. When a reviewer leaves a comment, ask one follow-up question so you understand the reasoning, not only the fix. If your team does not yet have a review guideline, propose a one-page version this week and invite others to refine it. Your future self will thank you for every loop you close.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>codequality</category>
    </item>
    <item>
      <title>Designing the Perfect Curriculum: Balancing Agents and Hands-On Code Practice</title>
      <dc:creator>Fuad Husnan</dc:creator>
      <pubDate>Fri, 09 Oct 2026 13:36:36 +0000</pubDate>
      <link>https://dev.to/fuadhusnan_f44f3e13/designing-the-perfect-curriculum-balancing-agents-and-hands-on-code-practice-364b</link>
      <guid>https://dev.to/fuadhusnan_f44f3e13/designing-the-perfect-curriculum-balancing-agents-and-hands-on-code-practice-364b</guid>
      <description>&lt;p&gt;Every &lt;a href="https://it.telkomuniversity.ac.id/oop-vs-functional-programming/" rel="noopener noreferrer"&gt;programming&lt;/a&gt; instructor now faces the same question: should students learn with AI coding agents, or should they learn by writing code themselves? The honest answer is both, but the balance matters. A curriculum that leans too far toward agents produces learners who can generate code but cannot debug it. A curriculum that ignores agents prepares students for a workplace that no longer exists. Designing the right mix is the central challenge of modern programming education.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Old Curriculum Model No Longer Fits
&lt;/h2&gt;

&lt;p&gt;Traditional programming courses were built around a simple sequence: explain a concept, show an example, and ask the student to reproduce it. That model assumed the bottleneck was typing syntax and remembering APIs. Documentation was slow to search, and the friction of looking things up was part of the learning process.&lt;/p&gt;

&lt;p&gt;Agents have removed much of that friction. A student can describe a function in plain English and receive working code in seconds. This is powerful, but it also hides the thinking that code was supposed to teach. When the agent writes the loop, the student may never learn why the loop needed a boundary check.&lt;/p&gt;

&lt;p&gt;The goal of a modern curriculum is therefore not to ban agents or to pretend they do not exist. The goal is to structure learning so that students gain the judgment to use agents well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separate Learning Stages From Production Stages
&lt;/h2&gt;

&lt;p&gt;One practical approach is to divide every unit into two phases. The first phase is the learning stage, where agents are restricted or turned off. Students write code by hand, make mistakes, and build a mental model of how the language works. The second phase is the production stage, where students use agents to build something larger, faster, and more realistic.&lt;/p&gt;

&lt;p&gt;This separation protects the foundation. Students cannot evaluate agent output if they have never written the underlying logic themselves. A learner who has hand-coded a binary search will immediately notice when an agent returns a version with an off-by-one error.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Simple Example for the Learning Stage
&lt;/h3&gt;

&lt;p&gt;Consider a beginner exercise where students implement a function that finds the largest number in a list. Writing it manually forces them to think about initialization and iteration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_largest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The list is empty.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;largest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;largest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;largest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;largest&lt;/span&gt;


&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;find_largest&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;  &lt;span class="c1"&gt;# Output: 19
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The empty-list check is a detail that agents often include, but a student who writes it personally will understand why it matters. That understanding is what allows them to catch the same omission in code they did not write.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make Verification a Core Skill
&lt;/h2&gt;

&lt;p&gt;If agents are going to write code, students must learn to verify it. This is one of the most valuable skills a curriculum can teach, and it is often neglected. Verification includes reading code critically, writing tests, and checking edge cases.&lt;/p&gt;

&lt;p&gt;A strong assignment might give students an agent-generated function and ask them to find its weaknesses. The student then writes tests that expose the flaws. This turns the agent from an answer machine into a source of material for critical thinking.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing Agent Output
&lt;/h3&gt;

&lt;p&gt;Here is a short test file a student might write to check an agent-generated sorting function:&lt;br&gt;
&lt;/p&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;unittest&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sort_scores&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Assume this function was produced by an agent.
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reverse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestSortScores&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unittest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_sorts_descending&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sort_scores&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_handles_empty_list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sort_scores&lt;/span&gt;&lt;span class="p"&gt;([]),&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_handles_duplicates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;sort_scores&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;unittest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tests like these teach students that correctness must be demonstrated, not assumed. They also build the habit of thinking about edge cases before a bug reaches production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structure Projects Around Real Problems
&lt;/h2&gt;

&lt;p&gt;Isolated exercises build skill, but projects build judgment. A curriculum should include projects that resemble real work: a small API, a data pipeline, or a web application with a database. These projects are large enough that no agent can produce a finished result in one prompt, which forces students to plan, decompose, and integrate.&lt;/p&gt;

&lt;p&gt;Projects also reveal the limits of agents. Students quickly discover that agents lose context in large codebases, invent library functions that do not exist, and make architectural choices that conflict with earlier decisions. Learning to notice and correct these problems is a core professional skill.&lt;/p&gt;

&lt;h3&gt;
  
  
  Teaching Students to Write Good Prompts
&lt;/h3&gt;

&lt;p&gt;Agents respond to clear instructions, and prompting is now part of software work. Students should practice breaking a task into specific, testable requests. A vague prompt like "build a login system" produces unpredictable code. A precise prompt that specifies the framework, the storage method, and the error behavior produces something a student can review and improve.&lt;/p&gt;

&lt;p&gt;Instructors can grade prompts alongside code. A well-written prompt that produces correct, readable code deserves recognition, while a sloppy prompt that produces a fragile result shows where the student needs more practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Assess Understanding, Not Just Output
&lt;/h2&gt;

&lt;p&gt;Assessment is where many curricula fail. If grades depend only on the final working program, students will optimize for the result rather than the learning. Agents make this problem worse, because a student can submit a polished project without understanding any of it.&lt;/p&gt;

&lt;p&gt;To address this, instructors can add short oral reviews or live code walkthroughs. Asking a student to explain one function, modify it on the spot, or predict how it behaves under a new input quickly reveals whether the knowledge is real. Written reflections on design decisions also help, especially when students explain why they rejected an agent's suggestion.&lt;/p&gt;

&lt;p&gt;Assessment should reward three things: working code, clear reasoning, and the ability to explain both. When all three are present, the balance between agents and manual practice tends to take care of itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a Progression Over the Semester
&lt;/h2&gt;

&lt;p&gt;A balanced curriculum changes over time. Early units should emphasize hand-coding almost exclusively, with agents introduced only as a reference tool for reading documentation. Middle units can introduce agents for boilerplate and repetitive tasks while keeping core logic manual. Final projects can give students full access to agents, with the expectation that they justify every significant decision.&lt;/p&gt;

&lt;p&gt;This progression mirrors how professional developers grow. A junior engineer needs to understand the fundamentals before delegating work effectively, and a senior engineer uses agents constantly but still reviews everything carefully.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Mistakes to Avoid
&lt;/h2&gt;

&lt;p&gt;Several pitfalls appear repeatedly in programming courses that integrate agents. The first is banning agents entirely, which prepares students poorly for current workplaces. The second is allowing unrestricted use from day one, which skips the foundation students need. The third is grading only the final output, which rewards copying over comprehension.&lt;/p&gt;

&lt;p&gt;A fourth mistake is treating agent output as authoritative. Instructors should explicitly teach that agents can be confidently wrong, and that the responsibility for correctness always rests with the developer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: Designing a Curriculum That Lasts
&lt;/h2&gt;

&lt;p&gt;The perfect curriculum is not a fixed ratio of agents to manual coding. It is a deliberate structure that builds foundations first, introduces agents as tools for productivity, and assesses understanding throughout. Students who learn this way can write code by hand, verify code they did not write, and direct agents toward useful results.&lt;/p&gt;

&lt;p&gt;If you are designing a programming course or updating an existing one, start small. Choose one unit, separate its learning and production stages, and add a verification exercise. Then observe how students respond and adjust from there. If you would like a sample syllabus or a set of verification exercises tailored to your course level, share your learning goals and I can help you draft them.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>vibecoding</category>
    </item>
  </channel>
</rss>
