<?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: Suraj Nandan</title>
    <description>The latest articles on DEV Community by Suraj Nandan (@suraj_nandan).</description>
    <link>https://dev.to/suraj_nandan</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%2F3859390%2F61fb1878-a099-48c3-a66a-2efc6ed32a99.jpeg</url>
      <title>DEV Community: Suraj Nandan</title>
      <link>https://dev.to/suraj_nandan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/suraj_nandan"/>
    <language>en</language>
    <item>
      <title>Read other people's code: a habit I'm trying to build</title>
      <dc:creator>Suraj Nandan</dc:creator>
      <pubDate>Sat, 14 Nov 2026 03:30:00 +0000</pubDate>
      <link>https://dev.to/suraj_nandan/read-other-peoples-code-a-habit-im-trying-to-build-1675</link>
      <guid>https://dev.to/suraj_nandan/read-other-peoples-code-a-habit-im-trying-to-build-1675</guid>
      <description>&lt;p&gt;Most of my learning is from writing my own code. That means I mostly see my own habits, including the bad ones.&lt;/p&gt;

&lt;p&gt;Reading other people's code is the other half of the skill, and the half I practise less. This post is a method I'm trying to turn into a routine: how to pick something to read, how to read it without drowning, and how to turn that into a first contribution. I'm presenting it as a plan, not a record of achievement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why reading matters
&lt;/h2&gt;

&lt;p&gt;Writers become better by reading. Programmers are the same, with extra reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You see choices you wouldn't have made&lt;/strong&gt;, and sometimes they're better.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You learn how real projects handle messy cases&lt;/strong&gt;: errors, versions, odd inputs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You get humility.&lt;/strong&gt; Most mature codebases are less tidy than their READMEs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You prepare for the job.&lt;/strong&gt; Most professional work is reading and changing code that someone else wrote.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What not to do
&lt;/h2&gt;

&lt;p&gt;The classic mistake is opening a large repository and trying to understand all of it. You'll be lost in an hour and quit. Reading code is not like reading a book from page one.&lt;/p&gt;

&lt;h2&gt;
  
  
  A method that works for me
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Pick a small library you already use
&lt;/h3&gt;

&lt;p&gt;Familiarity gives you a hook: you know what the library &lt;em&gt;does&lt;/em&gt;, so you can read for &lt;em&gt;how&lt;/em&gt;. Small matters, since a few hundred lines can be understood completely.&lt;/p&gt;

&lt;p&gt;Good candidates: a tiny utility (a debounce helper, an ID generator, a small state library), or a single plugin.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Read the README and the tests first
&lt;/h3&gt;

&lt;p&gt;Tests are executable documentation. They show how the author expects the code to be used and which edge cases they cared about. A test file often explains a module faster than the module itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Find the entry point
&lt;/h3&gt;

&lt;p&gt;Where does the main function live? Look at &lt;code&gt;package.json&lt;/code&gt; (&lt;code&gt;main&lt;/code&gt;, &lt;code&gt;exports&lt;/code&gt;), then open that file.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Read one file, not the whole repo
&lt;/h3&gt;

&lt;p&gt;Pick the file that does the core job and read it top to bottom. Ignore everything else for now.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Trace one feature end to end
&lt;/h3&gt;

&lt;p&gt;Choose a single behaviour ("what happens when I call &lt;code&gt;debounce(fn, 200)&lt;/code&gt;?") and follow it through the code, writing down each hop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight coffeescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;debounce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;returns&lt;/span&gt; &lt;span class="nx"&gt;wrapped&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;wrapped&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;clears&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt; &lt;span class="nx"&gt;pending&lt;/span&gt; &lt;span class="nx"&gt;timer&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sets&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;`&lt;/span&gt;&lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="o"&gt;`&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt;
  &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt; &lt;span class="nx"&gt;fires&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;calls&lt;/span&gt; &lt;span class="nx"&gt;fn&lt;/span&gt; &lt;span class="nx"&gt;with&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;latest&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;arguments&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Writing the trace in your own words is what turns reading into understanding.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Ask "why is it structured this way?"
&lt;/h3&gt;

&lt;p&gt;For every surprising decision, form a guess: why a Map instead of an object? Why is this check first? Then look for evidence (a comment, a commit message, an issue). The gap between your guess and the truth is where you learn.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Run it and break it
&lt;/h3&gt;

&lt;p&gt;Add a &lt;code&gt;console.log&lt;/code&gt;, change a line, see what fails. Reading with a running debugger beats reading alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  A short worked example
&lt;/h2&gt;

&lt;p&gt;Take a small debounce utility. In about thirty lines you can learn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;debounce&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;ReturnType&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&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="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Questions this raises, each a mini-lesson:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why is &lt;code&gt;t&lt;/code&gt; declared outside the returned function? (It's closure state shared across calls.)&lt;/li&gt;
&lt;li&gt;What happens if the component unmounts before the timer fires? (A cleanup/cancel method is missing.)&lt;/li&gt;
&lt;li&gt;Should the first call run immediately (a "leading" option)?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mature libraries answer those questions in code, which is exactly what you learn by reading them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading code you'll have to change
&lt;/h2&gt;

&lt;p&gt;At work, the goal is usually different: find where to make a change safely. A workflow for that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reproduce the behaviour.&lt;/li&gt;
&lt;li&gt;Search for a distinctive string from the UI or log message.&lt;/li&gt;
&lt;li&gt;Follow it to the function that produces it.&lt;/li&gt;
&lt;li&gt;Read the tests around that function.&lt;/li&gt;
&lt;li&gt;Make the smallest possible change, and run the tests.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  From reading to contributing
&lt;/h2&gt;

&lt;p&gt;Reading becomes much more useful once it produces something. Small, realistic first contributions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fix a typo or a confusing sentence in the docs.&lt;/li&gt;
&lt;li&gt;Add a missing test for an edge case you noticed.&lt;/li&gt;
&lt;li&gt;Improve an error message.&lt;/li&gt;
&lt;li&gt;Reproduce a bug someone reported and add what you found.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open the issue first for anything beyond a typo, read the contributing guide, and keep the change small. A tiny accepted pull request teaches more about a project's workflow than weeks of reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  The next step I want to take
&lt;/h2&gt;

&lt;p&gt;I want to open a small pull request on a project I use. I haven't made that a regular habit yet, so I'm saying it here to commit. If it happens I'll write up what I learned, including anything that went wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  A weekly routine
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Day&lt;/th&gt;
&lt;th&gt;Activity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mon&lt;/td&gt;
&lt;td&gt;Pick a small library; read the README and tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tue&lt;/td&gt;
&lt;td&gt;Read the core file; write the trace for one feature&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wed&lt;/td&gt;
&lt;td&gt;Run and break it; note three questions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Thu&lt;/td&gt;
&lt;td&gt;Look for the answers (issues, commits, docs)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fri&lt;/td&gt;
&lt;td&gt;Write five lines of what you learned&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Tools that make reading code easier
&lt;/h2&gt;

&lt;p&gt;You don't have to hold everything in your head. A few commands do a lot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Find where something is used&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rg &lt;span class="s2"&gt;"transition_transaction"&lt;/span&gt;          &lt;span class="c"&gt;# fast text search (ripgrep)&lt;/span&gt;
git &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"transition_transaction"&lt;/span&gt;  &lt;span class="c"&gt;# search tracked files&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Find when a line or string appeared&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;-S&lt;/span&gt;&lt;span class="s2"&gt;"SKIP LOCKED"&lt;/span&gt; &lt;span class="nt"&gt;--oneline&lt;/span&gt;    &lt;span class="c"&gt;# commits that added or removed that string&lt;/span&gt;
git blame &lt;span class="nt"&gt;-L&lt;/span&gt; 40,70 src/claim.ts      &lt;span class="c"&gt;# who last changed lines 40 to 70, and in which commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;See the history of one file&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--follow&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; src/claim.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;See what a commit changed, and why&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git show &amp;lt;commit&amp;gt;                     &lt;span class="c"&gt;# the diff plus the message&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Commit messages and linked issues are often where the &lt;em&gt;reasoning&lt;/em&gt; lives, which the code alone can't tell you.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to read a pull request
&lt;/h2&gt;

&lt;p&gt;Reviewing someone's change is reading practice with a built-in goal.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read the description first.&lt;/strong&gt; What is this supposed to do?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read the tests.&lt;/strong&gt; They show intended behaviour.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skim the file list.&lt;/strong&gt; Does the shape of the change match the description?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Read the core change top-down.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask questions as you read.&lt;/strong&gt; "What happens if this is empty?"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run it&lt;/strong&gt; if you can.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Practise on open-source projects you use: read recently merged pull requests and see what reviewers pushed back on. That's free mentoring from strangers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Questions to ask of any unfamiliar code
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is the &lt;em&gt;input&lt;/em&gt; and what is the &lt;em&gt;output&lt;/em&gt;?&lt;/li&gt;
&lt;li&gt;Where does state live, and who can change it?&lt;/li&gt;
&lt;li&gt;What can fail, and what happens then?&lt;/li&gt;
&lt;li&gt;What does this depend on?&lt;/li&gt;
&lt;li&gt;What would break if I deleted it?&lt;/li&gt;
&lt;li&gt;Why is there a special case here?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you can answer all six for a module, you understand it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping a reading log
&lt;/h2&gt;

&lt;p&gt;A tiny habit with outsized returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2026-10-30  library: &amp;lt;name&amp;gt;  file: &amp;lt;path&amp;gt;
  Learned:   &amp;lt;one thing the code did that I wouldn't have thought of&amp;gt;
  Question:  &amp;lt;something I couldn't explain&amp;gt;
  Steal:     &amp;lt;a pattern worth reusing&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a month, the "steal" column is a personal library of patterns, and the "question" column is your study list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing something to read
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Goal&lt;/th&gt;
&lt;th&gt;Pick&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Learn clean small-scale design&lt;/td&gt;
&lt;td&gt;A tiny utility library (a few hundred lines)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learn how frameworks work&lt;/td&gt;
&lt;td&gt;A small plugin or example app from the framework's own repository&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learn production patterns&lt;/td&gt;
&lt;td&gt;Mid-sized open-source apps with good tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learn algorithms in practice&lt;/td&gt;
&lt;td&gt;A scheduler, a parser or a small database&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Start with something you &lt;em&gt;use&lt;/em&gt;, so you already have questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common obstacles
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;"It's too big."&lt;/strong&gt; Read one file, not the repo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"I don't understand the language features."&lt;/strong&gt; Look each one up, then continue. Don't pretend.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"There are no comments."&lt;/strong&gt; Read the tests, the commit history and the issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"I get lost in the indirection."&lt;/strong&gt; Trace one concrete call with a debugger or print statements instead of reading abstractions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"I keep forgetting."&lt;/strong&gt; Write the trace down. Writing is how memory sticks.&lt;/p&gt;

&lt;h2&gt;
  
  
  One small contribution to aim for
&lt;/h2&gt;

&lt;p&gt;Pick one project you use. Read its issue tracker for tickets labelled "good first issue" or "docs". Find one you can understand in an hour. Leave a comment saying you're taking it, make the smallest change, and run the project's checks before opening the pull request. Being polite and patient matters as much as the code.&lt;/p&gt;

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

&lt;p&gt;What's your favourite codebase to read, and what made it easy to follow?&lt;/p&gt;




&lt;p&gt;☕ &lt;strong&gt;Enjoyed this post? You can support my writing on Ko-fi.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ko-fi.com/surajnandan" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2z7dch5enfz2e5i2t2gj.png" alt="Support me on Ko-fi" width="286" height="73"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>learning</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The History of AI, Part 5: Perceptrons, ELIZA, SHRDLU, and Shakey</title>
      <dc:creator>Suraj Nandan</dc:creator>
      <pubDate>Fri, 13 Nov 2026 04:30:00 +0000</pubDate>
      <link>https://dev.to/suraj_nandan/the-history-of-ai-part-5-perceptrons-eliza-shrdlu-and-shakey-24oe</link>
      <guid>https://dev.to/suraj_nandan/the-history-of-ai-part-5-perceptrons-eliza-shrdlu-and-shakey-24oe</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The History of AI, Part 5 of 24.&lt;/strong&gt; In Part 4 the field got its name at Dartmouth and entered its "golden years." This chapter is a guided tour of the machines and programs that made those years feel golden: a learning machine that thrilled the press, a chatbot that unsettled its own creator, a program that could talk about blocks, and a robot that wobbled around a laboratory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you could visit an AI lab in 1966, what would you see?&lt;/p&gt;

&lt;p&gt;You wouldn't see a robot butler. You wouldn't see anything that looked like a modern chatbot or a self-driving car. What you'd see are mainframes the size of refrigerators, teletype terminals clattering out text, and graduate students arguing in front of blackboards covered with logic notation.&lt;/p&gt;

&lt;p&gt;But if you looked at what the programs &lt;em&gt;did&lt;/em&gt;, you'd be astonished. They solved algebra word problems written in English. They held conversations. They manipulated imaginary blocks in response to typed commands. They steered a wheeled robot around a room. They learned to recognize simple patterns from examples.&lt;/p&gt;

&lt;p&gt;This chapter looks at four landmark creations of the mid-1960s and early 1970s, each of which taught the field something important, usually something it didn't want to hear. We'll write a little code for two of them so you can feel how they worked.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Perceptron: a machine that learns
&lt;/h2&gt;

&lt;p&gt;Let's start with the connectionist side of the story, which we left in Part 3 with McCulloch, Pitts, and Hebb.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fydspr6qm8zorx0qdrtz0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fydspr6qm8zorx0qdrtz0.jpg" alt="Frank Rosenblatt's Mark I Perceptron, a U.S. Navy-funded machine that learned to identify letters" width="800" height="626"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Frank Rosenblatt's Mark I Perceptron, a U.S. Navy-funded machine that learned to identify letters. Public domain, via &lt;a href="https://commons.wikimedia.org/wiki/File:330-PSA-80-60_(USN_710739)_(20897323365).jpg" rel="noopener noreferrer"&gt;Wikimedia Commons&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frank Rosenblatt&lt;/strong&gt; (1928-1971) was a psychologist and researcher at the Cornell Aeronautical Laboratory in Buffalo, New York. He was fascinated by how brains learn, and he wanted to build a machine that learned in a similar way, not by being programmed with rules, but by being shown examples and adjusting itself.&lt;/p&gt;

&lt;p&gt;In 1957 he described his design in a technical report, and in 1958 he published a more complete account in the journal &lt;em&gt;Psychological Review&lt;/em&gt;: the &lt;strong&gt;Perceptron&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  How the perceptron works
&lt;/h3&gt;

&lt;p&gt;The perceptron is a direct descendant of the McCulloch-Pitts neuron, with one crucial upgrade: &lt;strong&gt;the weights are learned.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It takes a set of inputs (say, the brightness values of pixels in an image), multiplies each by a weight, adds them up, and compares the total to a threshold. If the total is high enough, the output is 1 ("yes, it's a triangle"); otherwise it's 0.&lt;/p&gt;

&lt;p&gt;The learning rule is beautifully simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Show the perceptron an example and compute its output.&lt;/li&gt;
&lt;li&gt;If the output is correct, do nothing.&lt;/li&gt;
&lt;li&gt;If the output is wrong, &lt;strong&gt;nudge the weights&lt;/strong&gt; in the direction that would have given the right answer: increase weights for active inputs if the output should have been 1, decrease them if it should have been 0.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Repeat over all the examples, many times. Here it is in a few lines of 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;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;train_perceptron&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;epochs&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="n"&gt;lr&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;w&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;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="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;epoch&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="n"&gt;epochs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;xi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&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;pred&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;if&lt;/span&gt; &lt;span class="n"&gt;xi&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&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="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;pred&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;       &lt;span class="c1"&gt;# 0 if correct, +/-1 if wrong
&lt;/span&gt;            &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;xi&lt;/span&gt;
            &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;
            &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;+=&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;update&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;if&lt;/span&gt; &lt;span class="n"&gt;errors&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="c1"&gt;# every example classified correctly
&lt;/span&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;epoch&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;return&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;epochs&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;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&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="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;1&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="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;1&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;

&lt;span class="c1"&gt;# AND is learnable...
&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;train_perceptron&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;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&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="mi"&gt;0&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="mi"&gt;1&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;AND learned in&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;epochs; weights =&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bias =&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# ...but XOR never converges, no matter how long you train.
&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;train_perceptron&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;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&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="mi"&gt;1&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;0&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="n"&gt;epochs&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="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;XOR after 1000 epochs: still making mistakes&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;Run this and AND is learned within a few passes. XOR never settles. Keep that in mind, because it is about to become the most famous failure in the history of AI.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Mark I Perceptron and the press conference
&lt;/h3&gt;

&lt;p&gt;Rosenblatt didn't stop at theory. He built hardware. The &lt;strong&gt;Mark I Perceptron&lt;/strong&gt;, completed around 1958 to 1960 and funded by the US Office of Naval Research, was a physical machine. It had a 20 by 20 grid of 400 photocells as its "retina," connected through a tangle of wires to banks of units whose weights were stored in &lt;strong&gt;motor-driven potentiometers&lt;/strong&gt;, literally little knobs that turned to adjust a connection's strength during learning. You could show it a card with a letter on it, and over many trials it learned to tell the letters apart.&lt;/p&gt;

&lt;p&gt;In July 1958 the Navy and Rosenblatt held a press demonstration (using an IBM 704 computer to simulate the perceptron). The next day &lt;em&gt;The New York Times&lt;/em&gt; reported on what it called the embryo of an electronic computer that the Navy expected would eventually be able to walk, talk, see, write, reproduce itself, and be conscious of its existence. That was a staggering thing for a newspaper to say about a machine that could, at that moment, distinguish marks on the left of a card from marks on the right.&lt;/p&gt;

&lt;p&gt;Rosenblatt himself was more careful in his scientific papers than the press coverage suggested, but he was also a confident and charismatic promoter, and he did make bold claims about where the research could go. He proved the &lt;strong&gt;perceptron convergence theorem&lt;/strong&gt;: if the data can be separated by a straight line (more precisely, a hyperplane), the learning rule is guaranteed to find a separating line in a finite number of steps. That was a real mathematical result, and it made the perceptron respectable.&lt;/p&gt;

&lt;h3&gt;
  
  
  A cousin: ADALINE
&lt;/h3&gt;

&lt;p&gt;Around the same time, Bernard Widrow and his student Marcian "Ted" Hoff at Stanford developed &lt;strong&gt;ADALINE&lt;/strong&gt; (Adaptive Linear Neuron) in 1960, using a slightly different learning rule, the &lt;strong&gt;least mean squares (LMS)&lt;/strong&gt; or "delta" rule. Rather than only reacting to hard right/wrong errors, it nudged weights in proportion to &lt;em&gt;how far off&lt;/em&gt; its output was. That rule is a direct ancestor of &lt;strong&gt;gradient descent&lt;/strong&gt;, the workhorse of modern deep learning. (Hoff later went on to co-invent the Intel 4004 microprocessor.)&lt;/p&gt;

&lt;h3&gt;
  
  
  The seeds of the problem
&lt;/h3&gt;

&lt;p&gt;For a few years, the perceptron was the toast of the field. But there was a catch, and Rosenblatt's critics were circling. The perceptron could only learn problems where the classes could be separated by a straight line. XOR, in which the correct output for (0,1) and (1,0) is 1 but for (0,0) and (1,1) is 0, can't be separated by any single line.&lt;/p&gt;

&lt;p&gt;Rosenblatt knew that multi-layer perceptrons could in principle overcome this, and he explored them. But he had no good way to &lt;em&gt;train&lt;/em&gt; the extra layers. That missing piece, a learning rule for multi-layer networks, wasn't widely solved until the 1980s. We will pick up this story in Part 6, because it ended in a controversy that nearly killed the whole approach.&lt;/p&gt;

&lt;p&gt;Rosenblatt himself did not live to see the vindication. He died in a boating accident on his 43rd birthday, 11 July 1971.&lt;/p&gt;

&lt;h2&gt;
  
  
  ELIZA: the chatbot that wasn't thinking
&lt;/h2&gt;

&lt;p&gt;Now to the other end of the spectrum: a program that understood nothing and yet unsettled everyone who used it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Joseph Weizenbaum&lt;/strong&gt; (1923-2008) was a German-born computer scientist at MIT who had escaped Nazi Germany as a teenager. Between 1964 and 1966, working on MIT's Project MAC, he wrote a program called &lt;strong&gt;ELIZA&lt;/strong&gt;, named after Eliza Doolittle in &lt;em&gt;Pygmalion&lt;/em&gt; (the same Pygmalion myth we met in Part 1, now with a nice irony: the program "learns" to speak, but only superficially).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9rrugk80k30s6waoiooa.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9rrugk80k30s6waoiooa.jpg" alt="Joseph Weizenbaum, creator of ELIZA, in 1982" width="692" height="1017"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Joseph Weizenbaum, creator of ELIZA, in 1982. Public domain, via &lt;a href="https://commons.wikimedia.org/wiki/File:Weizenbaum_1982.jpg" rel="noopener noreferrer"&gt;Wikimedia Commons&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;ELIZA was intended as a demonstration of how superficial human-machine conversation could be. Its most famous script, &lt;strong&gt;DOCTOR&lt;/strong&gt;, imitated a &lt;strong&gt;Rogerian psychotherapist&lt;/strong&gt;, the type of therapist who mostly reflects the patient's words back as questions. This was a clever choice: it let the program say very little and still seem engaged.&lt;/p&gt;
&lt;h3&gt;
  
  
  How ELIZA worked (spoiler: it's simple)
&lt;/h3&gt;

&lt;p&gt;ELIZA did &lt;strong&gt;pattern matching and substitution&lt;/strong&gt;. It scanned your input for keywords, ranked by priority, matched a template, and filled a response template with fragments of what you wrote, swapping pronouns ("my" becomes "your", "I" becomes "you"). If it found nothing, it fell back on generic prompts like "Please go on" or "Tell me more."&lt;/p&gt;

&lt;p&gt;Here is a miniature ELIZA 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;random&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;

&lt;span class="n"&gt;REFLECT&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;i&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;you&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;my&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;your&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;me&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;you&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;am&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;are&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;you&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;I&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;your&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;my&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;RULES&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="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;i need (.*)&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;Why do you need {0}?&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;Would it really help you to get {0}?&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="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;i am (.*)&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;How long have you been {0}?&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;Why do you think you are {0}?&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="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;i feel (.*)&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;Tell me more about feeling {0}.&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;Do you often feel {0}?&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="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.*\bmother\b.*&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;Tell me more about your family.&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="sa"&gt;r&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="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Please go on.&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;I see. Can you elaborate?&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;reflect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fragment&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&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;REFLECT&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;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&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;w&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fragment&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="nf"&gt;split&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;respond&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;pattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;answers&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;RULES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;match&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;match&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="n"&gt;text&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="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;groups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;reflect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&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;g&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;groups&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;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;choice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;groups&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;respond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I am worried about my exams&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# e.g. "How long have you been worried about your exams?"
&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;respond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;My mother never listens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;# "Tell me more about your family."
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the essence. No understanding, no memory, no model of the world: just clever string handling. And yet.&lt;/p&gt;

&lt;h3&gt;
  
  
  The ELIZA effect
&lt;/h3&gt;

&lt;p&gt;Weizenbaum was startled by what happened next. People &lt;em&gt;talked&lt;/em&gt; to ELIZA. They confided in it. His own secretary, who had watched him build the program and knew exactly what it was, reportedly asked him to leave the room so she could have a private conversation with it. Some psychiatrists suggested that ELIZA might be developed into an automated therapy tool. Others, hearing about it, concluded that it demonstrated that computers could understand natural language.&lt;/p&gt;

&lt;p&gt;Weizenbaum found all of this disturbing. He had meant ELIZA to show how &lt;em&gt;little&lt;/em&gt; it takes to create an illusion of understanding. Instead people were taking the illusion at face value. The phenomenon is now called the &lt;strong&gt;ELIZA effect&lt;/strong&gt;: the human tendency to read understanding, empathy, and intention into the output of a computer program, simply because it uses language fluently.&lt;/p&gt;

&lt;p&gt;The effect is arguably more relevant today than ever. When a modern chatbot says "I understand how you feel," many people respond as though something understands. Whether and in what sense the system "understands" is a serious and unresolved question, but the ELIZA effect reminds us that our &lt;em&gt;feeling&lt;/em&gt; of being understood is a poor test.&lt;/p&gt;

&lt;p&gt;Weizenbaum became one of the field's most outspoken internal critics. In his 1976 book &lt;em&gt;Computer Power and Human Reason&lt;/em&gt;, he argued that there are tasks that should not be delegated to machines, even if machines could perform them, such as roles that require empathy, wisdom, and human responsibility. He was dismissed by many of his peers, but many of his concerns, about overreliance on automation and the erosion of human judgment, read as prescient today.&lt;/p&gt;

&lt;h3&gt;
  
  
  PARRY, the paranoid program
&lt;/h3&gt;

&lt;p&gt;In 1972, the Stanford psychiatrist &lt;strong&gt;Kenneth Colby&lt;/strong&gt; wrote a more elaborate program called &lt;strong&gt;PARRY&lt;/strong&gt;, which simulated a person with paranoid schizophrenia. It had an internal model with variables like "fear" and "anger" that shifted during conversation. In an early version of a Turing-style test, psychiatrists were shown transcripts of conversations with PARRY and with real patients, and they couldn't reliably tell them apart. That same year, ELIZA and PARRY were connected over the ARPANET to talk to each other, which produced a strange, stilted, slightly comic exchange.&lt;/p&gt;

&lt;p&gt;The lesson was not that these programs were intelligent. It was that &lt;strong&gt;conversation is a very forgiving test&lt;/strong&gt;. If the user is willing to supply meaning, a program can get away with remarkably little.&lt;/p&gt;

&lt;h2&gt;
  
  
  Microworlds: the strategy of the age
&lt;/h2&gt;

&lt;p&gt;Before we move on to the next two systems, it helps to understand the research strategy that produced them. Marvin Minsky and Seymour Papert at MIT promoted the idea of &lt;strong&gt;microworlds&lt;/strong&gt;: simplified, artificial domains small enough to be fully described, yet rich enough to require real reasoning. The logic was reasonable: if you can't solve intelligence in the full chaos of the real world, solve it in a restricted world first, then scale up.&lt;/p&gt;

&lt;p&gt;Some famous results came from this approach in the 1960s:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;STUDENT&lt;/strong&gt; (Daniel Bobrow, 1964) solved high-school algebra word problems stated in English by translating them into equations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SAINT&lt;/strong&gt; (James Slagle, 1961) performed symbolic integration at the level of a good first-year calculus student.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ANALOGY&lt;/strong&gt; (Thomas Evans, 1963) solved geometric analogy puzzles of the kind found on IQ tests ("A is to B as C is to which of these?").&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each worked within a narrow slice of reality and did impressively well inside it. The hope was that these slices could be gradually connected into a general intelligence. The hard truth, which took years to sink in, was that they didn't scale. Techniques that worked in a toy domain often broke when exposed to the unconstrained world.&lt;/p&gt;

&lt;p&gt;Two systems in particular embodied the promise and the problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  SHRDLU: understanding language in a world of blocks
&lt;/h2&gt;

&lt;p&gt;In 1968 to 1970, a PhD student at MIT named &lt;strong&gt;Terry Winograd&lt;/strong&gt; created one of the most impressive AI demonstrations ever made: &lt;strong&gt;SHRDLU&lt;/strong&gt; (the name came from the old printers' etaoin shrdlu, the second column of letters on a Linotype machine).&lt;/p&gt;

&lt;p&gt;SHRDLU lived in a simulated &lt;strong&gt;blocks world&lt;/strong&gt;: a table with blocks, pyramids, and boxes of different colors and sizes, plus a robot arm that could pick things up and move them. You could talk to it in ordinary English, and it would reply and act. A famously cited exchange goes something like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Person:&lt;/strong&gt; Pick up a big red block.&lt;br&gt;
&lt;strong&gt;Computer:&lt;/strong&gt; OK.&lt;br&gt;
&lt;strong&gt;Person:&lt;/strong&gt; Grasp the pyramid.&lt;br&gt;
&lt;strong&gt;Computer:&lt;/strong&gt; I don't understand which pyramid you mean.&lt;br&gt;
&lt;strong&gt;Person:&lt;/strong&gt; Find a block which is taller than the one you are holding and put it into the box.&lt;br&gt;
&lt;strong&gt;Computer:&lt;/strong&gt; By "it", I assume you mean the block which is taller than the one I am holding.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let that sink in. In 1970, a program was resolving pronouns ("it"), asking for clarification when a reference was ambiguous, planning sequences of physical actions (it would have to put down the block it was holding first, and it could explain &lt;em&gt;why&lt;/em&gt; it had done so), and remembering what had happened earlier in the conversation. It could answer questions like "Why did you do that?" by reading back its own reasoning.&lt;/p&gt;

&lt;p&gt;How did it work? Rather than treating language understanding as a separate problem from reasoning, Winograd integrated everything. SHRDLU had a &lt;strong&gt;parser&lt;/strong&gt; to analyze grammar, a &lt;strong&gt;semantic&lt;/strong&gt; component to map sentences onto its world model, and a &lt;strong&gt;planner&lt;/strong&gt; and &lt;strong&gt;reasoner&lt;/strong&gt; to figure out what actions to take. Crucially, these components could consult each other: knowledge about blocks helped decide how to parse an ambiguous sentence. It was programmed in Lisp and a language called Micro-Planner.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why SHRDLU didn't scale
&lt;/h3&gt;

&lt;p&gt;SHRDLU was widely admired, and it seemed to suggest that machines were close to &lt;em&gt;understanding&lt;/em&gt; language. But the limitations were severe, and Winograd himself was the first to say so.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The world was tiny and perfect.&lt;/strong&gt; The blocks world contained a few dozen objects with precisely known properties. There was no noise, no ambiguity in perception, no unknown objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The knowledge was hand-coded.&lt;/strong&gt; Every word, every rule of grammar, every fact about the domain had been written in by a human expert.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It was brittle.&lt;/strong&gt; Step outside the narrow vocabulary and domain, and it collapsed. Extending it to a kitchen, for instance, would not have been a matter of adding a few more words; it would have required encoding vast amounts of everyday knowledge about food, containers, and cooking.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Winograd later turned away from the approach. Influenced by philosophers like Martin Heidegger and by colleagues like Fernando Flores, he came to believe that human understanding is not a matter of manipulating symbolic representations in the head but is rooted in embodied, social activity. He moved into human-computer interaction, taught at Stanford, and (as a minor footnote) later served as the doctoral advisor of Google co-founder Larry Page. His name lives on in the &lt;strong&gt;Winograd Schema Challenge&lt;/strong&gt;, a test of commonsense reasoning (in which pronoun resolution depends on real-world knowledge, as in "The trophy doesn't fit in the suitcase because &lt;em&gt;it&lt;/em&gt; is too big"), which was proposed in 2011 by Hector Levesque, inspired by an example in Winograd's work.&lt;/p&gt;

&lt;p&gt;SHRDLU is the poster child for a pattern that will repeat in Parts 7 and 8: &lt;strong&gt;impressive demos in narrow domains, followed by a hard collision with the open-ended messiness of reality.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Shakey: the first robot that reasoned
&lt;/h2&gt;

&lt;p&gt;If SHRDLU lived in a simulated world, &lt;strong&gt;Shakey&lt;/strong&gt; lived in a real one.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frind1r90fc6xy4p2hqzf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frind1r90fc6xy4p2hqzf.jpg" alt="Shakey the robot, built at SRI International (Computer History Museum)" width="800" height="1200"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Shakey the robot, built at SRI International (Computer History Museum). Image: The wub, CC BY-SA 4.0, via &lt;a href="https://commons.wikimedia.org/wiki/File:SRI_Shakey_robot,_1969,_Computer_History_Museum.jpg" rel="noopener noreferrer"&gt;Wikimedia Commons&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;From 1966 to 1972, a team at the &lt;strong&gt;Stanford Research Institute (SRI)&lt;/strong&gt;, led by Charles Rosen and including &lt;strong&gt;Nils Nilsson&lt;/strong&gt;, &lt;strong&gt;Peter Hart&lt;/strong&gt;, &lt;strong&gt;Bertram Raphael&lt;/strong&gt;, and &lt;strong&gt;Richard Fikes&lt;/strong&gt;, built &lt;strong&gt;Shakey the Robot&lt;/strong&gt;, funded by DARPA. It was a boxy wheeled platform about the size of a small refrigerator, topped with a TV camera, a range-finder, and bump sensors ("cat whiskers"). Its trademark was a wobbling motion when it moved, which earned it the name.&lt;/p&gt;

&lt;p&gt;Shakey could be given a goal in plain language, such as "push the block off the platform," and it would work out a plan. It had to look at its environment through the camera, build a model of the rooms, decide which actions would achieve the goal, and carry them out, adapting if something went wrong, like a door being closed or a box being in the way.&lt;/p&gt;

&lt;p&gt;It was, in a real sense, the first &lt;strong&gt;mobile robot that reasoned about its own actions&lt;/strong&gt;. It was controlled by software running on a large computer (a PDP-10, later PDP-15) that communicated with the robot over a radio link, because the robot couldn't carry that much computing power. A single move could take minutes, and complex tasks could take hours.&lt;/p&gt;
&lt;h3&gt;
  
  
  Shakey's gifts to computer science
&lt;/h3&gt;

&lt;p&gt;What makes Shakey so important is less the robot than the algorithms invented to make it work. Several of them are still in everyday use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A* search&lt;/strong&gt; (1968, by Hart, Nilsson, and Raphael), a path-finding algorithm that finds the shortest route efficiently by combining the cost so far with an estimate of the remaining distance. A* is used in video games, GPS navigation, and robotics today. Here's the core idea in one line: choose the next node that minimizes &lt;code&gt;f(n) = g(n) + h(n)&lt;/code&gt;, the cost to reach &lt;code&gt;n&lt;/code&gt; plus a heuristic estimate of the cost to get from &lt;code&gt;n&lt;/code&gt; to the goal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;STRIPS&lt;/strong&gt; (1971, by Fikes and Nilsson), the Stanford Research Institute Problem Solver, a way of representing actions in terms of &lt;strong&gt;preconditions&lt;/strong&gt; and &lt;strong&gt;effects&lt;/strong&gt; (e.g., "to push a box, the robot must be next to it; afterwards, the box has moved"). STRIPS-style planning is the ancestor of modern AI planners.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Hough transform&lt;/strong&gt; and related methods for detecting lines and shapes in images, which were refined in this period and used in computer vision.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A* is a lovely illustration of how the field's search ideas matured. Here's a compact version on a grid:&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;heapq&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;astar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;goal&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;h&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;  &lt;span class="c1"&gt;# Manhattan distance heuristic
&lt;/span&gt;        &lt;span class="k"&gt;return&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;p&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="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;goal&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="o"&gt;+&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;p&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="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;goal&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="n"&gt;open_set&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="nf"&gt;h&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;])]&lt;/span&gt;
    &lt;span class="n"&gt;seen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&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;open_set&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="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;heapq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;heappop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;open_set&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;pos&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;goal&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;path&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;seen&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;seen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&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;dx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dy&lt;/span&gt; &lt;span class="ow"&gt;in&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;0&lt;/span&gt;&lt;span class="p"&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="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="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="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;0&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="n"&gt;nx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ny&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pos&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="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;dx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pos&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="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;dy&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;nx&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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;grid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;ny&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&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;grid&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="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;ny&lt;/span&gt;&lt;span class="p"&gt;]&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="n"&gt;heapq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;heappush&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;open_set&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&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;+&lt;/span&gt; &lt;span class="nf"&gt;h&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ny&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="n"&gt;g&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ny&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;nx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ny&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;None&lt;/span&gt;

&lt;span class="n"&gt;grid&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="mi"&gt;0&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="mi"&gt;0&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="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;1&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="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;0&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="mi"&gt;0&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="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="mi"&gt;1&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;0&lt;/span&gt;&lt;span class="p"&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="nf"&gt;astar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;,&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="mi"&gt;0&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;3&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare it with the water jug search from Part 4. The only real difference is that the next state to explore is chosen using an estimate of how close it is to the goal. That one change is a textbook example of using &lt;em&gt;knowledge&lt;/em&gt; to tame the combinatorial explosion.&lt;/p&gt;

&lt;h3&gt;
  
  
  The media sensation
&lt;/h3&gt;

&lt;p&gt;In 1970, &lt;em&gt;Life&lt;/em&gt; magazine ran a feature on Shakey, calling it the "first electronic person" and quoting researchers who suggested that machines with human-level intelligence might arrive within years. (The researchers later said that some of the quoted timelines were exaggerated by the writer, but the headline captured the mood.) The article is a perfect snapshot of the era's hype, and also of the gap between rhetoric and reality: the actual robot was slow and fragile, and operated only in carefully constructed rooms with plain painted walls and specially marked objects.&lt;/p&gt;

&lt;p&gt;Shakey now sits in the Computer History Museum in California, a delightful relic. In terms of legacy, though, its true heirs are the autonomous vehicles and warehouse robots of today, whose planners descend from STRIPS and whose route-finders descend from A*.&lt;/p&gt;

&lt;h2&gt;
  
  
  What these four teach us
&lt;/h2&gt;

&lt;p&gt;Let's lay the four side by side, because the contrast is instructive.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;System&lt;/th&gt;
&lt;th&gt;What it showed&lt;/th&gt;
&lt;th&gt;What it couldn't do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Perceptron&lt;/strong&gt; (1958)&lt;/td&gt;
&lt;td&gt;Machines can &lt;em&gt;learn&lt;/em&gt; from examples&lt;/td&gt;
&lt;td&gt;Couldn't solve non-linear problems like XOR; no training method for multiple layers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;ELIZA&lt;/strong&gt; (1966)&lt;/td&gt;
&lt;td&gt;Conversation can create the illusion of understanding&lt;/td&gt;
&lt;td&gt;Understood nothing; no memory or knowledge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;SHRDLU&lt;/strong&gt; (1970)&lt;/td&gt;
&lt;td&gt;Language, reasoning, and action can be integrated&lt;/td&gt;
&lt;td&gt;Worked only in a tiny hand-coded blocks world&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Shakey&lt;/strong&gt; (1972)&lt;/td&gt;
&lt;td&gt;A robot can plan and act toward goals&lt;/td&gt;
&lt;td&gt;Slow, fragile, limited to carefully prepared rooms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A few patterns emerge:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Narrow success, broad failure.&lt;/strong&gt; Each program worked in a restricted domain. Scaling up required vastly more knowledge and flexibility than anyone had built.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hand-coded knowledge is a bottleneck.&lt;/strong&gt; The programs were smart because humans had carefully written in what they needed to know. Getting from "dozens of facts" to "everything a person knows" was a gap of many orders of magnitude.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Perception was harder than reasoning.&lt;/strong&gt; Shakey could plan elegantly once it knew where things were, but figuring out where things were from camera images was painfully slow and error-prone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hype outruns results.&lt;/strong&gt; The press coverage of the Perceptron and Shakey promised far more than the machines could deliver.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of this means the work was a failure. Quite the opposite: it created tools (A*, STRIPS, parsing methods, pattern matching, knowledge representation) that are still used. But it set the stage for a collision between expectations and reality.&lt;/p&gt;

&lt;h2&gt;
  
  
  A glimpse of the cracks
&lt;/h2&gt;

&lt;p&gt;By the end of the 1960s, there were growing signs of trouble.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Machine translation, one of the most heavily funded early goals, was progressing slowly. A government committee would soon recommend cutting funding.&lt;/li&gt;
&lt;li&gt;Neural networks were under mathematical attack. A book was in preparation by two of AI's most prominent figures that would argue the perceptron approach was a dead end.&lt;/li&gt;
&lt;li&gt;Researchers working on problems like vision and robotics were finding that the real world was far messier than their microworlds.&lt;/li&gt;
&lt;li&gt;Funding agencies were beginning to ask: &lt;em&gt;where are the results we were promised?&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The golden years were about to meet the first great reckoning, and the connectionist camp was about to take the hardest hit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Timeline: 1957 to 1972
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1957:&lt;/strong&gt; Rosenblatt describes the Perceptron; Newell and Simon begin work on the General Problem Solver.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1958:&lt;/strong&gt; McCarthy creates Lisp; the Perceptron's press demonstration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1960:&lt;/strong&gt; Widrow and Hoff's ADALINE.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1964 to 1966:&lt;/strong&gt; Weizenbaum builds ELIZA; Bobrow's STUDENT solves algebra word problems; SRI starts Shakey.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1968:&lt;/strong&gt; A* search published.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1969:&lt;/strong&gt; &lt;em&gt;Perceptrons&lt;/em&gt; by Minsky and Papert (Part 6).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1970:&lt;/strong&gt; Winograd's SHRDLU; &lt;em&gt;Life&lt;/em&gt; magazine's Shakey feature.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1971:&lt;/strong&gt; STRIPS planner; Rosenblatt dies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1972:&lt;/strong&gt; PARRY, the simulated paranoid patient; Prolog is created.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The ELIZA effect, today
&lt;/h2&gt;

&lt;p&gt;Weizenbaum's observation has aged remarkably well. Modern chatbots are vastly more capable than ELIZA, but the human reaction is the same: when something talks to us fluently, we reach for the vocabulary of minds, saying it "wants," "thinks," or "feels." A few practical habits help keep your balance:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Separate fluency from reliability.&lt;/strong&gt; A smooth answer tells you about the system's skill at producing language, not about whether the content is true.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notice when you're supplying the meaning.&lt;/strong&gt; Ask whether the system really said something specific, or whether you filled in the gaps charitably.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remember who benefits.&lt;/strong&gt; Products that feel like friends keep users engaged, and engagement is a business metric. That doesn't make them bad, but it's worth noticing.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Quick glossary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pattern matching:&lt;/strong&gt; comparing input against templates to choose a response.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Microworld:&lt;/strong&gt; a simplified, self-contained domain used for AI research, such as SHRDLU's blocks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parser:&lt;/strong&gt; a program that analyzes the grammatical structure of a sentence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Precondition and effect:&lt;/strong&gt; in planning, what must be true to take an action and what changes once it's taken.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Heuristic search:&lt;/strong&gt; search guided by an estimate of how close a state is to the goal (A*).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rosenblatt's Perceptron (1958)&lt;/strong&gt; was the first practical &lt;em&gt;learning&lt;/em&gt; neural network. It learned by adjusting weights, and its convergence theorem was real, but it could solve only linearly separable problems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ELIZA (1966)&lt;/strong&gt; used simple pattern matching to simulate a Rogerian therapist and revealed the &lt;strong&gt;ELIZA effect&lt;/strong&gt;: people readily attribute understanding to fluent-sounding programs. Its creator, Weizenbaum, became a leading critic of overreliance on AI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SHRDLU (1970)&lt;/strong&gt; integrated language understanding, reasoning, and action in a &lt;strong&gt;blocks world&lt;/strong&gt;, a stunning demo that also exposed the brittleness of hand-coded, narrow-domain systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shakey (1966-72)&lt;/strong&gt; was the first mobile robot to plan its own actions, and it gave computer science &lt;strong&gt;A*&lt;/strong&gt; and &lt;strong&gt;STRIPS&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Early AI's &lt;strong&gt;microworld&lt;/strong&gt; strategy produced impressive results that did not scale to the open-ended real world.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Fix the perceptron's blind spot.&lt;/strong&gt; Add a hidden layer by hand: build XOR from two perceptrons (one computing OR, one computing NAND) feeding a third computing AND. You've just solved XOR with a two-layer network, exactly what Rosenblatt couldn't train.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make ELIZA a little smarter.&lt;/strong&gt; Add rules for "because," "always," and "dream," and give it a short memory so it can circle back to something you mentioned earlier ("Earlier you said your exams worried you..."). Notice how much more convincing it feels. What does that say about how we judge understanding?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Change the heuristic in A*.&lt;/strong&gt; Set &lt;code&gt;h&lt;/code&gt; to zero (this turns A* into plain uniform-cost search) and count how many cells each version explores on a larger grid. Then try a deliberately &lt;em&gt;bad&lt;/em&gt; heuristic and see how the path quality changes.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Next up
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;Part 6&lt;/strong&gt;, we confront the first great downturn. A 1969 book called &lt;em&gt;Perceptrons&lt;/em&gt; by Marvin Minsky and Seymour Papert delivers what many see as the knockout blow to neural networks. In 1966 the ALPAC report slashes funding for machine translation. And in 1973 the British mathematician Sir James Lighthill delivers a devastating review of AI that helps trigger the &lt;strong&gt;first AI winter&lt;/strong&gt;. How does a field with so much promise freeze over?&lt;/p&gt;

&lt;p&gt;If you've ever been fooled by a chatbot, or if you've built a toy AI project that fell apart on real data, share your story in the comments. It will fit right in with the next chapter.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;See you in Part 6.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;☕ &lt;strong&gt;If this series helped you, you can support my writing on Ko-fi.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ko-fi.com/surajnandan" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2z7dch5enfz2e5i2t2gj.png" alt="Support me on Ko-fi" width="286" height="73"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>history</category>
      <category>machinelearning</category>
      <category>python</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Packaging my own design as a template: the unglamorous parts</title>
      <dc:creator>Suraj Nandan</dc:creator>
      <pubDate>Fri, 13 Nov 2026 03:30:00 +0000</pubDate>
      <link>https://dev.to/suraj_nandan/packaging-my-own-design-as-a-template-the-unglamorous-parts-45m6</link>
      <guid>https://dev.to/suraj_nandan/packaging-my-own-design-as-a-template-the-unglamorous-parts-45m6</guid>
      <description>&lt;p&gt;I turned my portfolio design into a template. The code was done. The real work was &lt;strong&gt;removing myself from it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This post is about the unglamorous parts of packaging software for other people: what had to change, what I almost forgot, and what's still unfinished. If you're thinking about selling a starter kit or template, this is the checklist I wish I'd had.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a template
&lt;/h2&gt;

&lt;p&gt;As I wrote on Day 4, I weighed several ways to earn online and chose the one that needed the least &lt;em&gt;new&lt;/em&gt; work: packaging a design system I'd already built. A portfolio template is something other students genuinely need, and it was a better fit than starting a product from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  The principle: separate the owner from the engine
&lt;/h2&gt;

&lt;p&gt;My live site is full of &lt;em&gt;me&lt;/em&gt;: my name, links, location, project list, certificates, even phrases in the chat assistant's persona. A template can't have any of that hard-coded. Everything owner-specific has to live in one clearly marked place, and the rest has to read from it.&lt;/p&gt;

&lt;p&gt;I worked on a &lt;strong&gt;separate copy&lt;/strong&gt;, so the live site stayed untouched. (That's the "copy, don't rewrite" approach from Day 22.)&lt;/p&gt;

&lt;h2&gt;
  
  
  What had to change
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. One config file for every owner-specific fact
&lt;/h3&gt;

&lt;p&gt;All the personal facts moved into a single &lt;code&gt;site&lt;/code&gt; object: name, tagline, links, location, and values derived from them (full name, site URL, and so on).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/data/site.ts  (simplified)&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;site&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Avery Quill&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tagline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Designer-developer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://your-site.example&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;City, Country&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;github&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://github.com/your-username&lt;/span&gt;&lt;span class="dl"&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;FULL_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SITE_URL&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I hunted for hard-coded copies. This is the tedious part: search for the old name, old URLs and old city across HTML, scripts, metadata and generated files. Every miss would have shipped a stranger's details to a buyer.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. A template-driven &lt;code&gt;index.html&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The HTML head contains the title, description and social tags, which must also come from the config. A small build plugin fills the HTML from the same data, so the page's metadata can't disagree with the site.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Build scripts that read the same config
&lt;/h3&gt;

&lt;p&gt;Anything that runs at build time (sitemaps, feeds, prerender, share images) had to read from the config too, through one loader, instead of having their own copies of the facts.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. A section list that controls the page
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;sections&lt;/code&gt; array decides which home sections render and in what order. A buyer who doesn't want a blog section removes one line.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Parameterised APIs
&lt;/h3&gt;

&lt;p&gt;Some small stats endpoints took a hard-coded username. They now accept a query parameter, so a buyer's data shows up instead of mine.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. The assistant persona
&lt;/h3&gt;

&lt;p&gt;The chat assistant's knowledge and persona are generated from an &lt;code&gt;OWNER&lt;/code&gt; object, so a buyer gets an assistant that talks about &lt;em&gt;them&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A sample persona, not my life
&lt;/h2&gt;

&lt;p&gt;The template ships with a fictional owner ("Avery Quill", &lt;em&gt;The Quill Review&lt;/em&gt;) and placeholder links (&lt;code&gt;your-username&lt;/code&gt;, &lt;code&gt;your-site.example&lt;/code&gt;). Sample PDFs and images are generated by a script, so no personal photos or real certificates are included.&lt;/p&gt;

&lt;h2&gt;
  
  
  The licence question
&lt;/h2&gt;

&lt;p&gt;This one almost slipped past. The live site has a little pixel mascot. I wasn't certain I could legally redistribute those sprites, so I &lt;strong&gt;removed them&lt;/strong&gt; from the template and made a mascot an optional config feature instead.&lt;/p&gt;

&lt;p&gt;The rule I took: &lt;em&gt;if I can't verify the licence of an asset, it doesn't ship.&lt;/em&gt; Fonts, images, icons, sounds, sprites. Check each one. Selling something that includes someone else's work without permission is a serious problem, and "I found it online" isn't a licence.&lt;/p&gt;

&lt;p&gt;I also wrote a draft licence for the template itself. It's a draft, &lt;strong&gt;not legal advice&lt;/strong&gt;, and anyone selling software should get proper advice for their situation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test like a buyer
&lt;/h2&gt;

&lt;p&gt;The most valuable check: do what a buyer will do, from scratch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;unzip press-template.zip &lt;span class="nt"&gt;-d&lt;/span&gt; /tmp/buyer-test
&lt;span class="nb"&gt;cd&lt;/span&gt; /tmp/buyer-test/press-template
npm ci
npm run typecheck
npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do it in a &lt;strong&gt;clean directory&lt;/strong&gt;, not your working copy. Things that work on your machine because of leftover files or cached installs will fail here. I also made a customised copy (changing the name, links and sections) to confirm that the config really controls everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I found along the way
&lt;/h2&gt;

&lt;p&gt;Packaging forced me to look at the code with fresh eyes, and I found real bugs in the live portfolio:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The command palette ignored the Escape key.&lt;/li&gt;
&lt;li&gt;A certificate modal's animated children lacked React keys.&lt;/li&gt;
&lt;li&gt;Certificates without a URL crashed the modal and the featured row.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All three were fixed in the live site too. Preparing something for strangers is a great forcing function for quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I haven't finished
&lt;/h2&gt;

&lt;p&gt;The honest status, as on Day 4: the template is built and verified, the listing copy and screenshots are ready, and a demo is deployed. But the Gumroad listing is &lt;strong&gt;a draft that's not published&lt;/strong&gt;, because payouts need bank details I haven't connected.&lt;/p&gt;

&lt;p&gt;So: built, tested, not shipped. Naming that publicly is partly to make it harder to leave it that way.&lt;/p&gt;

&lt;h2&gt;
  
  
  A checklist you can reuse
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Every personal fact lives in one config file&lt;/li&gt;
&lt;li&gt;[ ] Search for your name, handles, URLs, city across &lt;em&gt;all&lt;/em&gt; files&lt;/li&gt;
&lt;li&gt;[ ] Sample content uses a fictional persona&lt;/li&gt;
&lt;li&gt;[ ] No personal images, documents or certificates&lt;/li&gt;
&lt;li&gt;[ ] Every asset's licence is verified, or the asset is removed&lt;/li&gt;
&lt;li&gt;[ ] A README with setup steps a stranger can follow&lt;/li&gt;
&lt;li&gt;[ ] A clean install and build from the final zip&lt;/li&gt;
&lt;li&gt;[ ] A customised copy to prove the config works&lt;/li&gt;
&lt;li&gt;[ ] A licence file (get advice)&lt;/li&gt;
&lt;li&gt;[ ] Listing text that says exactly what's included, and what isn't&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lesson
&lt;/h2&gt;

&lt;p&gt;"It works for me" and "someone else can use it" are different levels of finished. The second one took longer than the first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing the listing page
&lt;/h2&gt;

&lt;p&gt;A template listing has to answer a buyer's questions fast. Mine follows this outline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Name: one-line promise&lt;/span&gt;

&lt;span class="gu"&gt;## What you get&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; A complete React + TypeScript site (list the main sections)
&lt;span class="p"&gt;-&lt;/span&gt; Design system with tokens and primitives
&lt;span class="p"&gt;-&lt;/span&gt; Sample content you can replace
&lt;span class="p"&gt;-&lt;/span&gt; Documentation: setup, customising, deploying

&lt;span class="gu"&gt;## Who it's for / not for&lt;/span&gt;
For: students and developers who want a distinctive portfolio.
Not for: people who want a no-code builder.

&lt;span class="gu"&gt;## Requirements&lt;/span&gt;
Node version, package manager, hosting suggestions.

&lt;span class="gu"&gt;## What's *not* included&lt;/span&gt;
Domain, hosting, your content, support beyond [stated scope].

&lt;span class="gu"&gt;## Preview&lt;/span&gt;
Screenshots, a live demo link.

&lt;span class="gu"&gt;## Licence&lt;/span&gt;
Plain-language summary + link to the full text.

&lt;span class="gu"&gt;## Changelog&lt;/span&gt;
Version history.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The "what's not included" section prevents refunds and disappointment.&lt;/p&gt;

&lt;h2&gt;
  
  
  README for the buyer
&lt;/h2&gt;

&lt;p&gt;The README should get a stranger from zip to running site:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Requirements.&lt;/li&gt;
&lt;li&gt;Install and run commands.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Where to put your information&lt;/strong&gt; (the one config file).&lt;/li&gt;
&lt;li&gt;How to add a project, a post and a certificate.&lt;/li&gt;
&lt;li&gt;How to change colours and fonts (the tokens).&lt;/li&gt;
&lt;li&gt;How to deploy.&lt;/li&gt;
&lt;li&gt;Troubleshooting for the three most common problems.&lt;/li&gt;
&lt;li&gt;Licence and credits.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A README that a first-time buyer can follow &lt;em&gt;without asking you anything&lt;/em&gt; is a product feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Support and refunds: think before you sell
&lt;/h2&gt;

&lt;p&gt;I'm not a lawyer and rules differ by country and platform, so treat this as a prompt, not advice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Decide in advance what support you'll offer (for example, installation questions for 30 days) and say it plainly.&lt;/li&gt;
&lt;li&gt;Read the platform's terms about refunds, taxes and payouts.&lt;/li&gt;
&lt;li&gt;Check whether you need to register for tax in your country once you earn.&lt;/li&gt;
&lt;li&gt;Keep a record of what you sold, to whom and when.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Handling this &lt;em&gt;before&lt;/em&gt; the first sale is much less stressful than after.&lt;/p&gt;

&lt;h2&gt;
  
  
  A pre-launch dry run
&lt;/h2&gt;

&lt;p&gt;Do this on a machine that has never seen your project:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download the zip from the listing, as a buyer would.&lt;/li&gt;
&lt;li&gt;Follow the README to the letter. Note every place you hesitate.&lt;/li&gt;
&lt;li&gt;Change the name, links and colours. Does everything update?&lt;/li&gt;
&lt;li&gt;Build and deploy somewhere.&lt;/li&gt;
&lt;li&gt;Fix what confused you, then repeat with a friend.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Every point of friction you fix is a support email you won't answer later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Versioning and updates
&lt;/h2&gt;

&lt;p&gt;If people buy it, it needs maintenance. A lightweight plan:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Semantic version numbers (1.0.0, 1.0.1…).&lt;/li&gt;
&lt;li&gt;A changelog.&lt;/li&gt;
&lt;li&gt;A promise about how long you'll support a major version.&lt;/li&gt;
&lt;li&gt;A note on dependencies: they age, and security updates matter.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Be honest about what you can maintain. An abandoned template with promises is worse than a small one that's kept updated.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd tell my past self
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Set up payouts on day one, not last.&lt;/li&gt;
&lt;li&gt;Write the README before the last feature.&lt;/li&gt;
&lt;li&gt;Check licences as you add each asset, not at the end.&lt;/li&gt;
&lt;li&gt;Test from a clean zip early. Many problems only show there.&lt;/li&gt;
&lt;li&gt;Price low, and treat it as an experiment you learn from.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;If you've sold a template or starter kit, what surprised you most?&lt;/p&gt;




&lt;p&gt;☕ &lt;strong&gt;Enjoyed this post? You can support my writing on Ko-fi.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ko-fi.com/surajnandan" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2z7dch5enfz2e5i2t2gj.png" alt="Support me on Ko-fi" width="286" height="73"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>design</category>
      <category>gumroad</category>
      <category>react</category>
      <category>career</category>
    </item>
    <item>
      <title>Impostor syndrome, minus the pep talk</title>
      <dc:creator>Suraj Nandan</dc:creator>
      <pubDate>Thu, 12 Nov 2026 03:30:00 +0000</pubDate>
      <link>https://dev.to/suraj_nandan/impostor-syndrome-minus-the-pep-talk-24mc</link>
      <guid>https://dev.to/suraj_nandan/impostor-syndrome-minus-the-pep-talk-24mc</guid>
      <description>&lt;p&gt;You've heard "everyone feels like an impostor." That's true, and it isn't very helpful. Telling someone a feeling is common doesn't tell them what to do with it.&lt;/p&gt;

&lt;p&gt;This post is about what I try to do with the feeling: practical moves, not reassurance. It's written by a student who still feels it, so it isn't advice from the other side of the problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  First, separate two different things
&lt;/h2&gt;

&lt;p&gt;"Impostor syndrome" gets used for two very different situations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A feeling that doesn't match the evidence.&lt;/strong&gt; You've shipped real work, but you feel like a fraud.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A feeling that matches a real gap.&lt;/strong&gt; You don't know something important yet.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;They need different responses. The first needs evidence and perspective. The second needs &lt;em&gt;learning&lt;/em&gt;, and the feeling is simply accurate information. Mixing them up leads to either false reassurance or unnecessary despair.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make it concrete
&lt;/h2&gt;

&lt;p&gt;"I'm not good enough" is vague, and vague fears grow in the dark. Try translating:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Vague fear&lt;/th&gt;
&lt;th&gt;Concrete task&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"I'm not a real developer"&lt;/td&gt;
&lt;td&gt;"I don't know how to write integration tests."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"I'll never understand system design"&lt;/td&gt;
&lt;td&gt;"I can't yet explain how a write-ahead log helps durability."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Everyone's ahead of me"&lt;/td&gt;
&lt;td&gt;"I haven't deployed anything with a real database to production."&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Vague fears are heavy. Tasks are small and have next steps. The translation itself often shrinks the feeling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep a record
&lt;/h2&gt;

&lt;p&gt;When I feel behind, I look at what exists: the projects, the case studies, the changelog of what shipped. That record is &lt;strong&gt;evidence, not opinion&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Mind you, the record cuts both ways. It also shows my gaps clearly: no tests on CardBridge, an AI eval that's never been run, a template that's built but unpublished. That's fine. An honest record of strengths &lt;em&gt;and&lt;/em&gt; gaps is more useful than a flattering memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  A simple version
&lt;/h3&gt;

&lt;p&gt;Keep a file called &lt;code&gt;wins.md&lt;/code&gt;. At the end of each week, add three lines (these are example entries, use your own):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2026-W42
- Fixed the RLS recursion with a SECURITY DEFINER helper.
- Wrote the plan for transition tests.
- Helped a friend debug a CORS error.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the bad weeks, read it back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limit the comparison
&lt;/h2&gt;

&lt;p&gt;Social feeds show other people's finished work next to your messy middle. The comparison is rigged: you're seeing their highlight reel and living your own behind-the-scenes.&lt;/p&gt;

&lt;p&gt;I try to compare myself to &lt;strong&gt;last month's me&lt;/strong&gt;. Am I able to do something now that I couldn't then? That's a fair measure, and it's the only one fully under my control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ask the question out loud
&lt;/h2&gt;

&lt;p&gt;Most "stupid questions" are the ones everyone has. Asking early is cheaper than hiding it for months and building on a misunderstanding. A good way to ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Say what you've tried.&lt;/li&gt;
&lt;li&gt;Say what you expected.&lt;/li&gt;
&lt;li&gt;Say what you got.&lt;/li&gt;
&lt;li&gt;Ask the narrowest question you can.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;People respond well to specific questions, and writing one often reveals the answer before you press send.&lt;/p&gt;

&lt;h2&gt;
  
  
  Notice what you discount
&lt;/h2&gt;

&lt;p&gt;A common pattern: you discount your own achievements ("anyone could've done that") and inflate other people's. Try the reverse test: if a friend described your work to you, would you be impressed? If so, you may be applying a stricter standard to yourself than to anyone else.&lt;/p&gt;

&lt;h2&gt;
  
  
  When "I don't belong" isn't about skill
&lt;/h2&gt;

&lt;p&gt;Sometimes the feeling is about environment, not ability: being the only person from your background, city or college in a room, or lacking a network. That's a real disadvantage, and telling yourself "it's all in your head" is wrong. In those cases, finding a community (online counts) matters more than any amount of studying.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this doesn't fix
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Real skill gaps.&lt;/strong&gt; The feeling is a signal to learn, not a verdict on your worth.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Burnout or deeper anxiety.&lt;/strong&gt; If the feeling is constant and heavy, or affecting sleep and health, talk to someone you trust or a professional. A blog post can't substitute for that.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A one-week exercise
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Write down three things you're afraid you can't do.&lt;/li&gt;
&lt;li&gt;Turn each into a specific, learnable task.&lt;/li&gt;
&lt;li&gt;Pick the smallest one and do it this week.&lt;/li&gt;
&lt;li&gt;Add the result to your &lt;code&gt;wins.md&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Scripts for asking and answering
&lt;/h2&gt;

&lt;p&gt;Sometimes the hardest part is the first sentence. Steal these.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Asking for help&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I'm trying to [goal]. I expected [X] but got [Y]. I've tried [A] and [B]. Could you point me at what I'm missing?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Asking for feedback&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Could you look at [thing] and tell me the one thing that's confusing or weak? I don't need polish, just the biggest problem."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Admitting you don't know&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I haven't worked with that yet. Here's how I'd approach learning it..."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Receiving criticism&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Thanks, that's helpful. Let me check and I'll get back to you."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;All four are specific, polite and honest, and none apologises for existing.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to talk about gaps in an interview
&lt;/h2&gt;

&lt;p&gt;Having a clear view of your gaps is an &lt;em&gt;advantage&lt;/em&gt; in interviews, not a liability.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Name the gap plainly.&lt;/strong&gt; "I haven't operated a production system."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Show you understand why it matters.&lt;/strong&gt; "I know incident response and monitoring are a big part of reliability."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Show what you've done about it.&lt;/strong&gt; "I added health checks and a post-deploy verification routine to my own projects."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Show the next step.&lt;/strong&gt; "I'm looking for a role where I can learn that from people who do it."&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That structure turns "I don't know" into "here's how I learn."&lt;/p&gt;

&lt;h2&gt;
  
  
  A quick audit: what's feeding the feeling?
&lt;/h2&gt;

&lt;p&gt;Check your inputs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Who am I comparing myself to?&lt;/strong&gt; Strangers with highlight reels?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What am I reading or watching before I code?&lt;/strong&gt; Content that makes me feel behind?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Am I sleeping and eating properly?&lt;/strong&gt; Fatigue magnifies self-doubt.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Have I told anyone how I feel?&lt;/strong&gt; Secrets get heavier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Changing inputs often does more than arguing with the feeling.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "evidence file" idea
&lt;/h2&gt;

&lt;p&gt;Beyond a &lt;code&gt;wins.md&lt;/code&gt;, collect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;screenshots of kind messages or helpful reviews,&lt;/li&gt;
&lt;li&gt;links to things you shipped,&lt;/li&gt;
&lt;li&gt;the list of problems you've solved that you once thought were impossible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On a bad day, you want to have something to read that isn't made of memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  What helps when the feeling is about belonging
&lt;/h2&gt;

&lt;p&gt;If you're the only person in your circle doing this, the distance can feel like proof that you don't belong. A few things that can help:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Join an online community around a tool you actually use.&lt;/li&gt;
&lt;li&gt;Find one person a bit ahead of you and ask a specific question.&lt;/li&gt;
&lt;li&gt;Find one person a bit behind you and explain something. Teaching reminds you what you know.&lt;/li&gt;
&lt;li&gt;Share small work. Replies are a reminder that other people exist.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A note for people who feel this strongly
&lt;/h2&gt;

&lt;p&gt;If the feeling is constant, affects your sleep, appetite or relationships, or comes with hopelessness, it's more than a learning curve. Please talk to someone: a friend, family member, counsellor or doctor. That isn't weakness. It's the same logic as asking for help with a bug you can't solve alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reminders worth keeping
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Competence arrives unevenly. You can be strong in one area and a beginner in another.&lt;/li&gt;
&lt;li&gt;Experienced people also look things up constantly.&lt;/li&gt;
&lt;li&gt;Comparison to people with different resources is not a fair benchmark.&lt;/li&gt;
&lt;li&gt;The question isn't "am I good enough?" but "what's my next step?"&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;How do you handle it? And has anything specific ever actually helped?&lt;/p&gt;




&lt;p&gt;☕ &lt;strong&gt;Enjoyed this post? You can support my writing on Ko-fi.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ko-fi.com/surajnandan" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2z7dch5enfz2e5i2t2gj.png" alt="Support me on Ko-fi" width="286" height="73"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>career</category>
      <category>mentalhealth</category>
      <category>beginners</category>
      <category>discuss</category>
    </item>
    <item>
      <title>The History of AI, Part 4: Dartmouth 1956 and the Birth of Artificial Intelligence</title>
      <dc:creator>Suraj Nandan</dc:creator>
      <pubDate>Wed, 11 Nov 2026 04:30:00 +0000</pubDate>
      <link>https://dev.to/suraj_nandan/the-history-of-ai-part-4-dartmouth-1956-and-the-birth-of-artificial-intelligence-3lik</link>
      <guid>https://dev.to/suraj_nandan/the-history-of-ai-part-4-dartmouth-1956-and-the-birth-of-artificial-intelligence-3lik</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The History of AI, Part 4 of 24.&lt;/strong&gt; Part 3 followed the neurons and feedback loops of the 1940s. Now a small group of researchers gives the whole enterprise a name, a mission, and an audacious deadline. This is the story of the summer of 1956 and the "golden years" that followed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On 31 August 1955, a young mathematics professor at Dartmouth College named &lt;strong&gt;John McCarthy&lt;/strong&gt; sent a funding proposal to the Rockefeller Foundation. It was only a few pages long. It asked for money to bring about ten researchers together for the following summer to study a problem that, until then, had no common name.&lt;/p&gt;

&lt;p&gt;That proposal used the phrase &lt;strong&gt;"artificial intelligence"&lt;/strong&gt; for the first time in a document of this kind. And it contained one of the boldest sentences in the history of science:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The study is to proceed on the basis of the conjecture that every aspect of learning or any other feature of intelligence can in principle be so precisely described that a machine can be made to simulate it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That sentence is the founding statement of the field. It's also, if you read it closely, a &lt;em&gt;bet&lt;/em&gt;: that intelligence is the kind of thing that can be described precisely enough to be programmed. Seventy years later, we are still collecting on that bet and still arguing about the terms.&lt;/p&gt;

&lt;p&gt;This chapter tells the story of that workshop, the program that dazzled its attendees, and the heady decade of optimism that followed, a time when some of the smartest people alive believed human-level machine intelligence was a couple of decades away.&lt;/p&gt;

&lt;h2&gt;
  
  
  The state of the world in 1955
&lt;/h2&gt;

&lt;p&gt;To appreciate how audacious the proposal was, you need to picture the technology of the time.&lt;/p&gt;

&lt;p&gt;Electronic computers were barely a decade old. They were room-sized machines built from vacuum tubes, with a few thousand words of memory, programmed in machine code or primitive assembly language, and shared among whole departments. The IBM 701, announced in 1952, was IBM's first commercial scientific computer. The first high-level programming language, Fortran, would arrive in 1957. Programming meant punching cards or flipping switches. There were no operating systems as we understand them, no graphics, no networks.&lt;/p&gt;

&lt;p&gt;On the research side, the ingredients we've met in earlier chapters were all in the air:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Turing's idea that machines could think, and his 1950 paper.&lt;/li&gt;
&lt;li&gt;Shannon's work on information and chess.&lt;/li&gt;
&lt;li&gt;McCulloch and Pitts's neurons and Wiener's cybernetics.&lt;/li&gt;
&lt;li&gt;The first game-playing programs on real machines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What was missing was &lt;strong&gt;coherence&lt;/strong&gt;. Researchers who were interested in machine intelligence were scattered across mathematics, electrical engineering, psychology, and neuroscience, using different vocabularies. Some called it "automata theory," some "cybernetics," some "complex information processing." McCarthy wanted a clean break and a common banner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four authors, one proposal
&lt;/h2&gt;

&lt;p&gt;The proposal had four signatories, each of whom would leave a mark:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy852umliqei73hfs8m1r.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy852umliqei73hfs8m1r.jpg" alt="Marvin Minsky, co-author of the Dartmouth proposal and co-founder of the MIT AI Lab" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Marvin Minsky, co-author of the Dartmouth proposal and co-founder of the MIT AI Lab. Image: Joi, CC BY 2.0, via &lt;a href="https://commons.wikimedia.org/wiki/File:Marvin_Minsky_(1).jpg" rel="noopener noreferrer"&gt;Wikimedia Commons&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;John McCarthy&lt;/strong&gt; (1927-2011), then at Dartmouth, a mathematician who would soon invent the Lisp programming language and the idea of time-sharing, and who would found the Stanford AI Laboratory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Marvin Minsky&lt;/strong&gt; (1927-2016), then at Harvard, who had built the SNARC neural network machine we met in Part 3, and who would co-found the MIT AI Lab.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nathaniel Rochester&lt;/strong&gt; (1919-2001), the manager of information research at IBM, who had helped design the IBM 701 and had run early simulations of neural networks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude Shannon&lt;/strong&gt; (1916-2001), of Bell Labs, whom you already know as the father of information theory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They asked for &lt;strong&gt;$13,500&lt;/strong&gt; to support the summer workshop and received &lt;strong&gt;$7,500&lt;/strong&gt;. The proposal described a "2 month, 10 man study" and listed seven areas of interest, which read like a table of contents for the next half-century of AI research:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Automatic computers&lt;/strong&gt; (programming them to simulate higher functions)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How can a computer be programmed to use a language?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Neuron nets&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Theory of the size of a calculation&lt;/strong&gt; (what we'd now call computational complexity)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Self-improvement&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Abstractions&lt;/strong&gt; (forming concepts from sensory data)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Randomness and creativity&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Look at that list again. Natural language, neural networks, complexity, self-improvement, abstraction, creativity: every item is still an active frontier, and every one of them was already written down in 1955.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why "artificial intelligence"?
&lt;/h3&gt;

&lt;p&gt;McCarthy later explained that he chose the term deliberately. He wanted something neutral that wasn't already owned by an existing group. "Cybernetics" was strongly identified with Norbert Wiener, and McCarthy has said he did not want to adopt Wiener's framing or have to defer to him. "Automata studies," the title of a collection he and Shannon had edited, drew mostly papers about abstract machines rather than intelligence, which disappointed McCarthy. So he picked a bolder, more provocative label.&lt;/p&gt;

&lt;p&gt;The name was a stroke of marketing genius, but it also had a long-term cost. "Artificial intelligence" promised a lot. Every time the field fell short of the promise, the name made the disappointment sting more. Some of the field's later troubles, the hype cycles and AI winters we'll meet in Parts 6 and 8, can be traced to this early choice of grand terminology.&lt;/p&gt;
&lt;h2&gt;
  
  
  The workshop itself
&lt;/h2&gt;

&lt;p&gt;The Dartmouth Summer Research Project on Artificial Intelligence ran from roughly mid-June through August 1956 in Hanover, New Hampshire. Historians who have reconstructed what happened describe it as less of a focused meeting and more of a loose, drifting, extended conversation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu1a4ys5ypggnmgss3nkg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fu1a4ys5ypggnmgss3nkg.jpg" alt="Dartmouth Hall at Dartmouth College, Hanover, New Hampshire, home of the 1956 summer workshop" width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Dartmouth Hall at Dartmouth College, Hanover, New Hampshire, home of the 1956 summer workshop. Image: Daderot, CC0, via &lt;a href="https://commons.wikimedia.org/wiki/File:Dartmouth_Hall_-_Dartmouth_College_-_DSC01608.jpg" rel="noopener noreferrer"&gt;Wikimedia Commons&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;People came and went. Only a few stayed for the whole duration. Attendees at various points included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ray Solomonoff&lt;/strong&gt;, who worked on probabilistic approaches to induction and would help found the theory of algorithmic probability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Oliver Selfridge&lt;/strong&gt;, who developed early ideas about pattern recognition (his "Pandemonium" model, in which many simple "demons" shout evidence for competing interpretations).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trenchard More&lt;/strong&gt;, a mathematician who worked on logic and array theory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Arthur Samuel&lt;/strong&gt;, of IBM, who was writing a checkers program that learned from experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Allen Newell&lt;/strong&gt; and &lt;strong&gt;Herbert Simon&lt;/strong&gt;, who arrived with something none of the organizers had expected.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By the standard of "did they solve intelligence that summer?", the workshop failed spectacularly. McCarthy himself later recalled that it did not produce the collective breakthroughs he had hoped for, partly because attendees largely wanted to pursue their own approaches rather than collaborate. But it succeeded at something just as important: it gave a group of scattered researchers a &lt;strong&gt;name, an identity, and each other&lt;/strong&gt;. Most of the leaders of American AI for the next twenty years were either in that room or became students of those who were.&lt;/p&gt;
&lt;h2&gt;
  
  
  The star of the summer: Logic Theorist
&lt;/h2&gt;

&lt;p&gt;The one real result that was demonstrated at Dartmouth belonged to two visitors from Pittsburgh.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Allen Newell&lt;/strong&gt; (1927-1992), a young researcher at the RAND Corporation and Carnegie Tech, and &lt;strong&gt;Herbert Simon&lt;/strong&gt; (1916-2001), a polymath professor who would later win the &lt;strong&gt;Nobel Prize in Economics&lt;/strong&gt; (1978) for his work on decision-making, had been working with a RAND programmer named &lt;strong&gt;Cliff Shaw&lt;/strong&gt;. Together they had built a program called the &lt;strong&gt;Logic Theorist&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Its goal was ambitious: to &lt;strong&gt;prove mathematical theorems&lt;/strong&gt;. Specifically, it worked on the theorems in the second chapter of Whitehead and Russell's &lt;em&gt;Principia Mathematica&lt;/em&gt;, the same monumental work we met in Part 1.&lt;/p&gt;

&lt;p&gt;Simon later recalled that in the winter of 1955, he told his students that over the Christmas holiday "Al Newell and I invented a thinking machine." There was no computer available to run the program at that point, so the team famously simulated it by hand, with Simon's family and students playing the roles of individual subroutines, passing index cards back and forth. Once the program was ready, it ran on the &lt;strong&gt;JOHNNIAC&lt;/strong&gt; computer at RAND.&lt;/p&gt;
&lt;h3&gt;
  
  
  What it actually did
&lt;/h3&gt;

&lt;p&gt;The Logic Theorist didn't prove theorems by brute-force trying all possible deductions. That would have been hopeless, because the number of possible chains of reasoning explodes. Instead, it used &lt;strong&gt;heuristics&lt;/strong&gt;: rules of thumb that guided its search toward promising paths. Newell and Simon's key insight was that human problem-solvers don't exhaustively search either. They use hunches, working backward from the goal, spotting similar problems they've already solved.&lt;/p&gt;

&lt;p&gt;The program started with the axioms and tried to reach a goal theorem by applying a few rules of inference: substitution, detachment, and replacement. It worked &lt;em&gt;backward&lt;/em&gt; from the target, breaking it into subgoals. When a subgoal seemed unpromising, the program abandoned it.&lt;/p&gt;

&lt;p&gt;The results were striking. Logic Theorist proved &lt;strong&gt;38 of the first 52 theorems&lt;/strong&gt; in &lt;em&gt;Principia Mathematica&lt;/em&gt; chapter 2. For one of them, theorem 2.85, it found a proof that was more elegant than the one Whitehead and Russell had written. Simon was delighted and reportedly wrote to Bertrand Russell, who, according to the story, was amused.&lt;/p&gt;

&lt;p&gt;Newell and Simon tried to publish the result in the &lt;em&gt;Journal of Symbolic Logic&lt;/em&gt;, listing the program as a co-author. The editors rejected the paper. Whatever their reasons, it was a funny moment: perhaps the first time a program was effectively denied authorship credit.&lt;/p&gt;
&lt;h3&gt;
  
  
  The significance
&lt;/h3&gt;

&lt;p&gt;Why did attendees care so much? Because the Logic Theorist demonstrated that a machine could do something that seemed to require &lt;strong&gt;reasoning&lt;/strong&gt;, and it did it using &lt;strong&gt;symbols and search&lt;/strong&gt;, not just arithmetic.&lt;/p&gt;

&lt;p&gt;Newell and Simon went further. They claimed that the program wasn't merely &lt;em&gt;simulating&lt;/em&gt; human problem-solving; it embodied the &lt;em&gt;same kind of process&lt;/em&gt; the human mind used. They called it "information processing," and they would later formalize their view as the &lt;strong&gt;Physical Symbol System Hypothesis&lt;/strong&gt; (1976): &lt;em&gt;a physical symbol system has the necessary and sufficient means for general intelligent action.&lt;/em&gt; In plain words: thinking &lt;em&gt;is&lt;/em&gt; symbol manipulation, whether it takes place in a brain or in a computer. This was the manifesto of the symbolic approach.&lt;/p&gt;

&lt;p&gt;It's a philosophical position with huge consequences. If it's true, then building AI is just a matter of finding the right symbols and the right rules. And that is what the field spent the next three decades trying to do.&lt;/p&gt;
&lt;h2&gt;
  
  
  The idea at the heart of early AI: search
&lt;/h2&gt;

&lt;p&gt;Let's pause and appreciate the central technique of this era, because it's the foundation of so much that follows.&lt;/p&gt;

&lt;p&gt;Many problems can be framed as &lt;strong&gt;search&lt;/strong&gt;: you have a starting state, a goal state, and a set of moves that take you from one state to another. Solving the problem means finding a sequence of moves from start to goal. A theorem prover searches through the space of possible proofs. A chess program searches through possible game continuations. A route planner searches through possible roads.&lt;/p&gt;

&lt;p&gt;The difficulty is that the space of possibilities grows exponentially, which is called the &lt;strong&gt;combinatorial explosion&lt;/strong&gt;. In chess, for example, there are on the order of 10^120 possible games, far more than the number of atoms in the observable universe. Even with a fast computer you can't try them all. Intelligence, in this view, is largely about &lt;strong&gt;searching smartly&lt;/strong&gt;: using knowledge to prune the search and focus effort where it's most likely to pay off.&lt;/p&gt;

&lt;p&gt;Here's the idea in a short program. It solves the classic &lt;strong&gt;water jug puzzle&lt;/strong&gt;: with a 3-liter jug and a 5-liter jug, how do you measure exactly 4 liters? First, we search blindly (breadth-first); then we see how structure helps.&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;neighbors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;caps&lt;/span&gt;&lt;span class="o"&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;5&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;
    &lt;span class="n"&gt;ca&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;caps&lt;/span&gt;
    &lt;span class="n"&gt;moves&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;fill A&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;ca&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fill B&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;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;empty A&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;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;empty B&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;a&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;pour A-&amp;gt;B&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="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cb&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pour B-&amp;gt;A&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="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ca&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ca&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;a&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;moves&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&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;solve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;goal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&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="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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="n"&gt;frontier&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;start&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])])&lt;/span&gt;
    &lt;span class="n"&gt;seen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;start&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;frontier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;frontier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;popleft&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;goal&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;state&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;path&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;state&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;move&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nxt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;neighbors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&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;nxt&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;seen&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;seen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nxt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;frontier&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;nxt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;move&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;nxt&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="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&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="nf"&gt;solve&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It finds a six-step solution. The &lt;em&gt;state space&lt;/em&gt; here is tiny, only a few dozen possible configurations, so brute force works instantly. Now imagine a space with more states than atoms in the universe. That is chess, or theorem proving, or planning a real-world action. For those, you need heuristics, and finding good heuristics became the central craft of early AI.&lt;/p&gt;

&lt;h2&gt;
  
  
  From the Logic Theorist to the General Problem Solver
&lt;/h2&gt;

&lt;p&gt;Newell and Simon didn't stop. In 1957 they began work on a more ambitious program: the &lt;strong&gt;General Problem Solver (GPS)&lt;/strong&gt;. Where Logic Theorist was specialized for logic proofs, GPS aimed to separate the &lt;em&gt;problem-solving method&lt;/em&gt; from the &lt;em&gt;problem domain&lt;/em&gt;, so the same machinery could tackle different puzzles.&lt;/p&gt;

&lt;p&gt;Its signature technique was &lt;strong&gt;means-ends analysis&lt;/strong&gt;. At each step, the program compares the current state with the goal, finds the most important &lt;em&gt;difference&lt;/em&gt; between them, and picks an operator likely to reduce that difference. If the operator can't be applied yet, it sets up a &lt;em&gt;subgoal&lt;/em&gt; of making it applicable. It's the style of reasoning you use when you think, "I want to get to the airport. The difference is distance. A taxi reduces distance. To take a taxi I need to call one..."&lt;/p&gt;

&lt;p&gt;Newell and Simon were less interested in building a better machine than in understanding the human mind. They recorded people "thinking aloud" while solving puzzles and compared the protocols to GPS's behavior, an early attempt to treat programs as &lt;strong&gt;theories of cognition&lt;/strong&gt;. This line of work grew into the field of &lt;strong&gt;cognitive science&lt;/strong&gt;, and Simon and Newell's colleagues at Carnegie Mellon became enormously influential. GPS also exposed the limits of the approach: it worked well on neat, well-defined puzzles but struggled with the open-ended complexity of the real world.&lt;/p&gt;

&lt;h2&gt;
  
  
  McCarthy's contributions: Lisp and the Advice Taker
&lt;/h2&gt;

&lt;p&gt;While Newell and Simon built programs, McCarthy built &lt;em&gt;tools&lt;/em&gt;. In 1958, he created &lt;strong&gt;Lisp&lt;/strong&gt; (LISt Processing), a programming language designed to manipulate symbolic expressions. It introduced ideas that were way ahead of their time: recursion as a basic technique, functions as data, automatic memory management (garbage collection), and the idea that code and data can have the same representation. Lisp became the language of AI for decades, and its descendants (Scheme, Clojure, and the lambda expressions in Python and JavaScript) carry its influence.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9nxuxi4vwu2ike1kwpmn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9nxuxi4vwu2ike1kwpmn.jpg" alt="John McCarthy, who coined “artificial intelligence” and created Lisp" width="799" height="532"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;John McCarthy, who coined “artificial intelligence” and created Lisp. Image: null0 from Singapore, Singapore, CC BY 2.0, via &lt;a href="https://commons.wikimedia.org/wiki/File:John_McCarthy_(computer_scientist)_Stanford_2006_(272020300).jpg" rel="noopener noreferrer"&gt;Wikimedia Commons&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In the same period he proposed the &lt;strong&gt;Advice Taker&lt;/strong&gt;, a hypothetical program described in his 1959 paper "Programs with Common Sense." The idea was that a system should be able to &lt;em&gt;accept advice&lt;/em&gt; stated in a formal language and act on it, using logical deduction to figure out what to do. Whereas Newell and Simon were driven by simulating human psychology, McCarthy was driven by the dream of a &lt;em&gt;logical&lt;/em&gt; machine, closer to Leibniz's "Let us calculate." He believed common-sense knowledge could be written in formal logic and reasoned over, an ambition that would occupy him and others for decades and run, painfully, into the problem of how much common sense there is to write down.&lt;/p&gt;

&lt;p&gt;McCarthy also pioneered &lt;strong&gt;time-sharing&lt;/strong&gt;, the idea that many users could interact with one computer at the same time, which was crucial for AI researchers who wanted interactive programming rather than slow batch processing. And in 1959, he and Minsky founded the &lt;strong&gt;MIT Artificial Intelligence Project&lt;/strong&gt;, which grew into the MIT AI Lab. In 1963 McCarthy moved to Stanford and founded the &lt;strong&gt;Stanford Artificial Intelligence Laboratory (SAIL)&lt;/strong&gt;. Carnegie Mellon (Newell and Simon) became the third major center. Together, these hubs trained the generation that would define the field.&lt;/p&gt;

&lt;h2&gt;
  
  
  Samuel's checkers and the birth of "machine learning"
&lt;/h2&gt;

&lt;p&gt;Not everyone at Dartmouth was working on symbolic logic. &lt;strong&gt;Arthur Samuel&lt;/strong&gt; at IBM was building a checkers (draughts) program that could &lt;em&gt;improve with experience&lt;/em&gt;. His program evaluated board positions using a weighted combination of features, such as piece advantage and mobility, and it adjusted the weights by comparing its predictions to the results of games it played. It could also play against itself, learning from the outcomes.&lt;/p&gt;

&lt;p&gt;By the late 1950s, the program was good enough to beat a respectable amateur, and in 1962 it defeated a self-proclaimed checkers master in a widely publicized match (though that opponent was not a top player, and the match was later put in context). Samuel coined the phrase &lt;strong&gt;"machine learning"&lt;/strong&gt; in a 1959 paper, defining it, in a widely quoted paraphrase, as the field of study that gives computers "the ability to learn without being explicitly programmed."&lt;/p&gt;

&lt;p&gt;It was a small thread in the 1950s, overshadowed by the symbolic approach. But it was the same thread Turing had pulled with his "child machine," and the same one that would come roaring back later. Samuel's program used ideas we'd recognize today: a scoring function, self-play, and adjusting parameters based on outcomes, a primitive ancestor of reinforcement learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  The golden years: bold promises
&lt;/h2&gt;

&lt;p&gt;The period from roughly 1956 to 1974 is often called the &lt;strong&gt;golden years&lt;/strong&gt; of AI. Funding from the US Department of Defense's Advanced Research Projects Agency (ARPA, later DARPA) flowed generously, with few strings attached. J.C.R. Licklider, who ran ARPA's Information Processing Techniques Office from 1962, believed in funding talented people and letting them explore. MIT, Stanford, and CMU got millions.&lt;/p&gt;

&lt;p&gt;Programs of this era achieved results that astonished observers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Programs that solved &lt;strong&gt;algebra word problems&lt;/strong&gt; (STUDENT, by Daniel Bobrow).&lt;/li&gt;
&lt;li&gt;Programs that did &lt;strong&gt;symbolic integration&lt;/strong&gt; like a calculus student (SAINT, by James Slagle).&lt;/li&gt;
&lt;li&gt;Programs that solved &lt;strong&gt;geometric analogy problems&lt;/strong&gt; from IQ tests (ANALOGY, by Thomas Evans).&lt;/li&gt;
&lt;li&gt;Programs that proved &lt;strong&gt;geometry theorems&lt;/strong&gt; (Herbert Gelernter's Geometry Theorem Prover).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(We'll look at several of these, plus ELIZA and Shakey, in Part 5.)&lt;/p&gt;

&lt;p&gt;And the pronouncements were stunning. In 1957, Herbert Simon predicted that within ten years a computer would be the world's chess champion and would discover and prove an important new mathematical theorem. In 1965, he wrote that "machines will be capable, within twenty years, of doing any work a man can do." In 1967, Marvin Minsky declared that "within a generation... the problem of creating 'artificial intelligence' will substantially be solved." (Minsky later disputed how some of these statements were quoted, but the overall mood is undeniable.)&lt;/p&gt;

&lt;p&gt;It's easy to laugh at these forecasts now, and we should note that Simon's chess prediction was off by about thirty years: Deep Blue beat Garry Kasparov in 1997, as we'll see in Part 11. But try to put yourself in their position. They had seen computers go from not existing to proving theorems in ten years. Extrapolating that trend, it didn't seem crazy to expect human-level intelligence soon. The mistake was assuming that the &lt;em&gt;hard part&lt;/em&gt; was already behind them.&lt;/p&gt;

&lt;h3&gt;
  
  
  The easy problems were hard, and the hard problems were easy
&lt;/h3&gt;

&lt;p&gt;Here's the central irony that took the field decades to appreciate, which the roboticist Hans Moravec would later describe as &lt;strong&gt;Moravec's paradox&lt;/strong&gt;: tasks that humans find hard, like proving theorems, playing chess, and solving algebra problems, turned out to be &lt;em&gt;relatively easy&lt;/em&gt; for computers, because they are clean, well-defined, and symbolic. Tasks that a toddler does without effort, like recognizing a face, picking up an egg, understanding a sentence, and walking across a cluttered room, turned out to be &lt;em&gt;enormously&lt;/em&gt; hard.&lt;/p&gt;

&lt;p&gt;The early researchers worked on the first category because it was tractable, and they took progress there as a sign that the rest would follow. In fact, the real world is messy, ambiguous, noisy, and open-ended, and capturing it in neat symbols and rules was far harder than anyone anticipated. This is exactly what the next four chapters are about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two camps take shape
&lt;/h2&gt;

&lt;p&gt;By the end of the 1950s, the field was dividing into two camps with different philosophies, a split we've seen coming since Part 3.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The symbolists&lt;/strong&gt;, led by McCarthy, Newell, Simon, and to a large extent Minsky, believed that intelligence consisted of manipulating symbols according to rules. The tools were logic, search, and heuristics. The model was the mind as a program.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The connectionists&lt;/strong&gt;, inspired by McCulloch, Pitts, and Hebb, believed that intelligence emerged from networks of simple units learning from data. The tools were artificial neurons and learning rules. The model was the mind as a brain.&lt;/p&gt;

&lt;p&gt;In the late 1950s, both camps got a boost. On the symbolic side: Logic Theorist, Lisp, GPS. On the connectionist side, a psychologist named &lt;strong&gt;Frank Rosenblatt&lt;/strong&gt; unveiled a learning machine called the &lt;strong&gt;Perceptron&lt;/strong&gt;, and the Navy and the press got very excited. That story, and the intense rivalry that followed, is in the next chapter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Legacy of Dartmouth
&lt;/h2&gt;

&lt;p&gt;It's tempting to call Dartmouth the "birth" of AI, but historians prefer to see it more as a baptism. The work had started before: Turing, McCulloch and Pitts, Shannon, and others had already done much of the groundwork. What Dartmouth did was to rally a community and a name around the project.&lt;/p&gt;

&lt;p&gt;Its legacy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A name and a field.&lt;/strong&gt; "Artificial intelligence" stuck, for better and worse.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A set of research directions.&lt;/strong&gt; Language, learning, neural nets, search, and self-improvement all appear on that 1955 list.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Institutions.&lt;/strong&gt; MIT, Stanford, and Carnegie Mellon became the nerve centers of AI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A culture of optimism.&lt;/strong&gt; The founders' confidence energized funding and recruitment, and also set expectations that would be painfully unmet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A defining paradigm.&lt;/strong&gt; The idea that intelligence is symbol manipulation, formalized in the Physical Symbol System Hypothesis, shaped decades of research.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In 2006, on the fiftieth anniversary, several of the original attendees, including McCarthy, Minsky, Solomonoff, More, and Selfridge, reunited at Dartmouth. Seeing the pioneers together at last was a poignant reminder of how long this story has been unfolding, and how much of it has yet to be written.&lt;/p&gt;

&lt;h2&gt;
  
  
  A scorecard: the seven topics, seventy years later
&lt;/h2&gt;

&lt;p&gt;The 1955 proposal listed seven areas to study. It's a fun exercise to grade them against where things stand today:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;1955 topic&lt;/th&gt;
&lt;th&gt;Where it stands&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Automatic computers&lt;/strong&gt; (programming to simulate higher functions)&lt;/td&gt;
&lt;td&gt;Achieved beyond anything imagined; computers now write essays and code.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Programming a computer to use language&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The biggest success story. Large language models (Parts 19 to 21) converse fluently in dozens of languages, though "understanding" remains debated.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Neuron nets&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Vindicated. Deep neural networks power nearly every modern AI system.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Theory of the size of a calculation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Became computational complexity theory, including NP-completeness (Part 6). It explained &lt;em&gt;why&lt;/em&gt; many problems are hard.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Self-improvement&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Partly achieved: systems like AlphaZero improve by playing themselves (Part 17), but no system rewrites its own architecture in an open-ended way.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Abstractions&lt;/strong&gt; (forming concepts from sensory data)&lt;/td&gt;
&lt;td&gt;Largely achieved through learned representations: a vision network discovers "edge," "eye," and "face" on its own (Part 14).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Randomness and creativity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Randomness turned out to be essential (stochastic training, sampling), and creativity is hotly debated (Parts 16, 17, and 20).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Remarkably, the founders asked the right questions. What they badly underestimated was the &lt;em&gt;time&lt;/em&gt;, and the central role that data and computing power would play.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who was who
&lt;/h2&gt;

&lt;p&gt;A quick cast list for the rest of the series:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;John McCarthy:&lt;/strong&gt; coined "AI," invented Lisp, founded SAIL at Stanford.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Marvin Minsky:&lt;/strong&gt; built SNARC, co-founded the MIT AI Lab, co-wrote &lt;em&gt;Perceptrons&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude Shannon:&lt;/strong&gt; information theory, chess programming, Theseus.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nathaniel Rochester:&lt;/strong&gt; IBM, early neural network simulations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Allen Newell and Herbert Simon:&lt;/strong&gt; Logic Theorist, GPS, the symbolic paradigm; Simon won a Nobel Prize in Economics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Arthur Samuel:&lt;/strong&gt; the checkers program that learned; coined "machine learning."&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick glossary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Heuristic:&lt;/strong&gt; a rule of thumb that usually, but not always, finds good solutions quickly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Combinatorial explosion:&lt;/strong&gt; the rapid growth in the number of possibilities as a problem gets bigger.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Means-ends analysis:&lt;/strong&gt; reducing the difference between the current state and the goal, step by step.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Symbolic AI:&lt;/strong&gt; the approach that represents knowledge as symbols and manipulates them by rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time-sharing:&lt;/strong&gt; letting many users interact with one computer at once.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;In 1955, &lt;strong&gt;McCarthy, Minsky, Rochester, and Shannon&lt;/strong&gt; proposed a summer workshop at Dartmouth, coining the phrase &lt;strong&gt;"artificial intelligence"&lt;/strong&gt; and betting that "every aspect of learning or any other feature of intelligence" could be precisely described and simulated.&lt;/li&gt;
&lt;li&gt;The workshop (summer 1956) produced no single breakthrough, but it founded a &lt;strong&gt;community, a name, and a research agenda&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Newell, Simon, and Shaw's Logic Theorist&lt;/strong&gt; proved theorems from &lt;em&gt;Principia Mathematica&lt;/em&gt; using &lt;strong&gt;heuristic search&lt;/strong&gt;, and their &lt;strong&gt;General Problem Solver&lt;/strong&gt; introduced means-ends analysis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;McCarthy&lt;/strong&gt; created &lt;strong&gt;Lisp&lt;/strong&gt; and the Advice Taker idea; &lt;strong&gt;Samuel&lt;/strong&gt; coined &lt;strong&gt;"machine learning"&lt;/strong&gt; with a checkers program that learned from self-play.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;golden years&lt;/strong&gt; (1956-1974) brought generous DARPA funding, impressive demonstrations, and wildly optimistic predictions.&lt;/li&gt;
&lt;li&gt;The era's central lesson, later named &lt;strong&gt;Moravec's paradox&lt;/strong&gt;, was that tasks hard for humans (logic, chess) were comparatively easy for machines, while tasks easy for humans (perception, common sense) were extremely hard.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Extend the jug solver.&lt;/strong&gt; Change the capacities and goal (try jugs of 7 and 11 liters to measure 6). Which problems have no solution? Can you spot a pattern (hint: think about greatest common divisors)?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add a heuristic.&lt;/strong&gt; Replace the breadth-first queue with a priority queue that prefers states where one jug is closer to the goal volume. Count how many states each version explores. That difference is the whole idea of a heuristic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read the original.&lt;/strong&gt; Search for the text of the 1955 Dartmouth proposal (it's short and freely available online). Pick one of its seven topics and write a paragraph on how much progress has been made since 1955.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Next up
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;Part 5&lt;/strong&gt;, we dive into the programs and machines of the golden years: Rosenblatt's Perceptron and the media frenzy around it, Joseph Weizenbaum's ELIZA and the unsettling "ELIZA effect," Terry Winograd's SHRDLU and its blocks world, and Shakey, the first mobile robot that reasoned about its own actions. It's a story of real breakthroughs, and the first cracks.&lt;/p&gt;

&lt;p&gt;If you enjoyed this chapter, follow the series and tell me in the comments: which Dartmouth prediction do you think has aged best, and which worst?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;See you in Part 5.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;☕ &lt;strong&gt;If this series helped you, you can support my writing on Ko-fi.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ko-fi.com/surajnandan" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2z7dch5enfz2e5i2t2gj.png" alt="Support me on Ko-fi" width="286" height="73"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>history</category>
      <category>computerscience</category>
      <category>machinelearning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Shipping a Vercel serverless API route: the short version</title>
      <dc:creator>Suraj Nandan</dc:creator>
      <pubDate>Wed, 11 Nov 2026 03:30:00 +0000</pubDate>
      <link>https://dev.to/suraj_nandan/shipping-a-vercel-serverless-api-route-the-short-version-ilc</link>
      <guid>https://dev.to/suraj_nandan/shipping-a-vercel-serverless-api-route-the-short-version-ilc</guid>
      <description>&lt;p&gt;My portfolio has a small chat feature backed by a serverless function on Vercel. This post walks through the pattern end to end: the file shape, the gotchas I hit, how to keep costs sane, and the checks I run after each deploy.&lt;/p&gt;

&lt;p&gt;If you've never written a serverless function, this is a good first one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "serverless function" means here
&lt;/h2&gt;

&lt;p&gt;You write a file. The host runs it on demand, in response to an HTTP request, and you pay (or use free quota) per invocation instead of keeping a server running. For a small endpoint like a chat proxy, that's ideal: no server to maintain, and it scales to zero when nobody's using it.&lt;/p&gt;

&lt;p&gt;On Vercel, any file inside the &lt;code&gt;api/&lt;/code&gt; folder becomes an endpoint. &lt;code&gt;api/chat.ts&lt;/code&gt; is served at &lt;code&gt;/api/chat&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shape of a function
&lt;/h2&gt;

&lt;p&gt;I use the Web-standard &lt;code&gt;Request&lt;/code&gt; / &lt;code&gt;Response&lt;/code&gt; style, exporting a function per HTTP method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// api/chat.ts&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// A cheap health check: lets me verify a deploy with curl.&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&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;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2000&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="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// call your model here, using a key from process.env&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;askModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;reply&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;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Validate input.&lt;/strong&gt; Never pass raw user input anywhere without checking its type and size. Limits protect your bill.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Return proper status codes.&lt;/strong&gt; &lt;code&gt;400&lt;/code&gt; for bad input, &lt;code&gt;500&lt;/code&gt; for your own failure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep it small.&lt;/strong&gt; A function should do one thing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Calling it from the frontend
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;ask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/chat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Request failed&lt;/span&gt;&lt;span class="dl"&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="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;reply&lt;/span&gt; &lt;span class="kd"&gt;as &lt;/span&gt;&lt;span class="kr"&gt;string&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;h2&gt;
  
  
  Secrets stay on the server
&lt;/h2&gt;

&lt;p&gt;The model API key must never be in the browser or the repository. Put it in an &lt;strong&gt;environment variable&lt;/strong&gt; in the host's dashboard, and read it in the function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Not configured&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;503&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For my project, the key lives in the Vercel project's environment settings, and the function simply reads it. A key committed to a repo should be considered leaked, even if the repo is private.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gotchas I've hit
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Import extensions
&lt;/h3&gt;

&lt;p&gt;When importing sibling files from inside &lt;code&gt;api/&lt;/code&gt;, include the &lt;code&gt;.js&lt;/code&gt; extension in the import path, even though the source is TypeScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;buildPrompt&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./_prompt.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// note: .js&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Leave it off and the deployed function may fail to resolve the module, which is the kind of thing that works locally and breaks on the host.&lt;/p&gt;

&lt;h3&gt;
  
  
  Files that shouldn't be endpoints
&lt;/h3&gt;

&lt;p&gt;Files in &lt;code&gt;api/&lt;/code&gt; become routes. A helper that shouldn't be reachable from the internet should be prefixed with an underscore (&lt;code&gt;_prompt.ts&lt;/code&gt;) or live outside &lt;code&gt;api/&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cold starts and timeouts
&lt;/h3&gt;

&lt;p&gt;A function that hasn't run recently starts slower, and every function has a maximum duration. Keep work short and consider streaming for slow model calls.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pick the smallest model that does the job
&lt;/h2&gt;

&lt;p&gt;Cost matters when you're the one paying. For a portfolio chat that answers questions about my work, I chose a small, fast, inexpensive model (Claude Haiku) over a larger one. Smaller models are quicker, cheaper and usually good enough when the task is narrow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Protect your wallet
&lt;/h2&gt;

&lt;p&gt;A public endpoint that calls a paid API can be abused. Basic protections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Validate and cap input length.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limit&lt;/strong&gt; per IP or per session.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set a monthly spend limit&lt;/strong&gt; on the provider dashboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Give the model a narrow job&lt;/strong&gt; in the system prompt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Don't expose a general-purpose proxy.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The check I run after every deploy
&lt;/h2&gt;

&lt;p&gt;Remember Day 3: a deploy can fail silently. A health check makes verification trivial:&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;# Is the function up?&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://your-domain.com/api/chat
&lt;span class="c"&gt;# {"ready":true}&lt;/span&gt;

&lt;span class="c"&gt;# Other things worth confirming are live&lt;/span&gt;
curl &lt;span class="nt"&gt;-sI&lt;/span&gt; https://your-domain.com/rss.xml | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I run these against the production domain after each deploy. Ten seconds, and I know the &lt;em&gt;new&lt;/em&gt; build is serving.&lt;/p&gt;

&lt;h2&gt;
  
  
  A deployment checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Env vars set in the host dashboard (production &lt;em&gt;and&lt;/em&gt; preview if needed)&lt;/li&gt;
&lt;li&gt;[ ] Input validated, length capped&lt;/li&gt;
&lt;li&gt;[ ] Health endpoint works&lt;/li&gt;
&lt;li&gt;[ ] No secrets in the repo&lt;/li&gt;
&lt;li&gt;[ ] Spend limit set at the provider&lt;/li&gt;
&lt;li&gt;[ ] Verified on the live domain, not just locally&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Streaming a response
&lt;/h2&gt;

&lt;p&gt;For slow model calls, streaming lets the user see text as it arrives instead of staring at a spinner. A minimal pattern with Web streams:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;encoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextEncoder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ReadableStream&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;piece&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nf"&gt;askModelStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;   &lt;span class="c1"&gt;// your provider's stream&lt;/span&gt;
        &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enqueue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;encoder&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="nx"&gt;piece&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/plain; charset=utf-8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cache-control&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no-store&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the client, read it incrementally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/chat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getReader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TextDecoder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(;;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;done&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;appendToUI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;h2&gt;
  
  
  Test locally before deploying
&lt;/h2&gt;

&lt;p&gt;The Vercel CLI can run your functions locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-g&lt;/span&gt; vercel
vercel dev          &lt;span class="c"&gt;# serves the site and the /api routes locally&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; localhost:3000/api/chat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It reads environment variables from a local file (keep that file out of git), so you can test with a key without ever committing it.&lt;/p&gt;

&lt;h2&gt;
  
  
  A simple rate-limit sketch
&lt;/h2&gt;

&lt;p&gt;On a serverless host, in-memory counters reset on cold starts and don't share across instances, so a robust limit needs shared storage (a small key-value store). To show the &lt;em&gt;idea&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;allow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;limit&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="nx"&gt;windowMs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hits&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="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;rec&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;rec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;count&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="na"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;windowMs&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;rec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;limit&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;Treat that as a speed bump, not a lock. For anything you pay for, back it with a provider-side spend limit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error handling that doesn't leak
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Return a &lt;strong&gt;generic&lt;/strong&gt; message to the client ("Something went wrong"), and log the detail on the server.&lt;/li&gt;
&lt;li&gt;Never include stack traces or provider error bodies in responses.&lt;/li&gt;
&lt;li&gt;Use correct status codes so the frontend can react: 400 bad input, 429 too many requests, 503 not configured.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/* ... */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chat failed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Something went wrong&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&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;h2&gt;
  
  
  CORS in one paragraph
&lt;/h2&gt;

&lt;p&gt;If the frontend and the function share a domain (as with &lt;code&gt;/api/chat&lt;/code&gt; on the same site), you don't need CORS. If another origin calls it, you must return the right &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; header for &lt;em&gt;specific, trusted&lt;/em&gt; origins, never a blanket &lt;code&gt;*&lt;/code&gt; on an endpoint that spends your money.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits to know about
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Functions have &lt;strong&gt;maximum run times&lt;/strong&gt; and &lt;strong&gt;memory limits&lt;/strong&gt; on a given plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cold starts&lt;/strong&gt; make the first request slower.&lt;/li&gt;
&lt;li&gt;Local files are read-only or ephemeral. Don't treat the filesystem as storage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Request and response sizes&lt;/strong&gt; are capped.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check your host's current limits in its documentation, since they change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-launch checklist for an AI-backed endpoint
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Input validated and capped&lt;/li&gt;
&lt;li&gt;[ ] Spend limit set with the provider&lt;/li&gt;
&lt;li&gt;[ ] Rate limiting in place&lt;/li&gt;
&lt;li&gt;[ ] Narrow system prompt&lt;/li&gt;
&lt;li&gt;[ ] No secrets in the repo or in logs&lt;/li&gt;
&lt;li&gt;[ ] Health check responds&lt;/li&gt;
&lt;li&gt;[ ] Failure path returns a friendly error&lt;/li&gt;
&lt;li&gt;[ ] Verified on the production URL&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;What's the smallest useful serverless function you've shipped?&lt;/p&gt;




&lt;p&gt;☕ &lt;strong&gt;Enjoyed this post? You can support my writing on Ko-fi.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ko-fi.com/surajnandan" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2z7dch5enfz2e5i2t2gj.png" alt="Support me on Ko-fi" width="286" height="73"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vercel</category>
      <category>serverless</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How I try to write posts people actually finish reading</title>
      <dc:creator>Suraj Nandan</dc:creator>
      <pubDate>Tue, 10 Nov 2026 03:30:00 +0000</pubDate>
      <link>https://dev.to/suraj_nandan/how-i-try-to-write-posts-people-actually-finish-reading-84a</link>
      <guid>https://dev.to/suraj_nandan/how-i-try-to-write-posts-people-actually-finish-reading-84a</guid>
      <description>&lt;p&gt;These are things I'm &lt;em&gt;practising&lt;/em&gt;, not claiming mastery of. If you read a post of mine and found it dull, that's feedback I want.&lt;/p&gt;

&lt;p&gt;Still, after writing technical posts for my own site and this series, a few patterns stand out. This post is a field guide to the structure I aim for, a pre-publish checklist, and the mistakes I try to avoid.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the reader's question
&lt;/h2&gt;

&lt;p&gt;Every post answers a question someone has, even if they haven't typed it. Before writing, finish this sentence:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;After reading this, you'll be able to ______.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you can't, the post doesn't have a purpose yet. "Understand RAG" is vague. "Explain chunking and retrieval well enough to build a five-note prototype" is concrete.&lt;/p&gt;

&lt;h2&gt;
  
  
  The title is a promise
&lt;/h2&gt;

&lt;p&gt;Good titles are specific and honest:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vague: &lt;em&gt;Thoughts on databases&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Better: &lt;em&gt;I put my business rules in the database instead of React, here's what it bought me&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second tells you the topic, a decision, and a payoff. But don't overpromise. A title that claims more than the post delivers loses trust faster than a dull title loses clicks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first paragraph earns the second
&lt;/h2&gt;

&lt;p&gt;No throat-clearing. Skip "In today's fast-paced world of software development…". Start with the problem, a surprise, or a sentence that sets the stakes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"When something breaks, my worst instinct is to start changing things."&lt;/li&gt;
&lt;li&gt;"My site's deploys silently failed for two weeks."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a stranger can't tell why to keep reading after three sentences, cut until they can.&lt;/p&gt;

&lt;h2&gt;
  
  
  One idea per post
&lt;/h2&gt;

&lt;p&gt;If a post has three big ideas, it's three posts. Readers finish things with a clear spine. Everything that doesn't serve the spine goes into another post or gets cut.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use structure, then trust it
&lt;/h2&gt;

&lt;p&gt;For technical writing, I use a repeating shape:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The problem&lt;/strong&gt; in human terms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The idea&lt;/strong&gt; in one or two sentences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A concrete example&lt;/strong&gt;, with code if code helps.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What went wrong or what it costs.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A takeaway&lt;/strong&gt; you can reuse.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A question&lt;/strong&gt; for the reader.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Subheadings make it scannable, since most readers skim first and read second. Make each heading say something, not just "Overview".&lt;/p&gt;

&lt;h2&gt;
  
  
  Show, don't just tell
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code people can copy&lt;/strong&gt; is the most useful thing in a technical post, so make it runnable or clearly mark it as a sketch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tables&lt;/strong&gt; work for comparisons.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A diagram or a summary image&lt;/strong&gt; helps visual readers and gives your post a shareable image.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real numbers and real names&lt;/strong&gt;, when they're true and checkable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Keep the honesty rule
&lt;/h2&gt;

&lt;p&gt;For this series, I follow rules I wrote on Day 1: only write what I did or believe, say what didn't work, and label opinions as opinions. Practically that means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No invented statistics.&lt;/li&gt;
&lt;li&gt;No "everyone knows".&lt;/li&gt;
&lt;li&gt;If I didn't measure it, I don't say it's fast.&lt;/li&gt;
&lt;li&gt;Limits are part of the post, not hidden at the bottom.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Honest writing also happens to be easier to write: you never have to remember which story you made up.&lt;/p&gt;

&lt;h2&gt;
  
  
  An honest ending
&lt;/h2&gt;

&lt;p&gt;End on something useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A limit&lt;/strong&gt;: "here's what this doesn't cover."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A question&lt;/strong&gt;: something you genuinely want answered.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A next step&lt;/strong&gt;: what you'd try, or what comes next.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Avoid ending on a summary of what you've just said, unless the post is long enough that readers need it.&lt;/p&gt;

&lt;h2&gt;
  
  
  A pre-publish checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Can I finish the sentence "you'll be able to…"?&lt;/li&gt;
&lt;li&gt;[ ] Does the title match what the post delivers?&lt;/li&gt;
&lt;li&gt;[ ] Do the first three sentences give a reason to continue?&lt;/li&gt;
&lt;li&gt;[ ] One idea only?&lt;/li&gt;
&lt;li&gt;[ ] Is every claim something I can back up?&lt;/li&gt;
&lt;li&gt;[ ] Code tested or labelled as a sketch?&lt;/li&gt;
&lt;li&gt;[ ] Headings that say something?&lt;/li&gt;
&lt;li&gt;[ ] An ending that gives something back?&lt;/li&gt;
&lt;li&gt;[ ] Spelling and links checked?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The read-aloud test
&lt;/h2&gt;

&lt;p&gt;Read the post aloud. Wherever you stumble, the reader will too. Long sentences you run out of breath on need splitting. Words you wouldn't say to a friend need replacing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading time
&lt;/h2&gt;

&lt;p&gt;There's a trade-off between depth and attention. On my own site, reading time is computed from the word count so I don't hand-write it. A rough rule: 200 words a minute, so a 1,500-word post is about seven minutes. Long is fine if every section earns its place. Cut anything that's there to hit a length.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm still learning
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cutting my own favourite paragraph when it doesn't serve the post.&lt;/li&gt;
&lt;li&gt;Writing a title &lt;em&gt;after&lt;/em&gt; the draft, when I know what it really says.&lt;/li&gt;
&lt;li&gt;Resisting the urge to sound more expert than I am.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A before/after: rewriting an intro
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Before&lt;/strong&gt; (a typical first draft):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In the modern world of software development, testing is becoming more and more important. Many developers know they should write tests, but it can be hard to find the time. In this post I will talk about my experience with testing and how I plan to improve it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's polite and says almost nothing. Nothing happens in the first three sentences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Writing tests is advice I give and haven't followed everywhere. CardBridge has no automated test suite. So here's the plan, publicly, so I'm accountable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Same topic. The second version admits something specific, sets a stake and gives a reason to continue. It's also shorter.&lt;/p&gt;

&lt;h2&gt;
  
  
  A four-round editing pass
&lt;/h2&gt;

&lt;p&gt;Don't edit everything at once. Do it in rounds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Round 1: Structure.&lt;/strong&gt; Does the post have one idea? Are the sections in the right order? Cut or move whole sections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Round 2: Clarity.&lt;/strong&gt; Rewrite sentences that you had to read twice. Replace jargon with plain words, or define it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Round 3: Evidence.&lt;/strong&gt; For each claim, ask: can I back this up? Add the command, link or example. Delete what you can't.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Round 4: Polish.&lt;/strong&gt; Spelling, links, code formatting, headings, alt text.&lt;/p&gt;

&lt;p&gt;Taking a break of even a few hours between round 3 and round 4 makes errors much easier to see.&lt;/p&gt;

&lt;h2&gt;
  
  
  Words to cut
&lt;/h2&gt;

&lt;p&gt;These add length but not meaning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"very", "really", "quite", "basically", "actually"&lt;/li&gt;
&lt;li&gt;"In order to" (use "to")&lt;/li&gt;
&lt;li&gt;"It is important to note that" (just note it)&lt;/li&gt;
&lt;li&gt;"There are many X that Y" (name two)&lt;/li&gt;
&lt;li&gt;"Needless to say" (then don't)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sentences that earn their place
&lt;/h2&gt;

&lt;p&gt;Prefer concrete over abstract:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Vague&lt;/th&gt;
&lt;th&gt;Concrete&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"Performance improved."&lt;/td&gt;
&lt;td&gt;"The query went from a full scan to an index lookup." (only if true)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"It was a challenging bug."&lt;/td&gt;
&lt;td&gt;"It only failed for viewers, never for editors."&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"I learned a lot."&lt;/td&gt;
&lt;td&gt;"I learned that a postinstall script can be skipped by the host."&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you didn't measure a number, don't print one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Formatting for skimmers
&lt;/h2&gt;

&lt;p&gt;Many readers skim first. Help them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Headings&lt;/strong&gt; that carry information.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Short paragraphs&lt;/strong&gt;, three or four lines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lists&lt;/strong&gt; for parallel items, &lt;strong&gt;tables&lt;/strong&gt; for comparisons.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code blocks&lt;/strong&gt; with a language tag.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bold&lt;/strong&gt; for the one phrase per section you'd want a skimmer to see.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An image&lt;/strong&gt; or summary card to break up long text.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't overuse bold; if everything is emphasised, nothing is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Titles: some patterns
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The honest admission&lt;/td&gt;
&lt;td&gt;"My site's deploys silently failed for two weeks. I didn't notice"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The decision and payoff&lt;/td&gt;
&lt;td&gt;"I put my business rules in the database instead of React, here's what it bought me"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The plain how-to&lt;/td&gt;
&lt;td&gt;"Row Level Security explained with one tiny example"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The comparison&lt;/td&gt;
&lt;td&gt;"Learning in public vs learning in private: the trade-offs"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Write five titles, then pick the one that's most specific &lt;em&gt;and&lt;/em&gt; true.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting feedback before publishing
&lt;/h2&gt;

&lt;p&gt;Send the draft to one person and ask three questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Where did you get bored?&lt;/li&gt;
&lt;li&gt;Where did you get lost?&lt;/li&gt;
&lt;li&gt;What's the one thing you remember?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If their answer to the third isn't your main point, the post isn't clear yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  A habit: keep a "stuff" file
&lt;/h2&gt;

&lt;p&gt;Keep a note of small things you learn and the questions people ask you. Most good posts begin as a note that kept growing.&lt;/p&gt;

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

&lt;p&gt;What's one post you read recently that you couldn't stop reading? What made it work?&lt;/p&gt;




&lt;p&gt;☕ &lt;strong&gt;Enjoyed this post? You can support my writing on Ko-fi.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ko-fi.com/surajnandan" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2z7dch5enfz2e5i2t2gj.png" alt="Support me on Ko-fi" width="286" height="73"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>writing</category>
      <category>blogging</category>
      <category>career</category>
      <category>productivity</category>
    </item>
    <item>
      <title>The History of AI, Part 3: Neurons on Paper, McCulloch, Pitts, and the Birth of Cybernetics</title>
      <dc:creator>Suraj Nandan</dc:creator>
      <pubDate>Mon, 09 Nov 2026 04:30:00 +0000</pubDate>
      <link>https://dev.to/suraj_nandan/the-history-of-ai-part-3-neurons-on-paper-mcculloch-pitts-and-the-birth-of-cybernetics-1do3</link>
      <guid>https://dev.to/suraj_nandan/the-history-of-ai-part-3-neurons-on-paper-mcculloch-pitts-and-the-birth-of-cybernetics-1do3</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The History of AI, Part 3 of 24.&lt;/strong&gt; In Part 2, Alan Turing defined computation and asked whether machines could think. Now we meet the people who asked a different question: what if the &lt;em&gt;brain itself&lt;/em&gt; is a kind of computer? This is where neural networks, feedback, and information theory all begin.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By the early 1940s, two big ideas were sitting side by side, almost touching.&lt;/p&gt;

&lt;p&gt;On one side: &lt;strong&gt;logic and computation&lt;/strong&gt;. Boole had shown that reasoning can be written as algebra, and Turing had defined exactly what a computing machine is.&lt;/p&gt;

&lt;p&gt;On the other side: &lt;strong&gt;neuroscience&lt;/strong&gt;. Biologists had established that the brain is made of billions of individual cells called neurons, connected in vast networks, passing tiny electrical signals along their branches. A neuron receives signals, and if enough arrive, it "fires" and sends its own signal onward. That's about as much as anyone knew for sure.&lt;/p&gt;

&lt;p&gt;Someone was bound to put them together and say: &lt;em&gt;a neuron is a kind of logic gate, and the brain is a computing machine built from them.&lt;/em&gt; That someone turned out to be an odd partnership of a middle-aged psychiatrist and a homeless teenage prodigy.&lt;/p&gt;

&lt;p&gt;This chapter is about the birth of the &lt;strong&gt;neural network&lt;/strong&gt; idea, about a sprawling science called &lt;strong&gt;cybernetics&lt;/strong&gt; that briefly promised to explain minds, machines, and societies in one framework, and about the quiet groundwork that made later AI possible. It's also, unusually for a history of technology, a story with a genuinely sad ending.&lt;/p&gt;

&lt;h2&gt;
  
  
  The psychiatrist and the runaway
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Warren McCulloch&lt;/strong&gt; (1898-1969) was a restless, poetic, charismatic American neurophysiologist and psychiatrist. He had studied philosophy and psychology and medicine, and he carried around a question that he said had obsessed him since youth: &lt;em&gt;"What is a number, that a man may know it, and a man, that he may know a number?"&lt;/em&gt; In other words, how can a physical, biological thing, a brain, come to know abstract truths?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Walter Pitts&lt;/strong&gt; (1923-1969) was a very different figure. Born into a rough, poor family in Detroit, he was a self-taught prodigy who, as the often-told story goes, escaped bullies as a boy by hiding in a library, where he read Bertrand Russell and Alfred North Whitehead's &lt;em&gt;Principia Mathematica&lt;/em&gt;. He is said to have written to Russell with corrections, and Russell invited him to study in England. He couldn't go. Instead, at around fifteen, he left home for good and wandered into the University of Chicago, where he sat in on lectures by the philosopher Rudolf Carnap and impressed everyone he met, despite having no official student status and often nowhere to live.&lt;/p&gt;

&lt;p&gt;Through a fellow student, &lt;strong&gt;Jerome Lettvin&lt;/strong&gt;, Pitts met McCulloch. McCulloch, who had a large house and a large heart, essentially took the young man in. The two began working together on a way to use logic to describe the brain.&lt;/p&gt;

&lt;h2&gt;
  
  
  "A Logical Calculus of the Ideas Immanent in Nervous Activity"
&lt;/h2&gt;

&lt;p&gt;In 1943 they published a paper with that mouthful of a title in the &lt;em&gt;Bulletin of Mathematical Biophysics&lt;/em&gt;. It is one of the most important and least-read papers in the history of AI.&lt;/p&gt;

&lt;p&gt;Here is their central move. They took the real, messy biological neuron and simplified it brutally into an abstract unit with these properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It has several &lt;strong&gt;inputs&lt;/strong&gt;, each either on (1) or off (0).&lt;/li&gt;
&lt;li&gt;Some inputs are &lt;strong&gt;excitatory&lt;/strong&gt; (they push the neuron toward firing), and some are &lt;strong&gt;inhibitory&lt;/strong&gt; (they veto it).&lt;/li&gt;
&lt;li&gt;The neuron has a &lt;strong&gt;threshold&lt;/strong&gt;. If enough excitatory inputs are on, and no inhibitory input is on, the neuron fires (outputs 1). Otherwise it stays silent (outputs 0).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's all. And from this tiny building block, McCulloch and Pitts proved something remarkable: &lt;strong&gt;networks of these units can compute any logical function&lt;/strong&gt;. With the right wiring you can build AND, OR, and NOT, and since you can build any logic circuit from those three, you can build any logical computation. They also argued that, given a tape, such networks could in principle compute anything a Turing machine can.&lt;/p&gt;

&lt;p&gt;Let's see how little code this takes. Here is the McCulloch-Pitts neuron:&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;mp_neuron&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weights&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="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Fire (1) if the weighted sum of inputs reaches the threshold.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&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;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;weights&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;threshold&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="c1"&gt;# AND: both inputs must be on
&lt;/span&gt;&lt;span class="n"&gt;AND&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;mp_neuron&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&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;1&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="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# OR: at least one input must be on
&lt;/span&gt;&lt;span class="n"&gt;OR&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;mp_neuron&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&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;1&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# NOT: an inhibitory (negative) weight flips the signal
&lt;/span&gt;&lt;span class="n"&gt;NOT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="nf"&gt;mp_neuron&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&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="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="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;a&lt;/span&gt; &lt;span class="ow"&gt;in&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="mi"&gt;1&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;b&lt;/span&gt; &lt;span class="ow"&gt;in&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="mi"&gt;1&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;a&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;b&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; -&amp;gt; AND=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nc"&gt;AND&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  OR=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nc"&gt;OR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;b&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NOT 0 =&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;NOT&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;| NOT 1 =&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;NOT&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it and you'll see the truth tables Boole would recognize. Real neurons are enormously more complicated than this, and McCulloch and Pitts knew it. But the paper's power isn't biological accuracy. It's the &lt;strong&gt;bridge&lt;/strong&gt;. It said: whatever the brain does, if it can be described logically, then a network of simple threshold units can do it. Thinking might not be mystical. It might be &lt;em&gt;wiring&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wires and weights
&lt;/h3&gt;

&lt;p&gt;Notice the two ingredients that appear in the code: &lt;strong&gt;weights&lt;/strong&gt; and a &lt;strong&gt;threshold&lt;/strong&gt;. In the 1943 model, the weights were fixed by hand. Later researchers would let the weights &lt;em&gt;change&lt;/em&gt;, and that single modification, learning, would become the central theme of modern AI. A modern deep learning model has billions of weights, and nearly all of its "knowledge" is stored in them. But the core operation, "multiply inputs by weights, add them up, compare to a threshold," is still the McCulloch-Pitts neuron, with the hard threshold usually replaced by a smooth function.&lt;/p&gt;

&lt;p&gt;There's one more thing worth noticing: a single McCulloch-Pitts unit can't compute everything. It can do AND and OR, but a single unit &lt;strong&gt;cannot compute XOR&lt;/strong&gt; (exclusive or: "one or the other, but not both"). You need at least two layers of units to do it. That small fact will come back with a vengeance in Part 6, when it becomes the center of a famous and devastating critique of early neural networks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why it mattered
&lt;/h3&gt;

&lt;p&gt;The paper's impact was less about what researchers did with it immediately and more about the &lt;em&gt;frame&lt;/em&gt; it created:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It made the brain a legitimate object of &lt;strong&gt;mathematical&lt;/strong&gt; study.&lt;/li&gt;
&lt;li&gt;It linked neuroscience to &lt;strong&gt;computation&lt;/strong&gt;, suggesting the mind is something a machine might replicate.&lt;/li&gt;
&lt;li&gt;It inspired &lt;strong&gt;John von Neumann&lt;/strong&gt;, who cited the paper in his 1945 report describing the stored-program computer architecture and used its neuron-like notation to describe how computer components might work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also contained an idea that would take years to mature: networks with &lt;strong&gt;loops&lt;/strong&gt;, where signals feed back into earlier units, could have memory. That insight prefigured recurrent neural networks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Meeting Norbert Wiener
&lt;/h2&gt;

&lt;p&gt;In 1943, Pitts, only 20 years old, moved to Cambridge, Massachusetts, drawn to MIT by one of the most formidable intellects in America: &lt;strong&gt;Norbert Wiener&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw4zhlb18i1h6lx7zkojd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw4zhlb18i1h6lx7zkojd.jpg" alt="Norbert Wiener (right) examines the chess-playing automaton El Ajedrecista in 1951" width="800" height="659"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Norbert Wiener (right) examines the chess-playing automaton El Ajedrecista in 1951. Public domain, via &lt;a href="https://commons.wikimedia.org/wiki/File:Gonzalo_showing_El_Ajedrecista_to_Norbert_Wiener.jpg" rel="noopener noreferrer"&gt;Wikimedia Commons&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Wiener (1894-1964) was a former child prodigy who earned his PhD from Harvard at 18. A mathematician with wide-ranging curiosity and a reputation for absentmindedness (there are many stories of him wandering the halls of MIT lost in thought), he had spent the early war years on a very practical problem: &lt;strong&gt;anti-aircraft fire&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  The prediction problem
&lt;/h3&gt;

&lt;p&gt;To shoot down a fast-moving airplane, you can't aim at where it &lt;em&gt;is&lt;/em&gt;. By the time your shell arrives, the plane will have moved. You must aim at where it &lt;em&gt;will be&lt;/em&gt;. That requires predicting the pilot's path from recent observations, which is hard because the pilot is a human being trying to evade you.&lt;/p&gt;

&lt;p&gt;Wiener, working with the engineer Julian Bigelow, developed mathematical methods for predicting such trajectories, treating the pilot's motion as a noisy signal and finding the best statistical guess about the future. But they noticed something deeper: the whole &lt;em&gt;system&lt;/em&gt;, a gun, a radar, a human operator, and an airplane, behaved as a &lt;strong&gt;loop&lt;/strong&gt;. The gun makes an observation, adjusts its aim, observes the result, and corrects. This is &lt;strong&gt;feedback&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In a famous 1943 paper, "Behavior, Purpose and Teleology," Wiener, Bigelow, and the physiologist Arturo Rosenblueth argued that goal-directed behavior, in both animals and machines, could be explained through feedback. A thermostat has a "goal" (a target temperature). A guided missile has a "goal." A person reaching for a cup has a "goal." In each case, the system compares its current state with the desired state and acts to reduce the difference.&lt;/p&gt;

&lt;p&gt;That sounds obvious today, but in 1943 it was heretical. Scientists had avoided talk of "purpose" as unscientific, a leftover from Aristotle. Wiener showed that purposeful behavior could be explained &lt;em&gt;mechanistically&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Cybernetics
&lt;/h3&gt;

&lt;p&gt;In 1948, Wiener published a book titled &lt;strong&gt;&lt;em&gt;Cybernetics: Or Control and Communication in the Animal and the Machine&lt;/em&gt;&lt;/strong&gt;. He had coined the word from the Greek &lt;em&gt;kybernetes&lt;/em&gt;, "steersman", the person who steers a ship, constantly correcting course in response to wind and waves. (The same Greek root gives us "govern" and "governor.")&lt;/p&gt;

&lt;p&gt;The book is a strange mixture of dense mathematics and sweeping speculation, and, to the astonishment of its publisher, it became a bestseller. Its central claim was that &lt;strong&gt;control and communication are the same kind of thing&lt;/strong&gt; across biology, machines, and even society. Organisms, thermostats, computers, and economies are all systems that process &lt;strong&gt;information&lt;/strong&gt; and use &lt;strong&gt;feedback&lt;/strong&gt; to regulate themselves.&lt;/p&gt;

&lt;p&gt;For a few years, cybernetics was &lt;em&gt;the&lt;/em&gt; hot interdisciplinary idea. It influenced psychology, engineering, biology, anthropology, and management theory, and it supplied a vocabulary (feedback, input/output, signal, noise, control) that we still use constantly.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Macy Conferences
&lt;/h3&gt;

&lt;p&gt;The movement's social hub was a series of ten invitation-only meetings, the &lt;strong&gt;Macy Conferences&lt;/strong&gt;, held between 1946 and 1953 in New York. They were the sort of gathering that seems almost impossible today: mathematicians, neurophysiologists, psychologists, anthropologists (including Margaret Mead and Gregory Bateson), engineers, and philosophers all in one room, arguing late into the night, with McCulloch chairing.&lt;/p&gt;

&lt;p&gt;They debated how brains compute, how language works, how communities regulate themselves, and whether machines could think. Many of the questions that structured the next 70 years of cognitive science and AI were first sharpened in those rooms.&lt;/p&gt;
&lt;h2&gt;
  
  
  Claude Shannon: a bit of information
&lt;/h2&gt;

&lt;p&gt;One regular in these circles quietly changed the world twice before he turned 33.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk38p2k4xy4sgvq4a9joo.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk38p2k4xy4sgvq4a9joo.jpg" alt="Claude Shannon in a 1958 MIT portrait" width="588" height="743"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Claude Shannon in a 1958 MIT portrait. Public domain, via &lt;a href="https://commons.wikimedia.org/wiki/File:Claude_Shannon_1958_MIT_portrait_cropped.jpg" rel="noopener noreferrer"&gt;Wikimedia Commons&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Claude Shannon&lt;/strong&gt; (1916-2001) was a playful, inventive engineer who loved unicycles, juggling, and building odd gadgets. In his 1937 master's thesis at MIT, "A Symbolic Analysis of Relay and Switching Circuits," he noticed that the on/off behavior of electrical switches could be described using &lt;strong&gt;Boolean algebra&lt;/strong&gt;, the same algebra Boole had invented in 1854 to describe logic. Series circuits correspond to AND, parallel circuits to OR. This turned circuit design from an art into a mathematical discipline, and laid the foundation for digital computers. It is often called the most important master's thesis of the century.&lt;/p&gt;

&lt;p&gt;Then, in 1948, the same year as Wiener's book, Shannon published "A Mathematical Theory of Communication," founding &lt;strong&gt;information theory&lt;/strong&gt;. He defined the &lt;strong&gt;bit&lt;/strong&gt; as the unit of information and showed how to measure the information content of a message, how much a noisy channel can carry, and how to encode messages so errors can be corrected. Every text message, streamed video, and compressed file depends on his ideas.&lt;/p&gt;

&lt;p&gt;Shannon cared about machine intelligence too. In 1950 he published "Programming a Computer for Playing Chess," outlining the basic strategy of searching a tree of possible moves and scoring positions, which became the foundation of computer chess. He also built &lt;strong&gt;Theseus&lt;/strong&gt;, a small mechanical mouse that could learn to find its way through a maze, one of the first demonstrations of a machine that visibly learned from experience.&lt;/p&gt;

&lt;p&gt;His mathematics also hides a connection that will matter greatly in modern AI. The measure of information, &lt;strong&gt;entropy&lt;/strong&gt;, is the same quantity that today's language models are trained to minimize (in the form of cross-entropy loss) when they predict the next word. Shannon was already experimenting in 1948 with predicting English text one letter at a time using statistical models. In a very real sense, today's chatbots are descendants of those experiments.&lt;/p&gt;
&lt;h2&gt;
  
  
  Hebb: how brains learn
&lt;/h2&gt;

&lt;p&gt;McCulloch and Pitts left a gap. Their neurons had fixed connections. But real brains learn. How?&lt;/p&gt;

&lt;p&gt;In 1949, the Canadian psychologist &lt;strong&gt;Donald Hebb&lt;/strong&gt; proposed a simple and influential answer in his book &lt;em&gt;The Organization of Behavior&lt;/em&gt;. In his words:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When an axon of cell A is near enough to excite a cell B and repeatedly or persistently takes part in firing it, some growth process or metabolic change takes place in one or both cells such that A's efficiency, as one of the cells firing B, is increased.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is usually summarized, a little loosely, as: &lt;strong&gt;"neurons that fire together, wire together."&lt;/strong&gt; (That catchy phrase actually came later, from the neuroscientist Carla Shatz.) The idea is that connections between neurons strengthen when the neurons are active at the same time.&lt;/p&gt;

&lt;p&gt;This is &lt;strong&gt;Hebbian learning&lt;/strong&gt;, and it was the first plausible &lt;em&gt;learning rule&lt;/em&gt; for artificial neural networks. A tiny demonstration:&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="c1"&gt;# Learn an association between two patterns using Hebb's rule:
#   weight change = learning_rate * input * output
&lt;/span&gt;&lt;span class="n"&gt;patterns&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="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&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;0&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="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&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="c1"&gt;# input pattern -&amp;gt; "fire"
&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;array&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&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="c1"&gt;# input pattern -&amp;gt; "silent"
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;w&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="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;
&lt;span class="k"&gt;for&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="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;patterns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&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;y&lt;/span&gt;          &lt;span class="c1"&gt;# strengthen weights where input and output are both active
&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;weights after learning:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;          &lt;span class="c1"&gt;# [1. 0. 1.]
&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;response to [1,0,1]:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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;w&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;array&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;0&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="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# fires
&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;response to [0,1,0]:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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;w&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;array&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="mi"&gt;1&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="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# silent
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pure Hebbian learning has problems. Weights can grow without limit, and it can only learn correlations, not mistakes. Later rules, such as the &lt;strong&gt;perceptron learning rule&lt;/strong&gt; and &lt;strong&gt;backpropagation&lt;/strong&gt;, which we'll meet in Parts 5, 6, and 9, are much more powerful. But Hebb's idea, that learning means &lt;em&gt;adjusting the strengths of connections&lt;/em&gt;, is exactly what every modern neural network does during training.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first neural network machine
&lt;/h2&gt;

&lt;p&gt;The theory was ready; someone had to build one. In 1951, two Harvard graduate students, &lt;strong&gt;Marvin Minsky&lt;/strong&gt; and &lt;strong&gt;Dean Edmonds&lt;/strong&gt;, built the &lt;strong&gt;SNARC&lt;/strong&gt; (Stochastic Neural Analog Reinforcement Calculator). It used about 3,000 vacuum tubes and 40 artificial "neurons", each with a motor-driven potentiometer to represent an adjustable connection strength, and it simulated a rat learning to find its way out of a maze. When the "rat" made a choice that led to success, the connections that were involved were strengthened.&lt;/p&gt;

&lt;p&gt;It was crude and temperamental, and Minsky later said it was not much of a success. But it was probably the first physical neural-network learning machine ever built. The irony is rich: Minsky would become one of the most prominent &lt;em&gt;critics&lt;/em&gt; of neural networks in the 1960s, as we'll see. First, he built one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Machines that behave like animals
&lt;/h2&gt;

&lt;p&gt;Cybernetics wasn't only abstract. Two British researchers built machines you could actually watch behaving.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2n52fv372jk8383mzj3v.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2n52fv372jk8383mzj3v.jpg" alt="A replica of one of W. Grey Walter's robotic tortoises" width="800" height="530"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A replica of one of W. Grey Walter's robotic tortoises. Image: Anders Sandberg from Oxford, UK, CC BY 2.0, via &lt;a href="https://commons.wikimedia.org/wiki/File:Replica_of_Grey_Walter%27s_tortoise_(3572415081).jpg" rel="noopener noreferrer"&gt;Wikimedia Commons&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;W. Ross Ashby&lt;/strong&gt; was a psychiatrist who built the &lt;strong&gt;Homeostat&lt;/strong&gt; in 1948, a device made of four interconnected units that, when disturbed, kept adjusting themselves until they returned to a stable state. It demonstrated "ultrastability": a machine that could find equilibrium on its own, without being told how. Ashby's 1952 book &lt;em&gt;Design for a Brain&lt;/em&gt; argued that adaptive behavior could be explained by systems that seek stability through feedback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;W. Grey Walter&lt;/strong&gt;, a neurophysiologist in Bristol, built a pair of little three-wheeled robots in 1948 and 1949, nicknamed &lt;strong&gt;Elmer and Elsie&lt;/strong&gt; and collectively classified as &lt;strong&gt;&lt;em&gt;Machina speculatrix&lt;/em&gt;&lt;/strong&gt;, the "speculative machine." Often called "tortoises," they had a light sensor, a touch sensor, and just two vacuum-tube "neurons." Yet their behavior seemed lifelike: they wandered around exploring, moved toward moderate light, backed away from bright light, and when their batteries ran low, headed back to their charging hutch. When Grey Walter put a light on one tortoise and set it in front of a mirror, it danced in front of its own reflection.&lt;/p&gt;

&lt;p&gt;The tortoises are important to AI history for a deeper reason. They showed that &lt;strong&gt;complex-seeming behavior can emerge from very simple mechanisms interacting with the environment&lt;/strong&gt;, with no central model of the world, no stored reasoning, no deliberate planning. This idea would be reborn in the 1980s in Rodney Brooks's robotics, which argued for "intelligence without representation."&lt;/p&gt;

&lt;h2&gt;
  
  
  What cybernetics got right, and what happened to it
&lt;/h2&gt;

&lt;p&gt;Looking back, cybernetics seems to have been right about a surprising amount.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Feedback is everywhere.&lt;/strong&gt; Control theory is now a core part of engineering. Thermostats, cruise control, autopilots, and robot arms all depend on feedback loops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Information is a physical, measurable thing.&lt;/strong&gt; Shannon's theory is the foundation of the digital age.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Brains can be modeled with networks.&lt;/strong&gt; The McCulloch-Pitts neuron is the great-grandparent of modern deep learning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learning is adjusting connections.&lt;/strong&gt; Hebb's idea persists.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Behavior emerges from interaction.&lt;/strong&gt; Complex systems, from ant colonies to the internet, reward the cybernetic view.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reinforcement through feedback.&lt;/strong&gt; The notion of learning from reward and punishment is the heart of reinforcement learning, which we'll see in AlphaGo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yet cybernetics as a &lt;em&gt;movement&lt;/em&gt; faded by the late 1950s and 1960s. Why?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;It was too broad.&lt;/strong&gt; When a theory claims to explain everything, from thermostats to politics, it risks explaining nothing in particular. Researchers wanted sharper tools and clearer funding categories.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The new computers took over.&lt;/strong&gt; With stored-program digital computers arriving, many researchers found it more promising to write programs that manipulated symbols than to build analog feedback systems or networks of simple units.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personalities and politics.&lt;/strong&gt; Wiener was outspoken, a pacifist who refused to take military funding after the war and criticized the arms race, and he did not play the Washington game of grant-seeking. In a field where influence increasingly depended on defense and government money, that mattered.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A new name.&lt;/strong&gt; When John McCarthy organized a summer workshop in 1956 to explore machine intelligence, he deliberately invented the term &lt;strong&gt;"artificial intelligence"&lt;/strong&gt; in part to avoid associating the project with cybernetics and, as he later said, to avoid having to accept Wiener as a guru. Naming has consequences: the new label gave the symbolic, computer-centered approach its own banner, and cybernetics became a side current.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A tragedy
&lt;/h2&gt;

&lt;p&gt;The partnership that started all this ended badly.&lt;/p&gt;

&lt;p&gt;Pitts had thrived at MIT, working with Wiener and McCulloch, and Wiener was reportedly planning to supervise his PhD and treated him as one of his most gifted students. Then, in the early 1950s, something went wrong. According to accounts by later historians, Wiener's wife Margaret, who strongly disliked McCulloch's bohemian household, told Wiener that McCulloch's circle had corrupted their daughter. (The claim, by most accounts, was false.) Wiener angrily cut off all contact with McCulloch, Pitts, and their colleagues, and refused to explain why.&lt;/p&gt;

&lt;p&gt;Pitts was devastated. He had idolized Wiener. Reports say he withdrew, stopped working, and burned much of his own unpublished research, including a dissertation he had been working on. He retreated into isolation and alcohol, declining prizes and refusing to publish. Warren McCulloch and Walter Pitts both died in 1969, Pitts at just 46, largely forgotten outside a small circle.&lt;/p&gt;

&lt;p&gt;The story is a reminder that history of science is human history. The idea that launched neural networks came from two people who were, in different ways, outsiders, and the field they started would later honor the idea far more than the people.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this chapter matters for modern AI
&lt;/h2&gt;

&lt;p&gt;If you've ever trained a neural network, you've inherited this chapter. Consider the lineage:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Idea&lt;/th&gt;
&lt;th&gt;Origin&lt;/th&gt;
&lt;th&gt;Modern descendant&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Artificial neuron&lt;/td&gt;
&lt;td&gt;McCulloch &amp;amp; Pitts, 1943&lt;/td&gt;
&lt;td&gt;Every unit in a deep neural network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weights and thresholds&lt;/td&gt;
&lt;td&gt;McCulloch &amp;amp; Pitts&lt;/td&gt;
&lt;td&gt;Parameters and activation functions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning by strengthening connections&lt;/td&gt;
&lt;td&gt;Hebb, 1949&lt;/td&gt;
&lt;td&gt;Gradient descent, backpropagation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Feedback and goal-seeking&lt;/td&gt;
&lt;td&gt;Wiener, 1948&lt;/td&gt;
&lt;td&gt;Reinforcement learning, control systems&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Information and entropy&lt;/td&gt;
&lt;td&gt;Shannon, 1948&lt;/td&gt;
&lt;td&gt;Cross-entropy loss, compression, language modeling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Emergent behavior from simple parts&lt;/td&gt;
&lt;td&gt;Grey Walter, Ashby&lt;/td&gt;
&lt;td&gt;Behavior-based robotics, swarm systems&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At the same time, these early thinkers differed on a point that would split the field in two, and that divides researchers to this day:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The symbolic view.&lt;/strong&gt; Intelligence is the manipulation of symbols according to rules, like logic and Turing machines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The connectionist view.&lt;/strong&gt; Intelligence emerges from many simple units connected in networks and &lt;em&gt;learning&lt;/em&gt; from experience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;McCulloch and Pitts, interestingly, belong to both camps. Their paper described neurons, yet it proved things about &lt;em&gt;logic&lt;/em&gt;. For the next two decades, though, the symbolic camp would win the funding, the prestige, and the headlines. The connectionist camp would be pushed to the margins, and nearly declared dead, before staging one of the great comebacks in the history of science.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 1940s at a glance
&lt;/h2&gt;

&lt;p&gt;It helps to see how crowded this decade was. The same few years contain the founding documents of computing, information theory, neural networks, and cybernetics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1936 to 1937:&lt;/strong&gt; Turing defines computation (Part 2); Shannon applies Boolean algebra to relay circuits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1943:&lt;/strong&gt; McCulloch and Pitts publish their neuron model; Wiener, Bigelow, and Rosenblueth publish "Behavior, Purpose and Teleology."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1945:&lt;/strong&gt; John von Neumann circulates the EDVAC report, describing the stored-program computer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1946:&lt;/strong&gt; ENIAC is unveiled, and the first Macy Conference meets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1948:&lt;/strong&gt; Wiener's &lt;em&gt;Cybernetics&lt;/em&gt; and Shannon's "A Mathematical Theory of Communication" appear in the same year; Ashby builds the Homeostat; Grey Walter builds his first tortoises.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1949:&lt;/strong&gt; Hebb publishes &lt;em&gt;The Organization of Behavior&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1950 to 1951:&lt;/strong&gt; Shannon writes about computer chess and builds Theseus; Turing publishes "Computing Machinery and Intelligence"; Minsky and Edmonds build SNARC.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fewer than fifteen years separate Boole's algebra becoming a circuit-design tool from a machine learning to run a maze. That compression is part of why the early pioneers were so optimistic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three common misconceptions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;"The McCulloch-Pitts neuron is a model of a real neuron."&lt;/strong&gt; Not really, and its authors knew it. A real neuron has branching dendrites that compute in their own right, fires in timed spikes, and is modulated by dozens of chemicals. The 1943 unit is a deliberate cartoon, chosen because it can be analyzed with logic. Modern artificial neurons are "inspired by" biology in the way an airplane wing is inspired by a bird's: the principle is borrowed, the details are not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Cybernetics failed."&lt;/strong&gt; As a movement with its own conferences and gurus, it faded. But its ideas were absorbed so completely that we no longer notice them. Control theory, robotics, systems biology, ecology, and cognitive science all use feedback, information, and regulation as basic concepts. The prefix "cyber-" in cybersecurity and cyberspace descends from Wiener's coinage. What failed was the &lt;em&gt;label&lt;/em&gt;, not the substance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Hebb's rule is how brains learn, and backpropagation is how AI learns, so the two are basically the same."&lt;/strong&gt; They are cousins, not twins. Hebb's rule is &lt;em&gt;local&lt;/em&gt;: a connection changes based only on the activity of the two neurons it joins. Backpropagation needs error signals that flow backward through the whole network, which no one has found a clear biological equivalent for. Whether the brain approximates something like backpropagation by other means is an open research question, and Geoffrey Hinton, among others, has proposed alternatives to it, partly for that reason.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick glossary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Threshold:&lt;/strong&gt; the level of input a unit must reach before it fires.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weight:&lt;/strong&gt; a number scaling how strongly one unit's output influences another.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feedback:&lt;/strong&gt; using the result of an action to adjust the next action.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Homeostasis:&lt;/strong&gt; a system's tendency to restore a stable state after disturbance (Ashby's Homeostat, your body temperature).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entropy:&lt;/strong&gt; in Shannon's sense, a measure of the uncertainty (or average information) in a message source.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bit:&lt;/strong&gt; the amount of information in a single yes/no choice.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;McCulloch and Pitts (1943)&lt;/strong&gt; modeled the neuron as a simple threshold logic unit and showed that networks of such units can compute any logical function. This is the starting point of neural networks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Norbert Wiener&lt;/strong&gt; founded &lt;strong&gt;cybernetics&lt;/strong&gt; (1948), explaining goal-directed behavior in machines and animals through &lt;strong&gt;feedback&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude Shannon&lt;/strong&gt; applied Boolean algebra to circuits (1937) and created &lt;strong&gt;information theory&lt;/strong&gt; (1948), giving us the bit and the mathematics later used to train language models.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Donald Hebb (1949)&lt;/strong&gt; proposed that learning strengthens connections between co-active neurons, the first plausible learning rule for artificial networks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minsky and Edmonds&lt;/strong&gt; built the first neural network machine (SNARC, 1951), while &lt;strong&gt;Grey Walter&lt;/strong&gt; and &lt;strong&gt;Ashby&lt;/strong&gt; built lifelike feedback machines.&lt;/li&gt;
&lt;li&gt;Cybernetics faded, in part because the new field of &lt;strong&gt;AI&lt;/strong&gt; adopted a different name and a different, symbol-focused approach.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Build XOR the hard way.&lt;/strong&gt; A single McCulloch-Pitts neuron can't compute XOR. Combine three of the neurons from the code above, using AND, OR, and NOT, to build it: &lt;code&gt;XOR(a, b) = AND(OR(a, b), NOT(AND(a, b)))&lt;/code&gt;. You've just built a two-layer network by hand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stretch Hebb.&lt;/strong&gt; Run the Hebbian learning example with more patterns, and see what happens when two patterns overlap. Why does Hebb's rule start making mistakes? What kind of rule would fix them?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simulate a thermostat.&lt;/strong&gt; Write a loop that reads a temperature, compares it with a target, and turns a heater on or off. Then add noise and delay and see how the system oscillates. You've just rediscovered the core problem of control theory.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Next up
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;Part 4&lt;/strong&gt;, we go to a small New Hampshire college campus in the summer of 1956, where a group of ambitious young researchers met for a workshop whose proposal contained a bold prediction: that "every aspect of learning or any other feature of intelligence can in principle be so precisely described that a machine can be made to simulate it." It was the moment the field got its name, &lt;strong&gt;artificial intelligence&lt;/strong&gt;, and the moment its first great wave of optimism began.&lt;/p&gt;

&lt;p&gt;If this chapter changed how you see neural networks, follow the series and leave a comment: which of these ideas surprised you most?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;See you in Part 4.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;☕ &lt;strong&gt;If this series helped you, you can support my writing on Ko-fi.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ko-fi.com/surajnandan" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2z7dch5enfz2e5i2t2gj.png" alt="Support me on Ko-fi" width="286" height="73"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>history</category>
      <category>machinelearning</category>
      <category>computerscience</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Why I keep going back to data structures even though I build web apps</title>
      <dc:creator>Suraj Nandan</dc:creator>
      <pubDate>Mon, 09 Nov 2026 03:30:00 +0000</pubDate>
      <link>https://dev.to/suraj_nandan/why-i-keep-going-back-to-data-structures-even-though-i-build-web-apps-2iab</link>
      <guid>https://dev.to/suraj_nandan/why-i-keep-going-back-to-data-structures-even-though-i-build-web-apps-2iab</guid>
      <description>&lt;p&gt;As a student I'm told to study data structures and algorithms for interviews. That's true, but it undersells them. In my &lt;strong&gt;Job Scheduler&lt;/strong&gt; project, six hand-written structures run inside a real system. This post walks through what each one does and why SQL alone couldn't do the job.&lt;/p&gt;

&lt;h2&gt;
  
  
  The context
&lt;/h2&gt;

&lt;p&gt;A job scheduler has one promise that matters more than every feature: &lt;strong&gt;a job must never run twice by accident, and it must never be lost when a worker dies halfway through.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I built it on Postgres alone, using &lt;code&gt;FOR UPDATE SKIP LOCKED&lt;/code&gt; so many workers can poll one queue without colliding. Where SQL can't express a decision, I implemented six structures by hand and wired them into the running scheduler. It has 156 algorithm unit tests.&lt;/p&gt;

&lt;p&gt;One note: the code below is simplified to show each idea. It isn't copied from the repository.&lt;/p&gt;

&lt;p&gt;Let's go through them.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Binary min-heap: pick the next job by priority
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; many queues, each with jobs of different priority. Which job runs next, across all queues?&lt;/p&gt;

&lt;p&gt;A min-heap gives the best candidate in O(1) and removes it in O(log n).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MinHeap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="p"&gt;}[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&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;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&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="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&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="o"&gt;&amp;gt;&amp;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="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;
      &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&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;for &lt;/span&gt;&lt;span class="p"&gt;(;;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;i&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="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;l&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="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;]];&lt;/span&gt;
        &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Kahn's algorithm: order jobs that depend on each other
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; job C needs A and B to finish first. In what order do we run a whole graph of jobs?&lt;/p&gt;

&lt;p&gt;Kahn's algorithm repeatedly picks jobs with &lt;strong&gt;no unmet dependencies&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;executionOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;indegree&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;needs&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;indegree&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;needs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;needs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[...(&lt;/span&gt;&lt;span class="nx"&gt;next&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="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;[]),&lt;/span&gt; &lt;span class="nx"&gt;job&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ready&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;indegree&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(([,&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;d&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;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;k&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;next&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="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;indegree&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;indegree&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="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;indegree&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="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&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="nx"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// null = cycle&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A bonus: if &lt;code&gt;order&lt;/code&gt; is shorter than the job count, there's a cycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Three-colour DFS: reject dependency cycles up front
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; if A depends on B and B depends on A, nothing can ever run. We want to &lt;em&gt;reject&lt;/em&gt; that at submission time, not discover it later.&lt;/p&gt;

&lt;p&gt;Depth-first search with three colours (white = unvisited, grey = in progress, black = done). Meeting a &lt;strong&gt;grey&lt;/strong&gt; node means we've looped back on ourselves.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;hasCycle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&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;|&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// 0 white, 1 grey, 2 black&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;visit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&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;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;graph&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="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;color&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="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&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="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                  &lt;span class="c1"&gt;// back edge&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&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="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&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="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;()].&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;color&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="nx"&gt;u&lt;/span&gt;&lt;span class="p"&gt;)&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="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;u&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;h2&gt;
  
  
  4. Union-find: find independent clusters of jobs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; which jobs are connected through dependencies, and which are completely independent?&lt;/p&gt;

&lt;p&gt;Union-find (disjoint sets) merges items into groups and answers "are these in the same group?" in near-constant time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DSU&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;p&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="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                         &lt;span class="c1"&gt;// path compression&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;union&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Min-heap delay queue: retries with backoff
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; a failed job should retry later, not immediately. Keep a heap ordered by &lt;em&gt;next run time&lt;/em&gt;; look at the top, and only release it when its time has come. It's the same min-heap, keyed by timestamp instead of priority.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Deficit Round Robin: stop one queue starving the rest
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; if one queue always has jobs, a naive scheduler can keep serving it and starve every other queue.&lt;/p&gt;

&lt;p&gt;Deficit Round Robin gives each queue a "quantum" of credit each round. A queue can spend credit to dispatch jobs; unused credit carries over. Busy queues get their fair share, quiet queues aren't ignored.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not just SQL?
&lt;/h2&gt;

&lt;p&gt;I leaned on Postgres wherever it could do the job: claiming jobs, concurrency bounds, leader election with advisory locks. But &lt;em&gt;ordering across queues&lt;/em&gt;, &lt;em&gt;planning a dependency graph&lt;/em&gt; and &lt;em&gt;fair sharing&lt;/em&gt; are algorithmic decisions that SQL expresses awkwardly. That's the boundary where the structures earn their place.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I find hard
&lt;/h2&gt;

&lt;p&gt;Memorising patterns without understanding them. I do better when I connect a structure to a problem I've actually had.&lt;/p&gt;

&lt;h2&gt;
  
  
  A tip
&lt;/h2&gt;

&lt;p&gt;When you learn a structure, ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;What real thing in my own code is this?&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you can't name one, you haven't finished learning it. Heaps are priority queues; Kahn's is a build system; union-find is "who's connected to whom"; DRR is fairness.&lt;/p&gt;

&lt;h2&gt;
  
  
  A six-week practice plan
&lt;/h2&gt;

&lt;p&gt;One structure per week, tied to a real use. Roughly 3 to 4 hours a week.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Week&lt;/th&gt;
&lt;th&gt;Structure&lt;/th&gt;
&lt;th&gt;Build this&lt;/th&gt;
&lt;th&gt;Stretch&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;Min-heap&lt;/td&gt;
&lt;td&gt;A priority task list that always shows the most urgent item&lt;/td&gt;
&lt;td&gt;Add a "decrease priority" operation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Graph and Kahn's&lt;/td&gt;
&lt;td&gt;A build-order resolver for package-style dependencies&lt;/td&gt;
&lt;td&gt;Print the cycle when one exists&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;DFS and cycle detection&lt;/td&gt;
&lt;td&gt;A validator that rejects circular dependencies with a clear message&lt;/td&gt;
&lt;td&gt;Return the exact cycle path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Union-find&lt;/td&gt;
&lt;td&gt;A "which accounts are connected?" grouping tool&lt;/td&gt;
&lt;td&gt;Add a size-by-group report&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Delay queue (heap by time)&lt;/td&gt;
&lt;td&gt;A retry scheduler with exponential backoff&lt;/td&gt;
&lt;td&gt;Add jitter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Round robin with credit&lt;/td&gt;
&lt;td&gt;A fair scheduler across several noisy queues&lt;/td&gt;
&lt;td&gt;Add weights per queue&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The key is that every week produces something you could &lt;em&gt;use&lt;/em&gt;, not a worksheet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complexity cheat sheet
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Structure / operation&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Heap: peek / push / pop&lt;/td&gt;
&lt;td&gt;O(1) / O(log n) / O(log n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kahn's algorithm&lt;/td&gt;
&lt;td&gt;O(V + E)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DFS cycle detection&lt;/td&gt;
&lt;td&gt;O(V + E)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Union-find: find / union&lt;/td&gt;
&lt;td&gt;Near O(1) amortised&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hash map: get / set&lt;/td&gt;
&lt;td&gt;O(1) average&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sorting&lt;/td&gt;
&lt;td&gt;O(n log n)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;V&lt;/em&gt; is the number of nodes (jobs) and &lt;em&gt;E&lt;/em&gt; the number of edges (dependencies). If you can say what &lt;em&gt;V&lt;/em&gt; and &lt;em&gt;E&lt;/em&gt; are in your own problem, you can reason about its cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to practise without grinding
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Implement from scratch once&lt;/strong&gt;, then use the library version forever after.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write tests first.&lt;/strong&gt; Edge cases (empty input, one element, duplicates, cycles) are where bugs live.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explain it to someone&lt;/strong&gt; or write it down in your own words.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Find it in a real tool.&lt;/strong&gt; A build system uses topological sort; &lt;code&gt;git&lt;/code&gt; uses graphs; your browser uses queues.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Edge cases to always test
&lt;/h2&gt;

&lt;p&gt;For a heap: empty pop, single element, equal keys, many pushes then many pops.&lt;br&gt;
For a graph: a node with no edges, a self-loop, two nodes pointing at each other, a disconnected graph.&lt;br&gt;
For union-find: finding an unknown element, union of the same set, long chains (to check path compression).&lt;/p&gt;

&lt;h2&gt;
  
  
  What interviewers actually look for
&lt;/h2&gt;

&lt;p&gt;In my experience as a student &lt;em&gt;preparing&lt;/em&gt; (not as an interviewer), the common advice is that they care about:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Can you clarify the problem before coding?&lt;/li&gt;
&lt;li&gt;Can you choose a reasonable data structure and say why?&lt;/li&gt;
&lt;li&gt;Can you code it cleanly and test it?&lt;/li&gt;
&lt;li&gt;Can you state the time and space cost?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Those four are easier to practise when each structure is tied to a thing you've built.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small challenge
&lt;/h2&gt;

&lt;p&gt;Take any dependency list you know (your &lt;code&gt;package.json&lt;/code&gt;, or a recipe with "do X before Y" steps) and write a function that returns a valid order, or tells you the cycle if there isn't one. If that works, you've implemented two of the six structures from this post.&lt;/p&gt;

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

&lt;p&gt;Which data structure surprised you by being useful in a real project?&lt;/p&gt;




&lt;p&gt;☕ &lt;strong&gt;Enjoyed this post? You can support my writing on Ko-fi.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ko-fi.com/surajnandan" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2z7dch5enfz2e5i2t2gj.png" alt="Support me on Ko-fi" width="286" height="73"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>datastructures</category>
      <category>computerscience</category>
      <category>career</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Rewrite or refactor? How I decide</title>
      <dc:creator>Suraj Nandan</dc:creator>
      <pubDate>Sun, 08 Nov 2026 03:30:00 +0000</pubDate>
      <link>https://dev.to/suraj_nandan/rewrite-or-refactor-how-i-decide-1kbg</link>
      <guid>https://dev.to/suraj_nandan/rewrite-or-refactor-how-i-decide-1kbg</guid>
      <description>&lt;p&gt;Rewrites are tempting because old code is annoying. You open a file, wince, and a quiet voice says "I'd do this so much better from scratch."&lt;/p&gt;

&lt;p&gt;Sometimes that voice is right. Often it isn't. This post is a heuristic I use to decide, a list of traps, and an example from my own work where &lt;em&gt;not&lt;/em&gt; rewriting was the right call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why rewrites seduce us
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You understand the problem better now&lt;/strong&gt; than when you first wrote it, so the old design looks naive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Old code is visible, new code is imaginary.&lt;/strong&gt; You see every flaw in what exists and none in what doesn't yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Early progress is fast.&lt;/strong&gt; The first 80% of a rewrite always feels great.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Rewrites feel productive because the early days are fast. The last 20% is where they stall: the &lt;strong&gt;edge cases the old code already handled&lt;/strong&gt;. Those edge cases lived in bug fixes and odd conditionals that look ugly &lt;em&gt;because&lt;/em&gt; they encode reality. A rewrite throws them away and has to rediscover them one bug report at a time.&lt;/p&gt;

&lt;h2&gt;
  
  
  My heuristic
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Refactor when
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The code works and has users.&lt;/strong&gt; Working code is an asset. Breaking it has a real cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The problems are local.&lt;/strong&gt; One messy module, a confusing name, a duplicated function.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I can improve it in small, shippable steps.&lt;/strong&gt; If every step leaves the project working, risk stays low.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Rewrite when
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The core design makes the next feature impossible&lt;/strong&gt;, not just awkward.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I understand the problem much better&lt;/strong&gt; than when I started, and I can say &lt;em&gt;exactly&lt;/em&gt; what I'd do differently.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's small enough to finish&lt;/strong&gt; before I lose interest, ideally in days, not months.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The test I apply first
&lt;/h2&gt;

&lt;p&gt;Before any rewrite, write down, specifically, what the old design &lt;strong&gt;can't do&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Old design can't:
  1. ...
  2. ...
Because:
  ...
New design would allow:
  ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I can't fill that in with concrete statements, it's a refactor. "It's messy" isn't a reason. "It can't support two users editing at once because state lives in a single global" is.&lt;/p&gt;

&lt;h2&gt;
  
  
  A middle path: copy, don't rewrite
&lt;/h2&gt;

&lt;p&gt;There's a third option I use more than either extreme: &lt;strong&gt;copy the project, then change the copy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When I turned my portfolio design into a template, I didn't touch the live site. I made a separate copy and refactored &lt;em&gt;that&lt;/em&gt; until every owner-specific fact lived in one config file. The live site stayed stable; the copy became the template. I'll cover the details on Day 27.&lt;/p&gt;

&lt;p&gt;This approach works well when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the original must keep running,&lt;/li&gt;
&lt;li&gt;you want to try an ambitious change without risk,&lt;/li&gt;
&lt;li&gt;or you're generalising something built for one case.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Strangler-style change
&lt;/h2&gt;

&lt;p&gt;For bigger systems, the safest pattern is to replace pieces gradually:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Put a thin seam in front of the old piece.&lt;/li&gt;
&lt;li&gt;Build the new piece behind the same seam.&lt;/li&gt;
&lt;li&gt;Route a little traffic to it.&lt;/li&gt;
&lt;li&gt;Grow, then retire the old one.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You always have a working system, and each step can be reverted.&lt;/p&gt;

&lt;h2&gt;
  
  
  A decision that stayed written down
&lt;/h2&gt;

&lt;p&gt;For Job Scheduler, I used &lt;strong&gt;Postgres as the queue instead of a message broker&lt;/strong&gt;, and the trade-off is written down in its case study: one dependency instead of two, with a latency floor from polling and the jobs table as the throughput ceiling, acceptable at the scale I was targeting, with &lt;code&gt;LISTEN/NOTIFY&lt;/code&gt; as the known next step.&lt;/p&gt;

&lt;p&gt;Writing a trade-off down like that means that when the "this is limiting" itch appears, you can check it against what you already decided to accept.&lt;/p&gt;

&lt;h2&gt;
  
  
  Questions to ask yourself
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;What specifically can the old design not do?&lt;/li&gt;
&lt;li&gt;How long would the rewrite &lt;em&gt;really&lt;/em&gt; take (multiply my first guess)?&lt;/li&gt;
&lt;li&gt;What edge cases does the old code handle that I'd have to rediscover?&lt;/li&gt;
&lt;li&gt;Can I deliver value in the middle, or only at the end?&lt;/li&gt;
&lt;li&gt;Who depends on the current behaviour?&lt;/li&gt;
&lt;li&gt;Am I rewriting because it's needed, or because I'm bored?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That last one is worth asking out loud.&lt;/p&gt;

&lt;h2&gt;
  
  
  My rule
&lt;/h2&gt;

&lt;p&gt;Before a rewrite, write down &lt;em&gt;specifically&lt;/em&gt; what the old design can't do. If I can't, it's a refactor.&lt;/p&gt;

&lt;h2&gt;
  
  
  A rewrite-or-refactor scoring sheet
&lt;/h2&gt;

&lt;p&gt;Score each statement 0 (false), 1 (somewhat) or 2 (true). Total at the end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Points toward refactoring&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The code works and people use it.&lt;/li&gt;
&lt;li&gt;Problems are concentrated in a few places.&lt;/li&gt;
&lt;li&gt;I can change it in steps of a day or less.&lt;/li&gt;
&lt;li&gt;There are some tests, or I can add them first.&lt;/li&gt;
&lt;li&gt;The team understands the current behaviour.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Points toward rewriting&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The core design blocks a feature we need.&lt;/li&gt;
&lt;li&gt;The technology is end-of-life or unmaintained.&lt;/li&gt;
&lt;li&gt;I can state &lt;em&gt;exactly&lt;/em&gt; what the old version can't do.&lt;/li&gt;
&lt;li&gt;The scope is small enough to finish in days.&lt;/li&gt;
&lt;li&gt;I can run old and new in parallel and compare.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the refactoring score is clearly higher, refactor. If rewriting wins &lt;em&gt;and&lt;/em&gt; you can define the gap precisely, consider a rewrite, ideally incrementally. If the scores are close, default to the smaller change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Small refactoring moves
&lt;/h2&gt;

&lt;p&gt;Big refactors are made of small, safe steps. Four worth knowing:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Extract function.&lt;/strong&gt; Pull a block into a named function so the name explains it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// before&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FUNDED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cardholder_id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disputed_at&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// after&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canMarkPurchased&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Tx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FUNDED&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cardholder_id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disputed_at&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;canMarkPurchased&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Introduce a seam.&lt;/strong&gt; Put an interface between your code and a dependency so you can swap the implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;PaymentProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;charge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StubProvider&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;PaymentProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;charge&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stub-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// later: class RazorpayProvider implements PaymentProvider { ... }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CardBridge's stubbed escrow and KYC are the sort of thing this makes replaceable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Replace conditionals with data.&lt;/strong&gt; A long &lt;code&gt;if/else&lt;/code&gt; over states becomes a lookup table (like the legal-transitions map).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Rename for truth.&lt;/strong&gt; If a variable says &lt;code&gt;data&lt;/code&gt; and holds a list of claims, call it &lt;code&gt;claims&lt;/code&gt;. Cheap and surprisingly effective.&lt;/p&gt;

&lt;h2&gt;
  
  
  Always have a safety net
&lt;/h2&gt;

&lt;p&gt;Before changing structure, make sure &lt;em&gt;something&lt;/em&gt; will tell you if behaviour changed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an existing test suite,&lt;/li&gt;
&lt;li&gt;a handful of &lt;strong&gt;characterisation tests&lt;/strong&gt; that record what the code does today (even if it's odd),&lt;/li&gt;
&lt;li&gt;or manual checks written down in advance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Refactoring without a safety net is rewriting in slow motion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signs a rewrite is going wrong
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You keep discovering behaviour the old code had.&lt;/li&gt;
&lt;li&gt;The deadline keeps moving.&lt;/li&gt;
&lt;li&gt;The old system keeps getting patched meanwhile, so you're chasing a moving target.&lt;/li&gt;
&lt;li&gt;No one can say what "done" is.&lt;/li&gt;
&lt;li&gt;You're excited about the new tech more than the problem.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When two or three show up, stop and check whether a refactor or a gradual migration would do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Questions to ask a teammate
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;If we did nothing, what's the actual cost?&lt;/li&gt;
&lt;li&gt;What's the smallest change that removes most of the pain?&lt;/li&gt;
&lt;li&gt;How will we know it worked?&lt;/li&gt;
&lt;li&gt;What's our rollback plan?&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;What's your worst rewrite story? And did the new version end up better?&lt;/p&gt;




&lt;p&gt;☕ &lt;strong&gt;Enjoyed this post? You can support my writing on Ko-fi.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ko-fi.com/surajnandan" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2z7dch5enfz2e5i2t2gj.png" alt="Support me on Ko-fi" width="286" height="73"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>refactoring</category>
      <category>programming</category>
      <category>architecture</category>
      <category>career</category>
    </item>
    <item>
      <title>BTCPay Server hot wallets drained: what self-hosting a payment server really costs</title>
      <dc:creator>Suraj Nandan</dc:creator>
      <pubDate>Sat, 07 Nov 2026 18:30:00 +0000</pubDate>
      <link>https://dev.to/suraj_nandan/btcpay-server-hot-wallets-drained-what-self-hosting-a-payment-server-really-costs-582p</link>
      <guid>https://dev.to/suraj_nandan/btcpay-server-hot-wallets-drained-what-self-hosting-a-payment-server-really-costs-582p</guid>
      <description>&lt;p&gt;Self-hosting your payment stack sounds like the safest option: no custodian, no middleman, your keys on your server. Last weekend showed the other side of that. If your keys live on your server, its patch level is the only thing between the internet and your money.&lt;/p&gt;

&lt;p&gt;Over 1 November, attackers swept Bitcoin and Litecoin out of hot wallets on outdated &lt;strong&gt;BTCPay Server&lt;/strong&gt; instances. The project asked every operator to switch their servers off.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happened
&lt;/h2&gt;

&lt;p&gt;BTCPay Server is free, open-source software that merchants run on their own machines to accept bitcoin payments directly into their own wallets. There's no central service, so each operator patches and secures their own instance.&lt;/p&gt;

&lt;p&gt;According to the project's incident post (2 November 2026, times in UTC):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1 Nov, 13:46:&lt;/strong&gt; a wallet drain took place. The project says it hasn't established when exploitation first began.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1 Nov, 20:56:&lt;/strong&gt; the first email reporting a theft arrived.&lt;/li&gt;
&lt;li&gt;That evening the project asked VPS hosts, including LunaNode, to take BTCPay instances offline as a precaution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1 Nov, 22:25:&lt;/strong&gt; BTCPay warned on X and asked operators to shut down with &lt;code&gt;./btcpay-down.sh&lt;/code&gt; until the investigation was done.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2 Nov:&lt;/strong&gt; the investigation found the attacks targeted &lt;strong&gt;BTCPay Server 2.4.1 and earlier&lt;/strong&gt;. Servers already on 2.4.2 or later when the warning went out showed no impact.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Founder Nicolas Dorier said, as reported by CoinDesk and Unchained, that the attacker logged in as an administrator on affected servers, and that the team was still working out how. The project's public servers run 2.4.7 and, he said, weren't attacked.&lt;/p&gt;

&lt;h2&gt;
  
  
  How much was taken
&lt;/h2&gt;

&lt;p&gt;BTCPay hasn't published a loss figure or a count of affected servers. It published two attacker addresses, but warns that some activity there predates the thefts, so balances aren't a confirmed total.&lt;/p&gt;

&lt;p&gt;The on-chain analytics firm &lt;strong&gt;Bitquery&lt;/strong&gt; traced what it calls a floor of about &lt;strong&gt;$1.63 million&lt;/strong&gt; at 2 November prices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;18.38 BTC&lt;/strong&gt; across 534 sweeps and &lt;strong&gt;3,405 LTC&lt;/strong&gt; across 148 sweeps, 682 sweeps in all.&lt;/li&gt;
&lt;li&gt;The first sweep came on &lt;strong&gt;30 October at 08:22 UTC&lt;/strong&gt;, about 62 hours before the public alert.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;87%&lt;/strong&gt; of the value moved in one wave on 1 November, between 14:12 and 22:16 UTC.&lt;/li&gt;
&lt;li&gt;267 more sweeps, worth about $150,000, landed &lt;em&gt;after&lt;/em&gt; the alert.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bitquery stresses that sweeps are transactions, not victims, so the number of affected servers is unknown.&lt;/p&gt;

&lt;h2&gt;
  
  
  The background: two incidents in three months
&lt;/h2&gt;

&lt;p&gt;This isn't BTCPay's first bad week this year. On &lt;strong&gt;7 August 2026&lt;/strong&gt;, it shipped 2.4.2 to fix a critical, already-exploited flaw that let an unauthenticated attacker obtain LND &lt;code&gt;.macaroon&lt;/code&gt; credential files and take over a merchant's Lightning node. Researcher Craig Raw was credited with the disclosure. At the time, the project said on-chain wallets weren't affected by that issue.&lt;/p&gt;

&lt;p&gt;The November incident hits exactly those on-chain hot wallets. BTCPay says the attackers "used a different method to exploit the vulnerability fixed in 2.4.2" and hasn't published technical details. No CVE has been assigned. Some crypto news sites describe it as an authentication bypass, but BTCPay hasn't confirmed that, so treat it as a claim.&lt;/p&gt;

&lt;p&gt;There's a third thread. On &lt;strong&gt;29 October&lt;/strong&gt;, BTCPay released &lt;strong&gt;2.4.7&lt;/strong&gt;, which fixes &lt;strong&gt;85 findings&lt;/strong&gt; from an Anthropic OSS Scanner report (1 critical, 13 high, 52 medium, 19 low, using the report's own ratings). Bitquery notes the first sweep came less than a day later. BTCPay hasn't said the drains used any of those findings, and the affected servers were several releases behind 2.4.7 anyway.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a hot wallet changes the stakes
&lt;/h2&gt;

&lt;p&gt;A hot wallet keeps the spending keys on the server so the software can pay out automatically. BTCPay's own documentation flags the feature's security implications. The trade-off looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Watch-only wallet (keys off-server)
  attacker gets admin → can see invoices, change settings
                      → cannot sign a spend

Hot wallet (seed on the server)
  attacker gets admin → can sign and broadcast a sweep
                      → funds gone in one transaction, irreversibly
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With card payments, a compromised merchant account leads to chargebacks and disputes. With an on-chain hot wallet, a compromised admin session ends with a confirmed transaction. That's why the patch gap matters so much here: 2.4.2 had been out for almost three months.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who's affected
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Anyone who ran BTCPay Server 2.4.1 or earlier&lt;/strong&gt; with an internet-facing instance, especially with a hot wallet enabled. BTCPay says to move to a fresh server &lt;em&gt;even if you didn't notice a theft&lt;/em&gt;, and even if you updated after the 1 November warning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Merchants on hosted instances.&lt;/strong&gt; Some providers shut servers down automatically, and BTCPay suggests contacting yours to migrate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lightning users&lt;/strong&gt; should still follow the August advice to rotate LND credentials that were reachable through their own proxies or Tor services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hardware-wallet setups&lt;/strong&gt; weren't affected, according to BTCPay.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What operators and developers should do
&lt;/h2&gt;

&lt;p&gt;BTCPay's recovery steps, in short:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Check your version&lt;/strong&gt; (it's shown in the page footer when you're logged in).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If it's 2.4.1 or earlier, migrate.&lt;/strong&gt; Create a new wallet with a &lt;strong&gt;new seed on a trusted device&lt;/strong&gt; and sweep any remaining hot-wallet funds into it. Reusing the old seed leaves the funds exposed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Take the old server offline&lt;/strong&gt; and keep its logs and transaction records.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build a fresh VM&lt;/strong&gt; with the latest release from trusted sources. Don't restore the whole old server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rotate everything&lt;/strong&gt; the old server could reach (hosting, SSH, API and Lightning credentials) from a trusted device, never from the old machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep only operating cash hot.&lt;/strong&gt; Move the rest to a wallet whose keys never touch the server.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And the broader lessons for anyone running self-hosted software that holds value:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Subscribe to the project's security channel.&lt;/strong&gt; BTCPay says it wishes it had done more to reach users on old versions. Don't rely on the project to find you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Treat "update available" on a money-moving server as an incident&lt;/strong&gt;, not a backlog ticket.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Put admin panels behind a VPN, SSO or IP allow-list.&lt;/strong&gt; An admin login that can't be reached from the internet can't be abused from it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alert on outbound spends.&lt;/strong&gt; A watch-only monitor on your own addresses can flag a sweep within minutes. The first one here came 62 hours before the public alert.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What might happen next (analysis)
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This section is analysis, not reporting.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Expect a fuller technical write-up and possibly a CVE once BTCPay finishes its investigation, which may show whether the admin logins came from the 2.4.2 bug or something else. The 2.4.7 release also shows how AI-assisted code scanning can surface dozens of issues at once in a small open-source project, and those fixes then become public diffs that attackers can study. Self-hosted payment projects will likely push harder on auto-update and on-by-default hardening, and hosting providers may start forcing upgrades on images they distribute.&lt;/p&gt;

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

&lt;p&gt;BTCPay's design keeps merchants in control of their money, and that also makes them responsible for it. The software had a fix for months. The instances that got drained simply hadn't installed it, and their hot wallets turned an admin login into an irreversible transfer. If you run anything that can sign a payment, patch speed is part of your treasury policy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your turn:&lt;/strong&gt; if a server you run could move money on its own, how quickly would you find out it had been patched, or that it hadn't?&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;BTCPay Server, "Security Incident Affecting BTCPay Server 2.4.1 and Earlier" (2 Nov 2026): &lt;a href="https://blog.btcpayserver.org/btcpay-server-security-incident-2-4-1-and-earlier/" rel="noopener noreferrer"&gt;https://blog.btcpayserver.org/btcpay-server-security-incident-2-4-1-and-earlier/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;BTCPay Server, "Security Advisory: Update BTCPay Server to 2.4.2 Immediately" (7 Aug 2026, updated 2 Nov 2026): &lt;a href="https://blog.btcpayserver.org/security-advisory-btcpay-server-2-4-2/" rel="noopener noreferrer"&gt;https://blog.btcpayserver.org/security-advisory-btcpay-server-2-4-2/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;BTCPay Server, "BTCPay Server Security Incident: Our Response and Next Steps" (10 Aug 2026, updated 2 Nov 2026): &lt;a href="https://blog.btcpayserver.org/btcpay-server-security-incident-response-and-next-steps/" rel="noopener noreferrer"&gt;https://blog.btcpayserver.org/btcpay-server-security-incident-response-and-next-steps/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub, btcpayserver/btcpayserver release v2.4.7 (29 Oct 2026): &lt;a href="https://github.com/btcpayserver/btcpayserver/releases/tag/v2.4.7" rel="noopener noreferrer"&gt;https://github.com/btcpayserver/btcpayserver/releases/tag/v2.4.7&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Bitquery, "BTCPay Server hack" investigation (figures verified 2 Nov 2026): &lt;a href="https://bitquery.io/investigations/btcpay-server-hack" rel="noopener noreferrer"&gt;https://bitquery.io/investigations/btcpay-server-hack&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The Hacker News, "Hackers Exploit BTCPay Server Flaw to Steal Bitcoin and Litecoin From Hot Wallets" (3 Nov 2026): &lt;a href="https://thehackernews.com/2026/11/hackers-exploit-btcpay-server-flaw-to.html" rel="noopener noreferrer"&gt;https://thehackernews.com/2026/11/hackers-exploit-btcpay-server-flaw-to.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;CoinDesk, "BTCPay tells users to switch off their servers after reports of drained wallets" (1 Nov 2026): &lt;a href="https://www.coindesk.com/tech/2026/11/02/btcpay-a-bitcoin-payment-tool-tells-users-to-switch-off-their-servers-after-reports-of-drained-wallets" rel="noopener noreferrer"&gt;https://www.coindesk.com/tech/2026/11/02/btcpay-a-bitcoin-payment-tool-tells-users-to-switch-off-their-servers-after-reports-of-drained-wallets&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Unchained, "BTCPay Server reports no wallet drains on latest release after asking merchants to go offline" (2 Nov 2026): &lt;a href="https://unchainedcrypto.com/btcpay-server-reports-no-wallet-drains-on-latest-release-after-asking-merchants-to-go-offline/" rel="noopener noreferrer"&gt;https://unchainedcrypto.com/btcpay-server-reports-no-wallet-drains-on-latest-release-after-asking-merchants-to-go-offline/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Part of &lt;strong&gt;The Wire&lt;/strong&gt;, a daily brief on the tech and security news that matters to developers. Details are as reported up to 5 November 2026.&lt;/p&gt;

</description>
      <category>security</category>
      <category>bitcoin</category>
      <category>opensource</category>
      <category>news</category>
    </item>
    <item>
      <title>What a hackathon teaches you that a course doesn't</title>
      <dc:creator>Suraj Nandan</dc:creator>
      <pubDate>Sat, 07 Nov 2026 03:30:00 +0000</pubDate>
      <link>https://dev.to/suraj_nandan/what-a-hackathon-teaches-you-that-a-course-doesnt-436f</link>
      <guid>https://dev.to/suraj_nandan/what-a-hackathon-teaches-you-that-a-course-doesnt-436f</guid>
      <description>&lt;p&gt;Courses reward correctness. Hackathons reward &lt;strong&gt;something that runs&lt;/strong&gt;. Both matter, but the second teaches you things lectures can't.&lt;/p&gt;

&lt;p&gt;I've built under hackathon-style deadlines on three projects: &lt;strong&gt;GigShield&lt;/strong&gt; (a team of three, March to June 2026), &lt;strong&gt;Knot.ai&lt;/strong&gt; (the Echo Sphere × Agora hackathon, August to September 2026) and &lt;strong&gt;Hospitality.ai&lt;/strong&gt; (the GE HealthCare Precision Care Challenge 2026). This post is about what that format forces on you, what it can't teach, and a set of habits for getting the most out of one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the deadline forces
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cutting scope without agonising
&lt;/h3&gt;

&lt;p&gt;When time is fixed, scope is the only thing that can move. A hackathon makes you practise deciding what &lt;em&gt;not&lt;/em&gt; to build, quickly, without the luxury of perfect information. In normal projects that decision gets postponed forever.&lt;/p&gt;

&lt;p&gt;A useful question: &lt;em&gt;what is the smallest thing that still demonstrates the idea?&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing familiar tools
&lt;/h3&gt;

&lt;p&gt;It's not the time to learn a new framework. The fastest way to lose a weekend is to debug a tool you don't know while also building a product. Use what you already understand, and spend your novelty budget on exactly one thing that matters to the idea.&lt;/p&gt;

&lt;h3&gt;
  
  
  Demo-first thinking
&lt;/h3&gt;

&lt;p&gt;If the story isn't clear in two minutes, the features don't matter. Judges and users meet your project through a short demo, not through your code quality. That forces you to think about the &lt;em&gt;experience of understanding&lt;/em&gt; it, which is a skill product people use all the time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Splitting the problem so the hard part is isolated
&lt;/h3&gt;

&lt;p&gt;Knot.ai is a good example. The hard part wasn't the UI. It was keeping an AI interviewer under control. Isolating that, with a server-side state machine for difficulty and topic coverage while the model handled judgement and phrasing, meant the risky piece could be built and tested on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a hackathon exposes
&lt;/h2&gt;

&lt;p&gt;A tight deadline makes your shortcuts visible, and after each sprint it's worth listing what you'd have done with more time. Reading the "limits" sections of those projects gives a decent picture of what a sprint leaves behind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Knot.ai's voice path is the thinner-tested surface, and its state is single-node.&lt;/li&gt;
&lt;li&gt;Hospitality.ai runs on synthetic data and doesn't read scanned PDFs.&lt;/li&gt;
&lt;li&gt;GigShield's payouts are simulated, and some state lives in browser storage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of that is a failure. It's the honest shape of work done against a clock. The mistake would be pretending otherwise.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a hackathon doesn't teach
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Maintainable code.&lt;/strong&gt; A weekend prototype optimises for speed of writing, not ease of changing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests.&lt;/strong&gt; Under time pressure they're the first thing dropped.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sustainable pace.&lt;/strong&gt; Sprinting teaches you to sprint, not how to keep going for a year.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real users.&lt;/strong&gt; A demo audience is not a customer. Their questions are different.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A habit worth keeping
&lt;/h2&gt;

&lt;p&gt;After building something fast, &lt;strong&gt;schedule a clean-up week&lt;/strong&gt;, or admit to yourself it's a prototype. Lying to yourself about quality is how prototypes quietly become production.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical playbook
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Agree the one-sentence idea.&lt;/li&gt;
&lt;li&gt;Pick the stack you already know.&lt;/li&gt;
&lt;li&gt;Decide the roles (see Day 8) and the contract between pieces.&lt;/li&gt;
&lt;li&gt;Check the rules: what's judged, what's allowed, what must be live.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  During
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Get a thin end-to-end path working in the first few hours, however ugly.&lt;/li&gt;
&lt;li&gt;Write the &lt;strong&gt;demo script before the last feature&lt;/strong&gt;. It tells you what to cut.&lt;/li&gt;
&lt;li&gt;Deploy early. Don't discover hosting problems at the deadline.&lt;/li&gt;
&lt;li&gt;Keep a "not now" list (Day 10).&lt;/li&gt;
&lt;li&gt;Sleep. A rested person debugs faster than a heroic one.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  After
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Write down what's real and what's faked, while you remember.&lt;/li&gt;
&lt;li&gt;Fix the one thing that embarrassed you in the demo.&lt;/li&gt;
&lt;li&gt;Turn the work into a case study, including limits.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A tip on honesty in demos
&lt;/h2&gt;

&lt;p&gt;If part of your demo is mocked, simulated or stubbed, say so. It's tempting to let a mock look real. But being clear about it earns more respect than being caught, and it makes your real parts more credible.&lt;/p&gt;

&lt;h2&gt;
  
  
  A 24-hour timeline template
&lt;/h2&gt;

&lt;p&gt;Most hackathon time disappears at the beginning and the end. A rough plan helps. Scale it to your event's length.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Hours&lt;/th&gt;
&lt;th&gt;Focus&lt;/th&gt;
&lt;th&gt;Output&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0–1&lt;/td&gt;
&lt;td&gt;Agree the idea; read the rules and judging criteria&lt;/td&gt;
&lt;td&gt;One-sentence pitch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1–3&lt;/td&gt;
&lt;td&gt;Roles, contracts, repo, deploy skeleton&lt;/td&gt;
&lt;td&gt;A live "hello" on the real URL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3–10&lt;/td&gt;
&lt;td&gt;The one core feature, end to end&lt;/td&gt;
&lt;td&gt;A thin path that works, however ugly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10–16&lt;/td&gt;
&lt;td&gt;Second feature, error handling, data&lt;/td&gt;
&lt;td&gt;Something worth demoing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16–20&lt;/td&gt;
&lt;td&gt;Cut scope, fix the embarrassing bugs&lt;/td&gt;
&lt;td&gt;A stable build&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;20–22&lt;/td&gt;
&lt;td&gt;Demo script, screenshots, README&lt;/td&gt;
&lt;td&gt;A story in two minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;22–24&lt;/td&gt;
&lt;td&gt;Rehearse, deploy, sleep if you can&lt;/td&gt;
&lt;td&gt;A calm demo&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The deploy skeleton in hour 1 to 3 is the part people skip, and it's the one that saves the final hour.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design for the judging criteria
&lt;/h2&gt;

&lt;p&gt;Read the criteria before the first line of code. Typical ones, and what they imply:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Criterion&lt;/th&gt;
&lt;th&gt;What judges look for&lt;/th&gt;
&lt;th&gt;How to show it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Innovation&lt;/td&gt;
&lt;td&gt;Something fresh, not a clone&lt;/td&gt;
&lt;td&gt;One distinctive idea, stated early&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technical depth&lt;/td&gt;
&lt;td&gt;Hard parts handled well&lt;/td&gt;
&lt;td&gt;Name the hard problem and show your solution&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Usability&lt;/td&gt;
&lt;td&gt;A stranger can use it&lt;/td&gt;
&lt;td&gt;A demo with no explanation needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Impact&lt;/td&gt;
&lt;td&gt;A real problem and a real user&lt;/td&gt;
&lt;td&gt;A named persona and a concrete scenario&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Completeness&lt;/td&gt;
&lt;td&gt;It works end to end&lt;/td&gt;
&lt;td&gt;A thin full path beats three broken features&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Where the rules mention a sponsor's technology, plan how to use it &lt;em&gt;meaningfully&lt;/em&gt;, since a token integration is easy to spot.&lt;/p&gt;

&lt;h2&gt;
  
  
  A demo script template
&lt;/h2&gt;

&lt;p&gt;Two minutes is shorter than you think.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Hook (15 s):&lt;/strong&gt; the problem in one sentence, with a person in it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Show (60 s):&lt;/strong&gt; the one flow that matters, live or recorded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why it's hard (20 s):&lt;/strong&gt; the interesting technical decision.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What's next (15 s):&lt;/strong&gt; what you'd build with more time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask (10 s):&lt;/strong&gt; invite questions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Rehearse out loud at least twice. And &lt;strong&gt;record a backup video&lt;/strong&gt;: Wi-Fi fails at exactly the wrong moment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Team dynamics under pressure
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decide who has the final say&lt;/strong&gt; on scope when you disagree.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check in every few hours&lt;/strong&gt; for five minutes: what's done, what's blocked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protect each other's sleep.&lt;/strong&gt; Tired people write bugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Share credit&lt;/strong&gt; in the demo, by name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the mood light.&lt;/strong&gt; Humour is a performance tool.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  After the event
&lt;/h2&gt;

&lt;p&gt;The weekend isn't over when the demo ends. In the following week:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write down what's real and what's faked while you still remember.&lt;/li&gt;
&lt;li&gt;Fix the one thing that bit you on stage.&lt;/li&gt;
&lt;li&gt;Write a short case study including &lt;strong&gt;limits&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Thank the organisers and your teammates.&lt;/li&gt;
&lt;li&gt;Decide, honestly: is this a prototype to retire, or a project to continue?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Starting a new framework during the event.&lt;/li&gt;
&lt;li&gt;Building features the demo never shows.&lt;/li&gt;
&lt;li&gt;No deploy until the last hour.&lt;/li&gt;
&lt;li&gt;A demo that depends on a fragile live connection.&lt;/li&gt;
&lt;li&gt;Treating a mocked feature as real without saying so.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Did a hackathon change how you code? What did you drop first when time ran short?&lt;/p&gt;




&lt;p&gt;☕ &lt;strong&gt;Enjoyed this post? You can support my writing on Ko-fi.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ko-fi.com/surajnandan" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2z7dch5enfz2e5i2t2gj.png" alt="Support me on Ko-fi" width="286" height="73"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>hackathon</category>
      <category>career</category>
      <category>beginners</category>
      <category>teamwork</category>
    </item>
  </channel>
</rss>
